1#!/usr/bin/env python3 2# 3# Copyright (c) 2019, 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 unittest 31 32import thread_cert 33import config 34 35LEADER_1_1 = 1 36BBR_1 = 2 37BBR_2 = 3 38 39WAIT_ATTACH = 5 40WAIT_REDUNDANCE = 3 41ROUTER_SELECTION_JITTER = 1 42BBR_REGISTRATION_JITTER = 5 43""" 44 Topology 45 46 LEADER_1_1 --- BBR_1 47 \ | 48 \ | 49 \ | 50 BBR_2 51 52 1) Bring up Leader_1_1 and then BBR_1, BBR_1 becomes Primary Backbone Router. 53 2) Reset BBR_1, if bring back soon, it could restore the Backbone Router Service 54 from the network, after increasing sequence number, it will reregister its 55 Backbone Router Service to the Leader and become Primary. 56 3) Reset BBR_1, if bring back after it is released in the network, BBR_1 will 57 choose a random sequence number, register its Backbone Router Service to 58 Leader and become Primary. 59 4) Configure BBR_2 with highest sequence number and explicitly trigger SRV_DATA.ntf. 60 BBR_2 would become Primary and BBR_1 would change to Secondary with sequence 61 number increased by 1. 62 a) Check communication via DUA. 63 5) Stop BBR_2, BBR_1 would become Primary after detecting there is no available 64 Backbone Router Service in Thread Network. 65 6) Bring back BBR_2, and it would become Secondary. 66 a) Check the uniqueness of DUA by comparing the one in above 4a). 67 b) Check communication via DUA. 68 69""" 70 71 72class TestBackboneRouterService(thread_cert.TestCase): 73 TOPOLOGY = { 74 LEADER_1_1: { 75 'version': '1.1', 76 'allowlist': [BBR_1, BBR_2], 77 }, 78 BBR_1: { 79 'version': '1.2', 80 'allowlist': [LEADER_1_1, BBR_2], 81 'is_bbr': True 82 }, 83 BBR_2: { 84 'version': '1.2', 85 'allowlist': [LEADER_1_1, BBR_1], 86 'is_bbr': True 87 }, 88 } 89 """All nodes are created with default configurations""" 90 91 def test(self): 92 93 self.nodes[LEADER_1_1].start() 94 WAIT_TIME = WAIT_ATTACH 95 self.simulator.go(WAIT_TIME * 2) 96 self.assertEqual(self.nodes[LEADER_1_1].get_state(), 'leader') 97 self.simulator.set_lowpan_context(1, config.DOMAIN_PREFIX) 98 99 # 1) First Backbone Router would become the Primary. 100 self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 101 self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) 102 self.nodes[BBR_1].set_backbone_router(seqno=1) 103 self.nodes[BBR_1].start() 104 WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER 105 self.simulator.go(WAIT_TIME) 106 self.assertEqual(self.nodes[BBR_1].get_state(), 'router') 107 self.nodes[BBR_1].enable_backbone_router() 108 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 109 self.simulator.go(WAIT_TIME) 110 self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') 111 112 self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) 113 WAIT_TIME = WAIT_REDUNDANCE 114 self.simulator.go(WAIT_TIME) 115 116 # 2) Reset BBR_1 and bring it back soon. 117 # Verify that it restores Primary State with sequence number 118 # increased by 1. 119 self.nodes[BBR_1].reset() 120 self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) 121 self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 122 self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) 123 self.nodes[BBR_1].enable_backbone_router() 124 self.nodes[BBR_1].start() 125 WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER 126 self.simulator.go(WAIT_TIME) 127 self.assertEqual(self.nodes[BBR_1].get_state(), 'router') 128 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 129 self.simulator.go(WAIT_TIME) 130 self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') 131 self.assertEqual(self.nodes[BBR_1].get_backbone_router()['seqno'], 2) 132 133 # 3) Reset BBR_1 and bring it back after its original router id is released 134 # 200s (100s MaxNeighborAge + 90s InfiniteCost + 10s redundance) 135 # Verify it becomes Primary again. 136 # Note: To ensure test in next step, here Step 3) will repeat until 137 # the random sequence number is not the highest value 255. 138 while True: 139 self.nodes[BBR_1].reset() 140 WAIT_TIME = 200 141 self.simulator.go(WAIT_TIME) 142 self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 143 self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) 144 self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) 145 self.nodes[BBR_1].enable_backbone_router() 146 self.nodes[BBR_1].start() 147 WAIT_TIME = config.ROUTER_RESET_DELAY 148 self.simulator.go(WAIT_TIME) 149 self.assertEqual(self.nodes[BBR_1].get_state(), 'router') 150 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 151 self.simulator.go(WAIT_TIME) 152 self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') 153 BBR_1_SEQNO = self.nodes[BBR_1].get_backbone_router()['seqno'] 154 if (BBR_1_SEQNO != 255): 155 break 156 157 #4) Configure BBR_2 with highest sequence number (255) and 158 # explicitly trigger SRV_DATA.ntf. 159 # Verify BBR_2 would become Primary and BBR_1 would change to 160 # Secondary with sequence number increased by 1. 161 162 # Bring up BBR_2, it becomes Router with backbone function disabled 163 # by default. 164 self.nodes[BBR_2].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 165 self.nodes[BBR_2].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) 166 self.nodes[BBR_2].set_domain_prefix(config.DOMAIN_PREFIX) 167 self.nodes[BBR_2].start() 168 WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER 169 self.simulator.go(WAIT_TIME) 170 self.assertEqual(self.nodes[BBR_2].get_state(), 'router') 171 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 172 self.simulator.go(WAIT_TIME) 173 self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Disabled') 174 175 # Enable Backbone function, it will stay at Secondary state as 176 # there is Primary Backbone Router already. 177 # Here removes the Domain Prefix before enabling backbone function 178 # intentionally to avoid SRV_DATA.ntf due to prefix inconsistency. 179 self.nodes[BBR_2].remove_domain_prefix(config.DOMAIN_PREFIX) 180 self.nodes[BBR_2].enable_backbone_router() 181 self.nodes[BBR_2].set_backbone_router(seqno=255) 182 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 183 self.simulator.go(WAIT_TIME) 184 self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Secondary') 185 186 # Check no SRV_DATA.ntf. 187 messages = self.simulator.get_messages_sent_by(BBR_2) 188 msg = messages.next_coap_message('0.02', '/a/sd', False) 189 self.assertIsNone(msg) 190 191 # Flush relative message queue. 192 self.flush_nodes([BBR_1]) 193 194 # BBR_2 registers SRV_DATA.ntf explicitly. 195 self.nodes[BBR_2].register_backbone_router() 196 WAIT_TIME = WAIT_REDUNDANCE 197 self.simulator.go(WAIT_TIME) 198 self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Primary') 199 200 # Verify BBR_1 becomes Secondary and sends SRV_DATA.ntf to deregister 201 # its service. 202 messages = self.simulator.get_messages_sent_by(BBR_1) 203 messages.next_coap_message('0.02', '/a/sd', True) 204 self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Secondary') 205 # Verify Sequence number increases when become Secondary from Primary. 206 self.assertEqual(self.nodes[BBR_1].get_backbone_router()['seqno'], BBR_1_SEQNO + 1) 207 208 # 4a) Check communication via DUA. 209 bbr2_dua = self.nodes[BBR_2].get_addr(config.DOMAIN_PREFIX) 210 self.assertTrue(self.nodes[BBR_1].ping(bbr2_dua)) 211 212 # 5) Stop BBR_2, BBR_1 becomes Primary after detecting there is no 213 # available Backbone Router Service. 214 self.nodes[BBR_2].reset() 215 self.nodes[LEADER_1_1].release_router_id(self.nodes[BBR_2].get_router_id()) 216 # Wait for the dissemination of Network Data without Backbone Router service 217 self.simulator.go(10) 218 219 # BBR_1 becomes Primary. 220 self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') 221 messages = self.simulator.get_messages_sent_by(BBR_1) 222 messages.next_coap_message('0.02', '/a/sd', True) 223 224 # 6) Bring back BBR_2. 225 # Verify that BBR_2 stays at Secondary. 226 self.nodes[BBR_2].set_router_selection_jitter(ROUTER_SELECTION_JITTER) 227 self.nodes[BBR_2].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) 228 self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) 229 self.nodes[BBR_2].enable_backbone_router() 230 self.nodes[BBR_2].interface_up() 231 self.nodes[BBR_2].thread_start() 232 WAIT_TIME = config.ROUTER_RESET_DELAY 233 self.simulator.go(WAIT_TIME) 234 self.assertEqual(self.nodes[BBR_2].get_state(), 'router') 235 WAIT_TIME = BBR_REGISTRATION_JITTER + WAIT_REDUNDANCE 236 self.simulator.go(WAIT_TIME) 237 self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Secondary') 238 239 # 6a) Check the uniqueness of DUA by comparing the one in above 4a). 240 bbr2_dua2 = self.nodes[BBR_2].get_addr(config.DOMAIN_PREFIX) 241 self.assertEqual(bbr2_dua, bbr2_dua2) 242 243 # 6b) Check communication via DUA 244 self.assertTrue(self.nodes[BBR_1].ping(bbr2_dua)) 245 246 247if __name__ == '__main__': 248 unittest.main() 249