Skip to content
This repository was archived by the owner on Oct 13, 2025. It is now read-only.

Commit 3b29c48

Browse files
committed
port toranj test-013-off-mesh-route-traffic.py
1 parent 987ce0a commit 3b29c48

1 file changed

Lines changed: 233 additions & 0 deletions

File tree

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
# Copyright 2020 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Test traffic flow to off-mesh addresses resulted from addition of off-mesh routes (on routers and FEDs).
15+
"""
16+
17+
import enum
18+
import random
19+
import time
20+
import unittest
21+
22+
from silk.config import wpan_constants as wpan
23+
from silk.node.wpan_node import WpanCredentials
24+
from silk.utils import process_cleanup
25+
from silk.tools import wpan_table_parser
26+
from silk.tools.wpan_util import verify_within
27+
from silk.unit_tests.test_utils import random_string
28+
import silk.hw.hw_resource as hwr
29+
import silk.node.fifteen_four_dev_board as ffdb
30+
import silk.tests.testcase as testcase
31+
32+
hwr.global_instance()
33+
34+
WAIT_TIME = 10
35+
NUM_ROUTES = 3
36+
NUM_ROUTES_LOCAL = 1
37+
ON_MESH_PREFIX = "fd00:1234::"
38+
OFF_MESH_ROUTE_1 = "fd00:abba::"
39+
OFF_MESH_ROUTE_2 = "fd00:cafe::"
40+
OFF_MESH_ROUTE_3 = "fd00:baba::"
41+
OFF_MESH_ADDR_1 = OFF_MESH_ROUTE_1 + "1"
42+
OFF_MESH_ADDR_2 = OFF_MESH_ROUTE_2 + "2"
43+
OFF_MESH_ADDR_3 = OFF_MESH_ROUTE_3 + "3"
44+
POLL_INTERVAL = 400
45+
46+
47+
class TestOffMeshRouteTraffic(testcase.TestCase):
48+
# Test description: Adding off-mesh routes (on routers and FEDs) and traffic flow to off-mesh addresses.
49+
#
50+
# Test topology:
51+
#
52+
# r1 ---- r2
53+
# | |
54+
# | |
55+
# fed1 sed2
56+
#
57+
# The off-mesh-routes are added as follows:
58+
# - `r1` adds `OFF_MESH_ROUTE_1`,
59+
# - `r2` adds `OFF_MESH_ROUTE_2`,
60+
# - `fed1` adds `OFF_MESH_ROUTE_3`.
61+
#
62+
# Traffic flow:
63+
# - From `sed2` to an address matching `OFF_MESH_ROUTE_1` (verify it is received on `r1`),
64+
# - From `r1` to an address matching `OFF_MESH_ROUTE_2` (verify it is received on `r2`),
65+
# - From `r2` to an address matching `OFF_MESH_ROUTE_3` (verify it is received on `fed1`)
66+
#
67+
68+
@classmethod
69+
def hardware_select(cls: 'TestOffMeshRouteTraffic'):
70+
cls.r1 = ffdb.ThreadDevBoard()
71+
cls.fed1 = ffdb.ThreadDevBoard()
72+
cls.r2 = ffdb.ThreadDevBoard()
73+
cls.sed2 = ffdb.ThreadDevBoard()
74+
75+
cls.all_nodes = [cls.r1, cls.fed1, cls.r2, cls.sed2]
76+
77+
@classmethod
78+
@testcase.setup_class_decorator
79+
def setUpClass(cls: 'TestOffMeshRouteTraffic'):
80+
# Check and clean up wpantund process if any left over
81+
process_cleanup.ps_cleanup()
82+
83+
cls.hardware_select()
84+
85+
for device in cls.all_nodes:
86+
device.set_logger(cls.logger)
87+
cls.add_test_device(device)
88+
device.set_up()
89+
90+
cls.network_data = WpanCredentials(network_name="SILK-{0:04X}".format(random.randint(0, 0xffff)),
91+
psk="00112233445566778899aabbccdd{0:04x}".format(random.randint(0, 0xffff)),
92+
channel=random.randint(11, 25),
93+
fabric_id="{0:06x}dead".format(random.randint(0, 0xffffff)))
94+
95+
cls.thread_sniffer_init(cls.network_data.channel)
96+
97+
@classmethod
98+
@testcase.teardown_class_decorator
99+
def tearDownClass(cls: 'TestOffMeshRouteTraffic'):
100+
for device in cls.device_list:
101+
device.tear_down()
102+
103+
@testcase.setup_decorator
104+
def setUp(self):
105+
pass
106+
107+
@testcase.teardown_decorator
108+
def tearDown(self):
109+
pass
110+
111+
@testcase.test_method_decorator
112+
def test01_disable_autoupdate_interface_address_on_ncp(self):
113+
for node in self.all_nodes:
114+
# Disable `AutoUpdateInterfaceAddrsOnNCP` feature on wpantund
115+
# for all nodes. This ensures that added IPv6 address (on linux
116+
# interface) are not pushed to NCP (and therefore are not
117+
# on-mesh).
118+
node.setprop("Daemon:IPv6:AutoUpdateInterfaceAddrsOnNCP", "false")
119+
self.assertEqual(node.getprop("Daemon:IPv6:AutoUpdateInterfaceAddrsOnNCP"), "false")
120+
121+
@testcase.test_method_decorator
122+
def test02_pairing(self):
123+
# allowlisting between leader and router
124+
self.r1.allowlist_node(self.r2)
125+
self.r2.allowlist_node(self.r1)
126+
127+
# allowlisting between leader and end device
128+
self.r1.allowlist_node(self.fed1)
129+
self.fed1.allowlist_node(self.r1)
130+
131+
# allowlisting between router and sleepy-end-device
132+
self.r2.allowlist_node(self.sed2)
133+
self.sed2.allowlist_node(self.r2)
134+
135+
self.r1.form(self.network_data, "router")
136+
self.r1.permit_join(60)
137+
self.wait_for_completion(self.device_list)
138+
139+
self.logger.info(self.r1.ip6_lla)
140+
self.logger.info(self.r1.ip6_thread_ula)
141+
142+
self.network_data.xpanid = self.r1.xpanid
143+
self.network_data.panid = self.r1.panid
144+
145+
self.r2.join(self.network_data, "router")
146+
self.wait_for_completion(self.device_list)
147+
148+
self.fed1.join(self.network_data, "end-node")
149+
self.wait_for_completion(self.device_list)
150+
151+
self.sed2.join(self.network_data, "sleepy-end-device")
152+
self.sed2.set_sleep_poll_interval(POLL_INTERVAL)
153+
self.wait_for_completion(self.device_list)
154+
155+
@testcase.test_method_decorator
156+
def test03_verify_off_mesh_routes(self):
157+
# Add on-mesh prefix
158+
self.r1.config_gateway(ON_MESH_PREFIX)
159+
160+
# The off-mesh-routes are added as follows:
161+
# - `r1` adds OFF_MESH_ROUTE_1,
162+
# - `r2` adds OFF_MESH_ROUTE_2,
163+
# - `fed1` adds OFF_MESH_ROUTE_3.
164+
165+
self.r1.add_route_using_prefix(OFF_MESH_ROUTE_1)
166+
self.r1.add_ip6_address_on_interface(OFF_MESH_ADDR_1, prefix_len=64)
167+
self.wait_for_completion(self.device_list)
168+
169+
self.r2.add_route_using_prefix(OFF_MESH_ROUTE_2)
170+
self.r2.add_ip6_address_on_interface(OFF_MESH_ADDR_2, prefix_len=64)
171+
self.wait_for_completion(self.device_list)
172+
173+
self.fed1.add_route_using_prefix(OFF_MESH_ROUTE_3)
174+
self.fed1.add_ip6_address_on_interface(OFF_MESH_ADDR_3, prefix_len=64)
175+
self.wait_for_completion(self.device_list)
176+
177+
# Wait till network data is updated on r1, r2, and sed2 and they all see all
178+
# the added off-mesh routes.
179+
time.sleep(WAIT_TIME)
180+
181+
def check_off_mesh_routes():
182+
# If a node itself adds a route, the route entry will be seen twice in
183+
# its WPAN_THREAD_OFF_MESH_ROUTES list (one time as part of network-wide
184+
# network data and again as part of the local network data). Note that
185+
# `r1 and `r2` each add a route, while `sed2` does not.
186+
r1_routes = self.r1.wpanctl("get", "get " + wpan.WPAN_THREAD_OFF_MESH_ROUTES, 2)
187+
r1_routes = wpan_table_parser.parse_list(r1_routes)
188+
self.assertEqual(len(r1_routes), NUM_ROUTES + NUM_ROUTES_LOCAL)
189+
190+
r2_routes = self.r2.wpanctl("get", "get " + wpan.WPAN_THREAD_OFF_MESH_ROUTES, 2)
191+
r2_routes = wpan_table_parser.parse_list(r2_routes)
192+
self.assertEqual(len(r2_routes), NUM_ROUTES + NUM_ROUTES_LOCAL)
193+
194+
sed2_routes = self.sed2.wpanctl("get", "get " + wpan.WPAN_THREAD_OFF_MESH_ROUTES, 2)
195+
sed2_routes = wpan_table_parser.parse_list(sed2_routes)
196+
self.assertEqual(len(sed2_routes), NUM_ROUTES)
197+
198+
verify_within(check_off_mesh_routes, WAIT_TIME)
199+
200+
@testcase.test_method_decorator
201+
def test04_transmit_receive(self):
202+
# Traffic from `sed2` to `OFF_MESH_ADDR_1` (verify that it is received on`r1`).
203+
# Traffic from `r1` to `OFF_MESH_ADDR_2` (verify that it is received on `r2`),
204+
# Traffic from `r2` to `OFF_MESH_ADDR_3` (verify that it is received on `fed1`)
205+
class AddressType(enum.Enum):
206+
Prefix = 0
207+
208+
addresses = [
209+
(self.sed2, self.r1, AddressType.Prefix, OFF_MESH_ADDR_1),
210+
(self.r1, self.r2, AddressType.Prefix, OFF_MESH_ADDR_2),
211+
(self.r2, self.fed1, AddressType.Prefix, OFF_MESH_ADDR_3),
212+
]
213+
214+
timeout = 5
215+
delay = 1
216+
for i, (src, dst, src_type, dst_address) in enumerate(addresses):
217+
port = random.randint(10000 + i * 100, 10099 + i * 100)
218+
message = random_string(10)
219+
src_address = ""
220+
if src_type == AddressType.Prefix:
221+
address = src.find_ip6_address_with_prefix(ON_MESH_PREFIX)
222+
self.wait_for_completion(self.device_list)
223+
src_address = f"{address}%{src.netns}"
224+
225+
dst.receive_udp_data(port, message, timeout)
226+
time.sleep(delay)
227+
src.send_udp_data(dst_address, port, message, src_address)
228+
229+
time.sleep(timeout - delay)
230+
231+
232+
if __name__ == "__main__":
233+
unittest.main()

0 commit comments

Comments
 (0)