[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:
Song GUO
2022-12-21 17:52:00 -08:00
committed by GitHub
parent 438fb78720
commit 4c70cbb162
6 changed files with 79 additions and 21 deletions
+11 -2
View File
@@ -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:
+15 -1
View File
@@ -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)
+8 -2
View File
@@ -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__':
+14 -1
View File
@@ -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}")