• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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