1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="
5	ping_ipv4
6	ping_ipv6
7	multipath_test
8	nh_stats_test_v4
9	nh_stats_test_v6
10"
11NUM_NETIFS=8
12source lib.sh
13source router_mpath_nh_lib.sh
14
15h1_create()
16{
17	vrf_create "vrf-h1"
18	ip link set dev $h1 master vrf-h1
19
20	ip link set dev vrf-h1 up
21	ip link set dev $h1 up
22
23	ip address add 192.0.2.2/24 dev $h1
24	ip address add 2001:db8:1::2/64 dev $h1
25
26	ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1
27	ip route add 2001:db8:2::/64 vrf vrf-h1 nexthop via 2001:db8:1::1
28}
29
30h1_destroy()
31{
32	ip route del 2001:db8:2::/64 vrf vrf-h1
33	ip route del 198.51.100.0/24 vrf vrf-h1
34
35	ip address del 2001:db8:1::2/64 dev $h1
36	ip address del 192.0.2.2/24 dev $h1
37
38	ip link set dev $h1 down
39	vrf_destroy "vrf-h1"
40}
41
42h2_create()
43{
44	vrf_create "vrf-h2"
45	ip link set dev $h2 master vrf-h2
46
47	ip link set dev vrf-h2 up
48	ip link set dev $h2 up
49
50	ip address add 198.51.100.2/24 dev $h2
51	ip address add 2001:db8:2::2/64 dev $h2
52
53	ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1
54	ip route add 2001:db8:1::/64 vrf vrf-h2 nexthop via 2001:db8:2::1
55}
56
57h2_destroy()
58{
59	ip route del 2001:db8:1::/64 vrf vrf-h2
60	ip route del 192.0.2.0/24 vrf vrf-h2
61
62	ip address del 2001:db8:2::2/64 dev $h2
63	ip address del 198.51.100.2/24 dev $h2
64
65	ip link set dev $h2 down
66	vrf_destroy "vrf-h2"
67}
68
69router1_create()
70{
71	vrf_create "vrf-r1"
72	ip link set dev $rp11 master vrf-r1
73	ip link set dev $rp12 master vrf-r1
74	ip link set dev $rp13 master vrf-r1
75
76	ip link set dev vrf-r1 up
77	ip link set dev $rp11 up
78	ip link set dev $rp12 up
79	ip link set dev $rp13 up
80
81	ip address add 192.0.2.1/24 dev $rp11
82	ip address add 2001:db8:1::1/64 dev $rp11
83
84	ip address add 169.254.2.12/24 dev $rp12
85	ip address add fe80:2::12/64 dev $rp12
86
87	ip address add 169.254.3.13/24 dev $rp13
88	ip address add fe80:3::13/64 dev $rp13
89}
90
91router1_destroy()
92{
93	ip route del 2001:db8:2::/64 vrf vrf-r1
94	ip route del 198.51.100.0/24 vrf vrf-r1
95
96	ip address del fe80:3::13/64 dev $rp13
97	ip address del 169.254.3.13/24 dev $rp13
98
99	ip address del fe80:2::12/64 dev $rp12
100	ip address del 169.254.2.12/24 dev $rp12
101
102	ip address del 2001:db8:1::1/64 dev $rp11
103	ip address del 192.0.2.1/24 dev $rp11
104
105	ip nexthop del id 103
106	ip nexthop del id 101
107	ip nexthop del id 102
108	ip nexthop del id 106
109	ip nexthop del id 104
110	ip nexthop del id 105
111
112	ip link set dev $rp13 down
113	ip link set dev $rp12 down
114	ip link set dev $rp11 down
115
116	vrf_destroy "vrf-r1"
117}
118
119router2_create()
120{
121	vrf_create "vrf-r2"
122	ip link set dev $rp21 master vrf-r2
123	ip link set dev $rp22 master vrf-r2
124	ip link set dev $rp23 master vrf-r2
125
126	ip link set dev vrf-r2 up
127	ip link set dev $rp21 up
128	ip link set dev $rp22 up
129	ip link set dev $rp23 up
130
131	ip address add 198.51.100.1/24 dev $rp21
132	ip address add 2001:db8:2::1/64 dev $rp21
133
134	ip address add 169.254.2.22/24 dev $rp22
135	ip address add fe80:2::22/64 dev $rp22
136
137	ip address add 169.254.3.23/24 dev $rp23
138	ip address add fe80:3::23/64 dev $rp23
139}
140
141router2_destroy()
142{
143	ip route del 2001:db8:1::/64 vrf vrf-r2
144	ip route del 192.0.2.0/24 vrf vrf-r2
145
146	ip address del fe80:3::23/64 dev $rp23
147	ip address del 169.254.3.23/24 dev $rp23
148
149	ip address del fe80:2::22/64 dev $rp22
150	ip address del 169.254.2.22/24 dev $rp22
151
152	ip address del 2001:db8:2::1/64 dev $rp21
153	ip address del 198.51.100.1/24 dev $rp21
154
155	ip nexthop del id 201
156	ip nexthop del id 202
157	ip nexthop del id 204
158	ip nexthop del id 205
159
160	ip link set dev $rp23 down
161	ip link set dev $rp22 down
162	ip link set dev $rp21 down
163
164	vrf_destroy "vrf-r2"
165}
166
167routing_nh_obj()
168{
169	ip nexthop add id 101 via 169.254.2.22 dev $rp12
170	ip nexthop add id 102 via 169.254.3.23 dev $rp13
171	ip nexthop add id 103 group 101/102 type resilient buckets 512 \
172		idle_timer 0
173	ip route add 198.51.100.0/24 vrf vrf-r1 nhid 103
174
175	ip nexthop add id 104 via fe80:2::22 dev $rp12
176	ip nexthop add id 105 via fe80:3::23 dev $rp13
177	ip nexthop add id 106 group 104/105 type resilient buckets 512 \
178		idle_timer 0
179	ip route add 2001:db8:2::/64 vrf vrf-r1 nhid 106
180
181	ip nexthop add id 201 via 169.254.2.12 dev $rp22
182	ip nexthop add id 202 via 169.254.3.13 dev $rp23
183	ip nexthop add id 203 group 201/202 type resilient buckets 512 \
184		idle_timer 0
185	ip route add 192.0.2.0/24 vrf vrf-r2 nhid 203
186
187	ip nexthop add id 204 via fe80:2::12 dev $rp22
188	ip nexthop add id 205 via fe80:3::13 dev $rp23
189	ip nexthop add id 206 group 204/205 type resilient buckets 512 \
190		idle_timer 0
191	ip route add 2001:db8:1::/64 vrf vrf-r2 nhid 206
192}
193
194multipath4_test()
195{
196	local desc="$1"
197	local weight_rp12=$2
198	local weight_rp13=$3
199	local t0_rp12 t0_rp13 t1_rp12 t1_rp13
200	local packets_rp12 packets_rp13
201
202	# Transmit multiple flows from h1 to h2 and make sure they are
203	# distributed between both multipath links (rp12 and rp13)
204	# according to the provided weights.
205	sysctl_set net.ipv4.fib_multipath_hash_policy 1
206
207	t0_rp12=$(link_stats_tx_packets_get $rp12)
208	t0_rp13=$(link_stats_tx_packets_get $rp13)
209
210	ip vrf exec vrf-h1 $MZ $h1 -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \
211		-d $MZ_DELAY -t udp "sp=1024,dp=0-32768"
212
213	t1_rp12=$(link_stats_tx_packets_get $rp12)
214	t1_rp13=$(link_stats_tx_packets_get $rp13)
215
216	let "packets_rp12 = $t1_rp12 - $t0_rp12"
217	let "packets_rp13 = $t1_rp13 - $t0_rp13"
218	multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13
219
220	# Restore settings.
221	sysctl_restore net.ipv4.fib_multipath_hash_policy
222}
223
224multipath6_l4_test()
225{
226	local desc="$1"
227	local weight_rp12=$2
228	local weight_rp13=$3
229	local t0_rp12 t0_rp13 t1_rp12 t1_rp13
230	local packets_rp12 packets_rp13
231
232	# Transmit multiple flows from h1 to h2 and make sure they are
233	# distributed between both multipath links (rp12 and rp13)
234	# according to the provided weights.
235	sysctl_set net.ipv6.fib_multipath_hash_policy 1
236
237	t0_rp12=$(link_stats_tx_packets_get $rp12)
238	t0_rp13=$(link_stats_tx_packets_get $rp13)
239
240	$MZ $h1 -6 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \
241		-d $MZ_DELAY -t udp "sp=1024,dp=0-32768"
242
243	t1_rp12=$(link_stats_tx_packets_get $rp12)
244	t1_rp13=$(link_stats_tx_packets_get $rp13)
245
246	let "packets_rp12 = $t1_rp12 - $t0_rp12"
247	let "packets_rp13 = $t1_rp13 - $t0_rp13"
248	multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13
249
250	sysctl_restore net.ipv6.fib_multipath_hash_policy
251}
252
253multipath_test()
254{
255	# Without an idle timer, weight replacement should happen immediately.
256	log_info "Running multipath tests without an idle timer"
257	ip nexthop replace id 103 group 101/102 type resilient idle_timer 0
258	ip nexthop replace id 106 group 104/105 type resilient idle_timer 0
259
260	log_info "Running IPv4 multipath tests"
261	ip nexthop replace id 103 group 101,1/102,1 type resilient
262	multipath4_test "ECMP" 1 1
263	ip nexthop replace id 103 group 101,2/102,1 type resilient
264	multipath4_test "Weighted MP 2:1" 2 1
265	ip nexthop replace id 103 group 101,11/102,45 type resilient
266	multipath4_test "Weighted MP 11:45" 11 45
267
268	ip nexthop replace id 103 group 101,1/102,1 type resilient
269
270	log_info "Running IPv6 L4 hash multipath tests"
271	ip nexthop replace id 106 group 104,1/105,1 type resilient
272	multipath6_l4_test "ECMP" 1 1
273	ip nexthop replace id 106 group 104,2/105,1 type resilient
274	multipath6_l4_test "Weighted MP 2:1" 2 1
275	ip nexthop replace id 106 group 104,11/105,45 type resilient
276	multipath6_l4_test "Weighted MP 11:45" 11 45
277
278	ip nexthop replace id 106 group 104,1/105,1 type resilient
279
280	# With an idle timer, weight replacement should not happen, so the
281	# expected ratio should always be the initial one (1:1).
282	log_info "Running multipath tests with an idle timer of 120 seconds"
283	ip nexthop replace id 103 group 101/102 type resilient idle_timer 120
284	ip nexthop replace id 106 group 104/105 type resilient idle_timer 120
285
286	log_info "Running IPv4 multipath tests"
287	ip nexthop replace id 103 group 101,1/102,1 type resilient
288	multipath4_test "ECMP" 1 1
289	ip nexthop replace id 103 group 101,2/102,1 type resilient
290	multipath4_test "Weighted MP 2:1" 1 1
291	ip nexthop replace id 103 group 101,11/102,45 type resilient
292	multipath4_test "Weighted MP 11:45" 1 1
293
294	ip nexthop replace id 103 group 101,1/102,1 type resilient
295
296	log_info "Running IPv6 L4 hash multipath tests"
297	ip nexthop replace id 106 group 104,1/105,1 type resilient
298	multipath6_l4_test "ECMP" 1 1
299	ip nexthop replace id 106 group 104,2/105,1 type resilient
300	multipath6_l4_test "Weighted MP 2:1" 1 1
301	ip nexthop replace id 106 group 104,11/105,45 type resilient
302	multipath6_l4_test "Weighted MP 11:45" 1 1
303
304	ip nexthop replace id 106 group 104,1/105,1 type resilient
305
306	# With a short idle timer and enough idle time, weight replacement
307	# should happen.
308	log_info "Running multipath tests with an idle timer of 5 seconds"
309	ip nexthop replace id 103 group 101/102 type resilient idle_timer 5
310	ip nexthop replace id 106 group 104/105 type resilient idle_timer 5
311
312	log_info "Running IPv4 multipath tests"
313	sleep 10
314	ip nexthop replace id 103 group 101,1/102,1 type resilient
315	multipath4_test "ECMP" 1 1
316	sleep 10
317	ip nexthop replace id 103 group 101,2/102,1 type resilient
318	multipath4_test "Weighted MP 2:1" 2 1
319	sleep 10
320	ip nexthop replace id 103 group 101,11/102,45 type resilient
321	multipath4_test "Weighted MP 11:45" 11 45
322
323	ip nexthop replace id 103 group 101,1/102,1 type resilient
324
325	log_info "Running IPv6 L4 hash multipath tests"
326	sleep 10
327	ip nexthop replace id 106 group 104,1/105,1 type resilient
328	multipath6_l4_test "ECMP" 1 1
329	sleep 10
330	ip nexthop replace id 106 group 104,2/105,1 type resilient
331	multipath6_l4_test "Weighted MP 2:1" 2 1
332	sleep 10
333	ip nexthop replace id 106 group 104,11/105,45 type resilient
334	multipath6_l4_test "Weighted MP 11:45" 11 45
335
336	ip nexthop replace id 106 group 104,1/105,1 type resilient
337}
338
339nh_stats_test_v4()
340{
341	__nh_stats_test_v4 resilient
342}
343
344nh_stats_test_v6()
345{
346	__nh_stats_test_v6 resilient
347}
348
349setup_prepare()
350{
351	h1=${NETIFS[p1]}
352	rp11=${NETIFS[p2]}
353
354	rp12=${NETIFS[p3]}
355	rp22=${NETIFS[p4]}
356
357	rp13=${NETIFS[p5]}
358	rp23=${NETIFS[p6]}
359
360	rp21=${NETIFS[p7]}
361	h2=${NETIFS[p8]}
362
363	vrf_prepare
364
365	h1_create
366	h2_create
367
368	router1_create
369	router2_create
370
371	forwarding_enable
372}
373
374cleanup()
375{
376	pre_cleanup
377
378	forwarding_restore
379
380	router2_destroy
381	router1_destroy
382
383	h2_destroy
384	h1_destroy
385
386	vrf_cleanup
387}
388
389ping_ipv4()
390{
391	ping_test $h1 198.51.100.2
392}
393
394ping_ipv6()
395{
396	ping6_test $h1 2001:db8:2::2
397}
398
399ip nexthop ls >/dev/null 2>&1
400if [ $? -ne 0 ]; then
401	echo "Nexthop objects not supported; skipping tests"
402	exit $ksft_skip
403fi
404
405trap cleanup EXIT
406
407setup_prepare
408setup_wait
409routing_nh_obj
410
411tests_run
412
413exit $EXIT_STATUS
414