From 8bb5b30b2bd7c3e17101cfe9837d4ddf486502c3 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 6 Jul 2026 15:16:17 -0700 Subject: [PATCH] [tests] remove border router MATN tests (#13306) Remove MATN border router certification tests as they have been replaced by equivalent tests in the ot-br-posix repository under: https://github.com/openthread/ot-br-posix/tree/main/tests/scripts/expect The new tests run using the docker-in-docker framework. Deleted tests: - MATN_02_MLRFirstUse.py - MATN_03_InvalidCommissionerDeregistration.py - MATN_04_MulticastListenerTimeout.py - MATN_05_ReregistrationToSameMulticastGroup.py - MATN_09_DefaultBRMulticastForwarding.py - MATN_12_HopLimitProcessing.py - MATN_15_ChangeOfPrimaryBBRTriggersRegistration.py - MATN_16_LargeNumberOfMulticastGroupSubscriptionsToBBR.py --- .github/workflows/otbr.yml | 6 - .../border_router/MATN/MATN_02_MLRFirstUse.py | 290 ------------------ ...TN_03_InvalidCommissionerDeregistration.py | 184 ----------- .../MATN/MATN_04_MulticastListenerTimeout.py | 219 ------------- ...N_05_ReregistrationToSameMulticastGroup.py | 242 --------------- .../MATN_09_DefaultBRMulticastForwarding.py | 191 ------------ .../MATN/MATN_12_HopLimitProcessing.py | 276 ----------------- ..._ChangeOfPrimaryBBRTriggersRegistration.py | 199 ------------ ...umberOfMulticastGroupSubscriptionsToBBR.py | 229 -------------- 9 files changed, 1836 deletions(-) delete mode 100755 tests/scripts/thread-cert/border_router/MATN/MATN_02_MLRFirstUse.py delete mode 100755 tests/scripts/thread-cert/border_router/MATN/MATN_03_InvalidCommissionerDeregistration.py delete mode 100755 tests/scripts/thread-cert/border_router/MATN/MATN_04_MulticastListenerTimeout.py delete mode 100755 tests/scripts/thread-cert/border_router/MATN/MATN_05_ReregistrationToSameMulticastGroup.py delete mode 100755 tests/scripts/thread-cert/border_router/MATN/MATN_09_DefaultBRMulticastForwarding.py delete mode 100755 tests/scripts/thread-cert/border_router/MATN/MATN_12_HopLimitProcessing.py delete mode 100755 tests/scripts/thread-cert/border_router/MATN/MATN_15_ChangeOfPrimaryBBRTriggersRegistration.py delete mode 100755 tests/scripts/thread-cert/border_router/MATN/MATN_16_LargeNumberOfMulticastGroupSubscriptionsToBBR.py diff --git a/.github/workflows/otbr.yml b/.github/workflows/otbr.yml index ec736b390..f22895b5c 100644 --- a/.github/workflows/otbr.yml +++ b/.github/workflows/otbr.yml @@ -63,12 +63,6 @@ jobs: packet_verification: 2 nat64: 0 description: "" - - otbr_mdns: "mDNSResponder" - otbr_trel: 0 - cert_scripts: ./tests/scripts/thread-cert/border_router/MATN/*.py - packet_verification: 1 - nat64: 0 - description: "MATN" - otbr_mdns: "mDNSResponder" otbr_trel: 0 cert_scripts: ./tests/scripts/thread-cert/border_router/internet/*.py diff --git a/tests/scripts/thread-cert/border_router/MATN/MATN_02_MLRFirstUse.py b/tests/scripts/thread-cert/border_router/MATN/MATN_02_MLRFirstUse.py deleted file mode 100755 index db215e6c8..000000000 --- a/tests/scripts/thread-cert/border_router/MATN/MATN_02_MLRFirstUse.py +++ /dev/null @@ -1,290 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2021, 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. -# - -import logging -import unittest - -import pktverify -from pktverify import packet_verifier, packet_filter -from pktverify.consts import MA1, MA1g, MA2, PBBR_ALOC -import config -import thread_cert - -# Test description: -# The purpose of this test case is to verify that a Thread device is able to -# register a multicast address with a Primary BBR and that the Primary BBR can -# notify devices on the backbone link of the multicast address. The test also -# verifies that an IPv6 multicast packet originating from the backbone is -# correctly forwarded (in the Thread Network) to the device that registered the -# multicast address. -# -# Topology: -# ----------------(eth)------------------ -# | | | -# BR1 (Leader) ----- BR2 HOST -# | | -# | | -# TD --------(when TD is router) -# - -BR_1 = 1 -BR_2 = 2 -TD = 3 -HOST = 4 - -CHANNEL1 = 18 - -MLR_NOTIFICATION_TIMEOUT = 3600 - - -class MATN_02_MLRFirstUse(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - BR_1: { - 'name': 'BR_1', - 'is_otbr': True, - 'allowlist': [BR_2, TD], - 'version': '1.2', - }, - BR_2: { - 'name': 'BR_2', - 'allowlist': [BR_1, TD], - 'is_otbr': True, - 'version': '1.2', - }, - TD: { - 'name': 'TD', - 'allowlist': [BR_1, BR_2], - 'version': '1.2', - }, - HOST: { - 'name': 'Host', - 'is_host': True - }, - } - - def test(self): - br1 = self.nodes[BR_1] - br2 = self.nodes[BR_2] - td = self.nodes[TD] - host = self.nodes[HOST] - - br1.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual('leader', br1.get_state()) - self.assertTrue(br1.is_primary_backbone_router) - - td.start() - self.simulator.go(5) - self.assertEqual('router', td.get_state()) - - br2.start() - self.simulator.go(5) - self.assertEqual('router', br2.get_state()) - - host.start(start_radvd=False) - self.simulator.go(10) - - # 1. TD registers for multicast address, MA1, at BR_1. - td.add_ipmaddr(MA1) - self.simulator.go(5) - - # 7. Host sends a ping packet to the multicast address, MA1. TD should - # respond to the ping request. - self.assertTrue( - host.ping(MA1, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(5) - - # 11. Host sends a ping packet to the multicast address, MA2. No one - # should respond. - self.assertFalse( - host.ping(MA2, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(5) - - # 14. Host sends a ping packet to the multicast address, MA1g. No one - # should respond. - self.assertFalse( - host.ping(MA1g, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(5) - - # 17. Host sends a ping packet to the global unicast address of BR2. BR2 - # should respond. - self.assertTrue(host.ping(br2.get_ip6_address(config.ADDRESS_TYPE.BACKBONE_GUA), backbone=True, ttl=10)) - self.simulator.go(5) - - self.collect_ipaddrs() - self.collect_rloc16s() - self.collect_rlocs() - self.collect_leader_aloc(BR_1) - self.collect_extra_vars() - - def verify(self, pv: pktverify.packet_verifier.PacketVerifier): - pkts = pv.pkts - vars = pv.vars - pv.summary.show() - - # Ensure the topology is formed correctly - pv.verify_attached('TD', 'BR_1') - pv.verify_attached('BR_2') - - # 1. TD Registers for multicast address, MA1, at BR_1. - # TD unicasts an MLR.req CoAP request to BR_1 as - # "coap://[]:MM/n/mr". - # The payload contains "IPv6Address TLV: MA1". - pkts.filter_wpan_src64(vars['TD']) \ - .filter_ipv6_2dsts(vars['BR_1_RLOC'], PBBR_ALOC) \ - .filter_coap_request('/n/mr') \ - .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1]) \ - .must_next() - - # 3. BR_1 responds to the multicast registration. - # BR_1 unicasts an MLR.rsp CoAP response to TD as "2.04 changed". - # The payload contains "Status TLV: ST_MLR_SUCCESS". - pkts.copy().filter_wpan_src64(vars['BR_1']) \ - .filter_ipv6_dst(vars['TD_RLOC']) \ - .filter_coap_ack('/n/mr') \ - .filter(lambda p: p.thread_nm.tlv.status == 0) \ - .must_next() - - # 3a. BR_2 does not respond to the multicast registration. - pkts.filter_wpan_src64(vars['BR_2']) \ - .filter_ipv6_dst(vars['TD_RLOC']) \ - .filter_coap_ack('/n/mr') \ - .must_not_next() - - # 4. BR_1 informs other BBRs on the network of multicast registration. - # BR_1 multicasts a BMLR.ntf CoAP request to the Backbone Link including - # to BR_2, as follows - pkts.filter_eth_src(vars['BR_1_ETH']) \ - .filter_ipv6_dst(config.ALL_NETWORK_BBRS_ADDRESS) \ - .filter_coap_request('/b/bmr') \ - .filter(lambda - p: p.thread_meshcop.tlv.ipv6_addr == [MA1] and - p.thread_bl.tlv.timeout == MLR_NOTIFICATION_TIMEOUT) \ - .must_next() - - # 6. BR_1 multicasts an MLDv2 message to start listening to MA1. - # BR_1 multicasts an MLDv2 message of type “Version 2 Multicast Listener - # Report” (see [RFC 3810] Section 5.2). Where: - # Nr of Mcast Address at least 1 Records (M): Multicast Address Record - # The Multicast Address Record contains the following: - # Record Type: 4 (CHANGE_TO_EXCLUDE_MODE) - # Number of Sources (N): 0 - # Multicast Address: MA1 - # TODO: Implement this verification - - # 7. Host sends a ping packet to the multicast address, MA1. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .must_next() - - # 8. BR_2 does not forward the ping packet with multicast address MA1 to - # its Thread Network. - pkts.filter_wpan_src64(vars['BR_2']) \ - .filter_AMPLFMA(mpl_seed_id=(vars['BR_2_RLOC'])) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - # 9. BR_1 forwards the ping packet to its Thread Network. - # BR_1 forwards the ping packet with multicast address, MA1, to its - # Thread Network encapsulated in an MPL packet, where: - # MPL Seed ID: If Source outer IP header = BR_1 RLOC, SeedID length = 0 - # Else, SeedID length = 1, and Seed ID = BR_1 RLOC16 - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=(vars['BR_1_RLOC'])) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 10. TD receives the multicast ping packet and sends a ping response - # packet back to Host. - # TD receives the MPL packet containing an encapsulated ping packet to - # MA1, sent by Host, and unicasts a ping response packet back to Host. - pkts.filter_wpan_src64(vars['TD']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 11. Host sends a ping packet to the multicast address, MA2. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA2) \ - .filter_ping_request() \ - .must_next() - - # 12. BR_2 does not forward the ping packet with multicast address, MA2, - # to the Thread Network in whatever way. - pkts.filter_wpan_src64(vars['BR_2']) \ - .filter_AMPLFMA(mpl_seed_id=(vars['BR_2_RLOC'])) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - # 13. BR_1 does not forward the ping packet with multicast address, MA2, - # to the Thread Network in whatever way. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=(vars['BR_1_RLOC'])) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - # 14. Host sends a ping packet to the multicast address, MA1g. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1g) \ - .filter_ping_request() \ - .must_next() - - # 15. BR_2 does not forward the ping packet with multicast address MA1g, - # to the Thread Network in whatever way. - pkts.filter_wpan_src64(vars['BR_2']) \ - .filter_AMPLFMA(mpl_seed_id=(vars['BR_2_RLOC'])) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - # 16. BR_1 does not forward the ping packet with multicast address MA1g, - # to its Thread Network in whatever way. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=(vars['BR_1_RLOC'])) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - # 17. Host sends a ping packet to the BR_2's global unicast address, Gg. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(vars['BR_2_BGUA']) \ - .filter_ping_request() \ - .must_next() - - # 18. BR_2 receives and provides the ping response. - # BR_2 Must send back the ping response to the Host. - pkts.filter_eth_src(vars['BR_2_ETH']) \ - .filter_ipv6_dst(vars['Host_BGUA']) \ - .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/scripts/thread-cert/border_router/MATN/MATN_03_InvalidCommissionerDeregistration.py b/tests/scripts/thread-cert/border_router/MATN/MATN_03_InvalidCommissionerDeregistration.py deleted file mode 100755 index 1d9de6591..000000000 --- a/tests/scripts/thread-cert/border_router/MATN/MATN_03_InvalidCommissionerDeregistration.py +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2021, 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. -# - -import logging -import pktverify -from pktverify import packet_verifier -from pktverify.consts import MA1, PBBR_ALOC -import unittest - -import config -import thread_cert - -# Test description: -# The purpose of this test case is to verify that a Primary BBR ignores a -# Timeout TLV if included in an MLR.req that does not contain a Commissioner -# Session ID TLV nor is signed by a Commissioner. -# -# Topology: -# ----------------(eth)------------------ -# | | | -# BR1 (Leader) ----- BR2 HOST -# | | -# | | -# Router_1------------+ -# - -BR_1 = 1 -BR_2 = 2 -ROUTER_1 = 3 -HOST = 4 - - -class MATN_03_InvalidCommissionerDeregistration(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - BR_1: { - 'name': 'BR_1', - 'is_otbr': True, - 'allowlist': [BR_2, ROUTER_1], - 'version': '1.2', - }, - BR_2: { - 'name': 'BR_2', - 'allowlist': [BR_1, ROUTER_1], - 'is_otbr': True, - 'version': '1.2', - }, - ROUTER_1: { - 'name': 'Router_1', - 'allowlist': [BR_1, BR_2], - 'version': '1.2', - }, - HOST: { - 'name': 'Host', - 'is_host': True - }, - } - - def test(self): - br1 = self.nodes[BR_1] - br2 = self.nodes[BR_2] - router = self.nodes[ROUTER_1] - host = self.nodes[HOST] - - br1.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual('leader', br1.get_state()) - self.assertTrue(br1.is_primary_backbone_router) - - router.start() - self.simulator.go(5) - self.assertEqual('router', router.get_state()) - - br2.start() - self.simulator.go(5) - self.assertEqual('router', router.get_state()) - self.assertFalse(br2.is_primary_backbone_router) - - host.start(start_radvd=False) - self.simulator.go(5) - - router.add_ipmaddr(MA1) - self.simulator.go(5) - - # Ensure that router can receive a multicast ping packet sent to MA1. - self.assertTrue( - host.ping(MA1, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(5) - - # 1. Router attempts to deregister for multicast address, MA1, at BR_1. - router.register_multicast_listener(MA1, timeout=0) - - # 3. Host sends a ping packet to the multicast address, MA1. - self.assertTrue( - host.ping(MA1, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(5) - - self.collect_ipaddrs() - self.collect_rloc16s() - self.collect_rlocs() - self.collect_leader_aloc(BR_1) - self.collect_extra_vars() - - def verify(self, pv: pktverify.packet_verifier.PacketVerifier): - pkts = pv.pkts - vars = pv.vars - pv.summary.show() - - # Ensure the topology is formed correctly - pv.verify_attached('Router_1', 'BR_1') - pv.verify_attached('BR_2') - - # 1. Router attempts to deregister for multicast address, MA1, at BR_1. - # Router unicasts an MLR.req CoAP request to BR_1 as follows: - # coap://[]:MM/n/mr - # Where the payload contains: - # IPv6 Addresses TLV: MA1 - # Timeout TLV: 0 - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_2dsts(vars['BR_1_RLOC'], PBBR_ALOC) \ - .filter_coap_request('/n/mr') \ - .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1] and - p.thread_nm.tlv.timeout == 0) \ - .must_next() - - # 2. BR_1 responds to the multicast registration successfully, - # ignoring the timeout value. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_ipv6_dst(vars['Router_1_RLOC']) \ - .filter_coap_ack('/n/mr') \ - .filter(lambda p: p.thread_nm.tlv.status == 0) \ - .must_next() - - # 3. Host sends a ping packet to the multicast address, MA1. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .must_next() - - # 4. BR_1 forwards the ping packet with multicast address, MA1, to its - # Thread Network encapsulated in an MPL packet. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 5. Router receives the MPL packet containing an encapsulated ping - # packet to MA1, sent by Host, and unicasts a ping response packet back - # to Host. - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/scripts/thread-cert/border_router/MATN/MATN_04_MulticastListenerTimeout.py b/tests/scripts/thread-cert/border_router/MATN/MATN_04_MulticastListenerTimeout.py deleted file mode 100755 index 119529ffc..000000000 --- a/tests/scripts/thread-cert/border_router/MATN/MATN_04_MulticastListenerTimeout.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2021, 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. -# - -import logging -import unittest - -import pktverify -from pktverify import packet_verifier, packet_filter, consts -from pktverify.consts import MA1 -import config -import thread_cert - -# Test description: -# The purpose of this test case is to verify that a Primary BBR can remove an -# entry from a Multicast Listeners Table, when the entry expires. The test case -# also verifies that the Primary BBR accepts a new registration to the -# previously expired multicast group. -# -# Topology: -# ----------------(eth)------------------ -# | | | -# BR1 (Leader) ----- BR2 HOST -# | | -# | | -# Router_1------------+ -# - -BR_1 = 1 -BR_2 = 2 -ROUTER_1 = 3 -HOST = 4 - -REG_DELAY = 10 - - -class MATN_04_MulticastListenerTimeout(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - BR_1: { - 'name': 'BR_1', - 'is_otbr': True, - 'allowlist': [BR_2, ROUTER_1], - 'version': '1.2', - }, - BR_2: { - 'name': 'BR_2', - 'allowlist': [BR_1, ROUTER_1], - 'is_otbr': True, - 'version': '1.2', - }, - ROUTER_1: { - 'name': 'Router_1', - 'allowlist': [BR_1, BR_2], - 'version': '1.2', - }, - HOST: { - 'name': 'Host', - 'is_host': True - }, - } - - def test(self): - br1 = self.nodes[BR_1] - br2 = self.nodes[BR_2] - router = self.nodes[ROUTER_1] - host = self.nodes[HOST] - - br1.set_backbone_router(reg_delay=REG_DELAY, mlr_timeout=consts.MLR_TIMEOUT_MIN) - br1.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual('leader', br1.get_state()) - self.assertTrue(br1.is_primary_backbone_router) - - router.start() - self.simulator.go(5) - self.assertEqual('router', router.get_state()) - - br2.start() - self.simulator.go(5) - self.assertEqual('router', br2.get_state()) - self.assertFalse(br2.is_primary_backbone_router) - - host.start(start_radvd=False) - self.simulator.go(10) - - # Router_1 registers for multicast address, MA1, at BR_1. - router.add_ipmaddr(MA1) - self.simulator.go(5) - - # 1. Host sends a ping packet to the multicast address, MA1. - self.assertTrue( - host.ping(MA1, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(5) - - # 3a. By internal means, Router_1 stop listening to the multicast - # address, MA1. - router.del_ipmaddr(MA1) - - # 4. After (MLR_TIMEOUT_MIN+2) seconds - self.simulator.go(consts.MLR_TIMEOUT_MIN + 2) - - # 5. Host sends a ping packet to the multicast address, MA1. - self.assertFalse( - host.ping(MA1, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(5) - - # 6a. Router_1 registers for multicast address, MA1, at BR_1. - router.add_ipmaddr(MA1) - self.simulator.go(5) - - # 7. Host sends a ping packet to MA1. - self.assertTrue( - host.ping(MA1, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - - self.collect_ipaddrs() - self.collect_rloc16s() - self.collect_rlocs() - self.collect_leader_aloc(BR_1) - self.collect_extra_vars() - - def verify(self, pv: pktverify.packet_verifier.PacketVerifier): - pkts = pv.pkts - vars = pv.vars - pv.summary.show() - - # Ensure the topology is formed correctly - pv.verify_attached('Router_1', 'BR_1') - pv.verify_attached('BR_2') - - # 1. Host sends a ping packet to the multicast address, MA1. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .must_next() - - # 2. BR_1 forwards the ping packet with multicast address, MA1, to its - # Thread Network encapsulated in an MPL packet. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(vars['BR_1_RLOC']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 3. Router_1 receives the MPL packet containing an encapsulated ping - # packet to MA1, sent by Host, and unicasts a ping response packet back - # to Host. - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 4. After (MLR_TIMEOUT_MIN+2) seconds, BR_1 multicasts an MLDv2 message - # of type “Version 2 Multicast Listener Report” (see [RFC 3810] Section - # 5.2) - # TODO - - # 5. Host sends a ping packet to the multicast address, MA1. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .must_next() - - # 6. BR_1 does not forward the ping packet with multicast address, MA1, - # to its Thread Network. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(vars['BR_1_RLOC']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - # 7. Host sends a ping packet to the multicast address, MA1. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .must_next() - - # 8. BR_1 forwards the ping packet with multicast address, MA1, to its - # Thread Network encapsulated in an MPL packet. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(vars['BR_1_RLOC']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 9. Router_1 receives the MPL packet containing an encapsulated ping - # packet to MA1, sent by Host, and unicasts a ping response packet back - # to Host. - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/scripts/thread-cert/border_router/MATN/MATN_05_ReregistrationToSameMulticastGroup.py b/tests/scripts/thread-cert/border_router/MATN/MATN_05_ReregistrationToSameMulticastGroup.py deleted file mode 100755 index e931127ea..000000000 --- a/tests/scripts/thread-cert/border_router/MATN/MATN_05_ReregistrationToSameMulticastGroup.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2021, 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. -# - -import logging -import unittest - -import pktverify -from pktverify import packet_verifier, packet_filter, consts -from pktverify.consts import MA1, PBBR_ALOC -import config -import thread_cert - -# Test description: -# The purpose of this test case is to verify that a Primary BBR (DUT) can manage -# a re-registration of a device on its network to remain receiving multicasts. -# The test also verifies the usage of UDP multicast packets across backbone and -# internal Thread network. -# -# Topology: -# ----------------(eth)------------------ -# | | | -# BR_1 (Leader) ---- BR_2 HOST -# | | -# | | -# Router_1 -----------+ -# - -BR_1 = 1 -BR_2 = 2 -ROUTER_1 = 3 -HOST = 4 - -REG_DELAY = 10 -UDP_HEADER_LENGTH = 8 - - -class MATN_05_ReregistrationToSameMulticastGroup(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - BR_1: { - 'name': 'BR_1', - 'is_otbr': True, - 'allowlist': [BR_2, ROUTER_1], - 'version': '1.2', - }, - BR_2: { - 'name': 'BR_2', - 'allowlist': [BR_1, ROUTER_1], - 'is_otbr': True, - 'version': '1.2', - }, - ROUTER_1: { - 'name': 'Router_1', - 'allowlist': [BR_1, BR_2], - 'version': '1.2', - }, - HOST: { - 'name': 'Host', - 'is_host': True - }, - } - - def test(self): - br1 = self.nodes[BR_1] - br2 = self.nodes[BR_2] - router1 = self.nodes[ROUTER_1] - host = self.nodes[HOST] - - br1.set_backbone_router(reg_delay=REG_DELAY, mlr_timeout=consts.MLR_TIMEOUT_MIN) - br1.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual('leader', br1.get_state()) - self.assertTrue(br1.is_primary_backbone_router) - - router1.start() - self.simulator.go(10) - self.assertEqual('router', router1.get_state()) - - br2.start() - self.simulator.go(10) - self.assertEqual('router', br2.get_state()) - self.assertFalse(br2.is_primary_backbone_router) - - host.start(start_radvd=False) - self.simulator.go(10) - - # Router_1 registers for multicast address, MA1, at BR_1. - router1.add_ipmaddr(MA1) - self.simulator.go(5) - - # 1. Host sends a ping packet to the multicast address, MA1. - self.assertTrue( - host.ping(MA1, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - - # Ensure Router_1 renews its multicast registration - self.simulator.go(consts.MLR_TIMEOUT_MIN - 10) - - # 4. Within MLR_TIMEOUT_MIN seconds, Host sends a ping packet to the - # multicast address, MA1. The destination port 5683 is used for the UDP - # Multicast packet transmission. - host.udp_send_host(data='PING', ipaddr=MA1, port=5683) - self.simulator.go(5) - - # 6a. By internal means, Router_1 stops listening to the multicast - # address, MA1. - router1.del_ipmaddr(MA1) - - # 7. After (MLR_TIMEOUT_MIN+2) seconds, Host multicasts a ping packet to - # multicast address, MA1, on the backbone link. - self.simulator.go(consts.MLR_TIMEOUT_MIN + 2) - self.assertFalse( - host.ping(MA1, backbone=True, ttl=10, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - - self.collect_ipaddrs() - self.collect_rloc16s() - self.collect_rlocs() - self.collect_leader_aloc(BR_1) - self.collect_extra_vars() - - def verify(self, pv: pktverify.packet_verifier.PacketVerifier): - pkts = pv.pkts - vars = pv.vars - pv.summary.show() - logging.info(f'vars = {vars}') - - # Ensure the topology is formed correctly - pv.verify_attached('Router_1', 'BR_1') - pv.verify_attached('BR_2') - - # Initial registration - # Router_1 registers for multicast address, MA1, at BR_1. - # Router_1 unicasts an MLR.req CoAP request to BR_1 as - # "coap://[]:MM/n/mr". - # The payload contains "IPv6Address TLV: MA1". - initial_registration_pkt = pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_2dsts(vars['BR_1_RLOC'], PBBR_ALOC) \ - .filter_coap_request('/n/mr') \ - .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1]) \ - .must_next() - - # 1. Host sends a ping packet to the multicast address, MA1. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .must_next() - - # 2. BR_1 forwards the ping packet with multicast address, MA1, to its - # Thread Network encapsulated in an MPL packet. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 3. Router_1 receives the MPL packet containing an encapsulated ping - # packet to MA1, sent by Host, and unicasts a ping response packet back - # to Host. - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 3a. Within MLR_TIMEOUT_MIN seconds of initial registration, Router_1 - # re-registers for multicast address, MA1, at BR_1. - # Router_1 unicasts an MLR.req CoAP request to BR_1 as - # "coap://[]:MM/n/mr". - # The payload contains "IPv6Address TLV: MA1". - pkts.copy() \ - .filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_2dsts(vars['BR_1_RLOC'], PBBR_ALOC) \ - .filter_coap_request('/n/mr') \ - .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1] and - p.sniff_timestamp <= initial_registration_pkt.sniff_timestamp + consts.MLR_TIMEOUT_MIN) \ - .must_next() - - # 4. Within MLR_TIMEOUT_MIN seconds, Host sends a ping packet to the - # multicast address, MA1. The destination port 5683 is used for the UDP - # Multicast packet transmission. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter(lambda p: p.udp.length == UDP_HEADER_LENGTH + len('PING') - and p.udp.dstport == 5683) \ - .must_next() - - # 5. BR_1 forwards the UDP ping packet with multicast address, MA1, to - # its Thread Network encapsulated in an MPL packet. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ - .filter(lambda p: p.udp.length == _pkt.udp.length) \ - .must_next() - - # 6. Router_1 receives the ping packet. - # Use the port 5683 (CoAP port) to verify that the - # UDP Multicast packet is received. - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter( - lambda p: p.udp.length == _pkt.udp.length and p.udp.dstport == 5683) \ - .must_next() - - # 7. After (MLR_TIMEOUT_MIN+2) seconds, Host multicasts a ping packet to - # multicast address, MA1, on the backbone link. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .must_next() - - # 8. BR_1 does not forward the ping packet with multicast address, MA1, - # to its Thread Network. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/scripts/thread-cert/border_router/MATN/MATN_09_DefaultBRMulticastForwarding.py b/tests/scripts/thread-cert/border_router/MATN/MATN_09_DefaultBRMulticastForwarding.py deleted file mode 100755 index df09f58a6..000000000 --- a/tests/scripts/thread-cert/border_router/MATN/MATN_09_DefaultBRMulticastForwarding.py +++ /dev/null @@ -1,191 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2021, 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. -# - -import logging -import unittest - -import pktverify -from pktverify import packet_verifier, packet_filter, consts -from pktverify.consts import MA1 -import config -import thread_cert - -# Test description: -# The purpose of this test case is to verify that a Secondary BBR can take over -# forwarding of outbound multicast transmissions from the Thread Network when -# the Primary BBR disconnects. The Secondary in that case becomes Primary. -# -# Topology: -# ----------------(eth)------------------ -# | | -# BR_1 (Leader) ---- BR_2 -# | | -# | | -# ROUTER_1 -----------+ -# -from pktverify.null_field import nullField - -BR_1 = 1 -BR_2 = 2 -ROUTER_1 = 3 - - -class MATN_09_FailureOfPrimaryBBROutboundMulticast(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - BR_1: { - 'name': 'BR_1', - 'is_otbr': True, - 'allowlist': [BR_2, ROUTER_1], - 'version': '1.2', - }, - BR_2: { - 'name': 'BR_2', - 'is_otbr': True, - 'allowlist': [BR_1, ROUTER_1], - 'version': '1.2', - }, - ROUTER_1: { - 'name': 'Router_1', - 'allowlist': [BR_1, BR_2], - 'version': '1.2', - 'partition_id': 1, - 'network_id_timeout': 150, - }, - } - - def test(self): - br1 = self.nodes[BR_1] - br2 = self.nodes[BR_2] - router1 = self.nodes[ROUTER_1] - - br1.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual('leader', br1.get_state()) - self.assertTrue(br1.is_primary_backbone_router) - - router1.start() - self.simulator.go(10) - self.assertEqual('router', router1.get_state()) - - br2.start() - self.simulator.go(5) - self.assertEqual('router', br2.get_state()) - self.assertFalse(br2.is_primary_backbone_router) - - # 1. Router sends a ping packet to the multicast address, MA1, - # encapsulated in an MPL packet - self.assertFalse(router1.ping(MA1)) - self.simulator.go(5) - - # 4a. Switch off BR_1 - br1.disable_backbone_router() - br1.thread_stop() - br1.interface_down() - self.simulator.go(180) - - # 4b. BR_2 detects the missing Primary BBR and becomes the Leader of - # the Thread Network. - self.assertEqual('disabled', br1.get_state()) - self.assertEqual('leader', br2.get_state()) - self.assertEqual('router', router1.get_state()) - self.assertFalse(br1.is_primary_backbone_router) - self.assertTrue(br2.is_primary_backbone_router) - - # 5. Router_1 sends a ping packet to the multicast address, MA1, - # encapsulated in an MPL packet. - self.assertFalse(router1.ping(MA1)) - - self.collect_ipaddrs() - self.collect_rloc16s() - self.collect_rlocs() - self.collect_leader_aloc(BR_2) - self.collect_extra_vars() - - def verify(self, pv: pktverify.packet_verifier.PacketVerifier): - pkts = pv.pkts - vars = pv.vars - pv.summary.show() - logging.info(f'vars = {vars}') - - # Ensure the topology is formed correctly - pv.verify_attached('Router_1', 'BR_1') - pv.verify_attached('BR_2') - - # 1. Router_1 sends a ping packet to the multicast address, MA1, - # encapsulated in an MPL packet. - _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ - .filter_ping_request() \ - .must_next() - - initial_identifier = _pkt.icmpv6.echo.identifier - - # 2. BR_1 forwards the multicast ping packet with multicast address, - # MA1, to the LAN. - pkts.filter_eth_src(vars['BR_1_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - with pkts.save_index(): - pv.verify_attached('Router_1', 'BR_2') - - # 4b. BR_2 detects the missing Primary BBR and becomes the Leader of the - # Thread Network, distributing its BBR dataset. - # Verify that Router_1 has received the new BBR Dataset from BR_2, - # where: - # • RLOC16 in Server TLV == The RLOC16 of BR_2 - # All fields in the Service TLV contain valid values. - pkts.filter_wpan_src64(vars['BR_2']) \ - .filter_mle() \ - .filter( - lambda p: p.thread_nwd.tlv.server_16 is not nullField and - vars['BR_2_RLOC16'] in p.thread_nwd.tlv.server_16) \ - .must_next() - - # 5.Router_1 sends a ping packet to the multicast address, MA1, - # encapsulated in an MPL packet. - _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ - .filter_ping_request() \ - .filter(lambda p: p.icmpv6.echo.identifier != initial_identifier) \ - .must_next() - - # 6. BR_2 forwards the multicast ping packet with multicast address, - # MA1, to the LAN. - pkts.filter_eth_src(vars['BR_2_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/scripts/thread-cert/border_router/MATN/MATN_12_HopLimitProcessing.py b/tests/scripts/thread-cert/border_router/MATN/MATN_12_HopLimitProcessing.py deleted file mode 100755 index c51c04810..000000000 --- a/tests/scripts/thread-cert/border_router/MATN/MATN_12_HopLimitProcessing.py +++ /dev/null @@ -1,276 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2021, 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. -# - -import logging -import unittest - -import pktverify -from pktverify import packet_verifier, packet_filter, consts -from pktverify.consts import MA1, MA2 -import config -import thread_cert - -# Test description: -# The purpose of this test case is to verify that a Primary BBR correctly -# decrements the Hop Limit field by 1 if packet is forwarded with MPL, and if -# forwarded from Thread Network (using MPL) to LAN. This test also verifies that -# the BR drops a packet with Hop Limit 0. It also checks the use of IPv6 packets -# that span multiple 6LoWPAN fragments. -# -# Topology: -# ----------------(eth)------------------ -# | | -# BR_1 (Leader) | -# | HOST -# | -# ROUTER_1 -# - -BR_1 = 1 -ROUTER_1 = 2 -HOST = 3 -ICMP_HEADER_LEN = 8 - - -class MATN_12_HopLimitProcessing(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - BR_1: { - 'name': 'BR_1', - 'is_otbr': True, - 'allowlist': [ROUTER_1], - 'version': '1.2', - }, - ROUTER_1: { - 'name': 'Router_1', - 'allowlist': [BR_1], - 'version': '1.2', - }, - HOST: { - 'name': 'Host', - 'is_host': True, - }, - } - - def test(self): - br1 = self.nodes[BR_1] - router1 = self.nodes[ROUTER_1] - host = self.nodes[HOST] - - br1.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual('leader', br1.get_state()) - self.assertTrue(br1.is_primary_backbone_router) - - router1.start() - self.simulator.go(5) - self.assertEqual('router', router1.get_state()) - - host.start(start_radvd=False) - self.simulator.go(10) - - # Router_1 registers a multicast address, MA1. - router1.add_ipmaddr(MA1) - self.simulator.go(5) - - # 1. Host multicasts a ping packet to the multicast address, MA1, with - # the IPv6 Hop Limit field set to 59. The size of the payload is 130 - # bytes. - self.assertTrue( - host.ping(MA1, - backbone=True, - ttl=59, - size=130, - interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(5) - - # 4. Host multicasts a ping packet to the multicast address, MA1, with - # the IPv6 Hop Limit field set to 1. The size of the payload is 130 - # bytes. - host.ping(MA1, - backbone=True, - ttl=1, - size=130, - interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0]) - self.simulator.go(5) - - # 6. Router_1 sends a ping packet encapsulated in an MPL packet to the - # multicast address, MA2, with the Hop Limit field of the inner packet - # set to 159. The size of the payload is 130 bytes. - self.assertFalse(router1.ping(MA2, hoplimit=159, size=130)) - self.simulator.go(5) - - # 8. Router_1 sends a ping packet encapsulated in an MPL multicast - # packet to the multicast address, MA2, with the Hop Limit field of - # the inner (encapsulated) packet set to 2. The size of the payload is - # 130 bytes. - self.assertFalse(router1.ping(MA2, hoplimit=2, size=130)) - self.simulator.go(5) - - # 10. Router_1 sends a ping packet encapsulated in an MPL multicast - # packet to the multicast address, MA2, with the Hop Limit field of the - # inner packet set to 1. The size of the payload is 130 bytes. - self.assertFalse(router1.ping(MA2, hoplimit=1, size=130)) - self.simulator.go(5) - - # 11. Router_1 sends a ping packet encapsulated in an MPL multicast - # packet to the multicast address, MA2, with the Hop Limit field of the - # inner packet set to 0. - self.assertFalse(router1.ping(MA2, hoplimit=0, size=130)) - self.simulator.go(5) - - self.collect_ipaddrs() - self.collect_rloc16s() - self.collect_rlocs() - self.collect_extra_vars() - - def verify(self, pv: pktverify.packet_verifier.PacketVerifier): - pkts = pv.pkts - vars = pv.vars - pv.summary.show() - logging.info(f'vars = {vars}') - - # Ensure the topology is formed correctly - pv.verify_attached('Router_1', 'BR_1') - - # 1. Host multicasts a ping packet to the multicast address, MA1, with - # the IPv6 Hop Limit field set to 59. The size of the payload is 130 - # bytes. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .filter(lambda - p: p.ipv6.hlim == 59 and p.ipv6.plen == 130 + ICMP_HEADER_LEN) \ - .must_next() - - # 2. BR_1 forwards the ping packet to Router_1 as an MPL packet - # encapsulating the IPv6 packet with the Hop Limit field of the inner - # packet set to 58. - _pkt2 = pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .filter(lambda - p: p.ipv6inner.hlim == 58 and p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ - .must_next() - - # 3. Router_1 receives the multicast ping packet. - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 4. Host multicasts a ping packet to the multicast address, MA1, with - # the IPv6 Hop Limit field set to 1. The size of the payload is 130 - # bytes. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA1) \ - .filter_ping_request() \ - .filter( - lambda - p: p.ipv6.hlim == 1 and p.ipv6.plen == 130 + ICMP_HEADER_LEN) \ - .must_next() - - # 5. BR_1 does not forward the ping packet. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['BR_1']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - # 6. Router_1 sends a ping packet encapsulated in an MPL packet to the - # multicast address, MA2, with the Hop Limit field of the inner - # packet set to 159. The size of the payload is 130 bytes. - _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ - .filter_ping_request() \ - .filter(lambda p: p.ipv6inner.dst == MA2 and - p.ipv6inner.hlim == 159 and - p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ - .must_next() - - # 7. BR_1 forwards the multicast ping packet to the LAN with the Hop - # Limit field set to 158. - pkts.filter_eth_src(vars['BR_1_ETH']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .filter(lambda p: p.ipv6.hlim == 158) \ - .must_next() - - # 8. Router_1 sends a ping packet encapsulated in an MPL multicast - # packet to the multicast address, MA2, with the Hop Limit field of the - # inner packet set to 2. The size of the payload is 130 bytes - _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ - .filter_ping_request() \ - .filter(lambda p: p.ipv6inner.dst == MA2 and - p.ipv6inner.hlim == 2 and - p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ - .must_next() - - # 9. BR_1 forwards the multicast packet to the LAN with the Hop Limit - # field set to 1. - pkts.filter_eth_src(vars['BR_1_ETH']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .filter(lambda p: p.ipv6.hlim == 1) \ - .must_next() - - # 10. Router_1 sends a ping packet encapsulated in an MPL multicast - # packet to the multicast address, MA2, with the Hop Limit field of the - # inner packet set to 1. The size of the payload is 130 bytes. - _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ - .filter_ping_request() \ - .filter(lambda p: p.ipv6inner.dst == MA2 and - p.ipv6inner.hlim == 1 and - p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ - .must_next() - - # 11. BR_1 does not forward the ping packet to the LAN. - pkts.filter_eth_src(vars['BR_1_ETH']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - # 12. Router_1 sends a ping packet encapsulated in an MPL multicast - # packet to the multicast address, MA2, with the Hop Limit field of the - # inner packet set to 0. - _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['Router_1_RLOC']) \ - .filter_ping_request() \ - .filter(lambda p: p.ipv6inner.dst == MA2 and - p.ipv6inner.hlim == 0 and - p.ipv6inner.plen == 130 + ICMP_HEADER_LEN) \ - .must_next() - - # 13. BR_1 does not forward the ping packet to the LAN. - pkts.filter_eth_src(vars['BR_1_ETH']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/scripts/thread-cert/border_router/MATN/MATN_15_ChangeOfPrimaryBBRTriggersRegistration.py b/tests/scripts/thread-cert/border_router/MATN/MATN_15_ChangeOfPrimaryBBRTriggersRegistration.py deleted file mode 100755 index 71c7da285..000000000 --- a/tests/scripts/thread-cert/border_router/MATN/MATN_15_ChangeOfPrimaryBBRTriggersRegistration.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2021, 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. -# - -import logging -import unittest - -import pktverify -from pktverify import packet_verifier, packet_filter, consts -from pktverify.consts import MA1, MA2 -import config -import thread_cert - -# Test description: -# The purpose of this test case is to verify that a Thread End Device detects a -# change of Primary BBR device and triggers a re-registration to its multicast -# groups. -# -# Topology: -# -# -# ----------------(eth)-------------------- -# | -# BR_1 (Leader) -----BR_2 -# | | -# | | -# | | -# Router_1-------------+ -# | -# | -# TD -# - -BR_1 = 1 -BR_2 = 2 -ROUTER_1 = 3 -TD = 4 - -REG_DELAY = 10 - -NETWORK_ID_TIMEOUT = 120 -WAIT_TIME_ALLOWANCE = 60 - - -class MATN_15_ChangeOfPrimaryBBRTriggersRegistration(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - BR_1: { - 'name': 'BR_1', - 'is_otbr': True, - 'allowlist': [BR_2, ROUTER_1], - 'version': '1.2', - }, - BR_2: { - 'name': 'BR_2', - 'is_otbr': True, - 'allowlist': [BR_1, ROUTER_1], - 'version': '1.2', - }, - ROUTER_1: { - 'name': 'Router_1', - 'allowlist': [BR_1, BR_2, TD], - 'version': '1.2', - 'partition_id': 1, - }, - TD: { - 'name': 'TD', - 'allowlist': [ROUTER_1], - 'router_eligible': False, - 'version': '1.2', - 'partition_id': 1, - }, - } - - def test(self): - br1 = self.nodes[BR_1] - br2 = self.nodes[BR_2] - router1 = self.nodes[ROUTER_1] - td = self.nodes[TD] - - br1.set_backbone_router(reg_delay=REG_DELAY, mlr_timeout=consts.MLR_TIMEOUT_MIN) - br1.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual('leader', br1.get_state()) - self.assertTrue(br1.is_primary_backbone_router) - - br2.set_backbone_router(reg_delay=REG_DELAY, mlr_timeout=consts.MLR_TIMEOUT_MIN) - router1.start() - self.simulator.go(5) - self.assertEqual('router', router1.get_state()) - - td.start() - self.simulator.go(5) - self.assertEqual('child', td.get_state()) - - br2.start() - self.simulator.go(5) - self.assertEqual('router', br2.get_state()) - self.assertFalse(br2.is_primary_backbone_router) - - # TD registers for a multicast address, MA1. - td.add_ipmaddr(MA1) - self.simulator.go(20) - - # 1. Disable BR_1 such that BR_2 becomes the Primary BBR for the Thread - # Network. - br1.disable_backbone_router() - br1.thread_stop() - br1.interface_down() - self.simulator.go(NETWORK_ID_TIMEOUT + WAIT_TIME_ALLOWANCE) - - # Make sure that BR_2 becomes the primary BBR - self.assertEqual('disabled', br1.get_state()) - self.assertFalse(br1.is_primary_backbone_router) - self.assertTrue(br2.is_primary_backbone_router) - - self.collect_ipaddrs() - self.collect_rloc16s() - self.collect_rlocs() - self.collect_extra_vars() - - def verify(self, pv: pktverify.packet_verifier.PacketVerifier): - pkts = pv.pkts - vars = pv.vars - pv.summary.show() - - # Ensure the topology is formed correctly - pv.verify_attached('Router_1', 'BR_1') - - # 2. TD automatically detects the Primary BBR change and registers for - # multicast address, MA1, at BR_2. - # TD unicasts an MLR.req CoAP request as follows: - # coap://[]:MM/n/mr - # Where the payload contains: - # IPv6 Addresses TLV: MA1 - _pkt = pkts.filter_wpan_src64(vars['TD']) \ - .filter_ipv6_2dsts(vars['BR_2_RLOC'], consts.PBBR_ALOC) \ - .filter_coap_request('/n/mr') \ - .filter(lambda p: p.thread_meshcop.tlv.ipv6_addr == [MA1]) \ - .must_next() - - # 3. Router_1 forwards the registration request to BR_2. - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_2dsts(vars['BR_2_RLOC'], consts.PBBR_ALOC) \ - .filter_coap_request('/n/mr') \ - .filter(lambda - p: p.thread_meshcop.tlv.ipv6_addr == [MA1] and - p.coap.mid == _pkt.coap.mid) \ - .must_next() - - # 4. BR_2 unicasts an MLR.rsp CoAP response to TD as: 2.04 changed. - # Where the payload contains: - # Status TLV: ST_MLR_SUCCESS - pkts.filter_wpan_src64(vars['BR_2']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_coap_ack('/n/mr') \ - .filter(lambda - p: p.coap.mid == _pkt.coap.mid and - p.thread_nm.tlv.status == 0) \ - .must_next() - - # 5. Router_1 forwards the response to TD. - pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_coap_ack('/n/mr') \ - .filter(lambda - p: p.coap.mid == _pkt.coap.mid and - p.thread_nm.tlv.status == 0) \ - .must_next() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/scripts/thread-cert/border_router/MATN/MATN_16_LargeNumberOfMulticastGroupSubscriptionsToBBR.py b/tests/scripts/thread-cert/border_router/MATN/MATN_16_LargeNumberOfMulticastGroupSubscriptionsToBBR.py deleted file mode 100755 index d5a2ae16f..000000000 --- a/tests/scripts/thread-cert/border_router/MATN/MATN_16_LargeNumberOfMulticastGroupSubscriptionsToBBR.py +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2021, 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. -# - -import logging -import unittest - -import pktverify -from pktverify import packet_verifier, packet_filter, consts -from pktverify.consts import MAS, MA2 -import config -import thread_cert - -# Test description: -# The purpose of this test case is to verify that the Primary BBR can handle a -# large number (75) of subscriptions to different multicast groups. Multicast -# registrations are performed each time with 15 multicast addresses per -# registration request. -# -# Topology: -# -# -# ----------------(eth)-------------------- -# | | -# BR_1 (Leader) | -# | Host -# | -# | -# Router_1 -# -# -# - -BR_1 = 1 -ROUTER_1 = 2 -HOST = 3 - -REG_DELAY = 10 - - -class MATN_16_LargeNumberOfMulticastGroupSubscriptionsToBBR(thread_cert.TestCase): - USE_MESSAGE_FACTORY = False - - TOPOLOGY = { - BR_1: { - 'name': 'BR_1', - 'is_otbr': True, - 'allowlist': [ROUTER_1], - 'version': '1.2', - }, - ROUTER_1: { - 'name': 'Router_1', - 'allowlist': [BR_1], - 'version': '1.2', - }, - HOST: { - 'name': 'Host', - 'is_host': True, - }, - } - - def test(self): - br1 = self.nodes[BR_1] - router1 = self.nodes[ROUTER_1] - host = self.nodes[HOST] - - br1.set_backbone_router(reg_delay=REG_DELAY, mlr_timeout=consts.MLR_TIMEOUT_MIN) - br1.start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual('leader', br1.get_state()) - self.assertTrue(br1.is_primary_backbone_router) - - router1.start() - self.simulator.go(5) - self.assertEqual('router', router1.get_state()) - - host.start(start_radvd=False) - self.simulator.go(5) - - # Loop steps 1 to 4 with i := 1 to 5. - for i in range(1, 6): - # 1. Router_1 registers for 15 multicast addresses, MASi. - self.assertEqual((0, []), router1.register_multicast_listener(*(MAS[i][1:]), - timeout=consts.MLR_TIMEOUT_MIN)) - self.simulator.go(5) - - # Loop steps 5 to 6 with i := 1 to 5. - for i in range(1, 6): - # 5. Host sends a ping packet to the multicast address, - # MASi[ 3 * i - 1], on the backbone link. - host.ping(MAS[i][i * 3 - 1], - backbone=True, - ttl=64, - interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0]) - - self.simulator.go(3) - - # 7. Host multicasts a packet to the multicast addresses, MA2. - self.assertFalse( - host.ping(MA2, backbone=True, ttl=64, interface=host.get_ip6_address(config.ADDRESS_TYPE.ONLINK_ULA)[0])) - self.simulator.go(3) - - self.collect_ipaddrs() - self.collect_rloc16s() - self.collect_rlocs() - self.collect_extra_vars() - self.collect_leader_aloc(BR_1) - - def verify(self, pv: pktverify.packet_verifier.PacketVerifier): - pkts = pv.pkts - vars = pv.vars - pv.summary.show() - - # Ensure the topology is formed correctly - pv.verify_attached('Router_1', 'BR_1') - - # Loop steps 1 to 4 with i := 1 to 5. - for i in range(1, 6): - # 1. Router_1 registers for 15 multicast addresses, MASi. - # [Automatic result:] - # Unicasts an MLR.req CoAP request to BR_1 as follows: - # coap://[ or ]:MM/n/mr - # Where the payload contains: - # IPv6 Addresses TLV: MASi (15 addresses) - _pkt = pkts.filter_wpan_src64(vars['Router_1']) \ - .filter_ipv6_2dsts(vars['BR_1_RLOC'], consts.PBBR_ALOC) \ - .filter_coap_request('/n/mr') \ - .filter(lambda p: set(p.thread_meshcop.tlv.ipv6_addr) == set(MAS[i][1:])) \ - .must_next() - - # 2. BR_1 Responds to the multicast registration. - # BR_1 unicasts an MLR.rsp CoAP response to Router_1 as follows: - # 2.04 changed - # Where the payload contains: - # Status TLV: ST_MLR_SUCCESS - pkts.copy().filter_wpan_src64(vars['BR_1']) \ - .filter_ipv6_dst(_pkt.ipv6.src) \ - .filter_coap_ack('/n/mr') \ - .filter(lambda p: p.coap.mid == _pkt.coap.mid and p.thread_nm.tlv.status == 0) \ - .must_next() - - # 3. BR_1 informs other BBRs on the network of the multicast - # registrations. - # BR_1 multicasts a BMLR.ntf CoAP request to the Backbone Link, - # as follows: - # coap://[]:BB/b/bmr - # Where the payload contains: - # IPv6 Addresses TLV: MASi (15 addresses) - # Timeout TLV: default MLR timeout of BR_1 - pkts.filter_eth_src(vars['BR_1_ETH']) \ - .filter_ipv6_dst(config.ALL_NETWORK_BBRS_ADDRESS) \ - .filter_coap_request('/b/bmr') \ - .filter( - lambda p: set(p.thread_meshcop.tlv.ipv6_addr) == set(MAS[i][1:]) and - p.thread_bl.tlv.timeout == consts.MLR_TIMEOUT_MIN) \ - .must_next() - - # 4. BR_1 multicasts an MLDv2 message of type “Version 2 - # Multicast Listener Report” (see [RFC 3810] Section 5.2). - # Where: - # Nr of Mcast Address Records(M) >= 15 - # Multicast Address Record[j]: - # Each of the j := 1 ... 15 Multicast Address Record containing an - # address of the set MASi contains the following: - # Record Type: 4 (CHANGE_TO_EXCLUDE_MODE) - # Number of Sources (N): 0 - # Multicast Address: MASi[j] - # Alternatively, the DUT may also send multiple of above messages - # each with a portion of the 15 addresses MASi. - # In this case the Nr of Mcast Address Records can be < 15 - # but the sum over all messages MUST be >= 15. - # TODO - - # Loop steps 5 to 6 with i := 1 to 5. - for i in range(1, 6): - # 5. Host sends a ping packet to the multicast address, - # MASi[ 3 * i - 1], on the backbone link. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MAS[i][3 * i - 1]) \ - .filter_ping_request() \ - .must_next() - - # 6. BR_1 forwards the ping packet of the previous step to its - # Thread Network encapsulated in an MPL packet. - pkts.copy().filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA(mpl_seed_id=vars['BR_1_RLOC']) \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_next() - - # 7. Host multicasts a packet to the multicast addresses, MA2. - _pkt = pkts.filter_eth_src(vars['Host_ETH']) \ - .filter_ipv6_dst(MA2) \ - .filter_ping_request() \ - .must_next() - - # 8. BR_1 does not forward the packet to its Thread Network. - pkts.filter_wpan_src64(vars['BR_1']) \ - .filter_AMPLFMA() \ - .filter_ping_request(identifier=_pkt.icmpv6.echo.identifier) \ - .must_not_next() - - -if __name__ == '__main__': - unittest.main()