From 481a064f034496d93273f4b837d46559f7b74e5c Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 16 Jun 2022 21:28:08 -0700 Subject: [PATCH] [ip6] update `Ip6::Prefix` comparison (#7813) This commit updates `Ip6::Prefix` comparison (overload of `<` operator). If the two prefixes have same length N, then the bytes are compared directly (as two big-endian N-bit numbers). If the two prefix have different lengths, the shorter prefix is padded by `0` bit up to the longer prefix length N before the bytes are compared (as big-endian N-bit numbers). If all bytes are equal, the prefix with shorter length is considered smaller. This commit also updates `test_ip_address` unit test to validate the new comparison behavior. --- src/core/net/ip6_address.cpp | 12 ++++++---- src/core/net/ip6_address.hpp | 6 +++-- tests/unit/test_ip_address.cpp | 43 ++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp index 11dcf9393..5708146a0 100644 --- a/src/core/net/ip6_address.cpp +++ b/src/core/net/ip6_address.cpp @@ -77,13 +77,17 @@ bool Prefix::IsEqual(const uint8_t *aPrefixBytes, uint8_t aPrefixLength) const bool Prefix::operator<(const Prefix &aOther) const { bool isSmaller; + uint8_t minLength; uint8_t matchedLength; - VerifyOrExit(GetLength() == aOther.GetLength(), isSmaller = GetLength() < aOther.GetLength()); + minLength = OT_MIN(GetLength(), aOther.GetLength()); + matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), SizeForLength(minLength)); - matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), GetBytesSize()); - - VerifyOrExit(matchedLength < GetLength(), isSmaller = false); + if (matchedLength >= minLength) + { + isSmaller = (GetLength() < aOther.GetLength()); + ExitNow(); + } isSmaller = GetBytes()[matchedLength / CHAR_BIT] < aOther.GetBytes()[matchedLength / CHAR_BIT]; diff --git a/src/core/net/ip6_address.hpp b/src/core/net/ip6_address.hpp index c7bf081c0..3c55f2190 100644 --- a/src/core/net/ip6_address.hpp +++ b/src/core/net/ip6_address.hpp @@ -266,8 +266,10 @@ public: /** * This method overloads operator `<` to compare two prefixes. * - * A prefix with shorter length is considered smaller than the one with longer length. If the prefix lengths are - * equal, then the prefix bytes are compared directly. + * If the two prefixes have the same length N, then the bytes are compared directly (as two big-endian N-bit + * numbers). If the two prefix have different lengths, the shorter prefix is padded by `0` bit up to the longer + * prefix length N before the bytes are compared (as big-endian N-bit numbers). If all bytes are equal, the prefix + * with shorter length is considered smaller. * * @param[in] aOther The other prefix to compare against. * diff --git a/tests/unit/test_ip_address.cpp b/tests/unit/test_ip_address.cpp index 09d656d9b..4ad860d99 100644 --- a/tests/unit/test_ip_address.cpp +++ b/tests/unit/test_ip_address.cpp @@ -274,6 +274,17 @@ void TestIp6AddressSetPrefix(void) } } +ot::Ip6::Prefix PrefixFrom(const char *aAddressString, uint8_t aPrefixLength) +{ + ot::Ip6::Prefix prefix; + ot::Ip6::Address address; + + SuccessOrQuit(address.FromString(aAddressString)); + prefix.Set(address.GetBytes(), aPrefixLength); + + return prefix; +} + void TestIp6Prefix(void) { const uint8_t kPrefixes[][OT_IP6_ADDRESS_SIZE] = { @@ -351,6 +362,38 @@ void TestIp6Prefix(void) } } } + + { + struct TestCase + { + ot::Ip6::Prefix mPrefixA; + ot::Ip6::Prefix mPrefixB; + }; + + TestCase kTestCases[] = { + {PrefixFrom("fd00::", 16), PrefixFrom("fd01::", 16)}, + {PrefixFrom("fc00::", 16), PrefixFrom("fd00::", 16)}, + {PrefixFrom("fd00::", 15), PrefixFrom("fd00::", 16)}, + {PrefixFrom("fd00::", 16), PrefixFrom("fd00:0::", 32)}, + {PrefixFrom("2001:0:0:0::", 64), PrefixFrom("fd00::", 8)}, + {PrefixFrom("2001:dba::", 32), PrefixFrom("fd12:3456:1234:abcd::", 64)}, + {PrefixFrom("910b:1000:0::", 48), PrefixFrom("910b:2000::", 32)}, + {PrefixFrom("::", 0), PrefixFrom("fd00::", 8)}, + {PrefixFrom("::", 0), PrefixFrom("::", 16)}, + {PrefixFrom("fd00:2:2::", 33), PrefixFrom("fd00:2:2::", 35)}, + {PrefixFrom("1:2:3:ffff::", 62), PrefixFrom("1:2:3:ffff::", 63)}, + }; + + printf("\nCompare Prefixes:\n"); + + for (const TestCase &testCase : kTestCases) + { + printf(" %26s < %s\n", testCase.mPrefixA.ToString().AsCString(), + testCase.mPrefixB.ToString().AsCString()); + VerifyOrQuit(testCase.mPrefixA < testCase.mPrefixB); + VerifyOrQuit(!(testCase.mPrefixB < testCase.mPrefixA)); + } + } } void TestIp4Ip6Translation(void)