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# 29import logging 30import unittest 31from ipaddress import IPv6Network 32 33import config 34import thread_cert 35 36# Test description: 37# This test verifies that a single OMR and on-link prefix is chosen 38# and advertised when there are multiple Border Routers in the same 39# Thread and infrastructure network. 40# 41# Topology: 42# ----------------(eth)------------------ 43# | | | 44# BR1 (Leader) ----- BR2 HOST 45# | | 46# ROUTER1 ROUTER2 47# 48 49BR1 = 1 50ROUTER1 = 2 51BR2 = 3 52ROUTER2 = 4 53HOST = 5 54 55CHANNEL = 18 56 57 58class MultiBorderRouters(thread_cert.TestCase): 59 USE_MESSAGE_FACTORY = False 60 61 TOPOLOGY = { 62 BR1: { 63 'name': 'BR_1', 64 'allowlist': [ROUTER1, BR2], 65 'is_otbr': True, 66 'version': '1.2', 67 'channel': CHANNEL, 68 }, 69 ROUTER1: { 70 'name': 'Router_1', 71 'allowlist': [BR1], 72 'version': '1.2', 73 'channel': CHANNEL, 74 }, 75 BR2: { 76 'name': 'BR_2', 77 'allowlist': [BR1, ROUTER2], 78 'is_otbr': True, 79 'version': '1.2', 80 'channel': CHANNEL, 81 }, 82 ROUTER2: { 83 'name': 'Router_2', 84 'allowlist': [BR2], 85 'version': '1.2', 86 'channel': CHANNEL, 87 }, 88 HOST: { 89 'name': 'Host', 90 'is_host': True 91 }, 92 } 93 94 def test(self): 95 br1 = self.nodes[BR1] 96 router1 = self.nodes[ROUTER1] 97 br2 = self.nodes[BR2] 98 router2 = self.nodes[ROUTER2] 99 host = self.nodes[HOST] 100 101 host.start(start_radvd=False) 102 self.simulator.go(5) 103 104 br1.start() 105 self.simulator.go(config.LEADER_STARTUP_DELAY) 106 self.assertEqual('leader', br1.get_state()) 107 108 router1.start() 109 self.simulator.go(config.ROUTER_STARTUP_DELAY) 110 self.assertEqual('router', router1.get_state()) 111 112 self.simulator.go(5) 113 114 br2.start() 115 self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY) 116 self.assertEqual('router', br2.get_state()) 117 118 router2.start() 119 self.simulator.go(config.ROUTER_STARTUP_DELAY) 120 self.assertEqual('router', router2.get_state()) 121 122 # 123 # Case 1. bi-directional connectivity when there are two BRs. 124 # 125 126 self.simulator.go(10) 127 self.collect_ipaddrs() 128 129 logging.info("BR1 addrs: %r", br1.get_addrs()) 130 logging.info("ROUTER1 addrs: %r", router1.get_addrs()) 131 logging.info("BR2 addrs: %r", br2.get_addrs()) 132 logging.info("ROUTER2 addrs: %r", router2.get_addrs()) 133 logging.info("HOST addrs: %r", host.get_addrs()) 134 135 self.assertEqual(len(br1.get_netdata_omr_prefixes()), 1) 136 self.assertEqual(len(router1.get_netdata_omr_prefixes()), 1) 137 self.assertEqual(len(br2.get_netdata_omr_prefixes()), 1) 138 self.assertEqual(len(router2.get_netdata_omr_prefixes()), 1) 139 140 br1_omr_prefix = br1.get_br_omr_prefix() 141 self.assertEqual(br1_omr_prefix, br1.get_netdata_omr_prefixes()[0]) 142 143 # Each BR should independently register an external route for the on-link prefix. 144 self.assertEqual(len(br1.get_netdata_non_nat64_routes()), 2) 145 self.assertEqual(len(router1.get_netdata_non_nat64_routes()), 2) 146 self.assertEqual(len(br2.get_netdata_non_nat64_routes()), 2) 147 self.assertEqual(len(router2.get_netdata_non_nat64_routes()), 2) 148 149 br1_on_link_prefix = br1.get_br_on_link_prefix() 150 151 self.assertEqual(len(br1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 152 self.assertEqual(len(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 153 self.assertEqual(len(br2.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 154 self.assertEqual(len(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 155 self.assertEqual(len(host.get_matched_ula_addresses(br1_on_link_prefix)), 1) 156 157 # Router1 and Router2 can ping each other inside the Thread network. 158 self.assertTrue(router1.ping(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0])) 159 self.assertTrue(router2.ping(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0])) 160 161 # Both Router1 and Router2 can ping to/from the Host on infra link. 162 self.assertTrue(router1.ping(host.get_matched_ula_addresses(br1_on_link_prefix)[0])) 163 self.assertTrue(host.ping(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True)) 164 self.assertTrue(router2.ping(host.get_matched_ula_addresses(br1_on_link_prefix)[0])) 165 self.assertTrue(host.ping(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True)) 166 167 # 168 # Case 2. Another BR continues providing Border Routing when current one is disabled. 169 # 170 171 br1.disable_br() 172 173 self.simulator.go(315) 174 self.collect_ipaddrs() 175 176 logging.info("BR1 addrs: %r", br1.get_addrs()) 177 logging.info("ROUTER1 addrs: %r", router1.get_addrs()) 178 logging.info("BR2 addrs: %r", br2.get_addrs()) 179 logging.info("ROUTER2 addrs: %r", router2.get_addrs()) 180 logging.info("HOST addrs: %r", host.get_addrs()) 181 182 self.assertGreaterEqual(len(host.get_addrs()), 3) 183 184 self.assertEqual(len(br1.get_netdata_omr_prefixes()), 1) 185 self.assertEqual(len(router1.get_netdata_omr_prefixes()), 1) 186 self.assertEqual(len(br2.get_netdata_omr_prefixes()), 1) 187 self.assertEqual(len(router2.get_netdata_omr_prefixes()), 1) 188 189 br2_omr_prefix = br2.get_br_omr_prefix() 190 self.assertEqual(br2_omr_prefix, br2.get_netdata_omr_prefixes()[0]) 191 192 # There should be no changes to the external route for the 193 # on-link prefix, given that the on-link prefix is derived 194 # from the Extended PAN ID. 195 self.assertEqual(len(br1.get_netdata_non_nat64_routes()), 1) 196 self.assertEqual(len(router1.get_netdata_non_nat64_routes()), 1) 197 self.assertEqual(len(br2.get_netdata_non_nat64_routes()), 1) 198 self.assertEqual(len(router2.get_netdata_non_nat64_routes()), 1) 199 200 br2_on_link_prefix = br2.get_br_on_link_prefix() 201 202 self.assertEqual(len(br1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 203 self.assertEqual(len(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 204 self.assertEqual(len(br2.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 205 self.assertEqual(len(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)), 1) 206 207 self.assertEqual(len(host.get_matched_ula_addresses(br2_on_link_prefix)), 1) 208 209 # Router1 and Router2 can ping each other inside the Thread network. 210 self.assertTrue(router1.ping(router2.get_ip6_address(config.ADDRESS_TYPE.OMR)[0])) 211 self.assertTrue(router2.ping(router1.get_ip6_address(config.ADDRESS_TYPE.OMR)[0])) 212 213 # Both Router1 and Router2 can ping to/from the Host on infra link. 214 for router in [router1, router2]: 215 self.assertTrue(router.ping(host.get_matched_ula_addresses(br2_on_link_prefix)[0])) 216 self.assertTrue(host.ping(router.get_ip6_address(config.ADDRESS_TYPE.OMR)[0], backbone=True)) 217 218 219if __name__ == '__main__': 220 unittest.main() 221