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: Multicast traffic 35# 36# Network topology 37# 38# r1 ---- r2 ---- r3 ---- r4 39# | | 40# | | 41# fed sed 42# 43# Test covers the following multicast traffic: 44# 45# - r2 =>> link-local all-nodes. Expected to receive on [r1, r2, r3, fed]. 46# - r3 =>> mesh-local all-nodes. Expected to receive on [r1, r2, r3, r4, fed]. 47# - r3 =>> link-local all-routers. Expected to receive on [r2, r3, r4]. 48# - r3 =>> mesh-local all-routers. Expected to receive on all routers. 49# - r1 =>> link-local all-thread. Expected to receive on [r1, r2]. 50# - fed =>> mesh-local all-thread. Expected to receive on all nodes. 51# - r1 =>> specific address (on r2 and sed). Expected to receive on [r2, sed]. 52# - Check behavior with different multicast hop limit values (1-hop up to 4-hops). 53# 54 55test_name = __file__[:-3] if __file__.endswith('.py') else __file__ 56print('-' * 120) 57print('Starting \'{}\''.format(test_name)) 58 59# ----------------------------------------------------------------------------------------------------------------------- 60# Utility functions 61 62 63def send_mcast( 64 src_node, 65 src_addr, 66 mcast_addr, 67 recving_nodes, 68 non_recving_nodes=[], 69 msg_len=30, 70 mcast_hops=5, 71): 72 """ 73 Send a multicast message with given `len` from `src_node` using `src_addr` to the multicast address `mcast_addr`. 74 Verify that the message is received on all nodes in `recving_nodes` list and that it is not received on all 75 nodes in `non_recving_nodes` list. 76 """ 77 sender = src_node.prepare_tx(src_addr, mcast_addr, msg_len, mcast_hops=mcast_hops) 78 recvers = [node.prepare_rx(sender) for node in recving_nodes] 79 listeners = [node.prepare_listener(sender.dst_port, timeout=0.5) for node in non_recving_nodes] 80 81 wpan.Node.perform_async_tx_rx() 82 83 verify(sender.was_successful) 84 for recvr in recvers: 85 verify(recvr.was_successful) 86 for lsnr in listeners: 87 # `all_rx_msg` contains a list of (msg_content, (src_addr, src_port)). 88 verify( 89 len(lsnr.all_rx_msg) == 0 or 90 all([msg[1][0] != sender.src_addr and msg[1][1] != sender.src_port for msg in lsnr.all_rx_msg])) 91 92 93# ----------------------------------------------------------------------------------------------------------------------- 94# Creating `wpan.Nodes` instances 95 96speedup = 4 97wpan.Node.set_time_speedup_factor(speedup) 98 99r1 = wpan.Node() 100r2 = wpan.Node() 101r3 = wpan.Node() 102r4 = wpan.Node() 103fed = wpan.Node() 104sed = wpan.Node() 105 106all_routers = [r1, r2, r3, r4] 107all_nodes = all_routers + [fed, sed] 108 109# ----------------------------------------------------------------------------------------------------------------------- 110# Init all nodes 111 112wpan.Node.init_all_nodes() 113 114# ----------------------------------------------------------------------------------------------------------------------- 115# Build network topology 116# 117# Test topology: 118# 119# r1 ---- r2 ---- r3 ---- r4 120# | | 121# | | 122# fed sed 123# 124 125r1.form("mcast-traffic") 126 127r1.allowlist_node(r2) 128r2.allowlist_node(r1) 129r2.join_node(r1, wpan.JOIN_TYPE_ROUTER) 130 131r2.allowlist_node(fed) 132fed.allowlist_node(r2) 133fed.join_node(r2, wpan.JOIN_TYPE_END_DEVICE) 134 135r2.allowlist_node(r3) 136r3.allowlist_node(r2) 137r3.join_node(r2, wpan.JOIN_TYPE_ROUTER) 138 139r3.allowlist_node(r4) 140r4.allowlist_node(r3) 141r4.join_node(r3, wpan.JOIN_TYPE_ROUTER) 142 143r4.allowlist_node(sed) 144sed.allowlist_node(r4) 145sed.join_node(r4, wpan.JOIN_TYPE_SLEEPY_END_DEVICE) 146sed.set(wpan.WPAN_POLL_INTERVAL, '600') 147 148# ----------------------------------------------------------------------------------------------------------------------- 149# Test implementation 150 151ml1 = r1.get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] 152ll1 = r1.get(wpan.WPAN_IP6_LINK_LOCAL_ADDRESS)[1:-1] 153 154ml2 = r2.get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] 155ll2 = r2.get(wpan.WPAN_IP6_LINK_LOCAL_ADDRESS)[1:-1] 156 157ml3 = r3.get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] 158ll3 = r3.get(wpan.WPAN_IP6_LINK_LOCAL_ADDRESS)[1:-1] 159 160ml4 = r4.get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] 161ll4 = r4.get(wpan.WPAN_IP6_LINK_LOCAL_ADDRESS)[1:-1] 162 163ml_fed = fed.get(wpan.WPAN_IP6_MESH_LOCAL_ADDRESS)[1:-1] 164ll_fed = fed.get(wpan.WPAN_IP6_LINK_LOCAL_ADDRESS)[1:-1] 165 166# Multicast addresses 167 168ll_all_nodes = "ff02::1" 169ml_all_nodes = "ff03::1" 170ml_all_mlp_fwder_nodes = "ff03::fc" 171 172ll_all_routers = "ff02::2" 173ml_all_routers = "ff03::2" 174 175ml_prefix = r1.get(wpan.WPAN_IP6_MESH_LOCAL_PREFIX)[1:-1].split('/')[0] 176ll_all_thread_nodes_addr = 'ff32:40:' + ml_prefix + '1' 177ml_all_thread_nodes_addr = 'ff33:40:' + ml_prefix + '1' 178 179# 180# r1 ---- r2 ---- r3 ---- r4 181# | | 182# | | 183# fed sed 184# 185 186# r2 =>> link-local all-nodes. 187send_mcast(r2, ll2, ll_all_nodes, [r1, r2, r3, fed], [r4, sed]) 188 189# r3 =>> mesh-local all-nodes. 190send_mcast(r3, ml3, ml_all_nodes, [r1, r2, r3, r4, fed]) 191 192# r3 =>> link-local all-routers. 193send_mcast(r3, ml3, ll_all_routers, [r2, r3, r4], [r1, fed, sed]) 194 195# r3 =>> mesh-local all-routers. 196send_mcast(r3, ml3, ml_all_routers, all_routers, [sed]) 197 198# r1 =>> link-local all-thread. 199send_mcast(r1, ll1, ll_all_thread_nodes_addr, [r1, r2], [fed, r3, r4, sed]) 200 201# fed =>> mesh-local all-thread. 202send_mcast(fed, ml_fed, ml_all_thread_nodes_addr, all_nodes) 203 204# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 205# Send a large multicast message (requiring MAC level fragmentations) 206 207send_mcast(r3, ml3, ml_all_thread_nodes_addr, all_nodes, msg_len=400) 208 209# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 210# Check the hop limit behavior 211 212# r1 =>> mesh-local all-thread (one hop) 213send_mcast( 214 r1, 215 ml1, 216 ml_all_thread_nodes_addr, 217 [r1, r2], 218 [fed, r3, r4, sed], 219 mcast_hops=1, 220) 221 222# r1 =>> mesh-local all-thread (two hops) 223send_mcast( 224 r1, 225 ml1, 226 ml_all_thread_nodes_addr, 227 [r1, r2, fed, r3], 228 [r4, sed], 229 mcast_hops=2, 230) 231 232# r1 =>> mesh-local all-thread (three hops) 233send_mcast( 234 r1, 235 ml1, 236 ml_all_thread_nodes_addr, 237 [r1, r2, fed, r3, r4], 238 [sed], 239 mcast_hops=3, 240) 241 242# r1 =>> mesh-local all-thread (four hops) 243send_mcast(r1, ml1, ml_all_thread_nodes_addr, [r1, r2, fed, r3, r4, sed], mcast_hops=4) 244 245# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 246# Subscribe to a specific multicast address on r2 and sed 247 248mcast_addr = "ff03::114" 249r2.add(wpan.WPAN_IP6_MULTICAST_ADDRESSES, mcast_addr) 250sed.add(wpan.WPAN_IP6_MULTICAST_ADDRESSES, mcast_addr) 251time.sleep(1) 252 253# r1 =>> specific address 254send_mcast(r1, ml1, mcast_addr, [r2, sed], [r1, r3, r4, fed]) 255 256# ----------------------------------------------------------------------------------------------------------------------- 257# Test finished 258 259wpan.Node.finalize_all_nodes() 260 261print('\'{}\' passed.'.format(test_name)) 262