mirror of
https://github.com/espressif/openthread.git
synced 2026-10-16 04:37:42 +00:00
[mlr] implement native multicast routing for backbone router (#5793)
This commit implements native multicast routing using kernel Ip6 multicast forwarding.
This commit is contained in:
@@ -300,6 +300,7 @@ LOCAL_SRC_FILES := \
|
||||
src/posix/platform/hdlc_interface.cpp \
|
||||
src/posix/platform/logging.cpp \
|
||||
src/posix/platform/misc.cpp \
|
||||
src/posix/platform/multicast_routing.cpp \
|
||||
src/posix/platform/netif.cpp \
|
||||
src/posix/platform/radio.cpp \
|
||||
src/posix/platform/radio_url.cpp \
|
||||
|
||||
+1
-1
@@ -230,7 +230,7 @@ do_build_otbr_docker()
|
||||
local otdir
|
||||
local otbrdir
|
||||
local otbr_options="-DOT_DUA=ON -DOT_MLR=ON -DOT_COVERAGE=ON -DOTBR_REST=OFF -DOTBR_WEB=OFF"
|
||||
local otbr_commit=${OTBR_COMMIT:-8d0b6ccd857441208f56ed29050a9367d8d74a62} # [backbone-router] implement Backbone ND proxy #581
|
||||
local otbr_commit=${OTBR_COMMIT:-5092e71b06b23f78f2288fcc5386bce3a8986bb1} # [backbone-router] remove MLR multicast routing using smcroute #604
|
||||
local otbr_docker_image=${OTBR_DOCKER_IMAGE:-otbr-ot12-backbone-ci}
|
||||
|
||||
otbrdir=$(mktemp -d -t otbr_XXXXXX)
|
||||
|
||||
@@ -2218,6 +2218,35 @@ const char *otLogLevelToPrefixString(otLogLevel aLogLevel);
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_LOG_DEFINE_AS_MACRO_ONLY
|
||||
|
||||
#define _otLogResult(aRegion, aError, ...) \
|
||||
do \
|
||||
{ \
|
||||
otError _err = (aError); \
|
||||
\
|
||||
if (_err == OT_ERROR_NONE) \
|
||||
{ \
|
||||
otLogInfo##aRegion(OT_FIRST_ARG(__VA_ARGS__) ": %s" OT_REST_ARGS(__VA_ARGS__), \
|
||||
otThreadErrorToString(_err)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
otLogWarn##aRegion(OT_FIRST_ARG(__VA_ARGS__) ": %s" OT_REST_ARGS(__VA_ARGS__), \
|
||||
otThreadErrorToString(_err)); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
/**
|
||||
* @def otLogResultPlat
|
||||
*
|
||||
* This function generates a log for the Plat region according to the error result. If @p aError is `OT_ERROR_NONE`, the
|
||||
* log level is info. Otherwise the log level is warn.
|
||||
*
|
||||
* @param[in] aError The error result.
|
||||
* @param[in] ... Arguments for the format specification.
|
||||
*
|
||||
*/
|
||||
#define otLogResultPlat(aError, ...) _otLogResult(Plat, aError, OT_FIRST_ARG(__VA_ARGS__) OT_REST_ARGS(__VA_ARGS__))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -533,6 +533,15 @@ public:
|
||||
*/
|
||||
const uint8_t *GetBytes(void) const { return mFields.m8; }
|
||||
|
||||
/**
|
||||
* This method sets the IPv6 address from a given byte array.
|
||||
*
|
||||
* @param[in] aBuffer Pointer to an array containing the IPv6 address. `kSize` bytes from the buffer
|
||||
* are copied to form the IPv6 address.
|
||||
*
|
||||
*/
|
||||
void SetBytes(const uint8_t *aBuffer) { memcpy(mFields.m8, aBuffer, kSize); }
|
||||
|
||||
/**
|
||||
* This method indicates whether or not the IPv6 address is the Unspecified Address.
|
||||
*
|
||||
@@ -885,6 +894,20 @@ public:
|
||||
*/
|
||||
InfoString ToString(void) const;
|
||||
|
||||
/**
|
||||
* This method overloads operator `<` to compare two IPv6 addresses.
|
||||
*
|
||||
* @param[in] aOther The other IPv6 address to compare with.
|
||||
*
|
||||
* @retval true The IPv6 address is smaller than @p aOther.
|
||||
* @retval false The IPv6 address is larger than or equal to @p aOther.
|
||||
*
|
||||
*/
|
||||
bool operator<(const Ip6::Address &aOther) const
|
||||
{
|
||||
return memcmp(mFields.m8, aOther.mFields.m8, sizeof(Ip6::Address)) < 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void SetPrefix(uint8_t aOffset, const uint8_t *aPrefix, uint8_t aPrefixLength);
|
||||
void SetToLocator(const NetworkPrefix &aNetworkPrefix, uint16_t aLocator);
|
||||
|
||||
+7
-20
@@ -101,15 +101,13 @@ void __gcov_flush();
|
||||
*/
|
||||
enum
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
OT_POSIX_OPT_BACKBONE_INTERFACE_NAME = 'B',
|
||||
#endif
|
||||
OT_POSIX_OPT_DEBUG_LEVEL = 'd',
|
||||
OT_POSIX_OPT_DRY_RUN = 'n',
|
||||
OT_POSIX_OPT_HELP = 'h',
|
||||
OT_POSIX_OPT_INTERFACE_NAME = 'I',
|
||||
OT_POSIX_OPT_TIME_SPEED = 's',
|
||||
OT_POSIX_OPT_VERBOSE = 'v',
|
||||
OT_POSIX_OPT_DEBUG_LEVEL = 'd',
|
||||
OT_POSIX_OPT_DRY_RUN = 'n',
|
||||
OT_POSIX_OPT_HELP = 'h',
|
||||
OT_POSIX_OPT_INTERFACE_NAME = 'I',
|
||||
OT_POSIX_OPT_TIME_SPEED = 's',
|
||||
OT_POSIX_OPT_VERBOSE = 'v',
|
||||
|
||||
OT_POSIX_OPT_SHORT_MAX = 128,
|
||||
|
||||
@@ -118,9 +116,7 @@ enum
|
||||
};
|
||||
|
||||
static const struct option kOptions[] = {
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
{"backbone-interface-name", required_argument, NULL, OT_POSIX_OPT_BACKBONE_INTERFACE_NAME},
|
||||
#endif
|
||||
{"debug-level", required_argument, NULL, OT_POSIX_OPT_DEBUG_LEVEL},
|
||||
{"dry-run", no_argument, NULL, OT_POSIX_OPT_DRY_RUN},
|
||||
{"help", no_argument, NULL, OT_POSIX_OPT_HELP},
|
||||
@@ -137,9 +133,7 @@ static void PrintUsage(const char *aProgramName, FILE *aStream, int aExitCode)
|
||||
"Syntax:\n"
|
||||
" %s [Options] RadioURL\n"
|
||||
"Options:\n"
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
" -B --backbone-interface-name Backbone network interface name.\n"
|
||||
#endif
|
||||
" -d --debug-level Debug level of logging.\n"
|
||||
" -h --help Display this usage information.\n"
|
||||
" -I --interface-name name Thread network interface name.\n"
|
||||
@@ -173,12 +167,7 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig)
|
||||
while (true)
|
||||
{
|
||||
int index = 0;
|
||||
int option = getopt_long(aArgCount, aArgVector,
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
"B:"
|
||||
#endif
|
||||
"d:hI:ns:v",
|
||||
kOptions, &index);
|
||||
int option = getopt_long(aArgCount, aArgVector, "B:d:hI:ns:v", kOptions, &index);
|
||||
|
||||
if (option == -1)
|
||||
{
|
||||
@@ -196,11 +185,9 @@ static void ParseArg(int aArgCount, char *aArgVector[], PosixConfig *aConfig)
|
||||
case OT_POSIX_OPT_INTERFACE_NAME:
|
||||
aConfig->mPlatformConfig.mInterfaceName = optarg;
|
||||
break;
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
case OT_POSIX_OPT_BACKBONE_INTERFACE_NAME:
|
||||
aConfig->mPlatformConfig.mBackboneInterfaceName = optarg;
|
||||
break;
|
||||
#endif
|
||||
case OT_POSIX_OPT_DRY_RUN:
|
||||
aConfig->mIsDryRun = true;
|
||||
break;
|
||||
|
||||
@@ -66,6 +66,7 @@ add_library(openthread-posix
|
||||
hdlc_interface.cpp
|
||||
logging.cpp
|
||||
misc.cpp
|
||||
multicast_routing.cpp
|
||||
netif.cpp
|
||||
radio.cpp
|
||||
radio_url.cpp
|
||||
|
||||
@@ -50,6 +50,7 @@ libopenthread_posix_a_SOURCES = \
|
||||
hdlc_interface.cpp \
|
||||
logging.cpp \
|
||||
misc.cpp \
|
||||
multicast_routing.cpp \
|
||||
netif.cpp \
|
||||
radio.cpp \
|
||||
radio_url.cpp \
|
||||
@@ -68,6 +69,7 @@ libopenthread_posix_a_LIBADD
|
||||
|
||||
noinst_HEADERS = \
|
||||
hdlc_interface.hpp \
|
||||
multicast_routing.hpp \
|
||||
openthread-posix-config.h \
|
||||
platform-posix.h \
|
||||
radio_url.hpp \
|
||||
|
||||
@@ -35,17 +35,19 @@
|
||||
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
|
||||
#include "multicast_routing.hpp"
|
||||
#include "platform-posix.h"
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
char gBackboneNetifName[IFNAMSIZ] = "";
|
||||
unsigned int gBackboneNetifIndex = 0;
|
||||
char gBackboneNetifName[IFNAMSIZ] = "";
|
||||
unsigned int gBackboneNetifIndex = 0;
|
||||
static ot::Posix::MulticastRoutingManager sMulticastRoutingManager;
|
||||
|
||||
void platformBackboneInit(otInstance *aInstance, const char *aInterfaceName)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
VerifyOrExit(aInterfaceName != nullptr, otLogInfoPlat("Backbone interface is not configured"));
|
||||
VerifyOrDie(aInterfaceName != nullptr, OT_EXIT_INVALID_ARGUMENTS);
|
||||
|
||||
VerifyOrDie(strnlen(aInterfaceName, IFNAMSIZ) <= IFNAMSIZ - 1, OT_EXIT_INVALID_ARGUMENTS);
|
||||
strcpy(gBackboneNetifName, aInterfaceName);
|
||||
@@ -55,8 +57,22 @@ void platformBackboneInit(otInstance *aInstance, const char *aInterfaceName)
|
||||
|
||||
otLogInfoPlat("Backbone interface is configured to %s (%d)", gBackboneNetifName, gBackboneNetifIndex);
|
||||
|
||||
exit:
|
||||
return;
|
||||
sMulticastRoutingManager.Init(aInstance);
|
||||
}
|
||||
|
||||
void platformBackboneUpdateFdSet(fd_set &aReadFdSet, int &aMaxFd)
|
||||
{
|
||||
sMulticastRoutingManager.UpdateFdSet(aReadFdSet, aMaxFd);
|
||||
}
|
||||
|
||||
void platformBackboneProcess(const fd_set &aReadSet)
|
||||
{
|
||||
sMulticastRoutingManager.Process(aReadSet);
|
||||
}
|
||||
|
||||
void platformBackboneStateChange(otInstance *aInstance, otChangedFlags aFlags)
|
||||
{
|
||||
sMulticastRoutingManager.HandleStateChange(aInstance, aFlags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 "posix/platform/multicast_routing.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
|
||||
#include <assert.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#if __linux__
|
||||
#include <linux/mroute6.h>
|
||||
#else
|
||||
#error "Multicast Routing feature is not ported to non-Linux platforms yet."
|
||||
#endif
|
||||
|
||||
#include <openthread/backbone_router_ftd.h>
|
||||
|
||||
#include "core/common/logging.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
void MulticastRoutingManager::Init(otInstance *aInstance)
|
||||
{
|
||||
mInstance = aInstance;
|
||||
|
||||
otBackboneRouterSetMulticastListenerCallback(aInstance,
|
||||
&MulticastRoutingManager::HandleBackboneMulticastListenerEvent, this);
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::HandleBackboneMulticastListenerEvent(void * aContext,
|
||||
otBackboneRouterMulticastListenerEvent aEvent,
|
||||
const otIp6Address * aAddress)
|
||||
{
|
||||
static_cast<MulticastRoutingManager *>(aContext)->HandleBackboneMulticastListenerEvent(
|
||||
aEvent, static_cast<const Ip6::Address &>(*aAddress));
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::HandleBackboneMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent,
|
||||
const Ip6::Address & aAddress)
|
||||
{
|
||||
switch (aEvent)
|
||||
{
|
||||
case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ADDED:
|
||||
Add(aAddress);
|
||||
break;
|
||||
case OT_BACKBONE_ROUTER_MULTICAST_LISTENER_REMOVED:
|
||||
Remove(aAddress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::Enable(void)
|
||||
{
|
||||
VerifyOrExit(!IsEnabled());
|
||||
|
||||
InitMulticastRouterSock();
|
||||
|
||||
otLogResultPlat(OT_ERROR_NONE, "MulticastRoutingManager: %s", __FUNCTION__);
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::Disable(void)
|
||||
{
|
||||
FinalizeMulticastRouterSock();
|
||||
|
||||
otLogResultPlat(OT_ERROR_NONE, "MulticastRoutingManager: %s", __FUNCTION__);
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::Add(const Ip6::Address &aAddress)
|
||||
{
|
||||
VerifyOrExit(IsEnabled());
|
||||
|
||||
UnblockInboundMulticastForwardingCache(aAddress);
|
||||
otLogResultPlat(OT_ERROR_NONE, "MulticastRoutingManager: %s: %s", __FUNCTION__, aAddress.ToString().AsCString());
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::Remove(const Ip6::Address &aAddress)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(IsEnabled());
|
||||
|
||||
RemoveInboundMulticastForwardingCache(aAddress);
|
||||
otLogResultPlat(error, "MulticastRoutingManager: %s: %s", __FUNCTION__, aAddress.ToString().AsCString());
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
bool MulticastRoutingManager::HasMulticastListener(const Ip6::Address &aAddress) const
|
||||
{
|
||||
bool found = false;
|
||||
otBackboneRouterMulticastListenerIterator iter = OT_BACKBONE_ROUTER_MULTICAST_LISTENER_ITERATOR_INIT;
|
||||
otBackboneRouterMulticastListenerInfo listenerInfo;
|
||||
|
||||
while (otBackboneRouterMulticastListenerGetNext(mInstance, &iter, &listenerInfo) == OT_ERROR_NONE)
|
||||
{
|
||||
VerifyOrExit(static_cast<const Ip6::Address &>(listenerInfo.mAddress) != aAddress, found = true);
|
||||
}
|
||||
|
||||
exit:
|
||||
return found;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::UpdateFdSet(fd_set &aReadFdSet, int &aMaxFd) const
|
||||
{
|
||||
VerifyOrExit(IsEnabled());
|
||||
|
||||
FD_SET(mMulticastRouterSock, &aReadFdSet);
|
||||
aMaxFd = OT_MAX(aMaxFd, mMulticastRouterSock);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::Process(const fd_set &aReadFdSet)
|
||||
{
|
||||
VerifyOrExit(IsEnabled());
|
||||
|
||||
ExpireMulticastForwardingCache();
|
||||
|
||||
if (FD_ISSET(mMulticastRouterSock, &aReadFdSet))
|
||||
{
|
||||
ProcessMulticastRouterMessages();
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::InitMulticastRouterSock(void)
|
||||
{
|
||||
int one = 1;
|
||||
struct icmp6_filter filter;
|
||||
struct mif6ctl mif6ctl;
|
||||
|
||||
// Create a Multicast Routing socket
|
||||
mMulticastRouterSock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
||||
VerifyOrDie(mMulticastRouterSock != -1, OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
// Enable Multicast Forwarding in Kernel
|
||||
VerifyOrDie(0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_INIT, &one, sizeof(one)), OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
// Filter all ICMPv6 messages
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||
VerifyOrDie(0 == setsockopt(mMulticastRouterSock, IPPROTO_ICMPV6, ICMP6_FILTER, (void *)&filter, sizeof(filter)),
|
||||
OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
memset(&mif6ctl, 0, sizeof(mif6ctl));
|
||||
mif6ctl.mif6c_flags = 0;
|
||||
mif6ctl.vifc_threshold = 1;
|
||||
mif6ctl.vifc_rate_limit = 0;
|
||||
|
||||
// Add Thread network interface to MIF
|
||||
mif6ctl.mif6c_mifi = kMifIndexThread;
|
||||
mif6ctl.mif6c_pifi = if_nametoindex(gNetifName);
|
||||
VerifyOrDie(mif6ctl.mif6c_pifi > 0, OT_EXIT_ERROR_ERRNO);
|
||||
VerifyOrDie(0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_ADD_MIF, &mif6ctl, sizeof(mif6ctl)),
|
||||
OT_EXIT_ERROR_ERRNO);
|
||||
|
||||
// Add Backbone network interface to MIF
|
||||
mif6ctl.mif6c_mifi = kMifIndexBackbone;
|
||||
mif6ctl.mif6c_pifi = if_nametoindex(gBackboneNetifName);
|
||||
VerifyOrDie(mif6ctl.mif6c_pifi > 0, OT_EXIT_ERROR_ERRNO);
|
||||
VerifyOrDie(0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_ADD_MIF, &mif6ctl, sizeof(mif6ctl)),
|
||||
OT_EXIT_ERROR_ERRNO);
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::FinalizeMulticastRouterSock(void)
|
||||
{
|
||||
VerifyOrExit(IsEnabled());
|
||||
|
||||
close(mMulticastRouterSock);
|
||||
mMulticastRouterSock = -1;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::ProcessMulticastRouterMessages(void)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
char buf[sizeof(struct mrt6msg)];
|
||||
int nr;
|
||||
struct mrt6msg *mrt6msg;
|
||||
Ip6::Address src, dst;
|
||||
|
||||
nr = read(mMulticastRouterSock, buf, sizeof(buf));
|
||||
|
||||
VerifyOrExit(nr >= static_cast<int>(sizeof(struct mrt6msg)), error = OT_ERROR_FAILED);
|
||||
|
||||
mrt6msg = reinterpret_cast<struct mrt6msg *>(buf);
|
||||
|
||||
VerifyOrExit(mrt6msg->im6_mbz == 0);
|
||||
VerifyOrExit(mrt6msg->im6_msgtype == MRT6MSG_NOCACHE);
|
||||
|
||||
src.SetBytes(mrt6msg->im6_src.s6_addr);
|
||||
dst.SetBytes(mrt6msg->im6_dst.s6_addr);
|
||||
|
||||
error = AddMulticastForwardingCache(src, dst, static_cast<MifIndex>(mrt6msg->im6_mif));
|
||||
|
||||
exit:
|
||||
otLogResultPlat(error, "MulticastRoutingManager: %s", __FUNCTION__);
|
||||
}
|
||||
|
||||
otError MulticastRoutingManager::AddMulticastForwardingCache(const Ip6::Address &aSrcAddr,
|
||||
const Ip6::Address &aGroupAddr,
|
||||
MifIndex aIif)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
struct mf6cctl mf6cctl;
|
||||
MifIndex forwardMif = kMifIndexNone;
|
||||
|
||||
VerifyOrExit(aIif == kMifIndexThread || aIif == kMifIndexBackbone, error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
ExpireMulticastForwardingCache();
|
||||
|
||||
if (aIif == kMifIndexBackbone)
|
||||
{
|
||||
// Forward multicast traffic from Backbone to Thread if the group address is subscribed by any Thread device via
|
||||
// MLR.
|
||||
if (HasMulticastListener(aGroupAddr))
|
||||
{
|
||||
forwardMif = kMifIndexThread;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Forward multicast traffic from Thread to Backbone if multicast scope > kRealmLocalScope
|
||||
// TODO: (MLR) allow scope configuration of outbound multicast routing
|
||||
if (aGroupAddr.GetScope() > Ip6::Address::kRealmLocalScope)
|
||||
{
|
||||
forwardMif = kMifIndexBackbone;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&mf6cctl, 0, sizeof(mf6cctl));
|
||||
|
||||
memcpy(mf6cctl.mf6cc_origin.sin6_addr.s6_addr, aSrcAddr.GetBytes(), sizeof(mf6cctl.mf6cc_origin.sin6_addr.s6_addr));
|
||||
memcpy(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr, aGroupAddr.GetBytes(),
|
||||
sizeof(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr));
|
||||
mf6cctl.mf6cc_parent = aIif;
|
||||
|
||||
if (forwardMif != kMifIndexNone)
|
||||
{
|
||||
IF_SET(forwardMif, &mf6cctl.mf6cc_ifset);
|
||||
}
|
||||
|
||||
// Note that kernel reports repetitive `MRT6MSG_NOCACHE` upcalls with a rate limit (e.g. once per 10s for Linux).
|
||||
// Because of it, we need to add a "blocking" MFC even if there is no forwarding for this group address.
|
||||
// When a Multicast Listener is later added, the "blocking" MFC will be altered to be a "forwarding" MFC so that
|
||||
// corresponding multicast traffic can be forwarded instantly.
|
||||
VerifyOrExit(0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_ADD_MFC, &mf6cctl, sizeof(mf6cctl)),
|
||||
error = OT_ERROR_FAILED);
|
||||
|
||||
SaveMulticastForwardingCache(aSrcAddr, aGroupAddr, aIif, forwardMif);
|
||||
exit:
|
||||
otLogResultPlat(error, "MulticastRoutingManager: %s: add dynamic route: %s %s => %s %s", __FUNCTION__,
|
||||
MifIndexToString(aIif), aSrcAddr.ToString().AsCString(), aGroupAddr.ToString().AsCString(),
|
||||
MifIndexToString(forwardMif));
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::UnblockInboundMulticastForwardingCache(const Ip6::Address &aGroupAddr)
|
||||
{
|
||||
struct mf6cctl mf6cctl;
|
||||
|
||||
memset(&mf6cctl, 0, sizeof(mf6cctl));
|
||||
memcpy(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr, aGroupAddr.GetBytes(),
|
||||
sizeof(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr));
|
||||
mf6cctl.mf6cc_parent = kMifIndexBackbone;
|
||||
IF_SET(kMifIndexThread, &mf6cctl.mf6cc_ifset);
|
||||
|
||||
for (MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
|
||||
{
|
||||
otError error;
|
||||
|
||||
if (!mfc.IsValid() || mfc.mIif != kMifIndexBackbone || mfc.mOif == kMifIndexThread ||
|
||||
mfc.mGroupAddr != aGroupAddr)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Unblock this inbound route
|
||||
memcpy(mf6cctl.mf6cc_origin.sin6_addr.s6_addr, mfc.mSrcAddr.GetBytes(),
|
||||
sizeof(mf6cctl.mf6cc_origin.sin6_addr.s6_addr));
|
||||
|
||||
error = (0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_ADD_MFC, &mf6cctl, sizeof(mf6cctl)))
|
||||
? OT_ERROR_NONE
|
||||
: OT_ERROR_FAILED;
|
||||
|
||||
mfc.Set(kMifIndexBackbone, kMifIndexThread);
|
||||
|
||||
otLogResultPlat(error, "MulticastRoutingManager: %s: %s %s => %s %s", __FUNCTION__, MifIndexToString(mfc.mIif),
|
||||
mfc.mSrcAddr.ToString().AsCString(), mfc.mGroupAddr.ToString().AsCString(),
|
||||
MifIndexToString(kMifIndexThread));
|
||||
}
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::RemoveInboundMulticastForwardingCache(const Ip6::Address &aGroupAddr)
|
||||
{
|
||||
for (MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
|
||||
{
|
||||
if (mfc.IsValid() && mfc.mIif == kMifIndexBackbone && mfc.mGroupAddr == aGroupAddr)
|
||||
{
|
||||
RemoveMulticastForwardingCache(mfc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::ExpireMulticastForwardingCache(void)
|
||||
{
|
||||
struct sioc_sg_req6 sioc_sg_req6;
|
||||
uint64_t now = otPlatTimeGet();
|
||||
struct mf6cctl mf6cctl;
|
||||
|
||||
VerifyOrExit(now >= mLastExpireTime + kMulticastForwardingCacheExpiringInterval * US_PER_S);
|
||||
|
||||
mLastExpireTime = now;
|
||||
|
||||
memset(&mf6cctl, 0, sizeof(mf6cctl));
|
||||
memset(&sioc_sg_req6, 0, sizeof(sioc_sg_req6));
|
||||
|
||||
for (MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
|
||||
{
|
||||
if (mfc.IsValid() && mfc.mLastUseTime + kMulticastForwardingCacheExpireTimeout * US_PER_S < now)
|
||||
{
|
||||
if (!UpdateMulticastRouteInfo(mfc))
|
||||
{
|
||||
// The multicast route is expired
|
||||
RemoveMulticastForwardingCache(mfc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DumpMulticastForwardingCache();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
bool MulticastRoutingManager::UpdateMulticastRouteInfo(MulticastForwardingCache &aMfc) const
|
||||
{
|
||||
bool updated = false;
|
||||
struct sioc_sg_req6 sioc_sg_req6;
|
||||
|
||||
memset(&sioc_sg_req6, 0, sizeof(sioc_sg_req6));
|
||||
|
||||
memcpy(sioc_sg_req6.src.sin6_addr.s6_addr, aMfc.mSrcAddr.GetBytes(), sizeof(sioc_sg_req6.src.sin6_addr.s6_addr));
|
||||
memcpy(sioc_sg_req6.grp.sin6_addr.s6_addr, aMfc.mGroupAddr.GetBytes(), sizeof(sioc_sg_req6.grp.sin6_addr.s6_addr));
|
||||
|
||||
if (ioctl(mMulticastRouterSock, SIOCGETSGCNT_IN6, &sioc_sg_req6) != -1)
|
||||
{
|
||||
unsigned long validPktCnt;
|
||||
|
||||
otLogDebgPlat("MulticastRoutingManager: %s: SIOCGETSGCNT_IN6 %s => %s: bytecnt=%lu, pktcnt=%lu, wrong_if=%lu",
|
||||
__FUNCTION__, aMfc.mSrcAddr.ToString().AsCString(), aMfc.mGroupAddr.ToString().AsCString(),
|
||||
sioc_sg_req6.bytecnt, sioc_sg_req6.pktcnt, sioc_sg_req6.wrong_if);
|
||||
|
||||
validPktCnt = sioc_sg_req6.pktcnt - sioc_sg_req6.wrong_if;
|
||||
if (validPktCnt != aMfc.mValidPktCnt)
|
||||
{
|
||||
aMfc.SetValidPktCnt(validPktCnt);
|
||||
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogWarnPlat("MulticastRoutingManager: %s: SIOCGETSGCNT_IN6 %s => %s failed: %s", __FUNCTION__,
|
||||
aMfc.mSrcAddr.ToString().AsCString(), aMfc.mGroupAddr.ToString().AsCString(), strerror(errno));
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
const char *MulticastRoutingManager::MifIndexToString(MifIndex aMif)
|
||||
{
|
||||
const char *string = "Unknown";
|
||||
|
||||
switch (aMif)
|
||||
{
|
||||
case kMifIndexNone:
|
||||
string = "None";
|
||||
break;
|
||||
case kMifIndexThread:
|
||||
string = "Thread";
|
||||
break;
|
||||
case kMifIndexBackbone:
|
||||
string = "Backbone";
|
||||
break;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::DumpMulticastForwardingCache(void) const
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_DEBG
|
||||
otLogDebgPlat("MulticastRoutingManager: ==================== MFC ENTRIES ====================");
|
||||
|
||||
for (const MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
|
||||
{
|
||||
if (mfc.IsValid())
|
||||
{
|
||||
otLogDebgPlat("MulticastRoutingManager: %s %s => %s %s", MifIndexToString(mfc.mIif),
|
||||
mfc.mSrcAddr.ToString().AsCString(), mfc.mGroupAddr.ToString().AsCString(),
|
||||
MifIndexToString(mfc.mOif));
|
||||
}
|
||||
}
|
||||
|
||||
otLogDebgPlat("MulticastRoutingManager: =====================================================");
|
||||
#endif
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::HandleStateChange(otInstance *aInstance, otChangedFlags aFlags)
|
||||
{
|
||||
if (aFlags & OT_CHANGED_THREAD_BACKBONE_ROUTER_STATE)
|
||||
{
|
||||
otBackboneRouterState state = otBackboneRouterGetState(aInstance);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case OT_BACKBONE_ROUTER_STATE_DISABLED:
|
||||
case OT_BACKBONE_ROUTER_STATE_SECONDARY:
|
||||
Disable();
|
||||
break;
|
||||
case OT_BACKBONE_ROUTER_STATE_PRIMARY:
|
||||
Enable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::MulticastForwardingCache::Set(MulticastRoutingManager::MifIndex aIif,
|
||||
MulticastRoutingManager::MifIndex aOif)
|
||||
{
|
||||
mIif = aIif;
|
||||
mOif = aOif;
|
||||
mValidPktCnt = 0;
|
||||
mLastUseTime = otPlatTimeGet();
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::MulticastForwardingCache::Set(const Ip6::Address &aSrcAddr,
|
||||
const Ip6::Address &aGroupAddr,
|
||||
MifIndex aIif,
|
||||
MifIndex aOif)
|
||||
{
|
||||
mSrcAddr = aSrcAddr;
|
||||
mGroupAddr = aGroupAddr;
|
||||
Set(aIif, aOif);
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::MulticastForwardingCache::SetValidPktCnt(unsigned long aValidPktCnt)
|
||||
{
|
||||
mValidPktCnt = aValidPktCnt;
|
||||
mLastUseTime = otPlatTimeGet();
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::SaveMulticastForwardingCache(const Ip6::Address & aSrcAddr,
|
||||
const Ip6::Address & aGroupAddr,
|
||||
MulticastRoutingManager::MifIndex aIif,
|
||||
MulticastRoutingManager::MifIndex aOif)
|
||||
{
|
||||
MulticastForwardingCache *invalid = nullptr;
|
||||
MulticastForwardingCache *oldest = nullptr;
|
||||
|
||||
for (MulticastForwardingCache &mfc : mMulticastForwardingCacheTable)
|
||||
{
|
||||
if (mfc.IsValid())
|
||||
{
|
||||
if (mfc.mSrcAddr == aSrcAddr && mfc.mGroupAddr == aGroupAddr)
|
||||
{
|
||||
mfc.Set(aIif, aOif);
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
if (oldest == nullptr || mfc.mLastUseTime < oldest->mLastUseTime)
|
||||
{
|
||||
oldest = &mfc;
|
||||
}
|
||||
}
|
||||
else if (invalid == nullptr)
|
||||
{
|
||||
invalid = &mfc;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid != nullptr)
|
||||
{
|
||||
invalid->Set(aSrcAddr, aGroupAddr, aIif, aOif);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveMulticastForwardingCache(*oldest);
|
||||
oldest->Set(aSrcAddr, aGroupAddr, aIif, aOif);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void MulticastRoutingManager::RemoveMulticastForwardingCache(
|
||||
MulticastRoutingManager::MulticastForwardingCache &aMfc) const
|
||||
{
|
||||
otError error;
|
||||
struct mf6cctl mf6cctl;
|
||||
|
||||
memset(&mf6cctl, 0, sizeof(mf6cctl));
|
||||
|
||||
memcpy(mf6cctl.mf6cc_origin.sin6_addr.s6_addr, aMfc.mSrcAddr.GetBytes(),
|
||||
sizeof(mf6cctl.mf6cc_origin.sin6_addr.s6_addr));
|
||||
memcpy(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr, aMfc.mGroupAddr.GetBytes(),
|
||||
sizeof(mf6cctl.mf6cc_mcastgrp.sin6_addr.s6_addr));
|
||||
|
||||
mf6cctl.mf6cc_parent = aMfc.mIif;
|
||||
|
||||
error = (0 == setsockopt(mMulticastRouterSock, IPPROTO_IPV6, MRT6_DEL_MFC, &mf6cctl, sizeof(mf6cctl)))
|
||||
? OT_ERROR_NONE
|
||||
: OT_ERROR_FAILED;
|
||||
|
||||
otLogResultPlat(error, "MulticastRoutingManager: %s: %s %s => %s %s", __FUNCTION__, MifIndexToString(aMfc.mIif),
|
||||
aMfc.mSrcAddr.ToString().AsCString(), aMfc.mGroupAddr.ToString().AsCString(),
|
||||
MifIndexToString(aMfc.mOif));
|
||||
|
||||
aMfc.Erase();
|
||||
}
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
#ifndef OT_POSIX_PLATFORM_MULTICAST_ROUTING_HPP_
|
||||
#define OT_POSIX_PLATFORM_MULTICAST_ROUTING_HPP_
|
||||
|
||||
#include "openthread-posix-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <openthread/backbone_router_ftd.h>
|
||||
#include <openthread/openthread-system.h>
|
||||
|
||||
#include "platform-posix.h"
|
||||
#include "core/common/non_copyable.hpp"
|
||||
#include "core/net/ip6_address.hpp"
|
||||
#include "lib/url/url.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Posix {
|
||||
|
||||
/**
|
||||
* This class implements Multicast Routing management.
|
||||
*
|
||||
*/
|
||||
class MulticastRoutingManager : private NonCopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes a Multicast Routing manager instance.
|
||||
*
|
||||
*/
|
||||
explicit MulticastRoutingManager()
|
||||
: mLastExpireTime(0)
|
||||
, mMulticastRouterSock(-1)
|
||||
, mInstance(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method initializes the Multicast Routing manager.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
*
|
||||
*/
|
||||
void Init(otInstance *aInstance);
|
||||
|
||||
/**
|
||||
* This method updates the fd_set and timeout for mainloop.
|
||||
*
|
||||
* @param[inout] aReadFdSet A reference to fd_set for polling read.
|
||||
* @param[inout] aMaxFd A reference to the current max fd in fd_sets.
|
||||
*
|
||||
*/
|
||||
void UpdateFdSet(fd_set &aReadFdSet, int &aMaxFd) const;
|
||||
|
||||
/**
|
||||
* This method performs Multicast Routing processing.
|
||||
*
|
||||
* @param[in] aReadFdSet A reference to read file descriptors.
|
||||
*
|
||||
*/
|
||||
void Process(const fd_set &aReadFdSet);
|
||||
|
||||
/**
|
||||
* This method handles Thread state changes.
|
||||
*
|
||||
* @param[in] aInstance A pointer to an OpenThread instance.
|
||||
* @param[in] aFlags Flags that denote the state change events.
|
||||
*
|
||||
*/
|
||||
void HandleStateChange(otInstance *aInstance, otChangedFlags aFlags);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
kMulticastForwardingCacheExpireTimeout = 300, //< Expire timeout of Multicast Forwarding Cache (in seconds)
|
||||
kMulticastForwardingCacheExpiringInterval = 60, //< Expire interval of Multicast Forwarding Cache (in seconds)
|
||||
kMulitcastForwardingCacheTableSize =
|
||||
OPENTHREAD_POSIX_CONFIG_MAX_MULTICAST_FORWARDING_CACHE_TABLE, //< The max size of MFC table.
|
||||
};
|
||||
|
||||
enum MifIndex : uint8_t
|
||||
{
|
||||
kMifIndexNone = 0xff,
|
||||
kMifIndexThread = 0,
|
||||
kMifIndexBackbone = 1,
|
||||
};
|
||||
|
||||
class MulticastForwardingCache
|
||||
{
|
||||
friend class MulticastRoutingManager;
|
||||
|
||||
private:
|
||||
MulticastForwardingCache()
|
||||
: mIif(kMifIndexNone)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsValid() const { return mIif != kMifIndexNone; }
|
||||
void Set(MifIndex aIif, MifIndex aOif);
|
||||
void Set(const Ip6::Address &aSrcAddr, const Ip6::Address &aGroupAddr, MifIndex aIif, MifIndex aOif);
|
||||
void Erase(void) { mIif = kMifIndexNone; }
|
||||
void SetValidPktCnt(unsigned long aValidPktCnt);
|
||||
|
||||
Ip6::Address mSrcAddr;
|
||||
Ip6::Address mGroupAddr;
|
||||
uint64_t mLastUseTime;
|
||||
unsigned long mValidPktCnt;
|
||||
MifIndex mIif;
|
||||
MifIndex mOif;
|
||||
};
|
||||
|
||||
void Enable(void);
|
||||
void Disable(void);
|
||||
void Add(const Ip6::Address &aAddress);
|
||||
void Remove(const Ip6::Address &aAddress);
|
||||
bool HasMulticastListener(const Ip6::Address &aAddress) const;
|
||||
bool IsEnabled(void) const { return mMulticastRouterSock >= 0; }
|
||||
void InitMulticastRouterSock(void);
|
||||
void FinalizeMulticastRouterSock(void);
|
||||
void ProcessMulticastRouterMessages(void);
|
||||
otError AddMulticastForwardingCache(const Ip6::Address &aSrcAddr, const Ip6::Address &aGroupAddr, MifIndex aIif);
|
||||
void SaveMulticastForwardingCache(const Ip6::Address &aSrcAddr,
|
||||
const Ip6::Address &aGroupAddr,
|
||||
MifIndex aIif,
|
||||
MifIndex aOif);
|
||||
void UnblockInboundMulticastForwardingCache(const Ip6::Address &aGroupAddr);
|
||||
void RemoveInboundMulticastForwardingCache(const Ip6::Address &aGroupAddr);
|
||||
void ExpireMulticastForwardingCache(void);
|
||||
bool UpdateMulticastRouteInfo(MulticastForwardingCache &aMfc) const;
|
||||
void RemoveMulticastForwardingCache(MulticastForwardingCache &aMfc) const;
|
||||
static const char *MifIndexToString(MifIndex aMif);
|
||||
void DumpMulticastForwardingCache(void) const;
|
||||
static void HandleBackboneMulticastListenerEvent(void * aContext,
|
||||
otBackboneRouterMulticastListenerEvent aEvent,
|
||||
const otIp6Address * aAddress);
|
||||
void HandleBackboneMulticastListenerEvent(otBackboneRouterMulticastListenerEvent aEvent,
|
||||
const Ip6::Address & aAddress);
|
||||
|
||||
MulticastForwardingCache mMulticastForwardingCacheTable[kMulitcastForwardingCacheTableSize];
|
||||
uint64_t mLastExpireTime;
|
||||
int mMulticastRouterSock;
|
||||
otInstance * mInstance;
|
||||
};
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
|
||||
#endif // OT_POSIX_PLATFORM_MULTICAST_ROUTING_HPP_
|
||||
@@ -537,11 +537,11 @@ static void processAddressChange(const otIp6AddressInfo *aAddressInfo, bool aIsA
|
||||
}
|
||||
}
|
||||
|
||||
static void processStateChange(otChangedFlags aFlags, void *aContext)
|
||||
void platformNetifStateChange(otInstance *aInstance, otChangedFlags aFlags)
|
||||
{
|
||||
if (OT_CHANGED_THREAD_NETIF_STATE & aFlags)
|
||||
{
|
||||
UpdateLink(static_cast<otInstance *>(aContext));
|
||||
UpdateLink(aInstance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1500,7 +1500,6 @@ void platformNetifInit(otInstance *aInstance, const char *aInterfaceName)
|
||||
otIcmp6SetEchoMode(aInstance, OT_ICMP6_ECHO_HANDLER_DISABLED);
|
||||
otIp6SetReceiveCallback(aInstance, processReceive, aInstance);
|
||||
otIp6SetAddressCallback(aInstance, processAddressChange, aInstance);
|
||||
SuccessOrDie(otSetStateChangedCallback(aInstance, processStateChange, aInstance));
|
||||
#if OPENTHREAD_POSIX_MULTICAST_PROMISCUOUS_REQUIRED
|
||||
otIp6SetMulticastPromiscuousEnabled(aInstance, true);
|
||||
#endif
|
||||
|
||||
@@ -101,6 +101,16 @@
|
||||
#define OPENTHREAD_POSIX_CONFIG_MAX_POWER_TABLE_ENABLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_POSIX_CONFIG_MAX_MULTICAST_FORWARDING_CACHE_TABLE
|
||||
*
|
||||
* This setting configures the maximum number of Multicast Forwarding Cache table for POSIX native multicast routing.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_POSIX_CONFIG_MAX_MULTICAST_FORWARDING_CACHE_TABLE
|
||||
#define OPENTHREAD_POSIX_CONFIG_MAX_MULTICAST_FORWARDING_CACHE_TABLE (OPENTHREAD_CONFIG_MAX_MULTICAST_LISTENERS * 10)
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
/**
|
||||
|
||||
@@ -270,6 +270,15 @@ void platformNetifUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *a
|
||||
*/
|
||||
void platformNetifProcess(const fd_set *aReadFdSet, const fd_set *aWriteFdSet, const fd_set *aErrorFdSet);
|
||||
|
||||
/**
|
||||
* This function performs notifies state changes to platform netif.
|
||||
*
|
||||
* @param[in] aInstance A pointer to the OpenThread instance.
|
||||
* @param[in] aFlags Flags that denote the state change events.
|
||||
*
|
||||
*/
|
||||
void platformNetifStateChange(otInstance *aInstance, otChangedFlags aFlags);
|
||||
|
||||
/**
|
||||
* This function initialize virtual time simulation.
|
||||
*
|
||||
@@ -407,7 +416,6 @@ extern char gNetifName[IFNAMSIZ];
|
||||
*/
|
||||
extern unsigned int gNetifIndex;
|
||||
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
/**
|
||||
* This function initializes platform Backbone network.
|
||||
*
|
||||
@@ -417,6 +425,32 @@ extern unsigned int gNetifIndex;
|
||||
*/
|
||||
void platformBackboneInit(otInstance *aInstance, const char *aInterfaceName);
|
||||
|
||||
/**
|
||||
* This function updates the file descriptor sets with file descriptors used by the platform Backbone network.
|
||||
*
|
||||
* @param[inout] aReadFdSet A reference to the read file descriptors.
|
||||
* @param[inout] aMaxFd A reference to the max file descriptor.
|
||||
*
|
||||
*/
|
||||
void platformBackboneUpdateFdSet(fd_set &aReadFdSet, int &aMaxFd);
|
||||
|
||||
/**
|
||||
* This function performs platform Backbone network processing.
|
||||
*
|
||||
* @param[in] aReadFdSet A reference to the read file descriptors.
|
||||
*
|
||||
*/
|
||||
void platformBackboneProcess(const fd_set &aReadSet);
|
||||
|
||||
/**
|
||||
* This function performs notifies state changes to platform Backbone network.
|
||||
*
|
||||
* @param[in] aInstance A pointer to the OpenThread instance.
|
||||
* @param[in] aFlags Flags that denote the state change events.
|
||||
*
|
||||
*/
|
||||
void platformBackboneStateChange(otInstance *aInstance, otChangedFlags aFlags);
|
||||
|
||||
/**
|
||||
* The name of Backbone network interface.
|
||||
*
|
||||
@@ -428,7 +462,6 @@ extern char gBackboneNetifName[IFNAMSIZ];
|
||||
*
|
||||
*/
|
||||
extern unsigned int gBackboneNetifIndex;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -46,6 +46,24 @@
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE || OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
|
||||
static void processStateChange(otChangedFlags aFlags, void *aContext)
|
||||
{
|
||||
otInstance *instance = static_cast<otInstance *>(aContext);
|
||||
|
||||
OT_UNUSED_VARIABLE(instance);
|
||||
OT_UNUSED_VARIABLE(aFlags);
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
|
||||
platformNetifStateChange(instance, aFlags);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
platformBackboneStateChange(instance, aFlags);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
otInstance *otSysInit(otPlatformConfig *aPlatformConfig)
|
||||
{
|
||||
otInstance * instance = nullptr;
|
||||
@@ -82,6 +100,10 @@ otInstance *otSysInit(otPlatformConfig *aPlatformConfig)
|
||||
platformUdpInit(aPlatformConfig->mInterfaceName);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE || OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
|
||||
SuccessOrDie(otSetStateChangedCallback(instance, processStateChange, instance));
|
||||
#endif
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -142,6 +164,9 @@ void otSysMainloopUpdate(otInstance *aInstance, otSysMainloopContext *aMainloop)
|
||||
platformNetifUpdateFdSet(&aMainloop->mReadFdSet, &aMainloop->mWriteFdSet, &aMainloop->mErrorFdSet,
|
||||
&aMainloop->mMaxFd);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
platformBackboneUpdateFdSet(aMainloop->mReadFdSet, aMainloop->mMaxFd);
|
||||
#endif
|
||||
#if OPENTHREAD_POSIX_VIRTUAL_TIME
|
||||
virtualTimeUpdateFdSet(&aMainloop->mReadFdSet, &aMainloop->mWriteFdSet, &aMainloop->mErrorFdSet, &aMainloop->mMaxFd,
|
||||
&aMainloop->mTimeout);
|
||||
@@ -214,6 +239,9 @@ void otSysMainloopProcess(otInstance *aInstance, const otSysMainloopContext *aMa
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE
|
||||
platformUdpProcess(aInstance, &aMainloop->mReadFdSet);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
|
||||
platformBackboneProcess(aMainloop->mReadFdSet);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_OTNS_ENABLE
|
||||
|
||||
Reference in New Issue
Block a user