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