mirror of
https://github.com/espressif/openthread.git
synced 2026-08-13 14:17:47 +00:00
[routing-manager] add support for to use a prefix received from DHCPv6 PD (#10000)
This commit adds support for adding a DHCPv6 delegated prefix to the Routing Manager via a new Open Thread API. Previously this feature was only supported using a platform generated RA on a Posix based BR. For platforms that can get the prefix directly from a DHCPv6 PD client API there is no point in creating a RA for setting the prefix. It's much easier to use a direct call to configure it. This new API uses an otBorderRoutingPrefixTableEntry structure as an input parameter and evaluates the prefix based on the same rules as one coming from a platform RA. The lifetime of the prefix can be updated by calling the function again with new time values.
This commit is contained in:
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (405)
|
||||
#define OPENTHREAD_API_VERSION (406)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -65,6 +65,25 @@ extern "C" {
|
||||
*/
|
||||
extern void otPlatBorderRoutingProcessIcmp6Ra(otInstance *aInstance, const uint8_t *aMessage, uint16_t aLength);
|
||||
|
||||
/**
|
||||
* Process a prefix received from the DHCPv6 PD Server. The prefix is received on
|
||||
* the DHCPv6 PD client callback and provided to the Routing Manager via this
|
||||
* API.
|
||||
*
|
||||
* The prefix lifetime can be updated by calling the function again with updated time values.
|
||||
* If the preferred lifetime of the prefix is set to 0, the prefix becomes deprecated.
|
||||
* When this function is called multiple times, the smallest prefix is preferred as this rule allows
|
||||
* choosing a GUA instead of a ULA.
|
||||
*
|
||||
* Requires `OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE`.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aPrefixInfo A pointer to the prefix information structure
|
||||
*
|
||||
*/
|
||||
extern void otPlatBorderRoutingProcessDhcp6PdPrefix(otInstance *aInstance,
|
||||
const otBorderRoutingPrefixTableEntry *aPrefixInfo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1744,6 +1744,15 @@ void RoutingManager::DiscoveredPrefixTable::Entry::SetFrom(const RouteInfoOption
|
||||
mLastUpdateTime = TimerMilli::GetNow();
|
||||
}
|
||||
|
||||
void RoutingManager::DiscoveredPrefixTable::Entry::SetFrom(const PrefixTableEntry &aPrefixTableEntry)
|
||||
{
|
||||
mPrefix = AsCoreType(&aPrefixTableEntry.mPrefix);
|
||||
mType = aPrefixTableEntry.mIsOnLink ? kTypeOnLink : kTypeRoute;
|
||||
mValidLifetime = aPrefixTableEntry.mValidLifetime;
|
||||
mShared.mPreferredLifetime = aPrefixTableEntry.mPreferredLifetime;
|
||||
mLastUpdateTime = TimerMilli::GetNow();
|
||||
}
|
||||
|
||||
bool RoutingManager::DiscoveredPrefixTable::Entry::operator==(const Entry &aOther) const
|
||||
{
|
||||
return (mType == aOther.mType) && (mPrefix == aOther.mPrefix);
|
||||
@@ -1776,6 +1785,11 @@ TimeMilli RoutingManager::DiscoveredPrefixTable::Entry::GetStaleTime(void) const
|
||||
return mLastUpdateTime + TimeMilli::SecToMsec(delay);
|
||||
}
|
||||
|
||||
TimeMilli RoutingManager::DiscoveredPrefixTable::Entry::GetStaleTimeFromPreferredLifetime(void) const
|
||||
{
|
||||
return mLastUpdateTime + CalculateExpireDelay(GetPreferredLifetime());
|
||||
}
|
||||
|
||||
bool RoutingManager::DiscoveredPrefixTable::Entry::IsDeprecated(void) const
|
||||
{
|
||||
OT_ASSERT(IsOnLinkPrefix());
|
||||
@@ -3681,70 +3695,74 @@ void RoutingManager::PdPrefixManager::ProcessPlatformGeneratedRa(const uint8_t *
|
||||
Error error = kErrorNone;
|
||||
RouterAdvert::Icmp6Packet packet;
|
||||
|
||||
VerifyOrExit(IsRunning(), LogWarn("Ignore platform generated RA since PD is disabled or not running."));
|
||||
packet.Init(aRouterAdvert, aLength);
|
||||
error = Process(RouterAdvert::RxMessage(packet));
|
||||
mNumPlatformRaReceived++;
|
||||
mLastPlatformRaTime = TimerMilli::GetNow();
|
||||
if (mEnabled)
|
||||
{
|
||||
packet.Init(aRouterAdvert, aLength);
|
||||
RouterAdvert::RxMessage aMessage = RouterAdvert::RxMessage(packet);
|
||||
|
||||
error = Process(&aMessage, nullptr);
|
||||
mNumPlatformRaReceived++;
|
||||
mLastPlatformRaTime = TimerMilli::GetNow();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogWarn("Ignore platform generated RA since PD is disabled.");
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error != kErrorNone)
|
||||
{
|
||||
LogCrit("Failed to process platform generated ND OnMeshPrefix: %s", ErrorToString(error));
|
||||
}
|
||||
}
|
||||
|
||||
Error RoutingManager::PdPrefixManager::Process(const RouterAdvert::RxMessage &aMessage)
|
||||
void RoutingManager::PdPrefixManager::ProcessDhcpPdPrefix(const PrefixTableEntry &aPrefixTableEntry)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(mEnabled, LogWarn("Ignore DHCPv6 delegated prefix since PD is disabled."));
|
||||
|
||||
error = Process(nullptr, &aPrefixTableEntry);
|
||||
|
||||
exit:
|
||||
|
||||
if (error != kErrorNone)
|
||||
{
|
||||
LogCrit("Failed to process DHCPv6 delegated prefix: %s", ErrorToString(error));
|
||||
}
|
||||
}
|
||||
|
||||
Error RoutingManager::PdPrefixManager::Process(const RouterAdvert::RxMessage *aMessage,
|
||||
const PrefixTableEntry *aPrefixTableEntry)
|
||||
{
|
||||
bool currentPrefixUpdated = false;
|
||||
Error error = kErrorNone;
|
||||
DiscoveredPrefixTable::Entry favoredEntry;
|
||||
bool currentPrefixUpdated = false;
|
||||
DiscoveredPrefixTable::Entry entry;
|
||||
|
||||
VerifyOrExit(aMessage.IsValid(), error = kErrorParse);
|
||||
favoredEntry.Clear();
|
||||
|
||||
for (const Option &option : aMessage)
|
||||
// aMessage or aPrefixTableEntry must be different from null
|
||||
if (aMessage != nullptr)
|
||||
{
|
||||
DiscoveredPrefixTable::Entry entry;
|
||||
VerifyOrExit(aMessage->IsValid(), error = kErrorParse);
|
||||
|
||||
if (option.GetType() != Option::kTypePrefixInfo || !static_cast<const PrefixInfoOption &>(option).IsValid())
|
||||
for (const Option &option : *aMessage)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mNumPlatformPioProcessed++;
|
||||
entry.SetFrom(static_cast<const PrefixInfoOption &>(option));
|
||||
|
||||
if (!IsValidPdPrefix(entry.GetPrefix()))
|
||||
{
|
||||
LogWarn("PdPrefixManager: Ignore invalid PIO entry %s", entry.GetPrefix().ToString().AsCString());
|
||||
continue;
|
||||
}
|
||||
|
||||
entry.mPrefix.Tidy();
|
||||
entry.mPrefix.SetLength(kOmrPrefixLength);
|
||||
|
||||
// The platform may send another RA message to announce that the current prefix we are using is no longer
|
||||
// preferred or no longer valid.
|
||||
if (entry.GetPrefix() == GetPrefix())
|
||||
{
|
||||
currentPrefixUpdated = true;
|
||||
mPrefix = entry;
|
||||
}
|
||||
|
||||
if (entry.IsDeprecated())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Some platforms may delegate us more than one prefixes. We will pick the smallest one. This is a simple rule
|
||||
// to pick the GUA prefix from the RA messages since GUA prefixes (2000::/3) are always smaller than ULA
|
||||
// prefixes (fc00::/7).
|
||||
if (favoredEntry.GetPrefix().GetLength() == 0 || entry.GetPrefix() < favoredEntry.GetPrefix())
|
||||
{
|
||||
favoredEntry = entry;
|
||||
if (option.GetType() != Option::kTypePrefixInfo || !static_cast<const PrefixInfoOption &>(option).IsValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mNumPlatformPioProcessed++;
|
||||
entry.SetFrom(static_cast<const PrefixInfoOption &>(option));
|
||||
currentPrefixUpdated |= ProcessPrefixEntry(entry, favoredEntry);
|
||||
}
|
||||
}
|
||||
else // aPrefixTableEntry != nullptr
|
||||
{
|
||||
entry.SetFrom(*aPrefixTableEntry);
|
||||
currentPrefixUpdated = ProcessPrefixEntry(entry, favoredEntry);
|
||||
}
|
||||
|
||||
if (currentPrefixUpdated && mPrefix.IsDeprecated())
|
||||
{
|
||||
@@ -3762,7 +3780,15 @@ Error RoutingManager::PdPrefixManager::Process(const RouterAdvert::RxMessage &aM
|
||||
exit:
|
||||
if (HasPrefix())
|
||||
{
|
||||
mTimer.FireAt(mPrefix.GetStaleTime());
|
||||
// If prefix has been set from aPrefixTableEntry use only preferred lifetime to calculate stale time
|
||||
if (aPrefixTableEntry)
|
||||
{
|
||||
mTimer.FireAt(mPrefix.GetStaleTimeFromPreferredLifetime());
|
||||
}
|
||||
else
|
||||
{
|
||||
mTimer.FireAt(mPrefix.GetStaleTime());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3772,6 +3798,41 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool RoutingManager::PdPrefixManager::ProcessPrefixEntry(DiscoveredPrefixTable::Entry &aEntry,
|
||||
DiscoveredPrefixTable::Entry &aFavoredEntry)
|
||||
{
|
||||
bool currentPrefixUpdated = false;
|
||||
|
||||
if (!IsValidPdPrefix(aEntry.GetPrefix()))
|
||||
{
|
||||
LogWarn("PdPrefixManager: Ignore invalid prefix entry %s", aEntry.GetPrefix().ToString().AsCString());
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
aEntry.mPrefix.SetLength(kOmrPrefixLength);
|
||||
aEntry.mPrefix.Tidy();
|
||||
|
||||
// Check if there is an update to the current prefix. The valid or preferred lifetime might change.
|
||||
if (aEntry.GetPrefix() == GetPrefix())
|
||||
{
|
||||
currentPrefixUpdated = true;
|
||||
mPrefix = aEntry;
|
||||
}
|
||||
|
||||
VerifyOrExit(!aEntry.IsDeprecated());
|
||||
|
||||
// Some platforms may delegate us more than one prefix. We will pick the smallest one. This is a simple rule
|
||||
// to pick the GUA prefix from the RA messages since GUA prefixes (2000::/3) are always smaller than ULA
|
||||
// prefixes (fc00::/7).
|
||||
if (aFavoredEntry.GetPrefix().GetLength() == 0 || aEntry.GetPrefix() < aFavoredEntry.GetPrefix())
|
||||
{
|
||||
aFavoredEntry = aEntry;
|
||||
}
|
||||
|
||||
exit:
|
||||
return currentPrefixUpdated;
|
||||
}
|
||||
|
||||
void RoutingManager::PdPrefixManager::SetEnabled(bool aEnabled)
|
||||
{
|
||||
Dhcp6PdState oldState = GetState();
|
||||
@@ -3788,6 +3849,14 @@ extern "C" void otPlatBorderRoutingProcessIcmp6Ra(otInstance *aInstance, const u
|
||||
{
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().ProcessPlatformGeneratedRa(aMessage, aLength);
|
||||
}
|
||||
|
||||
extern "C" void otPlatBorderRoutingProcessDhcp6PdPrefix(otInstance *aInstance,
|
||||
const otBorderRoutingPrefixTableEntry *aPrefixInfo)
|
||||
{
|
||||
AssertPointerIsNotNull(aPrefixInfo);
|
||||
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().ProcessDhcpPdPrefix(*aPrefixInfo);
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
|
||||
|
||||
} // namespace BorderRouter
|
||||
|
||||
@@ -540,6 +540,19 @@ public:
|
||||
mPdPrefixManager.ProcessPlatformGeneratedRa(aRouterAdvert, aLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a prefix delegated from a DHCPv6 PD server. The prefix is received on the DHCPv6 PD client callback and
|
||||
* then this method can be used to configure the prefix in the Routing Manager module.
|
||||
*
|
||||
* Note: This method is a part of DHCPv6 PD support on Thread border routers. For platforms where it doesn't make
|
||||
* sense to generate a RA to set a DHCPv6 PD prefix this method can be used to set the prefix directly. The lifetime
|
||||
* of the prefix can be updated by calling the function again with updated values.
|
||||
*
|
||||
* @param[in] aPrefixInfo Prefix information structure received from the DHCPv6 PD server.
|
||||
*
|
||||
*/
|
||||
void ProcessDhcpPdPrefix(const PrefixTableEntry &aPrefixInfo) { mPdPrefixManager.ProcessDhcpPdPrefix(aPrefixInfo); }
|
||||
|
||||
/**
|
||||
* Enables / Disables the functions for DHCPv6 PD.
|
||||
*
|
||||
@@ -753,6 +766,7 @@ private:
|
||||
void SetFrom(const RouterAdvert::Header &aRaHeader);
|
||||
void SetFrom(const PrefixInfoOption &aPio);
|
||||
void SetFrom(const RouteInfoOption &aRio);
|
||||
void SetFrom(const PrefixTableEntry &aPrefixTableEntry);
|
||||
Type GetType(void) const { return mType; }
|
||||
bool IsOnLinkPrefix(void) const { return (mType == kTypeOnLink); }
|
||||
bool IsRoutePrefix(void) const { return (mType == kTypeRoute); }
|
||||
@@ -762,6 +776,7 @@ private:
|
||||
void ClearValidLifetime(void) { mValidLifetime = 0; }
|
||||
TimeMilli GetExpireTime(void) const;
|
||||
TimeMilli GetStaleTime(void) const;
|
||||
TimeMilli GetStaleTimeFromPreferredLifetime(void) const;
|
||||
RoutePreference GetPreference(void) const;
|
||||
bool operator==(const Entry &aOther) const;
|
||||
bool Matches(const Matcher &aMatcher) const;
|
||||
@@ -1276,6 +1291,7 @@ private:
|
||||
Dhcp6PdState GetState(void) const;
|
||||
|
||||
void ProcessPlatformGeneratedRa(const uint8_t *aRouterAdvert, uint16_t aLength);
|
||||
void ProcessDhcpPdPrefix(const PrefixTableEntry &aPrefixTableEntry);
|
||||
Error GetPrefixInfo(PrefixTableEntry &aInfo) const;
|
||||
Error GetProcessedRaInfo(PdProcessedRaInfo &aPdProcessedRaInfo) const;
|
||||
void HandleTimer(void) { WithdrawPrefix(); }
|
||||
@@ -1290,7 +1306,8 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
Error Process(const RouterAdvert::RxMessage &aMessage);
|
||||
Error Process(const RouterAdvert::RxMessage *aMessage, const PrefixTableEntry *aPrefixTableEntry);
|
||||
bool ProcessPrefixEntry(DiscoveredPrefixTable::Entry &aEntry, DiscoveredPrefixTable::Entry &aFavoredEntry);
|
||||
void EvaluateStateChange(Dhcp6PdState aOldState);
|
||||
void WithdrawPrefix(void);
|
||||
void StartStop(bool aStart);
|
||||
|
||||
Reference in New Issue
Block a user