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