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