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