1#!/usr/bin/env python3 2# 3# Copyright (c) 2020, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import ipaddress 31import logging 32import time 33import unittest 34from typing import Union, List 35 36import config 37import network_layer 38import thread_cert 39 40logging.basicConfig(level=logging.DEBUG) 41 42_, BBR_1, BBR_2, ROUTER_1_2, ROUTER_1_1, SED_1, MED_1, MED_2, FED_1 = range(9) 43 44WAIT_ATTACH = 5 45WAIT_REDUNDANCE = 3 46ROUTER_SELECTION_JITTER = 1 47BBR_REGISTRATION_JITTER = 5 48SED_POLL_PERIOD = 1000 # 1s 49 50REREG_DELAY = 10 51MLR_TIMEOUT = 300 52PARENT_AGGREGATE_DELAY = 5 53 54MA1 = 'ff04::1234:777a:1' 55MA1g = 'ff0e::1234:777a:1' 56MA2 = 'ff05::1234:777a:2' 57MA3 = 'ff0e::1234:777a:3' 58MA4 = 'ff05::1234:777a:4' 59 60MA5 = 'ff03::1234:777a:5' 61MA6 = 'ff02::10' 62""" 63 Initial topology: 64 65 BBR_1---BBR_2 66 | / \ | 67 | / \ | 68 ROUTER_1_2 ROUTER_1_1 69 | | \____ | 70 | | \ | 71 SED_1 MED_1/2 FED_1 72""" 73 74 75class TestMulticastListenerRegistration(thread_cert.TestCase): 76 TOPOLOGY = { 77 BBR_1: { 78 'version': '1.2', 79 'allowlist': [BBR_2, ROUTER_1_2], 80 'is_bbr': True, 81 }, 82 BBR_2: { 83 'version': '1.2', 84 'allowlist': [BBR_1, ROUTER_1_2, ROUTER_1_1], 85 'is_bbr': True, 86 }, 87 ROUTER_1_2: { 88 'version': '1.2', 89 'allowlist': [BBR_1, BBR_2, SED_1, MED_1, MED_2, FED_1], 90 }, 91 ROUTER_1_1: { 92 'version': '1.1', 93 'allowlist': [BBR_2], 94 }, 95 MED_1: { 96 'mode': 'rn', 97 'version': '1.2', 98 'allowlist': [ROUTER_1_2], 99 'timeout': config.DEFAULT_CHILD_TIMEOUT, 100 }, 101 MED_2: { 102 'mode': 'rn', 103 'version': '1.2', 104 'allowlist': [ROUTER_1_2], 105 'timeout': config.DEFAULT_CHILD_TIMEOUT, 106 }, 107 SED_1: { 108 'mode': 'n', 109 'version': '1.2', 110 'allowlist': [ROUTER_1_2], 111 'timeout': config.DEFAULT_CHILD_TIMEOUT, 112 }, 113 FED_1: { 114 'mode': 'rdn', 115 'version': '1.2', 116 'allowlist': [ROUTER_1_2], 117 'router_eligible': False, 118 'timeout': config.DEFAULT_CHILD_TIMEOUT, 119 }, 120 } 121 """All nodes are created with default configurations""" 122 123 def _bootstrap(self, bbr_1_enable_backbone_router=True, turn_on_bbr_2=True, turn_on_router_1_1=True): 124 assert (turn_on_bbr_2 or not turn_on_router_1_1) # ROUTER_1_1 needs BBR_2 125 126 # starting context id 127 t0 = time.time() 128 context_id = 1 129 130 # Bring up BBR_1, BBR_1 becomes Leader and Primary Backbone Router 131 self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 132 self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) 133 134 self.nodes[BBR_1].set_backbone_router(seqno=1, reg_delay=REREG_DELAY, mlr_timeout=MLR_TIMEOUT) 135 self.nodes[BBR_1].start() 136 WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER 137 self.simulator.go(WAIT_TIME * 2) 138 self.assertEqual(self.nodes[BBR_1].get_state(), 'leader') 139 140 if bbr_1_enable_backbone_router: 141 self.nodes[BBR_1].enable_backbone_router() 142 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 143 self.simulator.go(WAIT_TIME) 144 self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') 145 146 self.pbbr_seq = 1 147 self.pbbr_id = BBR_1 148 149 if turn_on_bbr_2: 150 # Bring up BBR_2, BBR_2 becomes Router and Secondary Backbone Router 151 self.nodes[BBR_2].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 152 self.nodes[BBR_2].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) 153 self.nodes[BBR_2].set_backbone_router(seqno=2, reg_delay=REREG_DELAY, mlr_timeout=MLR_TIMEOUT) 154 self.nodes[BBR_2].start() 155 WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER 156 self.simulator.go(WAIT_TIME) 157 self.assertEqual(self.nodes[BBR_2].get_state(), 'router') 158 self.nodes[BBR_2].enable_backbone_router() 159 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 160 self.simulator.go(WAIT_TIME) 161 self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Secondary') 162 163 self.simulator.set_lowpan_context(context_id, config.DOMAIN_PREFIX) 164 domain_prefix_cid = context_id 165 166 # Bring up ROUTER_1_2 167 self.nodes[ROUTER_1_2].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 168 self.nodes[ROUTER_1_2].start() 169 WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER 170 self.simulator.go(WAIT_TIME) 171 self.assertEqual(self.nodes[ROUTER_1_2].get_state(), 'router') 172 173 if turn_on_router_1_1: 174 # Bring up ROUTER_1_1 175 self.nodes[ROUTER_1_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 176 self.nodes[ROUTER_1_1].start() 177 WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER 178 self.simulator.go(WAIT_TIME) 179 self.assertEqual(self.nodes[ROUTER_1_1].get_state(), 'router') 180 181 # Bring up FED_1 182 self.nodes[FED_1].start() 183 self.simulator.go(WAIT_ATTACH) 184 self.assertEqual(self.nodes[FED_1].get_state(), 'child') 185 186 # Bring up MED_1 187 self.nodes[MED_1].start() 188 self.simulator.go(WAIT_ATTACH) 189 self.assertEqual(self.nodes[MED_1].get_state(), 'child') 190 191 # Bring up MED_2 192 self.nodes[MED_2].start() 193 self.simulator.go(WAIT_ATTACH) 194 self.assertEqual(self.nodes[MED_2].get_state(), 'child') 195 196 # Bring up SED_1 197 self.nodes[SED_1].set_pollperiod(SED_POLL_PERIOD) 198 self.nodes[SED_1].start() 199 self.simulator.go(WAIT_ATTACH) 200 self.assertEqual(self.nodes[SED_1].get_state(), 'child') 201 202 logging.info("bootstrap takes %f seconds", time.time() - t0) 203 204 def test(self): 205 self._bootstrap() 206 207 # Verify MLR.req for each device when parent is 1.2 208 self.__check_mlr_ok(ROUTER_1_2, is_ftd=True) 209 self.__check_mlr_ok(FED_1, is_ftd=True) 210 self.__check_mlr_ok(MED_1, is_ftd=False) 211 self.__check_mlr_ok(SED_1, is_ftd=False) 212 213 # Switch to parent 1.1 214 self.__switch_to_1_1_parent() 215 216 # Verify MLR.req for each device when parent is 1.1 217 self.__check_mlr_ok(FED_1, is_ftd=True, is_parent_1p1=True) 218 self.__check_mlr_ok(MED_1, is_ftd=False, is_parent_1p1=True) 219 self.__check_mlr_ok(SED_1, is_ftd=False, is_parent_1p1=True) 220 221 # Switch to parent 1.2 222 self.__switch_to_1_2_parent() 223 224 def testParentMergeMedMlrReq(self): 225 self._bootstrap() 226 227 # Make sure Parent registers multiple MAs of MED Children in one MLR.req 228 self.__check_parent_merge_med_mlr_req([MED_1, MED_2], ROUTER_1_2) 229 230 def testNotSendMlrReqIfSubscribed(self): 231 self._bootstrap() 232 233 # Make sure Parent does not send MLR.req of Child if it's already subscribed by Netif or other Children 234 self.__check_not_send_mlr_req_if_subscribed([MED_1, MED_2], ROUTER_1_2) 235 236 def testIpmaddrAddBeforeBBREnable(self): 237 self._bootstrap(bbr_1_enable_backbone_router=False, turn_on_bbr_2=False, turn_on_router_1_1=False) 238 239 self.flush_all() 240 241 # Subscribing to MAs when there is no PBBR should not send MLR.req 242 self.nodes[ROUTER_1_2].add_ipmaddr("ff04::1") 243 self.nodes[FED_1].add_ipmaddr("ff04::2") 244 self.nodes[MED_1].add_ipmaddr("ff04::3") 245 self.nodes[SED_1].add_ipmaddr("ff04::4") 246 247 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 248 router_reg = ["ff04::1", "ff04::2", "ff04::3", "ff04::4"] 249 self.__check_send_mlr_req(ROUTER_1_2, router_reg, should_send=False) 250 251 self.flush_all() 252 253 # Turn on PBBR 254 self.nodes[BBR_1].enable_backbone_router() 255 256 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 257 self.simulator.go(WAIT_TIME) 258 self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') 259 260 self.simulator.go(REREG_DELAY) 261 # Expect MLR.req sent by ROUTER_1_2 and FED_1 262 self.__check_send_mlr_req(ROUTER_1_2, router_reg, should_send=True, expect_mlr_rsp=True) 263 264 def testMulticastListenersTableAdd(self): 265 self._bootstrap() 266 self.__test_multicast_listeners_table_add() 267 268 def testMulticastListenersTableExpire(self): 269 self._bootstrap() 270 self.__test_multicast_listeners_table_expire() 271 272 def testMulticastListenersTableFull(self): 273 self._bootstrap() 274 self.__test_multicast_listeners_table_full() 275 276 def testMulticastListenersTableTwoFreeSlot(self): 277 self._bootstrap() 278 self.__test_multicast_listeners_table_two_free_slots() 279 280 def testMulticastListenerTableAPI(self): 281 self._bootstrap() 282 self.__test_multicast_listeners_table_api() 283 284 def testMlrConfigResponse(self): 285 self._bootstrap() 286 self.__test_mlr_config_response() 287 288 def __test_mlr_config_response(self): 289 bbr = self.nodes[BBR_1] 290 router = self.nodes[ROUTER_1_2] 291 292 self.flush_all() 293 294 # Configure next response to 0 295 bbr.set_next_mlr_response(0) 296 router.add_ipmaddr("ff04::1") 297 self.simulator.go(WAIT_REDUNDANCE) 298 self.__check_send_mlr_req(ROUTER_1_2, ["ff04::1"], 299 should_send=True, 300 expect_mlr_rsp=True, 301 expect_mlr_rsp_status=0) 302 self.assertNotIn(ipaddress.IPv6Address("ff04::1"), bbr.multicast_listener_list()) 303 304 router.del_ipmaddr("ff04::1") 305 self.simulator.go(WAIT_REDUNDANCE) 306 self.flush_all() 307 308 # Configure next response to 2 309 bbr.set_next_mlr_response(2) 310 router.add_ipmaddr("ff04::2") 311 self.simulator.go(WAIT_REDUNDANCE) 312 self.__check_send_mlr_req(ROUTER_1_2, ["ff04::2"], 313 should_send=True, 314 expect_mlr_rsp=True, 315 expect_mlr_rsp_status=2) 316 317 router.del_ipmaddr("ff04::2") 318 self.simulator.go(WAIT_REDUNDANCE) 319 self.flush_all() 320 321 # Configure next response to 4 322 bbr.set_next_mlr_response(4) 323 router.add_ipmaddr("ff04::4") 324 self.simulator.go(WAIT_REDUNDANCE) 325 self.__check_send_mlr_req(ROUTER_1_2, ["ff04::4"], 326 should_send=True, 327 expect_mlr_rsp=True, 328 expect_mlr_rsp_status=4) 329 330 # The MA should be eventually registered after reregistration 331 self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE) 332 self.assertIn(ipaddress.IPv6Address("ff04::4"), bbr.multicast_listener_list()) 333 334 router.del_ipmaddr("ff04::4") 335 self.simulator.go(WAIT_REDUNDANCE) 336 self.flush_all() 337 338 def testCommissionerRegisterMulticastListeners(self): 339 self._bootstrap() 340 341 # Use ROUTER_1_2 as the Commissioner 342 commissioiner = self.nodes[ROUTER_1_2] 343 344 self.assertEqual((0, []), commissioiner.register_multicast_listener("ff04::1")) 345 346 commissioiner.commissioner_start() 347 self.simulator.go(10) 348 349 # Now the Commissioner should be able to register MAs 350 for ip in ["ff04::1", "ff04::2"]: 351 status, failed_ips = commissioiner.register_multicast_listener(ip) 352 self.assertTrue(status == 0 and not failed_ips) 353 self.__check_multicast_listener(ip, expect_mlr_timeout_range=[290, 300]) 354 355 # Register existing MA with a new timeout should be able to update the timeout 356 for ip in ["ff04::1", "ff04::2"]: 357 status, failed_ips = commissioiner.register_multicast_listener(ip, timeout=1000) 358 self.assertTrue(status == 0 and not failed_ips) 359 self.__check_multicast_listener(ip, expect_mlr_timeout_range=[990, 1000]) 360 361 # Register MAs with given timeouts 362 for ip, timeout in [("ff05::1", 400), ("ff05::2", 500), ("ff05::3", 600)]: 363 status, failed_ips = commissioiner.register_multicast_listener(ip, timeout=timeout) 364 self.assertTrue(status == 0 and not failed_ips) 365 self.__check_multicast_listener(ip, expect_mlr_timeout_range=[timeout - 10, timeout]) 366 367 # Register multiple MAs with one call 368 ips = ["ff05::4", "ff05::5", "ff05::6"] 369 status, failed_ips = commissioiner.register_multicast_listener(*ips, timeout=700) 370 self.assertTrue(status == 0 and not failed_ips) 371 for ip in ips: 372 self.__check_multicast_listener(ip, expect_mlr_timeout_range=[690, 700]) 373 374 # Register multiple MAs with one call (without timeout) 375 ips = ["ff05::7", "ff05::8", "ff05::9"] 376 status, failed_ips = commissioiner.register_multicast_listener(*ips) 377 self.assertTrue(status == 0 and not failed_ips) 378 for ip in ips: 379 self.__check_multicast_listener(ip, expect_mlr_timeout_range=[290, 300]) 380 381 # Unregister MAs using timeout=0 382 for ip in ["ff05::1", "ff05::2", "ff05::3"]: 383 status, failed_ips = commissioiner.register_multicast_listener(ip, timeout=0) 384 self.assertTrue(status == 0 and not failed_ips) 385 self.__check_multicast_listener(ip, expect_not_present=True) 386 387 # Unregister multiple MAs 388 ips = ["ff05::4", "ff05::5", "ff05::6"] 389 status, failed_ips = commissioiner.register_multicast_listener(*ips, timeout=0) 390 self.assertTrue(status == 0 and not failed_ips) 391 self.__check_multicast_listener(ip, expect_not_present=True) 392 393 # Remove MAs that are not subscribed should not fail 394 ips = ["ff06::1", "ff02::1", "2001::1"] 395 status, failed_ips = commissioiner.register_multicast_listener(*ips, timeout=0) 396 self.assertTrue(status == 0 and not failed_ips) 397 self.__check_multicast_listener(ip, expect_not_present=True) 398 399 # Register invalid MAs should fail 400 for ip in ["ff02::1", "ff03::1", "2001::1"]: 401 status, failed_ips = commissioiner.register_multicast_listener(ip) 402 self.assertEqual(status, 2) 403 self.assertEqual(set(failed_ips), {ipaddress.IPv6Address(ip)}) 404 self.__check_multicast_listener(ip, expect_not_present=True) 405 406 # Register valid MAs with invalid MAs should succeed partially 407 ips = ["ff05::1", "ff05::2", "ff02::1", "2001::1"] 408 status, failed_ips = commissioiner.register_multicast_listener(*ips) 409 self.assertEqual(status, 2) 410 self.assertEqual(set(failed_ips), {ipaddress.IPv6Address("ff02::1"), ipaddress.IPv6Address("2001::1")}) 411 self.__check_multicast_listener("ff05::1") 412 self.__check_multicast_listener("ff05::2") 413 self.__check_multicast_listener("ff02::1", expect_not_present=True) 414 self.__check_multicast_listener("2001::1", expect_not_present=True) 415 416 # Registering persistent MAs should fail for now 417 status, failed_ips = commissioiner.register_multicast_listener("ff06::1", timeout=0xffffffff) 418 self.assertEqual(status, 3) 419 # "ff06::1" should not be included in failed IPs because all IPs failed 420 self.assertTrue(not failed_ips == 0) 421 422 def __check_multicast_listener(self, *addrs, expect_mlr_timeout_range=None, expect_not_present=False): 423 addrs = map(ipaddress.IPv6Address, addrs) 424 listeners = self.nodes[BBR_1].multicast_listener_list() 425 logging.info("__check_multicast_listener get listeners: %s", listeners) 426 427 for addr in addrs: 428 if not expect_not_present: 429 self.assertIn(addr, listeners) 430 if expect_mlr_timeout_range is not None: 431 self.assertGreaterEqual(listeners[addr], expect_mlr_timeout_range[0]) 432 self.assertLessEqual(listeners[addr], expect_mlr_timeout_range[1]) 433 else: 434 self.assertNotIn(addr, listeners) 435 436 def __test_multicast_listeners_table_api(self): 437 self.assertTrue(self.nodes[BBR_1].multicast_listener_list() == {}) 438 439 self.nodes[BBR_1].multicast_listener_add("ff04::1") 440 self.assertEqual(1, len(self.nodes[BBR_1].multicast_listener_list())) 441 self.nodes[BBR_1].multicast_listener_add("ff04::2", 300) 442 self.assertEqual(2, len(self.nodes[BBR_1].multicast_listener_list())) 443 self.nodes[BBR_1].multicast_listener_clear() 444 self.assertTrue(self.nodes[BBR_1].multicast_listener_list() == {}) 445 446 def __test_multicast_listeners_table_add(self): 447 self.assertTrue(self.nodes[BBR_1].multicast_listener_list() == {}) 448 449 all_mas = set() 450 451 CHECK_LIST = [(ROUTER_1_2, "ff04::1"), (FED_1, "ff04::2"), (MED_1, "ff04::3"), (SED_1, "ff04::4")] 452 453 for id, ip in CHECK_LIST: 454 self.nodes[id].add_ipmaddr(ip) 455 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 456 all_mas.add(ipaddress.IPv6Address(ip)) 457 self.assertEqual(all_mas, set(self.nodes[BBR_1].multicast_listener_list().keys())) 458 459 # restore 460 for id, ip in CHECK_LIST: 461 self.nodes[id].del_ipmaddr(ip) 462 463 self.simulator.go(WAIT_REDUNDANCE) 464 465 def __test_multicast_listeners_table_expire(self): 466 self.assertEqual({}, self.nodes[BBR_1].multicast_listener_list()) 467 468 all_mas = set() 469 470 CHECK_LIST = [(ROUTER_1_2, "ff04::1"), (FED_1, "ff04::2"), (MED_1, "ff04::3"), (SED_1, "ff04::4")] 471 472 for id, ip in CHECK_LIST: 473 self.nodes[id].add_ipmaddr(ip) 474 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 475 all_mas.add(ipaddress.IPv6Address(ip)) 476 self.assertEqual(all_mas, set(self.nodes[BBR_1].multicast_listener_list().keys())) 477 478 # remove MAs from nodes, and wait for Multicast Listeners to expire on BBR_1 479 for id, ip in CHECK_LIST: 480 self.nodes[id].del_ipmaddr(ip) 481 482 # Wait for MLR_TIMEOUT/3, and expect Multicast Listeners not to expire. 483 self.simulator.go(MLR_TIMEOUT / 3) 484 self.assertEqual(all_mas, set(self.nodes[BBR_1].multicast_listener_list().keys())) 485 486 # Wait for MLR_TIMEOUT*2/3, and expect all Multicast Listeners to expire. 487 self.simulator.go(MLR_TIMEOUT * 2 / 3 + WAIT_REDUNDANCE) 488 self.assertEqual({}, self.nodes[BBR_1].multicast_listener_list()) 489 490 def __test_multicast_listeners_table_full(self): 491 self.assertTrue(self.nodes[BBR_1].multicast_listener_list() == {}) 492 493 table = set() 494 495 # Add to Multicast Listeners Table until it's full 496 for i in range(1, 76): 497 self.nodes[BBR_1].multicast_listener_add(f"ff04::{i}") 498 table.add(ipaddress.IPv6Address(f"ff04::{i}")) 499 self.assertEqual(table, set(self.nodes[BBR_1].multicast_listener_list().keys())) 500 501 # Add when Multicast Listeners Table is full should not succeed 502 self.nodes[BBR_1].multicast_listener_add(f"ff05::1") 503 self.assertEqual(table, set(self.nodes[BBR_1].multicast_listener_list().keys())) 504 505 self.flush_all() 506 507 # Expect PBBR to respond with MLR_NO_RESOURCES Multicast Listeners Table when it's full 508 self.nodes[ROUTER_1_2].add_ipmaddr("ff06::1") 509 self.simulator.go(WAIT_REDUNDANCE) 510 511 self.__check_send_mlr_req(ROUTER_1_2, 512 "ff06::1", 513 should_send=True, 514 expect_mlr_rsp=True, 515 expect_mlr_rsp_status=4) 516 517 self.assertEqual(table, set(self.nodes[BBR_1].multicast_listener_list().keys())) 518 519 self.nodes[MED_1].add_ipmaddr("ff06::2") 520 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 521 522 self.__check_send_mlr_req(ROUTER_1_2, 523 "ff06::2", 524 should_send=True, 525 expect_mlr_rsp=True, 526 expect_mlr_rsp_status=4) 527 528 self.assertEqual(table, set(self.nodes[BBR_1].multicast_listener_list().keys())) 529 530 # the ROUTER_1_2 should be resending both ff06::1 and ff06::2 531 for i in range(3): 532 self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE) 533 self.__check_send_mlr_req(ROUTER_1_2, ['ff06::1', 'ff06::2'], 534 should_send=True, 535 expect_mlr_rsp=True, 536 expect_mlr_rsp_status=4) 537 538 # Restore 539 self.nodes[ROUTER_1_2].del_ipmaddr("ff06::1") 540 self.nodes[MED_1].del_ipmaddr("ff06::2") 541 self.simulator.go(WAIT_REDUNDANCE) 542 543 def __test_multicast_listeners_table_two_free_slots(self): 544 545 # Add to Multicast Listeners Table until there is only two free slots 546 for i in range(1, 74): 547 self.nodes[BBR_1].multicast_listener_add(f"ff04::{i}") 548 549 self.assertEqual(73, len(self.nodes[BBR_1].multicast_listener_list())) 550 551 self.nodes[MED_1].add_ipmaddr("ff05::1") 552 self.nodes[MED_1].add_ipmaddr("ff05::2") 553 self.nodes[MED_2].add_ipmaddr("ff05::3") 554 self.nodes[MED_2].add_ipmaddr("ff05::4") 555 self.nodes[SED_1].add_ipmaddr("ff05::5") 556 self.nodes[SED_1].add_ipmaddr("ff05::6") 557 558 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 559 self.__check_send_mlr_req(ROUTER_1_2, ["ff05::1", "ff05::2", "ff05::3", "ff05::4", "ff05::5", "ff05::6"]) 560 561 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 562 self.flush_all() 563 # two addresses should be registered, others can not 564 for i in range(3): 565 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 566 self.assertEqual(4, len(set(self.__get_registered_MAs(ROUTER_1_2)))) 567 568 # Restore 569 self.nodes[MED_1].del_ipmaddr("ff05::1") 570 self.nodes[MED_1].del_ipmaddr("ff05::2") 571 self.nodes[MED_2].del_ipmaddr("ff05::3") 572 self.nodes[MED_2].del_ipmaddr("ff05::4") 573 self.nodes[SED_1].del_ipmaddr("ff05::5") 574 self.nodes[SED_1].del_ipmaddr("ff05::6") 575 576 def __check_mlr_ok(self, id, is_ftd, is_parent_1p1=False): 577 """Check if MLR works for the node""" 578 # Add MA1 and send MLR.req 579 logging.info("======== checking MLR: Node%d (%s), Parent=%s ========" % 580 (id, 'FTD' if is_ftd else 'MTD', '1.1' if is_parent_1p1 else '1.2')) 581 expect_mlr_req = is_ftd or is_parent_1p1 582 583 if id == ROUTER_1_2: 584 parent_id = None 585 else: 586 parent_id = ROUTER_1_1 if is_parent_1p1 else ROUTER_1_2 587 588 for addr in [MA1, MA1g, MA2, MA3, MA4]: 589 self.__check_ipmaddr_add(id, 590 parent_id, 591 addr, 592 expect_mlr_req=expect_mlr_req, 593 expect_mlr_req_proxied=(not expect_mlr_req)) 594 595 for addr in [MA5, MA6]: 596 self.__check_ipmaddr_add(id, parent_id, addr, expect_mlr_req=False, expect_mlr_req_proxied=False) 597 logging.info('=' * 120) 598 599 def __check_ipmaddr_add(self, id, parent_id, addr, expect_mlr_req=True, expect_mlr_req_proxied=False): 600 """Check MLR works for the added multicast address""" 601 logging.info("Node %d: ipmaddr %s" % (id, addr)) 602 self.flush_all() 603 self.nodes[id].add_ipmaddr(addr) 604 self.assertTrue(self.nodes[id].has_ipmaddr(addr)) 605 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 606 607 self.__check_send_mlr_req(id, addr, should_send=expect_mlr_req, expect_mlr_rsp=expect_mlr_req) 608 # Parent should either forward or proxy the MLR.req 609 if parent_id: 610 self.__check_send_mlr_req(parent_id, 611 addr, 612 should_send=expect_mlr_req or expect_mlr_req_proxied, 613 expect_mlr_rsp=expect_mlr_req_proxied) 614 615 self.__check_rereg(id, 616 parent_id, 617 addr, 618 expect_mlr_req=expect_mlr_req, 619 expect_mlr_req_proxied=expect_mlr_req_proxied) 620 self.__check_renewing(id, 621 parent_id, 622 addr, 623 expect_mlr_req=expect_mlr_req, 624 expect_mlr_req_proxied=expect_mlr_req_proxied) 625 626 self.nodes[id].del_ipmaddr(addr) 627 self.simulator.go(1) 628 629 def __check_send_mlr_req(self, 630 id, 631 addrs: Union[List[str], str], 632 should_send=True, 633 expect_mlr_rsp=False, 634 expect_mlr_rsp_status=0, 635 expect_mlr_req_num=None, 636 expect_unique_reg=False): 637 if isinstance(addrs, str): 638 addrs = [addrs] 639 640 message_ids = [] 641 reg_mas = self.__get_registered_MAs(id, expect_mlr_req_num=expect_mlr_req_num, message_ids=message_ids) 642 if should_send: 643 for addr in addrs: 644 self.assertIn(ipaddress.IPv6Address(addr), reg_mas) 645 if expect_unique_reg: 646 self.assertEqual(1, reg_mas.count(ipaddress.IPv6Address(addr))) 647 648 # BBR should send MLR.rsp ACK 649 if expect_mlr_rsp: 650 message_id = message_ids[0] 651 rsp = self.__expect_MLR_rsp(message_id) 652 653 logging.info('MLR.rsp %s uri_path=%s, payload=%s', rsp, rsp.coap.uri_path, rsp.coap.payload) 654 655 statusTlv = None 656 for tlv in rsp.coap.payload: 657 if isinstance(tlv, network_layer.Status): 658 statusTlv = tlv 659 break 660 661 self.assertIsNotNone(statusTlv) 662 self.assertEqual(expect_mlr_rsp_status, statusTlv.status) 663 664 else: 665 for addr in addrs: 666 self.assertNotIn(ipaddress.IPv6Address(addr), reg_mas) 667 668 def __expect_MLR_rsp(self, message_id): 669 logging.info("Expecting MLR.rsp with message ID = %s", message_id) 670 messages = self.simulator.get_messages_sent_by(self.pbbr_id) 671 logging.info("PBBR %d messages: %s", self.pbbr_id, messages) 672 673 while True: 674 msg = messages.next_coap_message('2.04') 675 logging.info('Check ACK for %s: %s, %s, %s, %s', message_id, msg, msg.coap.message_id, msg.coap.uri_path, 676 msg.coap.payload) 677 if msg.coap.message_id == message_id: 678 return msg 679 680 def __get_registered_MAs(self, id, expect_mlr_req_num=None, message_ids=None): 681 """Get MAs registered via MLR.req by the node""" 682 messages = self.simulator.get_messages_sent_by(id) 683 reg_mas = [] 684 while True: 685 msg = messages.next_coap_message('0.02', '/n/mr', assert_enabled=False) 686 if not msg: 687 break 688 689 logging.info("MLR.req: %s %s" % (msg.coap.message_id, msg.coap.payload)) 690 addrs = msg.get_coap_message_tlv(network_layer.IPv6Addresses) 691 reg_mas.append(addrs) 692 if message_ids is not None: 693 message_ids.append(msg.coap.message_id) 694 695 logging.info('Node %d registered MAs: %s' % (id, reg_mas)) 696 697 if expect_mlr_req_num is not None: 698 self.assertEqual(len(reg_mas), expect_mlr_req_num) 699 700 # expand from [[...], [...], ...] to [...] 701 reg_mas = [ma for mas in reg_mas for ma in mas] 702 703 return reg_mas 704 705 def __check_renewing(self, id, parent_id, addr, expect_mlr_req=True, expect_mlr_req_proxied=False): 706 """Check if MLR works that a node can renew it's registered MAs""" 707 assert self.pbbr_id == BBR_1 708 self.flush_all() 709 self.simulator.go(MLR_TIMEOUT + WAIT_REDUNDANCE) 710 711 self.__check_send_mlr_req(id, addr, should_send=expect_mlr_req, expect_mlr_rsp=expect_mlr_req) 712 # Parent should either forward or proxy the MLR.req 713 if parent_id: 714 self.__check_send_mlr_req(parent_id, 715 addr, 716 should_send=expect_mlr_req or expect_mlr_req_proxied, 717 expect_mlr_rsp=expect_mlr_req_proxied) 718 719 def __check_rereg(self, id, parent_id, addr, expect_mlr_req=True, expect_mlr_req_proxied=False): 720 """Check if MLR works that a node can do MLR reregistration when necessary""" 721 self.__check_rereg_seqno(id, 722 parent_id, 723 addr, 724 expect_mlr_req=expect_mlr_req, 725 expect_mlr_req_proxied=expect_mlr_req_proxied) 726 self.__check_rereg_pbbr_change(id, 727 parent_id, 728 addr, 729 expect_mlr_req=expect_mlr_req, 730 expect_mlr_req_proxied=expect_mlr_req_proxied) 731 732 def __check_rereg_seqno(self, id, parent_id, addr, expect_mlr_req=True, expect_mlr_req_proxied=False): 733 """Check if MLR works that a node can do MLR reregistration when PBBR seqno changes""" 734 # Change seq on PBBR and expect MLR.req within REREG_DELAY 735 self.flush_all() 736 self.pbbr_seq = (self.pbbr_seq + 10) % 256 737 self.nodes[BBR_1].set_backbone_router(seqno=self.pbbr_seq) 738 self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE) 739 740 self.__check_send_mlr_req(id, addr, should_send=expect_mlr_req, expect_mlr_rsp=expect_mlr_req) 741 # Parent should either forward or proxy the MLR.req 742 if parent_id: 743 self.__check_send_mlr_req(parent_id, 744 addr, 745 should_send=expect_mlr_req or expect_mlr_req_proxied, 746 expect_mlr_rsp=expect_mlr_req_proxied) 747 748 def __check_rereg_pbbr_change(self, id, parent_id, addr, expect_mlr_req=True, expect_mlr_req_proxied=False): 749 """Check if MLR works that a node can do MLR reregistration when PBBR changes""" 750 # Make BBR_2 to be Primary and expect MLR.req within REREG_DELAY 751 assert self.pbbr_id == BBR_1 752 753 self.flush_all() 754 self.nodes[BBR_1].disable_backbone_router() 755 self.simulator.go(BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE) 756 self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Primary') 757 self.pbbr_id = BBR_2 758 759 self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE) 760 761 self.__check_send_mlr_req(id, addr, should_send=expect_mlr_req, expect_mlr_rsp=expect_mlr_req) 762 # Parent should either forward or proxy the MLR.req 763 if parent_id: 764 self.__check_send_mlr_req(parent_id, 765 addr, 766 should_send=expect_mlr_req or expect_mlr_req_proxied, 767 expect_mlr_rsp=expect_mlr_req_proxied) 768 769 # Restore BBR_1 to be Primary and BBR_2 to be Secondary 770 self.nodes[BBR_2].disable_backbone_router() 771 self.nodes[BBR_1].enable_backbone_router() 772 self.simulator.go(BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE) 773 self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') 774 self.nodes[BBR_2].enable_backbone_router() 775 self.simulator.go(BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE) 776 self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Secondary') 777 self.pbbr_id = BBR_1 778 779 def __switch_to_1_1_parent(self): 780 """Check if MLR works when nodes are switching to a 1.1 parent""" 781 # Add MA1 to EDs to prepare for parent switching 782 logging.info("=" * 10 + " switching to 1.1 parent " + '=' * 10) 783 784 self.flush_all() 785 786 self.nodes[FED_1].add_ipmaddr(MA1) 787 self.nodes[MED_1].add_ipmaddr(MA1) 788 self.nodes[SED_1].add_ipmaddr(MA1) 789 790 self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE) 791 self.assertIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(FED_1)) 792 self.assertNotIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(MED_1)) 793 self.assertNotIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(SED_1)) 794 795 self.flush_all() 796 797 # Turn off Router 1.2 and turn on Router 1.1 798 self.nodes[ROUTER_1_2].stop() 799 for id in [FED_1, MED_1, SED_1]: 800 self.nodes[ROUTER_1_1].add_allowlist(self.nodes[id].get_addr64()) 801 self.nodes[id].add_allowlist(self.nodes[ROUTER_1_1].get_addr64()) 802 self.simulator.go(config.DEFAULT_CHILD_TIMEOUT + WAIT_REDUNDANCE) 803 804 self.assertEqual(self.nodes[id].get_state(), 'child') 805 self.assertEqual(self.nodes[id].get_router_id(), self.nodes[ROUTER_1_1].get_router_id()) 806 807 self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE) 808 809 # Verify all FED send MLR.req within REREG_DELAY when parent is 1.1 810 self.assertIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(FED_1)) 811 self.assertIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(MED_1)) 812 self.assertIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(SED_1)) 813 814 self.nodes[FED_1].del_ipmaddr(MA1) 815 self.nodes[MED_1].del_ipmaddr(MA1) 816 self.nodes[SED_1].del_ipmaddr(MA1) 817 818 self.simulator.go(WAIT_REDUNDANCE) 819 820 def __switch_to_1_2_parent(self): 821 """Check if MLR works when nodes are switching to a 1.2 parent""" 822 # Add MA1 to EDs to prepare for parent switching 823 logging.info("=" * 10, "switching to 1.2 parent", '=' * 10) 824 825 self.flush_all() 826 827 self.nodes[FED_1].add_ipmaddr(MA1) 828 self.nodes[MED_1].add_ipmaddr(MA1) 829 self.nodes[SED_1].add_ipmaddr(MA1) 830 831 self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE) 832 self.assertIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(FED_1)) 833 self.assertIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(MED_1)) 834 self.assertIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(SED_1)) 835 836 self.flush_all() 837 838 # Turn off Router 1.1 and turn on Router 1.2 839 self.nodes[ROUTER_1_1].stop() 840 self.nodes[ROUTER_1_2].start() 841 for id in [FED_1, MED_1, SED_1]: 842 self.simulator.go(config.DEFAULT_CHILD_TIMEOUT + WAIT_REDUNDANCE) 843 844 self.assertEqual(self.nodes[id].get_state(), 'child') 845 self.assertEqual(self.nodes[id].get_router_id(), self.nodes[ROUTER_1_2].get_router_id()) 846 847 self.simulator.go(REREG_DELAY + WAIT_REDUNDANCE) 848 849 # Verify only FTD sends MLR.req within REREG_DELAY when parent is 1.2 850 self.assertIn(ipaddress.IPv6Address(MA1), self.__get_registered_MAs(FED_1)) 851 852 # MED and SED might still send MLR.req during this period because it could be sending to it's 1.2 parent. 853 854 self.nodes[FED_1].del_ipmaddr(MA1) 855 self.nodes[MED_1].del_ipmaddr(MA1) 856 self.nodes[SED_1].del_ipmaddr(MA1) 857 858 self.simulator.go(WAIT_REDUNDANCE) 859 860 def __check_parent_merge_med_mlr_req(self, meds, parent_id): 861 """Check that the 1.2 parent merge multiple multicast addresses for MED children.""" 862 self.flush_all() 863 for med in meds: 864 self.nodes[med].add_ipmaddr(MA1) 865 866 self.nodes[meds[0]].add_ipmaddr(MA2) 867 self.nodes[meds[1]].add_ipmaddr(MA3) 868 869 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 870 871 self.__check_send_mlr_req(parent_id, [MA1, MA2, MA3], 872 should_send=True, 873 expect_mlr_rsp=True, 874 expect_mlr_req_num=1, 875 expect_unique_reg=True) 876 877 # restore 878 self.nodes[meds[0]].del_ipmaddr(MA2) 879 self.nodes[meds[1]].del_ipmaddr(MA3) 880 for med in meds: 881 self.nodes[med].del_ipmaddr(MA1) 882 883 self.simulator.go(WAIT_REDUNDANCE) 884 885 def __check_not_send_mlr_req_if_subscribed(self, meds, parent_id): 886 """Check that the 1.2 parent does not send MLR.req if the MA is already subscribed.""" 887 # Parent should register MA1 on Netif 888 self.flush_all() 889 self.nodes[parent_id].add_ipmaddr(MA1) 890 self.simulator.go(WAIT_REDUNDANCE) 891 self.__check_send_mlr_req(parent_id, MA1, should_send=True, expect_mlr_rsp=True) 892 893 # Parent should not register MA1 of Child 1 because it's already registerd 894 self.flush_all() 895 self.nodes[meds[0]].add_ipmaddr(MA1) 896 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 897 self.__check_send_mlr_req(parent_id, MA1, should_send=False) 898 899 # Parent should register MA2 of Child 1 because it's new 900 self.flush_all() 901 self.nodes[meds[0]].add_ipmaddr(MA2) 902 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 903 self.__check_send_mlr_req(parent_id, MA2, should_send=True) 904 905 # Parent should not register MA2 of Child 2 because it's already registered for Child 1 906 self.flush_all() 907 self.nodes[meds[1]].add_ipmaddr(MA2) 908 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 909 self.__check_send_mlr_req(parent_id, MA2, should_send=False) 910 911 # Parent should register MA3 of Child 2 because it's new 912 self.flush_all() 913 self.nodes[meds[1]].add_ipmaddr(MA3) 914 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 915 self.__check_send_mlr_req(parent_id, MA3, should_send=True) 916 917 # Parent should not register MA2 and MA3 because they are already registered for Child2 itself 918 self.flush_all() 919 self.nodes[meds[1]].del_ipmaddr(MA2) 920 self.nodes[meds[1]].del_ipmaddr(MA3) 921 self.nodes[meds[1]].add_ipmaddr(MA2) 922 self.nodes[meds[1]].add_ipmaddr(MA3) 923 self.simulator.go(PARENT_AGGREGATE_DELAY + WAIT_REDUNDANCE) 924 self.__check_send_mlr_req(parent_id, [MA2, MA3], should_send=False) 925 926 # Restore 927 self.nodes[parent_id].del_ipmaddr(MA1) 928 self.nodes[meds[0]].del_ipmaddr(MA1) 929 self.nodes[meds[0]].del_ipmaddr(MA2) 930 self.nodes[meds[1]].del_ipmaddr(MA2) 931 self.nodes[meds[1]].del_ipmaddr(MA3) 932 self.simulator.go(WAIT_REDUNDANCE) 933 934 935if __name__ == '__main__': 936 unittest.main() 937