mirror of
https://github.com/espressif/openthread.git
synced 2026-08-05 02:17:47 +00:00
[posix] add unified platform API for setting NAT64 CIDR during runtime (#8947)
We should notice that the default CIDR (`192.168.255.0/24`) is not safe to use, however, in most cases, the CIDR used can only be determined during runtime since the single binary might be distributed to BRs in different network conditions. And we cannot conclude an always safe CIDR in all conditions. This commit will emit an event when NAT64 CIDR is changed. So the platform driver can update the route for NAT64.
This commit is contained in:
+34
-15
@@ -681,25 +681,44 @@ template <> otError Interpreter::Process<Cmd("nat64")>(Arg aArgs[])
|
||||
#endif
|
||||
}
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
/**
|
||||
* @cli nat64 cidr
|
||||
* @code
|
||||
* nat64 cidr
|
||||
* 192.168.255.0/24
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otNat64GetCidr
|
||||
*
|
||||
*/
|
||||
else if (aArgs[0] == "cidr")
|
||||
{
|
||||
otIp4Cidr cidr;
|
||||
char cidrString[OT_IP4_CIDR_STRING_SIZE];
|
||||
|
||||
SuccessOrExit(error = otNat64GetCidr(GetInstancePtr(), &cidr));
|
||||
otIp4CidrToString(&cidr, cidrString, sizeof(cidrString));
|
||||
OutputLine("%s", cidrString);
|
||||
/**
|
||||
* @cli nat64 cidr
|
||||
* @code
|
||||
* nat64 cidr
|
||||
* 192.168.255.0/24
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otNat64GetCidr
|
||||
*
|
||||
*/
|
||||
if (aArgs[1].IsEmpty())
|
||||
{
|
||||
char cidrString[OT_IP4_CIDR_STRING_SIZE];
|
||||
|
||||
SuccessOrExit(error = otNat64GetCidr(GetInstancePtr(), &cidr));
|
||||
otIp4CidrToString(&cidr, cidrString, sizeof(cidrString));
|
||||
OutputLine("%s", cidrString);
|
||||
}
|
||||
/**
|
||||
* @cli nat64 cidr <cidr>
|
||||
* @code
|
||||
* nat64 cidr 192.168.255.0/24
|
||||
* Done
|
||||
* @endcode
|
||||
* @par api_copy
|
||||
* #otPlatNat64SetIp4Cidr
|
||||
*
|
||||
*/
|
||||
else
|
||||
{
|
||||
SuccessOrExit(error = otIp4CidrFromString(aArgs[1].GetCString(), &cidr));
|
||||
error = otNat64SetIp4Cidr(GetInstancePtr(), &cidr);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @cli nat64 mappings
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
|
||||
#include <openthread/platform/toolchain.h>
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/locator_getters.hpp"
|
||||
#include "common/log.hpp"
|
||||
@@ -507,7 +509,8 @@ Error Translator::SetIp4Cidr(const Ip4::Cidr &aCidr)
|
||||
numberOfHosts);
|
||||
mIp4Cidr = aCidr;
|
||||
|
||||
UpdateState();
|
||||
// Always notify the platform when the CIDR is changed.
|
||||
UpdateState(true /* aAlwaysNotify */);
|
||||
|
||||
exit:
|
||||
return err;
|
||||
@@ -631,7 +634,7 @@ void Translator::ProtocolCounters::Count4To6Packet(uint8_t aProtocol, uint64_t a
|
||||
mTotal.m4To6Bytes += aPacketSize;
|
||||
}
|
||||
|
||||
void Translator::UpdateState(void)
|
||||
void Translator::UpdateState(bool aAlwaysNotify)
|
||||
{
|
||||
State newState;
|
||||
|
||||
@@ -651,7 +654,14 @@ void Translator::UpdateState(void)
|
||||
newState = kStateDisabled;
|
||||
}
|
||||
|
||||
SuccessOrExit(Get<Notifier>().Update(mState, newState, kEventNat64TranslatorStateChanged));
|
||||
if (aAlwaysNotify)
|
||||
{
|
||||
Get<Notifier>().Signal(kEventNat64TranslatorStateChanged);
|
||||
}
|
||||
else
|
||||
{
|
||||
SuccessOrExit(Get<Notifier>().Update(mState, newState, kEventNat64TranslatorStateChanged));
|
||||
}
|
||||
LogInfo("NAT64 translator is now %s", StateToString(mState));
|
||||
|
||||
exit:
|
||||
|
||||
@@ -380,7 +380,7 @@ private:
|
||||
|
||||
using MappingTimer = TimerMilliIn<Translator, &Translator::HandleMappingExpirerTimer>;
|
||||
|
||||
void UpdateState(void);
|
||||
void UpdateState(bool aAlwaysNotify = false);
|
||||
|
||||
bool mEnabled;
|
||||
State mState;
|
||||
|
||||
@@ -156,7 +156,9 @@ extern int
|
||||
|
||||
unsigned int gNetifIndex = 0;
|
||||
char gNetifName[IFNAMSIZ];
|
||||
otIp4Cidr gNat64Cidr;
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
static otIp4Cidr sActiveNat64Cidr;
|
||||
#endif
|
||||
|
||||
const char *otSysGetThreadNetifName(void) { return gNetifName; }
|
||||
|
||||
@@ -896,24 +898,55 @@ static void processAddressChange(const otIp6AddressInfo *aAddressInfo, bool aIsA
|
||||
}
|
||||
|
||||
#if defined(__linux__) && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
void processNat64StateChange(otNat64State aNewState)
|
||||
static bool isSameIp4Cidr(const otIp4Cidr &aCidr1, const otIp4Cidr &aCidr2)
|
||||
{
|
||||
// If the interface is not up and we are enabling NAT64, the route will be added when we bring up the route.
|
||||
// Also, the route will be deleted by the kernel when we shutting down the interface.
|
||||
// We should try to add route first, since otNat64SetEnabled never fails.
|
||||
if (otIp6IsEnabled(gInstance))
|
||||
bool res = true;
|
||||
|
||||
VerifyOrExit(aCidr1.mLength == aCidr2.mLength, res = false);
|
||||
|
||||
// The higher (32 - length) bits must be the same, host bits are ignored.
|
||||
VerifyOrExit(((ntohl(aCidr1.mAddress.mFields.m32) ^ ntohl(aCidr2.mAddress.mFields.m32)) >> (32 - aCidr1.mLength)) ==
|
||||
0,
|
||||
res = false);
|
||||
|
||||
exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void processNat64StateChange(void)
|
||||
{
|
||||
otIp4Cidr translatorCidr;
|
||||
|
||||
// Skip if NAT64 translator has not been configured with a CIDR.
|
||||
SuccessOrExit(otNat64GetCidr(gInstance, &translatorCidr));
|
||||
|
||||
if (!isSameIp4Cidr(translatorCidr, sActiveNat64Cidr)) // Someone sets a new CIDR for NAT64.
|
||||
{
|
||||
if (aNewState == OT_NAT64_STATE_ACTIVE)
|
||||
char cidrString[OT_IP4_CIDR_STRING_SIZE];
|
||||
|
||||
if (sActiveNat64Cidr.mLength != 0)
|
||||
{
|
||||
AddIp4Route(gNat64Cidr, kNat64RoutePriority);
|
||||
otLogInfoPlat("[netif] Adding route for NAT64");
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteIp4Route(gNat64Cidr);
|
||||
otLogInfoPlat("[netif] Deleting route for NAT64");
|
||||
DeleteIp4Route(sActiveNat64Cidr);
|
||||
}
|
||||
sActiveNat64Cidr = translatorCidr;
|
||||
|
||||
otIp4CidrToString(&translatorCidr, cidrString, sizeof(cidrString));
|
||||
otLogInfoPlat("[netif] NAT64 CIDR updated to %s.", cidrString);
|
||||
}
|
||||
|
||||
if (otNat64GetTranslatorState(gInstance) == OT_NAT64_STATE_ACTIVE)
|
||||
{
|
||||
AddIp4Route(sActiveNat64Cidr, kNat64RoutePriority);
|
||||
otLogInfoPlat("[netif] Adding route for NAT64");
|
||||
}
|
||||
else if (sActiveNat64Cidr.mLength > 0) // Translator is not active.
|
||||
{
|
||||
DeleteIp4Route(sActiveNat64Cidr);
|
||||
otLogInfoPlat("[netif] Deleting route for NAT64");
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
#endif // defined(__linux__) && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
|
||||
@@ -936,9 +969,9 @@ void platformNetifStateChange(otInstance *aInstance, otChangedFlags aFlags)
|
||||
#endif
|
||||
}
|
||||
#if defined(__linux__) && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
if (OT_CHANGED_NAT64_TRANSLATOR_STATE & aFlags)
|
||||
if ((OT_CHANGED_NAT64_TRANSLATOR_STATE | OT_CHANGED_THREAD_NETIF_STATE) & aFlags)
|
||||
{
|
||||
processNat64StateChange(otNat64GetTranslatorState(aInstance));
|
||||
processNat64StateChange();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1207,10 +1240,10 @@ static void processNetifLinkEvent(otInstance *aInstance, struct nlmsghdr *aNetli
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
if (isUp && gNat64Cidr.mLength > 0)
|
||||
if (isUp && sActiveNat64Cidr.mLength > 0)
|
||||
{
|
||||
SuccessOrExit(error = otNat64SetIp4Cidr(gInstance, &gNat64Cidr));
|
||||
otLogInfoPlat("[netif] Succeeded to enable NAT64");
|
||||
// Recover NAT64 route.
|
||||
AddIp4Route(sActiveNat64Cidr, kNat64RoutePriority);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1886,6 +1919,22 @@ void platformNetifInit(otPlatformConfig *aPlatformConfig)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
void nat64Init(void)
|
||||
{
|
||||
otIp4Cidr cidr;
|
||||
|
||||
if (otIp4CidrFromString(OPENTHREAD_POSIX_CONFIG_NAT64_CIDR, &cidr) == OT_ERROR_NONE && cidr.mLength != 0)
|
||||
{
|
||||
otNat64SetIp4Cidr(gInstance, &cidr);
|
||||
}
|
||||
else
|
||||
{
|
||||
otLogInfoPlat("[netif] No default NAT64 CIDR provided.");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void platformNetifSetUp(void)
|
||||
{
|
||||
OT_ASSERT(gInstance != nullptr);
|
||||
@@ -1905,6 +1954,9 @@ void platformNetifSetUp(void)
|
||||
#if OPENTHREAD_POSIX_MULTICAST_PROMISCUOUS_REQUIRED
|
||||
otIp6SetMulticastPromiscuousEnabled(aInstance, true);
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
nat64Init();
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_DNS_UPSTREAM_QUERY_ENABLE
|
||||
gResolver.Init();
|
||||
#endif
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/logging.h>
|
||||
#include <openthread/nat64.h>
|
||||
#include <openthread/openthread-system.h>
|
||||
#include <openthread/platform/time.h>
|
||||
|
||||
@@ -448,11 +447,6 @@ extern char gNetifName[IFNAMSIZ];
|
||||
*/
|
||||
extern unsigned int gNetifIndex;
|
||||
|
||||
/**
|
||||
* The CIDR for NAT64
|
||||
*/
|
||||
extern otIp4Cidr gNat64Cidr;
|
||||
|
||||
/**
|
||||
* Initializes platform Backbone network.
|
||||
*
|
||||
|
||||
@@ -148,13 +148,6 @@ void platformInit(otPlatformConfig *aPlatformConfig)
|
||||
|
||||
gNetifName[0] = '\0';
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
if (otIp4CidrFromString(OPENTHREAD_POSIX_CONFIG_NAT64_CIDR, &gNat64Cidr) != OT_ERROR_NONE)
|
||||
{
|
||||
gNat64Cidr.mLength = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE
|
||||
platformNetifInit(aPlatformConfig);
|
||||
#endif
|
||||
|
||||
@@ -63,6 +63,9 @@ SMALL_NAT64_PREFIX = "fd00:00:00:01:00:00::/96"
|
||||
# So the BR will remove the random-generated one.
|
||||
LARGE_NAT64_PREFIX = "ff00:00:00:01:00:00::/96"
|
||||
|
||||
DEFAULT_NAT64_CIDR = ipaddress.IPv4Network("192.168.255.0/24")
|
||||
UPDATED_NAT64_CIDR = ipaddress.IPv4Network("100.64.64.0/24")
|
||||
|
||||
|
||||
class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
@@ -235,7 +238,16 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
self.assertEqual(counters['protocol']['ICMP']['6to4']['packets'], 2)
|
||||
|
||||
#
|
||||
# Case 6. Disable and re-enable ethernet on the border router.
|
||||
# Case 6. Change the CIDR used by NAT64 during runtime
|
||||
#
|
||||
self.assertEqual(br.nat64_cidr, DEFAULT_NAT64_CIDR)
|
||||
|
||||
br.nat64_cidr = UPDATED_NAT64_CIDR
|
||||
self.assertEqual(br.nat64_cidr, UPDATED_NAT64_CIDR)
|
||||
self.assertTrue(router.ping(ipaddr=host_ip))
|
||||
|
||||
#
|
||||
# Case 7. Disable and re-enable ethernet on the border router.
|
||||
# Note: disable_ether will remove default route but enable_ether won't add it back,
|
||||
# NAT64 connectivity tests will fail after this.
|
||||
# TODO: Add a default IPv4 route after enable_ether.
|
||||
|
||||
@@ -413,6 +413,19 @@ class OtbrDocker:
|
||||
def nat64_set_enabled(self, enable):
|
||||
return self.call_dbus_method('io.openthread.BorderRouter', 'SetNat64Enabled', enable)
|
||||
|
||||
@property
|
||||
def nat64_cidr(self):
|
||||
self.send_command('nat64 cidr')
|
||||
cidr = self._expect_command_output()[0].strip()
|
||||
return ipaddress.IPv4Network(cidr, strict=False)
|
||||
|
||||
@nat64_cidr.setter
|
||||
def nat64_cidr(self, cidr: ipaddress.IPv4Network):
|
||||
if not isinstance(cidr, ipaddress.IPv4Network):
|
||||
raise ValueError("cidr is expected to be an instance of ipaddress.IPv4Network")
|
||||
self.send_command(f'nat64 cidr {cidr}')
|
||||
self._expect_done()
|
||||
|
||||
@property
|
||||
def nat64_state(self):
|
||||
state = self.get_dbus_property('Nat64State')
|
||||
|
||||
Reference in New Issue
Block a user