[scripts] add MLR Backbone multicast routing test (#5578)

- backbone/test_mlr_multicast_routing.py verifies the basic features
  of Backbone multicast routing

- backbone/test_mlr_multicast_routing_timeout.py verifies that MLR
  timeout works

- backbone/test_mlr_multicast_routing_commissioner_timeout.py verifies
  that Commissioner MLR timeout works
This commit is contained in:
Simon Lin
2020-10-26 22:46:48 -07:00
committed by GitHub
parent 12b967cce2
commit 8707b63894
12 changed files with 565 additions and 9 deletions
+1 -1
View File
@@ -227,7 +227,7 @@ jobs:
COVERAGE: 1
MULTIPLY: 3
PYTHONUNBUFFERED: 1
OTBR_COMMIT: "bf28f461fa2a8551f0a4161c04b87f7240856608" # Date: Wed Oct 14 12:00:44 2020 +0800
VERBOSE: 1
steps:
- uses: actions/checkout@v2
- name: Build OTBR Docker
+3 -2
View File
@@ -271,8 +271,8 @@ do_build_otbr_docker()
echo "Building OTBR Docker ..."
local otdir
local otbrdir
local otbr_options="-DOTBR_BACKBONE_ROUTER=ON -DOT_DUA=ON -DOT_MLR=ON -DOT_REFERENCE_DEVICE=ON -DOT_COVERAGE=ON"
local otbr_commit=${OTBR_COMMIT:-master}
local otbr_options="-DOT_DUA=ON -DOT_MLR=ON -DOT_COVERAGE=ON"
local otbr_commit=${OTBR_COMMIT:-ce1cc3f9141571505bc9a8b705d2eb775849c92c} # ot-br-posix #532
local otbr_docker_image=${OTBR_DOCKER_IMAGE:-otbr-ot12-backbone-ci}
otbrdir=$(mktemp -d -t otbr_XXXXXX)
@@ -289,6 +289,7 @@ do_build_otbr_docker()
cp -r "${otdir}" third_party/openthread/repo
rm -rf .git
docker build -t "${otbr_docker_image}" -f etc/docker/Dockerfile . \
--build-arg BACKBONE_ROUTER=1 \
--build-arg REFERENCE_DEVICE=1 \
--build-arg OT_BACKBONE_CI=1 \
--build-arg NAT64=0 \
@@ -0,0 +1,224 @@
#!/usr/bin/env python3
#
# Copyright (c) 2020, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# This test verifies that the basic MLR feature works.
#
import logging
import unittest
import config
import thread_cert
from pktverify.packet_verifier import PacketVerifier
PBBR = 1
SBBR = 2
ROUTER = 3
LEADER = 4
FED = 5
MED = 6
SED = 7
HOST = 8
SED_POLL_PERIOD = 1000 # Milliseconds
MA1 = 'ff04::1234:777a:1'
MA2 = 'ff05::1234:777a:2'
MA3 = 'ff05::1234:777a:3'
MA4 = 'ff05::1234:777a:4'
MA5 = 'ff05::1234:777a:5'
BBR_REGISTRATION_JITTER = 1
WAIT_REDUNDANCE = 3
class TestMlr(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
# Topology:
# --------(eth)---------
# | | |
# PBBR---SBBR HOST
# \ / \
# \ / \
# ROUTER--LEADER
# / | \
# / | \
# FED MED SED
#
# More links:
# PBBR---LEADER
#
TOPOLOGY = {
PBBR: {
'name': 'PBBR',
'allowlist': [SBBR, ROUTER, LEADER],
'is_otbr': True,
'version': '1.2',
'router_selection_jitter': 1,
'bbr_registration_jitter': BBR_REGISTRATION_JITTER,
},
SBBR: {
'name': 'SBBR',
'allowlist': [PBBR, ROUTER, LEADER],
'is_otbr': True,
'version': '1.2',
'router_selection_jitter': 1,
'bbr_registration_jitter': BBR_REGISTRATION_JITTER,
},
ROUTER: {
'name': 'ROUTER',
'allowlist': [PBBR, SBBR, LEADER, FED, MED, SED],
'version': '1.2',
'router_selection_jitter': 1,
},
LEADER: {
'name': 'LEADER',
'allowlist': [PBBR, SBBR, ROUTER],
'version': '1.2',
'router_selection_jitter': 1,
},
FED: {
'name': 'FED',
'allowlist': [ROUTER],
'version': '1.2',
'router_upgrade_threshold': 0,
},
MED: {
'name': 'MED',
'allowlist': [ROUTER],
'version': '1.2',
'mode': 'rn',
},
SED: {
'name': 'SED',
'allowlist': [ROUTER],
'version': '1.2',
'mode': 'n'
},
HOST: {
'name': 'Host',
'is_host': True
},
}
def test(self):
# Bring up Host
self.nodes[HOST].start()
# Bring up Leader
self.nodes[LEADER].start()
self.simulator.go(5)
self.assertEqual('leader', self.nodes[LEADER].get_state())
# Bring up Router
self.nodes[ROUTER].start()
self.simulator.go(5)
self.assertEqual('router', self.nodes[ROUTER].get_state())
# Bring up PBBR
self.nodes[PBBR].start()
self.simulator.go(5)
self.assertEqual('router', self.nodes[PBBR].get_state())
self.nodes[PBBR].enable_backbone_router()
self.simulator.go(10)
self.assertTrue(self.nodes[PBBR].is_primary_backbone_router)
self.nodes[PBBR].add_prefix(config.DOMAIN_PREFIX, "parosD")
self.nodes[PBBR].register_netdata()
# Bring up SBBR
self.nodes[SBBR].start()
self.simulator.go(5)
self.assertEqual('router', self.nodes[SBBR].get_state())
self.nodes[SBBR].enable_backbone_router()
self.simulator.go(10)
self.assertFalse(self.nodes[SBBR].is_primary_backbone_router)
# Bring up FED, MED, SED
self.nodes[FED].start()
self.nodes[MED].start()
self.nodes[SED].set_pollperiod(SED_POLL_PERIOD)
self.nodes[SED].start()
self.simulator.go(5)
self.assertEqual('child', self.nodes[FED].get_state())
self.assertEqual('child', self.nodes[MED].get_state())
self.assertEqual('child', self.nodes[SED].get_state())
# Verify Multicast Routing works for all devices
self._verify_multicast_routing(ROUTER, MA1)
self._verify_multicast_routing(LEADER, MA2)
self._verify_multicast_routing(FED, MA3)
self._verify_multicast_routing(MED, MA4, is_med=True)
self._verify_multicast_routing(SED, MA5, is_med=True, is_sed=True)
# Verify MA_scope2 is not reachable from Host
MA_scope2 = 'ff02::10'
self.nodes[ROUTER].add_ipmaddr(MA_scope2)
self.simulator.go(3)
self.assertFalse(self.nodes[HOST].ping(MA_scope2, backbone=True, ttl=10))
self.nodes[ROUTER].del_ipmaddr(MA_scope2)
# Verify MA_scope3 is not reachable from Host
MA_scope3 = 'ff03::1234:777a:5'
self.nodes[ROUTER].add_ipmaddr(MA_scope3)
self.simulator.go(3)
self.assertFalse(self.nodes[HOST].ping(MA_scope3, backbone=True, ttl=10))
self.nodes[ROUTER].del_ipmaddr(MA_scope3)
# Router subscribes MA2 and MA3 at the same time and verify that they are both reachable
self.nodes[ROUTER].add_ipmaddr(MA2)
self.nodes[ROUTER].add_ipmaddr(MA3)
self.simulator.go(3)
self.assertTrue(self.nodes[HOST].ping(MA2, backbone=True, ttl=10))
self.assertTrue(self.nodes[HOST].ping(MA3, backbone=True, ttl=10))
self.nodes[ROUTER].del_ipmaddr(MA2)
self.nodes[ROUTER].del_ipmaddr(MA3)
self.simulator.go(1)
def _verify_multicast_routing(self, nodeid: int, ma: str, is_med=False, is_sed=False):
logging.info('_verify_multicast_routing: nodeid=%d, MA=%s', nodeid, ma)
# Verify MA is not reachable from Host initially
self.assertFalse(self.nodes[HOST].ping(ma, backbone=True, ttl=10))
# Device subscribes MA
self.nodes[nodeid].add_ipmaddr(ma)
self.simulator.go(3 + (SED_POLL_PERIOD * 2 / 1000) * is_sed + config.PARENT_AGGREGATIOIN_DELAY * is_med +
WAIT_REDUNDANCE)
# Verify MA is reachable from Host
self.assertTrue(self.nodes[HOST].ping(ma, backbone=True, ttl=10))
# Device unsubscribes MA
self.nodes[nodeid].del_ipmaddr(ma)
self.simulator.go(1)
# Verify MA is not reachable from Host after unsubscribed
self.assertFalse(self.nodes[HOST].ping(ma, backbone=True, ttl=10))
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,137 @@
#!/usr/bin/env python3
#
# Copyright (c) 2020, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# This test verifies that the MLR timeout configured by Commissioner works for multicast routing.
#
import unittest
from pktverify.consts import NM_COMMISSIONER_SESSION_ID_TLV
from pktverify.packet_verifier import PacketVerifier
from test_mlr_multicast_routing_timeout import ROUTER, HOST
from test_mlr_multicast_routing_timeout import TestMlrTimeout, MLR_TIMEOUT, WAIT_REDUNDANCE, MA1
COMMISSIONER_MLR_TIMEOUT = 360
assert COMMISSIONER_MLR_TIMEOUT > MLR_TIMEOUT + WAIT_REDUNDANCE * 3, "COMMISSIONER_MLR_TIMEOUT should be significantly larger than MLR_TIMEOUT"
class TestMlrCommissionerTimeout(TestMlrTimeout):
# Topology (same as TestMlrTimeout):
# --------(eth)---------
# | |
# PBBR(Leader) HOST
# |
# ROUTER
#
def test(self):
self._bootstrap()
# Ping 1: PBBR should not forward to Thread network
self.assertFalse(self.nodes[HOST].ping(MA1, backbone=True, ttl=10))
# Router starts Commissioner
self.nodes[ROUTER].commissioner_start()
self.simulator.go(10)
self.assertEqual('active', self.nodes[ROUTER].commissioner_state())
# Router (Commissioner) registers MA1
self.nodes[ROUTER].register_multicast_listener(MA1, timeout=COMMISSIONER_MLR_TIMEOUT)
self.simulator.go(WAIT_REDUNDANCE)
# Ping 2: PBBR should forward to Thread network
self.assertFalse(self.nodes[HOST].ping(MA1, backbone=True, ttl=10))
self.simulator.go(MLR_TIMEOUT + WAIT_REDUNDANCE)
# Ping 3: PBBR should forward to Thread network
self.assertFalse(self.nodes[HOST].ping(MA1, backbone=True, ttl=10))
self.simulator.go(COMMISSIONER_MLR_TIMEOUT - MLR_TIMEOUT)
# Ping 4: PBBR should NOT forward to Thread network
self.assertFalse(self.nodes[HOST].ping(MA1, backbone=True, ttl=10))
def verify(self, pv: PacketVerifier):
pkts = pv.pkts
pv.add_common_vars()
pv.summary.show()
ROUTER = pv.vars['ROUTER']
PBBR = pv.vars['PBBR']
MM = pv.vars['MM_PORT']
HOST_ETH = pv.vars['Host_ETH']
HOST_BGUA = pv.vars['Host_BGUA']
start = pkts.index
# Verify that Router sends MLR.req for MA1 with Commissioner timeout
pkts.filter_wpan_src64(ROUTER).filter_coap_request('/n/mr', port=MM).must_next().must_verify(
"""
thread_meshcop.tlv.ipv6_addr == {ipv6_addr}
and thread_nm.tlv.timeout == {timeout}
and {NM_COMMISSIONER_SESSION_ID_TLV} in thread_nm.tlv.type
""",
ipv6_addr=[MA1],
timeout=COMMISSIONER_MLR_TIMEOUT,
NM_COMMISSIONER_SESSION_ID_TLV=NM_COMMISSIONER_SESSION_ID_TLV)
mr_index = pkts.index
# Ping 1: Host pings Router before MLR.reg
before_mr_pkts = pkts.range(start, mr_index, cascade=False)
ping1 = before_mr_pkts.filter_eth_src(HOST_ETH).filter_ipv6_dst(MA1).filter_ping_request().must_next()
# PBBR should not forward Ping 1 to Thread network
before_mr_pkts.filter_wpan_src64(PBBR).filter_ipv6_dst(MA1).filter_ping_request(
identifier=ping1.icmpv6.echo.identifier).must_not_next()
# Ping 2: Host pings Router after MLR.req
ping2 = pkts.filter_eth_src(HOST_ETH).filter_ipv6_dst(MA1).filter_ping_request().must_next()
# PBBR should forward this ping request to Thread network
pkts.filter_wpan_src64(PBBR).filter_AMPLFMA().filter_ping_request(
identifier=ping2.icmpv6.echo.identifier).must_next()
# Ping 3: Host pings Router after delayed MLR Timeout
ping3 = pkts.filter_eth_src(HOST_ETH).filter_ipv6_dst(MA1).filter_ping_request().must_next()
# PBBR should forward this ping request to Thread network because MA doesn't expire yet
pkts.filter_wpan_src64(PBBR).filter_AMPLFMA().filter_ping_request(
identifier=ping3.icmpv6.echo.identifier).must_next()
# Ping 4: Host pings Router after delayed Commissioner MLR Timeout
ping4 = pkts.filter_eth_src(HOST_ETH).filter_ipv6_dst(MA1).filter_ping_request().must_next()
# PBBR should NOT forward this ping request to Thread network because MLR has timeout
pkts.filter_wpan_src64(PBBR).filter_AMPLFMA().filter_ping_request(
identifier=ping4.icmpv6.echo.identifier).must_not_next()
del TestMlrTimeout
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,182 @@
#!/usr/bin/env python3
#
# Copyright (c) 2020, The OpenThread Authors.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# This test verifies that the MLR timeout works for multicast routing.
#
import unittest
import config
import thread_cert
from pktverify.packet_verifier import PacketVerifier
PBBR = 1
ROUTER = 2
HOST = 3
MA1 = 'ff05::1234:777a:1'
BBR_REGISTRATION_JITTER = 1
REG_DELAY = 10
MLR_TIMEOUT = 300
WAIT_REDUNDANCE = 3
class TestMlrTimeout(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
# Topology:
# --------(eth)---------
# | |
# PBBR(Leader) HOST
# |
# ROUTER
#
TOPOLOGY = {
PBBR: {
'name': 'PBBR',
'allowlist': [ROUTER],
'is_otbr': True,
'version': '1.2',
'router_selection_jitter': 1,
'bbr_registration_jitter': BBR_REGISTRATION_JITTER,
},
ROUTER: {
'name': 'ROUTER',
'allowlist': [PBBR],
'version': '1.2',
'router_selection_jitter': 1,
},
HOST: {
'name': 'Host',
'is_host': True
},
}
def _bootstrap(self):
# Bring up Host
self.nodes[HOST].start()
# Bring up PBBR
self.nodes[PBBR].start()
self.simulator.go(5)
self.assertEqual('leader', self.nodes[PBBR].get_state())
self.nodes[PBBR].enable_backbone_router()
self.nodes[PBBR].set_backbone_router(reg_delay=REG_DELAY, mlr_timeout=MLR_TIMEOUT)
self.simulator.go(10)
self.assertTrue(self.nodes[PBBR].is_primary_backbone_router)
self.nodes[PBBR].add_prefix(config.DOMAIN_PREFIX, "parosD")
self.nodes[PBBR].register_netdata()
# Bring up Router
self.nodes[ROUTER].start()
self.simulator.go(5)
self.assertEqual('router', self.nodes[ROUTER].get_state())
self.collect_ipaddrs()
def test(self):
self._bootstrap()
self.assertFalse(self.nodes[HOST].ping(MA1, backbone=True, ttl=10))
# Router subscribes MA
self.nodes[ROUTER].add_ipmaddr(MA1)
self.simulator.go(WAIT_REDUNDANCE)
# Verify MA is reachable from Host
self.assertTrue(self.nodes[HOST].ping(MA1, backbone=True, ttl=10))
self.simulator.go(WAIT_REDUNDANCE)
# Router unsubscribes MA
self.nodes[ROUTER].del_ipmaddr(MA1)
self.simulator.go(WAIT_REDUNDANCE)
# Verify MA is not reachable from Host after unsubscribed
# But PBBR should still forward the Ping Requests to Thread network
self.assertFalse(self.nodes[HOST].ping(MA1, backbone=True, ttl=10))
self.simulator.go(MLR_TIMEOUT + WAIT_REDUNDANCE)
# Verify MA is not reachable from Host after MLR timeout
# PBBR should not forward the Ping Requests to Thread network
self.assertFalse(self.nodes[HOST].ping(MA1, backbone=True, ttl=10))
def verify(self, pv: PacketVerifier):
pkts = pv.pkts
pv.add_common_vars()
pv.summary.show()
ROUTER = pv.vars['ROUTER']
PBBR = pv.vars['PBBR']
MM = pv.vars['MM_PORT']
HOST_ETH = pv.vars['Host_ETH']
HOST_BGUA = pv.vars['Host_BGUA']
start = pkts.index
# Verify that Router sends MLR.req for MA1
pkts.filter_wpan_src64(ROUTER).filter_coap_request('/n/mr', port=MM).must_next().must_verify(
'thread_meshcop.tlv.ipv6_addr == {ipv6_addr}', ipv6_addr=[MA1])
mr_index = pkts.index
# Host pings Router before MLR.reg
before_mr_pkts = pkts.range(start, mr_index, cascade=False)
ping = before_mr_pkts.filter_eth_src(HOST_ETH).filter_ipv6_dst(MA1).filter_ping_request().must_next()
# PBBR should not forward this ping request to Thread network
before_mr_pkts.filter_wpan_src64(PBBR).filter_ipv6_dst(MA1).filter_ping_request(
identifier=ping.icmpv6.echo.identifier).must_not_next()
# Host pings Router after MLR.req
ping = pkts.filter_eth_src(HOST_ETH).filter_ipv6_dst(MA1).filter_ping_request().must_next()
# PBBR should forward this ping request to Thread network
pkts.filter_wpan_src64(PBBR).filter_AMPLFMA().filter_ping_request(
identifier=ping.icmpv6.echo.identifier).must_next()
# Router should reply
pkts.filter_wpan_src64(ROUTER).filter_ipv6_dst(HOST_BGUA).filter_ping_reply(
identifier=ping.icmpv6.echo.identifier).must_next()
# Host pings Router after Router unsubscribed MA
ping = pkts.filter_eth_src(HOST_ETH).filter_ipv6_dst(MA1).filter_ping_request().must_next()
# PBBR should forward this ping request to Thread network because MA doesn't expire yet
pkts.filter_wpan_src64(PBBR).filter_AMPLFMA().filter_ping_request(
identifier=ping.icmpv6.echo.identifier).must_next()
# Router should NOT reply because it has unsubcribed the multicast address
pkts.filter_wpan_src64(ROUTER).filter_ipv6_dst(HOST_BGUA).filter_ping_reply(
identifier=ping.icmpv6.echo.identifier).must_not_next()
# Host pings Router after MLR timeout
ping = pkts.filter_eth_src(HOST_ETH).filter_ipv6_dst(MA1).filter_ping_request().must_next()
# PBBR should NOT forward this ping request to Thread network because MLR has timeout
pkts.filter_wpan_src64(PBBR).filter_AMPLFMA().filter_ping_request(
identifier=ping.icmpv6.echo.identifier).must_not_next()
if __name__ == '__main__':
unittest.main()
-1
View File
@@ -71,7 +71,6 @@ BACKBONE_IFNAME = 'eth0'
OTBR_DOCKER_IMAGE = os.getenv('OTBR_DOCKER_IMAGE', 'otbr-ot12-backbone-ci')
OTBR_DOCKER_NAME_PREFIX = f'otbr_{PORT_OFFSET}_'
OTBR_COMMIT = os.getenv('OTBR_COMMIT', 'master')
ALL_NETWORK_BBRS_ADDRESS = 'ff32:40:fd00:db8:0:0:0:3'
+5 -1
View File
@@ -1956,11 +1956,14 @@ class LinuxHost():
assert False, output
def ping_ether(self, ipaddr, num_responses=1, size=None, timeout=5) -> int:
def ping_ether(self, ipaddr, num_responses=1, size=None, timeout=5, ttl=None) -> int:
cmd = f'ping -6 {ipaddr} -I eth0 -c {num_responses} -W {timeout}'
if size is not None:
cmd += f' -s {size}'
if ttl is not None:
cmd += f' -t {ttl}'
resp_count = 0
try:
@@ -1990,6 +1993,7 @@ class LinuxHost():
class OtbrNode(LinuxHost, NodeImpl, OtbrDocker):
is_otbr = True
is_bbr = True # OTBR is also BBR
node_type = 'otbr-docker'
def __repr__(self):
return f'Otbr<{self.nodeid}>'
@@ -136,6 +136,7 @@ NL_ROUTER_MASK_TLV = 7
NL_ND_OPTION_TLV = 8
NL_ND_DATA_TLV = 9
NL_THREAD_NETWORK_DATA_TLV = 10
NM_COMMISSIONER_SESSION_ID_TLV = 15
# Network Layer Status
NL_SUCESS = 0
@@ -128,6 +128,7 @@ class Packet(object):
def must_verify(self, func: Union[str, Callable], **vars):
if not self.verify(func, **vars):
self.debug_fields()
raise errors.VerifyFailed(self)
def must_not_verify(self, func: Union[str, Callable], **vars):
@@ -436,8 +436,10 @@ class PacketFilter(object):
assert isinstance(addr, (str, ExtAddr)), addr
return self.filter(lambda p: p.wpan.dst64 == addr, **kwargs)
def filter_ping_request(self, **kwargs):
return self.filter(lambda p: p.icmpv6.is_ping_request, **kwargs)
def filter_ping_request(self, identifier=None, **kwargs):
return self.filter(
lambda p: p.icmpv6.is_ping_request and (identifier is None or p.icmpv6.echo.identifier == identifier),
**kwargs)
def filter_ping_reply(self, **kwargs):
identifier = kwargs.pop('identifier', None)
@@ -475,6 +477,9 @@ class PacketFilter(object):
def filter_LLARMA(self, **kwargs):
return self.filter(lambda p: p.ipv6.dst == consts.LINK_LOCAL_ALL_ROUTERS_MULTICAST_ADDRESS, **kwargs)
def filter_AMPLFMA(self, **kwargs):
return self.filter(lambda p: p.ipv6.dst == consts.ALL_MPL_FORWARDERS_MA, **kwargs)
def filter_mle(self, **kwargs):
return self.filter(attrgetter('mle'), **kwargs)
+1 -1
View File
@@ -36,7 +36,7 @@ from collections import Counter
import config
MULTIPLE_JOBS = 10
MULTIPLE_JOBS = 20
logging.basicConfig(level=logging.DEBUG,
format='File "%(pathname)s", line %(lineno)d, in %(funcName)s\n'
+3 -1
View File
@@ -208,6 +208,9 @@ class TestCase(NcpSupportMixin, unittest.TestCase):
if 'max_children' in params:
self.nodes[i].set_max_children(params['max_children'])
if 'bbr_registration_jitter' in params:
self.nodes[i].set_bbr_registration_jitter(params['bbr_registration_jitter'])
# we have to add allowlist after nodes are all created
for i, params in initial_topology.items():
allowlist = params['allowlist']
@@ -364,7 +367,6 @@ class TestCase(NcpSupportMixin, unittest.TestCase):
'interface': config.BACKBONE_DOCKER_NETWORK_NAME,
'prefix': config.BACKBONE_PREFIX,
},
'otbr_commit': config.OTBR_COMMIT,
'domain_prefix': config.DOMAIN_PREFIX,
'env': {
'PORT_OFFSET': config.PORT_OFFSET,