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