[posix] install high priority kernel routes for OMR prefixes (#7636)

This commit is contained in:
Simon Lin
2022-05-09 22:30:18 -07:00
committed by GitHub
parent d068df82a6
commit d9dd34ea6f
9 changed files with 287 additions and 21 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (205)
#define OPENTHREAD_API_VERSION (206)
/**
* @addtogroup api-instance
+14
View File
@@ -230,6 +230,20 @@ struct otJoinerDiscerner;
otError otNetDataSteeringDataCheckJoinerWithDiscerner(otInstance * aInstance,
const struct otJoinerDiscerner *aDiscerner);
/**
* This function checks whether a given Prefix can act as a valid OMR prefix and also the Leader's Network Data contains
* this prefix.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aPrefix A pointer to the IPv6 prefix.
*
* @returns Whether @p aPrefix is a valid OMR prefix and Leader's Network Data contains the OMR prefix @p aPrefix.
*
* @note This API is only available when `OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE` is used.
*
*/
bool otNetDataContainsOmrPrefix(otInstance *aInstance, const otIp6Prefix *aPrefix);
/**
* @}
*
+7
View File
@@ -60,6 +60,13 @@ exit:
return error;
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
bool otNetDataContainsOmrPrefix(otInstance *aInstance, const otIp6Prefix *aPrefix)
{
return AsCoreType(aInstance).Get<NetworkData::Leader>().ContainsOmrPrefix(AsCoreType(aPrefix));
}
#endif
otError otNetDataGetNextRoute(otInstance *aInstance, otNetworkDataIterator *aIterator, otExternalRouteConfig *aConfig)
{
Error error = kErrorNone;
+19 -2
View File
@@ -185,6 +185,25 @@ public:
*/
Error HandleInfraIfStateChanged(uint32_t aInfraIfIndex, bool aIsRunning);
/**
* This method checks if the on-mesh prefix configuration is a valid OMR prefix.
*
* @param[in] aOnMeshPrefixConfig The on-mesh prefix configuration to check.
*
* @returns Whether the on-mesh prefix configuration is a valid OMR prefix.
*
*/
static bool IsValidOmrPrefix(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
/**
* This method checks if the OMR prefix is valid (i.e. GUA/ULA prefix with length being 64).
*
* @param[in] aOmrPrefix The OMR prefix to check.
* @returns Whether the OMR prefix is valid.
*
*/
static bool IsValidOmrPrefix(const Ip6::Prefix &aOmrPrefix);
private:
typedef NetworkData::RoutePreference RoutePreference;
@@ -347,8 +366,6 @@ private:
void ResetDiscoveredPrefixStaleTimer(void);
static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix);
static bool IsValidOmrPrefix(const NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
static bool IsValidOmrPrefix(const Ip6::Prefix &aOmrPrefix);
static bool IsValidOnLinkPrefix(const RouterAdv::PrefixInfoOption &aPio);
static bool IsValidOnLinkPrefix(const Ip6::Prefix &aOnLinkPrefix);
@@ -1378,6 +1378,45 @@ exit:
return error;
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
bool Leader::ContainsOmrPrefix(const Ip6::Prefix &aPrefix)
{
PrefixTlv *prefixTlv;
bool contains = false;
VerifyOrExit(BorderRouter::RoutingManager::IsValidOmrPrefix(aPrefix));
prefixTlv = FindPrefix(aPrefix);
VerifyOrExit(prefixTlv != nullptr);
for (int i = 0; i < 2; i++)
{
const BorderRouterTlv *borderRouter = prefixTlv->FindSubTlv<BorderRouterTlv>(/* aStable */ (i == 0));
if (borderRouter == nullptr)
{
continue;
}
for (const BorderRouterEntry *entry = borderRouter->GetFirstEntry(); entry <= borderRouter->GetLastEntry();
entry = entry->GetNext())
{
OnMeshPrefixConfig config;
config.SetFrom(*prefixTlv, *borderRouter, *entry);
if (BorderRouter::RoutingManager::IsValidOmrPrefix(config))
{
ExitNow(contains = true);
}
}
}
exit:
return contains;
}
#endif
} // namespace NetworkData
} // namespace ot
@@ -173,6 +173,19 @@ public:
*/
Error RemoveStaleChildEntries(Coap::ResponseHandler aHandler, void *aContext);
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
/**
* This method indicates whether a given Prefix can act as a valid OMR prefix and exists in the network data.
*
* @param[in] aPrefix The OMR prefix to check.
*
* @retval TRUE If @p aPrefix is a valid OMR prefix and Network Data contains @p aPrefix.
* @retval FALSE Otherwise.
*
*/
bool ContainsOmrPrefix(const Ip6::Prefix &aPrefix);
#endif
private:
class ChangedFlags
{
+1
View File
@@ -169,6 +169,7 @@ class OnMeshPrefixConfig : public otBorderRouterConfig,
public Equatable<OnMeshPrefixConfig>
{
friend class NetworkData;
friend class Leader;
friend class Local;
friend class Publisher;
+155 -18
View File
@@ -137,6 +137,7 @@ extern int
#endif // defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
#include <openthread/border_router.h>
#include <openthread/icmp6.h>
#include <openthread/instance.h>
#include <openthread/ip6.h>
@@ -193,6 +194,13 @@ using namespace ot::Posix::Ip6Utils;
static uint32_t sNetlinkSequence = 0; ///< Netlink message sequence.
#endif
#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__
static constexpr uint32_t kOmrRoutesPriority = OPENTHREAD_POSIX_CONFIG_OMR_ROUTES_PRIORITY;
static constexpr uint8_t kMaxOmrRoutesNum = OPENTHREAD_POSIX_CONFIG_MAX_OMR_ROUTES_NUM;
static uint8_t sAddedOmrRoutesNum = 0;
static otIp6Prefix sAddedOmrRoutes[kMaxOmrRoutesNum];
#endif
#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
static constexpr uint32_t kExternalRoutePriority = OPENTHREAD_POSIX_CONFIG_EXTERNAL_ROUTE_PRIORITY;
static constexpr uint8_t kMaxExternalRoutesNum = OPENTHREAD_POSIX_CONFIG_MAX_EXTERNAL_ROUTE_NUM;
@@ -345,8 +353,19 @@ void AddRtAttrUint32(struct nlmsghdr *aHeader, uint32_t aMaxLen, uint8_t aType,
AddRtAttr(aHeader, aMaxLen, aType, &aData, sizeof(aData));
}
static void UpdateUnicastLinux(const otIp6AddressInfo &aAddressInfo, bool aIsAdded)
#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE
static bool IsOmrAddress(otInstance *aInstance, const otIp6AddressInfo &aAddressInfo)
{
otIp6Prefix addressPrefix{*aAddressInfo.mAddress, aAddressInfo.mPrefixLength};
return otNetDataContainsOmrPrefix(aInstance, &addressPrefix);
}
#endif
static void UpdateUnicastLinux(otInstance *aInstance, const otIp6AddressInfo &aAddressInfo, bool aIsAdded)
{
OT_UNUSED_VARIABLE(aInstance);
struct
{
struct nlmsghdr nh;
@@ -380,12 +399,26 @@ static void UpdateUnicastLinux(const otIp6AddressInfo &aAddressInfo, bool aIsAdd
AddRtAttr(&req.nh, sizeof(req), IFA_CACHEINFO, &cacheinfo, sizeof(cacheinfo));
}
#if OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC > 0
if (aAddressInfo.mScope > ot::Ip6::Address::kLinkLocalScope)
#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE
if (IsOmrAddress(aInstance, aAddressInfo))
{
AddRtAttrUint32(&req.nh, sizeof(req), IFA_RT_PRIORITY, OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC);
// Remove prefix route for OMR address if `OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE` is enabled to
// avoid having two routes.
if (aIsAdded)
{
AddRtAttrUint32(&req.nh, sizeof(req), IFA_FLAGS, IFA_F_NOPREFIXROUTE);
}
}
else
#endif
{
#if OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC > 0
if (aAddressInfo.mScope > ot::Ip6::Address::kLinkLocalScope)
{
AddRtAttrUint32(&req.nh, sizeof(req), IFA_RT_PRIORITY, OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC);
}
#endif
}
if (send(sNetlinkFd, &req, req.nh.nlmsg_len, 0) != -1)
{
@@ -410,7 +443,7 @@ static void UpdateUnicast(otInstance *aInstance, const otIp6AddressInfo &aAddres
assert(sIpFd >= 0);
#if defined(__linux__)
UpdateUnicastLinux(aAddressInfo, aIsAdded);
UpdateUnicastLinux(aInstance, aAddressInfo, aIsAdded);
#elif defined(__APPLE__) || defined(__NetBSD__) || defined(__FreeBSD__)
{
int rval;
@@ -531,8 +564,10 @@ exit:
}
}
#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
static otError AddExternalRoute(const otIp6Prefix &aPrefix)
#if __linux__ && \
(OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE || OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE)
static otError AddRoute(const otIp6Prefix &aPrefix, uint32_t aPriority)
{
constexpr unsigned int kBufSize = 128;
struct
@@ -548,7 +583,6 @@ static otError AddExternalRoute(const otIp6Prefix &aPrefix)
VerifyOrExit(netifIdx > 0, error = OT_ERROR_INVALID_STATE);
VerifyOrExit(sNetlinkFd >= 0, error = OT_ERROR_INVALID_STATE);
VerifyOrExit(sAddedExternalRoutesNum < kMaxExternalRoutesNum, error = OT_ERROR_NO_BUFS);
req.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
@@ -570,7 +604,7 @@ static otError AddExternalRoute(const otIp6Prefix &aPrefix)
otIp6AddressToString(&aPrefix.mPrefix, addrBuf, OT_IP6_ADDRESS_STRING_SIZE);
inet_pton(AF_INET6, addrBuf, data);
AddRtAttr(reinterpret_cast<nlmsghdr *>(&req), sizeof(req), RTA_DST, data, sizeof(data));
AddRtAttrUint32(&req.header, sizeof(req), RTA_PRIORITY, kExternalRoutePriority);
AddRtAttrUint32(&req.header, sizeof(req), RTA_PRIORITY, aPriority);
AddRtAttrUint32(&req.header, sizeof(req), RTA_OIF, netifIdx);
if (send(sNetlinkFd, &req, sizeof(req), 0) < 0)
@@ -582,7 +616,7 @@ exit:
return error;
}
static otError DeleteExternalRoute(const otIp6Prefix &aPrefix)
static otError DeleteRoute(const otIp6Prefix &aPrefix)
{
constexpr unsigned int kBufSize = 512;
struct
@@ -631,6 +665,105 @@ exit:
return error;
}
#endif // __linux__ && (OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE ||
// OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE)
#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__
static bool HasAddedOmrRoute(const otIp6Prefix &aOmrPrefix)
{
bool found = false;
for (uint8_t i = 0; i < sAddedOmrRoutesNum; ++i)
{
if (otIp6ArePrefixesEqual(&sAddedOmrRoutes[i], &aOmrPrefix))
{
found = true;
break;
}
}
return found;
}
static otError AddOmrRoute(const otIp6Prefix &aPrefix)
{
otError error;
VerifyOrExit(sAddedOmrRoutesNum < kMaxOmrRoutesNum, error = OT_ERROR_NO_BUFS);
error = AddRoute(aPrefix, kOmrRoutesPriority);
exit:
return error;
}
static void UpdateOmrRoutes(otInstance *aInstance)
{
otError error;
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
otBorderRouterConfig config;
char prefixString[OT_IP6_PREFIX_STRING_SIZE];
// Remove kernel routes if the OMR prefix is removed
for (int i = 0; i < static_cast<int>(sAddedOmrRoutesNum); ++i)
{
if (otNetDataContainsOmrPrefix(aInstance, &sAddedOmrRoutes[i]))
{
continue;
}
otIp6PrefixToString(&sAddedOmrRoutes[i], prefixString, sizeof(prefixString));
if ((error = DeleteRoute(sAddedOmrRoutes[i])) != OT_ERROR_NONE)
{
otLogWarnPlat("[netif] Failed to delete an OMR route %s in kernel: %s", prefixString,
otThreadErrorToString(error));
}
else
{
sAddedOmrRoutes[i] = sAddedOmrRoutes[sAddedOmrRoutesNum - 1];
--sAddedOmrRoutesNum;
--i;
otLogInfoPlat("[netif] Successfully deleted an OMR route %s in kernel", prefixString);
}
}
// Add kernel routes for OMR prefixes in Network Data
while (otNetDataGetNextOnMeshPrefix(aInstance, &iterator, &config) == OT_ERROR_NONE)
{
if (HasAddedOmrRoute(config.mPrefix))
{
continue;
}
otIp6PrefixToString(&config.mPrefix, prefixString, sizeof(prefixString));
if ((error = AddOmrRoute(config.mPrefix)) != OT_ERROR_NONE)
{
otLogWarnPlat("[netif] Failed to add an OMR route %s in kernel: %s", prefixString,
otThreadErrorToString(error));
}
else
{
sAddedOmrRoutes[sAddedOmrRoutesNum++] = config.mPrefix;
otLogInfoPlat("[netif] Successfully added an OMR route %s in kernel: %s", prefixString);
}
}
}
#endif // OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__
#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
static otError AddExternalRoute(const otIp6Prefix &aPrefix)
{
otError error;
VerifyOrExit(sAddedExternalRoutesNum < kMaxExternalRoutesNum, error = OT_ERROR_NO_BUFS);
error = AddRoute(aPrefix, kExternalRoutePriority);
exit:
return error;
}
bool HasExternalRouteInNetData(otInstance *aInstance, const otIp6Prefix &aExternalRoute)
{
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
@@ -676,9 +809,10 @@ static void UpdateExternalRoutes(otInstance *aInstance)
{
continue;
}
if ((error = DeleteExternalRoute(sAddedExternalRoutes[i])) != OT_ERROR_NONE)
otIp6PrefixToString(&sAddedExternalRoutes[i], prefixString, sizeof(prefixString));
if ((error = DeleteRoute(sAddedExternalRoutes[i])) != OT_ERROR_NONE)
{
otIp6PrefixToString(&sAddedExternalRoutes[i], prefixString, sizeof(prefixString));
otLogWarnPlat("[netif] Failed to delete an external route %s in kernel: %s", prefixString,
otThreadErrorToString(error));
}
@@ -687,6 +821,7 @@ static void UpdateExternalRoutes(otInstance *aInstance)
sAddedExternalRoutes[i] = sAddedExternalRoutes[sAddedExternalRoutesNum - 1];
--sAddedExternalRoutesNum;
--i;
otLogWarnPlat("[netif] Successfully deleted an external route %s in kernel", prefixString);
}
}
@@ -698,15 +833,17 @@ static void UpdateExternalRoutes(otInstance *aInstance)
}
VerifyOrExit(sAddedExternalRoutesNum < kMaxExternalRoutesNum,
otLogWarnPlat("[netif] No buffer to add more external routes in kernel"));
otIp6PrefixToString(&config.mPrefix, prefixString, sizeof(prefixString));
if ((error = AddExternalRoute(config.mPrefix)) != OT_ERROR_NONE)
{
otIp6PrefixToString(&config.mPrefix, prefixString, sizeof(prefixString));
otLogWarnPlat("[netif] Failed to add an external route %s in kernel: %s", prefixString,
otThreadErrorToString(error));
}
else
{
sAddedExternalRoutes[sAddedExternalRoutesNum++] = config.mPrefix;
otLogWarnPlat("[netif] Successfully added an external route %s in kernel: %s", prefixString);
}
}
exit:
@@ -732,18 +869,18 @@ void platformNetifStateChange(otInstance *aInstance, otChangedFlags aFlags)
{
UpdateLink(aInstance);
}
#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
if (OT_CHANGED_THREAD_NETDATA & aFlags)
{
#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE && __linux__
UpdateOmrRoutes(aInstance);
#endif
#if OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE && __linux__
UpdateExternalRoutes(aInstance);
}
#endif
#if OPENTHREAD_POSIX_CONFIG_FIREWALL_ENABLE
if (OT_CHANGED_THREAD_NETDATA & aFlags)
{
ot::Posix::UpdateIpSets(aInstance);
}
#endif
}
}
static void processReceive(otMessage *aMessage, void *aContext)
@@ -132,11 +132,49 @@
* This setting configures the prefix route metric on the Thread network interface.
* Define as 0 to use use the default prefix route metric.
*
* Note: The feature works on Linux kernel v4.18+.
*
*/
#ifndef OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC
#define OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC 0
#endif
/**
* @def OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE
*
* Define as 1 to add OMR routes to POSIX kernel when OMR prefixes are changed in netdata.
*
* Note: This feature can be used to add OMR routes with non-default priority. Unlike
* `OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC`, it works on Linux kernels before v4.18.
* However, `OPENTHREAD_POSIX_CONFIG_NETIF_PREFIX_ROUTE_METRIC` should be preferred on Linux kernel v4.18+.
*
*/
#ifndef OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE
#define OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE 0
#endif
/**
* @def OPENTHREAD_POSIX_CONFIG_OMR_ROUTES_PRIORITY
*
* This macro defines the priority of OMR routes added to kernel. The larger the number, the lower the priority. We
* need to assign a high priority to such routes so that kernel prefers the Thread link rather than infrastructure.
* Otherwise we may unnecessarily transmit packets via infrastructure, which potentially causes looping issue.
*
*/
#ifndef OPENTHREAD_POSIX_CONFIG_OMR_ROUTES_PRIORITY
#define OPENTHREAD_POSIX_CONFIG_OMR_ROUTES_PRIORITY 1
#endif
/**
* @def OPENTHREAD_POSIX_CONFIG_MAX_OMR_ROUTES_NUM
*
* This macro defines the max number of OMR routes that can be added to kernel.
*
*/
#ifndef OPENTHREAD_POSIX_CONFIG_MAX_OMR_ROUTES_NUM
#define OPENTHREAD_POSIX_CONFIG_MAX_OMR_ROUTES_NUM OPENTHREAD_CONFIG_IP6_SLAAC_NUM_ADDRESSES
#endif
/**
* @def OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE
*