1#!/usr/bin/env python3 2# 3# Copyright (c) 2018, 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 time 30import wpan 31from wpan import verify 32 33# ----------------------------------------------------------------------------------------------------------------------- 34# Test description: Partition formation and merge 35# 36# Network Topology: 37# 38# r1 ---- / ---- r2 39# | \ | 40# | / | 41# c1 \ c2 42# 43# 44# Test covers the following situations: 45# 46# - r2 forming its own partition when it can no longer hear r1 47# - Partitions merging into one once r1 and r2 can talk again 48# - Adding on-mesh prefixes on each partition and ensuring after 49# merge the info in combined. 50# 51 52test_name = __file__[:-3] if __file__.endswith('.py') else __file__ 53print('-' * 120) 54print('Starting \'{}\''.format(test_name)) 55 56# ----------------------------------------------------------------------------------------------------------------------- 57# Utility functions 58 59 60def verify_prefix( 61 node_list, 62 prefix, 63 prefix_len=64, 64 stable=True, 65 priority='med', 66 on_mesh=False, 67 slaac=False, 68 dhcp=False, 69 configure=False, 70 default_route=False, 71 preferred=False, 72): 73 """ 74 This function verifies that the `prefix` is present on all the nodes in the `node_list`. 75 """ 76 for node in node_list: 77 prefixes = wpan.parse_on_mesh_prefix_result(node.get(wpan.WPAN_THREAD_ON_MESH_PREFIXES)) 78 for p in prefixes: 79 if p.prefix == prefix: 80 verify(int(p.prefix_len) == prefix_len) 81 verify(p.is_stable() == stable) 82 verify(p.is_on_mesh() == on_mesh) 83 verify(p.is_def_route() == default_route) 84 verify(p.is_slaac() == slaac) 85 verify(p.is_dhcp() == dhcp) 86 verify(p.is_config() == configure) 87 verify(p.is_preferred() == preferred) 88 verify(p.priority == priority) 89 break 90 else: 91 raise wpan.VerifyError("Did not find prefix {} on node {}".format(prefix, node)) 92 93 94# ----------------------------------------------------------------------------------------------------------------------- 95# Creating `wpan.Nodes` instances 96 97speedup = 25 98wpan.Node.set_time_speedup_factor(speedup) 99 100r1 = wpan.Node() 101r2 = wpan.Node() 102c1 = wpan.Node() 103c2 = wpan.Node() 104 105# ----------------------------------------------------------------------------------------------------------------------- 106# Init all nodes 107 108wpan.Node.init_all_nodes() 109 110# ----------------------------------------------------------------------------------------------------------------------- 111# Build network topology 112# 113 114r1.form("partition") 115 116r1.allowlist_node(r2) 117r2.allowlist_node(r1) 118r2.join_node(r1, wpan.JOIN_TYPE_ROUTER) 119 120c1.allowlist_node(r1) 121r1.allowlist_node(c1) 122c1.join_node(r1, wpan.JOIN_TYPE_END_DEVICE) 123 124c2.allowlist_node(r2) 125r2.allowlist_node(c2) 126c2.join_node(r2, wpan.JOIN_TYPE_END_DEVICE) 127 128# ----------------------------------------------------------------------------------------------------------------------- 129# Test implementation 130 131short_wait = 6 132long_wait = 15 # With speedup of 25, this emulates 375s (~6 min). 133 134prefix1 = "fd00:1234::" 135prefix2 = "fd00:abcd::" 136 137time.sleep(1) 138 139verify(r1.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_LEADER) 140verify(r2.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_ROUTER) 141 142# Now force the two routers to form their own partition 143# by removing them from each other's allowlist table 144r1.un_allowlist_node(r2) 145r2.un_allowlist_node(r1) 146 147# Add a prefix before r2 realizes it can not longer talk 148# to leader (r1). 149r2.add_prefix(prefix2) 150 151# Check that r2 forms its own partition 152 153 154def check_r2_become_leader(): 155 verify(r2.get(wpan.WPAN_NODE_TYPE) == wpan.NODE_TYPE_LEADER) 156 157 158wpan.verify_within(check_r2_become_leader, long_wait) 159 160# While we have two partition, add a prefix on r1 161r1.add_prefix(prefix1) 162 163# Update allowlist and wait for partitions to merge. 164r1.allowlist_node(r2) 165r2.allowlist_node(r1) 166 167 168def check_partition_id_match(): 169 verify(r1.get(wpan.WPAN_PARTITION_ID) == r2.get(wpan.WPAN_PARTITION_ID)) 170 171 172wpan.verify_within(check_partition_id_match, long_wait) 173 174# Check that partitions merged successfully 175 176 177def check_r1_r2_roles(): 178 r1_type = r1.get(wpan.WPAN_NODE_TYPE) 179 r2_type = r2.get(wpan.WPAN_NODE_TYPE) 180 verify((r1_type == wpan.NODE_TYPE_LEADER and r2_type == wpan.NODE_TYPE_ROUTER) or 181 (r2_type == wpan.NODE_TYPE_LEADER and r1_type == wpan.NODE_TYPE_ROUTER)) 182 183 184wpan.verify_within(check_r1_r2_roles, short_wait) 185 186# Verify all nodes have both prefixes 187 188 189def check_prefixes(): 190 verify_prefix([r1, r2, c1, c2], prefix1) 191 verify_prefix([r1, r2, c1, c2], prefix2) 192 193 194wpan.verify_within(check_prefixes, short_wait) 195 196# Verify that the children stayed with their parents 197verify(len(wpan.parse_list(r1.get(wpan.WPAN_THREAD_CHILD_TABLE))) == 1) 198verify(len(wpan.parse_list(r2.get(wpan.WPAN_THREAD_CHILD_TABLE))) == 1) 199 200# ----------------------------------------------------------------------------------------------------------------------- 201# Test finished 202 203wpan.Node.finalize_all_nodes() 204 205print('\'{}\' passed.'.format(test_name)) 206