xref: /linux/tools/testing/selftests/net/fib_nexthops.sh (revision dbf8fe85a16a33d6b6bd01f2bc606fc017771465)
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
1677ipv4_fcnal_runtime()
1678{
1679	local lladdr
1680	local rc
1681
1682	echo
1683	echo "IPv4 functional runtime"
1684	echo "-----------------------"
1685
1686	run_cmd "$IP nexthop add id 21 via 172.16.1.2 dev veth1"
1687	run_cmd "$IP ro add 172.16.101.1/32 nhid 21"
1688	log_test $? 0 "Route add"
1689	check_route "172.16.101.1" "172.16.101.1 nhid 21 via 172.16.1.2 dev veth1"
1690
1691	run_cmd "$IP ro delete 172.16.101.1/32 nhid 21"
1692	log_test $? 0 "Route delete"
1693
1694	#
1695	# scope mismatch
1696	#
1697	run_cmd "$IP nexthop add id 22 via 172.16.1.2 dev veth1"
1698	run_cmd "$IP ro add 172.16.101.1/32 nhid 22 scope host"
1699	log_test $? 2 "Route add - scope conflict with nexthop"
1700
1701	run_cmd "$IP nexthop replace id 22 dev veth3"
1702	run_cmd "$IP ro add 172.16.101.1/32 nhid 22 scope host"
1703	run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
1704	log_test $? 2 "Nexthop replace with invalid scope for existing route"
1705
1706	# check cleanup path on invalid metric
1707	run_cmd "$IP ro add 172.16.101.2/32 nhid 22 congctl lock foo"
1708	log_test $? 2 "IPv4 route with invalid metric"
1709
1710	#
1711	# add route with nexthop and check traffic
1712	#
1713	run_cmd "$IP nexthop replace id 21 via 172.16.1.2 dev veth1"
1714	run_cmd "$IP ro replace 172.16.101.1/32 nhid 21"
1715	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1716	log_test $? 0 "Basic ping"
1717
1718	run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
1719	run_cmd "$IP nexthop add id 122 group 21/22"
1720	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
1721	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1722	log_test $? 0 "Ping - multipath"
1723
1724	run_cmd "$IP ro delete 172.16.101.1/32 nhid 122"
1725
1726	#
1727	# multiple default routes
1728	# - tests fib_select_default
1729	run_cmd "$IP nexthop add id 501 via 172.16.1.2 dev veth1"
1730	run_cmd "$IP ro add default nhid 501"
1731	run_cmd "$IP ro add default via 172.16.1.3 dev veth1 metric 20"
1732	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1733	log_test $? 0 "Ping - multiple default routes, nh first"
1734
1735	# flip the order
1736	run_cmd "$IP ro del default nhid 501"
1737	run_cmd "$IP ro del default via 172.16.1.3 dev veth1 metric 20"
1738	run_cmd "$IP ro add default via 172.16.1.2 dev veth1 metric 20"
1739	run_cmd "$IP nexthop replace id 501 via 172.16.1.3 dev veth1"
1740	run_cmd "$IP ro add default nhid 501 metric 20"
1741	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1742	log_test $? 0 "Ping - multiple default routes, nh second"
1743
1744	run_cmd "$IP nexthop delete nhid 501"
1745	run_cmd "$IP ro del default"
1746
1747	#
1748	# IPv4 with blackhole nexthops
1749	#
1750	run_cmd "$IP nexthop add id 23 blackhole"
1751	run_cmd "$IP ro replace 172.16.101.1/32 nhid 23"
1752	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1753	log_test $? 2 "Ping - blackhole"
1754
1755	run_cmd "$IP nexthop replace id 23 via 172.16.1.2 dev veth1"
1756	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1757	log_test $? 0 "Ping - blackhole replaced with gateway"
1758
1759	run_cmd "$IP nexthop replace id 23 blackhole"
1760	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1761	log_test $? 2 "Ping - gateway replaced by blackhole"
1762
1763	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
1764	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1765	if [ $? -eq 0 ]; then
1766		run_cmd "$IP nexthop replace id 122 group 23"
1767		run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1768		log_test $? 2 "Ping - group with blackhole"
1769
1770		run_cmd "$IP nexthop replace id 122 group 21/22"
1771		run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1772		log_test $? 0 "Ping - group blackhole replaced with gateways"
1773	else
1774		log_test 2 0 "Ping - multipath failed"
1775	fi
1776
1777	#
1778	# device only and gw + dev only mix
1779	#
1780	run_cmd "$IP nexthop add id 85 dev veth1"
1781	run_cmd "$IP ro replace 172.16.101.1/32 nhid 85"
1782	log_test $? 0 "IPv4 route with device only nexthop"
1783	check_route "172.16.101.1" "172.16.101.1 nhid 85 dev veth1"
1784
1785	run_cmd "$IP nexthop add id 123 group 21/85"
1786	run_cmd "$IP ro replace 172.16.101.1/32 nhid 123"
1787	log_test $? 0 "IPv4 multipath route with nexthop mix - dev only + gw"
1788	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"
1789
1790	#
1791	# IPv4 with IPv6
1792	#
1793	set -e
1794	lladdr=$(get_linklocal veth2 $peer)
1795	run_cmd "$IP nexthop add id 24 via ${lladdr} dev veth1"
1796	set +e
1797	run_cmd "$IP ro replace 172.16.101.1/32 nhid 24"
1798	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1799	log_test $? 0 "IPv6 nexthop with IPv4 route"
1800
1801	$IP neigh sh | grep -q "${lladdr} dev veth1"
1802	if [ $? -eq 1 ]; then
1803		echo "    WARNING: Neigh entry missing for ${lladdr}"
1804		$IP neigh sh | grep 'dev veth1'
1805	fi
1806
1807	$IP neigh sh | grep -q "172.16.101.1 dev eth1"
1808	if [ $? -eq 0 ]; then
1809		echo "    WARNING: Neigh entry exists for 172.16.101.1"
1810		$IP neigh sh | grep 'dev veth1'
1811	fi
1812
1813	set -e
1814	run_cmd "$IP nexthop add id 25 via 172.16.1.2 dev veth1"
1815	run_cmd "$IP nexthop add id 101 group 24/25"
1816	set +e
1817	run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
1818	log_test $? 0 "IPv4 route with mixed v4-v6 multipath route"
1819
1820	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"
1821
1822	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1823	log_test $? 0 "IPv6 nexthop with IPv4 route"
1824
1825	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
1826	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1827	log_test $? 0 "IPv4 route with IPv6 gateway"
1828
1829	$IP neigh sh | grep -q "${lladdr} dev veth1"
1830	if [ $? -eq 1 ]; then
1831		echo "    WARNING: Neigh entry missing for ${lladdr}"
1832		$IP neigh sh | grep 'dev veth1'
1833	fi
1834
1835	$IP neigh sh | grep -q "172.16.101.1 dev eth1"
1836	if [ $? -eq 0 ]; then
1837		echo "    WARNING: Neigh entry exists for 172.16.101.1"
1838		$IP neigh sh | grep 'dev veth1'
1839	fi
1840
1841	run_cmd "$IP ro del 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
1842	run_cmd "$IP -4 ro add default via inet6 ${lladdr} dev veth1"
1843	run_cmd "ip netns exec $me ping -c1 -w$PING_TIMEOUT 172.16.101.1"
1844	log_test $? 0 "IPv4 default route with IPv6 gateway"
1845
1846	#
1847	# MPLS as an example of LWT encap
1848	#
1849	run_cmd "$IP nexthop add id 51 encap mpls 101 via 172.16.1.2 dev veth1"
1850	log_test $? 0 "IPv4 route with MPLS encap"
1851	check_nexthop "id 51" "id 51 encap mpls 101 via 172.16.1.2 dev veth1 scope link"
1852	log_test $? 0 "IPv4 route with MPLS encap - check"
1853
1854	run_cmd "$IP nexthop add id 52 encap mpls 102 via inet6 2001:db8:91::2 dev veth1"
1855	log_test $? 0 "IPv4 route with MPLS encap and v6 gateway"
1856	check_nexthop "id 52" "id 52 encap mpls 102 via 2001:db8:91::2 dev veth1 scope link"
1857	log_test $? 0 "IPv4 route with MPLS encap, v6 gw - check"
1858}
1859
1860ipv4_large_grp()
1861{
1862	local ecmp=32
1863
1864	echo
1865	echo "IPv4 large groups (x$ecmp)"
1866	echo "---------------------"
1867
1868	check_large_grp 4 $ecmp
1869
1870	$IP nexthop flush >/dev/null 2>&1
1871}
1872
1873ipv4_large_res_grp()
1874{
1875	echo
1876	echo "IPv4 large resilient group (128k buckets)"
1877	echo "-----------------------------------------"
1878
1879	check_nexthop_res_support
1880	if [ $? -eq $ksft_skip ]; then
1881		return $ksft_skip
1882	fi
1883
1884	check_large_res_grp 4 $((128 * 1024))
1885
1886	$IP nexthop flush >/dev/null 2>&1
1887}
1888
1889sysctl_nexthop_compat_mode_check()
1890{
1891	local sysctlname="net.ipv4.nexthop_compat_mode"
1892	local lprefix=$1
1893
1894	IPE="ip netns exec $me"
1895
1896	$IPE sysctl -q $sysctlname 2>&1 >/dev/null
1897	if [ $? -ne 0 ]; then
1898		echo "SKIP: kernel lacks nexthop compat mode sysctl control"
1899		return $ksft_skip
1900	fi
1901
1902	out=$($IPE sysctl $sysctlname 2>/dev/null)
1903	log_test $? 0 "$lprefix default nexthop compat mode check"
1904	check_output "${out}" "$sysctlname = 1"
1905}
1906
1907sysctl_nexthop_compat_mode_set()
1908{
1909	local sysctlname="net.ipv4.nexthop_compat_mode"
1910	local mode=$1
1911	local lprefix=$2
1912
1913	IPE="ip netns exec $me"
1914
1915	out=$($IPE sysctl -w $sysctlname=$mode)
1916	log_test $? 0 "$lprefix set compat mode - $mode"
1917	check_output "${out}" "net.ipv4.nexthop_compat_mode = $mode"
1918}
1919
1920ipv6_compat_mode()
1921{
1922	local rc
1923
1924	echo
1925	echo "IPv6 nexthop api compat mode test"
1926	echo "--------------------------------"
1927
1928	sysctl_nexthop_compat_mode_check "IPv6"
1929	if [ $? -eq $ksft_skip ]; then
1930		return $ksft_skip
1931	fi
1932
1933	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1934	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1935	run_cmd "$IP nexthop add id 122 group 62/63"
1936	ipmout=$(start_ip_monitor route)
1937
1938	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 122"
1939	# route add notification should contain expanded nexthops
1940	stop_ip_monitor $ipmout 3
1941	log_test $? 0 "IPv6 compat mode on - route add notification"
1942
1943	# route dump should contain expanded nexthops
1944	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"
1945	log_test $? 0 "IPv6 compat mode on - route dump"
1946
1947	# change in nexthop group should generate route notification
1948	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
1949	ipmout=$(start_ip_monitor route)
1950	run_cmd "$IP nexthop replace id 122 group 62/64"
1951	stop_ip_monitor $ipmout 3
1952
1953	log_test $? 0 "IPv6 compat mode on - nexthop change"
1954
1955	# set compat mode off
1956	sysctl_nexthop_compat_mode_set 0 "IPv6"
1957
1958	run_cmd "$IP -6 ro del 2001:db8:101::1/128 nhid 122"
1959
1960	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1961	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1962	run_cmd "$IP nexthop add id 122 group 62/63"
1963	ipmout=$(start_ip_monitor route)
1964
1965	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 122"
1966	# route add notification should not contain expanded nexthops
1967	stop_ip_monitor $ipmout 1
1968	log_test $? 0 "IPv6 compat mode off - route add notification"
1969
1970	# route dump should not contain expanded nexthops
1971	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 122 metric 1024"
1972	log_test $? 0 "IPv6 compat mode off - route dump"
1973
1974	# change in nexthop group should not generate route notification
1975	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
1976	ipmout=$(start_ip_monitor route)
1977	run_cmd "$IP nexthop replace id 122 group 62/64"
1978	stop_ip_monitor $ipmout 0
1979	log_test $? 0 "IPv6 compat mode off - nexthop change"
1980
1981	# nexthop delete should not generate route notification
1982	ipmout=$(start_ip_monitor route)
1983	run_cmd "$IP nexthop del id 122"
1984	stop_ip_monitor $ipmout 0
1985	log_test $? 0 "IPv6 compat mode off - nexthop delete"
1986
1987	# set compat mode back on
1988	sysctl_nexthop_compat_mode_set 1 "IPv6"
1989}
1990
1991ipv4_compat_mode()
1992{
1993	local rc
1994
1995	echo
1996	echo "IPv4 nexthop api compat mode"
1997	echo "----------------------------"
1998
1999	sysctl_nexthop_compat_mode_check "IPv4"
2000	if [ $? -eq $ksft_skip ]; then
2001		return $ksft_skip
2002	fi
2003
2004	run_cmd "$IP nexthop add id 21 via 172.16.1.2 dev veth1"
2005	run_cmd "$IP nexthop add id 22 via 172.16.1.2 dev veth1"
2006	run_cmd "$IP nexthop add id 122 group 21/22"
2007	ipmout=$(start_ip_monitor route)
2008
2009	run_cmd "$IP ro add 172.16.101.1/32 nhid 122"
2010	stop_ip_monitor $ipmout 3
2011
2012	# route add notification should contain expanded nexthops
2013	log_test $? 0 "IPv4 compat mode on - route add notification"
2014
2015	# route dump should contain expanded nexthops
2016	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"
2017	log_test $? 0 "IPv4 compat mode on - route dump"
2018
2019	# change in nexthop group should generate route notification
2020	run_cmd "$IP nexthop add id 23 via 172.16.1.3 dev veth1"
2021	ipmout=$(start_ip_monitor route)
2022	run_cmd "$IP nexthop replace id 122 group 21/23"
2023	stop_ip_monitor $ipmout 3
2024	log_test $? 0 "IPv4 compat mode on - nexthop change"
2025
2026	sysctl_nexthop_compat_mode_set 0 "IPv4"
2027
2028	# cleanup
2029	run_cmd "$IP ro del 172.16.101.1/32 nhid 122"
2030
2031	ipmout=$(start_ip_monitor route)
2032	run_cmd "$IP ro add 172.16.101.1/32 nhid 122"
2033	stop_ip_monitor $ipmout 1
2034	# route add notification should not contain expanded nexthops
2035	log_test $? 0 "IPv4 compat mode off - route add notification"
2036
2037	# route dump should not contain expanded nexthops
2038	check_route "172.16.101.1" "172.16.101.1 nhid 122"
2039	log_test $? 0 "IPv4 compat mode off - route dump"
2040
2041	# change in nexthop group should not generate route notification
2042	ipmout=$(start_ip_monitor route)
2043	run_cmd "$IP nexthop replace id 122 group 21/22"
2044	stop_ip_monitor $ipmout 0
2045	log_test $? 0 "IPv4 compat mode off - nexthop change"
2046
2047	# nexthop delete should not generate route notification
2048	ipmout=$(start_ip_monitor route)
2049	run_cmd "$IP nexthop del id 122"
2050	stop_ip_monitor $ipmout 0
2051	log_test $? 0 "IPv4 compat mode off - nexthop delete"
2052
2053	sysctl_nexthop_compat_mode_set 1 "IPv4"
2054}
2055
2056ipv4_del_add_loop1()
2057{
2058	while :; do
2059		$IP nexthop del id 100
2060		$IP nexthop add id 100 via 172.16.1.2 dev veth1
2061	done >/dev/null 2>&1
2062}
2063
2064ipv4_grp_replace_loop()
2065{
2066	while :; do
2067		$IP nexthop replace id 102 group 100/101
2068	done >/dev/null 2>&1
2069}
2070
2071ipv4_torture()
2072{
2073	local pid1
2074	local pid2
2075	local pid3
2076	local pid4
2077	local pid5
2078
2079	echo
2080	echo "IPv4 runtime torture"
2081	echo "--------------------"
2082	if [ ! -x "$(command -v mausezahn)" ]; then
2083		echo "SKIP: Could not run test; need mausezahn tool"
2084		return
2085	fi
2086
2087	run_cmd "$IP nexthop add id 100 via 172.16.1.2 dev veth1"
2088	run_cmd "$IP nexthop add id 101 via 172.16.2.2 dev veth3"
2089	run_cmd "$IP nexthop add id 102 group 100/101"
2090	run_cmd "$IP route add 172.16.101.1 nhid 102"
2091	run_cmd "$IP route add 172.16.101.2 nhid 102"
2092
2093	ipv4_del_add_loop1 &
2094	pid1=$!
2095	ipv4_grp_replace_loop &
2096	pid2=$!
2097	ip netns exec $me ping -f 172.16.101.1 >/dev/null 2>&1 &
2098	pid3=$!
2099	ip netns exec $me ping -f 172.16.101.2 >/dev/null 2>&1 &
2100	pid4=$!
2101	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 &
2102	pid5=$!
2103
2104	sleep 300
2105	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
2106	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
2107
2108	# if we did not crash, success
2109	log_test 0 0 "IPv4 torture test"
2110}
2111
2112ipv4_res_grp_replace_loop()
2113{
2114	while :; do
2115		$IP nexthop replace id 102 group 100/101 type resilient
2116	done >/dev/null 2>&1
2117}
2118
2119ipv4_res_torture()
2120{
2121	local pid1
2122	local pid2
2123	local pid3
2124	local pid4
2125	local pid5
2126
2127	echo
2128	echo "IPv4 runtime resilient nexthop group torture"
2129	echo "--------------------------------------------"
2130
2131	check_nexthop_res_support
2132	if [ $? -eq $ksft_skip ]; then
2133		return $ksft_skip
2134	fi
2135
2136	if [ ! -x "$(command -v mausezahn)" ]; then
2137		echo "SKIP: Could not run test; need mausezahn tool"
2138		return
2139	fi
2140
2141	run_cmd "$IP nexthop add id 100 via 172.16.1.2 dev veth1"
2142	run_cmd "$IP nexthop add id 101 via 172.16.2.2 dev veth3"
2143	run_cmd "$IP nexthop add id 102 group 100/101 type resilient buckets 512 idle_timer 0"
2144	run_cmd "$IP route add 172.16.101.1 nhid 102"
2145	run_cmd "$IP route add 172.16.101.2 nhid 102"
2146
2147	ipv4_del_add_loop1 &
2148	pid1=$!
2149	ipv4_res_grp_replace_loop &
2150	pid2=$!
2151	ip netns exec $me ping -f 172.16.101.1 >/dev/null 2>&1 &
2152	pid3=$!
2153	ip netns exec $me ping -f 172.16.101.2 >/dev/null 2>&1 &
2154	pid4=$!
2155	ip netns exec $me mausezahn veth1 \
2156				-B 172.16.101.2 -A 172.16.1.1 -c 0 \
2157				-t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
2158	pid5=$!
2159
2160	sleep 300
2161	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
2162	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
2163
2164	# if we did not crash, success
2165	log_test 0 0 "IPv4 resilient nexthop group torture test"
2166}
2167
2168basic()
2169{
2170	echo
2171	echo "Basic functional tests"
2172	echo "----------------------"
2173	run_cmd "$IP nexthop ls"
2174	log_test $? 0 "List with nothing defined"
2175
2176	run_cmd "$IP nexthop get id 1"
2177	log_test $? 2 "Nexthop get on non-existent id"
2178
2179	run_cmd "$IP nexthop del id 1"
2180	log_test $? 2 "Nexthop del with non-existent id"
2181
2182	run_cmd "$IP nexthop del id 1 group 1/2/3/4/5/6/7/8"
2183	log_test $? 2 "Nexthop del with non-existent id and extra attributes"
2184
2185	# attempt to create nh without a device or gw - fails
2186	run_cmd "$IP nexthop add id 1"
2187	log_test $? 2 "Nexthop with no device or gateway"
2188
2189	# attempt to create nh with down device - fails
2190	$IP li set veth1 down
2191	run_cmd "$IP nexthop add id 1 dev veth1"
2192	log_test $? 2 "Nexthop with down device"
2193
2194	# create nh with linkdown device - fails
2195	$IP li set veth1 up
2196	ip -netns $peer li set veth2 down
2197	run_cmd "$IP nexthop add id 1 dev veth1"
2198	log_test $? 2 "Nexthop with device that is linkdown"
2199	ip -netns $peer li set veth2 up
2200
2201	# device only
2202	run_cmd "$IP nexthop add id 1 dev veth1"
2203	log_test $? 0 "Nexthop with device only"
2204
2205	# create nh with duplicate id
2206	run_cmd "$IP nexthop add id 1 dev veth3"
2207	log_test $? 2 "Nexthop with duplicate id"
2208
2209	# blackhole nexthop
2210	run_cmd "$IP nexthop add id 2 blackhole"
2211	log_test $? 0 "Blackhole nexthop"
2212
2213	# blackhole nexthop can not have other specs
2214	run_cmd "$IP nexthop replace id 2 blackhole dev veth1"
2215	log_test $? 2 "Blackhole nexthop with other attributes"
2216
2217	# blackhole nexthop should not be affected by the state of the loopback
2218	# device
2219	run_cmd "$IP link set dev lo down"
2220	check_nexthop "id 2" "id 2 blackhole"
2221	log_test $? 0 "Blackhole nexthop with loopback device down"
2222
2223	run_cmd "$IP link set dev lo up"
2224
2225	# Dump should not loop endlessly when maximum nexthop ID is configured.
2226	run_cmd "$IP nexthop add id $((2**32-1)) blackhole"
2227	run_cmd "timeout 5 $IP nexthop"
2228	log_test $? 0 "Maximum nexthop ID dump"
2229
2230	#
2231	# groups
2232	#
2233
2234	run_cmd "$IP nexthop add id 101 group 1"
2235	log_test $? 0 "Create group"
2236
2237	run_cmd "$IP nexthop add id 102 group 2"
2238	log_test $? 0 "Create group with blackhole nexthop"
2239
2240	# multipath group can not have a blackhole as 1 path
2241	run_cmd "$IP nexthop add id 103 group 1/2"
2242	log_test $? 2 "Create multipath group where 1 path is a blackhole"
2243
2244	# multipath group can not have a member replaced by a blackhole
2245	run_cmd "$IP nexthop replace id 2 dev veth3"
2246	run_cmd "$IP nexthop replace id 102 group 1/2"
2247	run_cmd "$IP nexthop replace id 2 blackhole"
2248	log_test $? 2 "Multipath group can not have a member replaced by blackhole"
2249
2250	# attempt to create group with non-existent nexthop
2251	run_cmd "$IP nexthop add id 103 group 12"
2252	log_test $? 2 "Create group with non-existent nexthop"
2253
2254	# attempt to create group with same nexthop
2255	run_cmd "$IP nexthop add id 103 group 1/1"
2256	log_test $? 2 "Create group with same nexthop multiple times"
2257
2258	# replace nexthop with a group - fails
2259	run_cmd "$IP nexthop replace id 2 group 1"
2260	log_test $? 2 "Replace nexthop with nexthop group"
2261
2262	# replace nexthop group with a nexthop - fails
2263	run_cmd "$IP nexthop replace id 101 dev veth1"
2264	log_test $? 2 "Replace nexthop group with nexthop"
2265
2266	# nexthop group with other attributes fail
2267	run_cmd "$IP nexthop add id 104 group 1 dev veth1"
2268	log_test $? 2 "Nexthop group and device"
2269
2270	# Tests to ensure that flushing works as expected.
2271	run_cmd "$IP nexthop add id 105 blackhole proto 99"
2272	run_cmd "$IP nexthop add id 106 blackhole proto 100"
2273	run_cmd "$IP nexthop add id 107 blackhole proto 99"
2274	run_cmd "$IP nexthop flush proto 99"
2275	check_nexthop "id 105" ""
2276	check_nexthop "id 106" "id 106 blackhole proto 100"
2277	check_nexthop "id 107" ""
2278	run_cmd "$IP nexthop flush proto 100"
2279	check_nexthop "id 106" ""
2280
2281	run_cmd "$IP nexthop flush proto 100"
2282	log_test $? 0 "Test proto flush"
2283
2284	run_cmd "$IP nexthop add id 104 group 1 blackhole"
2285	log_test $? 2 "Nexthop group and blackhole"
2286
2287	$IP nexthop flush >/dev/null 2>&1
2288
2289	# Test to ensure that flushing with a multi-part nexthop dump works as
2290	# expected.
2291	local batch_file=$(mktemp)
2292
2293	for i in $(seq 1 $((64 * 1024))); do
2294		echo "nexthop add id $i blackhole" >> $batch_file
2295	done
2296
2297	$IP -b $batch_file
2298	$IP nexthop flush >/dev/null 2>&1
2299	[[ $($IP nexthop | wc -l) -eq 0 ]]
2300	log_test $? 0 "Large scale nexthop flushing"
2301
2302	rm $batch_file
2303}
2304
2305check_nexthop_buckets_balance()
2306{
2307	local nharg=$1; shift
2308	local ret
2309
2310	while (($# > 0)); do
2311		local selector=$1; shift
2312		local condition=$1; shift
2313		local count
2314
2315		count=$($IP -j nexthop bucket ${nharg} ${selector} | jq length)
2316		(( $count $condition ))
2317		ret=$?
2318		if ((ret != 0)); then
2319			return $ret
2320		fi
2321	done
2322
2323	return 0
2324}
2325
2326basic_res()
2327{
2328	echo
2329	echo "Basic resilient nexthop group functional tests"
2330	echo "----------------------------------------------"
2331
2332	check_nexthop_res_support
2333	if [ $? -eq $ksft_skip ]; then
2334		return $ksft_skip
2335	fi
2336
2337	run_cmd "$IP nexthop add id 1 dev veth1"
2338
2339	#
2340	# resilient nexthop group addition
2341	#
2342
2343	run_cmd "$IP nexthop add id 101 group 1 type resilient buckets 8"
2344	log_test $? 0 "Add a nexthop group with default parameters"
2345
2346	run_cmd "$IP nexthop get id 101"
2347	check_nexthop "id 101" \
2348		"id 101 group 1 type resilient buckets 8 idle_timer 120 unbalanced_timer 0 unbalanced_time 0"
2349	log_test $? 0 "Get a nexthop group with default parameters"
2350
2351	run_cmd "$IP nexthop add id 102 group 1 type resilient
2352			buckets 4 idle_timer 100 unbalanced_timer 5"
2353	run_cmd "$IP nexthop get id 102"
2354	check_nexthop "id 102" \
2355		"id 102 group 1 type resilient buckets 4 idle_timer 100 unbalanced_timer 5 unbalanced_time 0"
2356	log_test $? 0 "Get a nexthop group with non-default parameters"
2357
2358	run_cmd "$IP nexthop add id 103 group 1 type resilient buckets 0"
2359	log_test $? 2 "Add a nexthop group with 0 buckets"
2360
2361	#
2362	# resilient nexthop group replacement
2363	#
2364
2365	run_cmd "$IP nexthop replace id 101 group 1 type resilient
2366			buckets 8 idle_timer 240 unbalanced_timer 80"
2367	log_test $? 0 "Replace nexthop group parameters"
2368	check_nexthop "id 101" \
2369		"id 101 group 1 type resilient buckets 8 idle_timer 240 unbalanced_timer 80 unbalanced_time 0"
2370	log_test $? 0 "Get a nexthop group after replacing parameters"
2371
2372	run_cmd "$IP nexthop replace id 101 group 1 type resilient idle_timer 512"
2373	log_test $? 0 "Replace idle timer"
2374	check_nexthop "id 101" \
2375		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 80 unbalanced_time 0"
2376	log_test $? 0 "Get a nexthop group after replacing idle timer"
2377
2378	run_cmd "$IP nexthop replace id 101 group 1 type resilient unbalanced_timer 256"
2379	log_test $? 0 "Replace unbalanced timer"
2380	check_nexthop "id 101" \
2381		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2382	log_test $? 0 "Get a nexthop group after replacing unbalanced timer"
2383
2384	run_cmd "$IP nexthop replace id 101 group 1 type resilient"
2385	log_test $? 0 "Replace with no parameters"
2386	check_nexthop "id 101" \
2387		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2388	log_test $? 0 "Get a nexthop group after replacing no parameters"
2389
2390	run_cmd "$IP nexthop replace id 101 group 1"
2391	log_test $? 2 "Replace nexthop group type - implicit"
2392
2393	run_cmd "$IP nexthop replace id 101 group 1 type mpath"
2394	log_test $? 2 "Replace nexthop group type - explicit"
2395
2396	run_cmd "$IP nexthop replace id 101 group 1 type resilient buckets 1024"
2397	log_test $? 2 "Replace number of nexthop buckets"
2398
2399	check_nexthop "id 101" \
2400		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2401	log_test $? 0 "Get a nexthop group after replacing with invalid parameters"
2402
2403	#
2404	# resilient nexthop buckets dump
2405	#
2406
2407	$IP nexthop flush >/dev/null 2>&1
2408	run_cmd "$IP nexthop add id 1 dev veth1"
2409	run_cmd "$IP nexthop add id 2 dev veth3"
2410	run_cmd "$IP nexthop add id 101 group 1/2 type resilient buckets 4"
2411	run_cmd "$IP nexthop add id 201 group 1/2"
2412
2413	check_nexthop_bucket "" \
2414		"id 101 index 0 nhid 2 id 101 index 1 nhid 2 id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2415	log_test $? 0 "Dump all nexthop buckets"
2416
2417	check_nexthop_bucket "list id 101" \
2418		"id 101 index 0 nhid 2 id 101 index 1 nhid 2 id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2419	log_test $? 0 "Dump all nexthop buckets in a group"
2420
2421	sleep 0.1
2422	(( $($IP -j nexthop bucket list id 101 |
2423	     jq '[.[] | select(.bucket.idle_time > 0 and
2424	                       .bucket.idle_time < 2)] | length') == 4 ))
2425	log_test $? 0 "All nexthop buckets report a positive near-zero idle time"
2426
2427	check_nexthop_bucket "list dev veth1" \
2428		"id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2429	log_test $? 0 "Dump all nexthop buckets with a specific nexthop device"
2430
2431	check_nexthop_bucket "list nhid 2" \
2432		"id 101 index 0 nhid 2 id 101 index 1 nhid 2"
2433	log_test $? 0 "Dump all nexthop buckets with a specific nexthop identifier"
2434
2435	run_cmd "$IP nexthop bucket list id 111"
2436	log_test $? 2 "Dump all nexthop buckets in a non-existent group"
2437
2438	run_cmd "$IP nexthop bucket list id 201"
2439	log_test $? 2 "Dump all nexthop buckets in a non-resilient group"
2440
2441	run_cmd "$IP nexthop bucket list dev bla"
2442	log_test $? 255 "Dump all nexthop buckets using a non-existent device"
2443
2444	run_cmd "$IP nexthop bucket list groups"
2445	log_test $? 255 "Dump all nexthop buckets with invalid 'groups' keyword"
2446
2447	run_cmd "$IP nexthop bucket list fdb"
2448	log_test $? 255 "Dump all nexthop buckets with invalid 'fdb' keyword"
2449
2450	# Dump should not loop endlessly when maximum nexthop ID is configured.
2451	run_cmd "$IP nexthop add id $((2**32-1)) group 1/2 type resilient buckets 4"
2452	run_cmd "timeout 5 $IP nexthop bucket"
2453	log_test $? 0 "Maximum nexthop ID dump"
2454
2455	#
2456	# resilient nexthop buckets get requests
2457	#
2458
2459	check_nexthop_bucket "get id 101 index 0" "id 101 index 0 nhid 2"
2460	log_test $? 0 "Get a valid nexthop bucket"
2461
2462	run_cmd "$IP nexthop bucket get id 101 index 999"
2463	log_test $? 2 "Get a nexthop bucket with valid group, but invalid index"
2464
2465	run_cmd "$IP nexthop bucket get id 201 index 0"
2466	log_test $? 2 "Get a nexthop bucket from a non-resilient group"
2467
2468	run_cmd "$IP nexthop bucket get id 999 index 0"
2469	log_test $? 2 "Get a nexthop bucket from a non-existent group"
2470
2471	#
2472	# tests for bucket migration
2473	#
2474
2475	$IP nexthop flush >/dev/null 2>&1
2476
2477	run_cmd "$IP nexthop add id 1 dev veth1"
2478	run_cmd "$IP nexthop add id 2 dev veth3"
2479	run_cmd "$IP nexthop add id 101
2480			group 1/2 type resilient buckets 10
2481			idle_timer 1 unbalanced_timer 20"
2482
2483	check_nexthop_buckets_balance "list id 101" \
2484				      "nhid 1" "== 5" \
2485				      "nhid 2" "== 5"
2486	log_test $? 0 "Initial bucket allocation"
2487
2488	run_cmd "$IP nexthop replace id 101
2489			group 1,2/2,3 type resilient"
2490	check_nexthop_buckets_balance "list id 101" \
2491				      "nhid 1" "== 4" \
2492				      "nhid 2" "== 6"
2493	log_test $? 0 "Bucket allocation after replace"
2494
2495	# Check that increase in idle timer does not make buckets appear busy.
2496	run_cmd "$IP nexthop replace id 101
2497			group 1,2/2,3 type resilient
2498			idle_timer 10"
2499	run_cmd "$IP nexthop replace id 101
2500			group 1/2 type resilient"
2501	check_nexthop_buckets_balance "list id 101" \
2502				      "nhid 1" "== 5" \
2503				      "nhid 2" "== 5"
2504	log_test $? 0 "Buckets migrated after idle timer change"
2505
2506	$IP nexthop flush >/dev/null 2>&1
2507}
2508
2509################################################################################
2510# usage
2511
2512usage()
2513{
2514	cat <<EOF
2515usage: ${0##*/} OPTS
2516
2517        -t <test>   Test(s) to run (default: all)
2518                    (options: $ALL_TESTS)
2519        -4          IPv4 tests only
2520        -6          IPv6 tests only
2521        -p          Pause on fail
2522        -P          Pause after each test before cleanup
2523        -v          verbose mode (show commands and output)
2524	-w	    Timeout for ping
2525
2526    Runtime test
2527	-n num	    Number of nexthops to target
2528	-N    	    Use new style to install routes in DUT
2529
2530done
2531EOF
2532}
2533
2534################################################################################
2535# main
2536
2537while getopts :t:pP46hvw: o
2538do
2539	case $o in
2540		t) TESTS=$OPTARG;;
2541		4) TESTS=${IPV4_TESTS};;
2542		6) TESTS=${IPV6_TESTS};;
2543		p) PAUSE_ON_FAIL=yes;;
2544		P) PAUSE=yes;;
2545		v) VERBOSE=$(($VERBOSE + 1));;
2546		w) PING_TIMEOUT=$OPTARG;;
2547		h) usage; exit 0;;
2548		*) usage; exit 1;;
2549	esac
2550done
2551
2552# make sure we don't pause twice
2553[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
2554
2555if [ "$(id -u)" -ne 0 ];then
2556	echo "SKIP: Need root privileges"
2557	exit $ksft_skip;
2558fi
2559
2560if [ ! -x "$(command -v ip)" ]; then
2561	echo "SKIP: Could not run test without ip tool"
2562	exit $ksft_skip
2563fi
2564
2565ip help 2>&1 | grep -q nexthop
2566if [ $? -ne 0 ]; then
2567	echo "SKIP: iproute2 too old, missing nexthop command"
2568	exit $ksft_skip
2569fi
2570
2571out=$(ip nexthop ls 2>&1 | grep -q "Operation not supported")
2572if [ $? -eq 0 ]; then
2573	echo "SKIP: kernel lacks nexthop support"
2574	exit $ksft_skip
2575fi
2576
2577for t in $TESTS
2578do
2579	case $t in
2580	none) IP="ip -netns $peer"; setup; exit 0;;
2581	*) setup; $t; cleanup;;
2582	esac
2583done
2584
2585if [ "$TESTS" != "none" ]; then
2586	printf "\nTests passed: %3d\n" ${nsuccess}
2587	printf "Tests failed: %3d\n"   ${nfail}
2588	printf "Tests skipped: %2d\n"  ${nskip}
2589fi
2590
2591exit $ret
2592