xref: /linux/tools/testing/selftests/net/fib_nexthops.sh (revision 26ba30221c03364d6ed9910be8da4c1fd871b07b)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# ns: me               | ns: peer              | ns: remote
5#   2001:db8:91::1     |       2001:db8:91::2  |
6#   172.16.1.1         |       172.16.1.2      |
7#            veth1 <---|---> veth2             |
8#                      |              veth5 <--|--> veth6  172.16.101.1
9#            veth3 <---|---> veth4             |           2001:db8:101::1
10#   172.16.2.1         |       172.16.2.2      |
11#   2001:db8:92::1     |       2001:db8:92::2  |
12#
13# This test is for checking IPv4 and IPv6 FIB behavior with nexthop
14# objects. Device reference counts and network namespace cleanup tested
15# by use of network namespace for peer.
16
17source lib.sh
18ret=0
19# Kselftest framework requirement - SKIP code is 4.
20ksft_skip=4
21
22# all tests in this script. Can be overridden with -t option
23IPV4_TESTS="
24	ipv4_fcnal
25	ipv4_grp_fcnal
26	ipv4_res_grp_fcnal
27	ipv4_withv6_fcnal
28	ipv4_fcnal_runtime
29	ipv4_large_grp
30	ipv4_large_res_grp
31	ipv4_compat_mode
32	ipv4_fdb_grp_fcnal
33	ipv4_fdb_port_fcnal
34	ipv4_mpath_select
35	ipv4_torture
36	ipv4_res_torture
37"
38
39IPV6_TESTS="
40	ipv6_fcnal
41	ipv6_grp_fcnal
42	ipv6_res_grp_fcnal
43	ipv6_fcnal_runtime
44	ipv6_large_grp
45	ipv6_large_res_grp
46	ipv6_compat_mode
47	ipv6_fdb_grp_fcnal
48	ipv6_fdb_port_fcnal
49	ipv6_mpath_select
50	ipv6_torture
51	ipv6_res_torture
52"
53
54ALL_TESTS="
55	basic
56	basic_res
57	${IPV4_TESTS}
58	${IPV6_TESTS}
59"
60TESTS="${ALL_TESTS}"
61VERBOSE=0
62PAUSE_ON_FAIL=no
63PAUSE=no
64PING_TIMEOUT=5
65
66nsid=100
67
68################################################################################
69# utilities
70
71log_test()
72{
73	local rc=$1
74	local expected=$2
75	local msg="$3"
76
77	if [ ${rc} -eq ${expected} ]; then
78		printf "TEST: %-60s  [ OK ]\n" "${msg}"
79		nsuccess=$((nsuccess+1))
80	else
81		if [[ $rc -eq $ksft_skip ]]; then
82			[[ $ret -eq 0 ]] && ret=$ksft_skip
83			nskip=$((nskip+1))
84			printf "TEST: %-60s  [SKIP]\n" "${msg}"
85		else
86			ret=1
87			nfail=$((nfail+1))
88			printf "TEST: %-60s  [FAIL]\n" "${msg}"
89		fi
90
91		if [ "$VERBOSE" = "1" ]; then
92			echo "    rc=$rc, expected $expected"
93		fi
94
95		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
96		echo
97			echo "hit enter to continue, 'q' to quit"
98			read a
99			[ "$a" = "q" ] && exit 1
100		fi
101	fi
102
103	if [ "${PAUSE}" = "yes" ]; then
104		echo
105		echo "hit enter to continue, 'q' to quit"
106		read a
107		[ "$a" = "q" ] && exit 1
108	fi
109
110	[ "$VERBOSE" = "1" ] && echo
111}
112
113run_cmd()
114{
115	local cmd="$1"
116	local out
117	local stderr="2>/dev/null"
118
119	if [ "$VERBOSE" = "1" ]; then
120		printf "COMMAND: $cmd\n"
121		stderr=
122	fi
123
124	out=$(eval $cmd $stderr)
125	rc=$?
126	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
127		echo "    $out"
128	fi
129
130	return $rc
131}
132
133get_linklocal()
134{
135	local dev=$1
136	local ns
137	local addr
138
139	[ -n "$2" ] && ns="-netns $2"
140	addr=$(ip $ns -6 -br addr show dev ${dev} | \
141	awk '{
142		for (i = 3; i <= NF; ++i) {
143			if ($i ~ /^fe80/)
144				print $i
145		}
146	}'
147	)
148	addr=${addr/\/*}
149
150	[ -z "$addr" ] && return 1
151
152	echo $addr
153
154	return 0
155}
156
157create_ns()
158{
159	local n=${1}
160
161	set -e
162
163	ip netns exec ${n} sysctl -qw net.ipv4.ip_forward=1
164	ip netns exec ${n} sysctl -qw net.ipv4.fib_multipath_use_neigh=1
165	ip netns exec ${n} sysctl -qw net.ipv4.conf.default.ignore_routes_with_linkdown=1
166	ip netns exec ${n} sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
167	ip netns exec ${n} sysctl -qw net.ipv6.conf.all.forwarding=1
168	ip netns exec ${n} sysctl -qw net.ipv6.conf.default.forwarding=1
169	ip netns exec ${n} sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1
170	ip netns exec ${n} sysctl -qw net.ipv6.conf.all.accept_dad=0
171	ip netns exec ${n} sysctl -qw net.ipv6.conf.default.accept_dad=0
172
173	set +e
174}
175
176setup()
177{
178	cleanup
179
180	setup_ns me peer remote
181	create_ns $me
182	create_ns $peer
183	create_ns $remote
184
185	IP="ip -netns $me"
186	BRIDGE="bridge -netns $me"
187	set -e
188	$IP li add veth1 type veth peer name veth2
189	$IP li set veth1 up
190	$IP addr add 172.16.1.1/24 dev veth1
191	$IP -6 addr add 2001:db8:91::1/64 dev veth1 nodad
192
193	$IP li add veth3 type veth peer name veth4
194	$IP li set veth3 up
195	$IP addr add 172.16.2.1/24 dev veth3
196	$IP -6 addr add 2001:db8:92::1/64 dev veth3 nodad
197
198	$IP li set veth2 netns $peer up
199	ip -netns $peer addr add 172.16.1.2/24 dev veth2
200	ip -netns $peer -6 addr add 2001:db8:91::2/64 dev veth2 nodad
201
202	$IP li set veth4 netns $peer up
203	ip -netns $peer addr add 172.16.2.2/24 dev veth4
204	ip -netns $peer -6 addr add 2001:db8:92::2/64 dev veth4 nodad
205
206	ip -netns $remote li add veth5 type veth peer name veth6
207	ip -netns $remote li set veth5 up
208	ip -netns $remote addr add dev veth5 172.16.101.1/24
209	ip -netns $remote -6 addr add dev veth5 2001:db8:101::1/64 nodad
210	ip -netns $remote ro add 172.16.0.0/22 via 172.16.101.2
211	ip -netns $remote -6 ro add 2001:db8:90::/40 via 2001:db8:101::2
212
213	ip -netns $remote li set veth6 netns $peer up
214	ip -netns $peer addr add dev veth6 172.16.101.2/24
215	ip -netns $peer -6 addr add dev veth6 2001:db8:101::2/64 nodad
216	set +e
217}
218
219cleanup()
220{
221	local ns
222
223	for ns in $me $peer $remote; do
224		ip netns del ${ns} 2>/dev/null
225	done
226}
227
228check_output()
229{
230	local out="$1"
231	local expected="$2"
232	local rc=0
233
234	[ "${out}" = "${expected}" ] && return 0
235
236	if [ -z "${out}" ]; then
237		if [ "$VERBOSE" = "1" ]; then
238			printf "\nNo entry found\n"
239			printf "Expected:\n"
240			printf "    ${expected}\n"
241		fi
242		return 1
243	fi
244
245	out=$(echo ${out})
246	if [ "${out}" != "${expected}" ]; then
247		rc=1
248		if [ "${VERBOSE}" = "1" ]; then
249			printf "    Unexpected entry. Have:\n"
250			printf "        ${out}\n"
251			printf "    Expected:\n"
252			printf "        ${expected}\n\n"
253		else
254			echo "      WARNING: Unexpected route entry"
255		fi
256	fi
257
258	return $rc
259}
260
261check_nexthop()
262{
263	local nharg="$1"
264	local expected="$2"
265	local out
266
267	out=$($IP nexthop ls ${nharg} 2>/dev/null)
268
269	check_output "${out}" "${expected}"
270}
271
272check_nexthop_bucket()
273{
274	local nharg="$1"
275	local expected="$2"
276	local out
277
278	# remove the idle time since we cannot match it
279	out=$($IP nexthop bucket ${nharg} \
280		| sed s/idle_time\ [0-9.]*\ // 2>/dev/null)
281
282	check_output "${out}" "${expected}"
283}
284
285check_route()
286{
287	local pfx="$1"
288	local expected="$2"
289	local out
290
291	out=$($IP route ls match ${pfx} 2>/dev/null)
292
293	check_output "${out}" "${expected}"
294}
295
296check_route6()
297{
298	local pfx="$1"
299	local expected="$2"
300	local out
301
302	out=$($IP -6 route ls match ${pfx} 2>/dev/null | sed -e 's/pref medium//')
303
304	check_output "${out}" "${expected}"
305}
306
307check_large_grp()
308{
309	local ipv=$1
310	local ecmp=$2
311	local grpnum=100
312	local nhidstart=100
313	local grpidstart=1000
314	local iter=0
315	local nhidstr=""
316	local grpidstr=""
317	local grpstr=""
318	local ipstr=""
319
320	if [ $ipv -eq 4 ]; then
321		ipstr="172.16.1."
322	else
323		ipstr="2001:db8:91::"
324	fi
325
326	#
327	# Create $grpnum groups with specified $ecmp and dump them
328	#
329
330	# create nexthops with different gateways
331	iter=2
332	while [ $iter -le $(($ecmp + 1)) ]
333	do
334		nhidstr="$(($nhidstart + $iter))"
335		run_cmd "$IP nexthop add id $nhidstr via $ipstr$iter dev veth1"
336		check_nexthop "id $nhidstr" "id $nhidstr via $ipstr$iter dev veth1 scope link"
337
338		if [ $iter -le $ecmp ]; then
339			grpstr+="$nhidstr/"
340		else
341			grpstr+="$nhidstr"
342		fi
343		((iter++))
344	done
345
346	# create duplicate large ecmp groups
347	iter=0
348	while [ $iter -le $grpnum ]
349	do
350		grpidstr="$(($grpidstart + $iter))"
351		run_cmd "$IP nexthop add id $grpidstr group $grpstr"
352		check_nexthop "id $grpidstr" "id $grpidstr group $grpstr"
353		((iter++))
354	done
355
356	# dump large groups
357	run_cmd "$IP nexthop list"
358	log_test $? 0 "Dump large (x$ecmp) ecmp groups"
359}
360
361check_large_res_grp()
362{
363	local ipv=$1
364	local buckets=$2
365	local ipstr=""
366
367	if [ $ipv -eq 4 ]; then
368		ipstr="172.16.1.2"
369	else
370		ipstr="2001:db8:91::2"
371	fi
372
373	# create a resilient group with $buckets buckets and dump them
374	run_cmd "$IP nexthop add id 100 via $ipstr dev veth1"
375	run_cmd "$IP nexthop add id 1000 group 100 type resilient buckets $buckets"
376	run_cmd "$IP nexthop bucket list"
377	log_test $? 0 "Dump large (x$buckets) nexthop buckets"
378}
379
380get_route_dev()
381{
382	local pfx="$1"
383	local out
384
385	if out=$($IP -j route get "$pfx" | jq -re ".[0].dev"); then
386		echo "$out"
387	fi
388}
389
390check_route_dev()
391{
392	local pfx="$1"
393	local expected="$2"
394	local out
395
396	out=$(get_route_dev "$pfx")
397
398	check_output "$out" "$expected"
399}
400
401start_ip_monitor()
402{
403	local mtype=$1
404
405	# start the monitor in the background
406	tmpfile=`mktemp /var/run/nexthoptestXXX`
407	mpid=`($IP monitor $mtype > $tmpfile & echo $!) 2>/dev/null`
408	sleep 0.2
409	echo "$mpid $tmpfile"
410}
411
412stop_ip_monitor()
413{
414	local mpid=$1
415	local tmpfile=$2
416	local el=$3
417
418	# check the monitor results
419	kill $mpid
420	lines=`wc -l $tmpfile | cut "-d " -f1`
421	test $lines -eq $el
422	rc=$?
423	rm -rf $tmpfile
424
425	return $rc
426}
427
428check_nexthop_fdb_support()
429{
430	$IP nexthop help 2>&1 | grep -q fdb
431	if [ $? -ne 0 ]; then
432		echo "SKIP: iproute2 too old, missing fdb nexthop support"
433		return $ksft_skip
434	fi
435}
436
437check_nexthop_fdb_port_support()
438{
439	$IP nexthop help 2>&1 | grep -q "dst_port"
440	if [ $? -ne 0 ]; then
441		echo "SKIP: iproute2 too old, missing nexthop dst_port support"
442		return $ksft_skip
443	fi
444}
445
446check_nexthop_res_support()
447{
448	$IP nexthop help 2>&1 | grep -q resilient
449	if [ $? -ne 0 ]; then
450		echo "SKIP: iproute2 too old, missing resilient nexthop group support"
451		return $ksft_skip
452	fi
453}
454
455ipv6_fdb_grp_fcnal()
456{
457	local rc
458
459	echo
460	echo "IPv6 fdb groups functional"
461	echo "--------------------------"
462
463	check_nexthop_fdb_support
464	if [ $? -eq $ksft_skip ]; then
465		return $ksft_skip
466	fi
467
468	# create group with multiple nexthops
469	run_cmd "$IP nexthop add id 61 via 2001:db8:91::2 fdb"
470	run_cmd "$IP nexthop add id 62 via 2001:db8:91::3 fdb"
471	run_cmd "$IP nexthop add id 102 group 61/62 fdb"
472	check_nexthop "id 102" "id 102 group 61/62 fdb"
473	log_test $? 0 "Fdb Nexthop group with multiple nexthops"
474
475	## get nexthop group
476	run_cmd "$IP nexthop get id 102"
477	check_nexthop "id 102" "id 102 group 61/62 fdb"
478	log_test $? 0 "Get Fdb nexthop group by id"
479
480	# fdb nexthop group can only contain fdb nexthops
481	run_cmd "$IP nexthop add id 63 via 2001:db8:91::4 dev veth1"
482	run_cmd "$IP nexthop add id 64 via 2001:db8:91::5 dev veth1"
483	run_cmd "$IP nexthop add id 103 group 63/64 fdb"
484	log_test $? 2 "Fdb Nexthop group with non-fdb nexthops"
485
486	# Non fdb nexthop group can not contain fdb nexthops
487	run_cmd "$IP nexthop add id 65 via 2001:db8:91::5 fdb"
488	run_cmd "$IP nexthop add id 66 via 2001:db8:91::6 fdb"
489	run_cmd "$IP nexthop add id 104 group 65/66"
490	log_test $? 2 "Non-Fdb Nexthop group with fdb nexthops"
491
492	# fdb nexthop cannot have blackhole
493	run_cmd "$IP nexthop add id 67 blackhole fdb"
494	log_test $? 2 "Fdb Nexthop with blackhole"
495
496	# fdb nexthop with oif
497	run_cmd "$IP nexthop add id 68 via 2001:db8:91::7 dev veth1 fdb"
498	log_test $? 2 "Fdb Nexthop with oif"
499
500	# fdb nexthop with onlink
501	run_cmd "$IP nexthop add id 68 via 2001:db8:91::7 onlink fdb"
502	log_test $? 2 "Fdb Nexthop with onlink"
503
504	# fdb nexthop with encap
505	run_cmd "$IP nexthop add id 69 encap mpls 101 via 2001:db8:91::8 dev veth1 fdb"
506	log_test $? 2 "Fdb Nexthop with encap"
507
508	# Replace FDB nexthop to non-FDB and vice versa
509	run_cmd "$IP nexthop add id 70 via 2001:db8:91::2 fdb"
510	run_cmd "$IP nexthop replace id 70 via 2001:db8:91::2 dev veth1"
511	log_test $? 0 "Replace FDB nexthop to non-FDB nexthop"
512	run_cmd "$IP nexthop replace id 70 via 2001:db8:91::2 fdb"
513	log_test $? 0 "Replace non-FDB nexthop to FDB nexthop"
514
515	# Replace FDB nexthop address while in a group
516	run_cmd "$IP nexthop add id 71 group 70 fdb"
517	run_cmd "$IP nexthop replace id 70 via 2001:db8:91::3 fdb"
518	log_test $? 0 "Replace FDB nexthop address while in a group"
519
520	# Cannot replace FDB nexthop to non-FDB and vice versa while in a group
521	run_cmd "$IP nexthop replace id 70 via 2001:db8:91::2 dev veth1"
522	log_test $? 2 "Replace FDB nexthop to non-FDB nexthop while in a group"
523	run_cmd "$IP nexthop add id 72 via 2001:db8:91::2 dev veth1"
524	run_cmd "$IP nexthop add id 73 group 72"
525	run_cmd "$IP nexthop replace id 72 via 2001:db8:91::2 fdb"
526	log_test $? 2 "Replace non-FDB nexthop to FDB nexthop while in a group"
527
528	run_cmd "$IP link add name vx10 type vxlan id 1010 local 2001:db8:91::9 remote 2001:db8:91::10 dstport 4789 nolearning noudpcsum tos inherit ttl 100"
529	run_cmd "$BRIDGE fdb add 02:02:00:00:00:13 dev vx10 nhid 102 self"
530	log_test $? 0 "Fdb mac add with nexthop group"
531
532	## fdb nexthops can only reference nexthop groups and not nexthops
533	run_cmd "$BRIDGE fdb add 02:02:00:00:00:14 dev vx10 nhid 61 self"
534	log_test $? 255 "Fdb mac add with nexthop"
535
536	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 66"
537	log_test $? 2 "Route add with fdb nexthop"
538
539	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 103"
540	log_test $? 2 "Route add with fdb nexthop group"
541
542	run_cmd "$IP nexthop del id 61"
543	run_cmd "$BRIDGE fdb get to 02:02:00:00:00:13 dev vx10 self"
544	log_test $? 0 "Fdb entry after deleting a single nexthop"
545
546	run_cmd "$IP nexthop del id 102"
547	log_test $? 0 "Fdb nexthop delete"
548
549	run_cmd "$BRIDGE fdb get to 02:02:00:00:00:13 dev vx10 self"
550	log_test $? 254 "Fdb entry after deleting a nexthop group"
551
552	$IP link del dev vx10
553}
554
555ipv6_fdb_port_fcnal()
556{
557	echo
558	echo "IPv6 fdb nexthop dst_port functional"
559	echo "------------------------------------"
560
561	check_nexthop_fdb_port_support
562	if [ $? -eq $ksft_skip ]; then
563		return $ksft_skip
564	fi
565
566	# NHA_DST_PORT: optional per-nexthop VXLAN destination UDP port,
567	# letting an fdb nexthop group balance a flow across legs that share
568	# an underlay IP but listen on different UDP ports.
569	run_cmd "$IP nexthop add id 80 via 2001:db8:91::2 fdb dst_port 4790"
570	check_nexthop "id 80" \
571		"id 80 via 2001:db8:91::2 scope link fdb dst_port 4790"
572	log_test $? 0 "Fdb nexthop with dst_port"
573
574	run_cmd "$IP nexthop add id 81 fdb dst_port 4790"
575	log_test $? 2 "Fdb nexthop with dst_port but no gateway"
576
577	run_cmd "$IP nexthop add id 81 via 2001:db8:91::2 fdb dst_port 0"
578	log_test $? 2 "Fdb nexthop with dst_port 0"
579
580	run_cmd "$IP nexthop add id 82 via 2001:db8:91::2 fdb dst_port 4789"
581	run_cmd "$IP nexthop add id 83 via 2001:db8:91::3 fdb dst_port 5789"
582	run_cmd "$IP nexthop add id 106 group 82/83 fdb"
583	check_nexthop "id 106" "id 106 group 82/83 fdb"
584	log_test $? 0 "Fdb nexthop group with legs differing in dst_port"
585
586	run_cmd "$IP nexthop add id 84 via 2001:db8:91::2 fdb"
587	check_nexthop "id 84" "id 84 via 2001:db8:91::2 scope link fdb"
588	log_test $? 0 "Fdb nexthop without dst_port omits dst_port"
589}
590
591ipv4_fdb_grp_fcnal()
592{
593	local rc
594
595	echo
596	echo "IPv4 fdb groups functional"
597	echo "--------------------------"
598
599	check_nexthop_fdb_support
600	if [ $? -eq $ksft_skip ]; then
601		return $ksft_skip
602	fi
603
604	# create group with multiple nexthops
605	run_cmd "$IP nexthop add id 12 via 172.16.1.2 fdb"
606	run_cmd "$IP nexthop add id 13 via 172.16.1.3 fdb"
607	run_cmd "$IP nexthop add id 102 group 12/13 fdb"
608	check_nexthop "id 102" "id 102 group 12/13 fdb"
609	log_test $? 0 "Fdb Nexthop group with multiple nexthops"
610
611	# get nexthop group
612	run_cmd "$IP nexthop get id 102"
613	check_nexthop "id 102" "id 102 group 12/13 fdb"
614	log_test $? 0 "Get Fdb nexthop group by id"
615
616	# fdb nexthop group can only contain fdb nexthops
617	run_cmd "$IP nexthop add id 14 via 172.16.1.2 dev veth1"
618	run_cmd "$IP nexthop add id 15 via 172.16.1.3 dev veth1"
619	run_cmd "$IP nexthop add id 103 group 14/15 fdb"
620	log_test $? 2 "Fdb Nexthop group with non-fdb nexthops"
621
622	# Non fdb nexthop group can not contain fdb nexthops
623	run_cmd "$IP nexthop add id 16 via 172.16.1.2 fdb"
624	run_cmd "$IP nexthop add id 17 via 172.16.1.3 fdb"
625	run_cmd "$IP nexthop add id 104 group 16/17"
626	log_test $? 2 "Non-Fdb Nexthop group with fdb nexthops"
627
628	# fdb nexthop cannot have blackhole
629	run_cmd "$IP nexthop add id 18 blackhole fdb"
630	log_test $? 2 "Fdb Nexthop with blackhole"
631
632	# fdb nexthop with oif
633	run_cmd "$IP nexthop add id 16 via 172.16.1.2 dev veth1 fdb"
634	log_test $? 2 "Fdb Nexthop with oif"
635
636	# fdb nexthop with onlink
637	run_cmd "$IP nexthop add id 16 via 172.16.1.2 onlink fdb"
638	log_test $? 2 "Fdb Nexthop with onlink"
639
640	# fdb nexthop with encap
641	run_cmd "$IP nexthop add id 17 encap mpls 101 via 172.16.1.2 dev veth1 fdb"
642	log_test $? 2 "Fdb Nexthop with encap"
643
644	# Replace FDB nexthop to non-FDB and vice versa
645	run_cmd "$IP nexthop add id 18 via 172.16.1.2 fdb"
646	run_cmd "$IP nexthop replace id 18 via 172.16.1.2 dev veth1"
647	log_test $? 0 "Replace FDB nexthop to non-FDB nexthop"
648	run_cmd "$IP nexthop replace id 18 via 172.16.1.2 fdb"
649	log_test $? 0 "Replace non-FDB nexthop to FDB nexthop"
650
651	# Replace FDB nexthop address while in a group
652	run_cmd "$IP nexthop add id 19 group 18 fdb"
653	run_cmd "$IP nexthop replace id 18 via 172.16.1.3 fdb"
654	log_test $? 0 "Replace FDB nexthop address while in a group"
655
656	# Cannot replace FDB nexthop to non-FDB and vice versa while in a group
657	run_cmd "$IP nexthop replace id 18 via 172.16.1.2 dev veth1"
658	log_test $? 2 "Replace FDB nexthop to non-FDB nexthop while in a group"
659	run_cmd "$IP nexthop add id 20 via 172.16.1.2 dev veth1"
660	run_cmd "$IP nexthop add id 21 group 20"
661	run_cmd "$IP nexthop replace id 20 via 172.16.1.2 fdb"
662	log_test $? 2 "Replace non-FDB nexthop to FDB nexthop while in a group"
663
664	run_cmd "$IP link add name vx10 type vxlan id 1010 local 10.0.0.1 remote 10.0.0.2 dstport 4789 nolearning noudpcsum tos inherit ttl 100"
665	run_cmd "$BRIDGE fdb add 02:02:00:00:00:13 dev vx10 nhid 102 self"
666	log_test $? 0 "Fdb mac add with nexthop group"
667
668	# fdb nexthops can only reference nexthop groups and not nexthops
669	run_cmd "$BRIDGE fdb add 02:02:00:00:00:14 dev vx10 nhid 12 self"
670	log_test $? 255 "Fdb mac add with nexthop"
671
672	run_cmd "$IP ro add 172.16.0.0/22 nhid 16"
673	log_test $? 2 "Route add with fdb nexthop"
674
675	run_cmd "$IP ro add 172.16.0.0/22 nhid 103"
676	log_test $? 2 "Route add with fdb nexthop group"
677
678	run_cmd "$IP nexthop del id 12"
679	run_cmd "$BRIDGE fdb get to 02:02:00:00:00:13 dev vx10 self"
680	log_test $? 0 "Fdb entry after deleting a single nexthop"
681
682	run_cmd "$IP nexthop del id 102"
683	log_test $? 0 "Fdb nexthop delete"
684
685	run_cmd "$BRIDGE fdb get to 02:02:00:00:00:13 dev vx10 self"
686	log_test $? 254 "Fdb entry after deleting a nexthop group"
687
688	$IP link del dev vx10
689}
690
691ipv4_fdb_port_fcnal()
692{
693	echo
694	echo "IPv4 fdb nexthop dst_port functional"
695	echo "------------------------------------"
696
697	check_nexthop_fdb_port_support
698	if [ $? -eq $ksft_skip ]; then
699		return $ksft_skip
700	fi
701
702	# NHA_DST_PORT: optional per-nexthop VXLAN destination UDP port,
703	# letting an fdb nexthop group balance a flow across legs that share
704	# an underlay IP but listen on different UDP ports.
705	run_cmd "$IP nexthop add id 30 via 172.16.1.2 fdb dst_port 4790"
706	check_nexthop "id 30" \
707		"id 30 via 172.16.1.2 scope link fdb dst_port 4790"
708	log_test $? 0 "Fdb nexthop with dst_port"
709
710	run_cmd "$IP nexthop add id 31 fdb dst_port 4790"
711	log_test $? 2 "Fdb nexthop with dst_port but no gateway"
712
713	run_cmd "$IP nexthop add id 31 via 172.16.1.2 fdb dst_port 0"
714	log_test $? 2 "Fdb nexthop with dst_port 0"
715
716	run_cmd "$IP nexthop add id 32 via 172.16.1.2 fdb dst_port 4789"
717	run_cmd "$IP nexthop add id 33 via 172.16.1.3 fdb dst_port 5789"
718	run_cmd "$IP nexthop add id 105 group 32/33 fdb"
719	check_nexthop "id 105" "id 105 group 32/33 fdb"
720	log_test $? 0 "Fdb nexthop group with legs differing in dst_port"
721
722	run_cmd "$IP nexthop add id 34 via 172.16.1.2 fdb"
723	check_nexthop "id 34" "id 34 via 172.16.1.2 scope link fdb"
724	log_test $? 0 "Fdb nexthop without dst_port omits dst_port"
725}
726
727ipv4_mpath_select()
728{
729	local rc dev match h addr
730
731	echo
732	echo "IPv4 multipath selection"
733	echo "------------------------"
734	if [ ! -x "$(command -v jq)" ]; then
735		echo "SKIP: Could not run test; need jq tool"
736		return $ksft_skip
737	fi
738
739	# Use status of existing neighbor entry when determining nexthop for
740	# multipath routes.
741	local -A gws
742	gws=([veth1]=172.16.1.2 [veth3]=172.16.2.2)
743	local -A other_dev
744	other_dev=([veth1]=veth3 [veth3]=veth1)
745
746	run_cmd "$IP nexthop add id 1 via ${gws["veth1"]} dev veth1"
747	run_cmd "$IP nexthop add id 2 via ${gws["veth3"]} dev veth3"
748	run_cmd "$IP nexthop add id 1001 group 1/2"
749	run_cmd "$IP ro add 172.16.101.0/24 nhid 1001"
750	rc=0
751	for dev in veth1 veth3; do
752		match=0
753		for h in {1..254}; do
754			addr="172.16.101.$h"
755			if [ "$(get_route_dev "$addr")" = "$dev" ]; then
756				match=1
757				break
758			fi
759		done
760		if (( match == 0 )); then
761			echo "SKIP: Did not find a route using device $dev"
762			return $ksft_skip
763		fi
764		run_cmd "$IP neigh add ${gws[$dev]} dev $dev nud failed"
765		if ! check_route_dev "$addr" "${other_dev[$dev]}"; then
766			rc=1
767			break
768		fi
769		run_cmd "$IP neigh del ${gws[$dev]} dev $dev"
770	done
771	log_test $rc 0 "Use valid neighbor during multipath selection"
772
773	run_cmd "$IP neigh add 172.16.1.2 dev veth1 nud incomplete"
774	run_cmd "$IP neigh add 172.16.2.2 dev veth3 nud incomplete"
775	run_cmd "$IP route get 172.16.101.1"
776	# if we did not crash, success
777	log_test $rc 0 "Multipath selection with no valid neighbor"
778}
779
780ipv6_mpath_select()
781{
782	local rc dev match h addr
783
784	echo
785	echo "IPv6 multipath selection"
786	echo "------------------------"
787	if [ ! -x "$(command -v jq)" ]; then
788		echo "SKIP: Could not run test; need jq tool"
789		return $ksft_skip
790	fi
791
792	# Use status of existing neighbor entry when determining nexthop for
793	# multipath routes.
794	local -A gws
795	gws=([veth1]=2001:db8:91::2 [veth3]=2001:db8:92::2)
796	local -A other_dev
797	other_dev=([veth1]=veth3 [veth3]=veth1)
798
799	run_cmd "$IP nexthop add id 1 via ${gws["veth1"]} dev veth1"
800	run_cmd "$IP nexthop add id 2 via ${gws["veth3"]} dev veth3"
801	run_cmd "$IP nexthop add id 1001 group 1/2"
802	run_cmd "$IP ro add 2001:db8:101::/64 nhid 1001"
803	rc=0
804	for dev in veth1 veth3; do
805		match=0
806		for h in {1..65535}; do
807			addr=$(printf "2001:db8:101::%x" $h)
808			if [ "$(get_route_dev "$addr")" = "$dev" ]; then
809				match=1
810				break
811			fi
812		done
813		if (( match == 0 )); then
814			echo "SKIP: Did not find a route using device $dev"
815			return $ksft_skip
816		fi
817		run_cmd "$IP neigh add ${gws[$dev]} dev $dev nud failed"
818		if ! check_route_dev "$addr" "${other_dev[$dev]}"; then
819			rc=1
820			break
821		fi
822		run_cmd "$IP neigh del ${gws[$dev]} dev $dev"
823	done
824	log_test $rc 0 "Use valid neighbor during multipath selection"
825
826	run_cmd "$IP neigh add 2001:db8:91::2 dev veth1 nud incomplete"
827	run_cmd "$IP neigh add 2001:db8:92::2 dev veth3 nud incomplete"
828	run_cmd "$IP route get 2001:db8:101::1"
829	# if we did not crash, success
830	log_test $rc 0 "Multipath selection with no valid neighbor"
831}
832
833################################################################################
834# basic operations (add, delete, replace) on nexthops and nexthop groups
835#
836# IPv6
837
838ipv6_fcnal()
839{
840	local rc
841
842	echo
843	echo "IPv6"
844	echo "----------------------"
845
846	run_cmd "$IP nexthop add id 52 via 2001:db8:91::2 dev veth1"
847	rc=$?
848	log_test $rc 0 "Create nexthop with id, gw, dev"
849	if [ $rc -ne 0 ]; then
850		echo "Basic IPv6 create fails; can not continue"
851		return 1
852	fi
853
854	run_cmd "$IP nexthop get id 52"
855	log_test $? 0 "Get nexthop by id"
856	check_nexthop "id 52" "id 52 via 2001:db8:91::2 dev veth1 scope link"
857
858	run_cmd "$IP nexthop del id 52"
859	log_test $? 0 "Delete nexthop by id"
860	check_nexthop "id 52" ""
861
862	#
863	# gw, device spec
864	#
865	# gw validation, no device - fails since dev required
866	run_cmd "$IP nexthop add id 52 via 2001:db8:92::3"
867	log_test $? 2 "Create nexthop - gw only"
868
869	# gw is not reachable through given dev
870	run_cmd "$IP nexthop add id 53 via 2001:db8:3::3 dev veth1"
871	log_test $? 2 "Create nexthop - invalid gw+dev combination"
872
873	# onlink arg overrides gw+dev lookup
874	run_cmd "$IP nexthop add id 53 via 2001:db8:3::3 dev veth1 onlink"
875	log_test $? 0 "Create nexthop - gw+dev and onlink"
876
877	# admin down should delete nexthops
878	set -e
879	run_cmd "$IP -6 nexthop add id 55 via 2001:db8:91::3 dev veth1"
880	run_cmd "$IP nexthop add id 56 via 2001:db8:91::4 dev veth1"
881	run_cmd "$IP nexthop add id 57 via 2001:db8:91::5 dev veth1"
882	run_cmd "$IP li set dev veth1 down"
883	set +e
884	check_nexthop "dev veth1" ""
885	log_test $? 0 "Nexthops removed on admin down"
886
887	# error routes should be deleted when their nexthop is deleted
888	run_cmd "$IP li set dev veth1 up"
889	run_cmd "$IP -6 nexthop add id 58 dev veth1"
890	run_cmd "$IP ro add blackhole 2001:db8:101::1/128 nhid 58"
891	run_cmd "$IP nexthop del id 58"
892	check_route6 "2001:db8:101::1" ""
893	log_test $? 0 "Error route removed on nexthop deletion"
894}
895
896ipv6_grp_refs()
897{
898	if [ ! -x "$(command -v mausezahn)" ]; then
899		echo "SKIP: Could not run test; need mausezahn tool"
900		return
901	fi
902
903	run_cmd "$IP link set dev veth1 up"
904	run_cmd "$IP link add veth1.10 link veth1 up type vlan id 10"
905	run_cmd "$IP link add veth1.20 link veth1 up type vlan id 20"
906	run_cmd "$IP -6 addr add 2001:db8:91::1/64 dev veth1.10"
907	run_cmd "$IP -6 addr add 2001:db8:92::1/64 dev veth1.20"
908	run_cmd "$IP -6 neigh add 2001:db8:91::2 lladdr 00:11:22:33:44:55 dev veth1.10"
909	run_cmd "$IP -6 neigh add 2001:db8:92::2 lladdr 00:11:22:33:44:55 dev veth1.20"
910	run_cmd "$IP nexthop add id 100 via 2001:db8:91::2 dev veth1.10"
911	run_cmd "$IP nexthop add id 101 via 2001:db8:92::2 dev veth1.20"
912	run_cmd "$IP nexthop add id 102 group 100"
913	run_cmd "$IP route add 2001:db8:101::1/128 nhid 102"
914
915	# create per-cpu dsts through nh 100
916	run_cmd "ip netns exec $me mausezahn -6 veth1.10 -B 2001:db8:101::1 -A 2001:db8:91::1 -c 5 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1"
917
918	# remove nh 100 from the group to delete the route potentially leaving
919	# a stale per-cpu dst which holds a reference to the nexthop's net
920	# device and to the IPv6 route
921	run_cmd "$IP nexthop replace id 102 group 101"
922	run_cmd "$IP route del 2001:db8:101::1/128"
923
924	# add both nexthops to the group so a reference is taken on them
925	run_cmd "$IP nexthop replace id 102 group 100/101"
926
927	# if the bug described in commit "net: nexthop: release IPv6 per-cpu
928	# dsts when replacing a nexthop group" exists at this point we have
929	# an unlinked IPv6 route (but not freed due to stale dst) with a
930	# reference over the group so we delete the group which will again
931	# only unlink it due to the route reference
932	run_cmd "$IP nexthop del id 102"
933
934	# delete the nexthop with stale dst, since we have an unlinked
935	# group with a ref to it and an unlinked IPv6 route with ref to the
936	# group, the nh will only be unlinked and not freed so the stale dst
937	# remains forever and we get a net device refcount imbalance
938	run_cmd "$IP nexthop del id 100"
939
940	# if a reference was lost this command will hang because the net device
941	# cannot be removed
942	timeout -s KILL 5 ip netns exec $me ip link del veth1.10 >/dev/null 2>&1
943
944	# we can't cleanup if the command is hung trying to delete the netdev
945	if [ $? -eq 137 ]; then
946		return 1
947	fi
948
949	# cleanup
950	run_cmd "$IP link del veth1.20"
951	run_cmd "$IP nexthop flush"
952
953	return 0
954}
955
956ipv6_grp_fcnal()
957{
958	local rc
959
960	echo
961	echo "IPv6 groups functional"
962	echo "----------------------"
963
964	# basic functionality: create a nexthop group, default weight
965	run_cmd "$IP nexthop add id 61 via 2001:db8:91::2 dev veth1"
966	run_cmd "$IP nexthop add id 101 group 61"
967	log_test $? 0 "Create nexthop group with single nexthop"
968
969	# get nexthop group
970	run_cmd "$IP nexthop get id 101"
971	log_test $? 0 "Get nexthop group by id"
972	check_nexthop "id 101" "id 101 group 61"
973
974	# delete nexthop group
975	run_cmd "$IP nexthop del id 101"
976	log_test $? 0 "Delete nexthop group by id"
977	check_nexthop "id 101" ""
978
979	$IP nexthop flush >/dev/null 2>&1
980	check_nexthop "id 101" ""
981
982	#
983	# create group with multiple nexthops - mix of gw and dev only
984	#
985	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
986	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
987	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
988	run_cmd "$IP nexthop add id 65 dev veth1"
989	run_cmd "$IP nexthop add id 102 group 62/63/64/65"
990	log_test $? 0 "Nexthop group with multiple nexthops"
991	check_nexthop "id 102" "id 102 group 62/63/64/65"
992
993	# Delete nexthop in a group and group is updated
994	run_cmd "$IP nexthop del id 63"
995	check_nexthop "id 102" "id 102 group 62/64/65"
996	log_test $? 0 "Nexthop group updated when entry is deleted"
997
998	# create group with multiple weighted nexthops
999	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1000	run_cmd "$IP nexthop add id 103 group 62/63,2/64,3/65,4"
1001	log_test $? 0 "Nexthop group with weighted nexthops"
1002	check_nexthop "id 103" "id 103 group 62/63,2/64,3/65,4"
1003
1004	# Delete nexthop in a weighted group and group is updated
1005	run_cmd "$IP nexthop del id 63"
1006	check_nexthop "id 103" "id 103 group 62/64,3/65,4"
1007	log_test $? 0 "Weighted nexthop group updated when entry is deleted"
1008
1009	# admin down - nexthop is removed from group
1010	run_cmd "$IP li set dev veth1 down"
1011	check_nexthop "dev veth1" ""
1012	log_test $? 0 "Nexthops in groups removed on admin down"
1013
1014	# expect groups to have been deleted as well
1015	check_nexthop "" ""
1016
1017	run_cmd "$IP li set dev veth1 up"
1018
1019	$IP nexthop flush >/dev/null 2>&1
1020
1021	# group with nexthops using different devices
1022	set -e
1023	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1024	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1025	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
1026	run_cmd "$IP nexthop add id 65 via 2001:db8:91::5 dev veth1"
1027
1028	run_cmd "$IP nexthop add id 72 via 2001:db8:92::2 dev veth3"
1029	run_cmd "$IP nexthop add id 73 via 2001:db8:92::3 dev veth3"
1030	run_cmd "$IP nexthop add id 74 via 2001:db8:92::4 dev veth3"
1031	run_cmd "$IP nexthop add id 75 via 2001:db8:92::5 dev veth3"
1032	set +e
1033
1034	# multiple groups with same nexthop
1035	run_cmd "$IP nexthop add id 104 group 62"
1036	run_cmd "$IP nexthop add id 105 group 62"
1037	check_nexthop "group" "id 104 group 62 id 105 group 62"
1038	log_test $? 0 "Multiple groups with same nexthop"
1039
1040	run_cmd "$IP nexthop flush groups"
1041	[ $? -ne 0 ] && return 1
1042
1043	# on admin down of veth1, it should be removed from the group
1044	run_cmd "$IP nexthop add id 105 group 62/63/72/73/64"
1045	run_cmd "$IP li set veth1 down"
1046	check_nexthop "id 105" "id 105 group 72/73"
1047	log_test $? 0 "Nexthops in group removed on admin down - mixed group"
1048
1049	run_cmd "$IP nexthop add id 106 group 105/74"
1050	log_test $? 2 "Nexthop group can not have a group as an entry"
1051
1052	# a group can have a blackhole entry only if it is the only
1053	# nexthop in the group. Needed for atomic replace with an
1054	# actual nexthop group
1055	run_cmd "$IP -6 nexthop add id 31 blackhole"
1056	run_cmd "$IP nexthop add id 107 group 31"
1057	log_test $? 0 "Nexthop group with a blackhole entry"
1058
1059	run_cmd "$IP nexthop add id 108 group 31/24"
1060	log_test $? 2 "Nexthop group can not have a blackhole and another nexthop"
1061
1062	ipv6_grp_refs
1063	log_test $? 0 "Nexthop group replace refcounts"
1064
1065	#
1066	# 16-bit weights.
1067	#
1068	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1069	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1070	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
1071	run_cmd "$IP nexthop add id 65 via 2001:db8:91::5 dev veth1"
1072	run_cmd "$IP nexthop add id 66 dev veth1"
1073
1074	run_cmd "$IP nexthop add id 103 group 62,1000"
1075	if [[ $? == 0 ]]; then
1076		local GRP="id 103 group 62,254/63,255/64,256/65,257/66,65535"
1077		run_cmd "$IP nexthop replace $GRP"
1078		check_nexthop "id 103" "$GRP"
1079		rc=$?
1080	else
1081		rc=$ksft_skip
1082	fi
1083
1084	$IP nexthop flush >/dev/null 2>&1
1085
1086	log_test $rc 0 "16-bit weights"
1087}
1088
1089ipv6_res_grp_fcnal()
1090{
1091	local rc
1092
1093	echo
1094	echo "IPv6 resilient groups functional"
1095	echo "--------------------------------"
1096
1097	check_nexthop_res_support
1098	if [ $? -eq $ksft_skip ]; then
1099		return $ksft_skip
1100	fi
1101
1102	#
1103	# migration of nexthop buckets - equal weights
1104	#
1105	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1106	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1107	run_cmd "$IP nexthop add id 102 group 62/63 type resilient buckets 2 idle_timer 0"
1108
1109	run_cmd "$IP nexthop del id 63"
1110	check_nexthop "id 102" \
1111		"id 102 group 62 type resilient buckets 2 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1112	log_test $? 0 "Nexthop group updated when entry is deleted"
1113	check_nexthop_bucket "list id 102" \
1114		"id 102 index 0 nhid 62 id 102 index 1 nhid 62"
1115	log_test $? 0 "Nexthop buckets updated when entry is deleted"
1116
1117	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1118	run_cmd "$IP nexthop replace id 102 group 62/63 type resilient buckets 2 idle_timer 0"
1119	check_nexthop "id 102" \
1120		"id 102 group 62/63 type resilient buckets 2 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1121	log_test $? 0 "Nexthop group updated after replace"
1122	check_nexthop_bucket "list id 102" \
1123		"id 102 index 0 nhid 63 id 102 index 1 nhid 62"
1124	log_test $? 0 "Nexthop buckets updated after replace"
1125
1126	$IP nexthop flush >/dev/null 2>&1
1127
1128	#
1129	# migration of nexthop buckets - unequal weights
1130	#
1131	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1132	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1133	run_cmd "$IP nexthop add id 102 group 62,3/63,1 type resilient buckets 4 idle_timer 0"
1134
1135	run_cmd "$IP nexthop del id 63"
1136	check_nexthop "id 102" \
1137		"id 102 group 62,3 type resilient buckets 4 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1138	log_test $? 0 "Nexthop group updated when entry is deleted - nECMP"
1139	check_nexthop_bucket "list id 102" \
1140		"id 102 index 0 nhid 62 id 102 index 1 nhid 62 id 102 index 2 nhid 62 id 102 index 3 nhid 62"
1141	log_test $? 0 "Nexthop buckets updated when entry is deleted - nECMP"
1142
1143	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1144	run_cmd "$IP nexthop replace id 102 group 62,3/63,1 type resilient buckets 4 idle_timer 0"
1145	check_nexthop "id 102" \
1146		"id 102 group 62,3/63 type resilient buckets 4 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1147	log_test $? 0 "Nexthop group updated after replace - nECMP"
1148	check_nexthop_bucket "list id 102" \
1149		"id 102 index 0 nhid 63 id 102 index 1 nhid 62 id 102 index 2 nhid 62 id 102 index 3 nhid 62"
1150	log_test $? 0 "Nexthop buckets updated after replace - nECMP"
1151
1152	#
1153	# 16-bit weights.
1154	#
1155	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1156	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1157	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
1158	run_cmd "$IP nexthop add id 65 via 2001:db8:91::5 dev veth1"
1159	run_cmd "$IP nexthop add id 66 dev veth1"
1160
1161	run_cmd "$IP nexthop add id 103 group 62,1000 type resilient buckets 32"
1162	if [[ $? == 0 ]]; then
1163		local GRP="id 103 group 62,254/63,255/64,256/65,257/66,65535 $(:
1164			  )type resilient buckets 32 idle_timer 0 $(:
1165			  )unbalanced_timer 0"
1166		run_cmd "$IP nexthop replace $GRP"
1167		check_nexthop "id 103" "$GRP unbalanced_time 0"
1168		rc=$?
1169	else
1170		rc=$ksft_skip
1171	fi
1172
1173	$IP nexthop flush >/dev/null 2>&1
1174
1175	log_test $rc 0 "16-bit weights"
1176}
1177
1178ipv6_fcnal_runtime()
1179{
1180	local rc
1181
1182	echo
1183	echo "IPv6 functional runtime"
1184	echo "-----------------------"
1185
1186	#
1187	# IPv6 - the basics
1188	#
1189	run_cmd "$IP nexthop add id 81 via 2001:db8:91::2 dev veth1"
1190	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
1191	log_test $? 0 "Route add"
1192
1193	run_cmd "$IP ro delete 2001:db8:101::1/128 nhid 81"
1194	log_test $? 0 "Route delete"
1195
1196	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
1197	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1198	log_test $? 0 "Ping with nexthop"
1199
1200	run_cmd "$IP nexthop add id 82 via 2001:db8:92::2 dev veth3"
1201	run_cmd "$IP nexthop add id 122 group 81/82"
1202	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
1203	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1204	log_test $? 0 "Ping - multipath"
1205
1206	#
1207	# IPv6 with blackhole nexthops
1208	#
1209	run_cmd "$IP -6 nexthop add id 83 blackhole"
1210	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 83"
1211	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1212	log_test $? 2 "Ping - blackhole"
1213
1214	run_cmd "$IP nexthop replace id 83 via 2001:db8:91::2 dev veth1"
1215	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1216	log_test $? 0 "Ping - blackhole replaced with gateway"
1217
1218	run_cmd "$IP -6 nexthop replace id 83 blackhole"
1219	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1220	log_test $? 2 "Ping - gateway replaced by blackhole"
1221
1222	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
1223	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1224	if [ $? -eq 0 ]; then
1225		run_cmd "$IP nexthop replace id 122 group 83"
1226		run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1227		log_test $? 2 "Ping - group with blackhole"
1228
1229		run_cmd "$IP nexthop replace id 122 group 81/82"
1230		run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1231		log_test $? 0 "Ping - group blackhole replaced with gateways"
1232	else
1233		log_test 2 0 "Ping - multipath failed"
1234	fi
1235
1236	#
1237	# device only and gw + dev only mix
1238	#
1239	run_cmd "$IP -6 nexthop add id 85 dev veth1"
1240	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 85"
1241	log_test $? 0 "IPv6 route with device only nexthop"
1242	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 dev veth1 metric 1024"
1243
1244	run_cmd "$IP nexthop add id 123 group 81/85"
1245	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 123"
1246	log_test $? 0 "IPv6 multipath route with nexthop mix - dev only + gw"
1247	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 123 metric 1024 nexthop via 2001:db8:91::2 dev veth1 weight 1 nexthop dev veth1 weight 1"
1248
1249	#
1250	# IPv6 route with v4 nexthop - not allowed
1251	#
1252	run_cmd "$IP ro delete 2001:db8:101::1/128"
1253	run_cmd "$IP nexthop add id 84 via 172.16.1.1 dev veth1"
1254	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 84"
1255	log_test $? 2 "IPv6 route can not have a v4 gateway"
1256
1257	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 81"
1258	run_cmd "$IP nexthop replace id 81 via 172.16.1.1 dev veth1"
1259	log_test $? 2 "Nexthop replace - v6 route, v4 nexthop"
1260
1261	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
1262	run_cmd "$IP nexthop replace id 81 via 172.16.1.1 dev veth1"
1263	log_test $? 2 "Nexthop replace of group entry - v6 route, v4 nexthop"
1264
1265	run_cmd "$IP nexthop add id 86 via 2001:db8:92::2 dev veth3"
1266	run_cmd "$IP nexthop add id 87 via 172.16.1.1 dev veth1"
1267	run_cmd "$IP nexthop add id 88 via 172.16.1.1 dev veth1"
1268	run_cmd "$IP nexthop add id 124 group 86/87/88"
1269	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
1270	log_test $? 2 "IPv6 route can not have a group with v4 and v6 gateways"
1271
1272	run_cmd "$IP nexthop del id 88"
1273	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
1274	log_test $? 2 "IPv6 route can not have a group with v4 and v6 gateways"
1275
1276	run_cmd "$IP nexthop del id 87"
1277	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
1278	log_test $? 0 "IPv6 route using a group after removing v4 gateways"
1279
1280	run_cmd "$IP ro delete 2001:db8:101::1/128"
1281	run_cmd "$IP nexthop add id 87 via 172.16.1.1 dev veth1"
1282	run_cmd "$IP nexthop add id 88 via 172.16.1.1 dev veth1"
1283	run_cmd "$IP nexthop replace id 124 group 86/87/88"
1284	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
1285	log_test $? 2 "IPv6 route can not have a group with v4 and v6 gateways"
1286
1287	run_cmd "$IP nexthop replace id 88 via 2001:db8:92::2 dev veth3"
1288	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
1289	log_test $? 2 "IPv6 route can not have a group with v4 and v6 gateways"
1290
1291	run_cmd "$IP nexthop replace id 87 via 2001:db8:92::2 dev veth3"
1292	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
1293	log_test $? 0 "IPv6 route using a group after replacing v4 gateways"
1294
1295	# Replacing an IPv6 nexthop with an IPv4 nexthop should update has_v4
1296	# for all groups using it, preventing IPv6 routes from referencing the
1297	# group after the replace.
1298	run_cmd "$IP nexthop add id 89 via 2001:db8:91::2 dev veth1"
1299	run_cmd "$IP nexthop add id 125 group 89"
1300	run_cmd "$IP nexthop replace id 89 via 172.16.1.1 dev veth1"
1301	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 125"
1302	log_test $? 2 "IPv6 route can not use group after v6 nexthop replaced by v4"
1303
1304	# Same scenario but with a blackhole nexthop: the group has no IPv6
1305	# routes yet when the replace happens, so fib6_check_nh_list returns
1306	# early without checking. has_v4 must still be updated to block
1307	# subsequent IPv6 route additions.
1308	run_cmd "$IP nexthop flush >/dev/null 2>&1"
1309	run_cmd "$IP -6 nexthop add id 90 blackhole"
1310	run_cmd "$IP nexthop add id 125 group 90"
1311	run_cmd "$IP nexthop replace id 90 blackhole"
1312	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 125"
1313	log_test $? 2 "IPv6 route reject v6 blackhole replaced by v4 blackhole"
1314	run_cmd "ip netns exec $me ping -6 2001:db8:101::1 -c1 -w$PING_TIMEOUT"
1315	log_test $? 2 "Ping unreachable after rejected route"
1316
1317	$IP nexthop flush >/dev/null 2>&1
1318
1319	#
1320	# weird IPv6 cases
1321	#
1322	run_cmd "$IP nexthop add id 86 via 2001:db8:91::2 dev veth1"
1323	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
1324
1325	# route can not use prefsrc with nexthops
1326	run_cmd "$IP ro add 2001:db8:101::2/128 nhid 86 from 2001:db8:91::1"
1327	log_test $? 2 "IPv6 route can not use src routing with external nexthop"
1328
1329	# check cleanup path on invalid metric
1330	run_cmd "$IP ro add 2001:db8:101::2/128 nhid 86 congctl lock foo"
1331	log_test $? 2 "IPv6 route with invalid metric"
1332
1333	# rpfilter and default route
1334	$IP nexthop flush >/dev/null 2>&1
1335	run_cmd "ip netns exec $me ip6tables -t mangle -I PREROUTING 1 -m rpfilter --invert -j DROP"
1336	run_cmd "$IP nexthop add id 91 via 2001:db8:91::2 dev veth1"
1337	run_cmd "$IP nexthop add id 92 via 2001:db8:92::2 dev veth3"
1338	run_cmd "$IP nexthop add id 93 group 91/92"
1339	run_cmd "$IP -6 ro add default nhid 91"
1340	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1341	log_test $? 0 "Nexthop with default route and rpfilter"
1342	run_cmd "$IP -6 ro replace default nhid 93"
1343	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 2001:db8:101::1"
1344	log_test $? 0 "Nexthop with multipath default route and rpfilter"
1345
1346	# TO-DO:
1347	# existing route with old nexthop; append route with new nexthop
1348	# existing route with old nexthop; replace route with new
1349	# existing route with new nexthop; replace route with old
1350	# route with src address and using nexthop - not allowed
1351}
1352
1353ipv6_large_grp()
1354{
1355	local ecmp=32
1356
1357	echo
1358	echo "IPv6 large groups (x$ecmp)"
1359	echo "---------------------"
1360
1361	check_large_grp 6 $ecmp
1362
1363	$IP nexthop flush >/dev/null 2>&1
1364}
1365
1366ipv6_large_res_grp()
1367{
1368	echo
1369	echo "IPv6 large resilient group (128k buckets)"
1370	echo "-----------------------------------------"
1371
1372	check_nexthop_res_support
1373	if [ $? -eq $ksft_skip ]; then
1374		return $ksft_skip
1375	fi
1376
1377	check_large_res_grp 6 $((128 * 1024))
1378
1379	$IP nexthop flush >/dev/null 2>&1
1380}
1381
1382ipv6_del_add_loop1()
1383{
1384	while :; do
1385		$IP nexthop del id 100
1386		$IP nexthop add id 100 via 2001:db8:91::2 dev veth1
1387	done >/dev/null 2>&1
1388}
1389
1390ipv6_grp_replace_loop()
1391{
1392	while :; do
1393		$IP nexthop replace id 102 group 100/101
1394	done >/dev/null 2>&1
1395}
1396
1397ipv6_torture()
1398{
1399	local pid1
1400	local pid2
1401	local pid3
1402	local pid4
1403	local pid5
1404
1405	echo
1406	echo "IPv6 runtime torture"
1407	echo "--------------------"
1408	if [ ! -x "$(command -v mausezahn)" ]; then
1409		echo "SKIP: Could not run test; need mausezahn tool"
1410		return
1411	fi
1412
1413	run_cmd "$IP nexthop add id 100 via 2001:db8:91::2 dev veth1"
1414	run_cmd "$IP nexthop add id 101 via 2001:db8:92::2 dev veth3"
1415	run_cmd "$IP nexthop add id 102 group 100/101"
1416	run_cmd "$IP route add 2001:db8:101::1 nhid 102"
1417	run_cmd "$IP route add 2001:db8:101::2 nhid 102"
1418
1419	ipv6_del_add_loop1 &
1420	pid1=$!
1421	ipv6_grp_replace_loop &
1422	pid2=$!
1423	ip netns exec $me ping -f 2001:db8:101::1 >/dev/null 2>&1 &
1424	pid3=$!
1425	ip netns exec $me ping -f 2001:db8:101::2 >/dev/null 2>&1 &
1426	pid4=$!
1427	ip netns exec $me mausezahn -6 veth1 -B 2001:db8:101::2 -A 2001:db8:91::1 -c 0 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
1428	pid5=$!
1429
1430	sleep 300
1431	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
1432	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
1433
1434	# if we did not crash, success
1435	log_test 0 0 "IPv6 torture test"
1436}
1437
1438ipv6_res_grp_replace_loop()
1439{
1440	while :; do
1441		$IP nexthop replace id 102 group 100/101 type resilient
1442	done >/dev/null 2>&1
1443}
1444
1445ipv6_res_torture()
1446{
1447	local pid1
1448	local pid2
1449	local pid3
1450	local pid4
1451	local pid5
1452
1453	echo
1454	echo "IPv6 runtime resilient nexthop group torture"
1455	echo "--------------------------------------------"
1456
1457	check_nexthop_res_support
1458	if [ $? -eq $ksft_skip ]; then
1459		return $ksft_skip
1460	fi
1461
1462	if [ ! -x "$(command -v mausezahn)" ]; then
1463		echo "SKIP: Could not run test; need mausezahn tool"
1464		return
1465	fi
1466
1467	run_cmd "$IP nexthop add id 100 via 2001:db8:91::2 dev veth1"
1468	run_cmd "$IP nexthop add id 101 via 2001:db8:92::2 dev veth3"
1469	run_cmd "$IP nexthop add id 102 group 100/101 type resilient buckets 512 idle_timer 0"
1470	run_cmd "$IP route add 2001:db8:101::1 nhid 102"
1471	run_cmd "$IP route add 2001:db8:101::2 nhid 102"
1472
1473	ipv6_del_add_loop1 &
1474	pid1=$!
1475	ipv6_res_grp_replace_loop &
1476	pid2=$!
1477	ip netns exec $me ping -f 2001:db8:101::1 >/dev/null 2>&1 &
1478	pid3=$!
1479	ip netns exec $me ping -f 2001:db8:101::2 >/dev/null 2>&1 &
1480	pid4=$!
1481	ip netns exec $me mausezahn -6 veth1 \
1482			    -B 2001:db8:101::2 -A 2001:db8:91::1 -c 0 \
1483			    -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
1484	pid5=$!
1485
1486	sleep 300
1487	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
1488	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
1489
1490	# if we did not crash, success
1491	log_test 0 0 "IPv6 resilient nexthop group torture test"
1492}
1493
1494ipv4_fcnal()
1495{
1496	local rc
1497
1498	echo
1499	echo "IPv4 functional"
1500	echo "----------------------"
1501
1502	#
1503	# basic IPv4 ops - add, get, delete
1504	#
1505	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1506	rc=$?
1507	log_test $rc 0 "Create nexthop with id, gw, dev"
1508	if [ $rc -ne 0 ]; then
1509		echo "Basic IPv4 create fails; can not continue"
1510		return 1
1511	fi
1512
1513	run_cmd "$IP nexthop get id 12"
1514	log_test $? 0 "Get nexthop by id"
1515	check_nexthop "id 12" "id 12 via 172.16.1.2 dev veth1 scope link"
1516
1517	run_cmd "$IP nexthop del id 12"
1518	log_test $? 0 "Delete nexthop by id"
1519	check_nexthop "id 52" ""
1520
1521	#
1522	# gw, device spec
1523	#
1524	# gw validation, no device - fails since dev is required
1525	run_cmd "$IP nexthop add id 12 via 172.16.2.3"
1526	log_test $? 2 "Create nexthop - gw only"
1527
1528	# gw not reachable through given dev
1529	run_cmd "$IP nexthop add id 13 via 172.16.3.2 dev veth1"
1530	log_test $? 2 "Create nexthop - invalid gw+dev combination"
1531
1532	# onlink flag overrides gw+dev lookup
1533	run_cmd "$IP nexthop add id 13 via 172.16.3.2 dev veth1 onlink"
1534	log_test $? 0 "Create nexthop - gw+dev and onlink"
1535
1536	# admin down should delete nexthops
1537	set -e
1538	run_cmd "$IP nexthop add id 15 via 172.16.1.3 dev veth1"
1539	run_cmd "$IP nexthop add id 16 via 172.16.1.4 dev veth1"
1540	run_cmd "$IP nexthop add id 17 via 172.16.1.5 dev veth1"
1541	run_cmd "$IP li set dev veth1 down"
1542	set +e
1543	check_nexthop "dev veth1" ""
1544	log_test $? 0 "Nexthops removed on admin down"
1545
1546	# nexthop route delete warning: route add with nhid and delete
1547	# using device
1548	run_cmd "$IP li set dev veth1 up"
1549	run_cmd "$IP nexthop add id 12 via 172.16.1.3 dev veth1"
1550	out1=`dmesg | grep "WARNING:.*fib_nh_match.*" | wc -l`
1551	run_cmd "$IP route add 172.16.101.1/32 nhid 12"
1552	run_cmd "$IP route delete 172.16.101.1/32 dev veth1"
1553	out2=`dmesg | grep "WARNING:.*fib_nh_match.*" | wc -l`
1554	[ $out1 -eq $out2 ]
1555	rc=$?
1556	log_test $rc 0 "Delete nexthop route warning"
1557	run_cmd "$IP route delete 172.16.101.1/32 nhid 12"
1558	run_cmd "$IP nexthop del id 12"
1559
1560	run_cmd "$IP nexthop add id 21 via 172.16.1.6 dev veth1"
1561	run_cmd "$IP ro add 172.16.101.0/24 nhid 21"
1562	run_cmd "$IP ro del 172.16.101.0/24 nexthop via 172.16.1.7 dev veth1 nexthop via 172.16.1.8 dev veth1"
1563	log_test $? 2 "Delete multipath route with only nh id based entry"
1564
1565	run_cmd "$IP nexthop add id 22 via 172.16.1.6 dev veth1"
1566	run_cmd "$IP ro add 172.16.102.0/24 nhid 22"
1567	run_cmd "$IP ro del 172.16.102.0/24 dev veth1"
1568	log_test $? 2 "Delete route when specifying only nexthop device"
1569
1570	run_cmd "$IP ro del 172.16.102.0/24 via 172.16.1.6"
1571	log_test $? 2 "Delete route when specifying only gateway"
1572
1573	run_cmd "$IP ro del 172.16.102.0/24"
1574	log_test $? 0 "Delete route when not specifying nexthop attributes"
1575
1576	# error routes should be deleted when their nexthop is deleted
1577	run_cmd "$IP nexthop add id 23 dev veth1"
1578	run_cmd "$IP ro add blackhole 172.16.102.100/32 nhid 23"
1579	run_cmd "$IP nexthop del id 23"
1580	check_route "172.16.102.100" ""
1581	log_test $? 0 "Error route removed on nexthop deletion"
1582}
1583
1584ipv4_grp_fcnal()
1585{
1586	local rc
1587
1588	echo
1589	echo "IPv4 groups functional"
1590	echo "----------------------"
1591
1592	# basic functionality: create a nexthop group, default weight
1593	run_cmd "$IP nexthop add id 11 via 172.16.1.2 dev veth1"
1594	run_cmd "$IP nexthop add id 101 group 11"
1595	log_test $? 0 "Create nexthop group with single nexthop"
1596
1597	# get nexthop group
1598	run_cmd "$IP nexthop get id 101"
1599	log_test $? 0 "Get nexthop group by id"
1600	check_nexthop "id 101" "id 101 group 11"
1601
1602	# delete nexthop group
1603	run_cmd "$IP nexthop del id 101"
1604	log_test $? 0 "Delete nexthop group by id"
1605	check_nexthop "id 101" ""
1606
1607	$IP nexthop flush >/dev/null 2>&1
1608
1609	#
1610	# create group with multiple nexthops
1611	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1612	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1613	run_cmd "$IP nexthop add id 14 via 172.16.1.4 dev veth1"
1614	run_cmd "$IP nexthop add id 15 via 172.16.1.5 dev veth1"
1615	run_cmd "$IP nexthop add id 102 group 12/13/14/15"
1616	log_test $? 0 "Nexthop group with multiple nexthops"
1617	check_nexthop "id 102" "id 102 group 12/13/14/15"
1618
1619	# Delete nexthop in a group and group is updated
1620	run_cmd "$IP nexthop del id 13"
1621	check_nexthop "id 102" "id 102 group 12/14/15"
1622	log_test $? 0 "Nexthop group updated when entry is deleted"
1623
1624	# create group with multiple weighted nexthops
1625	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1626	run_cmd "$IP nexthop add id 103 group 12/13,2/14,3/15,4"
1627	log_test $? 0 "Nexthop group with weighted nexthops"
1628	check_nexthop "id 103" "id 103 group 12/13,2/14,3/15,4"
1629
1630	# Delete nexthop in a weighted group and group is updated
1631	run_cmd "$IP nexthop del id 13"
1632	check_nexthop "id 103" "id 103 group 12/14,3/15,4"
1633	log_test $? 0 "Weighted nexthop group updated when entry is deleted"
1634
1635	# admin down - nexthop is removed from group
1636	run_cmd "$IP li set dev veth1 down"
1637	check_nexthop "dev veth1" ""
1638	log_test $? 0 "Nexthops in groups removed on admin down"
1639
1640	# expect groups to have been deleted as well
1641	check_nexthop "" ""
1642
1643	run_cmd "$IP li set dev veth1 up"
1644
1645	$IP nexthop flush >/dev/null 2>&1
1646
1647	# group with nexthops using different devices
1648	set -e
1649	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1650	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1651	run_cmd "$IP nexthop add id 14 via 172.16.1.4 dev veth1"
1652	run_cmd "$IP nexthop add id 15 via 172.16.1.5 dev veth1"
1653
1654	run_cmd "$IP nexthop add id 22 via 172.16.2.2 dev veth3"
1655	run_cmd "$IP nexthop add id 23 via 172.16.2.3 dev veth3"
1656	run_cmd "$IP nexthop add id 24 via 172.16.2.4 dev veth3"
1657	run_cmd "$IP nexthop add id 25 via 172.16.2.5 dev veth3"
1658	set +e
1659
1660	# multiple groups with same nexthop
1661	run_cmd "$IP nexthop add id 104 group 12"
1662	run_cmd "$IP nexthop add id 105 group 12"
1663	check_nexthop "group" "id 104 group 12 id 105 group 12"
1664	log_test $? 0 "Multiple groups with same nexthop"
1665
1666	run_cmd "$IP nexthop flush groups"
1667	[ $? -ne 0 ] && return 1
1668
1669	# on admin down of veth1, it should be removed from the group
1670	run_cmd "$IP nexthop add id 105 group 12/13/22/23/14"
1671	run_cmd "$IP li set veth1 down"
1672	check_nexthop "id 105" "id 105 group 22/23"
1673	log_test $? 0 "Nexthops in group removed on admin down - mixed group"
1674
1675	run_cmd "$IP nexthop add id 106 group 105/24"
1676	log_test $? 2 "Nexthop group can not have a group as an entry"
1677
1678	# a group can have a blackhole entry only if it is the only
1679	# nexthop in the group. Needed for atomic replace with an
1680	# actual nexthop group
1681	run_cmd "$IP nexthop add id 31 blackhole"
1682	run_cmd "$IP nexthop add id 107 group 31"
1683	log_test $? 0 "Nexthop group with a blackhole entry"
1684
1685	run_cmd "$IP nexthop add id 108 group 31/24"
1686	log_test $? 2 "Nexthop group can not have a blackhole and another nexthop"
1687}
1688
1689ipv4_res_grp_fcnal()
1690{
1691	local rc
1692
1693	echo
1694	echo "IPv4 resilient groups functional"
1695	echo "--------------------------------"
1696
1697	check_nexthop_res_support
1698	if [ $? -eq $ksft_skip ]; then
1699		return $ksft_skip
1700	fi
1701
1702	#
1703	# migration of nexthop buckets - equal weights
1704	#
1705	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1706	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1707	run_cmd "$IP nexthop add id 102 group 12/13 type resilient buckets 2 idle_timer 0"
1708
1709	run_cmd "$IP nexthop del id 13"
1710	check_nexthop "id 102" \
1711		"id 102 group 12 type resilient buckets 2 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1712	log_test $? 0 "Nexthop group updated when entry is deleted"
1713	check_nexthop_bucket "list id 102" \
1714		"id 102 index 0 nhid 12 id 102 index 1 nhid 12"
1715	log_test $? 0 "Nexthop buckets updated when entry is deleted"
1716
1717	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1718	run_cmd "$IP nexthop replace id 102 group 12/13 type resilient buckets 2 idle_timer 0"
1719	check_nexthop "id 102" \
1720		"id 102 group 12/13 type resilient buckets 2 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1721	log_test $? 0 "Nexthop group updated after replace"
1722	check_nexthop_bucket "list id 102" \
1723		"id 102 index 0 nhid 13 id 102 index 1 nhid 12"
1724	log_test $? 0 "Nexthop buckets updated after replace"
1725
1726	$IP nexthop flush >/dev/null 2>&1
1727
1728	#
1729	# migration of nexthop buckets - unequal weights
1730	#
1731	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1732	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1733	run_cmd "$IP nexthop add id 102 group 12,3/13,1 type resilient buckets 4 idle_timer 0"
1734
1735	run_cmd "$IP nexthop del id 13"
1736	check_nexthop "id 102" \
1737		"id 102 group 12,3 type resilient buckets 4 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1738	log_test $? 0 "Nexthop group updated when entry is deleted - nECMP"
1739	check_nexthop_bucket "list id 102" \
1740		"id 102 index 0 nhid 12 id 102 index 1 nhid 12 id 102 index 2 nhid 12 id 102 index 3 nhid 12"
1741	log_test $? 0 "Nexthop buckets updated when entry is deleted - nECMP"
1742
1743	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1744	run_cmd "$IP nexthop replace id 102 group 12,3/13,1 type resilient buckets 4 idle_timer 0"
1745	check_nexthop "id 102" \
1746		"id 102 group 12,3/13 type resilient buckets 4 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1747	log_test $? 0 "Nexthop group updated after replace - nECMP"
1748	check_nexthop_bucket "list id 102" \
1749		"id 102 index 0 nhid 13 id 102 index 1 nhid 12 id 102 index 2 nhid 12 id 102 index 3 nhid 12"
1750	log_test $? 0 "Nexthop buckets updated after replace - nECMP"
1751}
1752
1753ipv4_withv6_fcnal()
1754{
1755	local lladdr
1756
1757	set -e
1758	lladdr=$(get_linklocal veth2 $peer)
1759	run_cmd "$IP nexthop add id 11 via ${lladdr} dev veth1"
1760	set +e
1761	run_cmd "$IP ro add 172.16.101.1/32 nhid 11"
1762	log_test $? 0 "IPv6 nexthop with IPv4 route"
1763	check_route "172.16.101.1" "172.16.101.1 nhid 11 via inet6 ${lladdr} dev veth1"
1764
1765	set -e
1766	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1767	run_cmd "$IP nexthop add id 101 group 11/12"
1768	set +e
1769	run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
1770	log_test $? 0 "IPv6 nexthop with IPv4 route"
1771
1772	check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via inet6 ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
1773
1774	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
1775	log_test $? 0 "IPv4 route with IPv6 gateway"
1776	check_route "172.16.101.1" "172.16.101.1 via inet6 ${lladdr} dev veth1"
1777
1778	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 2001:db8:50::1 dev veth1"
1779	log_test $? 2 "IPv4 route with invalid IPv6 gateway"
1780
1781	# Test IPv4 route with loopback IPv6 nexthop
1782	# Regression test: loopback IPv6 nexthop was misclassified as reject
1783	# route, skipping nhc_pcpu_rth_output allocation, causing panic when
1784	# an IPv4 route references it and triggers __mkroute_output().
1785	run_cmd "$IP -6 nexthop add id 20 dev lo"
1786	run_cmd "$IP ro add 172.20.20.0/24 nhid 20"
1787	run_cmd "ip netns exec $me ping -c1 -W1 172.20.20.1"
1788	log_test $? 1 "IPv4 route with loopback IPv6 nexthop (no crash)"
1789	run_cmd "$IP ro del 172.20.20.0/24"
1790	run_cmd "$IP nexthop del id 20"
1791}
1792
1793ipv4_fcnal_runtime()
1794{
1795	local lladdr
1796	local rc
1797
1798	echo
1799	echo "IPv4 functional runtime"
1800	echo "-----------------------"
1801
1802	run_cmd "$IP nexthop add id 21 via 172.16.1.2 dev veth1"
1803	run_cmd "$IP ro add 172.16.101.1/32 nhid 21"
1804	log_test $? 0 "Route add"
1805	check_route "172.16.101.1" "172.16.101.1 nhid 21 via 172.16.1.2 dev veth1"
1806
1807	run_cmd "$IP ro delete 172.16.101.1/32 nhid 21"
1808	log_test $? 0 "Route delete"
1809
1810	#
1811	# scope mismatch
1812	#
1813	run_cmd "$IP nexthop add id 22 via 172.16.1.2 dev veth1"
1814	run_cmd "$IP ro add 172.16.101.1/32 nhid 22 scope host"
1815	log_test $? 2 "Route add - scope conflict with nexthop"
1816
1817	run_cmd "$IP nexthop replace id 22 dev veth3"
1818	run_cmd "$IP ro add 172.16.101.1/32 nhid 22 scope host"
1819	run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
1820	log_test $? 2 "Nexthop replace with invalid scope for existing route"
1821
1822	# check cleanup path on invalid metric
1823	run_cmd "$IP ro add 172.16.101.2/32 nhid 22 congctl lock foo"
1824	log_test $? 2 "IPv4 route with invalid metric"
1825
1826	#
1827	# add route with nexthop and check traffic
1828	#
1829	run_cmd "$IP nexthop replace id 21 via 172.16.1.2 dev veth1"
1830	run_cmd "$IP ro replace 172.16.101.1/32 nhid 21"
1831	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1832	log_test $? 0 "Basic ping"
1833
1834	run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
1835	run_cmd "$IP nexthop add id 122 group 21/22"
1836	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
1837	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1838	log_test $? 0 "Ping - multipath"
1839
1840	run_cmd "$IP ro delete 172.16.101.1/32 nhid 122"
1841
1842	#
1843	# multiple default routes
1844	# - tests fib_select_default
1845	run_cmd "$IP nexthop add id 501 via 172.16.1.2 dev veth1"
1846	run_cmd "$IP ro add default nhid 501"
1847	run_cmd "$IP ro add default via 172.16.1.3 dev veth1 metric 20"
1848	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1849	log_test $? 0 "Ping - multiple default routes, nh first"
1850
1851	# flip the order
1852	run_cmd "$IP ro del default nhid 501"
1853	run_cmd "$IP ro del default via 172.16.1.3 dev veth1 metric 20"
1854	run_cmd "$IP ro add default via 172.16.1.2 dev veth1 metric 20"
1855	run_cmd "$IP nexthop replace id 501 via 172.16.1.3 dev veth1"
1856	run_cmd "$IP ro add default nhid 501 metric 20"
1857	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1858	log_test $? 0 "Ping - multiple default routes, nh second"
1859
1860	run_cmd "$IP nexthop delete nhid 501"
1861	run_cmd "$IP ro del default"
1862
1863	#
1864	# IPv4 with blackhole nexthops
1865	#
1866	run_cmd "$IP nexthop add id 23 blackhole"
1867	run_cmd "$IP ro replace 172.16.101.1/32 nhid 23"
1868	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1869	log_test $? 2 "Ping - blackhole"
1870
1871	run_cmd "$IP nexthop replace id 23 via 172.16.1.2 dev veth1"
1872	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1873	log_test $? 0 "Ping - blackhole replaced with gateway"
1874
1875	run_cmd "$IP nexthop replace id 23 blackhole"
1876	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1877	log_test $? 2 "Ping - gateway replaced by blackhole"
1878
1879	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
1880	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1881	if [ $? -eq 0 ]; then
1882		run_cmd "$IP nexthop replace id 122 group 23"
1883		run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1884		log_test $? 2 "Ping - group with blackhole"
1885
1886		run_cmd "$IP nexthop replace id 122 group 21/22"
1887		run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1888		log_test $? 0 "Ping - group blackhole replaced with gateways"
1889	else
1890		log_test 2 0 "Ping - multipath failed"
1891	fi
1892
1893	#
1894	# device only and gw + dev only mix
1895	#
1896	run_cmd "$IP nexthop add id 85 dev veth1"
1897	run_cmd "$IP ro replace 172.16.101.1/32 nhid 85"
1898	log_test $? 0 "IPv4 route with device only nexthop"
1899	check_route "172.16.101.1" "172.16.101.1 nhid 85 dev veth1"
1900
1901	run_cmd "$IP nexthop add id 123 group 21/85"
1902	run_cmd "$IP ro replace 172.16.101.1/32 nhid 123"
1903	log_test $? 0 "IPv4 multipath route with nexthop mix - dev only + gw"
1904	check_route "172.16.101.1" "172.16.101.1 nhid 123 nexthop via 172.16.1.2 dev veth1 weight 1 nexthop dev veth1 weight 1"
1905
1906	#
1907	# IPv4 with IPv6
1908	#
1909	set -e
1910	lladdr=$(get_linklocal veth2 $peer)
1911	run_cmd "$IP nexthop add id 24 via ${lladdr} dev veth1"
1912	set +e
1913	run_cmd "$IP ro replace 172.16.101.1/32 nhid 24"
1914	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1915	log_test $? 0 "IPv6 nexthop with IPv4 route"
1916
1917	$IP neigh sh | grep -q "${lladdr} dev veth1"
1918	if [ $? -eq 1 ]; then
1919		echo "    WARNING: Neigh entry missing for ${lladdr}"
1920		$IP neigh sh | grep 'dev veth1'
1921	fi
1922
1923	$IP neigh sh | grep -q "172.16.101.1 dev eth1"
1924	if [ $? -eq 0 ]; then
1925		echo "    WARNING: Neigh entry exists for 172.16.101.1"
1926		$IP neigh sh | grep 'dev veth1'
1927	fi
1928
1929	set -e
1930	run_cmd "$IP nexthop add id 25 via 172.16.1.2 dev veth1"
1931	run_cmd "$IP nexthop add id 101 group 24/25"
1932	set +e
1933	run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
1934	log_test $? 0 "IPv4 route with mixed v4-v6 multipath route"
1935
1936	check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via inet6 ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
1937
1938	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1939	log_test $? 0 "IPv6 nexthop with IPv4 route"
1940
1941	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
1942	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1943	log_test $? 0 "IPv4 route with IPv6 gateway"
1944
1945	$IP neigh sh | grep -q "${lladdr} dev veth1"
1946	if [ $? -eq 1 ]; then
1947		echo "    WARNING: Neigh entry missing for ${lladdr}"
1948		$IP neigh sh | grep 'dev veth1'
1949	fi
1950
1951	$IP neigh sh | grep -q "172.16.101.1 dev eth1"
1952	if [ $? -eq 0 ]; then
1953		echo "    WARNING: Neigh entry exists for 172.16.101.1"
1954		$IP neigh sh | grep 'dev veth1'
1955	fi
1956
1957	run_cmd "$IP ro del 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
1958	run_cmd "$IP -4 ro add default via inet6 ${lladdr} dev veth1"
1959	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1960	log_test $? 0 "IPv4 default route with IPv6 gateway"
1961
1962	#
1963	# MPLS as an example of LWT encap
1964	#
1965	run_cmd "$IP nexthop add id 51 encap mpls 101 via 172.16.1.2 dev veth1"
1966	log_test $? 0 "IPv4 route with MPLS encap"
1967	check_nexthop "id 51" "id 51 encap mpls 101 via 172.16.1.2 dev veth1 scope link"
1968	log_test $? 0 "IPv4 route with MPLS encap - check"
1969
1970	run_cmd "$IP nexthop add id 52 encap mpls 102 via inet6 2001:db8:91::2 dev veth1"
1971	log_test $? 0 "IPv4 route with MPLS encap and v6 gateway"
1972	check_nexthop "id 52" "id 52 encap mpls 102 via 2001:db8:91::2 dev veth1 scope link"
1973	log_test $? 0 "IPv4 route with MPLS encap, v6 gw - check"
1974}
1975
1976ipv4_large_grp()
1977{
1978	local ecmp=32
1979
1980	echo
1981	echo "IPv4 large groups (x$ecmp)"
1982	echo "---------------------"
1983
1984	check_large_grp 4 $ecmp
1985
1986	$IP nexthop flush >/dev/null 2>&1
1987}
1988
1989ipv4_large_res_grp()
1990{
1991	echo
1992	echo "IPv4 large resilient group (128k buckets)"
1993	echo "-----------------------------------------"
1994
1995	check_nexthop_res_support
1996	if [ $? -eq $ksft_skip ]; then
1997		return $ksft_skip
1998	fi
1999
2000	check_large_res_grp 4 $((128 * 1024))
2001
2002	$IP nexthop flush >/dev/null 2>&1
2003}
2004
2005sysctl_nexthop_compat_mode_check()
2006{
2007	local sysctlname="net.ipv4.nexthop_compat_mode"
2008	local lprefix=$1
2009
2010	IPE="ip netns exec $me"
2011
2012	$IPE sysctl -q $sysctlname 2>&1 >/dev/null
2013	if [ $? -ne 0 ]; then
2014		echo "SKIP: kernel lacks nexthop compat mode sysctl control"
2015		return $ksft_skip
2016	fi
2017
2018	out=$($IPE sysctl $sysctlname 2>/dev/null)
2019	log_test $? 0 "$lprefix default nexthop compat mode check"
2020	check_output "${out}" "$sysctlname = 1"
2021}
2022
2023sysctl_nexthop_compat_mode_set()
2024{
2025	local sysctlname="net.ipv4.nexthop_compat_mode"
2026	local mode=$1
2027	local lprefix=$2
2028
2029	IPE="ip netns exec $me"
2030
2031	out=$($IPE sysctl -w $sysctlname=$mode)
2032	log_test $? 0 "$lprefix set compat mode - $mode"
2033	check_output "${out}" "net.ipv4.nexthop_compat_mode = $mode"
2034}
2035
2036ipv6_compat_mode()
2037{
2038	local rc
2039
2040	echo
2041	echo "IPv6 nexthop api compat mode test"
2042	echo "--------------------------------"
2043
2044	sysctl_nexthop_compat_mode_check "IPv6"
2045	if [ $? -eq $ksft_skip ]; then
2046		return $ksft_skip
2047	fi
2048
2049	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
2050	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
2051	run_cmd "$IP nexthop add id 122 group 62/63"
2052	ipmout=$(start_ip_monitor route)
2053
2054	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 122"
2055	# route add notification should contain expanded nexthops
2056	stop_ip_monitor $ipmout 3
2057	log_test $? 0 "IPv6 compat mode on - route add notification"
2058
2059	# route dump should contain expanded nexthops
2060	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 122 metric 1024 nexthop via 2001:db8:91::2 dev veth1 weight 1 nexthop via 2001:db8:91::3 dev veth1 weight 1"
2061	log_test $? 0 "IPv6 compat mode on - route dump"
2062
2063	# change in nexthop group should generate route notification
2064	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
2065	ipmout=$(start_ip_monitor route)
2066	run_cmd "$IP nexthop replace id 122 group 62/64"
2067	stop_ip_monitor $ipmout 3
2068
2069	log_test $? 0 "IPv6 compat mode on - nexthop change"
2070
2071	# set compat mode off
2072	sysctl_nexthop_compat_mode_set 0 "IPv6"
2073
2074	run_cmd "$IP -6 ro del 2001:db8:101::1/128 nhid 122"
2075
2076	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
2077	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
2078	run_cmd "$IP nexthop add id 122 group 62/63"
2079	ipmout=$(start_ip_monitor route)
2080
2081	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 122"
2082	# route add notification should not contain expanded nexthops
2083	stop_ip_monitor $ipmout 1
2084	log_test $? 0 "IPv6 compat mode off - route add notification"
2085
2086	# route dump should not contain expanded nexthops
2087	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 122 metric 1024"
2088	log_test $? 0 "IPv6 compat mode off - route dump"
2089
2090	# change in nexthop group should not generate route notification
2091	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
2092	ipmout=$(start_ip_monitor route)
2093	run_cmd "$IP nexthop replace id 122 group 62/64"
2094	stop_ip_monitor $ipmout 0
2095	log_test $? 0 "IPv6 compat mode off - nexthop change"
2096
2097	# nexthop delete should not generate route notification
2098	ipmout=$(start_ip_monitor route)
2099	run_cmd "$IP nexthop del id 122"
2100	stop_ip_monitor $ipmout 0
2101	log_test $? 0 "IPv6 compat mode off - nexthop delete"
2102
2103	# set compat mode back on
2104	sysctl_nexthop_compat_mode_set 1 "IPv6"
2105}
2106
2107ipv4_compat_mode()
2108{
2109	local rc
2110
2111	echo
2112	echo "IPv4 nexthop api compat mode"
2113	echo "----------------------------"
2114
2115	sysctl_nexthop_compat_mode_check "IPv4"
2116	if [ $? -eq $ksft_skip ]; then
2117		return $ksft_skip
2118	fi
2119
2120	run_cmd "$IP nexthop add id 21 via 172.16.1.2 dev veth1"
2121	run_cmd "$IP nexthop add id 22 via 172.16.1.2 dev veth1"
2122	run_cmd "$IP nexthop add id 122 group 21/22"
2123	ipmout=$(start_ip_monitor route)
2124
2125	run_cmd "$IP ro add 172.16.101.1/32 nhid 122"
2126	stop_ip_monitor $ipmout 3
2127
2128	# route add notification should contain expanded nexthops
2129	log_test $? 0 "IPv4 compat mode on - route add notification"
2130
2131	# route dump should contain expanded nexthops
2132	check_route "172.16.101.1" "172.16.101.1 nhid 122 nexthop via 172.16.1.2 dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
2133	log_test $? 0 "IPv4 compat mode on - route dump"
2134
2135	# change in nexthop group should generate route notification
2136	run_cmd "$IP nexthop add id 23 via 172.16.1.3 dev veth1"
2137	ipmout=$(start_ip_monitor route)
2138	run_cmd "$IP nexthop replace id 122 group 21/23"
2139	stop_ip_monitor $ipmout 3
2140	log_test $? 0 "IPv4 compat mode on - nexthop change"
2141
2142	sysctl_nexthop_compat_mode_set 0 "IPv4"
2143
2144	# cleanup
2145	run_cmd "$IP ro del 172.16.101.1/32 nhid 122"
2146
2147	ipmout=$(start_ip_monitor route)
2148	run_cmd "$IP ro add 172.16.101.1/32 nhid 122"
2149	stop_ip_monitor $ipmout 1
2150	# route add notification should not contain expanded nexthops
2151	log_test $? 0 "IPv4 compat mode off - route add notification"
2152
2153	# route dump should not contain expanded nexthops
2154	check_route "172.16.101.1" "172.16.101.1 nhid 122"
2155	log_test $? 0 "IPv4 compat mode off - route dump"
2156
2157	# change in nexthop group should not generate route notification
2158	ipmout=$(start_ip_monitor route)
2159	run_cmd "$IP nexthop replace id 122 group 21/22"
2160	stop_ip_monitor $ipmout 0
2161	log_test $? 0 "IPv4 compat mode off - nexthop change"
2162
2163	# nexthop delete should not generate route notification
2164	ipmout=$(start_ip_monitor route)
2165	run_cmd "$IP nexthop del id 122"
2166	stop_ip_monitor $ipmout 0
2167	log_test $? 0 "IPv4 compat mode off - nexthop delete"
2168
2169	sysctl_nexthop_compat_mode_set 1 "IPv4"
2170}
2171
2172ipv4_del_add_loop1()
2173{
2174	while :; do
2175		$IP nexthop del id 100
2176		$IP nexthop add id 100 via 172.16.1.2 dev veth1
2177	done >/dev/null 2>&1
2178}
2179
2180ipv4_grp_replace_loop()
2181{
2182	while :; do
2183		$IP nexthop replace id 102 group 100/101
2184	done >/dev/null 2>&1
2185}
2186
2187ipv4_torture()
2188{
2189	local pid1
2190	local pid2
2191	local pid3
2192	local pid4
2193	local pid5
2194
2195	echo
2196	echo "IPv4 runtime torture"
2197	echo "--------------------"
2198	if [ ! -x "$(command -v mausezahn)" ]; then
2199		echo "SKIP: Could not run test; need mausezahn tool"
2200		return
2201	fi
2202
2203	run_cmd "$IP nexthop add id 100 via 172.16.1.2 dev veth1"
2204	run_cmd "$IP nexthop add id 101 via 172.16.2.2 dev veth3"
2205	run_cmd "$IP nexthop add id 102 group 100/101"
2206	run_cmd "$IP route add 172.16.101.1 nhid 102"
2207	run_cmd "$IP route add 172.16.101.2 nhid 102"
2208
2209	ipv4_del_add_loop1 &
2210	pid1=$!
2211	ipv4_grp_replace_loop &
2212	pid2=$!
2213	ip netns exec $me ping -f 172.16.101.1 >/dev/null 2>&1 &
2214	pid3=$!
2215	ip netns exec $me ping -f 172.16.101.2 >/dev/null 2>&1 &
2216	pid4=$!
2217	ip netns exec $me mausezahn veth1 -B 172.16.101.2 -A 172.16.1.1 -c 0 -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
2218	pid5=$!
2219
2220	sleep 300
2221	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
2222	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
2223
2224	# if we did not crash, success
2225	log_test 0 0 "IPv4 torture test"
2226}
2227
2228ipv4_res_grp_replace_loop()
2229{
2230	while :; do
2231		$IP nexthop replace id 102 group 100/101 type resilient
2232	done >/dev/null 2>&1
2233}
2234
2235ipv4_res_torture()
2236{
2237	local pid1
2238	local pid2
2239	local pid3
2240	local pid4
2241	local pid5
2242
2243	echo
2244	echo "IPv4 runtime resilient nexthop group torture"
2245	echo "--------------------------------------------"
2246
2247	check_nexthop_res_support
2248	if [ $? -eq $ksft_skip ]; then
2249		return $ksft_skip
2250	fi
2251
2252	if [ ! -x "$(command -v mausezahn)" ]; then
2253		echo "SKIP: Could not run test; need mausezahn tool"
2254		return
2255	fi
2256
2257	run_cmd "$IP nexthop add id 100 via 172.16.1.2 dev veth1"
2258	run_cmd "$IP nexthop add id 101 via 172.16.2.2 dev veth3"
2259	run_cmd "$IP nexthop add id 102 group 100/101 type resilient buckets 512 idle_timer 0"
2260	run_cmd "$IP route add 172.16.101.1 nhid 102"
2261	run_cmd "$IP route add 172.16.101.2 nhid 102"
2262
2263	ipv4_del_add_loop1 &
2264	pid1=$!
2265	ipv4_res_grp_replace_loop &
2266	pid2=$!
2267	ip netns exec $me ping -f 172.16.101.1 >/dev/null 2>&1 &
2268	pid3=$!
2269	ip netns exec $me ping -f 172.16.101.2 >/dev/null 2>&1 &
2270	pid4=$!
2271	ip netns exec $me mausezahn veth1 \
2272				-B 172.16.101.2 -A 172.16.1.1 -c 0 \
2273				-t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
2274	pid5=$!
2275
2276	sleep 300
2277	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
2278	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
2279
2280	# if we did not crash, success
2281	log_test 0 0 "IPv4 resilient nexthop group torture test"
2282}
2283
2284basic()
2285{
2286	echo
2287	echo "Basic functional tests"
2288	echo "----------------------"
2289	run_cmd "$IP nexthop ls"
2290	log_test $? 0 "List with nothing defined"
2291
2292	run_cmd "$IP nexthop get id 1"
2293	log_test $? 2 "Nexthop get on non-existent id"
2294
2295	run_cmd "$IP nexthop del id 1"
2296	log_test $? 2 "Nexthop del with non-existent id"
2297
2298	run_cmd "$IP nexthop del id 1 group 1/2/3/4/5/6/7/8"
2299	log_test $? 2 "Nexthop del with non-existent id and extra attributes"
2300
2301	# attempt to create nh without a device or gw - fails
2302	run_cmd "$IP nexthop add id 1"
2303	log_test $? 2 "Nexthop with no device or gateway"
2304
2305	# attempt to create nh with down device - fails
2306	$IP li set veth1 down
2307	run_cmd "$IP nexthop add id 1 dev veth1"
2308	log_test $? 2 "Nexthop with down device"
2309
2310	# create nh with linkdown device - fails
2311	$IP li set veth1 up
2312	ip -netns $peer li set veth2 down
2313	run_cmd "$IP nexthop add id 1 dev veth1"
2314	log_test $? 2 "Nexthop with device that is linkdown"
2315	ip -netns $peer li set veth2 up
2316
2317	# device only
2318	run_cmd "$IP nexthop add id 1 dev veth1"
2319	log_test $? 0 "Nexthop with device only"
2320
2321	# create nh with duplicate id
2322	run_cmd "$IP nexthop add id 1 dev veth3"
2323	log_test $? 2 "Nexthop with duplicate id"
2324
2325	# blackhole nexthop
2326	run_cmd "$IP nexthop add id 2 blackhole"
2327	log_test $? 0 "Blackhole nexthop"
2328
2329	# blackhole nexthop can not have other specs
2330	run_cmd "$IP nexthop replace id 2 blackhole dev veth1"
2331	log_test $? 2 "Blackhole nexthop with other attributes"
2332
2333	# blackhole nexthop should not be affected by the state of the loopback
2334	# device
2335	run_cmd "$IP link set dev lo down"
2336	check_nexthop "id 2" "id 2 blackhole"
2337	log_test $? 0 "Blackhole nexthop with loopback device down"
2338
2339	run_cmd "$IP link set dev lo up"
2340
2341	# Dump should not loop endlessly when maximum nexthop ID is configured.
2342	run_cmd "$IP nexthop add id $((2**32-1)) blackhole"
2343	run_cmd "timeout 5 $IP nexthop"
2344	log_test $? 0 "Maximum nexthop ID dump"
2345
2346	#
2347	# groups
2348	#
2349
2350	run_cmd "$IP nexthop add id 101 group 1"
2351	log_test $? 0 "Create group"
2352
2353	run_cmd "$IP nexthop add id 102 group 2"
2354	log_test $? 0 "Create group with blackhole nexthop"
2355
2356	# multipath group can not have a blackhole as 1 path
2357	run_cmd "$IP nexthop add id 103 group 1/2"
2358	log_test $? 2 "Create multipath group where 1 path is a blackhole"
2359
2360	# multipath group can not have a member replaced by a blackhole
2361	run_cmd "$IP nexthop replace id 2 dev veth3"
2362	run_cmd "$IP nexthop replace id 102 group 1/2"
2363	run_cmd "$IP nexthop replace id 2 blackhole"
2364	log_test $? 2 "Multipath group can not have a member replaced by blackhole"
2365
2366	# attempt to create group with non-existent nexthop
2367	run_cmd "$IP nexthop add id 103 group 12"
2368	log_test $? 2 "Create group with non-existent nexthop"
2369
2370	# attempt to create group with same nexthop
2371	run_cmd "$IP nexthop add id 103 group 1/1"
2372	log_test $? 2 "Create group with same nexthop multiple times"
2373
2374	# replace nexthop with a group - fails
2375	run_cmd "$IP nexthop replace id 2 group 1"
2376	log_test $? 2 "Replace nexthop with nexthop group"
2377
2378	# replace nexthop group with a nexthop - fails
2379	run_cmd "$IP nexthop replace id 101 dev veth1"
2380	log_test $? 2 "Replace nexthop group with nexthop"
2381
2382	# nexthop group with other attributes fail
2383	run_cmd "$IP nexthop add id 104 group 1 dev veth1"
2384	log_test $? 2 "Nexthop group and device"
2385
2386	# Tests to ensure that flushing works as expected.
2387	run_cmd "$IP nexthop add id 105 blackhole proto 99"
2388	run_cmd "$IP nexthop add id 106 blackhole proto 100"
2389	run_cmd "$IP nexthop add id 107 blackhole proto 99"
2390	run_cmd "$IP nexthop flush proto 99"
2391	check_nexthop "id 105" ""
2392	check_nexthop "id 106" "id 106 blackhole proto 100"
2393	check_nexthop "id 107" ""
2394	run_cmd "$IP nexthop flush proto 100"
2395	check_nexthop "id 106" ""
2396
2397	run_cmd "$IP nexthop flush proto 100"
2398	log_test $? 0 "Test proto flush"
2399
2400	run_cmd "$IP nexthop add id 104 group 1 blackhole"
2401	log_test $? 2 "Nexthop group and blackhole"
2402
2403	$IP nexthop flush >/dev/null 2>&1
2404
2405	# Test to ensure that flushing with a multi-part nexthop dump works as
2406	# expected.
2407	local batch_file=$(mktemp)
2408
2409	for i in $(seq 1 $((64 * 1024))); do
2410		echo "nexthop add id $i blackhole" >> $batch_file
2411	done
2412
2413	$IP -b $batch_file
2414	$IP nexthop flush >/dev/null 2>&1
2415	[[ $($IP nexthop | wc -l) -eq 0 ]]
2416	log_test $? 0 "Large scale nexthop flushing"
2417
2418	rm $batch_file
2419}
2420
2421check_nexthop_buckets_balance()
2422{
2423	local nharg=$1; shift
2424	local ret
2425
2426	while (($# > 0)); do
2427		local selector=$1; shift
2428		local condition=$1; shift
2429		local count
2430
2431		count=$($IP -j nexthop bucket ${nharg} ${selector} | jq length)
2432		(( $count $condition ))
2433		ret=$?
2434		if ((ret != 0)); then
2435			return $ret
2436		fi
2437	done
2438
2439	return 0
2440}
2441
2442basic_res()
2443{
2444	echo
2445	echo "Basic resilient nexthop group functional tests"
2446	echo "----------------------------------------------"
2447
2448	check_nexthop_res_support
2449	if [ $? -eq $ksft_skip ]; then
2450		return $ksft_skip
2451	fi
2452
2453	run_cmd "$IP nexthop add id 1 dev veth1"
2454
2455	#
2456	# resilient nexthop group addition
2457	#
2458
2459	run_cmd "$IP nexthop add id 101 group 1 type resilient buckets 8"
2460	log_test $? 0 "Add a nexthop group with default parameters"
2461
2462	run_cmd "$IP nexthop get id 101"
2463	check_nexthop "id 101" \
2464		"id 101 group 1 type resilient buckets 8 idle_timer 120 unbalanced_timer 0 unbalanced_time 0"
2465	log_test $? 0 "Get a nexthop group with default parameters"
2466
2467	run_cmd "$IP nexthop add id 102 group 1 type resilient
2468			buckets 4 idle_timer 100 unbalanced_timer 5"
2469	run_cmd "$IP nexthop get id 102"
2470	check_nexthop "id 102" \
2471		"id 102 group 1 type resilient buckets 4 idle_timer 100 unbalanced_timer 5 unbalanced_time 0"
2472	log_test $? 0 "Get a nexthop group with non-default parameters"
2473
2474	run_cmd "$IP nexthop add id 103 group 1 type resilient buckets 0"
2475	log_test $? 2 "Add a nexthop group with 0 buckets"
2476
2477	#
2478	# resilient nexthop group replacement
2479	#
2480
2481	run_cmd "$IP nexthop replace id 101 group 1 type resilient
2482			buckets 8 idle_timer 240 unbalanced_timer 80"
2483	log_test $? 0 "Replace nexthop group parameters"
2484	check_nexthop "id 101" \
2485		"id 101 group 1 type resilient buckets 8 idle_timer 240 unbalanced_timer 80 unbalanced_time 0"
2486	log_test $? 0 "Get a nexthop group after replacing parameters"
2487
2488	run_cmd "$IP nexthop replace id 101 group 1 type resilient idle_timer 512"
2489	log_test $? 0 "Replace idle timer"
2490	check_nexthop "id 101" \
2491		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 80 unbalanced_time 0"
2492	log_test $? 0 "Get a nexthop group after replacing idle timer"
2493
2494	run_cmd "$IP nexthop replace id 101 group 1 type resilient unbalanced_timer 256"
2495	log_test $? 0 "Replace unbalanced timer"
2496	check_nexthop "id 101" \
2497		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2498	log_test $? 0 "Get a nexthop group after replacing unbalanced timer"
2499
2500	run_cmd "$IP nexthop replace id 101 group 1 type resilient"
2501	log_test $? 0 "Replace with no parameters"
2502	check_nexthop "id 101" \
2503		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2504	log_test $? 0 "Get a nexthop group after replacing no parameters"
2505
2506	run_cmd "$IP nexthop replace id 101 group 1"
2507	log_test $? 2 "Replace nexthop group type - implicit"
2508
2509	run_cmd "$IP nexthop replace id 101 group 1 type mpath"
2510	log_test $? 2 "Replace nexthop group type - explicit"
2511
2512	run_cmd "$IP nexthop replace id 101 group 1 type resilient buckets 1024"
2513	log_test $? 2 "Replace number of nexthop buckets"
2514
2515	check_nexthop "id 101" \
2516		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2517	log_test $? 0 "Get a nexthop group after replacing with invalid parameters"
2518
2519	#
2520	# resilient nexthop buckets dump
2521	#
2522
2523	$IP nexthop flush >/dev/null 2>&1
2524	run_cmd "$IP nexthop add id 1 dev veth1"
2525	run_cmd "$IP nexthop add id 2 dev veth3"
2526	run_cmd "$IP nexthop add id 101 group 1/2 type resilient buckets 4"
2527	run_cmd "$IP nexthop add id 201 group 1/2"
2528
2529	check_nexthop_bucket "" \
2530		"id 101 index 0 nhid 2 id 101 index 1 nhid 2 id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2531	log_test $? 0 "Dump all nexthop buckets"
2532
2533	check_nexthop_bucket "list id 101" \
2534		"id 101 index 0 nhid 2 id 101 index 1 nhid 2 id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2535	log_test $? 0 "Dump all nexthop buckets in a group"
2536
2537	sleep 0.1
2538	(( $($IP -j nexthop bucket list id 101 |
2539	     jq '[.[] | select(.bucket.idle_time > 0 and
2540	                       .bucket.idle_time < 2)] | length') == 4 ))
2541	log_test $? 0 "All nexthop buckets report a positive near-zero idle time"
2542
2543	check_nexthop_bucket "list dev veth1" \
2544		"id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2545	log_test $? 0 "Dump all nexthop buckets with a specific nexthop device"
2546
2547	check_nexthop_bucket "list nhid 2" \
2548		"id 101 index 0 nhid 2 id 101 index 1 nhid 2"
2549	log_test $? 0 "Dump all nexthop buckets with a specific nexthop identifier"
2550
2551	run_cmd "$IP nexthop bucket list id 111"
2552	log_test $? 2 "Dump all nexthop buckets in a non-existent group"
2553
2554	run_cmd "$IP nexthop bucket list id 201"
2555	log_test $? 2 "Dump all nexthop buckets in a non-resilient group"
2556
2557	run_cmd "$IP nexthop bucket list dev bla"
2558	log_test $? 255 "Dump all nexthop buckets using a non-existent device"
2559
2560	run_cmd "$IP nexthop bucket list groups"
2561	log_test $? 255 "Dump all nexthop buckets with invalid 'groups' keyword"
2562
2563	run_cmd "$IP nexthop bucket list fdb"
2564	log_test $? 255 "Dump all nexthop buckets with invalid 'fdb' keyword"
2565
2566	# Dump should not loop endlessly when maximum nexthop ID is configured.
2567	run_cmd "$IP nexthop add id $((2**32-1)) group 1/2 type resilient buckets 4"
2568	run_cmd "timeout 5 $IP nexthop bucket"
2569	log_test $? 0 "Maximum nexthop ID dump"
2570
2571	#
2572	# resilient nexthop buckets get requests
2573	#
2574
2575	check_nexthop_bucket "get id 101 index 0" "id 101 index 0 nhid 2"
2576	log_test $? 0 "Get a valid nexthop bucket"
2577
2578	run_cmd "$IP nexthop bucket get id 101 index 999"
2579	log_test $? 2 "Get a nexthop bucket with valid group, but invalid index"
2580
2581	run_cmd "$IP nexthop bucket get id 201 index 0"
2582	log_test $? 2 "Get a nexthop bucket from a non-resilient group"
2583
2584	run_cmd "$IP nexthop bucket get id 999 index 0"
2585	log_test $? 2 "Get a nexthop bucket from a non-existent group"
2586
2587	#
2588	# tests for bucket migration
2589	#
2590
2591	$IP nexthop flush >/dev/null 2>&1
2592
2593	run_cmd "$IP nexthop add id 1 dev veth1"
2594	run_cmd "$IP nexthop add id 2 dev veth3"
2595	run_cmd "$IP nexthop add id 101
2596			group 1/2 type resilient buckets 10
2597			idle_timer 1 unbalanced_timer 20"
2598
2599	check_nexthop_buckets_balance "list id 101" \
2600				      "nhid 1" "== 5" \
2601				      "nhid 2" "== 5"
2602	log_test $? 0 "Initial bucket allocation"
2603
2604	run_cmd "$IP nexthop replace id 101
2605			group 1,2/2,3 type resilient"
2606	check_nexthop_buckets_balance "list id 101" \
2607				      "nhid 1" "== 4" \
2608				      "nhid 2" "== 6"
2609	log_test $? 0 "Bucket allocation after replace"
2610
2611	# Check that increase in idle timer does not make buckets appear busy.
2612	run_cmd "$IP nexthop replace id 101
2613			group 1,2/2,3 type resilient
2614			idle_timer 10"
2615	run_cmd "$IP nexthop replace id 101
2616			group 1/2 type resilient"
2617	check_nexthop_buckets_balance "list id 101" \
2618				      "nhid 1" "== 5" \
2619				      "nhid 2" "== 5"
2620	log_test $? 0 "Buckets migrated after idle timer change"
2621
2622	$IP nexthop flush >/dev/null 2>&1
2623}
2624
2625################################################################################
2626# usage
2627
2628usage()
2629{
2630	cat <<EOF
2631usage: ${0##*/} OPTS
2632
2633        -t <test>   Test(s) to run (default: all)
2634                    (options: $ALL_TESTS)
2635        -4          IPv4 tests only
2636        -6          IPv6 tests only
2637        -p          Pause on fail
2638        -P          Pause after each test before cleanup
2639        -v          verbose mode (show commands and output)
2640	-w	    Timeout for ping
2641
2642    Runtime test
2643	-n num	    Number of nexthops to target
2644	-N    	    Use new style to install routes in DUT
2645
2646done
2647EOF
2648}
2649
2650################################################################################
2651# main
2652
2653while getopts :t:pP46hvw: o
2654do
2655	case $o in
2656		t) TESTS=$OPTARG;;
2657		4) TESTS=${IPV4_TESTS};;
2658		6) TESTS=${IPV6_TESTS};;
2659		p) PAUSE_ON_FAIL=yes;;
2660		P) PAUSE=yes;;
2661		v) VERBOSE=$(($VERBOSE + 1));;
2662		w) PING_TIMEOUT=$OPTARG;;
2663		h) usage; exit 0;;
2664		*) usage; exit 1;;
2665	esac
2666done
2667
2668# make sure we don't pause twice
2669[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
2670
2671if [ "$(id -u)" -ne 0 ];then
2672	echo "SKIP: Need root privileges"
2673	exit $ksft_skip;
2674fi
2675
2676if [ ! -x "$(command -v ip)" ]; then
2677	echo "SKIP: Could not run test without ip tool"
2678	exit $ksft_skip
2679fi
2680
2681ip help 2>&1 | grep -q nexthop
2682if [ $? -ne 0 ]; then
2683	echo "SKIP: iproute2 too old, missing nexthop command"
2684	exit $ksft_skip
2685fi
2686
2687out=$(ip nexthop ls 2>&1 | grep -q "Operation not supported")
2688if [ $? -eq 0 ]; then
2689	echo "SKIP: kernel lacks nexthop support"
2690	exit $ksft_skip
2691fi
2692
2693for t in $TESTS
2694do
2695	case $t in
2696	none) IP="ip -netns $peer"; setup; exit 0;;
2697	*) setup; $t; cleanup;;
2698	esac
2699done
2700
2701if [ "$TESTS" != "none" ]; then
2702	printf "\nTests passed: %3d\n" ${nsuccess}
2703	printf "Tests failed: %3d\n"   ${nfail}
2704	printf "Tests skipped: %2d\n"  ${nskip}
2705fi
2706
2707exit $ret
2708