1#!/usr/bin/env python3
2#
3#  Copyright (c) 2021, 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#   This test verifies network data publisher behavior with DNS/SRP service entries and on-mesh prefix and external
39#   route entries.
40#
41# Topology:
42#
43#   1 leader, 5 routers and 5 end-devices all connected.
44#
45
46LEADER = 1
47ROUTER1 = 2
48ROUTER2 = 3
49ROUTER3 = 4
50ROUTER4 = 5
51ROUTER5 = 6
52END_DEV1 = 7
53END_DEV2 = 8
54END_DEV3 = 9
55END_DEV4 = 10
56END_DEV5 = 11
57
58WAIT_TIME = 55
59
60ON_MESH_PREFIX = 'fd00:1234:0:0::/64'
61ON_MESH_FLAGS = 'paso'
62
63EXTERNAL_ROUTE = 'fd00:abce:0:0::/64'
64EXTERNAL_FLAGS = 's'
65
66ANYCAST_SEQ_NUM = 4
67
68DNSSRP_ADDRESS = 'fd00::cdef'
69DNSSRP_PORT = 49152
70
71# The desired number of entries (based on related config).
72DESIRED_NUM_DNSSRP_ANYCAST = 8
73DESIRED_NUM_DNSSRP_UNICAST = 2
74DESIRED_NUM_ON_MESH_PREFIX = 3
75DESIRED_NUM_EXTERNAL_ROUTE = 10
76
77THREAD_ENTERPRISE_NUMBER = 44970
78ANYCAST_SERVICE_NUM = 0x5c
79UNICAST_SERVICE_NUM = 0x5d
80
81
82class NetDataPublisher(thread_cert.TestCase):
83    USE_MESSAGE_FACTORY = False
84    SUPPORT_NCP = False
85
86    TOPOLOGY = {
87        LEADER: {
88            'name': 'LEADER',
89            'mode': 'rdn',
90        },
91        ROUTER1: {
92            'name': 'ROUTER1',
93            'mode': 'rdn',
94        },
95        ROUTER2: {
96            'name': 'ROUTER2',
97            'mode': 'rdn',
98        },
99        ROUTER3: {
100            'name': 'ROUTER3',
101            'mode': 'rdn',
102        },
103        ROUTER4: {
104            'name': 'ROUTER4',
105            'mode': 'rdn',
106        },
107        ROUTER5: {
108            'name': 'ROUTER5',
109            'mode': 'rdn',
110        },
111        END_DEV1: {
112            'name': 'END_DEV1',
113            'mode': 'rn',
114        },
115        END_DEV2: {
116            'name': 'END_DEV2',
117            'mode': 'rn',
118        },
119        END_DEV3: {
120            'name': 'END_DEV3',
121            'mode': 'rn',
122        },
123        END_DEV4: {
124            'name': 'END_DEV4',
125            'mode': 'rn',
126        },
127        END_DEV5: {
128            'name': 'END_DEV5',
129            'mode': 'rn',
130        },
131    }
132
133    def verify_anycast_service(self, service):
134        # Verify the data in a single anycast `service` from `get_services()`
135        # Example of `service`: ['44970', '5c04', '', 's', 'bc00']
136        self.assertEqual(int(service[0]), THREAD_ENTERPRISE_NUMBER)
137        # Check service data
138        service_data = bytes.fromhex(service[1])
139        self.assertTrue(len(service_data) >= 2)
140        self.assertEqual(service_data[0], ANYCAST_SERVICE_NUM)
141        self.assertEqual(service_data[1], int(ANYCAST_SEQ_NUM))
142        # Verify that it stable
143        self.assertEqual(service[3], 's')
144
145    def verify_anycast_services(self, services):
146        # Verify a list of anycast `services` from `get_services()`
147        for service in services:
148            self.verify_anycast_service(service)
149
150    def verify_unicast_service(self, service):
151        # Verify the data in a single unicast `service` from `get_services()`
152        # Example of `service`: ['44970', '5d', 'fd000db800000000c6b0e5ee81f940e8223d', 's', '7000']
153        self.assertEqual(int(service[0]), THREAD_ENTERPRISE_NUMBER)
154        # Check service data
155        service_data = bytes.fromhex(service[1])
156        self.assertTrue(len(service_data) >= 1)
157        self.assertEqual(service_data[0], UNICAST_SERVICE_NUM)
158        # Verify that it stable
159        self.assertEqual(service[3], 's')
160
161    def verify_unicast_services(self, services):
162        # Verify a list of unicast `services` from `get_services()`
163        for service in services:
164            self.verify_unicast_service(service)
165
166    def check_num_of_prefixes(self, prefixes, num_low, num_med, num_high):
167        # Check and validate the prefix entries in network data (from
168        # `prefixes`) based on number of published prefix entries at
169        # different preference levels given by `num_low`, `num_med`,
170        # `num_high`. Prefixes is a list of the format
171        # 'fd00:1234:0:0::/64 paos low a802'.
172        self.assertEqual(len(prefixes), min(num_high + num_med + num_low, DESIRED_NUM_ON_MESH_PREFIX))
173        prfs = [prefix.split(' ')[2] for prefix in prefixes]
174        self.assertEqual(prfs.count('high'), min(num_high, DESIRED_NUM_ON_MESH_PREFIX))
175        self.assertEqual(prfs.count('med'), min(num_med, max(0, DESIRED_NUM_ON_MESH_PREFIX - num_high)))
176        self.assertEqual(prfs.count('low'), min(num_low, max(0, DESIRED_NUM_ON_MESH_PREFIX - num_high - num_med)))
177
178    def check_num_of_routes(self, routes, num_low, num_med, num_high):
179        # Check and validate the prefix entries in network data (from
180        # `routes`) based on number of published prefix entries at
181        # different preference levels given by `num_low`, `num_med`,
182        # `num_high`. Prefixes is a list of the format
183        # 'fd00:abce:0:0::/64 s med 6c01'.
184        self.assertEqual(len(routes), min(num_high + num_med + num_low, DESIRED_NUM_EXTERNAL_ROUTE))
185        prfs = [route.split(' ')[2] for route in routes]
186        self.assertEqual(prfs.count('high'), min(num_high, DESIRED_NUM_EXTERNAL_ROUTE))
187        self.assertEqual(prfs.count('med'), min(num_med, max(0, DESIRED_NUM_EXTERNAL_ROUTE - num_high)))
188        self.assertEqual(prfs.count('low'), min(num_low, max(0, DESIRED_NUM_EXTERNAL_ROUTE - num_high - num_med)))
189
190    def test(self):
191        leader = self.nodes[LEADER]
192        router1 = self.nodes[ROUTER1]
193        router2 = self.nodes[ROUTER2]
194        router3 = self.nodes[ROUTER3]
195        router4 = self.nodes[ROUTER4]
196        router5 = self.nodes[ROUTER5]
197        end_dev1 = self.nodes[END_DEV1]
198        end_dev2 = self.nodes[END_DEV2]
199        end_dev3 = self.nodes[END_DEV3]
200        end_dev4 = self.nodes[END_DEV4]
201        end_dev5 = self.nodes[END_DEV5]
202
203        nodes = self.nodes.values()
204        routers = [router1, router2, router3, router4, router5]
205        end_devs = [end_dev1, end_dev2, end_dev3, end_dev4, end_dev5]
206
207        # Start the nodes
208
209        leader.start()
210        self.simulator.go(config.LEADER_STARTUP_DELAY)
211        self.assertEqual(leader.get_state(), 'leader')
212
213        for router in routers:
214            router.start()
215            self.simulator.go(config.ROUTER_STARTUP_DELAY)
216            self.assertEqual(router.get_state(), 'router')
217
218        for end_dev in end_devs:
219            end_dev.start()
220            self.simulator.go(5)
221            self.assertEqual(end_dev.get_state(), 'child')
222
223        #---------------------------------------------------------------------------------
224        # DNS/SRP anycast entries - equal version number
225
226        # Publish DNS/SRP anycast on leader and all routers (6 nodes).
227
228        leader.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
229        for node in routers:
230            node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
231        self.simulator.go(WAIT_TIME)
232
233        # Check all entries are present in the network data
234
235        services = leader.get_services()
236        self.assertEqual(len(services), min(1 + len(routers), DESIRED_NUM_DNSSRP_ANYCAST))
237        self.verify_anycast_services(services)
238
239        # Publish same entry on all end-devices (5 nodes).
240
241        for node in end_devs:
242            node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
243            print(node.name)
244        self.simulator.go(WAIT_TIME)
245
246        # Check number of entries in the network data is limited to
247        # the desired number (8 entries).
248
249        services = leader.get_services()
250        self.assertEqual(len(leader.get_services()), min(len(nodes), DESIRED_NUM_DNSSRP_ANYCAST))
251        self.verify_anycast_services(services)
252
253        # Unpublish the entry from nodes one by one starting from leader
254        # and check that number of entries is correct in each step.
255
256        num = len(nodes)
257        for node in nodes:
258            node.netdata_unpublish_dnssrp()
259            self.simulator.go(WAIT_TIME)
260            num -= 1
261            services = leader.get_services()
262            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
263            self.verify_anycast_services(services)
264
265        #---------------------------------------------------------------------------------
266        # DNS/SRP anycast entries - different version numbers
267
268        # Publish DNS/SRP anycast on leader and all routers (6 nodes).
269
270        version = 0
271        leader.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version)
272        num = 1
273
274        for node in routers:
275            version += 1
276            node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version)
277            num += 1
278
279        self.simulator.go(WAIT_TIME)
280
281        # Check all entries are present in the network data
282
283        services = leader.get_services()
284        self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
285        self.verify_anycast_services(services)
286
287        # Publish same entry with same version on all end-devices (5 nodes).
288
289        for node in end_devs:
290            node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version)
291            num += 1
292            print(node.name)
293            self.simulator.go(WAIT_TIME)
294            # Check number of entries in the network data is limited
295            # to the desired number (8 entries). All new entries use
296            # higher version and should be preferred. Validate that
297            # the 'services' list contains the new services.
298            services = leader.get_services()
299            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
300            self.verify_anycast_services(services)
301            node_rloc16 = node.get_addr16()
302            self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services))
303
304        # Unpublish the entry from nodes one by one starting from leader
305        # and check that number of entries is correct in each step.
306
307        for node in nodes:
308            node.netdata_unpublish_dnssrp()
309            self.simulator.go(WAIT_TIME)
310            num -= 1
311            services = leader.get_services()
312            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
313            self.verify_anycast_services(services)
314
315        #---------------------------------------------------------------------------------
316        # DNS/SRP service data unicast entries - equal version number
317
318        num = 0
319        for node in routers:
320            node.netdata_publish_dnssrp_unicast(DNSSRP_ADDRESS, DNSSRP_PORT)
321            self.simulator.go(WAIT_TIME)
322            num += 1
323            services = leader.get_services()
324            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
325            self.verify_unicast_services(services)
326
327        for node in routers:
328            node.srp_server_set_enabled(True)
329            self.simulator.go(WAIT_TIME)
330
331        self.assertEqual(sum(node.srp_server_get_state() == 'running' for node in routers),
332                         min(len(routers), DESIRED_NUM_DNSSRP_UNICAST))
333        self.assertEqual(sum(node.srp_server_get_state() == 'stopped' for node in routers),
334                         max(len(routers) - DESIRED_NUM_DNSSRP_UNICAST, 0))
335
336        for node in routers:
337            node.netdata_unpublish_dnssrp()
338            self.simulator.go(WAIT_TIME)
339            num -= 1
340            services = leader.get_services()
341            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
342            self.verify_unicast_services(services)
343        for node in routers:
344            node.srp_server_set_enabled(False)
345            self.assertEqual(node.srp_server_get_state(), 'disabled')
346
347        #---------------------------------------------------------------------------------
348        # DNS/SRP service data unicast entries - different version numbers
349
350        num = 0
351        for node in routers:
352            # Use `num` as version.
353            node.netdata_publish_dnssrp_unicast(DNSSRP_ADDRESS, DNSSRP_PORT, num)
354            self.simulator.go(WAIT_TIME)
355            num += 1
356            services = leader.get_services()
357            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
358            self.verify_unicast_services(services)
359            # The most recent service should win as it uses a higher version
360            # number. Validate that the 'services' list contains the service
361            # from this node by checking the service RLOC16.
362            node_rloc16 = node.get_addr16()
363            self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services))
364
365        for node in reversed(routers):
366            node.netdata_unpublish_dnssrp()
367            self.simulator.go(WAIT_TIME)
368            num -= 1
369            services = leader.get_services()
370            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
371            self.verify_unicast_services(services)
372
373        #---------------------------------------------------------------------------------
374        # DNS/SRP server data unicast entries - equal version number
375
376        num = 0
377        for node in routers:
378            node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT)
379            self.simulator.go(WAIT_TIME)
380            num += 1
381            services = leader.get_services()
382            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
383            self.verify_unicast_services(services)
384
385        for node in routers:
386            node.srp_server_set_enabled(True)
387            self.simulator.go(WAIT_TIME)
388        self.assertEqual(sum(node.srp_server_get_state() == 'running' for node in routers),
389                         min(len(routers), DESIRED_NUM_DNSSRP_UNICAST))
390        self.assertEqual(sum(node.srp_server_get_state() == 'stopped' for node in routers),
391                         max(len(routers) - DESIRED_NUM_DNSSRP_UNICAST, 0))
392
393        for node in routers:
394            node.netdata_unpublish_dnssrp()
395            self.simulator.go(WAIT_TIME)
396            num -= 1
397            services = leader.get_services()
398            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
399            self.verify_unicast_services(services)
400        for node in routers:
401            node.srp_server_set_enabled(False)
402            self.assertEqual(node.srp_server_get_state(), 'disabled')
403
404        #---------------------------------------------------------------------------------
405        # DNS/SRP server data unicast entries - different version numbers
406
407        num = 0
408        for node in routers:
409            node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT, num)
410            self.simulator.go(WAIT_TIME)
411            num += 1
412            services = leader.get_services()
413            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
414            self.verify_unicast_services(services)
415            # The most recent service should win as it uses a higher version
416            # number. Validate that the 'services' list contains the service
417            # from this node by checking the service RLOC16.
418            node_rloc16 = node.get_addr16()
419            self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services))
420
421        for node in reversed(routers):
422            node.netdata_unpublish_dnssrp()
423            self.simulator.go(WAIT_TIME)
424            num -= 1
425            services = leader.get_services()
426            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
427            self.verify_unicast_services(services)
428
429        # Repeat the same test steps, but start with larger version
430        # numbers first.
431
432        num = 0
433        for node in routers:
434            node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT, 20 - num)
435            self.simulator.go(WAIT_TIME)
436            num += 1
437            services = leader.get_services()
438            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
439            self.verify_unicast_services(services)
440            # The service from first router should win as it uses the highest
441            # version number.
442            first_router_rloc16 = routers[0].get_addr16()
443            self.assertTrue(any(int(service[4], 16) == first_router_rloc16 for service in services))
444
445        for node in routers:
446            node.netdata_unpublish_dnssrp()
447            self.simulator.go(WAIT_TIME)
448            num -= 1
449            services = leader.get_services()
450            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
451            self.verify_unicast_services(services)
452
453        #---------------------------------------------------------------------------------
454        # DNS/SRP server data unicast vs anycast
455
456        num = 0
457        for node in routers:
458            node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT)
459            self.simulator.go(WAIT_TIME)
460            num += 1
461            services = leader.get_services()
462            self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
463            self.verify_unicast_services(services)
464
465        # Verify that publishing an anycast entry will update the
466        # limit for the server data unicast address entry and all are
467        # removed.
468
469        leader.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
470        self.simulator.go(WAIT_TIME)
471        services = leader.get_services()
472        self.assertEqual(len(services), 1)
473        self.verify_anycast_services(services)
474
475        # Removing the anycast entry will cause the lower priority
476        # server data unicast entries to be added again.
477
478        leader.netdata_unpublish_dnssrp()
479        self.simulator.go(WAIT_TIME)
480
481        services = leader.get_services()
482        self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
483        self.verify_unicast_services(services)
484
485        #---------------------------------------------------------------------------------
486        # DNS/SRP server data unicast vs service data unicast
487
488        leader.netdata_publish_dnssrp_unicast(DNSSRP_ADDRESS, DNSSRP_PORT)
489        self.simulator.go(WAIT_TIME)
490        services = leader.get_services()
491        self.assertEqual(len(services), 1)
492        self.verify_unicast_services(services)
493
494        # Removing the service data unicast entry will cause the lower
495        # priority server data unicast entries to be added again.
496
497        leader.netdata_unpublish_dnssrp()
498        self.simulator.go(WAIT_TIME)
499
500        services = leader.get_services()
501        self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
502        self.verify_unicast_services(services)
503
504        for node in routers:
505            node.netdata_unpublish_dnssrp()
506
507        #---------------------------------------------------------------------------------
508        # DNS/SRP entries: Verify publisher preference when removing
509        # entries.
510        #
511        # Publish DNS/SRP anycast on 8 nodes: leader, router1,
512        # router2, and all 5 end-devices. Afterwards, manually add
513        # the same service entry in Network Data on router3, router4,
514        # and router5 and at each step check that entry from one of
515        # the end-devices is removed (publisher prefers
516        # entries from routers over the ones from end-devices).
517
518        num = 0
519        test_routers = [leader, router1, router2]
520        for node in test_routers + end_devs:
521            node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
522            self.simulator.go(WAIT_TIME)
523            num += 1
524            services = leader.get_services()
525            self.assertEqual(len(services), num)
526            self.verify_anycast_services(services)
527
528        self.assertEqual(num, DESIRED_NUM_DNSSRP_ANYCAST)
529
530        service_data = '%02x%02x' % (ANYCAST_SERVICE_NUM, int(ANYCAST_SEQ_NUM))
531        for node in [router3, router4, router5]:
532            node.add_service(str(THREAD_ENTERPRISE_NUMBER), service_data, '00')
533            node.register_netdata()
534            self.simulator.go(WAIT_TIME)
535
536            services = leader.get_services()
537            self.assertEqual(len(services), num)
538            self.verify_anycast_services(services)
539
540            service_rlocs = [int(service[4], 16) for service in services]
541            test_routers.append(node)
542
543            for router in test_routers:
544                self.assertIn(router.get_addr16(), service_rlocs)
545
546        #---------------------------------------------------------------------------------
547        # On-mesh prefix
548
549        # Publish the same on-mesh prefix on different nodes (low
550        # preference on end-devices, medium preference on routers, and
551        # high on leader) one by one and then unpublish them one by one.
552        # Verify that at each step the entries in the network data are
553        # correct. Particularly verify that that higher preference
554        # entries replace lower preference ones even when there are
555        # already desired number in network data.
556
557        num_low = 0
558        num_med = 0
559        num_high = 0
560
561        for node in end_devs:
562            node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'low')
563            self.simulator.go(WAIT_TIME)
564            num_low += 1
565            prefixes = leader.get_prefixes()
566            self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
567
568        # Now add the entry as 'med' on routers and check that we see those in the list.
569        for node in routers:
570            node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
571            self.simulator.go(WAIT_TIME)
572            num_med += 1
573            prefixes = leader.get_prefixes()
574            self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
575
576        leader.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'high')
577        self.simulator.go(WAIT_TIME)
578        num_high += 1
579        prefixes = leader.get_prefixes()
580        self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
581
582        for node in routers:
583            node.netdata_unpublish_prefix(ON_MESH_PREFIX)
584            self.simulator.go(WAIT_TIME)
585            num_med -= 1
586            prefixes = leader.get_prefixes()
587            self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
588
589        leader.netdata_unpublish_prefix(ON_MESH_PREFIX)
590        self.simulator.go(WAIT_TIME)
591        num_high -= 1
592        prefixes = leader.get_prefixes()
593        self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
594
595        for node in end_devs:
596            node.netdata_unpublish_prefix(ON_MESH_PREFIX)
597            self.simulator.go(WAIT_TIME)
598            num_low -= 1
599            prefixes = leader.get_prefixes()
600            self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
601
602        #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
603        # Verify that when removing extra entries, non-preferred entries
604        # are removed first over preferred ones. Entries from routers are
605        # preferred over similar entries from end-devices.
606
607        # Publish prefix entry on `end_dev1` and verify that it is added.
608
609        end_dev1.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
610        self.simulator.go(WAIT_TIME)
611        prefixes = leader.get_prefixes()
612        self.check_num_of_prefixes(prefixes, 0, 1, 0)
613
614        # Publish same prefix on all routers (again as `med` preference).
615        # Verify that we reach the desired number of prefix entries in network
616        # data and that the entry from `end_dev1` is present in network data.
617
618        for node in routers:
619            node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
620            self.simulator.go(WAIT_TIME)
621        prefixes = leader.get_prefixes()
622        self.check_num_of_prefixes(prefixes, 0, 1 + len(routers), 0)
623        self.assertTrue(1 + len(routers) >= DESIRED_NUM_ON_MESH_PREFIX)
624        # `prefixes` is a list of format 'fd00:1234:0:0::/64 paos low a802'
625        rlocs = [int(prefix.split(' ')[3], 16) for prefix in prefixes]
626        self.assertTrue(rlocs.count(end_dev1.get_addr16()) == 1)
627
628        # Publish same prefix now with `high` preference on leader.
629        # Since it is `high` preference, it is added to network data
630        # which leads to total number of entries to go above the desired
631        # number temporarily and trigger other nodes to try to remove
632        # their entry. The entries from routers should be preferred over
633        # the one from `end_dev1` so that is the one we expect to be
634        # removed. We check that this is the case (i.e., the entry from
635        # `end_dev1` is no longer present in network data).
636
637        leader.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'high')
638        self.simulator.go(WAIT_TIME)
639        prefixes = leader.get_prefixes()
640        self.check_num_of_prefixes(prefixes, 0, 1 + len(routers), 1)
641        rlocs = [int(prefix.split(' ')[3], 16) for prefix in prefixes]
642        self.assertTrue(rlocs.count(end_dev1.get_addr16()) == 0)
643
644        #---------------------------------------------------------------------------------
645        # External route
646
647        # Publish same external route on all nodes with low preference.
648
649        num = 0
650        for node in nodes:
651            node.netdata_publish_route(EXTERNAL_ROUTE, EXTERNAL_FLAGS, 'low')
652            self.simulator.go(WAIT_TIME)
653            num += 1
654            routes = leader.get_routes()
655            self.check_num_of_routes(routes, num, 0, 0)
656
657        # Change the preference level of the existing entry on leader to high.
658
659        leader.netdata_publish_route(EXTERNAL_ROUTE, EXTERNAL_FLAGS, 'high')
660        self.simulator.go(WAIT_TIME)
661        routes = leader.get_routes()
662        self.check_num_of_routes(routes, num - 1, 0, 1)
663
664        # Replace the published route on leader with '::/0'.
665        leader.netdata_publish_replace(EXTERNAL_ROUTE, '::/0', EXTERNAL_FLAGS, 'med')
666        self.simulator.go(1)
667        routes = leader.get_routes()
668        self.assertEqual([route.split(' ')[0] == '::/0' for route in routes].count(True), 1)
669
670        # Replace it back to the original route.
671        leader.netdata_publish_replace('::/0', EXTERNAL_ROUTE, EXTERNAL_FLAGS, 'high')
672        self.simulator.go(WAIT_TIME)
673        routes = leader.get_routes()
674        self.assertEqual([route.split(' ')[0] == '::/0' for route in routes].count(True), 0)
675        self.check_num_of_routes(routes, num - 1, 0, 1)
676
677        # Publish the same prefix on leader as an on-mesh prefix. Make
678        # sure it is removed from external routes and now seen in the
679        # prefix list.
680
681        leader.netdata_publish_prefix(EXTERNAL_ROUTE, ON_MESH_FLAGS, 'low')
682        self.simulator.go(WAIT_TIME)
683        routes = leader.get_routes()
684        self.check_num_of_routes(routes, num - 1, 0, 0)
685
686        prefixes = leader.get_prefixes()
687        print(prefixes)
688        self.assertIn(EXTERNAL_ROUTE, [prefix.split()[0] for prefix in prefixes])
689
690
691if __name__ == '__main__':
692    unittest.main()
693