mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 07:37:46 +00:00
[nat64] NAT64 translator should be active only when local prefix is published (#8558)
If an infrastructure-provided NAT64 prefix is present, we should bypass the NAT64 translator to let the border router forward the packet to the infra NAT64 service.
This commit is contained in:
@@ -2702,7 +2702,7 @@ void RoutingManager::Nat64PrefixManager::Stop(void)
|
||||
mTimer.Stop();
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
Get<Nat64::Translator>().SetNat64Prefix(mPublishedPrefix);
|
||||
Get<Nat64::Translator>().ClearNat64Prefix();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2784,7 +2784,16 @@ void RoutingManager::Nat64PrefixManager::Evaluate(void)
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
Get<Nat64::Translator>().SetNat64Prefix(mPublishedPrefix);
|
||||
// When there is an prefix other than mLocalPrefix, means there is an external translator available. So we bypass
|
||||
// the NAT64 translator by clearing the NAT64 prefix in the translator.
|
||||
if (mPublishedPrefix == mLocalPrefix)
|
||||
{
|
||||
Get<Nat64::Translator>().SetNat64Prefix(mLocalPrefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
Get<Nat64::Translator>().ClearNat64Prefix();
|
||||
}
|
||||
#endif
|
||||
|
||||
exit:
|
||||
|
||||
@@ -515,13 +515,27 @@ exit:
|
||||
|
||||
void Translator::SetNat64Prefix(const Ip6::Prefix &aNat64Prefix)
|
||||
{
|
||||
if (mNat64Prefix != aNat64Prefix)
|
||||
if (aNat64Prefix.GetLength() == 0)
|
||||
{
|
||||
ClearNat64Prefix();
|
||||
}
|
||||
else if (mNat64Prefix != aNat64Prefix)
|
||||
{
|
||||
LogInfo("IPv6 Prefix for NAT64 updated to %s", aNat64Prefix.ToString().AsCString());
|
||||
mNat64Prefix = aNat64Prefix;
|
||||
UpdateState();
|
||||
}
|
||||
}
|
||||
|
||||
void Translator::ClearNat64Prefix(void)
|
||||
{
|
||||
VerifyOrExit(mNat64Prefix.GetLength() != 0);
|
||||
mNat64Prefix.Clear();
|
||||
LogInfo("IPv6 Prefix for NAT64 cleared");
|
||||
UpdateState();
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void Translator::HandleMappingExpirerTimer(void)
|
||||
|
||||
@@ -253,14 +253,20 @@ public:
|
||||
|
||||
/**
|
||||
* Sets the prefix of NAT64-mapped addresses in the thread network. The address mapping table will not be cleared.
|
||||
* If an empty NAT64 prefix is set, the translator will return kNotTranslated for all IPv6 datagrams and kDrop for
|
||||
* all IPv4 datagrams.
|
||||
* This function equals to `ClearNat64Prefix` when an empty prefix is provided.
|
||||
*
|
||||
* @param[in] aNat64Prefix The prefix of the NAT64-mapped addresses.
|
||||
*
|
||||
*/
|
||||
void SetNat64Prefix(const Ip6::Prefix &aNat64Prefix);
|
||||
|
||||
/**
|
||||
* Clear the prefix of NAT64-mapped addresses in the thread network. The address mapping table will not be cleared.
|
||||
* The translator will return kNotTranslated for all IPv6 datagrams and kDrop for all IPv4 datagrams.
|
||||
*
|
||||
*/
|
||||
void ClearNat64Prefix(void);
|
||||
|
||||
/**
|
||||
* Initializes an `otNat64AddressMappingIterator`.
|
||||
*
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
from typing import Mapping
|
||||
import unittest
|
||||
|
||||
import config
|
||||
@@ -85,19 +84,6 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
|
||||
},
|
||||
}
|
||||
|
||||
def assertDictIncludes(self, actual: Mapping[str, str], expected: Mapping[str, str]):
|
||||
""" Asserts the `actual` dict includes the `expected` dict.
|
||||
|
||||
Args:
|
||||
actual: A dict for checking.
|
||||
expected: The expected items that the actual dict should contains.
|
||||
"""
|
||||
for k, v in expected.items():
|
||||
if k not in actual:
|
||||
raise AssertionError(f"key {k} is not found in first dict")
|
||||
if v != actual[k]:
|
||||
raise AssertionError(f"{repr(actual[k])} != {repr(v)} for key {k}")
|
||||
|
||||
def test(self):
|
||||
br1 = self.nodes[BR1]
|
||||
router = self.nodes[ROUTER]
|
||||
@@ -123,6 +109,7 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
|
||||
#
|
||||
# Case 1. BR2 with an infrastructure prefix joins the network later and
|
||||
# it will add the infrastructure nat64 prefix to Network Data.
|
||||
# Note: NAT64 translator will be bypassed.
|
||||
#
|
||||
br2.start()
|
||||
# When feature flag is enabled, NAT64 might be disabled by default. So
|
||||
@@ -146,7 +133,7 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
|
||||
})
|
||||
self.assertDictIncludes(br2.nat64_state, {
|
||||
'PrefixManager': NAT64_STATE_ACTIVE,
|
||||
'Translator': NAT64_STATE_ACTIVE
|
||||
'Translator': NAT64_STATE_NOT_RUNNING
|
||||
})
|
||||
|
||||
#
|
||||
|
||||
@@ -52,6 +52,11 @@ SMALL_NAT64_PREFIX = "2000:0:0:1:0:0::/96"
|
||||
|
||||
NAT64_PREFIX_REFRESH_DELAY = 305
|
||||
|
||||
NAT64_STATE_DISABLED = 'disabled'
|
||||
NAT64_STATE_NOT_RUNNING = 'not_running'
|
||||
NAT64_STATE_IDLE = 'idle'
|
||||
NAT64_STATE_ACTIVE = 'active'
|
||||
|
||||
|
||||
class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
@@ -91,6 +96,10 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
self.assertEqual(len(br.get_netdata_nat64_prefix()), 1)
|
||||
nat64_prefix = br.get_netdata_nat64_prefix()[0]
|
||||
self.assertEqual(nat64_prefix, infra_nat64_prefix)
|
||||
self.assertDictIncludes(br.nat64_state, {
|
||||
'PrefixManager': NAT64_STATE_ACTIVE,
|
||||
'Translator': NAT64_STATE_NOT_RUNNING
|
||||
})
|
||||
|
||||
# Case 2 Withdraw infrastructure prefix when a smaller prefix in medium
|
||||
# preference is present
|
||||
@@ -100,6 +109,10 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
|
||||
self.assertEqual(len(br.get_netdata_nat64_prefix()), 1)
|
||||
self.assertNotEqual(infra_nat64_prefix, br.get_netdata_nat64_prefix()[0])
|
||||
self.assertDictIncludes(br.nat64_state, {
|
||||
'PrefixManager': NAT64_STATE_IDLE,
|
||||
'Translator': NAT64_STATE_NOT_RUNNING
|
||||
})
|
||||
|
||||
br.remove_route(SMALL_NAT64_PREFIX)
|
||||
br.register_netdata()
|
||||
@@ -115,6 +128,10 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
|
||||
self.assertEqual(len(br.get_netdata_nat64_prefix()), 2)
|
||||
self.assertEqual(br.get_netdata_nat64_prefix(), [infra_nat64_prefix, SMALL_NAT64_PREFIX])
|
||||
self.assertDictIncludes(br.nat64_state, {
|
||||
'PrefixManager': NAT64_STATE_ACTIVE,
|
||||
'Translator': NAT64_STATE_NOT_RUNNING
|
||||
})
|
||||
|
||||
br.remove_route(SMALL_NAT64_PREFIX)
|
||||
br.register_netdata()
|
||||
@@ -128,6 +145,10 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
self.assertNotEqual(local_nat64_prefix, infra_nat64_prefix)
|
||||
self.assertEqual(len(br.get_netdata_nat64_prefix()), 1)
|
||||
self.assertEqual(br.get_netdata_nat64_prefix()[0], local_nat64_prefix)
|
||||
self.assertDictIncludes(br.nat64_state, {
|
||||
'PrefixManager': NAT64_STATE_ACTIVE,
|
||||
'Translator': NAT64_STATE_ACTIVE
|
||||
})
|
||||
|
||||
# Case 5 Infrastructure nat64 prefix is recovered
|
||||
br.bash("service bind9 start")
|
||||
@@ -136,6 +157,10 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
self.assertEqual(br.get_br_favored_nat64_prefix(), infra_nat64_prefix)
|
||||
self.assertEqual(len(br.get_netdata_nat64_prefix()), 1)
|
||||
self.assertEqual(br.get_netdata_nat64_prefix()[0], infra_nat64_prefix)
|
||||
self.assertDictIncludes(br.nat64_state, {
|
||||
'PrefixManager': NAT64_STATE_ACTIVE,
|
||||
'Translator': NAT64_STATE_NOT_RUNNING
|
||||
})
|
||||
|
||||
# Case 6 Change infrastructure nat64 prefix
|
||||
br.bash("sed -i 's/dns64 /\/\/dns64 /' /etc/bind/named.conf.options")
|
||||
@@ -146,6 +171,10 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
self.assertEqual(br.get_br_favored_nat64_prefix(), SMALL_NAT64_PREFIX)
|
||||
self.assertEqual(len(br.get_netdata_nat64_prefix()), 1)
|
||||
self.assertEqual(br.get_netdata_nat64_prefix()[0], SMALL_NAT64_PREFIX)
|
||||
self.assertDictIncludes(br.nat64_state, {
|
||||
'PrefixManager': NAT64_STATE_ACTIVE,
|
||||
'Translator': NAT64_STATE_NOT_RUNNING
|
||||
})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -38,7 +38,7 @@ import sys
|
||||
import time
|
||||
import traceback
|
||||
import unittest
|
||||
from typing import Optional, Callable, Union, Any
|
||||
from typing import Optional, Callable, Union, Mapping, Any
|
||||
|
||||
import config
|
||||
import debug
|
||||
@@ -592,3 +592,16 @@ class TestCase(NcpSupportMixin, unittest.TestCase):
|
||||
|
||||
else:
|
||||
raise Exception("Route between node %d and %d is not established" % (node1, node2))
|
||||
|
||||
def assertDictIncludes(self, actual: Mapping[str, str], expected: Mapping[str, str]):
|
||||
""" Asserts the `actual` dict includes the `expected` dict.
|
||||
|
||||
Args:
|
||||
actual: A dict for checking.
|
||||
expected: The expected items that the actual dict should contains.
|
||||
"""
|
||||
for k, v in expected.items():
|
||||
if k not in actual:
|
||||
raise AssertionError(f"key {k} is not found in first dict")
|
||||
if v != actual[k]:
|
||||
raise AssertionError(f"{repr(actual[k])} != {repr(v)} for key {k}")
|
||||
|
||||
Reference in New Issue
Block a user