xref: /aosp_15_r20/external/openthread/tests/toranj/cli/test-017-network-data-versions.py (revision cfb92d1480a9e65faed56933e9c12405f45898b4)
1#!/usr/bin/env python3
2#
3#  Copyright (c) 2022, 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
29from cli import verify
30from cli import verify_within
31import cli
32import time
33
34# -----------------------------------------------------------------------------------------------------------------------
35# Test description: Network Data update and version changes (stable only vs. full version).
36#
37# Network topology
38#
39#      r1 ---- r2 ---- r3
40#              |
41#              |
42#              sed
43#
44#
45# sed is sleepy-end node and also configured to request stable Network Data only
46#
47# Test covers the following steps:
48# - Adding/removing prefixes (stable or temporary) on r1
49# - Verifying that Network Data is updated on all nodes
50# - Ensuring correct update to version and stable version
51#
52# The above steps are repeated over many different situations:
53# - Where the same prefixes are also added by other nodes
54# - Or the same prefixes are added as off-mesh routes by other nodes
55
56test_name = __file__[:-3] if __file__.endswith('.py') else __file__
57print('-' * 120)
58print('Starting \'{}\''.format(test_name))
59
60# -----------------------------------------------------------------------------------------------------------------------
61# Creating `cli.Node` instances
62
63speedup = 10
64cli.Node.set_time_speedup_factor(speedup)
65
66r1 = cli.Node()
67r2 = cli.Node()
68r3 = cli.Node()
69sed = cli.Node()
70
71# -----------------------------------------------------------------------------------------------------------------------
72# Form topology
73
74r1.allowlist_node(r2)
75
76r2.allowlist_node(r1)
77r2.allowlist_node(r3)
78r2.allowlist_node(sed)
79
80r2.allowlist_node(r2)
81
82sed.allowlist_node(r2)
83
84r1.form('netdata')
85r2.join(r1)
86r3.join(r1)
87sed.join(r1, cli.JOIN_TYPE_SLEEPY_END_DEVICE)
88
89sed.set_mode('-')
90sed.set_pollperiod(400)
91
92# -----------------------------------------------------------------------------------------------------------------------
93# Test Implementation
94
95r1_rloc = r1.get_rloc16()
96r2_rloc = r2.get_rloc16()
97r3_rloc = r3.get_rloc16()
98
99versions = r1.get_netdata_versions()
100
101# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
102
103
104def verify_versions_incremented():
105    global versions
106    new_versions = r1.get_netdata_versions()
107    verify(new_versions[0] == ((versions[0] + 1) % 256))
108    verify(new_versions[1] == ((versions[1] + 1) % 256))
109    versions = new_versions
110
111
112def verify_stabe_version_incremented():
113    global versions
114    new_versions = r1.get_netdata_versions()
115    verify(new_versions[0] == ((versions[0] + 1) % 256))
116    verify(new_versions[1] == versions[1])
117    versions = new_versions
118
119
120# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
121
122# Add prefix `fd00:1::/64` on r1 as stable and validate
123# that entries are updated on all nodes and versions are changed.
124
125r1.add_prefix('fd00:1::/64', 'os')
126r1.register_netdata()
127
128
129def check_r1_prefix_added_on_all_nodes():
130    for node in [r1, r2, r3]:
131        verify('fd00:1:0:0::/64 os med ' + r1_rloc in node.get_netdata_prefixes())
132    verify('fd00:1:0:0::/64 os med fffe' in sed.get_netdata_prefixes())
133
134
135verify_within(check_r1_prefix_added_on_all_nodes, 2)
136verify_versions_incremented()
137
138# Add prefix `fd00:2::/64` on r2 as temporary and ensure it is seen on
139# all nodes and not seen on sed.
140
141r2.add_prefix('fd00:2::/64', 'po', 'high')
142r2.register_netdata()
143
144
145def check_r2_prefix_added_on_all_nodes():
146    for node in [r1, r2, r3]:
147        verify('fd00:2:0:0::/64 po high ' + r2_rloc in node.get_netdata_prefixes())
148    verify(not 'fd00:2:0:0::/64 po high fffe' in sed.get_netdata_prefixes())
149
150
151verify_within(check_r2_prefix_added_on_all_nodes, 2)
152verify_stabe_version_incremented()
153
154# Remove prefix `fd00:1::/64` from r1.
155
156r1.remove_prefix('fd00:1::/64')
157r1.register_netdata()
158
159
160def check_r1_prefix_removed_on_all_nodes():
161    for node in [r1, r2, r3]:
162        verify(not 'fd00:1:0:0::/64 os med ' + r1_rloc in node.get_netdata_prefixes())
163    verify(not 'fd00:1:0:0::/64 os med fffe' in sed.get_netdata_prefixes())
164
165
166verify_within(check_r1_prefix_removed_on_all_nodes, 2)
167verify_versions_incremented()
168
169# Remove prefix `fd00:2::/64` from r2.
170
171r2.remove_prefix('fd00:2::/64')
172r2.register_netdata()
173
174
175def check_r2_prefix_removed_on_all_nodes():
176    for node in [r1, r2, r3]:
177        verify(not 'fd00:2:0:0::/64 po high ' + r2_rloc in node.get_netdata_prefixes())
178    verify(not 'fd00:2:0:0::/64 po high fffe' in sed.get_netdata_prefixes())
179
180
181verify_within(check_r2_prefix_removed_on_all_nodes, 2)
182verify_stabe_version_incremented()
183
184# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
185# Repeat the same checks but now r3 also adds ``fd00:1::/64` with different
186# flags.
187
188r3.add_prefix('fd00:1::/64', 'paos')
189r3.register_netdata()
190
191
192def check_r3_prefix_added_on_all_nodes():
193    for node in [r1, r2, r3]:
194        verify('fd00:1:0:0::/64 paos med ' + r3_rloc in node.get_netdata_prefixes())
195    verify('fd00:1:0:0::/64 paos med fffe' in sed.get_netdata_prefixes())
196
197
198verify_within(check_r3_prefix_added_on_all_nodes, 2)
199verify_versions_incremented()
200
201r1.add_prefix('fd00:1::/64', 'os')
202r1.register_netdata()
203verify_within(check_r1_prefix_added_on_all_nodes, 2)
204verify_versions_incremented()
205
206r2.add_prefix('fd00:2::/64', 'po', 'high')
207r2.register_netdata()
208verify_within(check_r2_prefix_added_on_all_nodes, 2)
209verify_stabe_version_incremented()
210
211r1.remove_prefix('fd00:1::/64')
212r1.register_netdata()
213verify_within(check_r1_prefix_removed_on_all_nodes, 2)
214verify_versions_incremented()
215
216r2.remove_prefix('fd00:2::/64')
217r2.register_netdata()
218verify_within(check_r2_prefix_removed_on_all_nodes, 2)
219verify_stabe_version_incremented()
220
221# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
222# Repeat the same checks with r3 also adding ``fd00:2::/64`
223
224r3.add_prefix('fd00:2::/64', 'paos')
225r3.register_netdata()
226
227
228def check_new_r3_prefix_added_on_all_nodes():
229    for node in [r1, r2, r3]:
230        verify('fd00:2:0:0::/64 paos med ' + r3_rloc in node.get_netdata_prefixes())
231    verify('fd00:2:0:0::/64 paos med fffe' in sed.get_netdata_prefixes())
232
233
234verify_within(check_new_r3_prefix_added_on_all_nodes, 2)
235verify_versions_incremented()
236
237r1.add_prefix('fd00:1::/64', 'os')
238r1.register_netdata()
239verify_within(check_r1_prefix_added_on_all_nodes, 2)
240verify_versions_incremented()
241
242r2.add_prefix('fd00:2::/64', 'po', 'high')
243r2.register_netdata()
244verify_within(check_r2_prefix_added_on_all_nodes, 2)
245verify_stabe_version_incremented()
246
247r1.remove_prefix('fd00:1::/64')
248r1.register_netdata()
249verify_within(check_r1_prefix_removed_on_all_nodes, 2)
250verify_versions_incremented()
251
252r2.remove_prefix('fd00:2::/64')
253r2.register_netdata()
254verify_within(check_r2_prefix_removed_on_all_nodes, 2)
255verify_stabe_version_incremented()
256
257# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
258# Repeat the same checks with r3 adding the two prefixes as temporary.
259
260r3.remove_prefix('fd00:1::/64')
261r3.remove_prefix('fd00:2::/64')
262r3.add_prefix('fd00:1::/64', 'pao')
263r3.add_prefix('fd00:2::/64', 'pao')
264r3.register_netdata()
265
266
267def check_r3_prefixes_as_temp_added_on_all_nodes():
268    for node in [r1, r2, r3]:
269        prefixes = node.get_netdata_prefixes()
270        verify('fd00:1:0:0::/64 pao med ' + r3_rloc in prefixes)
271        verify('fd00:1:0:0::/64 pao med ' + r3_rloc in prefixes)
272    verify(len(sed.get_netdata_prefixes()) == 0)
273
274
275verify_within(check_r3_prefixes_as_temp_added_on_all_nodes, 2)
276verify_versions_incremented()
277
278r1.add_prefix('fd00:1::/64', 'os')
279r1.register_netdata()
280verify_within(check_r1_prefix_added_on_all_nodes, 2)
281verify_versions_incremented()
282
283r2.add_prefix('fd00:2::/64', 'po', 'high')
284r2.register_netdata()
285verify_within(check_r2_prefix_added_on_all_nodes, 2)
286verify_stabe_version_incremented()
287
288r1.remove_prefix('fd00:1::/64')
289r1.register_netdata()
290verify_within(check_r1_prefix_removed_on_all_nodes, 2)
291verify_versions_incremented()
292
293r2.remove_prefix('fd00:2::/64')
294r2.register_netdata()
295verify_within(check_r2_prefix_removed_on_all_nodes, 2)
296verify_stabe_version_incremented()
297
298# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
299# Finally repeat the same checks with r3 adding the two prefixes
300# as off-mesh route prefix.
301
302r3.remove_prefix('fd00:1::/64')
303r3.remove_prefix('fd00:2::/64')
304r3.add_route('fd00:1::/64', 's')
305r3.add_route('fd00:2::/64', '-')
306r3.register_netdata()
307
308
309def check_r3_routes_added_on_all_nodes():
310    for node in [r1, r2, r3]:
311        routes = node.get_netdata_routes()
312        verify('fd00:1:0:0::/64 s med ' + r3_rloc in routes)
313        verify('fd00:2:0:0::/64 med ' + r3_rloc in routes)
314    verify('fd00:1:0:0::/64 s med fffe' in sed.get_netdata_routes())
315    verify(not 'fd00:1:0:0::/64 med fffe' in sed.get_netdata_routes())
316
317
318verify_within(check_r3_routes_added_on_all_nodes, 2)
319verify_versions_incremented()
320
321r1.add_prefix('fd00:1::/64', 'os')
322r1.register_netdata()
323verify_within(check_r1_prefix_added_on_all_nodes, 2)
324verify_versions_incremented()
325
326r2.add_prefix('fd00:2::/64', 'po', 'high')
327r2.register_netdata()
328verify_within(check_r2_prefix_added_on_all_nodes, 2)
329verify_stabe_version_incremented()
330
331r1.remove_prefix('fd00:1::/64')
332r1.register_netdata()
333verify_within(check_r1_prefix_removed_on_all_nodes, 2)
334verify_versions_incremented()
335
336r2.remove_prefix('fd00:2::/64')
337r2.register_netdata()
338verify_within(check_r2_prefix_removed_on_all_nodes, 2)
339verify_stabe_version_incremented()
340
341# -----------------------------------------------------------------------------------------------------------------------
342# Test finished
343
344cli.Node.finalize_all_nodes()
345
346print('\'{}\' passed.'.format(test_name))
347