[network-data] add support for NAT64 flag in HasRoute TLV (#6429)

This commit adds a new flag in `NetworkData::HasRouteEntry` to
indicate that an off-mesh route prefix in the Network Data is also a
NAT64 prefix. It updates the public `otExternalRouteConfig` structure
to include `mNat64` bit flag and adds support for it in the core
modules.

It also updates `test_network_data` unit test to cover the new flag
and also adds some smaller style changes in this test.

This commit updates the CLI modules to add support for the new
flag. It also adds smaller enhancements in CLI related to network
data, adding methods `NetworkData::OutputPreference()` and
`OutputIp6Prefix()` to output common info (shared between on-mesh
prefixes and off-mesh routes), also simplifying how the flags are
mapped to char array string (avoiding extra space char in the output
string).

This commit also updates spinel and NCP code to add support for the
new NAT64 flag.
This commit is contained in:
Abtin Keshavarzian
2021-04-21 22:19:27 -07:00
committed by GitHub
parent 6fa74b7674
commit f4344792da
14 changed files with 274 additions and 112 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (103)
#define OPENTHREAD_API_VERSION (104)
/**
* @addtogroup api-instance
+5
View File
@@ -143,6 +143,11 @@ typedef struct otExternalRouteConfig
*/
signed int mPreference : 2;
/**
* TRUE, if this is a NAT64 prefix, FALSE, otherwise.
*/
bool mNat64 : 1;
/**
* TRUE, if this configuration is considered Stable Network Data. FALSE, otherwise.
*/
+4
View File
@@ -3710,6 +3710,10 @@ otError Interpreter::ProcessRouteAdd(uint8_t aArgsLength, char *aArgs[])
{
config.mStable = true;
}
else if (strcmp(aArgs[argcur], "n") == 0)
{
config.mNat64 = true;
}
else if (strcmp(aArgs[argcur], "high") == 0)
{
config.mPreference = OT_ROUTE_PREFERENCE_HIGH;
+81 -44
View File
@@ -55,57 +55,123 @@ NetworkData::NetworkData(Interpreter &aInterpreter)
void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig)
{
mInterpreter.OutputFormat("%x:%x:%x:%x::/%d ", HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[0]),
HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[1]),
HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[2]),
HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[3]), aConfig.mPrefix.mLength);
enum
{
// BorderRouter flag is `uint16_t` (though some of the bits are
// reserved for future use), so we use 17 chars string (16 flags
// plus null char at end of string).
kMaxFlagStringSize = 17,
};
char flagsString[kMaxFlagStringSize];
char *flagsPtr = &flagsString[0];
OutputIp6Prefix(aConfig.mPrefix);
if (aConfig.mPreferred)
{
mInterpreter.OutputFormat("p");
*flagsPtr++ = 'p';
}
if (aConfig.mSlaac)
{
mInterpreter.OutputFormat("a");
*flagsPtr++ = 'a';
}
if (aConfig.mDhcp)
{
mInterpreter.OutputFormat("d");
*flagsPtr++ = 'd';
}
if (aConfig.mConfigure)
{
mInterpreter.OutputFormat("c");
*flagsPtr++ = 'c';
}
if (aConfig.mDefaultRoute)
{
mInterpreter.OutputFormat("r");
*flagsPtr++ = 'r';
}
if (aConfig.mOnMesh)
{
mInterpreter.OutputFormat("o");
*flagsPtr++ = 'o';
}
if (aConfig.mStable)
{
mInterpreter.OutputFormat("s");
*flagsPtr++ = 's';
}
if (aConfig.mNdDns)
{
mInterpreter.OutputFormat("n");
*flagsPtr++ = 'n';
}
if (aConfig.mDp)
{
mInterpreter.OutputFormat("D");
*flagsPtr++ = 'D';
}
switch (aConfig.mPreference)
*flagsPtr = '\0';
if (flagsPtr != &flagsString[0])
{
mInterpreter.OutputFormat(" %s", flagsString);
}
OutputPreference(aConfig.mPreference);
mInterpreter.OutputLine(" %04x", aConfig.mRloc16);
}
void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig)
{
enum
{
// ExternalRoute flag is `uint8_t` (though some of the bits are
// reserved for future use), so we use 9 chars string (8 flags
// plus null char at end of string).
kMaxFlagStringSize = 9,
};
char flagsString[kMaxFlagStringSize];
char *flagsPtr = &flagsString[0];
OutputIp6Prefix(aConfig.mPrefix);
if (aConfig.mStable)
{
*flagsPtr++ = 's';
}
if (aConfig.mNat64)
{
*flagsPtr++ = 'n';
}
*flagsPtr = '\0';
if (flagsPtr != &flagsString[0])
{
mInterpreter.OutputFormat(" %s", flagsString);
}
OutputPreference(aConfig.mPreference);
mInterpreter.OutputLine(" %04x", aConfig.mRloc16);
}
void NetworkData::OutputIp6Prefix(const otIp6Prefix &aPrefix)
{
mInterpreter.OutputFormat("%x:%x:%x:%x::/%d", HostSwap16(aPrefix.mPrefix.mFields.m16[0]),
HostSwap16(aPrefix.mPrefix.mFields.m16[1]), HostSwap16(aPrefix.mPrefix.mFields.m16[2]),
HostSwap16(aPrefix.mPrefix.mFields.m16[3]), aPrefix.mLength);
}
void NetworkData::OutputPreference(signed int aPreference)
{
switch (aPreference)
{
case OT_ROUTE_PREFERENCE_LOW:
mInterpreter.OutputFormat(" low");
@@ -118,39 +184,10 @@ void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig)
case OT_ROUTE_PREFERENCE_HIGH:
mInterpreter.OutputFormat(" high");
break;
}
mInterpreter.OutputLine(" %04x", aConfig.mRloc16);
}
void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig)
{
mInterpreter.OutputFormat("%x:%x:%x:%x::/%d ", HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[0]),
HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[1]),
HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[2]),
HostSwap16(aConfig.mPrefix.mPrefix.mFields.m16[3]), aConfig.mPrefix.mLength);
if (aConfig.mStable)
{
mInterpreter.OutputFormat("s ");
}
switch (aConfig.mPreference)
{
case OT_ROUTE_PREFERENCE_LOW:
mInterpreter.OutputFormat("low");
break;
case OT_ROUTE_PREFERENCE_MED:
mInterpreter.OutputFormat("med");
break;
case OT_ROUTE_PREFERENCE_HIGH:
mInterpreter.OutputFormat("high");
default:
break;
}
mInterpreter.OutputLine(" %04x", aConfig.mRloc16);
}
void NetworkData::OutputService(const otServiceConfig &aConfig)
+2
View File
@@ -111,6 +111,8 @@ private:
void OutputPrefixes(void);
void OutputRoutes(void);
void OutputServices(void);
void OutputIp6Prefix(const otIp6Prefix &aPrefix);
void OutputPreference(signed int aPreference);
static constexpr Command sCommands[] = {
{"help", &NetworkData::ProcessHelp},
+8 -4
View File
@@ -118,6 +118,12 @@ uint8_t Prefix::MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, ui
return matchedLength;
}
bool Prefix::IsValidNat64(void) const
{
return (mLength == 32) || (mLength == 40) || (mLength == 48) || (mLength == 56) || (mLength == 64) ||
(mLength == 96);
}
Prefix::InfoString Prefix::ToString(void) const
{
InfoString string;
@@ -480,16 +486,14 @@ void Address::SynthesizeFromIp4Address(const Prefix &aPrefix, const Ip4::Address
kSkipIndex = 8,
};
uint8_t prefixLen = aPrefix.GetLength();
uint8_t ip6Index;
OT_ASSERT((prefixLen == 32) || (prefixLen == 40) || (prefixLen == 48) || (prefixLen == 56) || (prefixLen == 64) ||
(prefixLen == 96));
OT_ASSERT(aPrefix.IsValidNat64());
Clear();
SetPrefix(aPrefix);
ip6Index = prefixLen / CHAR_BIT;
ip6Index = aPrefix.GetLength() / CHAR_BIT;
for (uint8_t i = 0; i < Ip4::Address::kSize; i++)
{
+11
View File
@@ -261,6 +261,17 @@ public:
*/
static uint8_t MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, uint8_t aMaxSize);
/**
* This method indicates whether or not the prefix has a valid length for use as a NAT64 prefix.
*
* A NAT64 prefix must have one of the following lengths: 32, 40, 48, 56, 64, or 96 (per RFC 6502).
*
* @retval TRUE If the prefix has a valid length for use as a NAT64 prefix.
* @retval FALSE If the prefix does not have a valid length for use as a NAT64 prefix.
*
*/
bool IsValidNat64(void) const;
/**
* This method converts the prefix to a string.
*
+1
View File
@@ -76,6 +76,7 @@ void ExternalRouteConfig::SetFrom(Instance & aInstance,
aPrefixTlv.CopyPrefixTo(GetPrefix());
mPreference = aHasRouteEntry.GetPreference();
mNat64 = aHasRouteEntry.IsNat64();
mStable = aHasRouteTlv.IsStable();
mRloc16 = aHasRouteEntry.GetRloc();
mNextHopIsThisDevice = (aHasRouteEntry.GetRloc() == aInstance.Get<Mle::MleRouter>().GetRloc16());
+14 -2
View File
@@ -159,8 +159,19 @@ exit:
Error Local::AddHasRoutePrefix(const ExternalRouteConfig &aConfig)
{
return AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeHasRoute, aConfig.mPreference, /* aFlags */ 0,
aConfig.mStable);
Error error;
uint8_t flags = 0;
if (aConfig.mNat64)
{
VerifyOrExit(aConfig.GetPrefix().IsValidNat64(), error = kErrorInvalidArgs);
flags |= HasRouteEntry::kNat64Flag;
}
error = AddPrefix(aConfig.GetPrefix(), NetworkDataTlv::kTypeHasRoute, aConfig.mPreference, flags, aConfig.mStable);
exit:
return error;
}
Error Local::RemoveHasRoutePrefix(const Ip6::Prefix &aPrefix)
@@ -208,6 +219,7 @@ Error Local::AddPrefix(const Ip6::Prefix & aPrefix,
hasRouteTlv->SetLength(hasRouteTlv->GetLength() + sizeof(HasRouteEntry));
hasRouteTlv->GetEntry(0)->Init();
hasRouteTlv->GetEntry(0)->SetPreference(aPrf);
hasRouteTlv->GetEntry(0)->SetFlags(static_cast<uint8_t>(aFlags));
}
if (aStable)
+3 -2
View File
@@ -110,8 +110,9 @@ public:
*
* @param[in] aConfig A reference to the external route configuration.
*
* @retval kErrorNone Successfully added the Has Route entry.
* @retval kErrorNoBufs Insufficient space to add the Has Route entry.
* @retval kErrorNone Successfully added the Has Route entry.
* @retval kErrorInvalidArgs One or more parameters in @p aConfig were invalid.
* @retval kErrorNoBufs Insufficient space to add the Has Route entry.
*
*/
Error AddHasRoutePrefix(const ExternalRouteConfig &aConfig);
+30
View File
@@ -227,6 +227,11 @@ OT_TOOL_PACKED_BEGIN
class HasRouteEntry : public Equatable<HasRouteEntry>
{
public:
enum : uint8_t
{
kNat64Flag = 1 << 5, // NAT64 flag.
};
/**
* This method initializes the header.
*
@@ -273,6 +278,31 @@ public:
mFlags = (mFlags & ~kPreferenceMask) | ((static_cast<uint8_t>(aPrf) << kPreferenceOffset) & kPreferenceMask);
}
/**
* This method gets the Flags value.
*
* @returns The Flags value.
*
*/
uint16_t GetFlags(void) const { return (mFlags & ~kPreferenceMask); }
/**
* This method sets the Flags value.
*
* @param[in] aFlags The Flags value.
*
*/
void SetFlags(uint8_t aFlags) { mFlags = (mFlags & kPreferenceMask) | (aFlags & ~kPreferenceMask); }
/**
* This method indicates whether or not the NAT64 flag is set.
*
* @retval TRUE If the NAT64 flag is set.
* @retval FALSE If the NAT64 flag is not set.
*
*/
bool IsNat64(void) const { return (mFlags & kNat64Flag) != 0; }
/**
* This method returns a pointer to the next HasRouteEntry.
*
+7 -2
View File
@@ -632,6 +632,11 @@ enum
SPINEL_ROUTE_PREFERENCE_LOW = (3 << SPINEL_NET_FLAG_PREFERENCE_OFFSET),
};
enum
{
SPINEL_ROUTE_FLAG_NAT64 = (1 << 5),
};
enum
{
SPINEL_THREAD_MODE_FULL_NETWORK_DATA = (1 << 0),
@@ -2367,7 +2372,7 @@ enum
* `6`: IPv6 Prefix
* `C`: Prefix length in bits
* `b`: Stable flag
* `C`: TLV flags
* `C`: TLV flags (SPINEL_NET_FLAG_* definition)
* `b`: "Is defined locally" flag. Set if this network was locally
* defined. Assumed to be true for set, insert and replace. Clear if
* the on mesh network was defined by another node.
@@ -2388,7 +2393,7 @@ enum
* `6`: Route Prefix
* `C`: Prefix length in bits
* `b`: Stable flag
* `C`: Route preference flags
* `C`: Route flags (SPINEL_ROUTE_FLAG_* and SPINEL_ROUTE_PREFERNCE_* definitions)
* `b`: "Is defined locally" flag. Set if this route info was locally
* defined as part of local network data. Assumed to be true for set,
* insert and replace. Clear if the route is part of partition's network
+16 -13
View File
@@ -80,7 +80,7 @@ namespace Ncp {
static uint8_t BorderRouterConfigToFlagByte(const otBorderRouterConfig &aConfig)
{
uint8_t flags(0);
uint8_t flags = 0;
if (aConfig.mPreferred)
{
@@ -119,7 +119,7 @@ static uint8_t BorderRouterConfigToFlagByte(const otBorderRouterConfig &aConfig)
static uint8_t BorderRouterConfigToFlagByteExtended(const otBorderRouterConfig &aConfig)
{
uint8_t flags(0);
uint8_t flags = 0;
if (aConfig.mNdDns)
{
@@ -134,29 +134,31 @@ static uint8_t BorderRouterConfigToFlagByteExtended(const otBorderRouterConfig &
return flags;
}
static uint8_t ExternalRoutePreferenceToFlagByte(int aPreference)
static uint8_t ExternalRouteConfigToFlagByte(const otExternalRouteConfig &aConfig)
{
uint8_t flags;
uint8_t flags = 0;
switch (aPreference)
switch (aConfig.mPreference)
{
case OT_ROUTE_PREFERENCE_LOW:
flags = SPINEL_ROUTE_PREFERENCE_LOW;
flags |= SPINEL_ROUTE_PREFERENCE_LOW;
break;
case OT_ROUTE_PREFERENCE_HIGH:
flags = SPINEL_ROUTE_PREFERENCE_HIGH;
flags |= SPINEL_ROUTE_PREFERENCE_HIGH;
break;
case OT_ROUTE_PREFERENCE_MED:
OT_FALL_THROUGH;
default:
flags = SPINEL_ROUTE_PREFERENCE_MEDIUM;
flags |= SPINEL_ROUTE_PREFERENCE_MEDIUM;
break;
}
if (aConfig.mNat64)
{
flags |= SPINEL_ROUTE_FLAG_NAT64;
}
return flags;
}
@@ -2149,7 +2151,7 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_OFF_MESH_ROUTE
SuccessOrExit(error = mEncoder.WriteIp6Address(routeConfig.mPrefix.mPrefix));
SuccessOrExit(error = mEncoder.WriteUint8(routeConfig.mPrefix.mLength));
SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mStable));
SuccessOrExit(error = mEncoder.WriteUint8(ExternalRoutePreferenceToFlagByte(routeConfig.mPreference)));
SuccessOrExit(error = mEncoder.WriteUint8(ExternalRouteConfigToFlagByte(routeConfig)));
SuccessOrExit(error = mEncoder.WriteBool(false)); // IsLocal
SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mNextHopIsThisDevice));
SuccessOrExit(error = mEncoder.WriteUint16(routeConfig.mRloc16));
@@ -2168,7 +2170,7 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_THREAD_OFF_MESH_ROUTE
SuccessOrExit(error = mEncoder.WriteIp6Address(routeConfig.mPrefix.mPrefix));
SuccessOrExit(error = mEncoder.WriteUint8(routeConfig.mPrefix.mLength));
SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mStable));
SuccessOrExit(error = mEncoder.WriteUint8(ExternalRoutePreferenceToFlagByte(routeConfig.mPreference)));
SuccessOrExit(error = mEncoder.WriteUint8(ExternalRouteConfigToFlagByte(routeConfig)));
SuccessOrExit(error = mEncoder.WriteBool(true)); // IsLocal
SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mNextHopIsThisDevice));
SuccessOrExit(error = mEncoder.WriteUint16(routeConfig.mRloc16));
@@ -2224,6 +2226,7 @@ template <> otError NcpBase::HandlePropertyInsert<SPINEL_PROP_THREAD_OFF_MESH_RO
routeConfig.mPrefix.mLength = prefixLength;
routeConfig.mStable = stable;
routeConfig.mPreference = FlagByteToExternalRoutePreference(flags);
routeConfig.mNat64 = ((flags & SPINEL_ROUTE_FLAG_NAT64) != 0);
error = otBorderRouterAddRoute(mInstance, &routeConfig);
+91 -44
View File
@@ -47,8 +47,8 @@ void PrintExternalRouteConfig(const ExternalRouteConfig &aConfig)
printf("%02x", b);
}
printf(", length:%d, rloc16:%04x, preference:%d, stable:%d, nexthop:%d", aConfig.mPrefix.mLength, aConfig.mRloc16,
aConfig.mPreference, aConfig.mStable, aConfig.mNextHopIsThisDevice);
printf(", length:%d, rloc16:%04x, preference:%d, nat64:%d, stable:%d, nexthop:%d", aConfig.mPrefix.mLength,
aConfig.mRloc16, aConfig.mPreference, aConfig.mNat64, aConfig.mStable, aConfig.mNextHopIsThisDevice);
}
// Returns true if the two given ExternalRouteConfig match (intentionally ignoring mNextHopIsThisDevice).
@@ -81,27 +81,37 @@ void TestNetworkDataIterator(void)
VerifyOrQuit(instance != nullptr, "Null OpenThread instance\n");
{
const uint8_t kNetworkData[] = {0x08, 0x04, 0x0B, 0x02, 0x00, 0x00, 0x03, 0x14, 0x00, 0x40,
0xFD, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0xC8, 0x00, 0x40, 0x01, 0x03, 0x54, 0x00, 0x00};
const uint8_t kNetworkData[] = {
0x08, 0x04, 0x0B, 0x02, 0x00, 0x00, 0x03, 0x14, 0x00, 0x40, 0xFD, 0x00, 0x12, 0x34,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC8, 0x00, 0x40, 0x01, 0x03, 0x54, 0x00, 0x00,
};
otExternalRouteConfig routes[] = {
{
{{{{0xfd, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
64},
0xc800,
1,
false,
false,
{
{{{0xfd, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0xc800, // mRloc16
1, // mPreference
false, // mNat64
false, // mStable
false, // mNextHopIsThisDevice
},
{
{{{{0xfd, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
64},
0x5400,
0,
true,
false,
}};
{
{{{0xfd, 0x00, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0x5400, // mRloc16
0, // mPreference
false, // mNat64
true, // mStable
false, // mNextHopIsThisDevice
},
};
TestNetworkData netData(instance, kNetworkData, sizeof(kNetworkData));
@@ -124,34 +134,71 @@ void TestNetworkDataIterator(void)
0x08, 0x04, 0x0B, 0x02, 0x00, 0x00, 0x03, 0x1E, 0x00, 0x40, 0xFD, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00,
0x07, 0x02, 0x11, 0x40, 0x00, 0x03, 0x10, 0x00, 0x40, 0x01, 0x03, 0x54, 0x00, 0x00, 0x05, 0x04, 0x54, 0x00,
0x31, 0x00, 0x02, 0x0F, 0x00, 0x40, 0xFD, 0x00, 0xAB, 0xBA, 0xCD, 0xDC, 0x00, 0x00, 0x00, 0x03, 0x10, 0x00,
0x00, 0x03, 0x0E, 0x00, 0x20, 0xFD, 0x00, 0xAB, 0xBA, 0x01, 0x06, 0x54, 0x00, 0x00, 0x04, 0x00, 0x00};
0x20, 0x03, 0x0E, 0x00, 0x20, 0xFD, 0x00, 0xAB, 0xBA, 0x01, 0x06, 0x54, 0x00, 0x00, 0x04, 0x00, 0x00,
};
otExternalRouteConfig routes[] = {
{{{{{0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, 64},
0x1000,
1,
false,
false},
{{{{{0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, 64},
0x5400,
0,
true,
false},
{{{{{0xfd, 0x00, 0xab, 0xba, 0xcd, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, 64},
0x1000,
0,
false,
false},
{{{{{0xfd, 0x00, 0xab, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, 32},
0x5400,
0,
true,
false},
{{{{{0xfd, 0x00, 0xab, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, 32},
0x0400,
0,
true,
false}};
{
{
{{{0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0x1000, // mRloc16
1, // mPreference
false, // mNat64
false, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0x5400, // mRloc16
0, // mPreference
false, // mNat64
true, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0xab, 0xba, 0xcd, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
64,
},
0x1000, // mRloc16
0, // mPreference
true, // mNat64
false, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0xab, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
32,
},
0x5400, // mRloc16
0, // mPreference
false, // mNat64
true, // mStable
false, // mNextHopIsThisDevice
},
{
{
{{{0xfd, 0x00, 0xab, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00}}},
32,
},
0x0400, // mRloc16
0, // mPreference
false, // mNat64
true, // mStable
false, // mNextHopIsThisDevice
},
};
TestNetworkData netData(instance, kNetworkData, sizeof(kNetworkData));