[nat64] add support for RFC8781 NAT64 prefix (#12012)

This commit introduces support for discovering NAT64 prefixes as
specified in RFC 8781.

The key changes include:
- New `Nat64PrefixInfoOption`: A new `Nat64PrefixInfoOption` class is
  added to represent the PREF64 option in ND messages. This handles
  parsing the prefix and its lifetime from incoming RAs.
- `RxRaTracker` Enhancement: The `RxRaTracker` is updated to process
  `Nat64PrefixInfoOption` from RAs. It now maintains a list of
  discovered NAT64 prefixes from routers on the infrastructure link
  and determines a "favored" prefix among them.
- `RoutingManager` Update: The `Nat64PrefixManager` is enhanced to
  utilize the RA-discovered prefix.
- `test_routing_manager` Update: The `TestNat64PrefixSelection` is
  updated to include cases with RA-discovered prefixes.
This commit is contained in:
Yang Song
2025-10-31 07:35:36 -07:00
committed by GitHub
parent 537d790c0d
commit 4e2a570d0e
13 changed files with 694 additions and 41 deletions
+114 -20
View File
@@ -613,6 +613,18 @@ void LogRouterAdvert(const Icmp6Packet &aPacket)
break;
}
case Ip6::Nd::Option::kTypeNat64Prefix:
{
const Ip6::Nd::Nat64PrefixOption &nat64Prefix = static_cast<const Ip6::Nd::Nat64PrefixOption &>(option);
Ip6::Prefix prefix;
VerifyOrQuit(nat64Prefix.IsValid());
SuccessOrQuit(nat64Prefix.GetPrefix(prefix));
Log(" NAT64 Prefix - %s, lifetime:%u", prefix.ToString().AsCString(), nat64Prefix.GetLifetime());
break;
}
case Ip6::Nd::Option::kTypeRecursiveDnsServer:
{
const Ip6::Nd::RecursiveDnsServerOption &rdnss =
@@ -880,6 +892,18 @@ struct RaFlags : public Clearable<RaFlags>
bool mSnacRouterFlag;
};
struct Nat64Prefix
{
Nat64Prefix(const Ip6::Prefix &aPrefix, uint32_t aLifetime)
: mPrefix(aPrefix)
, mLifetime(aLifetime)
{
}
const Ip6::Prefix &mPrefix;
uint32_t mLifetime;
};
struct Rdnss
{
template <uint16_t kNumAddrs> static Rdnss Create(uint32_t aLifetime, const Ip6::Address (&aAddresses)[kNumAddrs])
@@ -906,6 +930,8 @@ void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
uint16_t aNumRios,
const Rdnss *aRdnsses,
uint16_t aNumRdnsses,
const Nat64Prefix *aNat64Prefixes,
uint16_t aNumNat64Prefixes,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
{
@@ -942,6 +968,13 @@ void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
SuccessOrQuit(aRaMsg.AppendRouteInfoOption(aRios->mPrefix, aRios->mValidLifetime, aRios->mPreference));
}
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
for (; aNumNat64Prefixes > 0; aNat64Prefixes++, aNumNat64Prefixes--)
{
SuccessOrQuit(aRaMsg.AppendNat64PrefixOption(aNat64Prefixes->mPrefix, aNat64Prefixes->mLifetime));
}
#endif
for (; aNumRdnsses > 0; aRdnsses++, aNumRdnsses--)
{
SuccessOrQuit(
@@ -956,13 +989,16 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
uint16_t aNumRios,
const Rdnss *aRdnsses,
uint16_t aNumRdnsses,
const Nat64Prefix *aNat64Prefixes,
uint16_t aNumNat64Prefixes,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
{
Ip6::Nd::RouterAdvert::TxMessage raMsg;
Icmp6Packet packet;
BuildRouterAdvert(raMsg, aPios, aNumPios, aRios, aNumRios, aRdnsses, aNumRdnsses, aDefaultRoute, aRaFlags);
BuildRouterAdvert(raMsg, aPios, aNumPios, aRios, aNumRios, aRdnsses, aNumRdnsses, aNat64Prefixes, aNumNat64Prefixes,
aDefaultRoute, aRaFlags);
raMsg.GetAsPacket(packet);
SendRouterAdvert(aRouterAddress, packet);
@@ -977,7 +1013,7 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, aPios, kNumPios, aRios, kNumRios, nullptr, 0, aDefaultRoute, aRaFlags);
SendRouterAdvert(aRouterAddress, aPios, kNumPios, aRios, kNumRios, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
}
template <uint16_t kNumPios>
@@ -986,7 +1022,7 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, aPios, kNumPios, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
SendRouterAdvert(aRouterAddress, aPios, kNumPios, nullptr, 0, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
}
template <uint16_t kNumRios>
@@ -995,19 +1031,19 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, nullptr, 0, aRios, kNumRios, nullptr, 0, aDefaultRoute, aRaFlags);
SendRouterAdvert(aRouterAddress, nullptr, 0, aRios, kNumRios, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const Rdnss &aRdnss)
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, &aRdnss, 1,
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, &aRdnss, 1, nullptr, 0,
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
}
template <uint16_t kNumRdnsses>
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const Rdnss (&aRdnsses)[kNumRdnsses])
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, aRdnsses, kNumRdnsses,
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, aRdnsses, kNumRdnsses, nullptr, 0,
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
}
@@ -1015,15 +1051,21 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const RaFlags &aRaFlags)
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0,
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0,
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), aRaFlags);
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const Nat64Prefix &aNat64Pio)
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, &aNat64Pio, 1,
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
}
struct OnLinkPrefix : public Pio
{
OnLinkPrefix(const Ip6::Prefix &aPrefix,
@@ -4507,10 +4549,16 @@ void TestAutoEnableOfSrpServer(void)
void TestNat64PrefixSelection(void)
{
Ip6::Prefix localNat64;
Ip6::Prefix ailNat64 = PrefixFromString("2000:0:0:1:0:0::", 96);
Ip6::Prefix localOmr;
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
NetworkData::OnMeshPrefixConfig prefixConfig;
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
Ip6::Prefix infraIfNat64Prefix = PrefixFromString("2000:0:0:1:0:0::", 96);
Ip6::Prefix raTrackerNat64PrefixA = PrefixFromString("2000:0:0:2:0:f::", 96);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
Ip6::Prefix raTrackerNat64PrefixB = PrefixFromString("2000:0:0:2:0:0::", 96);
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
Ip6::Prefix raTrackerNat64PrefixC = PrefixFromString("2000:0:0:2:0:8::", 96);
Ip6::Address routerAddressC = AddressFromString("fd00::cccc");
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
@@ -4530,7 +4578,7 @@ void TestNat64PrefixSelection(void)
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Enable Nat64 Prefix Manager. Check local NAT64 prefix in Network Data.
// Enable NAT64 Prefix Manager. Check local NAT64 prefix in Network Data.
sInstance->Get<BorderRouter::RoutingManager>().SetNat64PrefixManagerEnabled(true);
@@ -4540,10 +4588,10 @@ void TestNat64PrefixSelection(void)
VerifyNat64PrefixInNetData(localNat64);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AIL NAT64 prefix discovered. No infra-derived OMR prefix in Network Data.
// Check local NAT64 prefix in Network Data.
// InfraIf NAT64 prefix (e.g. using DNS - RFC 7050) discovered. No infra-derived OMR prefix in Network Data. Check
// local NAT64 prefix in Network Data.
DiscoverNat64Prefix(ailNat64);
DiscoverNat64Prefix(infraIfNat64Prefix);
AdvanceTime(20000);
@@ -4551,7 +4599,7 @@ void TestNat64PrefixSelection(void)
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Add a medium preference OMR prefix into Network Data.
// Check AIL NAT64 prefix published in Network Data.
// Check InfraIf NAT64 prefix published in Network Data.
prefixConfig.Clear();
prefixConfig.mPrefix = omrPrefix;
@@ -4568,14 +4616,60 @@ void TestNat64PrefixSelection(void)
AdvanceTime(20000);
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
VerifyNat64PrefixInNetData(ailNat64);
VerifyNat64PrefixInNetData(infraIfNat64Prefix);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// AIL NAT64 prefix removed.
// Send an RA from a router advertising a NAT64 prefix.
// Check that the RA-discovered NAT64 prefix is now favored and published.
SendRouterAdvert(routerAddressA, Nat64Prefix(raTrackerNat64PrefixA, kValidLitime));
AdvanceTime(20000);
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
VerifyNat64PrefixInNetData(raTrackerNat64PrefixA);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send two RAs from routers B and C advertising two different NAT64 prefixes.
// Check that the numerically smallest prefix is now favored.
SendRouterAdvert(routerAddressB, Nat64Prefix(raTrackerNat64PrefixB, kValidLitime));
SendRouterAdvert(routerAddressC, Nat64Prefix(raTrackerNat64PrefixC, kValidLitime));
AdvanceTime(20000);
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
VerifyNat64PrefixInNetData(raTrackerNat64PrefixB);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Remove RA-discovered NAT64 prefix A and B from router A and B.
// Check that the remained RA-discovered prefix C is now favored.
SendRouterAdvert(routerAddressA, Nat64Prefix(raTrackerNat64PrefixA, 0));
SendRouterAdvert(routerAddressB, Nat64Prefix(raTrackerNat64PrefixB, 0));
AdvanceTime(20000);
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
VerifyNat64PrefixInNetData(raTrackerNat64PrefixC);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Remove RA-discovered NAT64 prefix C.
// Check that the infra-if NAT64 prefix is published again.
SendRouterAdvert(routerAddressC, Nat64Prefix(raTrackerNat64PrefixC, 0));
AdvanceTime(20000);
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
VerifyNat64PrefixInNetData(infraIfNat64Prefix);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// InfraIf NAT64 prefix removed.
// Check local NAT64 prefix in Network Data.
ailNat64.Clear();
DiscoverNat64Prefix(ailNat64);
infraIfNat64Prefix.Clear();
DiscoverNat64Prefix(infraIfNat64Prefix);
AdvanceTime(20000);
@@ -4614,7 +4708,7 @@ template <uint16_t kNumPios> void ReportPdPrefixesAsRa(const Pio (&aPios)[kNumPi
Ip6::Nd::RouterAdvert::TxMessage raMsg;
Icmp6Packet packet;
BuildRouterAdvert(raMsg, aPios, kNumPios, nullptr, 0, nullptr, 0,
BuildRouterAdvert(raMsg, aPios, kNumPios, nullptr, 0, nullptr, 0, nullptr, 0,
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
raMsg.GetAsPacket(packet);