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