1#!/usr/bin/env python3 2# 3# Copyright (c) 2020, 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 wpan 30from wpan import verify 31 32# ----------------------------------------------------------------------------------------------------------------------- 33# Test description: Network Data update and version changes (stable only vs. full version). 34# 35# Network topology 36# 37# leader 38# / | \ 39# / | \ 40# / | \ 41# c1 c2 c3 42# 43# 44# c3 is sleepy-end node and also configured to request stable Network Data only 45# 46# Test covers the following steps: 47# - Adding/removing prefixes (stable or temporary) on c1 48# - Verifying that Network Data is updated on all nodes 49# - Ensuring correct update to version and stable version 50 51# The above steps are repeated over many different situations: 52# - Where the same prefixes are also added by other nodes 53# - Or the same prefixes are added as off-mesh routes by other nodes 54# 55 56test_name = __file__[:-3] if __file__.endswith('.py') else __file__ 57print('-' * 120) 58print('Starting \'{}\''.format(test_name)) 59 60 61def verify_prefix( 62 node_list, 63 prefix, 64 rloc16, 65 prefix_len=64, 66 stable=True, 67 priority='med', 68 on_mesh=False, 69 slaac=False, 70 dhcp=False, 71 configure=False, 72 default_route=False, 73 preferred=False, 74): 75 """ 76 This function verifies that the `prefix` is present on all the nodes in the `node_list`. It also verifies that the 77 `prefix` is associated with the given `rloc16` (as an integer). 78 """ 79 for node in node_list: 80 prefixes = wpan.parse_on_mesh_prefix_result(node.get(wpan.WPAN_THREAD_ON_MESH_PREFIXES)) 81 for p in prefixes: 82 if (p.prefix == prefix and p.origin == "ncp" and int(p.rloc16(), 0) == rloc16): 83 verify(int(p.prefix_len) == prefix_len) 84 verify(p.is_stable() == stable) 85 verify(p.is_on_mesh() == on_mesh) 86 verify(p.is_def_route() == default_route) 87 verify(p.is_slaac() == slaac) 88 verify(p.is_dhcp() == dhcp) 89 verify(p.is_config() == configure) 90 verify(p.is_preferred() == preferred) 91 verify(p.priority == priority) 92 break 93 else: 94 raise wpan.VerifyError("Did not find prefix {} on node {}".format(prefix, node)) 95 96 97def verify_no_prefix(node_list, prefix, rloc16): 98 """ 99 This function verifies that none of the nodes in `node_list` contains the on-mesh `prefix` associated with the 100 given `rloc16`. 101 """ 102 for node in node_list: 103 prefixes = wpan.parse_on_mesh_prefix_result(node.get(wpan.WPAN_THREAD_ON_MESH_PREFIXES)) 104 for p in prefixes: 105 if (p.prefix == prefix and p.origin == "ncp" and int(p.rloc16(), 0) == rloc16): 106 raise wpan.VerifyError("Did find prefix {} with rloc {} on node {}".format(prefix, hex(rloc16), node)) 107 108 109# ----------------------------------------------------------------------------------------------------------------------- 110# Creating `wpan.Nodes` instances 111 112speedup = 25 113wpan.Node.set_time_speedup_factor(speedup) 114 115leader = wpan.Node() 116c1 = wpan.Node() 117c2 = wpan.Node() 118c3 = wpan.Node() 119 120# ----------------------------------------------------------------------------------------------------------------------- 121# Init all nodes 122 123wpan.Node.init_all_nodes() 124 125# ----------------------------------------------------------------------------------------------------------------------- 126# Build network topology 127# 128 129leader.form("bloodborne") # "fear the old blood" 130 131c1.join_node(leader, wpan.JOIN_TYPE_END_DEVICE) 132c2.join_node(leader, wpan.JOIN_TYPE_END_DEVICE) 133c3.join_node(leader, wpan.JOIN_TYPE_SLEEPY_END_DEVICE) 134c3.set(wpan.WPAN_POLL_INTERVAL, '400') 135 136# Clear the "full network data" flag on c3. 137c3.set(wpan.WPAN_THREAD_DEVICE_MODE, '-') 138 139# ----------------------------------------------------------------------------------------------------------------------- 140# Test implementation 141 142WAIT_TIME = 15 143 144prefix1 = "fd00:1::" 145prefix2 = "fd00:2::" 146prefix3 = "fd00:3::" 147 148leader_rloc = int(leader.get(wpan.WPAN_THREAD_RLOC16), 0) 149c1_rloc = int(c1.get(wpan.WPAN_THREAD_RLOC16), 0) 150c2_rloc = int(c2.get(wpan.WPAN_THREAD_RLOC16), 0) 151no_rloc = 0xfffe 152 153 154def test_prefix_add_remove(): 155 # Tests adding and removing stable and temporary prefixes on r1 156 # Verifies that all nodes in network do see the updates and that 157 # Network Data version and stable version are updated correctly. 158 159 old_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) 160 old_stable_version = int(leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) 161 162 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 163 # Add a stable prefix and check all nodes see the prefix 164 c1.add_prefix(prefix1, stable=True) 165 166 def check_prefix1(): 167 verify_prefix( 168 [leader, c1, c2], 169 prefix1, 170 c1_rloc, 171 stable=True, 172 ) 173 174 verify_prefix( 175 [c3], 176 prefix1, 177 no_rloc, 178 stable=True, 179 ) 180 181 wpan.verify_within(check_prefix1, WAIT_TIME) 182 183 new_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) 184 new_stable_version = int(leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) 185 186 verify(new_version == ((old_version + 1) % 256)) 187 verify(new_stable_version == ((old_stable_version + 1) % 256)) 188 189 old_version = new_version 190 old_stable_version = new_stable_version 191 192 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 193 # Add prefix 2 as temp (not stable) 194 195 c1.add_prefix(prefix2, stable=False) 196 197 def check_prefix2(): 198 verify_prefix( 199 [leader, c1, c2], 200 prefix2, 201 c1_rloc, 202 stable=False, 203 ) 204 205 wpan.verify_within(check_prefix1, WAIT_TIME) 206 wpan.verify_within(check_prefix2, WAIT_TIME) 207 208 new_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) 209 new_stable_version = int(leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) 210 211 verify(new_version == ((old_version + 1) % 256)) 212 verify(new_stable_version == old_stable_version) 213 214 old_version = new_version 215 old_stable_version = new_stable_version 216 217 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 218 # Remove prefix 1 219 220 c1.remove_prefix(prefix1) 221 222 def check_no_prefix1(): 223 verify_no_prefix([leader, c1, c2], prefix1, c1_rloc) 224 225 wpan.verify_within(check_no_prefix1, WAIT_TIME) 226 wpan.verify_within(check_prefix2, WAIT_TIME) 227 228 new_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) 229 new_stable_version = int(leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) 230 231 verify(new_version == ((old_version + 1) % 256)) 232 verify(new_stable_version == ((old_stable_version + 1) % 256)) 233 234 old_version = new_version 235 old_stable_version = new_stable_version 236 237 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 238 # Remove prefix 2 239 240 c1.remove_prefix(prefix2) 241 242 def check_no_prefix2(): 243 verify_no_prefix([leader, c1, c2], prefix2, c1_rloc) 244 245 wpan.verify_within(check_no_prefix1, WAIT_TIME) 246 wpan.verify_within(check_no_prefix2, WAIT_TIME) 247 248 new_version = int(leader.get(wpan.WPAN_THREAD_NETWORK_DATA_VERSION), 0) 249 new_stable_version = int(leader.get(wpan.WPAN_THREAD_STABLE_NETWORK_DATA_VERSION), 0) 250 251 verify(new_version == ((old_version + 1) % 256)) 252 verify(new_stable_version == old_stable_version) 253 254 255# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 256# Repeat the `test_prefix_add_remove()` under different situations 257# where same prefix is added/removed by other nodes in the network 258# or added as an off-mesh route. 259 260num_routes = 0 261 262test_prefix_add_remove() 263 264leader.add_prefix(prefix1, stable=False) 265test_prefix_add_remove() 266 267leader.add_prefix(prefix2, stable=True) 268test_prefix_add_remove() 269 270leader.remove_prefix(prefix1) 271test_prefix_add_remove() 272 273leader.remove_prefix(prefix2) 274test_prefix_add_remove() 275 276leader.add_route(prefix1, stable=False) 277num_routes = num_routes + 1 278test_prefix_add_remove() 279verify(len(wpan.parse_list(c2.get(wpan.WPAN_THREAD_OFF_MESH_ROUTES))) == num_routes) 280 281leader.add_route(prefix2, stable=True) 282num_routes = num_routes + 1 283test_prefix_add_remove() 284verify(len(wpan.parse_list(c2.get(wpan.WPAN_THREAD_OFF_MESH_ROUTES))) == num_routes) 285 286leader.add_prefix(prefix3, stable=True) 287test_prefix_add_remove() 288verify(len(wpan.parse_list(c2.get(wpan.WPAN_THREAD_OFF_MESH_ROUTES))) == num_routes) 289 290leader.remove_route(prefix2) 291num_routes = num_routes - 1 292test_prefix_add_remove() 293verify(len(wpan.parse_list(c2.get(wpan.WPAN_THREAD_OFF_MESH_ROUTES))) == num_routes) 294 295leader.remove_route(prefix1) 296num_routes = num_routes - 1 297test_prefix_add_remove() 298verify(len(wpan.parse_list(c2.get(wpan.WPAN_THREAD_OFF_MESH_ROUTES))) == num_routes) 299 300# ----------------------------------------------------------------------------------------------------------------------- 301# Test finished 302 303wpan.Node.finalize_all_nodes() 304 305print('\'{}\' passed.'.format(test_name)) 306