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