mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
318b4b0771
This commit removes all Domain Prefix configuration and management logic
from the OpenThread stack, CLI commands, unit tests, and GRL harness
THCI wrapper.
- Removed public Backbone Router Domain Prefix APIs.
- Removed Domain Prefix flag ('mDp') and 'D' flag parser/formatter
from core network data types, Spinel, and CLI.
- Cleaned up local Backbone Router and Leader logic to exclude Domain
Prefix configuration, tracking, and events.
- Updated RoutingManager prefix advertisement (RIO) to exclude
special handling for Domain Prefix.
- Updated CLI documentation to remove Domain Prefix references.
- Removed domain prefix helper methods from python test certification
scripts.
- Removed auto-addition of default domain prefix and D flag support
from GRL harness OpenThread.py.
5467 lines
208 KiB
C++
5467 lines
208 KiB
C++
/*
|
|
* Copyright (c) 2022, The OpenThread Authors.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the copyright holder nor the
|
|
* names of its contributors may be used to endorse or promote products
|
|
* derived from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <openthread/config.h>
|
|
|
|
#include "test_platform.h"
|
|
#include "test_util.hpp"
|
|
|
|
#include <openthread/dataset_ftd.h>
|
|
#include <openthread/thread.h>
|
|
#include <openthread/platform/border_routing.h>
|
|
|
|
#include "border_router/routing_manager.hpp"
|
|
#include "common/arg_macros.hpp"
|
|
#include "common/array.hpp"
|
|
#include "common/numeric_limits.hpp"
|
|
#include "common/time.hpp"
|
|
#include "instance/instance.hpp"
|
|
#include "net/icmp6.hpp"
|
|
#include "net/nd6.hpp"
|
|
|
|
namespace ot {
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
|
|
|
// Logs a message and adds current time (sNow) as "<hours>:<min>:<secs>.<msec>"
|
|
#define Log(...) \
|
|
printf("%02u:%02u:%02u.%03u " OT_FIRST_ARG(__VA_ARGS__) "\n", (sNow / 3600000), (sNow / 60000) % 60, \
|
|
(sNow / 1000) % 60, sNow % 1000 OT_REST_ARGS(__VA_ARGS__))
|
|
|
|
static constexpr uint32_t kInfraIfIndex = 1;
|
|
static const char kInfraIfAddress[] = "fe80::1";
|
|
|
|
static constexpr uint32_t kValidLitime = 2000;
|
|
static constexpr uint32_t kPreferredLifetime = 1800;
|
|
static constexpr uint32_t kInfiniteLifetime = NumericLimits<uint32_t>::kMax;
|
|
|
|
static constexpr uint32_t kRioValidLifetime = 1800;
|
|
static constexpr uint32_t kRioDeprecatingLifetime = 300;
|
|
|
|
static constexpr uint16_t kMaxRaSize = 800;
|
|
static constexpr uint16_t kMaxDeprecatingPrefixes = 16;
|
|
|
|
static constexpr otOperationalDataset kDataset = {
|
|
.mActiveTimestamp =
|
|
{
|
|
.mSeconds = 1,
|
|
.mTicks = 0,
|
|
.mAuthoritative = false,
|
|
},
|
|
.mNetworkKey =
|
|
{
|
|
.m8 = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
|
|
},
|
|
.mNetworkName = {"OpenThread"},
|
|
.mExtendedPanId =
|
|
{
|
|
.m8 = {0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0xca, 0xfe},
|
|
},
|
|
.mMeshLocalPrefix =
|
|
{
|
|
.m8 = {0xfd, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
|
|
},
|
|
.mPanId = 0x1234,
|
|
.mChannel = 11,
|
|
.mPskc =
|
|
{
|
|
.m8 = {0xc2, 0x3a, 0x76, 0xe9, 0x8f, 0x1a, 0x64, 0x83, 0x63, 0x9b, 0x1a, 0xc1, 0x27, 0x1e, 0x2e, 0x27},
|
|
},
|
|
.mSecurityPolicy =
|
|
{
|
|
.mRotationTime = 672,
|
|
.mObtainNetworkKeyEnabled = true,
|
|
.mNativeCommissioningEnabled = true,
|
|
.mRoutersEnabled = true,
|
|
.mExternalCommissioningEnabled = true,
|
|
},
|
|
.mChannelMask = 0x07fff800,
|
|
.mComponents =
|
|
{
|
|
.mIsActiveTimestampPresent = true,
|
|
.mIsNetworkKeyPresent = true,
|
|
.mIsNetworkNamePresent = true,
|
|
.mIsExtendedPanIdPresent = true,
|
|
.mIsMeshLocalPrefixPresent = true,
|
|
.mIsPanIdPresent = true,
|
|
.mIsChannelPresent = true,
|
|
.mIsPskcPresent = true,
|
|
.mIsSecurityPolicyPresent = true,
|
|
.mIsChannelMaskPresent = true,
|
|
},
|
|
};
|
|
|
|
static Instance *sInstance;
|
|
|
|
static uint32_t sNow = 0;
|
|
static uint32_t sAlarmTime;
|
|
static bool sAlarmOn = false;
|
|
|
|
static otRadioFrame sRadioTxFrame;
|
|
static uint8_t sRadioTxFramePsdu[OT_RADIO_FRAME_MAX_SIZE];
|
|
static bool sRadioTxOngoing = false;
|
|
|
|
using Icmp6Packet = Ip6::Nd::Icmp6Packet;
|
|
|
|
enum ExpectedPio
|
|
{
|
|
kNoPio, // Expect to see no PIO in RA.
|
|
kPioAdvertisingLocalOnLink, // Expect to see local on-link prefix advertised (non-zero preferred lifetime).
|
|
kPioDeprecatingLocalOnLink, // Expect to see local on-link prefix deprecated (zero preferred lifetime).
|
|
};
|
|
|
|
struct DeprecatingPrefix
|
|
{
|
|
DeprecatingPrefix(void) = default;
|
|
|
|
DeprecatingPrefix(const Ip6::Prefix &aPrefix, uint32_t aLifetime)
|
|
: mPrefix(aPrefix)
|
|
, mLifetime(aLifetime)
|
|
{
|
|
}
|
|
|
|
bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
|
|
|
|
Ip6::Prefix mPrefix; // Old on-link prefix being deprecated.
|
|
uint32_t mLifetime; // Valid lifetime of prefix from PIO.
|
|
};
|
|
|
|
static Ip6::Address sInfraIfAddress;
|
|
|
|
bool sRsEmitted; // Indicates if an RS message was emitted by BR.
|
|
bool sRaValidated; // Indicates if an RA was emitted by BR and successfully validated.
|
|
bool sNsEmitted; // Indicates if an NS message was emitted by BR.
|
|
bool sRespondToNs; // Indicates whether or not to respond to NS.
|
|
ExpectedPio sExpectedPio; // Expected PIO in the emitted RA by BR (MUST be seen in RA to set `sRaValidated`).
|
|
uint32_t sOnLinkLifetime; // Valid lifetime for local on-link prefix from the last processed RA.
|
|
|
|
// Indicate whether or not to check the emitted RA header (default route) lifetime
|
|
bool sCheckRaHeaderLifetime;
|
|
|
|
// Expected default route lifetime in emitted RA header by BR.
|
|
uint32_t sExpectedRaHeaderLifetime;
|
|
|
|
enum ExpectedRaHeaderFlags
|
|
{
|
|
kRaHeaderFlagsSkipChecking, // Skip checking the RA header flags.
|
|
kRaHeaderFlagsNone, // Expect no flag (neither M or O).
|
|
kRaHeaderFlagsOnlyM, // Expect M flag only.
|
|
kRaHeaderFlagsOnlyO, // Expect O flag only.
|
|
kRaHeaderFlagsBothMAndO, // Expect both M and O flags.
|
|
};
|
|
|
|
// The expected RA header flags when validating emitted RA message.
|
|
ExpectedRaHeaderFlags sExpectedRaHeaderFlags;
|
|
|
|
// Array containing deprecating prefixes from PIOs in the last processed RA.
|
|
Array<DeprecatingPrefix, kMaxDeprecatingPrefixes> sDeprecatingPrefixes;
|
|
|
|
static constexpr uint16_t kMaxRioPrefixes = 10;
|
|
|
|
using NetworkData::RoutePreference;
|
|
|
|
struct RioPrefix
|
|
{
|
|
RioPrefix(void) = default;
|
|
|
|
explicit RioPrefix(const Ip6::Prefix &aPrefix)
|
|
: mSawInRa(false)
|
|
, mPrefix(aPrefix)
|
|
, mLifetime(0)
|
|
, mPreference(NetworkData::kRoutePreferenceMedium)
|
|
{
|
|
}
|
|
|
|
bool mSawInRa; // Indicate whether or not this prefix was seen in the emitted RA (as RIO).
|
|
Ip6::Prefix mPrefix; // The RIO prefix.
|
|
uint32_t mLifetime; // The RIO prefix lifetime - only valid when `mSawInRa`
|
|
RoutePreference mPreference; // The RIO preference - only valid when `mSawInRa`
|
|
};
|
|
|
|
class ExpectedRios : public Array<RioPrefix, kMaxRioPrefixes>
|
|
{
|
|
public:
|
|
void Add(const Ip6::Prefix &aPrefix) { SuccessOrQuit(PushBack(RioPrefix(aPrefix))); }
|
|
|
|
bool SawAll(void) const
|
|
{
|
|
bool sawAll = true;
|
|
|
|
for (const RioPrefix &rioPrefix : *this)
|
|
{
|
|
if (!rioPrefix.mSawInRa)
|
|
{
|
|
sawAll = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return sawAll;
|
|
}
|
|
};
|
|
|
|
ExpectedRios sExpectedRios; // Expected RIO prefixes in emitted RAs.
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// Function prototypes
|
|
|
|
void ProcessRadioTxAndTasklets(void);
|
|
void AdvanceTime(uint32_t aDuration);
|
|
void LogRouterAdvert(const Icmp6Packet &aPacket);
|
|
void ValidateRouterAdvert(const Icmp6Packet &aPacket);
|
|
const char *PreferenceToString(int8_t aPreference);
|
|
void SendRouterAdvert(const Ip6::Address &aAddress, const Icmp6Packet &aPacket);
|
|
void SendNeighborAdvert(const Ip6::Address &aAddress, const Ip6::Nd::NeighborAdvertMessage &aNaMessage);
|
|
void DiscoverNat64Prefix(const Ip6::Prefix &aPrefix);
|
|
|
|
extern "C" {
|
|
|
|
#if OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_PLATFORM_DEFINED
|
|
#if OPENTHREAD_CONFIG_LOG_INSTANCE_AWARE_API_ENABLE
|
|
void otPlatLogOutput(otInstance *, otLogLevel, const char *aLogLine) { printf(" %s\n", aLogLine); }
|
|
#else
|
|
void otPlatLog(otLogLevel, otLogRegion, const char *aFormat, ...)
|
|
{
|
|
va_list args;
|
|
|
|
printf(" ");
|
|
va_start(args, aFormat);
|
|
vprintf(aFormat, args);
|
|
va_end(args);
|
|
printf("\n");
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// `otPlatRadio
|
|
|
|
otRadioCaps otPlatRadioGetCaps(otInstance *) { return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF; }
|
|
|
|
otError otPlatRadioTransmit(otInstance *, otRadioFrame *)
|
|
{
|
|
sRadioTxOngoing = true;
|
|
|
|
return OT_ERROR_NONE;
|
|
}
|
|
|
|
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *) { return &sRadioTxFrame; }
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
// `otPlatAlaram
|
|
|
|
void otPlatAlarmMilliStop(otInstance *) { sAlarmOn = false; }
|
|
|
|
void otPlatAlarmMilliStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
|
{
|
|
sAlarmOn = true;
|
|
sAlarmTime = aT0 + aDt;
|
|
}
|
|
|
|
uint32_t otPlatAlarmMilliGetNow(void) { return sNow; }
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
// otPlatInfraIf
|
|
|
|
bool otPlatInfraIfHasAddress(otInstance *aInstance, uint32_t aInfraIfIndex, const otIp6Address *aAddress)
|
|
{
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aInfraIfIndex == kInfraIfIndex);
|
|
|
|
return AsCoreType(aAddress) == sInfraIfAddress;
|
|
}
|
|
|
|
otError otPlatInfraIfSendIcmp6Nd(otInstance *aInstance,
|
|
uint32_t aInfraIfIndex,
|
|
const otIp6Address *aDestAddress,
|
|
const uint8_t *aBuffer,
|
|
uint16_t aBufferLength)
|
|
{
|
|
Icmp6Packet packet;
|
|
Ip6::Icmp6Header *header;
|
|
|
|
Log("otPlatInfraIfSendIcmp6Nd(aDestAddr: %s, aBufferLength:%u)", AsCoreType(aDestAddress).ToString().AsCString(),
|
|
aBufferLength);
|
|
|
|
VerifyOrQuit(aInstance == sInstance);
|
|
VerifyOrQuit(aInfraIfIndex == kInfraIfIndex);
|
|
|
|
packet.Init(aBuffer, aBufferLength);
|
|
|
|
VerifyOrQuit(aBufferLength >= sizeof(Ip6::Icmp6Header));
|
|
|
|
header = reinterpret_cast<Ip6::Icmp6Header *>(const_cast<uint8_t *>(aBuffer));
|
|
|
|
switch (header->GetType())
|
|
{
|
|
case Ip6::Icmp6Header::kTypeRouterSolicit:
|
|
Log(" Router Solicit message");
|
|
sRsEmitted = true;
|
|
otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &sInfraIfAddress, aBuffer, aBufferLength);
|
|
break;
|
|
|
|
case Ip6::Icmp6Header::kTypeRouterAdvert:
|
|
Log(" Router Advertisement message");
|
|
LogRouterAdvert(packet);
|
|
ValidateRouterAdvert(packet);
|
|
// Intentionally modify the checksum field in RA Header
|
|
// before passing it back to the OT stack.
|
|
header->SetChecksum(0x1234);
|
|
otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &sInfraIfAddress, aBuffer, aBufferLength);
|
|
break;
|
|
|
|
case Ip6::Icmp6Header::kTypeNeighborSolicit:
|
|
{
|
|
const Ip6::Nd::NeighborSolicitHeader *nsMsg =
|
|
reinterpret_cast<const Ip6::Nd::NeighborSolicitHeader *>(packet.GetBytes());
|
|
|
|
Log(" Neighbor Solicit message");
|
|
|
|
VerifyOrQuit(packet.GetLength() >= sizeof(Ip6::Nd::NeighborSolicitHeader));
|
|
VerifyOrQuit(nsMsg->IsValid());
|
|
sNsEmitted = true;
|
|
|
|
if (sRespondToNs)
|
|
{
|
|
Ip6::Nd::NeighborAdvertMessage naMsg;
|
|
|
|
naMsg.SetTargetAddress(nsMsg->GetTargetAddress());
|
|
naMsg.SetRouterFlag();
|
|
naMsg.SetSolicitedFlag();
|
|
SendNeighborAdvert(AsCoreType(aDestAddress), naMsg);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
VerifyOrQuit(false, "Bad ICMP6 type");
|
|
}
|
|
|
|
return OT_ERROR_NONE;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
Array<void *, 500> sHeapAllocatedPtrs;
|
|
|
|
#if OPENTHREAD_CONFIG_HEAP_EXTERNAL_ENABLE
|
|
|
|
void *otPlatCAlloc(size_t aNum, size_t aSize)
|
|
{
|
|
void *ptr = calloc(aNum, aSize);
|
|
|
|
SuccessOrQuit(sHeapAllocatedPtrs.PushBack(ptr));
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void otPlatFree(void *aPtr)
|
|
{
|
|
if (aPtr != nullptr)
|
|
{
|
|
void **entry = sHeapAllocatedPtrs.Find(aPtr);
|
|
|
|
VerifyOrQuit(entry != nullptr, "A heap allocated item is freed twice");
|
|
sHeapAllocatedPtrs.Remove(*entry);
|
|
}
|
|
|
|
free(aPtr);
|
|
}
|
|
|
|
#endif
|
|
|
|
} // extern "C"
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void ProcessRadioTxAndTasklets(void)
|
|
{
|
|
do
|
|
{
|
|
if (sRadioTxOngoing)
|
|
{
|
|
sRadioTxOngoing = false;
|
|
otPlatRadioTxStarted(sInstance, &sRadioTxFrame);
|
|
otPlatRadioTxDone(sInstance, &sRadioTxFrame, nullptr, OT_ERROR_NONE);
|
|
}
|
|
|
|
otTaskletsProcess(sInstance);
|
|
} while (otTaskletsArePending(sInstance));
|
|
}
|
|
|
|
void AdvanceTime(uint32_t aDuration)
|
|
{
|
|
uint32_t time = sNow + aDuration;
|
|
|
|
Log("AdvanceTime for %u.%03u", aDuration / 1000, aDuration % 1000);
|
|
|
|
while (TimeMilli(sAlarmTime) <= TimeMilli(time))
|
|
{
|
|
ProcessRadioTxAndTasklets();
|
|
sNow = sAlarmTime;
|
|
otPlatAlarmMilliFired(sInstance);
|
|
}
|
|
|
|
ProcessRadioTxAndTasklets();
|
|
sNow = time;
|
|
}
|
|
|
|
void ValidateRouterAdvert(const Icmp6Packet &aPacket)
|
|
{
|
|
constexpr uint8_t kMaxPrefixes = 16;
|
|
|
|
Ip6::Nd::RouterAdvert::RxMessage raMsg(aPacket);
|
|
bool sawExpectedPio = false;
|
|
Array<Ip6::Prefix, kMaxPrefixes> pioPrefixes;
|
|
Array<Ip6::Prefix, kMaxPrefixes> rioPrefixes;
|
|
|
|
VerifyOrQuit(raMsg.IsValid());
|
|
|
|
if (sCheckRaHeaderLifetime)
|
|
{
|
|
VerifyOrQuit(raMsg.GetHeader().GetRouterLifetime() == sExpectedRaHeaderLifetime);
|
|
}
|
|
|
|
switch (sExpectedRaHeaderFlags)
|
|
{
|
|
case kRaHeaderFlagsSkipChecking:
|
|
break;
|
|
case kRaHeaderFlagsNone:
|
|
VerifyOrQuit(!raMsg.GetHeader().IsManagedAddressConfigFlagSet());
|
|
VerifyOrQuit(!raMsg.GetHeader().IsOtherConfigFlagSet());
|
|
break;
|
|
case kRaHeaderFlagsOnlyM:
|
|
VerifyOrQuit(raMsg.GetHeader().IsManagedAddressConfigFlagSet());
|
|
VerifyOrQuit(!raMsg.GetHeader().IsOtherConfigFlagSet());
|
|
break;
|
|
case kRaHeaderFlagsOnlyO:
|
|
VerifyOrQuit(!raMsg.GetHeader().IsManagedAddressConfigFlagSet());
|
|
VerifyOrQuit(raMsg.GetHeader().IsOtherConfigFlagSet());
|
|
break;
|
|
case kRaHeaderFlagsBothMAndO:
|
|
VerifyOrQuit(raMsg.GetHeader().IsManagedAddressConfigFlagSet());
|
|
VerifyOrQuit(raMsg.GetHeader().IsOtherConfigFlagSet());
|
|
break;
|
|
}
|
|
|
|
VerifyOrQuit(raMsg.GetHeader().IsSnacRouterFlagSet());
|
|
|
|
sDeprecatingPrefixes.Clear();
|
|
|
|
for (const Ip6::Nd::Option &option : raMsg)
|
|
{
|
|
switch (option.GetType())
|
|
{
|
|
case Ip6::Nd::Option::kTypePrefixInfo:
|
|
{
|
|
const Ip6::Nd::PrefixInfoOption &pio = static_cast<const Ip6::Nd::PrefixInfoOption &>(option);
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix localOnLink;
|
|
|
|
VerifyOrQuit(pio.IsValid());
|
|
pio.GetPrefix(prefix);
|
|
|
|
VerifyOrQuit(!pioPrefixes.Contains(prefix), "Duplicate PIO prefix in RA");
|
|
SuccessOrQuit(pioPrefixes.PushBack(prefix));
|
|
|
|
SuccessOrQuit(otBorderRoutingGetOnLinkPrefix(sInstance, &localOnLink));
|
|
|
|
if (prefix == localOnLink)
|
|
{
|
|
switch (sExpectedPio)
|
|
{
|
|
case kNoPio:
|
|
break;
|
|
|
|
case kPioAdvertisingLocalOnLink:
|
|
if (pio.GetPreferredLifetime() > 0)
|
|
{
|
|
sOnLinkLifetime = pio.GetValidLifetime();
|
|
sawExpectedPio = true;
|
|
}
|
|
break;
|
|
|
|
case kPioDeprecatingLocalOnLink:
|
|
if (pio.GetPreferredLifetime() == 0)
|
|
{
|
|
sOnLinkLifetime = pio.GetValidLifetime();
|
|
sawExpectedPio = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
VerifyOrQuit(pio.GetPreferredLifetime() == 0, "Old on link prefix is not deprecated");
|
|
SuccessOrQuit(sDeprecatingPrefixes.PushBack(DeprecatingPrefix(prefix, pio.GetValidLifetime())));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Ip6::Nd::Option::kTypeRouteInfo:
|
|
{
|
|
const Ip6::Nd::RouteInfoOption &rio = static_cast<const Ip6::Nd::RouteInfoOption &>(option);
|
|
Ip6::Prefix prefix;
|
|
|
|
VerifyOrQuit(rio.IsValid());
|
|
rio.GetPrefix(prefix);
|
|
|
|
VerifyOrQuit(!rioPrefixes.Contains(prefix), "Duplicate RIO prefix in RA");
|
|
SuccessOrQuit(rioPrefixes.PushBack(prefix));
|
|
|
|
for (RioPrefix &rioPrefix : sExpectedRios)
|
|
{
|
|
if (prefix == rioPrefix.mPrefix)
|
|
{
|
|
rioPrefix.mSawInRa = true;
|
|
rioPrefix.mLifetime = rio.GetRouteLifetime();
|
|
rioPrefix.mPreference = rio.GetPreference();
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
VerifyOrQuit(false, "Unexpected option type in RA msg");
|
|
}
|
|
}
|
|
|
|
if (!sRaValidated)
|
|
{
|
|
switch (sExpectedPio)
|
|
{
|
|
case kNoPio:
|
|
break;
|
|
case kPioAdvertisingLocalOnLink:
|
|
case kPioDeprecatingLocalOnLink:
|
|
// First emitted RAs may not yet have the expected PIO
|
|
// so we exit and not set `sRaValidated` to allow it
|
|
// to be checked for next received RA.
|
|
VerifyOrExit(sawExpectedPio);
|
|
break;
|
|
}
|
|
|
|
sRaValidated = true;
|
|
}
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------------------------------------------------
|
|
|
|
void LogRouterAdvert(const Icmp6Packet &aPacket)
|
|
{
|
|
Ip6::Nd::RouterAdvert::RxMessage raMsg(aPacket);
|
|
|
|
VerifyOrQuit(raMsg.IsValid());
|
|
|
|
Log(" RA header - M:%u, O:%u, S:%u", raMsg.GetHeader().IsManagedAddressConfigFlagSet(),
|
|
raMsg.GetHeader().IsOtherConfigFlagSet(), raMsg.GetHeader().IsSnacRouterFlagSet());
|
|
Log(" RA header - lifetime %u, prf:%s", raMsg.GetHeader().GetRouterLifetime(),
|
|
PreferenceToString(raMsg.GetHeader().GetDefaultRouterPreference()));
|
|
|
|
for (const Ip6::Nd::Option &option : raMsg)
|
|
{
|
|
switch (option.GetType())
|
|
{
|
|
case Ip6::Nd::Option::kTypePrefixInfo:
|
|
{
|
|
const Ip6::Nd::PrefixInfoOption &pio = static_cast<const Ip6::Nd::PrefixInfoOption &>(option);
|
|
Ip6::Prefix prefix;
|
|
|
|
VerifyOrQuit(pio.IsValid());
|
|
pio.GetPrefix(prefix);
|
|
Log(" PIO - %s, flags:%s%s, valid:%u, preferred:%u", prefix.ToString().AsCString(),
|
|
pio.IsOnLinkFlagSet() ? "L" : "", pio.IsAutoAddrConfigFlagSet() ? "A" : "", pio.GetValidLifetime(),
|
|
pio.GetPreferredLifetime());
|
|
break;
|
|
}
|
|
|
|
case Ip6::Nd::Option::kTypeRouteInfo:
|
|
{
|
|
const Ip6::Nd::RouteInfoOption &rio = static_cast<const Ip6::Nd::RouteInfoOption &>(option);
|
|
Ip6::Prefix prefix;
|
|
|
|
VerifyOrQuit(rio.IsValid());
|
|
rio.GetPrefix(prefix);
|
|
Log(" RIO - %s, prf:%s, lifetime:%u", prefix.ToString().AsCString(),
|
|
PreferenceToString(rio.GetPreference()), rio.GetRouteLifetime());
|
|
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 =
|
|
static_cast<const Ip6::Nd::RecursiveDnsServerOption &>(option);
|
|
|
|
VerifyOrQuit(rdnss.IsValid());
|
|
|
|
for (uint16_t index = 0; index < rdnss.GetNumAddresses(); index++)
|
|
{
|
|
Log(" RDNSS - %s, lifetime:%u", rdnss.GetAddressAt(index).ToString().AsCString(),
|
|
rdnss.GetLifetime());
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
VerifyOrQuit(false, "Bad option type in RA msg");
|
|
}
|
|
}
|
|
}
|
|
|
|
void LogRouterAdvert(const uint8_t *aBuffer, size_t aLength)
|
|
{
|
|
Icmp6Packet packet;
|
|
packet.Init(aBuffer, aLength);
|
|
LogRouterAdvert(packet);
|
|
}
|
|
|
|
const char *PreferenceToString(int8_t aPreference)
|
|
{
|
|
const char *str = "";
|
|
|
|
switch (aPreference)
|
|
{
|
|
case NetworkData::kRoutePreferenceLow:
|
|
str = "low";
|
|
break;
|
|
|
|
case NetworkData::kRoutePreferenceMedium:
|
|
str = "med";
|
|
break;
|
|
|
|
case NetworkData::kRoutePreferenceHigh:
|
|
str = "high";
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
void SendRouterAdvert(const Ip6::Address &aAddress, const uint8_t *aBuffer, uint16_t aLength)
|
|
{
|
|
otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &aAddress, aBuffer, aLength);
|
|
}
|
|
|
|
void SendRouterAdvert(const Ip6::Address &aAddress, const Icmp6Packet &aPacket)
|
|
{
|
|
SendRouterAdvert(aAddress, aPacket.GetBytes(), aPacket.GetLength());
|
|
}
|
|
|
|
void SendNeighborAdvert(const Ip6::Address &aAddress, const Ip6::Nd::NeighborAdvertMessage &aNaMessage)
|
|
{
|
|
Log("Sending NA from %s", aAddress.ToString().AsCString());
|
|
otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &aAddress, reinterpret_cast<const uint8_t *>(&aNaMessage),
|
|
sizeof(aNaMessage));
|
|
}
|
|
|
|
void DiscoverNat64Prefix(const Ip6::Prefix &aPrefix)
|
|
{
|
|
Log("Discovered NAT64 prefix %s", aPrefix.ToString().AsCString());
|
|
|
|
otPlatInfraIfDiscoverNat64PrefixDone(sInstance, kInfraIfIndex, &aPrefix);
|
|
}
|
|
|
|
Ip6::Prefix PrefixFromString(const char *aString, uint8_t aPrefixLength)
|
|
{
|
|
Ip6::Prefix prefix;
|
|
|
|
SuccessOrQuit(AsCoreType(&prefix.mPrefix).FromString(aString));
|
|
prefix.mLength = aPrefixLength;
|
|
|
|
return prefix;
|
|
}
|
|
|
|
Ip6::Address AddressFromString(const char *aString)
|
|
{
|
|
Ip6::Address address;
|
|
|
|
SuccessOrQuit(address.FromString(aString));
|
|
|
|
return address;
|
|
}
|
|
|
|
void VerifyOmrPrefixInNetData(const Ip6::Prefix &aOmrPrefix, bool aDefaultRoute, RoutePreference *aPreference = nullptr)
|
|
{
|
|
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
|
|
NetworkData::OnMeshPrefixConfig prefixConfig;
|
|
|
|
Log("VerifyOmrPrefixInNetData(%s, def-route:%s)", aOmrPrefix.ToString().AsCString(), aDefaultRoute ? "yes" : "no");
|
|
|
|
SuccessOrQuit(otNetDataGetNextOnMeshPrefix(sInstance, &iterator, &prefixConfig));
|
|
VerifyOrQuit(prefixConfig.GetPrefix() == aOmrPrefix);
|
|
VerifyOrQuit(prefixConfig.mStable == true);
|
|
VerifyOrQuit(prefixConfig.mSlaac == true);
|
|
VerifyOrQuit(prefixConfig.mPreferred == true);
|
|
VerifyOrQuit(prefixConfig.mOnMesh == true);
|
|
VerifyOrQuit(prefixConfig.mDefaultRoute == aDefaultRoute);
|
|
|
|
if (aPreference != nullptr)
|
|
{
|
|
VerifyOrQuit(prefixConfig.mPreference == *aPreference);
|
|
}
|
|
|
|
VerifyOrQuit(otNetDataGetNextOnMeshPrefix(sInstance, &iterator, &prefixConfig) == kErrorNotFound);
|
|
}
|
|
|
|
void VerifyNoOmrPrefixInNetData(void)
|
|
{
|
|
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
|
|
NetworkData::OnMeshPrefixConfig prefixConfig;
|
|
|
|
Log("VerifyNoOmrPrefixInNetData()");
|
|
VerifyOrQuit(otNetDataGetNextOnMeshPrefix(sInstance, &iterator, &prefixConfig) != kErrorNone);
|
|
}
|
|
|
|
enum ExternalRouteMode : uint8_t
|
|
{
|
|
kNoRoute,
|
|
kDefaultRoute,
|
|
kUlaRoute,
|
|
};
|
|
|
|
enum AdvPioMode : uint8_t
|
|
{
|
|
kSkipAdvPioCheck,
|
|
kWithAdvPioFlagSet,
|
|
kWithAdvPioCleared,
|
|
};
|
|
|
|
void VerifyExternalRouteInNetData(ExternalRouteMode aExternalRouteMode, AdvPioMode aAdvPioMode = kSkipAdvPioCheck)
|
|
{
|
|
Error error;
|
|
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
|
|
otExternalRouteConfig routeConfig;
|
|
|
|
error = otNetDataGetNextRoute(sInstance, &iterator, &routeConfig);
|
|
|
|
switch (aExternalRouteMode)
|
|
{
|
|
case kNoRoute:
|
|
Log("VerifyExternalRouteInNetData(kNoRoute)");
|
|
VerifyOrQuit(error != kErrorNone);
|
|
break;
|
|
|
|
case kDefaultRoute:
|
|
Log("VerifyExternalRouteInNetData(kDefaultRoute)");
|
|
VerifyOrQuit(error == kErrorNone);
|
|
VerifyOrQuit(routeConfig.mPrefix.mLength == 0);
|
|
VerifyOrQuit((aAdvPioMode == kSkipAdvPioCheck) || (routeConfig.mAdvPio == (aAdvPioMode == kWithAdvPioFlagSet)));
|
|
VerifyOrQuit(otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) != kErrorNone);
|
|
break;
|
|
|
|
case kUlaRoute:
|
|
Log("VerifyExternalRouteInNetData(kUlaRoute)");
|
|
VerifyOrQuit(error == kErrorNone);
|
|
VerifyOrQuit(routeConfig.mPrefix.mLength == 7);
|
|
VerifyOrQuit(routeConfig.mPrefix.mPrefix.mFields.m8[0] == 0xfc);
|
|
VerifyOrQuit((aAdvPioMode == kSkipAdvPioCheck) || (routeConfig.mAdvPio == (aAdvPioMode == kWithAdvPioFlagSet)));
|
|
VerifyOrQuit(otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) != kErrorNone);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void VerifyNat64PrefixInNetData(const Ip6::Prefix &aNat64Prefix)
|
|
{
|
|
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
|
|
NetworkData::ExternalRouteConfig routeConfig;
|
|
bool didFind = false;
|
|
|
|
Log("VerifyNat64PrefixInNetData()");
|
|
|
|
while (otNetDataGetNextRoute(sInstance, &iterator, &routeConfig) == kErrorNone)
|
|
{
|
|
if (!routeConfig.mNat64 || !routeConfig.GetPrefix().IsValidNat64())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Log(" nat64 prefix:%s, prf:%s", routeConfig.GetPrefix().ToString().AsCString(),
|
|
PreferenceToString(routeConfig.mPreference));
|
|
|
|
VerifyOrQuit(routeConfig.GetPrefix() == aNat64Prefix);
|
|
didFind = true;
|
|
}
|
|
|
|
VerifyOrQuit(didFind);
|
|
}
|
|
|
|
struct Pio
|
|
{
|
|
using Flags = Ip6::Nd::PrefixInfoOption::Flags;
|
|
|
|
static constexpr Flags kOnLinkFlag = Ip6::Nd::PrefixInfoOption::kOnLinkFlag;
|
|
static constexpr Flags kAutoConfigFlag = Ip6::Nd::PrefixInfoOption::kAutoConfigFlag;
|
|
static constexpr Flags kDhcp6Flag = Ip6::Nd::PrefixInfoOption::kDhcp6PdPreferredFlag;
|
|
|
|
Pio(const Ip6::Prefix &aPrefix,
|
|
uint32_t aValidLifetime,
|
|
uint32_t aPreferredLifetime,
|
|
Flags aFlags = kOnLinkFlag | kAutoConfigFlag)
|
|
: mPrefix(aPrefix)
|
|
, mValidLifetime(aValidLifetime)
|
|
, mPreferredLifetime(aPreferredLifetime)
|
|
, mFlags(aFlags)
|
|
{
|
|
}
|
|
|
|
const Ip6::Prefix &mPrefix;
|
|
uint32_t mValidLifetime;
|
|
uint32_t mPreferredLifetime;
|
|
Flags mFlags;
|
|
};
|
|
|
|
struct Rio
|
|
{
|
|
Rio(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, RoutePreference aPreference)
|
|
: mPrefix(aPrefix)
|
|
, mValidLifetime(aValidLifetime)
|
|
, mPreference(aPreference)
|
|
{
|
|
}
|
|
|
|
const Ip6::Prefix &mPrefix;
|
|
uint32_t mValidLifetime;
|
|
RoutePreference mPreference;
|
|
};
|
|
|
|
struct DefaultRoute
|
|
{
|
|
DefaultRoute(uint32_t aLifetime, RoutePreference aPreference)
|
|
: mLifetime(aLifetime)
|
|
, mPreference(aPreference)
|
|
{
|
|
}
|
|
|
|
uint32_t mLifetime;
|
|
RoutePreference mPreference;
|
|
};
|
|
|
|
struct RaFlags : public Clearable<RaFlags>
|
|
{
|
|
RaFlags(void)
|
|
: mManagedAddressConfigFlag(false)
|
|
, mOtherConfigFlag(false)
|
|
, mSnacRouterFlag(false)
|
|
{
|
|
}
|
|
|
|
bool mManagedAddressConfigFlag;
|
|
bool mOtherConfigFlag;
|
|
bool mSnacRouterFlag;
|
|
};
|
|
|
|
struct Pref64
|
|
{
|
|
Pref64(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])
|
|
{
|
|
return Rdnss(aLifetime, aAddresses, kNumAddrs);
|
|
}
|
|
|
|
Rdnss(uint32_t aLifetime, const Ip6::Address *aAddresses, uint8_t aNumAddresses)
|
|
: mLifetime(aLifetime)
|
|
, mAddresses(aAddresses)
|
|
, mNumAddresses(aNumAddresses)
|
|
{
|
|
}
|
|
|
|
uint32_t mLifetime;
|
|
const Ip6::Address *mAddresses;
|
|
uint8_t mNumAddresses;
|
|
};
|
|
|
|
void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
|
|
const Pio *aPios,
|
|
uint16_t aNumPios,
|
|
const Rio *aRios,
|
|
uint16_t aNumRios,
|
|
const Rdnss *aRdnsses,
|
|
uint16_t aNumRdnsses,
|
|
const Pref64 *aPref64s,
|
|
uint16_t aNumPref64s,
|
|
const DefaultRoute &aDefaultRoute,
|
|
const RaFlags &aRaFlags)
|
|
{
|
|
Ip6::Nd::RouterAdvert::Header header;
|
|
|
|
header.SetRouterLifetime(aDefaultRoute.mLifetime);
|
|
header.SetDefaultRouterPreference(aDefaultRoute.mPreference);
|
|
|
|
if (aRaFlags.mManagedAddressConfigFlag)
|
|
{
|
|
header.SetManagedAddressConfigFlag();
|
|
}
|
|
|
|
if (aRaFlags.mOtherConfigFlag)
|
|
{
|
|
header.SetOtherConfigFlag();
|
|
}
|
|
|
|
if (aRaFlags.mSnacRouterFlag)
|
|
{
|
|
header.SetSnacRouterFlag();
|
|
}
|
|
|
|
SuccessOrQuit(aRaMsg.Append(header));
|
|
|
|
for (; aNumPios > 0; aPios++, aNumPios--)
|
|
{
|
|
SuccessOrQuit(aRaMsg.AppendPrefixInfoOption(aPios->mPrefix, aPios->mValidLifetime, aPios->mPreferredLifetime,
|
|
aPios->mFlags));
|
|
}
|
|
|
|
for (; aNumRios > 0; aRios++, aNumRios--)
|
|
{
|
|
SuccessOrQuit(aRaMsg.AppendRouteInfoOption(aRios->mPrefix, aRios->mValidLifetime, aRios->mPreference));
|
|
}
|
|
|
|
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
|
for (; aNumPref64s > 0; aPref64s++, aNumPref64s--)
|
|
{
|
|
SuccessOrQuit(aRaMsg.AppendNat64PrefixOption(aPref64s->mPrefix, aPref64s->mLifetime));
|
|
}
|
|
#endif
|
|
|
|
for (; aNumRdnsses > 0; aRdnsses++, aNumRdnsses--)
|
|
{
|
|
SuccessOrQuit(
|
|
aRaMsg.AppendRecursiveDnsServerOption(aRdnsses->mAddresses, aRdnsses->mNumAddresses, aRdnsses->mLifetime));
|
|
}
|
|
}
|
|
|
|
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
|
const Pio *aPios,
|
|
uint16_t aNumPios,
|
|
const Rio *aRios,
|
|
uint16_t aNumRios,
|
|
const Rdnss *aRdnsses,
|
|
uint16_t aNumRdnsses,
|
|
const Pref64 *aPref64s,
|
|
uint16_t aNumPref64s,
|
|
const DefaultRoute &aDefaultRoute,
|
|
const RaFlags &aRaFlags)
|
|
{
|
|
Ip6::Nd::RouterAdvert::TxMessage raMsg;
|
|
Icmp6Packet packet;
|
|
|
|
BuildRouterAdvert(raMsg, aPios, aNumPios, aRios, aNumRios, aRdnsses, aNumRdnsses, aPref64s, aNumPref64s,
|
|
aDefaultRoute, aRaFlags);
|
|
raMsg.GetAsPacket(packet);
|
|
|
|
SendRouterAdvert(aRouterAddress, packet);
|
|
Log("Sending RA from router %s", aRouterAddress.ToString().AsCString());
|
|
LogRouterAdvert(packet);
|
|
}
|
|
|
|
template <uint16_t kNumPios, uint16_t kNumRios>
|
|
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
|
const Pio (&aPios)[kNumPios],
|
|
const Rio (&aRios)[kNumRios],
|
|
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
|
|
const RaFlags &aRaFlags = RaFlags())
|
|
{
|
|
SendRouterAdvert(aRouterAddress, aPios, kNumPios, aRios, kNumRios, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
|
|
}
|
|
|
|
template <uint16_t kNumPios>
|
|
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
|
const Pio (&aPios)[kNumPios],
|
|
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
|
|
const RaFlags &aRaFlags = RaFlags())
|
|
{
|
|
SendRouterAdvert(aRouterAddress, aPios, kNumPios, nullptr, 0, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
|
|
}
|
|
|
|
template <uint16_t kNumRios>
|
|
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
|
const Rio (&aRios)[kNumRios],
|
|
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
|
|
const RaFlags &aRaFlags = RaFlags())
|
|
{
|
|
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, 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, nullptr, 0,
|
|
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
|
|
}
|
|
|
|
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
|
const DefaultRoute &aDefaultRoute,
|
|
const RaFlags &aRaFlags = RaFlags())
|
|
{
|
|
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, nullptr, 0,
|
|
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), aRaFlags);
|
|
}
|
|
|
|
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const Pref64 &aPref64)
|
|
{
|
|
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, &aPref64, 1,
|
|
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
|
|
}
|
|
|
|
struct OnLinkPrefix : public Pio
|
|
{
|
|
OnLinkPrefix(const Ip6::Prefix &aPrefix,
|
|
uint32_t aValidLifetime,
|
|
uint32_t aPreferredLifetime,
|
|
const Ip6::Address &aRouterAddress)
|
|
: Pio(aPrefix, aValidLifetime, aPreferredLifetime)
|
|
, mRouterAddress(aRouterAddress)
|
|
{
|
|
}
|
|
|
|
const Ip6::Address &mRouterAddress;
|
|
};
|
|
|
|
struct RoutePrefix : public Rio
|
|
{
|
|
RoutePrefix(const Ip6::Prefix &aPrefix,
|
|
uint32_t aValidLifetime,
|
|
RoutePreference aPreference,
|
|
const Ip6::Address &aRouterAddress)
|
|
: Rio(aPrefix, aValidLifetime, aPreference)
|
|
, mRouterAddress(aRouterAddress)
|
|
{
|
|
}
|
|
|
|
const Ip6::Address &mRouterAddress;
|
|
};
|
|
|
|
template <uint16_t kNumOnLinkPrefixes, uint16_t kNumRoutePrefixes>
|
|
void VerifyPrefixTable(const OnLinkPrefix (&aOnLinkPrefixes)[kNumOnLinkPrefixes],
|
|
const RoutePrefix (&aRoutePrefixes)[kNumRoutePrefixes])
|
|
{
|
|
VerifyPrefixTable(aOnLinkPrefixes, kNumOnLinkPrefixes, aRoutePrefixes, kNumRoutePrefixes);
|
|
}
|
|
|
|
template <uint16_t kNumOnLinkPrefixes> void VerifyPrefixTable(const OnLinkPrefix (&aOnLinkPrefixes)[kNumOnLinkPrefixes])
|
|
{
|
|
VerifyPrefixTable(aOnLinkPrefixes, kNumOnLinkPrefixes, nullptr, 0);
|
|
}
|
|
|
|
template <uint16_t kNumRoutePrefixes> void VerifyPrefixTable(const RoutePrefix (&aRoutePrefixes)[kNumRoutePrefixes])
|
|
{
|
|
VerifyPrefixTable(nullptr, 0, aRoutePrefixes, kNumRoutePrefixes);
|
|
}
|
|
|
|
void VerifyPrefixTable(const OnLinkPrefix *aOnLinkPrefixes,
|
|
uint16_t aNumOnLinkPrefixes,
|
|
const RoutePrefix *aRoutePrefixes,
|
|
uint16_t aNumRoutePrefixes)
|
|
{
|
|
BorderRouter::PrefixTableIterator iter;
|
|
BorderRouter::PrefixTableEntry entry;
|
|
uint16_t onLinkPrefixCount = 0;
|
|
uint16_t routePrefixCount = 0;
|
|
|
|
Log("VerifyPrefixTable()");
|
|
|
|
sInstance->Get<BorderRouter::RxRaTracker>().InitIterator(iter);
|
|
|
|
while (sInstance->Get<BorderRouter::RxRaTracker>().GetNextPrefixTableEntry(iter, entry) == kErrorNone)
|
|
{
|
|
bool didFind = false;
|
|
|
|
if (entry.mIsOnLink)
|
|
{
|
|
Log(" on-link prefix:%s, valid:%u, preferred:%u, router:%s, age:%u",
|
|
AsCoreType(&entry.mPrefix).ToString().AsCString(), entry.mValidLifetime, entry.mPreferredLifetime,
|
|
AsCoreType(&entry.mRouter.mAddress).ToString().AsCString(), entry.mMsecSinceLastUpdate / 1000);
|
|
|
|
onLinkPrefixCount++;
|
|
|
|
for (uint16_t index = 0; index < aNumOnLinkPrefixes; index++)
|
|
{
|
|
const OnLinkPrefix &onLinkPrefix = aOnLinkPrefixes[index];
|
|
|
|
if ((onLinkPrefix.mPrefix == AsCoreType(&entry.mPrefix)) &&
|
|
(AsCoreType(&entry.mRouter.mAddress) == onLinkPrefix.mRouterAddress))
|
|
{
|
|
VerifyOrQuit(entry.mValidLifetime == onLinkPrefix.mValidLifetime);
|
|
VerifyOrQuit(entry.mPreferredLifetime == onLinkPrefix.mPreferredLifetime);
|
|
didFind = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Log(" route prefix:%s, valid:%u, prf:%s, router:%s, age:%u",
|
|
AsCoreType(&entry.mPrefix).ToString().AsCString(), entry.mValidLifetime,
|
|
PreferenceToString(entry.mRoutePreference), AsCoreType(&entry.mRouter.mAddress).ToString().AsCString(),
|
|
entry.mMsecSinceLastUpdate / 1000);
|
|
|
|
routePrefixCount++;
|
|
|
|
for (uint16_t index = 0; index < aNumRoutePrefixes; index++)
|
|
{
|
|
const RoutePrefix &routePrefix = aRoutePrefixes[index];
|
|
|
|
if ((routePrefix.mPrefix == AsCoreType(&entry.mPrefix)) &&
|
|
(AsCoreType(&entry.mRouter.mAddress) == routePrefix.mRouterAddress))
|
|
{
|
|
VerifyOrQuit(entry.mValidLifetime == routePrefix.mValidLifetime);
|
|
VerifyOrQuit(static_cast<int8_t>(entry.mRoutePreference) == routePrefix.mPreference);
|
|
didFind = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(didFind);
|
|
}
|
|
|
|
VerifyOrQuit(onLinkPrefixCount == aNumOnLinkPrefixes);
|
|
VerifyOrQuit(routePrefixCount == aNumRoutePrefixes);
|
|
}
|
|
|
|
void VerifyPrefixTableIsEmpty(void) { VerifyPrefixTable(nullptr, 0, nullptr, 0); }
|
|
|
|
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
|
struct Nat64Prefix
|
|
{
|
|
Nat64Prefix(const Ip6::Prefix &aPrefix, uint32_t aLifetime, const Ip6::Address &aRouterAddress)
|
|
: mPrefix(aPrefix)
|
|
, mLifetime(aLifetime)
|
|
, mRouterAddress(aRouterAddress)
|
|
{
|
|
}
|
|
|
|
const Ip6::Prefix &mPrefix;
|
|
uint32_t mLifetime;
|
|
const Ip6::Address &mRouterAddress;
|
|
};
|
|
|
|
template <uint16_t kNumNat64Prefixes>
|
|
void VerifyNat64PrefixTable(const Nat64Prefix (&aNat64Prefixes)[kNumNat64Prefixes])
|
|
{
|
|
VerifyNat64PrefixTable(aNat64Prefixes, kNumNat64Prefixes);
|
|
}
|
|
|
|
void VerifyNat64PrefixTable(const Nat64Prefix *aNat64Prefixes, uint16_t aNumNat64Prefixes)
|
|
{
|
|
BorderRouter::PrefixTableIterator iter;
|
|
BorderRouter::Nat64PrefixEntry entry;
|
|
uint16_t count = 0;
|
|
|
|
Log("VerifyNat64PrefixTable()");
|
|
|
|
sInstance->Get<BorderRouter::RxRaTracker>().InitIterator(iter);
|
|
|
|
while (sInstance->Get<BorderRouter::RxRaTracker>().GetNextNat64PrefixEntry(iter, entry) == kErrorNone)
|
|
{
|
|
bool didFind = false;
|
|
|
|
Log(" nat64 prefix:%s, lifetime:%u, router:%s, age:%u", AsCoreType(&entry.mPrefix).ToString().AsCString(),
|
|
entry.mLifetime, AsCoreType(&entry.mRouter.mAddress).ToString().AsCString(),
|
|
entry.mMsecSinceLastUpdate / 1000);
|
|
|
|
count++;
|
|
|
|
for (uint16_t index = 0; index < aNumNat64Prefixes; index++)
|
|
{
|
|
const Nat64Prefix &nat64Prefix = aNat64Prefixes[index];
|
|
|
|
if ((nat64Prefix.mPrefix == AsCoreType(&entry.mPrefix)) &&
|
|
(AsCoreType(&entry.mRouter.mAddress) == nat64Prefix.mRouterAddress))
|
|
{
|
|
VerifyOrQuit(entry.mLifetime == nat64Prefix.mLifetime);
|
|
didFind = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(didFind);
|
|
}
|
|
|
|
VerifyOrQuit(count == aNumNat64Prefixes);
|
|
}
|
|
|
|
void VerifyNat64PrefixTableIsEmpty(void) { VerifyNat64PrefixTable(nullptr, 0); }
|
|
#endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
|
|
|
struct RdnssAddress
|
|
{
|
|
RdnssAddress(const Ip6::Address &aAddress, uint32_t aLifetime, const Ip6::Address &aRouterAddress)
|
|
: mAddress(aAddress)
|
|
, mLifetime(aLifetime)
|
|
, mRouterAddress(aRouterAddress)
|
|
{
|
|
}
|
|
|
|
const Ip6::Address &mAddress;
|
|
uint32_t mLifetime;
|
|
const Ip6::Address &mRouterAddress;
|
|
};
|
|
|
|
template <uint16_t kNumAddrs> void VerifyRdnssAddressTable(const RdnssAddress (&aRdnssAddresses)[kNumAddrs])
|
|
{
|
|
VerifyRdnssAddressTable(aRdnssAddresses, kNumAddrs);
|
|
}
|
|
|
|
void VerifyRdnssAddressTable(const RdnssAddress *aRdnssAddresses, uint16_t aNumAddrs)
|
|
{
|
|
BorderRouter::PrefixTableIterator iter;
|
|
BorderRouter::RdnssAddrEntry entry;
|
|
uint16_t count = 0;
|
|
|
|
Log("VerifyRdnssAddressTable()");
|
|
|
|
sInstance->Get<BorderRouter::RxRaTracker>().InitIterator(iter);
|
|
|
|
while (sInstance->Get<BorderRouter::RxRaTracker>().GetNextRdnssAddrEntry(iter, entry) == kErrorNone)
|
|
{
|
|
bool didFind = false;
|
|
|
|
Log(" address:%s, lifetime:%u, router:%s, age:%u", AsCoreType(&entry.mAddress).ToString().AsCString(),
|
|
entry.mLifetime, AsCoreType(&entry.mRouter.mAddress).ToString().AsCString(),
|
|
entry.mMsecSinceLastUpdate / 1000);
|
|
|
|
count++;
|
|
|
|
for (uint16_t index = 0; index < aNumAddrs; index++)
|
|
{
|
|
const RdnssAddress &rndssAddress = aRdnssAddresses[index];
|
|
|
|
if ((rndssAddress.mAddress == AsCoreType(&entry.mAddress)) &&
|
|
(AsCoreType(&entry.mRouter.mAddress) == rndssAddress.mRouterAddress))
|
|
{
|
|
VerifyOrQuit(entry.mLifetime == rndssAddress.mLifetime);
|
|
didFind = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(didFind);
|
|
}
|
|
|
|
VerifyOrQuit(count == aNumAddrs);
|
|
}
|
|
|
|
void VerifyRdnssAddressTableIsEmpty(void) { VerifyRdnssAddressTable(nullptr, 0); }
|
|
|
|
struct InfraRouter
|
|
{
|
|
InfraRouter(const Ip6::Address &aAddress,
|
|
bool aManagedAddressConfigFlag,
|
|
bool aOtherConfigFlag,
|
|
bool aSnacRouterFlag,
|
|
bool aIsLocalDevice = false)
|
|
: mAddress(aAddress)
|
|
, mIsLocalDevice(aIsLocalDevice)
|
|
{
|
|
mFlags.Clear();
|
|
mFlags.mManagedAddressConfigFlag = aManagedAddressConfigFlag;
|
|
mFlags.mOtherConfigFlag = aOtherConfigFlag;
|
|
mFlags.mSnacRouterFlag = aSnacRouterFlag;
|
|
}
|
|
|
|
Ip6::Address mAddress;
|
|
RaFlags mFlags;
|
|
bool mIsLocalDevice;
|
|
};
|
|
|
|
template <uint16_t kNumRouters> void VerifyDiscoveredRouters(const InfraRouter (&aRouters)[kNumRouters])
|
|
{
|
|
VerifyDiscoveredRouters(aRouters, kNumRouters);
|
|
}
|
|
|
|
void VerifyDiscoveredRouters(const InfraRouter *aRouters, uint16_t aNumRouters)
|
|
{
|
|
BorderRouter::PrefixTableIterator iter;
|
|
BorderRouter::RouterEntry entry;
|
|
uint16_t count = 0;
|
|
|
|
Log("VerifyDiscoveredRouters()");
|
|
|
|
sInstance->Get<BorderRouter::RxRaTracker>().InitIterator(iter);
|
|
|
|
while (sInstance->Get<BorderRouter::RxRaTracker>().GetNextRouterEntry(iter, entry) == kErrorNone)
|
|
{
|
|
bool didFind = false;
|
|
|
|
Log(" address:%s, M:%u, O:%u, S:%u%s", AsCoreType(&entry.mAddress).ToString().AsCString(),
|
|
entry.mManagedAddressConfigFlag, entry.mOtherConfigFlag, entry.mSnacRouterFlag,
|
|
entry.mIsLocalDevice ? " (this BR)" : "");
|
|
|
|
for (uint16_t index = 0; index < aNumRouters; index++)
|
|
{
|
|
if (AsCoreType(&entry.mAddress) == aRouters[index].mAddress)
|
|
{
|
|
VerifyOrQuit(entry.mManagedAddressConfigFlag == aRouters[index].mFlags.mManagedAddressConfigFlag);
|
|
VerifyOrQuit(entry.mOtherConfigFlag == aRouters[index].mFlags.mOtherConfigFlag);
|
|
VerifyOrQuit(entry.mSnacRouterFlag == aRouters[index].mFlags.mSnacRouterFlag);
|
|
VerifyOrQuit(entry.mIsLocalDevice == aRouters[index].mIsLocalDevice);
|
|
didFind = true;
|
|
}
|
|
}
|
|
|
|
VerifyOrQuit(didFind);
|
|
count++;
|
|
}
|
|
|
|
VerifyOrQuit(count == aNumRouters);
|
|
}
|
|
|
|
void VerifyDiscoveredRoutersIsEmpty(void) { VerifyDiscoveredRouters(nullptr, 0); }
|
|
|
|
void VerifyFavoredOnLinkPrefix(const Ip6::Prefix &aPrefix)
|
|
{
|
|
Ip6::Prefix favoredPrefix;
|
|
|
|
Log("VerifyFavoredOnLinkPrefix(%s)", aPrefix.ToString().AsCString());
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOnLinkPrefix(favoredPrefix));
|
|
VerifyOrQuit(favoredPrefix == aPrefix);
|
|
}
|
|
|
|
void InitTest(bool aEnablBorderRouting = false, bool aResetInstance = false)
|
|
{
|
|
uint32_t delay = 10000;
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Initialize OT instance.
|
|
|
|
sNow = 0;
|
|
sAlarmOn = false;
|
|
|
|
if (!aResetInstance)
|
|
{
|
|
sInstance = testInitInstance();
|
|
}
|
|
else
|
|
{
|
|
sInstance = testResetInstance(sInstance);
|
|
delay += 26000; // leader reset sync delay
|
|
}
|
|
|
|
memset(&sRadioTxFrame, 0, sizeof(sRadioTxFrame));
|
|
sRadioTxFrame.mPsdu = sRadioTxFramePsdu;
|
|
sRadioTxOngoing = false;
|
|
|
|
SuccessOrQuit(sInfraIfAddress.FromString(kInfraIfAddress));
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Initialize and start Border Router and Thread operation.
|
|
|
|
SuccessOrQuit(otBorderRoutingInit(sInstance, kInfraIfIndex, /* aInfraIfIsRunning */ true));
|
|
|
|
otOperationalDatasetTlvs datasetTlvs;
|
|
|
|
otDatasetConvertToTlvs(&kDataset, &datasetTlvs);
|
|
SuccessOrQuit(otDatasetSetActiveTlvs(sInstance, &datasetTlvs));
|
|
|
|
SuccessOrQuit(otIp6SetEnabled(sInstance, true));
|
|
SuccessOrQuit(otThreadSetEnabled(sInstance, true));
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
|
// We explicitly disable the multi-AIL detector to prevent
|
|
// interference with the tests. The detector enables
|
|
// `RxRaTracker` and keeps it enabled even when Border Routing is
|
|
// disabled, which keeps prefix entries in the heap and can
|
|
// invalidate the heap allocation checks. It may also mess up the
|
|
// expected timing of RS (Router Solicitation) messages (starting
|
|
// the `RxRaTracker` early).
|
|
otBorderRoutingSetMultiAilDetectionEnabled(sInstance, false);
|
|
#endif
|
|
|
|
SuccessOrQuit(otBorderRoutingSetEnabled(sInstance, aEnablBorderRouting));
|
|
|
|
// Reset all test flags
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kNoPio;
|
|
sExpectedRios.Clear();
|
|
sRespondToNs = true;
|
|
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
|
|
sCheckRaHeaderLifetime = true;
|
|
sExpectedRaHeaderLifetime = 0;
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Ensure device starts as leader.
|
|
|
|
AdvanceTime(delay);
|
|
|
|
VerifyOrQuit(otThreadGetDeviceRole(sInstance) == OT_DEVICE_ROLE_LEADER);
|
|
}
|
|
|
|
void FinalizeTest(void)
|
|
{
|
|
SuccessOrQuit(otIp6SetEnabled(sInstance, false));
|
|
SuccessOrQuit(otThreadSetEnabled(sInstance, false));
|
|
SuccessOrQuit(otInstanceErasePersistentInfo(sInstance));
|
|
testFreeInstance(sInstance);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------------------------------------
|
|
|
|
void TestSamePrefixesFromMultipleRouters(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestSamePrefixesFromMultipleRouters");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and on-link prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with a new on-link (PIO) and route prefix (RIO).
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
|
|
{Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that the local on-link prefix is now deprecating in the new RA.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
AdvanceTime(10000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure info from router A
|
|
// is present in the table.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
|
|
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include new prefixes from router A.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send the same RA again from router A with the on-link (PIO) and route prefix (RIO).
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
|
|
{Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure info from router A
|
|
// remains unchanged.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
|
|
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router B with same route prefix (RIO) but with
|
|
// high route preference.
|
|
|
|
SendRouterAdvert(routerAddressB, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh)});
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure info from router B
|
|
// is also included in the table.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
|
|
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA),
|
|
RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh, routerAddressB)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router B removing the route prefix.
|
|
|
|
SendRouterAdvert(routerAddressB, {Rio(routePrefix, 0, NetworkData::kRoutePreferenceHigh)});
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure info from router B
|
|
// is now removed from the table.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
|
|
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data.
|
|
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestSamePrefixesFromMultipleRouters");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestOmrSelection(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
|
|
NetworkData::OnMeshPrefixConfig prefixConfig;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestOmrSelection");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
|
|
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and on-link prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Add a new OMR prefix directly into net data. The new prefix should
|
|
// be favored over the local OMR prefix.
|
|
|
|
prefixConfig.Clear();
|
|
prefixConfig.mPrefix = omrPrefix;
|
|
prefixConfig.mStable = true;
|
|
prefixConfig.mSlaac = true;
|
|
prefixConfig.mPreferred = true;
|
|
prefixConfig.mOnMesh = true;
|
|
prefixConfig.mDefaultRoute = false;
|
|
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
|
|
|
|
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(100);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Make sure BR emits RA with the new OMR prefix now, and deprecates the old OMR prefix.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(omrPrefix);
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
|
|
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
|
|
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should now see that the local OMR prefix
|
|
// is removed.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the OMR prefix previously added in net data.
|
|
|
|
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &omrPrefix));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(100);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Make sure BR emits RA with local OMR prefix again and start
|
|
// deprecating the previously added OMR prefix.
|
|
|
|
sRaValidated = false;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(omrPrefix);
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceLow);
|
|
VerifyOrQuit(sExpectedRios[1].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceMedium);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should see that the local OMR prefix is
|
|
// added again.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait enough for old deprecating OMR prefix deprecating to expire.
|
|
|
|
sRaValidated = false;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(omrPrefix);
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(310000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime == 0);
|
|
VerifyOrQuit(sExpectedRios[1].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceLow);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestOmrSelection");
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestOmrConfig(void)
|
|
{
|
|
using OmrConfig = BorderRouter::RoutingManager::OmrConfig;
|
|
|
|
static constexpr OmrConfig kOmrConfigAuto = BorderRouter::RoutingManager::kOmrConfigAuto;
|
|
static constexpr OmrConfig kOmrConfigCustom = BorderRouter::RoutingManager::kOmrConfigCustom;
|
|
static constexpr OmrConfig kOmrConfigDisabled = BorderRouter::RoutingManager::kOmrConfigDisabled;
|
|
|
|
Ip6::Prefix localOmr;
|
|
RoutePreference preference;
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix customPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
|
|
uint16_t heapAllocations;
|
|
OmrConfig omrConfig;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestOmrConfig");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
|
|
VerifyOrQuit(omrConfig == kOmrConfigAuto);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Update OMR config to disable it
|
|
|
|
preference = NetworkData::kRoutePreferenceMedium;
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigDisabled, nullptr, preference));
|
|
|
|
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
|
|
VerifyOrQuit(omrConfig == kOmrConfigDisabled);
|
|
|
|
AdvanceTime(100);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Make sure BR emits RA with the new OMR prefix now, and deprecates the old OMR prefix.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceLow);
|
|
|
|
// Check Network Data. We should now see no OMR prefix in the Network Data.
|
|
|
|
VerifyNoOmrPrefixInNetData();
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference));
|
|
VerifyOrQuit(prefix.GetLength() == 0);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Update OMR config back `kOmrConfigAuto` mode.
|
|
|
|
preference = NetworkData::kRoutePreferenceMedium;
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigAuto, nullptr, preference));
|
|
|
|
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
|
|
VerifyOrQuit(omrConfig == kOmrConfigAuto);
|
|
|
|
AdvanceTime(100);
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30 * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Update OMR config to `kOmrConfigCustom` mode to use a custom prefix
|
|
|
|
preference = NetworkData::kRoutePreferenceMedium;
|
|
SuccessOrQuit(
|
|
sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigCustom, &customPrefix, preference));
|
|
|
|
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(&prefix, &preference);
|
|
VerifyOrQuit(omrConfig == kOmrConfigCustom);
|
|
VerifyOrQuit(prefix == customPrefix);
|
|
VerifyOrQuit(preference == NetworkData::kRoutePreferenceMedium);
|
|
|
|
AdvanceTime(100);
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(customPrefix);
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(60 * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
|
|
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
|
|
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow);
|
|
|
|
VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Update the custom prefix preference value to high.
|
|
|
|
preference = NetworkData::kRoutePreferenceHigh;
|
|
SuccessOrQuit(
|
|
sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigCustom, &customPrefix, preference));
|
|
|
|
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(&prefix, &preference);
|
|
VerifyOrQuit(omrConfig == kOmrConfigCustom);
|
|
VerifyOrQuit(prefix == customPrefix);
|
|
VerifyOrQuit(preference == NetworkData::kRoutePreferenceHigh);
|
|
|
|
AdvanceTime(100);
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(customPrefix);
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(60 * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
|
|
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
|
|
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow);
|
|
|
|
VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for previous local OMR to be fully deprecated and validate that is no
|
|
// longer seen in the emitted RA.
|
|
|
|
AdvanceTime(350 * 1000);
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Add(customPrefix);
|
|
|
|
AdvanceTime(200 * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference));
|
|
VerifyOrQuit(prefix == customPrefix);
|
|
VerifyOrQuit(preference == NetworkData::kRoutePreferenceHigh);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Switch back to `kOmrConfigDiable` mode. Check that custom prefix is
|
|
// removed from Network Data and we see it deprecating in emitted RAs.
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigDisabled, nullptr, preference));
|
|
|
|
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
|
|
VerifyOrQuit(omrConfig == kOmrConfigDisabled);
|
|
|
|
AdvanceTime(100);
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(customPrefix);
|
|
|
|
AdvanceTime(60 * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceLow);
|
|
|
|
VerifyNoOmrPrefixInNetData();
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference));
|
|
VerifyOrQuit(prefix.GetLength() == 0);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Switch back to `kOmrConfigAuto` mode.
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigAuto, nullptr, preference));
|
|
|
|
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
|
|
VerifyOrQuit(omrConfig == kOmrConfigAuto);
|
|
|
|
AdvanceTime(100);
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
sExpectedRios.Add(customPrefix);
|
|
|
|
AdvanceTime(60 * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
|
|
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
|
|
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
|
|
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow);
|
|
|
|
preference = NetworkData::kRoutePreferenceLow;
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false, &preference);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference));
|
|
VerifyOrQuit(prefix == localOmr);
|
|
VerifyOrQuit(preference == NetworkData::kRoutePreferenceLow);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestOmrConfig");
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestDefaultRoute(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
|
|
Ip6::Prefix defaultRoute = PrefixFromString("::", 0);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
NetworkData::OnMeshPrefixConfig prefixConfig;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDefaultRoute");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and ULA prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A advertising a default route.
|
|
|
|
SendRouterAdvert(routerAddressA, DefaultRoute(kValidLitime, NetworkData::kRoutePreferenceLow));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure default route
|
|
// from router A is in the table.
|
|
|
|
VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should not see default route in
|
|
// Network Data yet since there is no infrastructure-derived
|
|
// OMR prefix (with preference medium or higher).
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Add an OMR prefix directly into Network Data with
|
|
// preference medium (infrastructure-derived).
|
|
|
|
prefixConfig.Clear();
|
|
prefixConfig.mPrefix = omrPrefix;
|
|
prefixConfig.mStable = true;
|
|
prefixConfig.mSlaac = true;
|
|
prefixConfig.mPreferred = true;
|
|
prefixConfig.mOnMesh = true;
|
|
prefixConfig.mDefaultRoute = true;
|
|
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
|
|
|
|
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. Now that we have an infrastructure-derived
|
|
// OMR prefix, the default route should be published.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the OMR prefix from Network Data.
|
|
|
|
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &omrPrefix));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should again go back to ULA prefix. The
|
|
// default route advertised by router A should be still present in
|
|
// the discovered prefix table.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Add the OMR prefix again.
|
|
|
|
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. Again the default route should be published.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A removing the default route.
|
|
|
|
SendRouterAdvert(routerAddressA, DefaultRoute(0, NetworkData::kRoutePreferenceLow));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPrefixTableIsEmpty();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. Now that router A no longer advertised
|
|
// a default-route, we should go back to publishing ULA route.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A again advertising a default route.
|
|
|
|
SendRouterAdvert(routerAddressA, DefaultRoute(kValidLitime, NetworkData::kRoutePreferenceLow));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPrefixTable({RoutePrefix(defaultRoute, kValidLitime, NetworkData::kRoutePreferenceLow, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should see default route published.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
// Remove the manually added on-mesh prefix with a default route.
|
|
// This ensures the device is no longer considered a BR, so its heap
|
|
// allocation in `NetDataBrTracker` is released. Otherwise, the
|
|
// `heapAllocations` check would fail.
|
|
|
|
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &prefixConfig.mPrefix));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDefaultRoute");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestNonUlaPioWithOnlyOnLinkFlag(void)
|
|
{
|
|
static constexpr uint32_t kMaxRaTxInterval = 196; // In seconds
|
|
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestNonUlaPioWithOnlyOnLinkFlag");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the Network Data to include the local OMR and on-link prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with a new on-link (PIO) with
|
|
// only on-link (L) flag (no A or P).
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime, Pio::kOnLinkFlag)});
|
|
|
|
sRaValidated = false;
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure info from router A
|
|
// is present in the table.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the Network Data. Now that we have observed a non-ULA
|
|
// on-link prefix (even with only on-link `L` flag), a default
|
|
// route should be published.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that BR is still advertising its local on-link prefix.
|
|
|
|
AdvanceTime(kMaxRaTxInterval * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disallow responding to NS messages. This should cause
|
|
// the router A to be deemed unreachable and its prefix
|
|
// entries aged out and then removed.
|
|
|
|
sRespondToNs = false;
|
|
|
|
AdvanceTime(kValidLitime * 1000 + 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that the discovered prefix table is now empty.
|
|
|
|
VerifyPrefixTableIsEmpty();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate that the BR is no longer publishing a default route.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestNonUlaPioWithOnlyOnLinkFlag");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestAdvNonUlaRoute(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
|
|
Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
NetworkData::OnMeshPrefixConfig prefixConfig;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestAdvNonUlaRoute");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and ULA prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A advertising a non-ULA.
|
|
|
|
SendRouterAdvert(routerAddressA, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure the non-ULA
|
|
// from router A is in the table.
|
|
|
|
VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should not see default route in
|
|
// Network Data yet since there is no infrastructure-derived
|
|
// OMR prefix (with preference medium or higher).
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Add an OMR prefix directly into Network Data with
|
|
// preference medium (infrastructure-derived).
|
|
|
|
prefixConfig.Clear();
|
|
prefixConfig.mPrefix = omrPrefix;
|
|
prefixConfig.mStable = true;
|
|
prefixConfig.mSlaac = true;
|
|
prefixConfig.mPreferred = true;
|
|
prefixConfig.mOnMesh = true;
|
|
prefixConfig.mDefaultRoute = true;
|
|
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
|
|
|
|
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. Now that we have an infrastructure-derived
|
|
// OMR prefix, the default route should be published.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the OMR prefix from Network Data.
|
|
|
|
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &omrPrefix));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should again go back to ULA prefix. The
|
|
// non-ULA route advertised by router A should be still present in
|
|
// the discovered prefix table.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Add the OMR prefix again.
|
|
|
|
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(10000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. Again the default route should be published.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A removing the route.
|
|
|
|
SendRouterAdvert(routerAddressA, {Rio(routePrefix, 0, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPrefixTableIsEmpty();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. Now that router A no longer advertised
|
|
// the route, we should go back to publishing the ULA route.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A again advertising the route again.
|
|
|
|
SendRouterAdvert(routerAddressA, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPrefixTable({RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should see default route published.
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
// Remove the manually added on-mesh prefix with a default route.
|
|
// This ensures the device is no longer considered a BR, so its
|
|
// heap allocation in `NetDataBrTracker` is released. Otherwise,
|
|
// the `heapAllocations` check would fail.
|
|
|
|
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &prefixConfig.mPrefix));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestAdvNonUlaRoute");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestFavoredOnLinkPrefix(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefixA = PrefixFromString("2000:abba:baba:aaaa::", 64);
|
|
Ip6::Prefix onLinkPrefixB = PrefixFromString("2000:abba:baba:bbbb::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestFavoredOnLinkPrefix");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
VerifyFavoredOnLinkPrefix(localOnLink);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Advertise on-link prefix B from router B
|
|
|
|
SendRouterAdvert(routerAddressB, {Pio(onLinkPrefixB, kValidLitime, kPreferredLifetime)});
|
|
|
|
AdvanceTime(10 * 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure on-link prefix B is
|
|
// now the favored on-link prefix
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefixB, kValidLitime, kPreferredLifetime, routerAddressB)});
|
|
VerifyFavoredOnLinkPrefix(onLinkPrefixB);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Advertise on-link prefix A from router A with a short
|
|
// preferred lifetime (less than 1800 which is the threshold for it
|
|
// to be considered a valid favored on-link prefix).
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefixA, kValidLitime, 1799)});
|
|
|
|
AdvanceTime(10 * 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure on-link prefix B is
|
|
// still the favored on-link prefix.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefixB, kValidLitime, kPreferredLifetime, routerAddressB),
|
|
OnLinkPrefix(onLinkPrefixA, kValidLitime, 1799, routerAddressA)});
|
|
|
|
VerifyFavoredOnLinkPrefix(onLinkPrefixB);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Advertise on-link prefix A from router A with a long
|
|
// preferred lifetime now.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefixA, kValidLitime, kPreferredLifetime)});
|
|
|
|
AdvanceTime(10 * 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure that now on-link
|
|
// prefix A (which is numerically smaller) is considered as
|
|
// favored on-link prefix.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefixB, kValidLitime, kPreferredLifetime, routerAddressB),
|
|
OnLinkPrefix(onLinkPrefixA, kValidLitime, kPreferredLifetime, routerAddressA)});
|
|
|
|
VerifyFavoredOnLinkPrefix(onLinkPrefixA);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Deprecate on-link prefix A from router A
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefixA, kValidLitime, 0)});
|
|
|
|
AdvanceTime(10 * 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure that now on-link
|
|
// prefix B is again the favored on-link prefix.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefixB, kValidLitime, kPreferredLifetime, routerAddressB),
|
|
OnLinkPrefix(onLinkPrefixA, kValidLitime, 0, routerAddressA)});
|
|
|
|
VerifyFavoredOnLinkPrefix(onLinkPrefixB);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestFavoredOnLinkPrefix");
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestLocalOnLinkPrefixDeprecation(void)
|
|
{
|
|
static constexpr uint32_t kMaxRaTxInterval = 196; // In seconds
|
|
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("fd00:abba:baba::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
uint32_t localOnLinkLifetime;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestLocalOnLinkPrefixDeprecation");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Local on-link prefix is being advertised, lifetime: %d", sOnLinkLifetime);
|
|
localOnLinkLifetime = sOnLinkLifetime;
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and on-link prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with a new on-link (PIO) which is preferred over
|
|
// the local on-link prefix.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kInfiniteLifetime, kInfiniteLifetime)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that the local on-link prefix is now deprecating in the new RA.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(10000);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime);
|
|
VerifyOrQuit(sOnLinkLifetime < localOnLinkLifetime);
|
|
localOnLinkLifetime = sOnLinkLifetime;
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We must see the new on-link prefix from router A
|
|
// along with the deprecating local on-link prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for local on-link prefix to expire
|
|
|
|
while (localOnLinkLifetime > kMaxRaTxInterval)
|
|
{
|
|
// Send same RA from router A to keep the on-link prefix alive.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
// Ensure Network Data entries remain as before. Mainly we still
|
|
// see the deprecating local on-link prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kSkipAdvPioCheck);
|
|
|
|
// Keep checking the emitted RAs and make sure on-link prefix
|
|
// is included with smaller lifetime every time.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(kMaxRaTxInterval * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime);
|
|
VerifyOrQuit(sOnLinkLifetime < localOnLinkLifetime);
|
|
localOnLinkLifetime = sOnLinkLifetime;
|
|
}
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// The local on-link prefix must be expired and should no
|
|
// longer be seen in the emitted RA message.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kNoPio;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(kMaxRaTxInterval * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("On-link prefix is now expired");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioCleared);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestLocalOnLinkPrefixDeprecation");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestExtPanIdChange(void)
|
|
{
|
|
static constexpr uint32_t kMaxRaTxInterval = 196; // In seconds
|
|
|
|
static const otExtendedPanId kExtPanId1 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x08}};
|
|
static const otExtendedPanId kExtPanId2 = {{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x99, 0x88}};
|
|
static const otExtendedPanId kExtPanId3 = {{0x12, 0x34, 0x56, 0x78, 0x9a, 0xab, 0xcd, 0xef}};
|
|
static const otExtendedPanId kExtPanId4 = {{0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00}};
|
|
static const otExtendedPanId kExtPanId5 = {{0x77, 0x88, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55}};
|
|
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix oldLocalOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
uint32_t oldPrefixLifetime;
|
|
Ip6::Prefix oldPrefixes[4];
|
|
otOperationalDataset dataset;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestExtPanIdChange");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Local on-link prefix is being advertised, lifetime: %d", sOnLinkLifetime);
|
|
|
|
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
|
// Check behavior when ext PAN ID changes while the local on-link is
|
|
// being advertised.
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Change the extended PAN ID.
|
|
|
|
Log("Changing ext PAN ID");
|
|
|
|
oldLocalOnLink = localOnLink;
|
|
oldPrefixLifetime = sOnLinkLifetime;
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
SuccessOrQuit(otDatasetGetActive(sInstance, &dataset));
|
|
|
|
VerifyOrQuit(dataset.mComponents.mIsExtendedPanIdPresent);
|
|
|
|
dataset.mExtendedPanId = kExtPanId1;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
AdvanceTime(500);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
Log("Local on-link prefix changed to %s from %s", localOnLink.ToString().AsCString(),
|
|
oldLocalOnLink.ToString().AsCString());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate the received RA message and that it contains the
|
|
// old on-link prefix being deprecated.
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink);
|
|
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate Network Data.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Stop BR and validate that a final RA is emitted deprecating
|
|
// both current local on-link prefix and old prefix.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(100);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink);
|
|
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
|
|
|
|
sRaValidated = false;
|
|
AdvanceTime(350000);
|
|
VerifyOrQuit(!sRaValidated);
|
|
|
|
VerifyNoOmrPrefixInNetData();
|
|
VerifyExternalRouteInNetData(kNoRoute);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start BR again and validate old prefix will continue to
|
|
// be deprecated.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
AdvanceTime(300000);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink);
|
|
VerifyOrQuit(oldPrefixLifetime > sDeprecatingPrefixes[0].mLifetime);
|
|
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for old local on-link prefix to expire.
|
|
|
|
while (oldPrefixLifetime > 2 * kMaxRaTxInterval)
|
|
{
|
|
// Ensure Network Data entries remain as before.
|
|
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
// Keep checking the emitted RAs and make sure the prefix
|
|
// is included with smaller lifetime every time.
|
|
|
|
sRaValidated = false;
|
|
|
|
AdvanceTime(kMaxRaTxInterval * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
Log("Old on-link prefix is deprecating, remaining lifetime:%d", sDeprecatingPrefixes[0].mLifetime);
|
|
VerifyOrQuit(sDeprecatingPrefixes[0].mLifetime < oldPrefixLifetime);
|
|
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
|
|
}
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// The local on-link prefix must be expired now and should no
|
|
// longer be seen in the emitted RA message.
|
|
|
|
sRaValidated = false;
|
|
|
|
AdvanceTime(3 * kMaxRaTxInterval * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.IsEmpty());
|
|
Log("Old on-link prefix is now expired");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate the Network Data.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
|
// Check behavior when ext PAN ID changes while the local on-link is being
|
|
// deprecated.
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with a new on-link (PIO) which is preferred over
|
|
// the local on-link prefix.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate that the local on-link prefix is deprecated.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Change the extended PAN ID.
|
|
|
|
oldLocalOnLink = localOnLink;
|
|
oldPrefixLifetime = sOnLinkLifetime;
|
|
|
|
dataset.mExtendedPanId = kExtPanId2;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
AdvanceTime(500);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
Log("Local on-link prefix changed to %s from %s", localOnLink.ToString().AsCString(),
|
|
oldLocalOnLink.ToString().AsCString());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate that the old local on-link prefix is still being included
|
|
// as PIO in the emitted RA.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kNoPio;
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
VerifyOrQuit(sDeprecatingPrefixes[0].mPrefix == oldLocalOnLink);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate that Network Data.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for old local on-link prefix to expire.
|
|
|
|
while (oldPrefixLifetime > 2 * kMaxRaTxInterval)
|
|
{
|
|
// Send same RA from router A to keep its on-link prefix alive.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
// Ensure Network Data entries remain as before.
|
|
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
|
|
|
|
// Keep checking the emitted RAs and make sure the prefix
|
|
// is included with smaller lifetime every time.
|
|
|
|
sRaValidated = false;
|
|
|
|
AdvanceTime(kMaxRaTxInterval * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
Log("Old on-link prefix is deprecating, remaining lifetime:%d", sDeprecatingPrefixes[0].mLifetime);
|
|
VerifyOrQuit(sDeprecatingPrefixes[0].mLifetime < oldPrefixLifetime);
|
|
oldPrefixLifetime = sDeprecatingPrefixes[0].mLifetime;
|
|
}
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// The old on-link prefix must be expired now and should no
|
|
// longer be seen in the emitted RA message.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sRaValidated = false;
|
|
|
|
AdvanceTime(kMaxRaTxInterval * 1000);
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
AdvanceTime(kMaxRaTxInterval * 1000);
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
AdvanceTime(kMaxRaTxInterval * 1000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.IsEmpty());
|
|
Log("Old on-link prefix is now expired");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate the Network Data.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
|
|
|
|
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
|
// Check behavior when ext PAN ID changes while the local on-link is not
|
|
// advertised.
|
|
|
|
Log("Changing ext PAN ID again");
|
|
|
|
oldLocalOnLink = localOnLink;
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kNoPio;
|
|
|
|
dataset.mExtendedPanId = kExtPanId3;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
AdvanceTime(500);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
Log("Local on-link prefix changed to %s from %s", localOnLink.ToString().AsCString(),
|
|
oldLocalOnLink.ToString().AsCString());
|
|
|
|
AdvanceTime(35000);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.IsEmpty());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate the Network Data.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the on-link prefix PIO being advertised by router A
|
|
// and ensure local on-link prefix is advertised again.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, 0)});
|
|
|
|
AdvanceTime(300000);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.IsEmpty());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for longer than valid lifetime of PIO entry from router A.
|
|
// Validate that default route is unpublished from network data.
|
|
|
|
AdvanceTime(2000 * 1000);
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
|
// Multiple PAN ID changes and multiple deprecating old prefixes.
|
|
|
|
oldPrefixes[0] = localOnLink;
|
|
|
|
dataset.mExtendedPanId = kExtPanId2;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
|
|
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Change the prefix again. We should see two deprecating prefixes.
|
|
|
|
oldPrefixes[1] = localOnLink;
|
|
|
|
dataset.mExtendedPanId = kExtPanId1;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 2);
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
|
|
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for 15 minutes and then change ext PAN ID again.
|
|
// Now we should see three deprecating prefixes.
|
|
|
|
AdvanceTime(15 * 60 * 1000);
|
|
|
|
oldPrefixes[2] = localOnLink;
|
|
|
|
dataset.mExtendedPanId = kExtPanId4;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 3);
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[2]));
|
|
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Change ext PAN ID back to previous value of `kExtPanId1`.
|
|
// We should still see three deprecating prefixes and the last prefix
|
|
// at `oldPrefixes[2]` should again be treated as local on-link prefix.
|
|
|
|
oldPrefixes[3] = localOnLink;
|
|
|
|
dataset.mExtendedPanId = kExtPanId1;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 3);
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
|
|
VerifyOrQuit(oldPrefixes[2] == localOnLink);
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3]));
|
|
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Stop BR and validate the final emitted RA to contain
|
|
// all deprecating prefixes.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(100);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 3);
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3]));
|
|
|
|
VerifyNoOmrPrefixInNetData();
|
|
VerifyExternalRouteInNetData(kNoRoute);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for 15 minutes while BR stays disabled and validate
|
|
// there are no emitted RAs. We want to check that deprecating
|
|
// prefixes continue to expire while BR is stopped.
|
|
|
|
sRaValidated = false;
|
|
AdvanceTime(15 * 60 * 1000);
|
|
|
|
VerifyOrQuit(!sRaValidated);
|
|
|
|
VerifyNoOmrPrefixInNetData();
|
|
VerifyExternalRouteInNetData(kNoRoute);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start BR again, and check that we only see the last deprecating prefix
|
|
// at `oldPrefixes[3]` in emitted RA and the other two are expired and
|
|
// no longer included as PIO and/or in network data.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[3]));
|
|
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
|
// Validate the oldest prefix is removed when we have too many
|
|
// back-to-back PAN ID changes.
|
|
|
|
// Remember the oldest deprecating prefix (associated with `kExtPanId4`).
|
|
oldLocalOnLink = oldPrefixes[3];
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(oldPrefixes[0]));
|
|
dataset.mExtendedPanId = kExtPanId2;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
AdvanceTime(30000);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(oldPrefixes[1]));
|
|
dataset.mExtendedPanId = kExtPanId3;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
AdvanceTime(30000);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(oldPrefixes[2]));
|
|
dataset.mExtendedPanId = kExtPanId5;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
sRaValidated = false;
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 3);
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[0]));
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[1]));
|
|
VerifyOrQuit(sDeprecatingPrefixes.ContainsMatching(oldPrefixes[2]));
|
|
VerifyOrQuit(!sDeprecatingPrefixes.ContainsMatching(oldLocalOnLink));
|
|
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestExtPanIdChange");
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestPrefixStaleTime(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefixA = PrefixFromString("2000:abba:baba:aaaa::", 64);
|
|
Ip6::Prefix onLinkPrefixB = PrefixFromString("2000:abba:baba:bbbb::", 64);
|
|
Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestPrefixStaleTime");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Advertise a route prefix with 200 seconds lifetime from router A.
|
|
// Advertise the same route prefix with 800 seconds lifetime from
|
|
// router B.
|
|
|
|
SendRouterAdvert(routerAddressA, {Rio(routePrefix, 200, NetworkData::kRoutePreferenceMedium)});
|
|
SendRouterAdvert(routerAddressB, {Rio(routePrefix, 800, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
AdvanceTime(10);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure info from router A and B
|
|
// is present in the table.
|
|
|
|
VerifyPrefixTable({RoutePrefix(routePrefix, 200, NetworkData::kRoutePreferenceMedium, routerAddressA),
|
|
RoutePrefix(routePrefix, 800, NetworkData::kRoutePreferenceMedium, routerAddressB)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for a period exceeding the 200-second lifetime of the route
|
|
// advertised by router A. Confirm that the stale timer does not expire
|
|
// during this time, and no RS messages sent. This verifies that the
|
|
// presence of the matching entry from router B successfully extended
|
|
// the stale time for the route prefix.
|
|
|
|
sRsEmitted = false;
|
|
|
|
AdvanceTime(590 * 1000);
|
|
|
|
VerifyOrQuit(!sRsEmitted);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure router A entry is
|
|
// expired and removed.
|
|
|
|
VerifyPrefixTable({RoutePrefix(routePrefix, 800, NetworkData::kRoutePreferenceMedium, routerAddressB)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for the 600-second stale time to expire. This is shorter
|
|
// than the 800-second lifetime of the prefix advertised by
|
|
// Router B, so the 600-second value will be used. We should now
|
|
// observe RS messages being transmitted.
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
|
|
VerifyPrefixTableIsEmpty();
|
|
|
|
AdvanceTime(5 * 000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Advertise the same on-link prefix A with different lifetimes from routers A and B.
|
|
// Advertise a different on-link prefix from router A.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefixA, 1800, 200), Pio(onLinkPrefixB, 2000, 2000)});
|
|
SendRouterAdvert(routerAddressB, {Pio(onLinkPrefixA, 1800, 500)});
|
|
|
|
AdvanceTime(10);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure info from router A and B
|
|
// is present in the table.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefixA, 1800, 200, routerAddressA),
|
|
OnLinkPrefix(onLinkPrefixB, 2000, 2000, routerAddressA),
|
|
OnLinkPrefix(onLinkPrefixA, 1800, 500, routerAddressB)});
|
|
|
|
sRsEmitted = false;
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for a period exceeding the 200-second lifetime of the on-link prefix.
|
|
// Confirm stale timer is not expired and no RS is emitted.
|
|
|
|
sRsEmitted = false;
|
|
|
|
AdvanceTime(490 * 1000);
|
|
|
|
VerifyOrQuit(!sRsEmitted);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for a 500-second lifetime for prefix advertised by router B. Now
|
|
// we should see RS messages emitted.
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestPrefixStaleTime");
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestRouterNsProbe(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
Ip6::Prefix routePrefix = PrefixFromString("2000:1234:5678::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestRouterNsProbe");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with a new on-link (PIO) and route prefix (RIO).
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
|
|
{Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
AdvanceTime(10);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure info from router A
|
|
// is present in the table.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
|
|
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA)});
|
|
|
|
AdvanceTime(30000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router B with same route prefix (RIO) but with
|
|
// high route preference.
|
|
|
|
SendRouterAdvert(routerAddressB, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh)});
|
|
|
|
AdvanceTime(200);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table and ensure entries from
|
|
// both router A and B are seen.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)},
|
|
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceMedium, routerAddressA),
|
|
RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh, routerAddressB)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that BR emitted an NS to ensure routers are active.
|
|
|
|
sNsEmitted = false;
|
|
sRsEmitted = false;
|
|
|
|
AdvanceTime(160 * 1000);
|
|
|
|
VerifyOrQuit(sNsEmitted);
|
|
VerifyOrQuit(!sRsEmitted);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disallow responding to NS message.
|
|
//
|
|
// This should trigger `RoutingManager` to send RS (which will get
|
|
// no response as well) and then remove all router entries.
|
|
|
|
sRespondToNs = false;
|
|
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sRaValidated = false;
|
|
sNsEmitted = false;
|
|
|
|
AdvanceTime(240 * 1000);
|
|
|
|
VerifyOrQuit(sNsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check the discovered prefix table. We should see the on-link entry from
|
|
// router A as deprecated and no route prefix.
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, 0, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Verify that no more NS is being sent (since there is no more valid
|
|
// router entry in the table).
|
|
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sRaValidated = false;
|
|
sNsEmitted = false;
|
|
|
|
AdvanceTime(6 * 60 * 1000);
|
|
|
|
VerifyOrQuit(!sNsEmitted);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router B and verify that we see router B
|
|
// entry in prefix table.
|
|
|
|
SendRouterAdvert(routerAddressB, {Rio(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh)});
|
|
|
|
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, 0, routerAddressA)},
|
|
{RoutePrefix(routePrefix, kValidLitime, NetworkData::kRoutePreferenceHigh, routerAddressB)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for longer than router active time before NS probe.
|
|
// Check again that NS are sent again.
|
|
|
|
sRespondToNs = true;
|
|
sNsEmitted = false;
|
|
sRsEmitted = false;
|
|
|
|
AdvanceTime(3 * 60 * 1000);
|
|
|
|
VerifyOrQuit(sNsEmitted);
|
|
VerifyOrQuit(!sRsEmitted);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestRouterNsProbe");
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestLearningAndCopyingOfFlags(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
|
|
Ip6::Address routerAddressC = AddressFromString("fd00::cccc");
|
|
uint16_t heapAllocations;
|
|
RaFlags raFlags;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestLearningAndCopyingOfFlags");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
VerifyDiscoveredRoutersIsEmpty();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with M flag set, and make sure the
|
|
// emitted RA from BR also includes M flag.
|
|
|
|
raFlags.Clear();
|
|
raFlags.mManagedAddressConfigFlag = true;
|
|
|
|
SendRouterAdvert(routerAddressA, raFlags);
|
|
|
|
AdvanceTime(1);
|
|
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* S */ false)});
|
|
|
|
sRaValidated = false;
|
|
sExpectedRaHeaderFlags = kRaHeaderFlagsOnlyM;
|
|
|
|
AdvanceTime(310 * 1000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A without the M flag. Now the emitted
|
|
// RA should no longer contain the M flag.
|
|
|
|
raFlags.Clear();
|
|
|
|
SendRouterAdvert(routerAddressA, raFlags);
|
|
|
|
sRaValidated = false;
|
|
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
|
|
|
|
AdvanceTime(1);
|
|
VerifyDiscoveredRoutersIsEmpty();
|
|
|
|
AdvanceTime(310 * 1000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with both M and S flags.
|
|
// Since it is from a stub router, the M flag should be ignored.
|
|
// Ensure emitted RA does not set the M flag.
|
|
|
|
raFlags.Clear();
|
|
raFlags.mManagedAddressConfigFlag = true;
|
|
raFlags.mSnacRouterFlag = true;
|
|
|
|
SendRouterAdvert(routerAddressA, raFlags);
|
|
|
|
AdvanceTime(1);
|
|
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* S */ true)});
|
|
|
|
sRaValidated = false;
|
|
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
|
|
|
|
AdvanceTime(310 * 1000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router B with O flag and check that emitted
|
|
// RA include the same flag.
|
|
|
|
raFlags.Clear();
|
|
raFlags.mOtherConfigFlag = true;
|
|
|
|
SendRouterAdvert(routerAddressB, raFlags);
|
|
|
|
AdvanceTime(1);
|
|
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* S */ true),
|
|
InfraRouter(routerAddressB, /* M */ false, /* O */ true, /* S */ false)});
|
|
|
|
sRaValidated = false;
|
|
sExpectedRaHeaderFlags = kRaHeaderFlagsOnlyO;
|
|
|
|
AdvanceTime(310 * 1000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router C with M flag and check that emitted
|
|
// RA now includes both M and O flags.
|
|
|
|
raFlags.Clear();
|
|
raFlags.mManagedAddressConfigFlag = true;
|
|
|
|
SendRouterAdvert(routerAddressC, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
|
|
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), raFlags);
|
|
|
|
AdvanceTime(1);
|
|
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* S */ true),
|
|
InfraRouter(routerAddressB, /* M */ false, /* O */ true, /* S */ false),
|
|
InfraRouter(routerAddressC, /* M */ true, /* O */ false, /* S */ false)});
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
sExpectedRaHeaderFlags = kRaHeaderFlagsBothMAndO;
|
|
|
|
AdvanceTime(310 * 1000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Stop responding to NS, this should cause all routers
|
|
// to age and considered offline
|
|
|
|
sRespondToNs = false;
|
|
|
|
sExpectedRaHeaderFlags = kRaHeaderFlagsSkipChecking;
|
|
|
|
AdvanceTime(300 * 1000);
|
|
|
|
// Router C should be in the table since it will have a deprecating
|
|
// on-link prefix.
|
|
VerifyDiscoveredRouters({InfraRouter(routerAddressC, /* M */ true, /* O */ false, /* S */ false)});
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
|
|
|
|
AdvanceTime(610 * 1000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
VerifyDiscoveredRoutersIsEmpty();
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestLearningAndCopyingOfFlags");
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestLearnRaHeader(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestLearnRaHeader");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
VerifyDiscoveredRoutersIsEmpty();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from the same address (another entity on the device)
|
|
// advertising a default route.
|
|
|
|
SendRouterAdvert(sInfraIfAddress, DefaultRoute(1000, NetworkData::kRoutePreferenceLow));
|
|
|
|
AdvanceTime(1);
|
|
VerifyDiscoveredRouters(
|
|
{InfraRouter(sInfraIfAddress, /* M */ false, /* O */ false, /* S */ false, /* IsLocalDevice */ true)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// RoutingManager should learn the header from the
|
|
// received RA (from same address) and start advertising
|
|
// the same default route lifetime in the emitted RAs.
|
|
|
|
sRaValidated = false;
|
|
sCheckRaHeaderLifetime = true;
|
|
sExpectedRaHeaderLifetime = 1000;
|
|
|
|
AdvanceTime(30 * 1000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for longer than entry lifetime (for it to expire) and
|
|
// make sure `RoutingManager` stops advertising default route.
|
|
|
|
sCheckRaHeaderLifetime = false;
|
|
|
|
AdvanceTime(1000 * 1000);
|
|
|
|
sRaValidated = false;
|
|
sCheckRaHeaderLifetime = true;
|
|
sExpectedRaHeaderLifetime = 0;
|
|
|
|
AdvanceTime(700 * 1000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
VerifyDiscoveredRoutersIsEmpty();
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestLearnRaHeader");
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestConflictingPrefix(void)
|
|
{
|
|
static const otExtendedPanId kExtPanId1 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x08}};
|
|
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix oldLocalOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
|
|
otOperationalDataset dataset;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestConflictingPrefix");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and on-link prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with our local on-link prefix as RIO.
|
|
|
|
Log("Send RA from router A with local on-link as RIO");
|
|
SendRouterAdvert(routerAddressA, {Rio(localOnLink, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that the local on-link prefix is still being advertised.
|
|
|
|
sRaValidated = false;
|
|
AdvanceTime(310000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to still include the local OMR and ULA prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A removing local on-link prefix as RIO.
|
|
|
|
SendRouterAdvert(routerAddressA, {Rio(localOnLink, 0, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Verify that ULA prefix is still included in Network Data and
|
|
// the change by router A did not cause it to be unpublished.
|
|
|
|
AdvanceTime(10000);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that the local on-link prefix is still being advertised.
|
|
|
|
sRaValidated = false;
|
|
AdvanceTime(310000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router B advertising an on-link prefix. This
|
|
// should cause local on-link prefix to be deprecated.
|
|
|
|
SendRouterAdvert(routerAddressB, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that the local on-link prefix is now deprecating.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
AdvanceTime(10000);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("On-link prefix is deprecating, remaining lifetime:%d", sOnLinkLifetime);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the default route now due
|
|
// the new on-link prefix from router B.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A again adding local on-link prefix as RIO.
|
|
|
|
Log("Send RA from router A with local on-link as RIO");
|
|
SendRouterAdvert(routerAddressA, {Rio(localOnLink, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that the local on-link prefix is still being deprecated.
|
|
|
|
sRaValidated = false;
|
|
AdvanceTime(310000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data remains unchanged.
|
|
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A removing the previous RIO.
|
|
|
|
SendRouterAdvert(routerAddressA, {Rio(localOnLink, 0, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data remains unchanged.
|
|
|
|
AdvanceTime(60000);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router B removing its on-link prefix.
|
|
|
|
SendRouterAdvert(routerAddressB, {Pio(onLinkPrefix, kValidLitime, 0)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that the local on-link prefix is once again being advertised.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
AdvanceTime(10000);
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to remain unchanged.
|
|
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Change the extended PAN ID.
|
|
|
|
Log("Changing ext PAN ID");
|
|
|
|
SuccessOrQuit(otDatasetGetActive(sInstance, &dataset));
|
|
|
|
VerifyOrQuit(dataset.mComponents.mIsExtendedPanIdPresent);
|
|
|
|
dataset.mExtendedPanId = kExtPanId1;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
AdvanceTime(10000);
|
|
|
|
oldLocalOnLink = localOnLink;
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
|
|
Log("Local on-link prefix is changed to %s from %s", localOnLink.ToString().AsCString(),
|
|
oldLocalOnLink.ToString().AsCString());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data contains default route due to the
|
|
// deprecating on-link prefix from router B.
|
|
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A again adding the old local on-link prefix
|
|
// as RIO.
|
|
|
|
SendRouterAdvert(routerAddressA, {Rio(oldLocalOnLink, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data remains unchanged.
|
|
|
|
AdvanceTime(10000);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A removing the previous RIO.
|
|
|
|
SendRouterAdvert(routerAddressA, {Rio(localOnLink, 0, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data remains unchanged.
|
|
|
|
AdvanceTime(10000);
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestConflictingPrefix");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
#if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
|
void TestSavedOnLinkPrefixes(void)
|
|
{
|
|
static const otExtendedPanId kExtPanId1 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x08}};
|
|
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix oldLocalOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
otOperationalDataset dataset;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestSavedOnLinkPrefixes");
|
|
|
|
InitTest(/* aEnablBorderRouting */ true);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and ULA prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable the instance and re-enable it.
|
|
|
|
Log("Disabling and re-enabling OT Instance");
|
|
|
|
testFreeInstance(sInstance);
|
|
|
|
InitTest(/* aEnablBorderRouting */ true, /* aAfterReset */ true);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and ULA prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A advertising an on-link prefix.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 0);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable the instance and re-enable it.
|
|
|
|
Log("Disabling and re-enabling OT Instance");
|
|
|
|
InitTest(/* aEnablBorderRouting */ true, /* aResetInstance */ true);
|
|
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and ULA prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Log("Changing ext PAN ID");
|
|
|
|
oldLocalOnLink = localOnLink;
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
|
|
SuccessOrQuit(otDatasetGetActive(sInstance, &dataset));
|
|
|
|
VerifyOrQuit(dataset.mComponents.mIsExtendedPanIdPresent);
|
|
|
|
dataset.mExtendedPanId = kExtPanId1;
|
|
dataset.mActiveTimestamp.mSeconds++;
|
|
SuccessOrQuit(otDatasetSetActive(sInstance, &dataset));
|
|
|
|
AdvanceTime(30000);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
Log("Local on-link prefix changed to %s from %s", localOnLink.ToString().AsCString(),
|
|
oldLocalOnLink.ToString().AsCString());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable the instance and re-enable it.
|
|
|
|
Log("Disabling and re-enabling OT Instance");
|
|
|
|
InitTest(/* aEnablBorderRouting */ false, /* aResetInstance */ true);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager.
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
AdvanceTime(100);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A advertising an on-link prefix.
|
|
// This ensures the local on-link prefix is not advertised, but
|
|
// it must be deprecated since it was advertised last time and
|
|
// saved in `Settings`.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 1);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to now use default route due to the
|
|
// on-link prefix from router A.
|
|
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for more than 1800 seconds to let the deprecating
|
|
// prefixes expire (keep sending RA from router A).
|
|
|
|
for (uint16_t index = 0; index < 185; index++)
|
|
{
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
AdvanceTime(10 * 1000);
|
|
}
|
|
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable the instance and re-enable it and restart Routing Manager.
|
|
|
|
Log("Disabling and re-enabling OT Instance again");
|
|
|
|
InitTest(/* aEnablBorderRouting */ false, /* aResetInstance */ true);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
AdvanceTime(100);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A advertising an on-link prefix.
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kNoPio;
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sDeprecatingPrefixes.GetLength() == 0);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data still contains the default route.
|
|
|
|
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioCleared);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Log("End of TestSavedOnLinkPrefixes");
|
|
FinalizeTest();
|
|
}
|
|
#endif // OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
|
|
|
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
|
|
void TestAutoEnableOfSrpServer(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestAutoEnableOfSrpServer");
|
|
|
|
InitTest();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check SRP Server state and enable auto-enable mode
|
|
|
|
otSrpServerSetAutoEnableMode(sInstance, true);
|
|
VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance));
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Validate that SRP server was auto-enabled
|
|
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED);
|
|
Log("Srp::Server is enabled");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Signal that infra if state changed and is no longer running.
|
|
// This should stop Routing Manager and in turn the SRP server.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
Log("Signal infra if is not running");
|
|
SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, false));
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that SRP server is disabled.
|
|
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
|
|
Log("Srp::Server is disabled");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Signal that infra if state changed and is running again.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
Log("Signal infra if is running");
|
|
SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, true));
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that SRP server is enabled again.
|
|
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED);
|
|
Log("Srp::Server is enabled");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable `RoutingManager` explicitly.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioDeprecatingLocalOnLink;
|
|
|
|
Log("Disabling RoutingManager");
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that SRP server is also disabled.
|
|
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
|
|
Log("Srp::Server is disabled");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable auto-enable mode on SRP server.
|
|
|
|
otSrpServerSetAutoEnableMode(sInstance, false);
|
|
VerifyOrQuit(!otSrpServerIsAutoEnableMode(sInstance));
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Re-start Routing Manager. Check emitted RS and RA messages.
|
|
// This cycle, router A will send a RA including a PIO.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kNoPio;
|
|
sExpectedRios.Clear();
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(2000);
|
|
|
|
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check that SRP server is still disabled.
|
|
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
|
|
Log("Srp::Server is disabled");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Enable auto-enable mode on SRP server. Since `RoutingManager`
|
|
// is already done with initial policy evaluation, the SRP server
|
|
// must be started immediately.
|
|
|
|
otSrpServerSetAutoEnableMode(sInstance, true);
|
|
VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance));
|
|
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED);
|
|
Log("Srp::Server is enabled");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disable auto-enable mode on SRP server. It must not impact
|
|
// its current state and it should remain enabled.
|
|
|
|
otSrpServerSetAutoEnableMode(sInstance, false);
|
|
VerifyOrQuit(!otSrpServerIsAutoEnableMode(sInstance));
|
|
|
|
AdvanceTime(2000);
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) != OT_SRP_SERVER_STATE_DISABLED);
|
|
Log("Srp::Server is enabled");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Signal that infra if state changed and is no longer running.
|
|
// This should stop Routing Manager.
|
|
|
|
sRaValidated = false;
|
|
|
|
Log("Signal infra if is not running");
|
|
SuccessOrQuit(otPlatInfraIfStateChanged(sInstance, kInfraIfIndex, false));
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Re-enable auto-enable mode on SRP server. Since `RoutingManager`
|
|
// is stopped (infra if is down), the SRP serer must be stopped
|
|
// immediately.
|
|
|
|
otSrpServerSetAutoEnableMode(sInstance, true);
|
|
VerifyOrQuit(otSrpServerIsAutoEnableMode(sInstance));
|
|
|
|
VerifyOrQuit(otSrpServerGetState(sInstance) == OT_SRP_SERVER_STATE_DISABLED);
|
|
Log("Srp::Server is disabled");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() == heapAllocations);
|
|
|
|
Log("End of TestAutoEnableOfSrpServer");
|
|
FinalizeTest();
|
|
}
|
|
#endif // OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
|
|
|
|
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
|
void TestNat64PrefixSelection(void)
|
|
{
|
|
Ip6::Prefix localNat64;
|
|
Ip6::Prefix localOmr;
|
|
NetworkData::OnMeshPrefixConfig prefixConfig;
|
|
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
|
|
Ip6::Prefix platformNat64Prefix = 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("--------------------------------------------------------------------------------------------");
|
|
Log("TestNat64PrefixSelection");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check local NAT64 prefix generation.
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetNat64Prefix(localNat64));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local nat64 prefix is %s", localNat64.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Enable NAT64 Prefix Manager. Check local NAT64 prefix in Network Data.
|
|
|
|
sInstance->Get<BorderRouter::RoutingManager>().SetNat64PrefixManagerEnabled(true);
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyNat64PrefixInNetData(localNat64);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Platform-provided 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(platformNat64Prefix);
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyNat64PrefixInNetData(localNat64);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Add a medium preference OMR prefix into Network Data. Check that the platform-provided NAT64 prefix is now
|
|
// published in Network Data.
|
|
|
|
prefixConfig.Clear();
|
|
prefixConfig.mPrefix = omrPrefix;
|
|
prefixConfig.mStable = true;
|
|
prefixConfig.mSlaac = true;
|
|
prefixConfig.mPreferred = true;
|
|
prefixConfig.mOnMesh = true;
|
|
prefixConfig.mDefaultRoute = false;
|
|
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
|
|
|
|
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
|
VerifyNat64PrefixInNetData(platformNat64Prefix);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from a router advertising a NAT64 prefix. Check that the RA-discovered NAT64 prefix is now favored
|
|
// and published. Check the RA-discovered NAT64 prefix table.
|
|
|
|
VerifyNat64PrefixTableIsEmpty();
|
|
|
|
SendRouterAdvert(routerAddressA, Pref64(raTrackerNat64PrefixA, kValidLitime));
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
|
VerifyNat64PrefixInNetData(raTrackerNat64PrefixA);
|
|
|
|
VerifyNat64PrefixTable({Nat64Prefix(raTrackerNat64PrefixA, kValidLitime, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send two RAs from routers B and C advertising two different NAT64 prefixes. Check that the numerically smallest
|
|
// prefix is now favored. Check the RA-discovered NAT64 prefix table.
|
|
|
|
SendRouterAdvert(routerAddressB, Pref64(raTrackerNat64PrefixB, kValidLitime));
|
|
SendRouterAdvert(routerAddressC, Pref64(raTrackerNat64PrefixC, kValidLitime));
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
|
VerifyNat64PrefixInNetData(raTrackerNat64PrefixB);
|
|
|
|
VerifyNat64PrefixTable({Nat64Prefix(raTrackerNat64PrefixA, kValidLitime, routerAddressA),
|
|
Nat64Prefix(raTrackerNat64PrefixB, kValidLitime, routerAddressB),
|
|
Nat64Prefix(raTrackerNat64PrefixC, kValidLitime, routerAddressC)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove RA-discovered NAT64 prefix A and B from router A and B. Check that the remained RA-discovered prefix C
|
|
// is now favored. Check the RA-discovered NAT64 prefix table.
|
|
|
|
SendRouterAdvert(routerAddressA, Pref64(raTrackerNat64PrefixA, 0));
|
|
SendRouterAdvert(routerAddressB, Pref64(raTrackerNat64PrefixB, 0));
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
|
VerifyNat64PrefixInNetData(raTrackerNat64PrefixC);
|
|
|
|
VerifyNat64PrefixTable({Nat64Prefix(raTrackerNat64PrefixC, kValidLitime, routerAddressC)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove RA-discovered NAT64 prefix C. Check that the infra-if NAT64 prefix is published again. Check the
|
|
// RA-discovered NAT64 prefix table is empty.
|
|
|
|
SendRouterAdvert(routerAddressC, Pref64(raTrackerNat64PrefixC, 0));
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
|
VerifyNat64PrefixInNetData(platformNat64Prefix);
|
|
|
|
VerifyNat64PrefixTableIsEmpty();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Platform-provided NAT64 prefix removed.
|
|
// Check local NAT64 prefix in Network Data.
|
|
|
|
platformNat64Prefix.Clear();
|
|
DiscoverNat64Prefix(platformNat64Prefix);
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
|
VerifyNat64PrefixInNetData(localNat64);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() == heapAllocations);
|
|
|
|
Log("End of TestNat64PrefixSelection");
|
|
FinalizeTest();
|
|
}
|
|
#endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
|
|
|
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
|
|
|
|
void VerifyPdOmrPrefix(const Ip6::Prefix &aPrefix)
|
|
{
|
|
BorderRouter::Dhcp6PdPrefix pdPrefix;
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetDhcp6PdOmrPrefix(pdPrefix));
|
|
VerifyOrQuit(AsCoreType(&pdPrefix.mPrefix) == aPrefix);
|
|
}
|
|
|
|
void VerifyNoPdOmrPrefix(void)
|
|
{
|
|
BorderRouter::Dhcp6PdPrefix pdPrefix;
|
|
|
|
VerifyOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetDhcp6PdOmrPrefix(pdPrefix) == kErrorNotFound);
|
|
}
|
|
|
|
template <uint16_t kNumPios> void ReportPdPrefixesAsRa(const Pio (&aPios)[kNumPios])
|
|
{
|
|
Ip6::Nd::RouterAdvert::TxMessage raMsg;
|
|
Icmp6Packet packet;
|
|
|
|
BuildRouterAdvert(raMsg, aPios, kNumPios, nullptr, 0, nullptr, 0, nullptr, 0,
|
|
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
|
|
raMsg.GetAsPacket(packet);
|
|
|
|
Log("Reporting DHCPv6-PD prefixes as RA");
|
|
LogRouterAdvert(packet);
|
|
|
|
sInstance->Get<BorderRouter::RoutingManager>().ProcessDhcp6PdPrefixesFromRa(packet);
|
|
}
|
|
|
|
void TestDhcp6Pd(void)
|
|
{
|
|
static const uint8_t kInvalidDhcp6Ra1[] = {
|
|
0x86, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t kInvalidDhcp6Ra2[] = {
|
|
0x87, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t kInvalidDhcp6Ra3[] = {
|
|
0x86, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x03, 0x04, 0x41, 0xc0, 0x00, 0x00, 0x10, 0xe1, 0x00, 0x00, 0x04, 0xd2, 0x00, 0x00, 0x00, 0x00,
|
|
0x20, 0x01, 0x0d, 0xb8, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
struct InvalidDhcp6Ra
|
|
{
|
|
const uint8_t *mBytes;
|
|
uint16_t mLength;
|
|
};
|
|
|
|
static const InvalidDhcp6Ra kInvalidDhcp6Ras[] = {
|
|
{kInvalidDhcp6Ra1, sizeof(kInvalidDhcp6Ra1)},
|
|
{kInvalidDhcp6Ra2, sizeof(kInvalidDhcp6Ra2)},
|
|
{kInvalidDhcp6Ra3, sizeof(kInvalidDhcp6Ra3)},
|
|
};
|
|
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix prefix;
|
|
Ip6::Prefix ulaPrefix;
|
|
Ip6::Prefix newPrefix;
|
|
Ip6::Prefix shortPrefix;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6Pd");
|
|
|
|
InitTest(/* aEnableBorderRouting */ true);
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
sInstance->Get<BorderRouter::RoutingManager>().SetDhcp6PdEnabled(true);
|
|
VerifyOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetDhcp6PdState() !=
|
|
BorderRouter::RoutingManager::kDhcp6PdStateDisabled);
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Log("Invalid DHCPv6-PD RA messages");
|
|
|
|
for (const InvalidDhcp6Ra &invalidRa : kInvalidDhcp6Ras)
|
|
{
|
|
Icmp6Packet raPacket;
|
|
|
|
raPacket.Init(invalidRa.mBytes, invalidRa.mLength);
|
|
sInstance->Get<BorderRouter::RoutingManager>().ProcessDhcp6PdPrefixesFromRa(raPacket);
|
|
VerifyNoPdOmrPrefix();
|
|
}
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Log("Single DHCPv6-PD prefix");
|
|
|
|
prefix = PrefixFromString("2001:db8:dead:beef::", 64);
|
|
|
|
ReportPdPrefixesAsRa({Pio(prefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Add(prefix);
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(1500000);
|
|
sExpectedRios.Clear();
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(400000);
|
|
// Deprecated prefixes will be removed.
|
|
VerifyNoPdOmrPrefix();
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Multiple prefixes are reported, ensure favored one is used.
|
|
|
|
Log("Multiple DHCPv6-PD prefixes");
|
|
|
|
prefix = PrefixFromString("2001:db8:dead:beef::", 64);
|
|
ulaPrefix = PrefixFromString("fd01:db8:deaf:beef::", 64);
|
|
|
|
ReportPdPrefixesAsRa(
|
|
{Pio(ulaPrefix, kValidLitime * 2, kPreferredLifetime * 2), Pio(prefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Add(prefix);
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(1500000);
|
|
sExpectedRios.Clear();
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(400000);
|
|
// Deprecated prefixes will be removed.
|
|
VerifyNoPdOmrPrefix();
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
Log("Renew DHCPv6-PD prefix lifetime");
|
|
|
|
prefix = PrefixFromString("2001:db8:1:2::", 64);
|
|
|
|
ReportPdPrefixesAsRa({Pio(prefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Add(prefix);
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(1500000);
|
|
sExpectedRios.Clear();
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
ReportPdPrefixesAsRa({Pio(prefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
AdvanceTime(400000);
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(1500000);
|
|
VerifyNoPdOmrPrefix();
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Report a prefix, and remove it and report a new DHCPv6-PD prefix
|
|
|
|
Log("Update DHCPv6-PD prefix (add then remove and add new)");
|
|
|
|
prefix = PrefixFromString("2001:db8:1:2::", 64);
|
|
newPrefix = PrefixFromString("2001:db8:3:4::", 64);
|
|
|
|
ReportPdPrefixesAsRa({Pio(prefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Add(prefix);
|
|
sExpectedRios.Clear();
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(1000000);
|
|
VerifyPdOmrPrefix(prefix);
|
|
|
|
sExpectedRios.Add(newPrefix);
|
|
|
|
// When the prefix is replaced, there will be a short period when the old prefix is still in the netdata, and PD
|
|
// manager will refuse to request the prefix.
|
|
ReportPdPrefixesAsRa({Pio(prefix, 0, 0), Pio(newPrefix, kValidLitime, kPreferredLifetime)});
|
|
// Advance a short period of time to wait for a stable PD state.
|
|
AdvanceTime(5000);
|
|
VerifyOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetDhcp6PdState() ==
|
|
BorderRouter::RoutingManager::kDhcp6PdStateRunning);
|
|
ReportPdPrefixesAsRa({Pio(newPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
AdvanceTime(1000000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyPdOmrPrefix(newPrefix);
|
|
|
|
AdvanceTime(1000000);
|
|
VerifyNoPdOmrPrefix();
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Report a shorter (/48) prefix, validate it is extended to /64.
|
|
|
|
Log("Short DHCPv6-PD prefix");
|
|
|
|
prefix = PrefixFromString("2001:db8:cafe:0::", 64);
|
|
|
|
shortPrefix.InitFrom(prefix.GetBytes(), 48);
|
|
ReportPdPrefixesAsRa({Pio(shortPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Add(prefix);
|
|
AdvanceTime(10000);
|
|
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(1500000);
|
|
sExpectedRios.Clear();
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(400000);
|
|
VerifyNoPdOmrPrefix();
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Report a prefix with long lifetime, and wait until it expired.
|
|
|
|
Log("Single DHCPv6-PD prefix with long lifetime");
|
|
prefix = PrefixFromString("2001:db8:dead:beef::", 64);
|
|
|
|
ReportPdPrefixesAsRa({Pio(prefix, 5000, 5000)});
|
|
|
|
sExpectedRios.Add(prefix);
|
|
AdvanceTime(10 * 1000);
|
|
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(4900 * 1000);
|
|
sExpectedRios.Clear();
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(200 * 1000);
|
|
// Deprecated prefixes will be removed.
|
|
VerifyNoPdOmrPrefix();
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Replace a prefix: In some platforms there might be no messages to deprecate the old prefix, instead, they
|
|
// send new prefixes directly. In this case, we still use the old prefix as long as the old prefix preferred
|
|
// lifetime is not exceeded, and replace it with the new prefix when expired.
|
|
|
|
Log("Replacing DHCPv6-PD prefix");
|
|
|
|
prefix = PrefixFromString("2001:db8:1:2::", 64);
|
|
newPrefix = PrefixFromString("2001:db8:3:4::", 64);
|
|
|
|
ReportPdPrefixesAsRa({Pio(prefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Add(prefix);
|
|
sExpectedRios.Clear();
|
|
AdvanceTime(10 * 1000);
|
|
|
|
VerifyPdOmrPrefix(prefix);
|
|
VerifyOmrPrefixInNetData(prefix, /* aDefaultRoute */ false);
|
|
|
|
AdvanceTime(1000 * 1000);
|
|
VerifyPdOmrPrefix(prefix);
|
|
|
|
// Send new prefix without deprecating old prefix.
|
|
// The old prefix should be preferred for another (1800 - 10 - 1000) = 790s
|
|
ReportPdPrefixesAsRa({Pio(newPrefix, kValidLitime, kPreferredLifetime)});
|
|
AdvanceTime(500 * 1000);
|
|
VerifyPdOmrPrefix(prefix);
|
|
|
|
AdvanceTime(300 * 1000);
|
|
// Old Prefix should be removed now.
|
|
VerifyNoPdOmrPrefix();
|
|
|
|
sExpectedRios.Add(newPrefix);
|
|
|
|
// When the prefix is replaced, there will be a short period when the old prefix is still in the netdata, and PD
|
|
// manager will refuse to request the prefix.
|
|
ReportPdPrefixesAsRa({Pio(newPrefix, kValidLitime, kPreferredLifetime)});
|
|
// Advance a short period of time to wait for a stable PD state.
|
|
AdvanceTime(5000);
|
|
VerifyOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetDhcp6PdState() ==
|
|
BorderRouter::RoutingManager::kDhcp6PdStateRunning);
|
|
ReportPdPrefixesAsRa({Pio(newPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
AdvanceTime(1000 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyPdOmrPrefix(newPrefix);
|
|
|
|
AdvanceTime(1000 * 1000);
|
|
VerifyNoPdOmrPrefix();
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of TestDhcp6Pd");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
void TestDhcp6PdConflict(void)
|
|
{
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix pdPrefix = PrefixFromString("2001:db8:dead:beef::", 64);
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDhcp6PdConflict");
|
|
|
|
InitTest(/* aEnableBorderRouting */ true);
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
sInstance->Get<BorderRouter::RoutingManager>().SetDhcp6PdEnabled(true);
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Report a PD prefix and check that its used as OMR prefix
|
|
|
|
Log("Report DHCPv6-PD prefix");
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Add(pdPrefix);
|
|
AdvanceTime(10 * 1000);
|
|
|
|
VerifyPdOmrPrefix(pdPrefix);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOmrPrefixInNetData(pdPrefix, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Advertise the same prefix as on-link from a router.
|
|
|
|
Log("Router A advertises PD prefix as on-link");
|
|
SendRouterAdvert(routerAddressA, {Pio(pdPrefix, 200, 200)});
|
|
|
|
// Check that the PD prefix is no longer used as OMR prefix due to
|
|
// conflict. The OMR should switch back to local OMR.
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for the PIO from Router A to expire. We renew the PD
|
|
// prefix during this time to ensure it stays valid.
|
|
|
|
Log("Wait for Router A PIO to expire");
|
|
|
|
AdvanceTime(300 * 1000);
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, kValidLitime, kPreferredLifetime)});
|
|
AdvanceTime(300 * 1000);
|
|
|
|
// Router A entry should be expired and removed. The PD prefix is still
|
|
// valid (renewed). The conflict should be resolved. Validate that PD
|
|
// prefix is again being use as OMR prefix.
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(pdPrefix);
|
|
|
|
AdvanceTime(100 * 1000);
|
|
|
|
VerifyPdOmrPrefix(pdPrefix);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
VerifyOmrPrefixInNetData(pdPrefix, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the PD prefix
|
|
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, 0, 0)});
|
|
|
|
AdvanceTime(1 * 1000);
|
|
VerifyNoPdOmrPrefix();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Now Advertise the PD prefix as on-link from a router first.
|
|
|
|
Log("Router A advertises PD prefix as on-link before delegating the prefix");
|
|
SendRouterAdvert(routerAddressA, {Pio(pdPrefix, 350, 350)});
|
|
|
|
// Check that local OMR is used.
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Report the same PD prefix. Validate that local OMR prefix is
|
|
// still being used.
|
|
|
|
Log("Delegate PD prefix which conflicts with already advertised on-link prefix from router A");
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(200 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for the PIO from Router A to expire. We renew the PD
|
|
// prefix during this time to ensure it stays valid.
|
|
|
|
Log("Wait for Router A PIO to expire");
|
|
|
|
AdvanceTime(200 * 1000);
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, kValidLitime, kPreferredLifetime)});
|
|
AdvanceTime(200 * 1000);
|
|
|
|
// Router A entry should be expired and removed. The PD prefix is still
|
|
// valid (renewed). The conflict should be resolved. Validate that PD
|
|
// prefix is again being use as OMR prefix.
|
|
|
|
AdvanceTime(100 * 1000);
|
|
|
|
VerifyPdOmrPrefix(pdPrefix);
|
|
VerifyOmrPrefixInNetData(pdPrefix, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the PD prefix
|
|
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, 0, 0)});
|
|
|
|
AdvanceTime(1 * 1000);
|
|
VerifyNoPdOmrPrefix();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Now Advertise the PD prefix as RIO from a router first.
|
|
|
|
Log("Router A advertises PD prefix as RIO before delegating the prefix");
|
|
SendRouterAdvert(routerAddressA, {Rio(pdPrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
// Check that local OMR is used.
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Report the same PD prefix. Validate that local OMR prefix is
|
|
// still being used (due to RIO conflict).
|
|
|
|
Log("Delegate PD prefix which conflicts with already advertised RIO prefix from router A");
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(200 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the RIO from Router A. Validate that the PD prefix is
|
|
// now accepted and used as OMR.
|
|
|
|
Log("Router A removes RIO, conflict should be resolved");
|
|
SendRouterAdvert(routerAddressA, {Rio(pdPrefix, 0, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(pdPrefix);
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(pdPrefix, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the PD prefix
|
|
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, 0, 0)});
|
|
|
|
AdvanceTime(1 * 1000);
|
|
VerifyNoPdOmrPrefix();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Report the PD prefix again. Validate that it is used as OMR prefix.
|
|
|
|
Log("Delegate PD prefix");
|
|
ReportPdPrefixesAsRa({Pio(pdPrefix, kValidLitime, kPreferredLifetime)});
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(pdPrefix);
|
|
|
|
AdvanceTime(10 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(pdPrefix, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Advertise the same prefix as RIO from a router. This should NOT
|
|
// be treated as a conflict since the PD prefix is already adopted
|
|
// and used.
|
|
|
|
Log("Router A advertises PD prefix as RIO after it is delegated");
|
|
SendRouterAdvert(routerAddressA, {Rio(pdPrefix, kValidLitime, NetworkData::kRoutePreferenceMedium)});
|
|
|
|
AdvanceTime(1 * 1000);
|
|
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(pdPrefix);
|
|
|
|
AdvanceTime(300 * 1000);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
VerifyOmrPrefixInNetData(pdPrefix, /* aDefaultRoute */ false);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(sHeapAllocatedPtrs.GetLength() <= heapAllocations);
|
|
|
|
Log("End of TestDhcp6PdConflict");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
|
|
|
|
static void HandleRdnssChanged(void *aContext)
|
|
{
|
|
VerifyOrQuit(aContext != nullptr);
|
|
*static_cast<bool *>(aContext) = true;
|
|
}
|
|
|
|
void TestRdnss(void)
|
|
{
|
|
Ip6::Address rdnssAddr1 = AddressFromString("fd77::1");
|
|
Ip6::Address rdnssAddr2 = AddressFromString("fd77::2");
|
|
Ip6::Address rdnssAddr3 = AddressFromString("fd77::3");
|
|
Ip6::Address rdnssAddr4 = AddressFromString("fd77::4");
|
|
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
|
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
bool rdnssCallbackCalled = false;
|
|
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestRdnss");
|
|
|
|
InitTest();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Start Routing Manager. Check emitted RS and RA messages.
|
|
|
|
sRsEmitted = false;
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
|
|
heapAllocations = sHeapAllocatedPtrs.GetLength();
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
|
|
|
|
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
|
|
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
|
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(30000);
|
|
|
|
VerifyOrQuit(sRsEmitted);
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
Log("Received RA was validated");
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Set the RDNSS callback on Routing Manager
|
|
|
|
rdnssCallbackCalled = false;
|
|
sInstance->Get<BorderRouter::RxRaTracker>().SetRdnssAddrCallback(HandleRdnssChanged, &rdnssCallbackCalled);
|
|
|
|
VerifyOrQuit(!rdnssCallbackCalled);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data to include the local OMR and ULA prefix.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A advertising an RDNS address. Ensure
|
|
// that the RDNSS callback is called and new advertised address
|
|
// is present in the RDNSS table.
|
|
|
|
VerifyRdnssAddressTableIsEmpty();
|
|
|
|
rdnssCallbackCalled = false;
|
|
SendRouterAdvert(routerAddressA, {Rdnss::Create(300, {rdnssAddr1})});
|
|
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable({RdnssAddress(rdnssAddr1, 300, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send same RA again from router A, ensure there is no callback
|
|
// as there is no change in table.
|
|
|
|
rdnssCallbackCalled = false;
|
|
|
|
AdvanceTime(15 * 1000);
|
|
VerifyOrQuit(!rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable({RdnssAddress(rdnssAddr1, 300, routerAddressA)});
|
|
|
|
SendRouterAdvert(routerAddressA, {Rdnss::Create(300, {rdnssAddr1})});
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable({RdnssAddress(rdnssAddr1, 300, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A, now adding a different RDNSS address.
|
|
// Ensure callback is invoked and we see the new address in the
|
|
// table.
|
|
|
|
rdnssCallbackCalled = false;
|
|
|
|
SendRouterAdvert(routerAddressA, {Rdnss::Create(600, {rdnssAddr2})});
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable(
|
|
{RdnssAddress(rdnssAddr1, 300, routerAddressA), RdnssAddress(rdnssAddr2, 600, routerAddressA)});
|
|
|
|
AdvanceTime(20 * 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router B, adding a new different RDNSS address.
|
|
// Ensure callback is invoked and validate RDNSS address table.
|
|
|
|
rdnssCallbackCalled = false;
|
|
|
|
SendRouterAdvert(routerAddressB, {Rdnss::Create(0xffffffff, {rdnssAddr3})});
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable({RdnssAddress(rdnssAddr1, 300, routerAddressA),
|
|
RdnssAddress(rdnssAddr2, 600, routerAddressA),
|
|
RdnssAddress(rdnssAddr3, 0xffffffff, routerAddressB)});
|
|
|
|
AdvanceTime(10 * 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with two RDNSS options changing the
|
|
// lifetimes of the two addresses. Ensure the callback is not invoked
|
|
// (since there are no changes to the address table), but we should
|
|
// see the new lifetimes reflected in the RDNSS address table.
|
|
|
|
rdnssCallbackCalled = false;
|
|
|
|
SendRouterAdvert(routerAddressA, {Rdnss::Create(400, {rdnssAddr2}), Rdnss::Create(800, {rdnssAddr1})});
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable({RdnssAddress(rdnssAddr1, 800, routerAddressA),
|
|
RdnssAddress(rdnssAddr2, 400, routerAddressA),
|
|
RdnssAddress(rdnssAddr3, 0xffffffff, routerAddressB)});
|
|
|
|
AdvanceTime(30 * 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router B, removing a previous RDNSS address
|
|
// and one that it never advertised. Ensure callback is
|
|
// invoked and validate RDNSS address table is updated
|
|
// correctly.
|
|
|
|
rdnssCallbackCalled = false;
|
|
|
|
SendRouterAdvert(routerAddressB, {Rdnss::Create(0, {rdnssAddr3, rdnssAddr4, rdnssAddr3})});
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable(
|
|
{RdnssAddress(rdnssAddr1, 800, routerAddressA), RdnssAddress(rdnssAddr2, 400, routerAddressA)});
|
|
|
|
AdvanceTime(30 * 1000);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send RA from router A, advertising a short lifetime.
|
|
|
|
rdnssCallbackCalled = false;
|
|
|
|
SendRouterAdvert(routerAddressA, {Rdnss::Create(32, {rdnssAddr1, rdnssAddr2})});
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(!rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable(
|
|
{RdnssAddress(rdnssAddr1, 32, routerAddressA), RdnssAddress(rdnssAddr2, 32, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Wait for the expiration time (based on lifetime) and ensure
|
|
// callback is invoked and the addresses are removed from
|
|
// the table.
|
|
|
|
AdvanceTime(32 * 1000 - 10);
|
|
|
|
VerifyOrQuit(!rdnssCallbackCalled);
|
|
|
|
AdvanceTime(15);
|
|
VerifyOrQuit(rdnssCallbackCalled);
|
|
VerifyRdnssAddressTableIsEmpty();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router B, adding an RDNSS address with infinite
|
|
// lifetime.
|
|
|
|
rdnssCallbackCalled = false;
|
|
|
|
SendRouterAdvert(routerAddressB, {Rdnss::Create(0xffffffff, {rdnssAddr3})});
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable({RdnssAddress(rdnssAddr3, 0xffffffff, routerAddressB)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Disallow responding to NS message.
|
|
|
|
// Wait for longer than "reachable" timeout to ensure the router B
|
|
// is fully removed (deemed unreachable). Validate that its
|
|
// RNDSS address is also removed and RDNSS callback is invoked.
|
|
|
|
rdnssCallbackCalled = false;
|
|
sRespondToNs = false;
|
|
|
|
AdvanceTime(250 * 1000);
|
|
|
|
VerifyOrQuit(rdnssCallbackCalled);
|
|
VerifyRdnssAddressTableIsEmpty();
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Send an RA from router A with one RDNNS address. Validate
|
|
// that it is removed when `RoutingManager` is stopped.
|
|
|
|
rdnssCallbackCalled = false;
|
|
SendRouterAdvert(routerAddressA, {Rdnss::Create(300, {rdnssAddr1})});
|
|
AdvanceTime(1);
|
|
|
|
VerifyOrQuit(rdnssCallbackCalled);
|
|
VerifyRdnssAddressTable({RdnssAddress(rdnssAddr1, 300, routerAddressA)});
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
VerifyRdnssAddressTableIsEmpty();
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestRdnss");
|
|
|
|
FinalizeTest();
|
|
}
|
|
|
|
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
|
|
|
} // namespace ot
|
|
|
|
int main(void)
|
|
{
|
|
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
|
ot::TestSamePrefixesFromMultipleRouters();
|
|
ot::TestOmrSelection();
|
|
ot::TestOmrConfig();
|
|
ot::TestDefaultRoute();
|
|
ot::TestNonUlaPioWithOnlyOnLinkFlag();
|
|
ot::TestAdvNonUlaRoute();
|
|
ot::TestFavoredOnLinkPrefix();
|
|
ot::TestLocalOnLinkPrefixDeprecation();
|
|
ot::TestExtPanIdChange();
|
|
ot::TestConflictingPrefix();
|
|
ot::TestPrefixStaleTime();
|
|
ot::TestRouterNsProbe();
|
|
ot::TestLearningAndCopyingOfFlags();
|
|
ot::TestLearnRaHeader();
|
|
#if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
|
|
ot::TestSavedOnLinkPrefixes();
|
|
#endif
|
|
#if OPENTHREAD_CONFIG_SRP_SERVER_ENABLE
|
|
ot::TestAutoEnableOfSrpServer();
|
|
#endif
|
|
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
|
ot::TestNat64PrefixSelection();
|
|
#endif
|
|
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
|
|
ot::TestDhcp6Pd();
|
|
ot::TestDhcp6PdConflict();
|
|
#endif
|
|
ot::TestRdnss();
|
|
|
|
printf("All tests passed\n");
|
|
#else
|
|
printf("BORDER_ROUTING feature is not enabled\n");
|
|
#endif
|
|
|
|
return 0;
|
|
}
|