1#!/usr/bin/env python3 2# 3# Copyright (c) 2022, 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 unittest 32 33import command 34import config 35import thread_cert 36 37# Test description: 38# 39# This test verifies behavior of Border Routers (which provide IP connectivity) requesting router role within Thread 40# mesh. 41 42# Topology: 43# 44# 5 FTD nodes, all connected. 45# 46# Topology is expected to change during execution of test. 47# 48 49LEADER = 1 50ROUTER = 2 51BR1 = 3 52BR2 = 4 53BR3 = 5 54 55 56class BrUpgradeRouterRole(thread_cert.TestCase): 57 USE_MESSAGE_FACTORY = False 58 SUPPORT_NCP = False 59 60 TOPOLOGY = { 61 LEADER: { 62 'name': 'leader', 63 'mode': 'rdn', 64 }, 65 ROUTER: { 66 'name': 'reader', 67 'mode': 'rdn', 68 }, 69 BR1: { 70 'name': 'br-1', 71 'mode': 'rdn', 72 }, 73 BR2: { 74 'name': 'br-2', 75 'mode': 'rdn', 76 }, 77 BR3: { 78 'name': 'br-3', 79 'mode': 'rdn', 80 }, 81 } 82 83 def test(self): 84 leader = self.nodes[LEADER] 85 router = self.nodes[ROUTER] 86 br1 = self.nodes[BR1] 87 br2 = self.nodes[BR2] 88 br3 = self.nodes[BR3] 89 90 #------------------------------------------------------------------------------------- 91 # Set the router upgrade threshold to 2 on all nodes. 92 93 for node in [leader, router, br1, br2, br3]: 94 node.set_router_upgrade_threshold(2) 95 96 #------------------------------------------------------------------------------------- 97 # Start the leader and router. 98 99 leader.start() 100 self.simulator.go(config.LEADER_STARTUP_DELAY) 101 self.assertEqual(leader.get_state(), 'leader') 102 103 router.start() 104 self.simulator.go(125) 105 self.assertEqual(router.get_state(), 'router') 106 107 #------------------------------------------------------------------------------------- 108 # Start all three BRs, we expect all to stay as child since there are already two 109 # routers in the Thread mesh. 110 111 br1.start() 112 br2.start() 113 br3.start() 114 self.simulator.go(125) 115 self.assertEqual(br1.get_state(), 'child') 116 self.assertEqual(br2.get_state(), 'child') 117 self.assertEqual(br3.get_state(), 'child') 118 119 #------------------------------------------------------------------------------------- 120 # Add an external route on `br1`, it should now try to become a router requesting 121 # with status BorderRouterRequest. Verify that leader allows it to become router. 122 123 br1.add_route('2001:dead:beef:cafe::/64', stable=True) 124 br1.register_netdata() 125 self.simulator.go(15) 126 self.assertEqual(br1.get_state(), 'router') 127 128 #------------------------------------------------------------------------------------- 129 # Add a prefix with default route on `br2`, it should also become a router. 130 131 br2.add_prefix('2001:dead:beef:2222::/64', 'paros') 132 br2.register_netdata() 133 self.simulator.go(15) 134 self.assertEqual(br2.get_state(), 'router') 135 136 #------------------------------------------------------------------------------------- 137 # Add an external route on `br3`, it should not become a router since we already have 138 # two that requested router role upgrade as border router reason. 139 140 br3.add_route('2001:dead:beef:cafe::/64', stable=True) 141 br3.register_netdata() 142 self.simulator.go(120) 143 self.assertEqual(br3.get_state(), 'child') 144 145 #------------------------------------------------------------------------------------- 146 # Remove the external route on `br1`. This should now trigger `br3` to request a 147 # router role upgrade since number of BRs acting as router in network data is now 148 # below the threshold of two. 149 150 br1.remove_route('2001:dead:beef:cafe::/64') 151 br1.register_netdata() 152 self.simulator.go(15) 153 self.assertEqual(br1.get_state(), 'router') 154 self.assertEqual(br3.get_state(), 'router') 155 156 157if __name__ == '__main__': 158 unittest.main() 159