mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
cf733a331e
This commit updates the following `otPlatInfraIf` platform APIs to include an `otInstance *` as their first parameter: - `otPlatInfraIfHasAddress()` - `otPlatInfraIfSendIcmp6Nd()` - `otPlatInfraIfDiscoverNat64Prefix()` Other APIs under `otPlatInfraIf` already follow this pattern. Passing the `otInstance` pointer is the required standard for all platform and public APIs; however, it was missed during the initial design of these specific APIs. While missing this parameter is often not a blocker on platforms using a single OpenThread instance, it has become a blocker for simulations, especially when multiple Border Routers are emulated in the same simulation setup. This change introduces a compatibility break for existing platform implementations, however, it is necessary to support new use cases (simulation of BRs). It also helps ensure consistent API design across the stack.
5628 lines
214 KiB
C++
5628 lines
214 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
|
|
void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat, ...)
|
|
{
|
|
OT_UNUSED_VARIABLE(aLogLevel);
|
|
OT_UNUSED_VARIABLE(aLogRegion);
|
|
|
|
va_list args;
|
|
|
|
printf(" ");
|
|
va_start(args, aFormat);
|
|
vprintf(aFormat, args);
|
|
va_end(args);
|
|
printf("\n");
|
|
}
|
|
#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::Icmp::Header *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::Icmp::Header));
|
|
|
|
header = reinterpret_cast<Ip6::Icmp::Header *>(const_cast<uint8_t *>(aBuffer));
|
|
|
|
switch (header->GetType())
|
|
{
|
|
case Ip6::Icmp::Header::kTypeRouterSolicit:
|
|
Log(" Router Solicit message");
|
|
sRsEmitted = true;
|
|
otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &sInfraIfAddress, aBuffer, aBufferLength);
|
|
break;
|
|
|
|
case Ip6::Icmp::Header::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::Icmp::Header::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 aAfterReset = false)
|
|
{
|
|
uint32_t delay = 10000;
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Initialize OT instance.
|
|
|
|
sNow = 0;
|
|
sAlarmOn = false;
|
|
sInstance = static_cast<Instance *>(testInitInstance());
|
|
|
|
if (aAfterReset)
|
|
{
|
|
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();
|
|
}
|
|
|
|
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
|
void TestDomainPrefixAsOmr(void)
|
|
{
|
|
Ip6::Prefix localOnLink;
|
|
Ip6::Prefix localOmr;
|
|
Ip6::Prefix domainPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
|
|
NetworkData::OnMeshPrefixConfig prefixConfig;
|
|
uint16_t heapAllocations;
|
|
|
|
Log("--------------------------------------------------------------------------------------------");
|
|
Log("TestDomainPrefixAsOmr");
|
|
|
|
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);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Add a domain prefix directly into net data. The new prefix should
|
|
// be favored over the local OMR prefix.
|
|
|
|
otBackboneRouterSetEnabled(sInstance, true);
|
|
|
|
prefixConfig.Clear();
|
|
prefixConfig.mPrefix = domainPrefix;
|
|
prefixConfig.mStable = true;
|
|
prefixConfig.mSlaac = true;
|
|
prefixConfig.mPreferred = true;
|
|
prefixConfig.mOnMesh = true;
|
|
prefixConfig.mDefaultRoute = false;
|
|
prefixConfig.mDp = true;
|
|
prefixConfig.mPreference = NetworkData::kRoutePreferenceMedium;
|
|
|
|
SuccessOrQuit(otBorderRouterAddOnMeshPrefix(sInstance, &prefixConfig));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(100);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Make sure BR emits RA without domain prefix or previous local OMR.
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(domainPrefix);
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
// We should see RIO removing the local OMR prefix with lifetime zero
|
|
// and should not see the domain prefix as RIO.
|
|
|
|
VerifyOrQuit(sExpectedRios[0].mPrefix == domainPrefix);
|
|
VerifyOrQuit(!sExpectedRios[0].mSawInRa);
|
|
|
|
VerifyOrQuit(sExpectedRios[1].mPrefix == localOmr);
|
|
VerifyOrQuit(sExpectedRios[1].mSawInRa);
|
|
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
|
|
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow);
|
|
|
|
// Wait long enough for deprecating RIO prefix to expire
|
|
AdvanceTime(3200000);
|
|
|
|
sRaValidated = false;
|
|
sExpectedPio = kPioAdvertisingLocalOnLink;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(domainPrefix);
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
// Wait for next RA (650 seconds).
|
|
|
|
AdvanceTime(650000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
|
|
// We should not see either domain prefix or local OMR
|
|
// as RIO.
|
|
|
|
VerifyOrQuit(!sExpectedRios[0].mSawInRa);
|
|
VerifyOrQuit(!sExpectedRios[1].mSawInRa);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should now see that the local OMR prefix
|
|
// is removed.
|
|
|
|
VerifyOmrPrefixInNetData(domainPrefix, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Remove the domain prefix from net data.
|
|
|
|
SuccessOrQuit(otBorderRouterRemoveOnMeshPrefix(sInstance, &domainPrefix));
|
|
SuccessOrQuit(otBorderRouterRegister(sInstance));
|
|
|
|
AdvanceTime(100);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Make sure BR emits RA with local OMR prefix again.
|
|
|
|
sRaValidated = false;
|
|
sExpectedRios.Clear();
|
|
sExpectedRios.Add(localOmr);
|
|
|
|
AdvanceTime(20000);
|
|
|
|
VerifyOrQuit(sRaValidated);
|
|
VerifyOrQuit(sExpectedRios.SawAll());
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
// Check Network Data. We should see that the local OMR prefix is
|
|
// added again.
|
|
|
|
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
|
|
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
|
|
|
|
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
|
AdvanceTime(3000);
|
|
|
|
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
|
|
|
|
Log("End of TestDomainPrefixAsOmr");
|
|
FinalizeTest();
|
|
}
|
|
#endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
|
|
|
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");
|
|
|
|
testFreeInstance(sInstance);
|
|
|
|
InitTest(/* aEnablBorderRouting */ true, /* aAfterReset */ 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");
|
|
|
|
testFreeInstance(sInstance);
|
|
|
|
InitTest(/* aEnablBorderRouting */ false, /* aAfterReset */ 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");
|
|
|
|
testFreeInstance(sInstance);
|
|
InitTest(/* aEnablBorderRouting */ false, /* aAfterReset */ 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.Set(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, 200, 200)});
|
|
|
|
// 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(100 * 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(30 * 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();
|
|
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
|
ot::TestDomainPrefixAsOmr();
|
|
#endif
|
|
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;
|
|
}
|