mirror of
https://github.com/espressif/openthread.git
synced 2026-07-31 08:07:47 +00:00
[routing-manager] delay removing external route for on-link prefixes (#6878)
Per RFC 4862 section 5.5.3, the SLAAC address of a on-link prefix will not immediately be invalidated even if the on-link prefix is sent with zero PIO valid lifetime but we currently removes the external route for the on-link prefix when we see zero valid lifetime. This results in an error case that a Thread device can not reach a valid SLAAC address of a Wi-Fi host on the same infra link because there is no routes for this address. This commit fixes this issue by delay removing the external route for the discovered on-link prefix untill its valid lifetime expires. Meanwhile, the Border Router now considers a deprecated (zero preferred lifetime) on-link prefix not usable. Thus, the Border Router will start advertising its own on-link prefix when current on-link prefix is deprecated.
This commit is contained in:
@@ -237,6 +237,14 @@ public:
|
||||
*/
|
||||
void SetPreferredLifetime(uint32_t aPreferredLifetime) { mPreferredLifetime = HostSwap32(aPreferredLifetime); }
|
||||
|
||||
/**
|
||||
* THis method returns the preferred lifetime of the prefix in seconds.
|
||||
*
|
||||
* @returns The preferred lifetime in seconds.
|
||||
*
|
||||
*/
|
||||
uint32_t GetPreferredLifetime(void) const { return HostSwap32(mPreferredLifetime); }
|
||||
|
||||
/**
|
||||
* This method sets the prefix.
|
||||
*
|
||||
@@ -261,7 +269,8 @@ public:
|
||||
*/
|
||||
bool IsValid(void) const
|
||||
{
|
||||
return (GetSize() == sizeof(*this)) && (mPrefixLength <= OT_IP6_ADDRESS_SIZE * CHAR_BIT);
|
||||
return (GetSize() == sizeof(*this)) && (mPrefixLength <= OT_IP6_ADDRESS_SIZE * CHAR_BIT) &&
|
||||
(GetPreferredLifetime() <= GetValidLifetime());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -63,6 +63,7 @@ RoutingManager::RoutingManager(Instance &aInstance)
|
||||
, mInfraIfIsRunning(false)
|
||||
, mInfraIfIndex(0)
|
||||
, mAdvertisedOnLinkPrefix(nullptr)
|
||||
, mOnLinkPrefixDeprecateTimer(aInstance, HandleOnLinkPrefixDeprecateTimer)
|
||||
, mTimeRouterAdvMessageLastUpdate(TimerMilli::GetNow())
|
||||
, mDiscoveredPrefixInvalidTimer(aInstance, HandleDiscoveredPrefixInvalidTimer)
|
||||
, mDiscoveredPrefixStaleTimer(aInstance, HandleDiscoveredPrefixStaleTimer)
|
||||
@@ -224,17 +225,20 @@ void RoutingManager::Stop(void)
|
||||
if (mAdvertisedOnLinkPrefix != nullptr)
|
||||
{
|
||||
RemoveExternalRoute(*mAdvertisedOnLinkPrefix);
|
||||
}
|
||||
|
||||
InvalidateAllDiscoveredPrefixes();
|
||||
// Start deprecating the local on-link prefix to send a PIO
|
||||
// with zero preferred lifetime in `SendRouterAdvertisement`.
|
||||
DeprecateOnLinkPrefix();
|
||||
}
|
||||
|
||||
// Use empty OMR & on-link prefixes to invalidate possible advertised prefixes.
|
||||
SendRouterAdvertisement(OmrPrefixArray(), nullptr);
|
||||
|
||||
mAdvertisedOmrPrefixes.Clear();
|
||||
|
||||
mAdvertisedOnLinkPrefix = nullptr;
|
||||
mOnLinkPrefixDeprecateTimer.Stop();
|
||||
|
||||
InvalidateAllDiscoveredPrefixes();
|
||||
mDiscoveredPrefixes.Clear();
|
||||
mDiscoveredPrefixInvalidTimer.Stop();
|
||||
mDiscoveredPrefixStaleTimer.Stop();
|
||||
@@ -499,7 +503,7 @@ const Ip6::Prefix *RoutingManager::EvaluateOnLinkPrefix(void)
|
||||
|
||||
for (const ExternalPrefix &prefix : mDiscoveredPrefixes)
|
||||
{
|
||||
if (!prefix.mIsOnLinkPrefix)
|
||||
if (!prefix.mIsOnLinkPrefix || prefix.IsDeprecated())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -521,6 +525,8 @@ const Ip6::Prefix *RoutingManager::EvaluateOnLinkPrefix(void)
|
||||
{
|
||||
newOnLinkPrefix = &mLocalOnLinkPrefix;
|
||||
}
|
||||
|
||||
mOnLinkPrefixDeprecateTimer.Stop();
|
||||
}
|
||||
// When an application-specific on-link prefix is received and it is bigger than the
|
||||
// advertised prefix, we will not remove the advertised prefix. In this case, there
|
||||
@@ -536,14 +542,7 @@ const Ip6::Prefix *RoutingManager::EvaluateOnLinkPrefix(void)
|
||||
{
|
||||
otLogInfoBr("EvaluateOnLinkPrefix: There is already smaller on-link prefix %s on interface %u",
|
||||
smallestOnLinkPrefix->ToString().AsCString(), mInfraIfIndex);
|
||||
|
||||
// TODO: we remove the advertised on-link prefix by setting zero valid lifetime for PIO,
|
||||
// But SLAAC addresses configured by PIO prefix will not be removed immediately (
|
||||
// https://tools.ietf.org/html/rfc4862#section-5.5.3). This leads to a situation that
|
||||
// a WiFi device keeps using the old SLAAC address but a Thread device cannot reach to
|
||||
// it. One solution is to delay removing external route until the SLAAC addresses are
|
||||
// actually expired/deprecated.
|
||||
RemoveExternalRoute(*mAdvertisedOnLinkPrefix);
|
||||
DeprecateOnLinkPrefix();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,6 +550,26 @@ exit:
|
||||
return newOnLinkPrefix;
|
||||
}
|
||||
|
||||
void RoutingManager::HandleOnLinkPrefixDeprecateTimer(Timer &aTimer)
|
||||
{
|
||||
aTimer.Get<RoutingManager>().HandleOnLinkPrefixDeprecateTimer();
|
||||
}
|
||||
|
||||
void RoutingManager::HandleOnLinkPrefixDeprecateTimer(void)
|
||||
{
|
||||
otLogInfoBr("Local on-link prefix %s expired", mLocalOnLinkPrefix.ToString().AsCString());
|
||||
RemoveExternalRoute(mLocalOnLinkPrefix);
|
||||
}
|
||||
|
||||
void RoutingManager::DeprecateOnLinkPrefix(void)
|
||||
{
|
||||
OT_ASSERT(mAdvertisedOnLinkPrefix != nullptr);
|
||||
|
||||
otLogInfoBr("Deprecate local on-link prefix %s", mAdvertisedOnLinkPrefix->ToString().AsCString());
|
||||
mOnLinkPrefixDeprecateTimer.StartAt(mTimeAdvertisedOnLinkPrefix,
|
||||
TimeMilli::SecToMsec(kDefaultOnLinkPrefixLifetime));
|
||||
}
|
||||
|
||||
// This method evaluate the routing policy depends on prefix and route
|
||||
// information on Thread Network and infra link. As a result, this
|
||||
// method May send RA messages on infra link and publish/unpublish
|
||||
@@ -662,6 +681,8 @@ void RoutingManager::SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefix
|
||||
|
||||
if (aNewOnLinkPrefix != nullptr)
|
||||
{
|
||||
OT_ASSERT(aNewOnLinkPrefix == &mLocalOnLinkPrefix);
|
||||
|
||||
RouterAdv::PrefixInfoOption pio;
|
||||
|
||||
pio.SetOnLink(true);
|
||||
@@ -680,27 +701,29 @@ void RoutingManager::SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefix
|
||||
aNewOnLinkPrefix->ToString().AsCString(), mInfraIfIndex);
|
||||
}
|
||||
|
||||
otLogInfoBr("Send on-link prefix %s in PIO (valid lifetime = %u seconds)",
|
||||
aNewOnLinkPrefix->ToString().AsCString(), kDefaultOnLinkPrefixLifetime);
|
||||
otLogInfoBr("Send on-link prefix %s in PIO (preferred lifetime = %u seconds, valid lifetime = %u seconds)",
|
||||
aNewOnLinkPrefix->ToString().AsCString(), pio.GetPreferredLifetime(), pio.GetValidLifetime());
|
||||
|
||||
mTimeAdvertisedOnLinkPrefix = TimerMilli::GetNow();
|
||||
}
|
||||
else if (mAdvertisedOnLinkPrefix != nullptr)
|
||||
else if (mOnLinkPrefixDeprecateTimer.IsRunning())
|
||||
{
|
||||
RouterAdv::PrefixInfoOption pio;
|
||||
|
||||
pio.SetOnLink(true);
|
||||
pio.SetAutoAddrConfig(true);
|
||||
pio.SetValidLifetime(TimeMilli::MsecToSec(mOnLinkPrefixDeprecateTimer.GetFireTime() - TimerMilli::GetNow()));
|
||||
|
||||
// Set zero valid lifetime to immediately invalidate the advertised on-link prefix.
|
||||
pio.SetValidLifetime(0);
|
||||
// Set zero preferred lifetime to immediately deprecate the advertised on-link prefix.
|
||||
pio.SetPreferredLifetime(0);
|
||||
pio.SetPrefix(*mAdvertisedOnLinkPrefix);
|
||||
pio.SetPrefix(mLocalOnLinkPrefix);
|
||||
|
||||
OT_ASSERT(bufferLength + pio.GetSize() <= sizeof(buffer));
|
||||
memcpy(buffer + bufferLength, &pio, pio.GetSize());
|
||||
bufferLength += pio.GetSize();
|
||||
|
||||
otLogInfoBr("Stop advertising on-link prefix %s on interface %u",
|
||||
mAdvertisedOnLinkPrefix->ToString().AsCString(), mInfraIfIndex);
|
||||
otLogInfoBr("Send on-link prefix %s in PIO (preferred lifetime = %u seconds, valid lifetime = %u seconds)",
|
||||
mLocalOnLinkPrefix.ToString().AsCString(), pio.GetPreferredLifetime(), pio.GetValidLifetime());
|
||||
}
|
||||
|
||||
// Invalidate the advertised OMR prefixes if they are no longer in the new OMR prefix array.
|
||||
@@ -852,12 +875,19 @@ void RoutingManager::HandleRouterSolicitTimer(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalidate all prefixes that are not refreshed during Router Solicitation.
|
||||
for (const ExternalPrefix &prefix : mDiscoveredPrefixes)
|
||||
// Invalidate/deprecate all OMR/on-link prefixes that are not refreshed during Router Solicitation.
|
||||
for (ExternalPrefix &prefix : mDiscoveredPrefixes)
|
||||
{
|
||||
if (prefix.mTimeLastUpdate <= mTimeRouterSolicitStart)
|
||||
{
|
||||
InvalidateDiscoveredPrefixes(&prefix.mPrefix, prefix.mIsOnLinkPrefix);
|
||||
if (prefix.mIsOnLinkPrefix)
|
||||
{
|
||||
prefix.mPreferredLifetime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidateDiscoveredPrefixes(&prefix.mPrefix, prefix.mIsOnLinkPrefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1022,8 +1052,11 @@ exit:
|
||||
|
||||
bool RoutingManager::UpdateDiscoveredPrefixes(const RouterAdv::PrefixInfoOption &aPio, bool aManagedAddrConfig)
|
||||
{
|
||||
Ip6::Prefix prefix = aPio.GetPrefix();
|
||||
bool needReevaluate = false;
|
||||
Ip6::Prefix prefix = aPio.GetPrefix();
|
||||
bool needReevaluate = false;
|
||||
TimeMilli staleTime;
|
||||
ExternalPrefix onLinkPrefix;
|
||||
ExternalPrefix *existingPrefix = nullptr;
|
||||
|
||||
if (!IsValidOnLinkPrefix(aPio, aManagedAddrConfig))
|
||||
{
|
||||
@@ -1036,23 +1069,87 @@ bool RoutingManager::UpdateDiscoveredPrefixes(const RouterAdv::PrefixInfoOption
|
||||
otLogInfoBr("Discovered on-link prefix (%s, %u seconds) from interface %u", prefix.ToString().AsCString(),
|
||||
aPio.GetValidLifetime(), mInfraIfIndex);
|
||||
|
||||
if (aPio.GetValidLifetime() == 0)
|
||||
onLinkPrefix.mIsOnLinkPrefix = true;
|
||||
onLinkPrefix.mPrefix = prefix;
|
||||
onLinkPrefix.mValidLifetime = aPio.GetValidLifetime();
|
||||
onLinkPrefix.mPreferredLifetime = aPio.GetPreferredLifetime();
|
||||
onLinkPrefix.mTimeLastUpdate = TimerMilli::GetNow();
|
||||
|
||||
staleTime = TimerMilli::GetNow();
|
||||
|
||||
for (ExternalPrefix &externalPrefix : mDiscoveredPrefixes)
|
||||
{
|
||||
needReevaluate = InvalidateDiscoveredPrefixes(&prefix, /* aIsOnLinkPrefix */ true) > 0;
|
||||
if (externalPrefix == onLinkPrefix)
|
||||
{
|
||||
existingPrefix = &externalPrefix;
|
||||
}
|
||||
|
||||
staleTime = OT_MAX(staleTime, externalPrefix.GetStaleTime());
|
||||
}
|
||||
|
||||
if (existingPrefix == nullptr)
|
||||
{
|
||||
if (onLinkPrefix.mValidLifetime == 0)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
if (!mDiscoveredPrefixes.IsFull())
|
||||
{
|
||||
SuccessOrExit(AddExternalRoute(prefix, OT_ROUTE_PREFERENCE_MED));
|
||||
existingPrefix = mDiscoveredPrefixes.PushBack();
|
||||
*existingPrefix = onLinkPrefix;
|
||||
needReevaluate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogWarnBr("Discovered too many prefixes, ignore new on-link prefix %s", prefix.ToString().AsCString());
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
needReevaluate = AddDiscoveredPrefix(prefix, /* aIsOnLinkPrefix */ true, aPio.GetValidLifetime());
|
||||
constexpr uint32_t kTwoHoursInSeconds = 2 * 3600;
|
||||
|
||||
// Per RFC 4862 section 5.5.3.e:
|
||||
// 1. If the received Valid Lifetime is greater than 2 hours or
|
||||
// greater than RemainingLifetime, set the valid lifetime of the
|
||||
// corresponding address to the advertised Valid Lifetime.
|
||||
// 2. If RemainingLifetime is less than or equal to 2 hours, ignore
|
||||
// the Prefix Information option with regards to the valid
|
||||
// lifetime, unless ...
|
||||
// 3. Otherwise, reset the valid lifetime of the corresponding
|
||||
// address to 2 hours.
|
||||
|
||||
if (onLinkPrefix.mValidLifetime > kTwoHoursInSeconds ||
|
||||
onLinkPrefix.GetExpireTime() > existingPrefix->GetExpireTime())
|
||||
{
|
||||
existingPrefix->mValidLifetime = onLinkPrefix.mValidLifetime;
|
||||
}
|
||||
else if (existingPrefix->GetExpireTime() > TimerMilli::GetNow() + TimeMilli::SecToMsec(kTwoHoursInSeconds))
|
||||
{
|
||||
existingPrefix->mValidLifetime = kTwoHoursInSeconds;
|
||||
}
|
||||
|
||||
existingPrefix->mPreferredLifetime = onLinkPrefix.mPreferredLifetime;
|
||||
existingPrefix->mTimeLastUpdate = onLinkPrefix.mTimeLastUpdate;
|
||||
needReevaluate = (existingPrefix->mPreferredLifetime == 0);
|
||||
}
|
||||
|
||||
mDiscoveredPrefixInvalidTimer.FireAtIfEarlier(existingPrefix->GetExpireTime());
|
||||
staleTime = OT_MAX(staleTime, existingPrefix->GetStaleTime());
|
||||
mDiscoveredPrefixStaleTimer.FireAtIfEarlier(staleTime);
|
||||
|
||||
exit:
|
||||
return needReevaluate;
|
||||
}
|
||||
|
||||
bool RoutingManager::UpdateDiscoveredPrefixes(const RouterAdv::RouteInfoOption &aRio)
|
||||
{
|
||||
Ip6::Prefix prefix = aRio.GetPrefix();
|
||||
bool needReevaluate = false;
|
||||
Ip6::Prefix prefix = aRio.GetPrefix();
|
||||
bool needReevaluate = false;
|
||||
ExternalPrefix omrPrefix;
|
||||
ExternalPrefix *existingPrefix = nullptr;
|
||||
|
||||
if (!IsValidOmrPrefix(prefix))
|
||||
{
|
||||
@@ -1078,14 +1175,51 @@ bool RoutingManager::UpdateDiscoveredPrefixes(const RouterAdv::RouteInfoOption &
|
||||
|
||||
if (aRio.GetRouteLifetime() == 0)
|
||||
{
|
||||
needReevaluate = (InvalidateDiscoveredPrefixes(&prefix, /* aIsOnLinkPrefix */ false) > 0);
|
||||
needReevaluate = InvalidateDiscoveredPrefixes(&prefix, /* aIsOnLinkPrefix */ false);
|
||||
ExitNow();
|
||||
}
|
||||
else
|
||||
|
||||
omrPrefix.mIsOnLinkPrefix = false;
|
||||
omrPrefix.mPrefix = prefix;
|
||||
omrPrefix.mValidLifetime = aRio.GetRouteLifetime();
|
||||
omrPrefix.mRoutePreference = aRio.GetPreference();
|
||||
omrPrefix.mTimeLastUpdate = TimerMilli::GetNow();
|
||||
|
||||
for (ExternalPrefix &externalPrefix : mDiscoveredPrefixes)
|
||||
{
|
||||
needReevaluate =
|
||||
AddDiscoveredPrefix(prefix, /* aIsOnLinkPrefix */ false, aRio.GetRouteLifetime(), aRio.GetPreference());
|
||||
if (externalPrefix == omrPrefix)
|
||||
{
|
||||
existingPrefix = &externalPrefix;
|
||||
}
|
||||
|
||||
mDiscoveredPrefixStaleTimer.FireAtIfEarlier(externalPrefix.GetStaleTime());
|
||||
}
|
||||
|
||||
if (existingPrefix == nullptr)
|
||||
{
|
||||
if (omrPrefix.mValidLifetime == 0)
|
||||
{
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
if (!mDiscoveredPrefixes.IsFull())
|
||||
{
|
||||
SuccessOrExit(AddExternalRoute(prefix, omrPrefix.mRoutePreference));
|
||||
existingPrefix = mDiscoveredPrefixes.PushBack();
|
||||
needReevaluate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogWarnBr("Discovered too many prefixes, ignore new prefix %s", prefix.ToString().AsCString());
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
*existingPrefix = omrPrefix;
|
||||
|
||||
mDiscoveredPrefixInvalidTimer.FireAtIfEarlier(existingPrefix->GetExpireTime());
|
||||
mDiscoveredPrefixStaleTimer.FireAtIfEarlier(existingPrefix->GetStaleTime());
|
||||
|
||||
exit:
|
||||
return needReevaluate;
|
||||
}
|
||||
@@ -1144,77 +1278,6 @@ void RoutingManager::InvalidateAllDiscoveredPrefixes(void)
|
||||
OT_ASSERT(mDiscoveredPrefixes.IsEmpty());
|
||||
}
|
||||
|
||||
static void UpdateStaleTime(TimeMilli &aonLinkPrefixStaleTime,
|
||||
TimeMilli &aomrPrefixStaleTime,
|
||||
bool aIsOnLink,
|
||||
TimeMilli aPrefixStaleTime)
|
||||
{
|
||||
if (aIsOnLink)
|
||||
{
|
||||
aonLinkPrefixStaleTime = OT_MAX(aonLinkPrefixStaleTime, aPrefixStaleTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
aomrPrefixStaleTime = OT_MIN(aomrPrefixStaleTime, aPrefixStaleTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds a discovered prefix on infra link. If the same prefix already exists,
|
||||
// only the lifetime will be updated. Returns a boolean which indicates whether
|
||||
// a new prefix is added.
|
||||
bool RoutingManager::AddDiscoveredPrefix(const Ip6::Prefix &aPrefix,
|
||||
bool aIsOnLinkPrefix,
|
||||
uint32_t aLifetime,
|
||||
otRoutePreference aRoutePreference)
|
||||
{
|
||||
OT_ASSERT(aIsOnLinkPrefix ? IsValidOmrPrefix(aPrefix) : IsValidOnLinkPrefix(aPrefix));
|
||||
OT_ASSERT(aLifetime > 0);
|
||||
|
||||
bool addedNewPrefix = false;
|
||||
ExternalPrefix *discoveredPrefix = nullptr;
|
||||
TimeMilli now = TimerMilli::GetNow();
|
||||
TimeMilli onLinkPrefixStaleTime = now;
|
||||
TimeMilli omrPrefixStaleTime = now.GetDistantFuture();
|
||||
|
||||
for (ExternalPrefix &prefix : mDiscoveredPrefixes)
|
||||
{
|
||||
if (aPrefix == prefix.mPrefix && aIsOnLinkPrefix == prefix.mIsOnLinkPrefix)
|
||||
{
|
||||
discoveredPrefix = &prefix;
|
||||
}
|
||||
|
||||
UpdateStaleTime(onLinkPrefixStaleTime, omrPrefixStaleTime, prefix.mIsOnLinkPrefix, prefix.GetStaleTime());
|
||||
}
|
||||
|
||||
if (discoveredPrefix == nullptr)
|
||||
{
|
||||
if (!mDiscoveredPrefixes.IsFull())
|
||||
{
|
||||
SuccessOrExit(AddExternalRoute(aPrefix, aRoutePreference));
|
||||
discoveredPrefix = mDiscoveredPrefixes.PushBack();
|
||||
addedNewPrefix = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogWarnBr("Discovered too many prefixes, ignore new prefix %s", aPrefix.ToString().AsCString());
|
||||
ExitNow();
|
||||
}
|
||||
}
|
||||
|
||||
discoveredPrefix->mPrefix = aPrefix;
|
||||
discoveredPrefix->mIsOnLinkPrefix = aIsOnLinkPrefix;
|
||||
discoveredPrefix->mValidLifetime = aLifetime;
|
||||
discoveredPrefix->mTimeLastUpdate = now;
|
||||
mDiscoveredPrefixInvalidTimer.FireAtIfEarlier(discoveredPrefix->GetExpireTime());
|
||||
UpdateStaleTime(onLinkPrefixStaleTime, omrPrefixStaleTime, discoveredPrefix->mIsOnLinkPrefix,
|
||||
discoveredPrefix->GetStaleTime());
|
||||
|
||||
mDiscoveredPrefixStaleTimer.FireAtIfEarlier(OT_MIN(onLinkPrefixStaleTime, omrPrefixStaleTime));
|
||||
|
||||
exit:
|
||||
return addedNewPrefix;
|
||||
}
|
||||
|
||||
bool RoutingManager::NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const
|
||||
{
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
|
||||
@@ -113,9 +113,9 @@ public:
|
||||
* This method returns the off-mesh-routable (OMR) prefix.
|
||||
*
|
||||
* The randomly generated 64-bit prefix will be published
|
||||
* in the Thread network if there isn't already a OMR prefix.
|
||||
* in the Thread network if there isn't already an OMR prefix.
|
||||
*
|
||||
* @param[in] aPrefix A reference to where the prefix will be output to.
|
||||
* @param[out] aPrefix A reference to where the prefix will be output to.
|
||||
*
|
||||
* @retval kErrorInvalidState The Border Routing Manager is not initialized yet.
|
||||
* @retval kErrorNone Successfully retrieved the OMR prefix.
|
||||
@@ -130,7 +130,7 @@ public:
|
||||
* on the infrastructure link if there isn't already a usable
|
||||
* on-link prefix being advertised on the link.
|
||||
*
|
||||
* @param[in] aPrefix A reference to where the prefix will be output to.
|
||||
* @param[out] aPrefix A reference to where the prefix will be output to.
|
||||
*
|
||||
* @retval kErrorInvalidState The Border Routing Manager is not initialized yet.
|
||||
* @retval kErrorNone Successfully retrieved the on-link prefix.
|
||||
@@ -220,15 +220,44 @@ private:
|
||||
|
||||
// This struct represents an external prefix which is
|
||||
// discovered on the infrastructure interface.
|
||||
struct ExternalPrefix : public Clearable<ExternalPrefix>
|
||||
struct ExternalPrefix : public Clearable<ExternalPrefix>, public Unequatable<ExternalPrefix>
|
||||
{
|
||||
Ip6::Prefix mPrefix;
|
||||
uint32_t mValidLifetime;
|
||||
TimeMilli mTimeLastUpdate;
|
||||
bool mIsOnLinkPrefix;
|
||||
|
||||
TimeMilli GetExpireTime(void) const { return mTimeLastUpdate + GetPrefixExpireDelay(mValidLifetime); }
|
||||
TimeMilli GetStaleTime(void) const { return mTimeLastUpdate + TimeMilli::SecToMsec(kRtrAdvStaleTime); }
|
||||
union
|
||||
{
|
||||
// Preferred Lifetime of on-link prefix, available
|
||||
// only when `mIsOnLinkPrefix` is TRUE.
|
||||
uint32_t mPreferredLifetime;
|
||||
|
||||
// The preference of this route, available
|
||||
// only when `mIsOnLinkPrefix` is FALSE.
|
||||
otRoutePreference mRoutePreference;
|
||||
};
|
||||
TimeMilli mTimeLastUpdate;
|
||||
bool mIsOnLinkPrefix;
|
||||
|
||||
bool operator==(const ExternalPrefix &aPrefix) const
|
||||
{
|
||||
return mPrefix == aPrefix.mPrefix && mIsOnLinkPrefix == aPrefix.mIsOnLinkPrefix;
|
||||
}
|
||||
|
||||
bool IsDeprecated(void) const
|
||||
{
|
||||
OT_ASSERT(mIsOnLinkPrefix);
|
||||
|
||||
return mTimeLastUpdate + TimeMilli::SecToMsec(mPreferredLifetime) <= TimerMilli::GetNow();
|
||||
}
|
||||
|
||||
TimeMilli GetExpireTime(void) const { return mTimeLastUpdate + GetPrefixExpireDelay(mValidLifetime); }
|
||||
TimeMilli GetStaleTime(void) const
|
||||
{
|
||||
uint32_t delay = OT_MIN(kRtrAdvStaleTime, mIsOnLinkPrefix ? mPreferredLifetime : mValidLifetime);
|
||||
|
||||
return mTimeLastUpdate + TimeMilli::SecToMsec(delay);
|
||||
}
|
||||
|
||||
static uint32_t GetPrefixExpireDelay(uint32_t aValidLifetime);
|
||||
};
|
||||
|
||||
@@ -268,17 +297,16 @@ private:
|
||||
static void HandleDiscoveredPrefixStaleTimer(Timer &aTimer);
|
||||
void HandleDiscoveredPrefixStaleTimer(void);
|
||||
static void HandleRoutingPolicyTimer(Timer &aTimer);
|
||||
void HandleOnLinkPrefixDeprecateTimer(void);
|
||||
static void HandleOnLinkPrefixDeprecateTimer(Timer &aTimer);
|
||||
|
||||
void DeprecateOnLinkPrefix(void);
|
||||
void HandleRouterSolicit(const Ip6::Address &aSrcAddress, const uint8_t *aBuffer, uint16_t aBufferLength);
|
||||
void HandleRouterAdvertisement(const Ip6::Address &aSrcAddress, const uint8_t *aBuffer, uint16_t aBufferLength);
|
||||
bool UpdateDiscoveredPrefixes(const RouterAdv::PrefixInfoOption &aPio, bool aManagedAddrConfig);
|
||||
bool UpdateDiscoveredPrefixes(const RouterAdv::RouteInfoOption &aRio);
|
||||
bool InvalidateDiscoveredPrefixes(const Ip6::Prefix *aPrefix = nullptr, bool aIsOnLinkPrefix = true);
|
||||
void InvalidateAllDiscoveredPrefixes(void);
|
||||
bool AddDiscoveredPrefix(const Ip6::Prefix &aPrefix,
|
||||
bool aIsOnLinkPrefix,
|
||||
uint32_t aLifetime,
|
||||
otRoutePreference aRoutePreference = OT_ROUTE_PREFERENCE_MED);
|
||||
bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const;
|
||||
bool UpdateRouterAdvMessage(const RouterAdv::RouterAdvMessage *aRouterAdvMessage);
|
||||
|
||||
@@ -321,6 +349,11 @@ private:
|
||||
// Could only be nullptr or a pointer to mLocalOnLinkPrefix.
|
||||
const Ip6::Prefix *mAdvertisedOnLinkPrefix;
|
||||
|
||||
// The last time when the on-link prefix is advertised with
|
||||
// non-zero preferred lifetime.
|
||||
TimeMilli mTimeAdvertisedOnLinkPrefix;
|
||||
TimerMilli mOnLinkPrefixDeprecateTimer;
|
||||
|
||||
// The array of prefixes discovered on the infra link. Those
|
||||
// prefixes consist of on-link prefix(es) and OMR prefixes
|
||||
// advertised by BRs in another Thread Network which is connected to
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#
|
||||
import logging
|
||||
import unittest
|
||||
from ipaddress import IPv6Network
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
@@ -108,6 +109,8 @@ class MultiBorderRouters(thread_cert.TestCase):
|
||||
self.simulator.go(5)
|
||||
self.assertEqual('router', router1.get_state())
|
||||
|
||||
self.simulator.go(5)
|
||||
|
||||
br2.start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual('router', br2.get_state())
|
||||
@@ -129,27 +132,29 @@ class MultiBorderRouters(thread_cert.TestCase):
|
||||
logging.info("ROUTER2 addrs: %r", router2.get_addrs())
|
||||
logging.info("HOST addrs: %r", host.get_addrs())
|
||||
|
||||
self.assertTrue(len(br1.get_prefixes()) == 1)
|
||||
self.assertTrue(len(router1.get_prefixes()) == 1)
|
||||
self.assertTrue(len(br2.get_prefixes()) == 1)
|
||||
self.assertTrue(len(router2.get_prefixes()) == 1)
|
||||
self.assertEqual(len(br1.get_prefixes()), 1)
|
||||
self.assertEqual(len(router1.get_prefixes()), 1)
|
||||
self.assertEqual(len(br2.get_prefixes()), 1)
|
||||
self.assertEqual(len(router2.get_prefixes()), 1)
|
||||
|
||||
br1_omr_prefix = br1.get_prefixes()[0]
|
||||
br1_omr_prefix = br1.get_omr_prefix()
|
||||
self.assertEqual(br1_omr_prefix, br1.get_prefixes()[0].split(' ')[0])
|
||||
|
||||
# Each BR should independently register an external route for the on-link prefix.
|
||||
self.assertTrue(len(br1.get_routes()) == 2)
|
||||
self.assertTrue(len(router1.get_routes()) == 2)
|
||||
self.assertTrue(len(br2.get_routes()) == 2)
|
||||
self.assertTrue(len(router2.get_routes()) == 2)
|
||||
self.assertEqual(len(br1.get_routes()), 2)
|
||||
self.assertEqual(len(router1.get_routes()), 2)
|
||||
self.assertEqual(len(br2.get_routes()), 2)
|
||||
self.assertEqual(len(router2.get_routes()), 2)
|
||||
|
||||
external_route = br1.get_routes()[0]
|
||||
br1_on_link_prefix = external_route.split(' ')[0]
|
||||
br1_on_link_prefix = br1.get_on_link_prefix()
|
||||
self.assertEqual(br1_on_link_prefix, br1.get_routes()[0].split(' ')[0])
|
||||
self.assertEqual(br1_on_link_prefix, br1.get_routes()[1].split(' ')[0])
|
||||
|
||||
self.assertTrue(len(br1.get_ip6_address(config.ADDRESS_TYPE.OMR)) == 1)
|
||||
self.assertTrue(len(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)) == 1)
|
||||
self.assertTrue(len(br2.get_ip6_address(config.ADDRESS_TYPE.OMR)) == 1)
|
||||
self.assertTrue(len(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)) == 1)
|
||||
self.assertTrue(len(host.get_matched_ula_addresses(br1_on_link_prefix)) == 1)
|
||||
self.assertEqual(len(br1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
self.assertEqual(len(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
self.assertEqual(len(br2.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
self.assertEqual(len(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
self.assertEqual(len(host.get_matched_ula_addresses(br1_on_link_prefix)), 1)
|
||||
|
||||
# Router1 and Router2 can ping each other inside the Thread network.
|
||||
self.assertTrue(router1.ping(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0]))
|
||||
@@ -176,31 +181,35 @@ class MultiBorderRouters(thread_cert.TestCase):
|
||||
logging.info("ROUTER2 addrs: %r", router2.get_addrs())
|
||||
logging.info("HOST addrs: %r", host.get_addrs())
|
||||
|
||||
self.assertGreaterEqual(len(host.get_addrs()), 2)
|
||||
self.assertGreaterEqual(len(host.get_addrs()), 3)
|
||||
|
||||
self.assertTrue(len(br1.get_prefixes()) == 1)
|
||||
self.assertTrue(len(router1.get_prefixes()) == 1)
|
||||
self.assertTrue(len(br2.get_prefixes()) == 1)
|
||||
self.assertTrue(len(router2.get_prefixes()) == 1)
|
||||
self.assertEqual(len(br1.get_prefixes()), 1)
|
||||
self.assertEqual(len(router1.get_prefixes()), 1)
|
||||
self.assertEqual(len(br2.get_prefixes()), 1)
|
||||
self.assertEqual(len(router2.get_prefixes()), 1)
|
||||
|
||||
br2_omr_prefix = br1.get_prefixes()[0]
|
||||
self.assertNotEqual(br1_omr_prefix, br2_omr_prefix)
|
||||
br2_omr_prefix = br2.get_omr_prefix()
|
||||
self.assertEqual(br2_omr_prefix, br2.get_prefixes()[0].split(' ')[0])
|
||||
|
||||
# Only BR2 will register external route for the on-link prefix.
|
||||
self.assertTrue(len(br1.get_routes()) == 1)
|
||||
self.assertTrue(len(router1.get_routes()) == 1)
|
||||
self.assertTrue(len(br2.get_routes()) == 1)
|
||||
self.assertTrue(len(router2.get_routes()) == 1)
|
||||
# Only BR2 will keep the route for BR1's on-link prefix
|
||||
# and add route for on-link prefix of its own.
|
||||
self.assertEqual(len(br1.get_routes()), 2)
|
||||
self.assertEqual(len(router1.get_routes()), 2)
|
||||
self.assertEqual(len(br2.get_routes()), 2)
|
||||
self.assertEqual(len(router2.get_routes()), 2)
|
||||
|
||||
br2_external_route = br2.get_routes()[0]
|
||||
br2_on_link_prefix = br2_external_route.split(' ')[0]
|
||||
br2_external_routes = [route.split(' ')[0] for route in br2.get_routes()]
|
||||
|
||||
self.assertTrue(len(br1.get_ip6_address(config.ADDRESS_TYPE.OMR)) == 1)
|
||||
self.assertTrue(len(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)) == 1)
|
||||
self.assertTrue(len(br2.get_ip6_address(config.ADDRESS_TYPE.OMR)) == 1)
|
||||
self.assertTrue(len(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)) == 1)
|
||||
br2_on_link_prefix = br2.get_on_link_prefix()
|
||||
self.assertEqual(set(map(IPv6Network, br2_external_routes)),
|
||||
set(map(IPv6Network, [br1_on_link_prefix, br2_on_link_prefix])))
|
||||
|
||||
self.assertTrue(len(host.get_matched_ula_addresses(br2_on_link_prefix)) == 1)
|
||||
self.assertEqual(len(br1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
self.assertEqual(len(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
self.assertEqual(len(br2.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
self.assertEqual(len(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
|
||||
self.assertEqual(len(host.get_matched_ula_addresses(br2_on_link_prefix)), 1)
|
||||
|
||||
# Router1 and Router2 can ping each other inside the Thread network.
|
||||
self.assertTrue(router1.ping(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0]))
|
||||
|
||||
@@ -120,8 +120,8 @@ class MultiThreadNetworks(thread_cert.TestCase):
|
||||
self.assertTrue(len(br2.get_prefixes()) == 1)
|
||||
self.assertTrue(len(router2.get_prefixes()) == 1)
|
||||
|
||||
br1_omr_prefix = br1.get_prefixes()[0]
|
||||
br2_omr_prefix = br2.get_prefixes()[0]
|
||||
br1_omr_prefix = br1.get_omr_prefix()
|
||||
br2_omr_prefix = br2.get_omr_prefix()
|
||||
|
||||
self.assertNotEqual(br1_omr_prefix, br2_omr_prefix)
|
||||
|
||||
|
||||
@@ -107,6 +107,9 @@ class SingleBorderRouter(thread_cert.TestCase):
|
||||
|
||||
self.assertEqual(len(br.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
self.assertEqual(len(router.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1)
|
||||
|
||||
# radvd doesn't deprecates the PIO so that the Border Router will not
|
||||
# advertise its own on-link prefix immediately.
|
||||
self.assertEqual(len(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)), 1)
|
||||
|
||||
self.assertTrue(router.ping(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0]))
|
||||
|
||||
@@ -318,12 +318,11 @@ class SingleBorderRouter(thread_cert.TestCase):
|
||||
br.start_radvd_service(prefix=config.ONLINK_GUA_PREFIX, slaac=True)
|
||||
self.simulator.go(5)
|
||||
|
||||
self.assertEqual(len(br.get_routes()), 1)
|
||||
self.assertTrue(br.get_routes()[0].startswith(config.ONLINK_GUA_PREFIX.split('::/')[0]))
|
||||
self.assertEqual(len(router.get_routes()), 1)
|
||||
self.assertTrue(router.get_routes()[0].startswith(config.ONLINK_GUA_PREFIX.split('::/')[0]))
|
||||
self.assertEqual(len(br.get_routes()), 2)
|
||||
self.assertEqual(len(router.get_routes()), 2)
|
||||
|
||||
self.assertTrue(router.ping(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_GUA)[0]))
|
||||
self.assertTrue(router.ping(host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0]))
|
||||
self.assertTrue(host.ping(router.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True))
|
||||
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
import ipaddress
|
||||
import logging
|
||||
import unittest
|
||||
from ipaddress import IPv6Network
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
@@ -124,7 +124,7 @@ class MultiThreadNetworks(thread_cert.TestCase):
|
||||
|
||||
self.assertEqual(len(br1.get_routes()), 1)
|
||||
br1_on_link_prefix = br1.get_routes()[0].split(' ')[0]
|
||||
self.assertEqual(ipaddress.IPv6Network(br1_on_link_prefix), ipaddress.IPv6Network(ON_LINK_PREFIX))
|
||||
self.assertEqual(IPv6Network(br1_on_link_prefix), IPv6Network(ON_LINK_PREFIX))
|
||||
|
||||
host_on_link_addr = host.get_matched_ula_addresses(br1_on_link_prefix)[0]
|
||||
self.assertTrue(router1.ping(host_on_link_addr))
|
||||
@@ -156,14 +156,15 @@ class MultiThreadNetworks(thread_cert.TestCase):
|
||||
self.assertTrue(len(br2.get_prefixes()) == 1)
|
||||
self.assertTrue(len(router2.get_prefixes()) == 1)
|
||||
|
||||
br1_omr_prefix = br1.get_prefixes()[0].split(' ')[0]
|
||||
br2_omr_prefix = br2.get_prefixes()[0].split(' ')[0]
|
||||
br1_omr_prefix = br1.get_omr_prefix()
|
||||
br2_omr_prefix = br2.get_omr_prefix()
|
||||
self.assertNotEqual(br1_omr_prefix, br2_omr_prefix)
|
||||
|
||||
# Verify that BR1 removed ON_LINK_PREFIX from its
|
||||
# external routes list.
|
||||
self.assertEqual(len(br1.get_routes()), 2)
|
||||
self.assertEqual(len(router1.get_routes()), 2)
|
||||
# Verify that the Border Routers starts advertsing new on-link prefix
|
||||
# but don't remove the external routes for the radvd on-link prefix
|
||||
# immediately, because the SLAAC addresses are still valid.
|
||||
self.assertEqual(len(br1.get_routes()), 3)
|
||||
self.assertEqual(len(router1.get_routes()), 3)
|
||||
self.assertEqual(len(br2.get_routes()), 2)
|
||||
self.assertEqual(len(router2.get_routes()), 2)
|
||||
|
||||
@@ -172,21 +173,39 @@ class MultiThreadNetworks(thread_cert.TestCase):
|
||||
|
||||
on_link_prefixes = list(set(br1_external_routes).intersection(br2_external_routes))
|
||||
self.assertEqual(len(on_link_prefixes), 1)
|
||||
on_link_prefix = on_link_prefixes[0]
|
||||
self.assertEqual(IPv6Network(on_link_prefixes[0]), IPv6Network(br2.get_on_link_prefix()))
|
||||
|
||||
# Verify that both BR1 and BR2 are using a new on-link prefix.
|
||||
# BR1 is depending on the Vicarious Router Solicitation to find
|
||||
# out that the ON_LINK_PREFIX is stale and starts Router Solicitation
|
||||
# on its own.
|
||||
self.assertNotEqual(ipaddress.IPv6Network(on_link_prefix), ipaddress.IPv6Network(ON_LINK_PREFIX))
|
||||
router1_omr_addr = router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0]
|
||||
router2_omr_addr = router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0]
|
||||
|
||||
host_on_link_addr = host.get_matched_ula_addresses(on_link_prefix)[0]
|
||||
self.assertTrue(router1.ping(host_on_link_addr))
|
||||
self.assertTrue(
|
||||
host.ping(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True, interface=host_on_link_addr))
|
||||
self.assertTrue(router2.ping(host.get_matched_ula_addresses(on_link_prefix)[0]))
|
||||
self.assertTrue(
|
||||
host.ping(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True, interface=host_on_link_addr))
|
||||
# Make sure that addresses of both the deprecated radvd `ON_LINK_PREFIX`
|
||||
# and preferred Border Router on-link prefix can be reached by Thread
|
||||
# devices in network of Border Router 1.
|
||||
for host_on_link_addr in [
|
||||
host.get_matched_ula_addresses(on_link_prefixes[0])[0],
|
||||
host.get_matched_ula_addresses(ON_LINK_PREFIX)[0]
|
||||
]:
|
||||
self.assertTrue(router1.ping(host_on_link_addr))
|
||||
self.assertTrue(host.ping(router1_omr_addr, backbone=True, interface=host_on_link_addr))
|
||||
|
||||
host_on_link_addr = host.get_matched_ula_addresses(ON_LINK_PREFIX)[0]
|
||||
|
||||
# Make sure that addresses of the deprecated radvd `ON_LINK_PREFIX`
|
||||
# can't be reached by Thread devices in network of Border Router 2.
|
||||
self.assertFalse(router2.ping(host_on_link_addr))
|
||||
self.assertFalse(host.ping(router2_omr_addr, backbone=True, interface=host_on_link_addr))
|
||||
|
||||
# Wait 30 seconds for the radvd `ON_LINK_PREFIX` to be invalidated
|
||||
# and make sure that Thread devices in both networks can't reach
|
||||
# the on-link address.
|
||||
self.simulator.go(30) # Valid Lifetime of radvd PIO is set to 60 seconds.
|
||||
self.assertEqual(len(host.get_matched_ula_addresses(ON_LINK_PREFIX)), 0)
|
||||
self.assertFalse(router1.ping(host_on_link_addr))
|
||||
self.assertFalse(host.ping(router1_omr_addr, backbone=True, interface=host_on_link_addr))
|
||||
self.assertFalse(router2.ping(host_on_link_addr))
|
||||
self.assertFalse(host.ping(router2_omr_addr, backbone=True, interface=host_on_link_addr))
|
||||
|
||||
# Verify connectivity between the two networks.
|
||||
self.assertTrue(router1.ping(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0]))
|
||||
self.assertTrue(router2.ping(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0]))
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import sys
|
||||
import time
|
||||
import traceback
|
||||
import unittest
|
||||
from ipaddress import IPv6Address, IPv6Network
|
||||
from typing import Union, Dict, Optional, List
|
||||
|
||||
import pexpect
|
||||
@@ -1149,7 +1150,7 @@ class NodeImpl:
|
||||
self.send_command(cmd)
|
||||
self._expect_done()
|
||||
|
||||
def multicast_listener_list(self) -> Dict[ipaddress.IPv6Address, int]:
|
||||
def multicast_listener_list(self) -> Dict[IPv6Address, int]:
|
||||
cmd = 'bbr mgmt mlr listener'
|
||||
self.send_command(cmd)
|
||||
|
||||
@@ -1157,7 +1158,7 @@ class NodeImpl:
|
||||
for line in self._expect_results("\S+ \d+"):
|
||||
line = line.split()
|
||||
assert len(line) == 2, line
|
||||
ip = ipaddress.IPv6Address(line[0])
|
||||
ip = IPv6Address(line[0])
|
||||
timeout = int(line[1])
|
||||
assert ip not in table
|
||||
|
||||
@@ -1170,9 +1171,9 @@ class NodeImpl:
|
||||
self.send_command(cmd)
|
||||
self._expect_done()
|
||||
|
||||
def multicast_listener_add(self, ip: Union[ipaddress.IPv6Address, str], timeout: int = 0):
|
||||
if not isinstance(ip, ipaddress.IPv6Address):
|
||||
ip = ipaddress.IPv6Address(ip)
|
||||
def multicast_listener_add(self, ip: Union[IPv6Address, str], timeout: int = 0):
|
||||
if not isinstance(ip, IPv6Address):
|
||||
ip = IPv6Address(ip)
|
||||
|
||||
cmd = f'bbr mgmt mlr listener add {ip.compressed} {timeout}'
|
||||
self.send_command(cmd)
|
||||
@@ -1183,7 +1184,7 @@ class NodeImpl:
|
||||
self.send_command(cmd)
|
||||
self._expect_done()
|
||||
|
||||
def register_multicast_listener(self, *ipaddrs: Union[ipaddress.IPv6Address, str], timeout=None):
|
||||
def register_multicast_listener(self, *ipaddrs: Union[IPv6Address, str], timeout=None):
|
||||
assert len(ipaddrs) > 0, ipaddrs
|
||||
|
||||
ipaddrs = map(str, ipaddrs)
|
||||
@@ -1198,7 +1199,7 @@ class NodeImpl:
|
||||
status = int(m.group(1))
|
||||
failed_num = int(m.group(2))
|
||||
assert failed_num == len(lines) - 1
|
||||
failed_ips = list(map(ipaddress.IPv6Address, lines[1:]))
|
||||
failed_ips = list(map(IPv6Address, lines[1:]))
|
||||
print(f"register_multicast_listener {ipaddrs} => status: {status}, failed ips: {failed_ips}")
|
||||
return status, failed_ips
|
||||
|
||||
@@ -1516,7 +1517,7 @@ class NodeImpl:
|
||||
return None
|
||||
|
||||
def get_mleid_iid(self):
|
||||
ml_eid = ipaddress.IPv6Address(self.get_mleid())
|
||||
ml_eid = IPv6Address(self.get_mleid())
|
||||
return ml_eid.packed[8:].hex()
|
||||
|
||||
def get_eidcaches(self):
|
||||
@@ -1606,6 +1607,22 @@ class NodeImpl:
|
||||
|
||||
return None
|
||||
|
||||
def get_ip6_address_by_prefix(self, prefix: Union[str, IPv6Network]) -> List[IPv6Address]:
|
||||
"""Get addresses matched with given prefix.
|
||||
|
||||
Args:
|
||||
prefix: the prefix to match against.
|
||||
Can be either a string or ipaddress.IPv6Network.
|
||||
|
||||
Returns:
|
||||
The IPv6 address list.
|
||||
"""
|
||||
if isinstance(prefix, str):
|
||||
prefix = IPv6Network(prefix)
|
||||
addrs = map(IPv6Address, self.get_addrs())
|
||||
|
||||
return [addr for addr in addrs if addr in prefix]
|
||||
|
||||
def get_ip6_address(self, address_type):
|
||||
"""Get specific type of IPv6 address configured on thread device.
|
||||
|
||||
@@ -1661,6 +1678,16 @@ class NodeImpl:
|
||||
self.send_command('br disable')
|
||||
self._expect_done()
|
||||
|
||||
def get_omr_prefix(self):
|
||||
cmd = 'br omrprefix'
|
||||
self.send_command(cmd)
|
||||
return self._expect_command_output(cmd)[0]
|
||||
|
||||
def get_on_link_prefix(self):
|
||||
cmd = 'br onlinkprefix'
|
||||
self.send_command(cmd)
|
||||
return self._expect_command_output(cmd)[0]
|
||||
|
||||
def get_prefixes(self):
|
||||
return self.get_netdata()['Prefixes']
|
||||
|
||||
@@ -2936,6 +2963,8 @@ interface eth0
|
||||
AdvOnLink on;
|
||||
AdvAutonomous %s;
|
||||
AdvRouterAddr off;
|
||||
AdvPreferredLifetime 40;
|
||||
AdvValidLifetime 60;
|
||||
};
|
||||
};
|
||||
EOF
|
||||
@@ -3009,7 +3038,7 @@ class HostNode(LinuxHost, OtbrDocker):
|
||||
|
||||
addrs = []
|
||||
for addr in self.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA):
|
||||
if ipaddress.IPv6Address(addr) in ipaddress.IPv6Network(prefix):
|
||||
if IPv6Address(addr) in IPv6Network(prefix):
|
||||
addrs.append(addr)
|
||||
|
||||
return addrs
|
||||
|
||||
Reference in New Issue
Block a user