mirror of
https://github.com/espressif/openthread.git
synced 2026-06-06 05:24:51 +00:00
[nat64] use host ID tracking for IPv4 address allocation (#11909)
This change modifies the NAT64 translator to dynamically allocate IPv4 addresses by tracking a range of host IDs within the configured CIDR. This approach replaces the pre-allocated `mIp4AddressPool`, making it more memory-efficient by avoiding the storage of an entire address array. The translator now maintains `mMinHostId` and `mMaxHostId` derived from the configured CIDR. When allocating an IPv4 address for a new mapping: - If `PORT_TRANSLATION_ENABLE` is enabled, addresses are assigned sequentially by cycling through the host ID range. Mappings can share an IPv4 address as they are distinguished by translated port numbers. - If `PORT_TRANSLATION_ENABLE` is disabled, a 1-to-1 address mapping is used. The translator cycles through host IDs to find an unused IPv4 address. If all addresses are allocated, it attempts to free expired mappings before failing. A new test case, `TestNat64CidrAddressReuse`, is added to validate the address allocation and reuse logic. The test ensures that all available addresses from a CIDR are used, new requests fail when the pool is exhausted, and addresses are correctly reused after mappings expire. It is run against multiple CIDR sizes (`/32`, `/31`, `/30`, and `/27`) to verify behavior across various configurations.
This commit is contained in:
committed by
GitHub
parent
d5935a34f3
commit
eba5bdc434
@@ -546,6 +546,23 @@ public:
|
||||
*/
|
||||
Type *GetTail(void) { return AsNonConst(AsConst(this)->GetTail()); }
|
||||
|
||||
/**
|
||||
* Counts and returns the number of entries in the linked list.
|
||||
*
|
||||
* @returns The number of entries in the linked list.
|
||||
*/
|
||||
uint32_t CountAllEntries(void) const
|
||||
{
|
||||
uint32_t count = 0;
|
||||
|
||||
for (const Type *entry = mHead; entry != nullptr; entry = entry->GetNext())
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
// The following methods are intended to support range-based `for`
|
||||
// loop iteration over the linked-list entries and should not be
|
||||
// used directly.
|
||||
|
||||
@@ -238,6 +238,13 @@ public:
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
/**
|
||||
* Gets the CIDR length (in bits).
|
||||
*
|
||||
* @returns The CIDR length.
|
||||
*/
|
||||
uint8_t GetLength(void) const { return mLength; }
|
||||
|
||||
/**
|
||||
* Gets the prefix as a pointer to a byte array.
|
||||
*
|
||||
|
||||
@@ -67,6 +67,9 @@ Translator::Translator(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mState(kStateDisabled)
|
||||
, mMappingPool(aInstance)
|
||||
, mMinHostId(0)
|
||||
, mMaxHostId(0)
|
||||
, mNextHostId(0)
|
||||
, mTimer(aInstance)
|
||||
{
|
||||
Random::NonCrypto::Fill(mNextMappingId);
|
||||
@@ -355,20 +358,6 @@ void Translator::Mapping::Free(void)
|
||||
{
|
||||
LogInfo("Mapping removed: %s", ToString().AsCString());
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
if (Get<Translator>().mIp4Cidr.mLength > kAddressMappingCidrLimit)
|
||||
{
|
||||
// If `CONFIG_NAT64_PORT_TRANSLATION_ENABLE` is enabled
|
||||
// IPv4 addresses are allocated from the pool only when the
|
||||
// pool size is above a minimum value. Otherwise use just the
|
||||
// first address from the pool.
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
IgnoreError(Get<Translator>().mIp4AddressPool.PushBack(mIp4Address));
|
||||
}
|
||||
|
||||
Get<Translator>().mMappingPool.Free(*this);
|
||||
}
|
||||
|
||||
@@ -401,45 +390,70 @@ uint16_t Translator::AllocateSourcePort(uint16_t aSrcPort)
|
||||
}
|
||||
#endif
|
||||
|
||||
void Translator::GetNextIp4Address(Ip4::Address &aIp4Address)
|
||||
{
|
||||
aIp4Address.SynthesizeFromCidrAndHost(mIp4Cidr, mNextHostId);
|
||||
|
||||
mNextHostId++;
|
||||
|
||||
if (mNextHostId > mMaxHostId)
|
||||
{
|
||||
mNextHostId = mMinHostId;
|
||||
}
|
||||
}
|
||||
|
||||
#if !OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
|
||||
Error Translator::AllocateIp4Address(Ip4::Address &aIp4Address)
|
||||
{
|
||||
// Allocate a currently unused IPv4 address from the CIDR range.
|
||||
// If all addresses are allocated, try to free expired mappings.
|
||||
|
||||
Error error = kErrorNone;
|
||||
uint32_t numberOfHosts;
|
||||
|
||||
numberOfHosts = mMaxHostId - mMinHostId + 1;
|
||||
|
||||
if (mActiveMappings.CountAllEntries() >= numberOfHosts)
|
||||
{
|
||||
mActiveMappings.RemoveAndFreeAllMatching(TimerMilli::GetNow());
|
||||
|
||||
VerifyOrExit(mActiveMappings.CountAllEntries() < numberOfHosts, error = kErrorFailed);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
GetNextIp4Address(aIp4Address);
|
||||
} while (mActiveMappings.ContainsMatching(aIp4Address));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Translator::Mapping *Translator::AllocateMapping(const Ip6::Headers &aIp6Headers)
|
||||
{
|
||||
Mapping *mapping = nullptr;
|
||||
Ip4::Address ip4Addr;
|
||||
|
||||
// When `PORT_TRANSLATION_ENABLE` is enabled, the translator uses
|
||||
// IPv4 addresses from the provided CIDR range sequentially. In
|
||||
// this case, mappings can share an IPv4 address because they are
|
||||
// distinguished by their translated port numbers.
|
||||
//
|
||||
// Otherwise, a 1-to-1 address mapping is used, where each IPv6
|
||||
// address is mapped to a unique IPv4 address from the available
|
||||
// range.
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
// When port translation (`NAT64_PORT_TRANSLATION`) is enabled
|
||||
// the NAT64 translator can work in 2 ways, either with a single
|
||||
// IPv4 address or a larger pool of addresses. There is also the
|
||||
// corner case where the address pool is generated from a big
|
||||
// CIDR length and the number of available IPv4 addresses is not
|
||||
// big enough to apply a 1 to 1 translation from IPv6 to IPv4
|
||||
// address. When operating in the first case, there is no need to
|
||||
// manage the address pool and all active mappings will use 1
|
||||
// single address (or the limited number alternatively). If a
|
||||
// larger pool is available each active mapping will use a
|
||||
// separate IPv4 address.
|
||||
|
||||
if (mIp4Cidr.mLength > kAddressMappingCidrLimit)
|
||||
{
|
||||
// TODO: add logic to cycle between available IPv4 addresses
|
||||
ip4Addr = *mIp4AddressPool.At(0);
|
||||
}
|
||||
else
|
||||
GetNextIp4Address(ip4Addr);
|
||||
#else
|
||||
SuccessOrExit(AllocateIp4Address(ip4Addr));
|
||||
#endif
|
||||
{
|
||||
if (mIp4AddressPool.IsEmpty())
|
||||
{
|
||||
mActiveMappings.RemoveAndFreeAllMatching(TimerMilli::GetNow());
|
||||
}
|
||||
|
||||
VerifyOrExit(!mIp4AddressPool.IsEmpty());
|
||||
ip4Addr = *mIp4AddressPool.PopBack();
|
||||
}
|
||||
|
||||
mapping = mMappingPool.Allocate();
|
||||
|
||||
// We should get a valid item, there is enough space in the
|
||||
// mapping pool. Otherwise return null and fail the translation.
|
||||
VerifyOrExit(mapping != nullptr);
|
||||
|
||||
mActiveMappings.Push(*mapping);
|
||||
@@ -572,50 +586,33 @@ exit:
|
||||
|
||||
Error Translator::SetIp4Cidr(const Ip4::Cidr &aCidr)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
uint8_t len = aCidr.GetLength();
|
||||
|
||||
uint32_t numberOfHosts;
|
||||
uint32_t hostIdBegin;
|
||||
|
||||
VerifyOrExit(aCidr.mLength > 0 && aCidr.mLength <= 32, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(IsValueInRange<uint8_t>(len, 1, BitSizeOf(Ip4::Address)), error = kErrorInvalidArgs);
|
||||
|
||||
VerifyOrExit(mIp4Cidr != aCidr);
|
||||
|
||||
// Avoid using the 0s and 1s in the host id of an address, but
|
||||
// what if the user provides us with /32 or /31 addresses?
|
||||
// Determine the usable host ID range based on the CIDR prefix
|
||||
// length. For prefixes /1 through /30, the all-zeros and
|
||||
// all-ones host IDs are excluded. For /31 and /32 prefixes,
|
||||
// all host IDs are used.
|
||||
|
||||
if (aCidr.mLength == 32)
|
||||
mMinHostId = 0;
|
||||
mMaxHostId = (1 << (BitSizeOf(Ip4::Address) - len)) - 1;
|
||||
|
||||
if (len < BitSizeOf(Ip4::Address) - 1)
|
||||
{
|
||||
hostIdBegin = 0;
|
||||
numberOfHosts = 1;
|
||||
}
|
||||
else if (aCidr.mLength == 31)
|
||||
{
|
||||
hostIdBegin = 0;
|
||||
numberOfHosts = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
hostIdBegin = 1;
|
||||
numberOfHosts = static_cast<uint32_t>((1 << (Ip4::Address::kSize * 8 - aCidr.mLength)) - 2);
|
||||
mMinHostId++;
|
||||
mMaxHostId--;
|
||||
}
|
||||
|
||||
numberOfHosts = OT_MIN(numberOfHosts, kPoolSize);
|
||||
mNextHostId = mMinHostId;
|
||||
|
||||
mActiveMappings.Free();
|
||||
mIp4AddressPool.Clear();
|
||||
|
||||
for (uint32_t i = 0; i < numberOfHosts; i++)
|
||||
{
|
||||
Ip4::Address addr;
|
||||
|
||||
addr.SynthesizeFromCidrAndHost(aCidr, i + hostIdBegin);
|
||||
IgnoreError(mIp4AddressPool.PushBack(addr));
|
||||
}
|
||||
|
||||
LogInfo("IPv4 CIDR for NAT64: %s (actual address pool: %s - %s, %lu addresses)", aCidr.ToString().AsCString(),
|
||||
mIp4AddressPool.Front()->ToString().AsCString(), mIp4AddressPool.Back()->ToString().AsCString(),
|
||||
ToUlong(numberOfHosts));
|
||||
LogInfo("IPv4 CIDR for NAT64: %s (%lu addresses)", aCidr.ToString().AsCString(),
|
||||
ToUlong(mMaxHostId - mMinHostId + 1));
|
||||
|
||||
mIp4Cidr = aCidr;
|
||||
|
||||
@@ -635,7 +632,6 @@ void Translator::ClearIp4Cidr(void)
|
||||
|
||||
mIp4Cidr.Clear();
|
||||
mActiveMappings.Free();
|
||||
mIp4AddressPool.Clear();
|
||||
|
||||
UpdateState();
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#include "common/array.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/owning_list.hpp"
|
||||
#include "common/pool.hpp"
|
||||
@@ -284,20 +283,6 @@ private:
|
||||
static constexpr uint32_t kPoolSize = OPENTHREAD_CONFIG_NAT64_MAX_MAPPINGS;
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
// Under `PORT_TRANSLATION_ENABLE`, the translator can operate in
|
||||
// two modes: 1-to-1 address mapping where each IPv6 address gets
|
||||
// a unique IPv4 address from a pool, or having the mappings
|
||||
// share one (or a few) IPv4 addresses and are distinguished by
|
||||
// the translated port numbers.
|
||||
//
|
||||
// This constant defines the maximum allowed CIDR prefix length
|
||||
// for the IPv4 address pool to be considered large enough to use
|
||||
// 1-to-1 address mapping. If the configured prefix length is
|
||||
// greater than this value (e.g., /29, /30), the address pool is
|
||||
// too small, and the translator will fall back to using port
|
||||
// translation.
|
||||
static constexpr uint8_t kAddressMappingCidrLimit = 28;
|
||||
|
||||
static constexpr uint16_t kMinTranslationPort = 49152;
|
||||
static constexpr uint16_t kMaxTranslationPort = 65535;
|
||||
#endif
|
||||
@@ -323,6 +308,8 @@ private:
|
||||
bool Matches(const TimeMilli aNow) const { return mExpiry < aNow; }
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
bool Matches(const uint16_t aPort) const { return mTranslatedPortOrId == aPort; }
|
||||
#else
|
||||
bool Matches(const Ip4::Address &aIp4Address) const { return mIp4Address == aIp4Address; }
|
||||
#endif
|
||||
|
||||
Mapping *mNext;
|
||||
@@ -343,6 +330,8 @@ private:
|
||||
void UpdateState(void);
|
||||
Error TranslateIcmp4(Message &aMessage, uint16_t aOriginalId);
|
||||
Error TranslateIcmp6(Message &aMessage, uint16_t aTranslatedId);
|
||||
void GetNextIp4Address(Ip4::Address &aIp4Address);
|
||||
Error AllocateIp4Address(Ip4::Address &aIp4Address);
|
||||
Mapping *AllocateMapping(const Ip6::Headers &aIp6Headers);
|
||||
void HandleTimer(void);
|
||||
#if OPENTHREAD_CONFIG_NAT64_PORT_TRANSLATION_ENABLE
|
||||
@@ -354,16 +343,18 @@ private:
|
||||
|
||||
using TranslatorTimer = TimerMilliIn<Translator, &Translator::HandleTimer>;
|
||||
|
||||
State mState;
|
||||
uint64_t mNextMappingId;
|
||||
Array<Ip4::Address, kPoolSize> mIp4AddressPool;
|
||||
Pool<Mapping, kPoolSize> mMappingPool;
|
||||
OwningList<Mapping> mActiveMappings;
|
||||
Ip6::Prefix mNat64Prefix;
|
||||
Ip4::Cidr mIp4Cidr;
|
||||
TranslatorTimer mTimer;
|
||||
ProtocolCounters mCounters;
|
||||
ErrorCounters mErrorCounters;
|
||||
State mState;
|
||||
uint64_t mNextMappingId;
|
||||
Pool<Mapping, kPoolSize> mMappingPool;
|
||||
OwningList<Mapping> mActiveMappings;
|
||||
Ip6::Prefix mNat64Prefix;
|
||||
Ip4::Cidr mIp4Cidr;
|
||||
uint32_t mMinHostId;
|
||||
uint32_t mMaxHostId;
|
||||
uint32_t mNextHostId;
|
||||
TranslatorTimer mTimer;
|
||||
ProtocolCounters mCounters;
|
||||
ErrorCounters mErrorCounters;
|
||||
};
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
|
||||
|
||||
@@ -591,6 +591,175 @@ void TestNat64Mapping(void)
|
||||
VerifyOrQuit(iterator.GetNext(mapping) == kErrorNotFound);
|
||||
}
|
||||
|
||||
void TestNat64CidrAddressReuse(const char *aCidr)
|
||||
{
|
||||
static constexpr uint32_t kExpireTimeout = 120 * Time::kOneSecondInMsec;
|
||||
|
||||
static constexpr uint16_t kSrcPort = 55387;
|
||||
static constexpr uint16_t kDstPort = 55388;
|
||||
static constexpr uint16_t kPayloadLength = 32;
|
||||
|
||||
Core nexus;
|
||||
Node &node = nexus.CreateNode();
|
||||
Ip6::Prefix prefix;
|
||||
Ip4::Cidr cidr;
|
||||
uint16_t numIp4Addrs;
|
||||
Nat64::Translator::AddressMappingIterator iterator;
|
||||
Nat64::Translator::AddressMapping mapping;
|
||||
OwnedPtr<Message> message;
|
||||
Ip6::Address ip6Addr;
|
||||
Ip4::Address ip4Addr;
|
||||
Ip4::Headers ip4Headers;
|
||||
uint16_t count;
|
||||
|
||||
Log("------------------------------------------------------------------------------------------------------");
|
||||
Log("TestNat64CidrAddressReuse(%s)", aCidr);
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
node.Form();
|
||||
nexus.AdvanceTime(50 * Time::kOneSecondInMsec);
|
||||
VerifyOrQuit(node.Get<Mle::Mle>().IsLeader());
|
||||
|
||||
node.Get<Instance>().SetLogLevel(kLogLevelInfo);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Enable NAT64 translator");
|
||||
|
||||
SuccessOrQuit(prefix.FromString("fd01::/96"));
|
||||
SuccessOrQuit(cidr.FromString(aCidr));
|
||||
|
||||
node.Get<Nat64::Translator>().SetNat64Prefix(prefix);
|
||||
SuccessOrQuit(node.Get<Nat64::Translator>().SetIp4Cidr(cidr));
|
||||
|
||||
node.Get<Nat64::Translator>().SetEnabled(true);
|
||||
VerifyOrQuit(node.Get<Nat64::Translator>().GetState() == Nat64::kStateActive);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Determine number of available IPv4 addresses");
|
||||
|
||||
switch (cidr.GetLength())
|
||||
{
|
||||
case 32:
|
||||
numIp4Addrs = 1;
|
||||
break;
|
||||
case 31:
|
||||
numIp4Addrs = 2;
|
||||
break;
|
||||
default:
|
||||
numIp4Addrs = (1 << (32 - cidr.GetLength())) - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
Log("Number of available IPv4 addresses: %u", numIp4Addrs);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Translate IPv6 messages to use all IPv4 addresses");
|
||||
|
||||
for (uint16_t i = 0; i < numIp4Addrs; i++)
|
||||
{
|
||||
SuccessOrQuit(ip6Addr.FromString("fd02::0"));
|
||||
SuccessOrQuit(ip4Addr.FromString("200.100.1.1"));
|
||||
|
||||
ip6Addr.mFields.m8[15] = i;
|
||||
|
||||
message.Reset(PrepareMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength));
|
||||
|
||||
SuccessOrQuit(node.Get<Nat64::Translator>().TranslateIp6ToIp4(*message));
|
||||
|
||||
SuccessOrQuit(ip4Headers.ParseFrom(*message));
|
||||
VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr);
|
||||
VerifyOrQuit(ip4Headers.IsUdp());
|
||||
VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort);
|
||||
VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort);
|
||||
VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength);
|
||||
|
||||
nexus.AdvanceTime(1000);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check the Address Mappings");
|
||||
|
||||
iterator.Init(node.GetInstance());
|
||||
|
||||
for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++)
|
||||
{
|
||||
LogAddressMapping(mapping);
|
||||
VerifyOrQuit(mapping.mRemainingTimeMs > 0);
|
||||
}
|
||||
|
||||
VerifyOrQuit(count == numIp4Addrs);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Validate that next translation fails since all IPv4 addresses are in use");
|
||||
|
||||
SuccessOrQuit(ip6Addr.FromString("fd02::100"));
|
||||
|
||||
message.Reset(PrepareMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength));
|
||||
|
||||
VerifyOrQuit(node.Get<Nat64::Translator>().TranslateIp6ToIp4(*message) == kErrorDrop);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Wait for mapping entries to expire");
|
||||
|
||||
nexus.AdvanceTime(kExpireTimeout);
|
||||
|
||||
iterator.Init(node.GetInstance());
|
||||
|
||||
for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++)
|
||||
{
|
||||
LogAddressMapping(mapping);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Translate IPv6 messages again and check that IPv4 addresses are now reused");
|
||||
|
||||
for (uint16_t i = 0; i < numIp4Addrs; i++)
|
||||
{
|
||||
SuccessOrQuit(ip6Addr.FromString("fd02::200:0"));
|
||||
SuccessOrQuit(ip4Addr.FromString("200.100.3.3"));
|
||||
|
||||
ip6Addr.mFields.m8[15] = i + 100;
|
||||
|
||||
message.Reset(PrepareMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength));
|
||||
|
||||
SuccessOrQuit(node.Get<Nat64::Translator>().TranslateIp6ToIp4(*message));
|
||||
|
||||
SuccessOrQuit(ip4Headers.ParseFrom(*message));
|
||||
VerifyOrQuit(ip4Headers.GetDestinationAddress() == ip4Addr);
|
||||
VerifyOrQuit(ip4Headers.IsUdp());
|
||||
VerifyOrQuit(ip4Headers.GetSourcePort() == kSrcPort);
|
||||
VerifyOrQuit(ip4Headers.GetDestinationPort() == kDstPort);
|
||||
VerifyOrQuit(ip4Headers.GetUdpHeader().GetLength() == kPayloadLength);
|
||||
|
||||
nexus.AdvanceTime(1000);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Check the Address Mappings");
|
||||
|
||||
iterator.Init(node.GetInstance());
|
||||
|
||||
for (count = 0; iterator.GetNext(mapping) == kErrorNone; count++)
|
||||
{
|
||||
LogAddressMapping(mapping);
|
||||
VerifyOrQuit(mapping.mRemainingTimeMs > 0);
|
||||
}
|
||||
|
||||
VerifyOrQuit(count == numIp4Addrs);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Log("Validate that next translation fails since all IPv4 addresses are in use");
|
||||
|
||||
SuccessOrQuit(ip6Addr.FromString("fd02::200:100"));
|
||||
|
||||
message.Reset(PrepareMessage(node, ip6Addr, ip4Addr, kSrcPort, kDstPort, kPayloadLength));
|
||||
|
||||
VerifyOrQuit(node.Get<Nat64::Translator>().TranslateIp6ToIp4(*message) == kErrorDrop);
|
||||
|
||||
Log("End of TestNat64CidrAddressReuse(%s)", aCidr);
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
} // namespace ot
|
||||
|
||||
@@ -598,6 +767,10 @@ int main(void)
|
||||
{
|
||||
ot::Nexus::TestNat64StateChanges();
|
||||
ot::Nexus::TestNat64Mapping();
|
||||
ot::Nexus::TestNat64CidrAddressReuse("192.168.101.133/32");
|
||||
ot::Nexus::TestNat64CidrAddressReuse("192.168.102.178/31");
|
||||
ot::Nexus::TestNat64CidrAddressReuse("192.168.103.0/30");
|
||||
ot::Nexus::TestNat64CidrAddressReuse("192.168.104.0/27");
|
||||
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
|
||||
@@ -93,6 +93,7 @@ void VerifyLinkedListContent(const LinkedList<Entry> *aList, ...)
|
||||
Entry *argPrev = nullptr;
|
||||
const Entry *prev;
|
||||
uint16_t unusedId = 100;
|
||||
uint16_t count = 0;
|
||||
|
||||
va_start(args, aList);
|
||||
|
||||
@@ -117,6 +118,7 @@ void VerifyLinkedListContent(const LinkedList<Entry> *aList, ...)
|
||||
VerifyOrQuit(!argEntry->WasFreed());
|
||||
|
||||
argPrev = argEntry;
|
||||
count++;
|
||||
}
|
||||
|
||||
argEntry = va_arg(args, Entry *);
|
||||
@@ -129,6 +131,8 @@ void VerifyLinkedListContent(const LinkedList<Entry> *aList, ...)
|
||||
|
||||
VerifyOrQuit(aList->FindMatching("none") == nullptr, "succeeded for a missing entry");
|
||||
VerifyOrQuit(aList->FindMatching(unusedId) == nullptr, "succeeded for a missing entry");
|
||||
|
||||
VerifyOrQuit(aList->CountAllEntries() == count);
|
||||
}
|
||||
|
||||
void TestLinkedList(void)
|
||||
|
||||
Reference in New Issue
Block a user