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_fcnal()
633{
634	local rc
635
636	echo
637	echo "IPv6 groups functional"
638	echo "----------------------"
639
640	# basic functionality: create a nexthop group, default weight
641	run_cmd "$IP nexthop add id 61 via 2001:db8:91::2 dev veth1"
642	run_cmd "$IP nexthop add id 101 group 61"
643	log_test $? 0 "Create nexthop group with single nexthop"
644
645	# get nexthop group
646	run_cmd "$IP nexthop get id 101"
647	log_test $? 0 "Get nexthop group by id"
648	check_nexthop "id 101" "id 101 group 61"
649
650	# delete nexthop group
651	run_cmd "$IP nexthop del id 101"
652	log_test $? 0 "Delete nexthop group by id"
653	check_nexthop "id 101" ""
654
655	$IP nexthop flush >/dev/null 2>&1
656	check_nexthop "id 101" ""
657
658	#
659	# create group with multiple nexthops - mix of gw and dev only
660	#
661	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
662	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
663	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
664	run_cmd "$IP nexthop add id 65 dev veth1"
665	run_cmd "$IP nexthop add id 102 group 62/63/64/65"
666	log_test $? 0 "Nexthop group with multiple nexthops"
667	check_nexthop "id 102" "id 102 group 62/63/64/65"
668
669	# Delete nexthop in a group and group is updated
670	run_cmd "$IP nexthop del id 63"
671	check_nexthop "id 102" "id 102 group 62/64/65"
672	log_test $? 0 "Nexthop group updated when entry is deleted"
673
674	# create group with multiple weighted nexthops
675	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
676	run_cmd "$IP nexthop add id 103 group 62/63,2/64,3/65,4"
677	log_test $? 0 "Nexthop group with weighted nexthops"
678	check_nexthop "id 103" "id 103 group 62/63,2/64,3/65,4"
679
680	# Delete nexthop in a weighted group and group is updated
681	run_cmd "$IP nexthop del id 63"
682	check_nexthop "id 103" "id 103 group 62/64,3/65,4"
683	log_test $? 0 "Weighted nexthop group updated when entry is deleted"
684
685	# admin down - nexthop is removed from group
686	run_cmd "$IP li set dev veth1 down"
687	check_nexthop "dev veth1" ""
688	log_test $? 0 "Nexthops in groups removed on admin down"
689
690	# expect groups to have been deleted as well
691	check_nexthop "" ""
692
693	run_cmd "$IP li set dev veth1 up"
694
695	$IP nexthop flush >/dev/null 2>&1
696
697	# group with nexthops using different devices
698	set -e
699	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
700	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
701	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
702	run_cmd "$IP nexthop add id 65 via 2001:db8:91::5 dev veth1"
703
704	run_cmd "$IP nexthop add id 72 via 2001:db8:92::2 dev veth3"
705	run_cmd "$IP nexthop add id 73 via 2001:db8:92::3 dev veth3"
706	run_cmd "$IP nexthop add id 74 via 2001:db8:92::4 dev veth3"
707	run_cmd "$IP nexthop add id 75 via 2001:db8:92::5 dev veth3"
708	set +e
709
710	# multiple groups with same nexthop
711	run_cmd "$IP nexthop add id 104 group 62"
712	run_cmd "$IP nexthop add id 105 group 62"
713	check_nexthop "group" "id 104 group 62 id 105 group 62"
714	log_test $? 0 "Multiple groups with same nexthop"
715
716	run_cmd "$IP nexthop flush groups"
717	[ $? -ne 0 ] && return 1
718
719	# on admin down of veth1, it should be removed from the group
720	run_cmd "$IP nexthop add id 105 group 62/63/72/73/64"
721	run_cmd "$IP li set veth1 down"
722	check_nexthop "id 105" "id 105 group 72/73"
723	log_test $? 0 "Nexthops in group removed on admin down - mixed group"
724
725	run_cmd "$IP nexthop add id 106 group 105/74"
726	log_test $? 2 "Nexthop group can not have a group as an entry"
727
728	# a group can have a blackhole entry only if it is the only
729	# nexthop in the group. Needed for atomic replace with an
730	# actual nexthop group
731	run_cmd "$IP -6 nexthop add id 31 blackhole"
732	run_cmd "$IP nexthop add id 107 group 31"
733	log_test $? 0 "Nexthop group with a blackhole entry"
734
735	run_cmd "$IP nexthop add id 108 group 31/24"
736	log_test $? 2 "Nexthop group can not have a blackhole and another nexthop"
737}
738
739ipv6_res_grp_fcnal()
740{
741	local rc
742
743	echo
744	echo "IPv6 resilient groups functional"
745	echo "--------------------------------"
746
747	check_nexthop_res_support
748	if [ $? -eq $ksft_skip ]; then
749		return $ksft_skip
750	fi
751
752	#
753	# migration of nexthop buckets - equal weights
754	#
755	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
756	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
757	run_cmd "$IP nexthop add id 102 group 62/63 type resilient buckets 2 idle_timer 0"
758
759	run_cmd "$IP nexthop del id 63"
760	check_nexthop "id 102" \
761		"id 102 group 62 type resilient buckets 2 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
762	log_test $? 0 "Nexthop group updated when entry is deleted"
763	check_nexthop_bucket "list id 102" \
764		"id 102 index 0 nhid 62 id 102 index 1 nhid 62"
765	log_test $? 0 "Nexthop buckets updated when entry is deleted"
766
767	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
768	run_cmd "$IP nexthop replace id 102 group 62/63 type resilient buckets 2 idle_timer 0"
769	check_nexthop "id 102" \
770		"id 102 group 62/63 type resilient buckets 2 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
771	log_test $? 0 "Nexthop group updated after replace"
772	check_nexthop_bucket "list id 102" \
773		"id 102 index 0 nhid 63 id 102 index 1 nhid 62"
774	log_test $? 0 "Nexthop buckets updated after replace"
775
776	$IP nexthop flush >/dev/null 2>&1
777
778	#
779	# migration of nexthop buckets - unequal weights
780	#
781	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
782	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
783	run_cmd "$IP nexthop add id 102 group 62,3/63,1 type resilient buckets 4 idle_timer 0"
784
785	run_cmd "$IP nexthop del id 63"
786	check_nexthop "id 102" \
787		"id 102 group 62,3 type resilient buckets 4 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
788	log_test $? 0 "Nexthop group updated when entry is deleted - nECMP"
789	check_nexthop_bucket "list id 102" \
790		"id 102 index 0 nhid 62 id 102 index 1 nhid 62 id 102 index 2 nhid 62 id 102 index 3 nhid 62"
791	log_test $? 0 "Nexthop buckets updated when entry is deleted - nECMP"
792
793	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
794	run_cmd "$IP nexthop replace id 102 group 62,3/63,1 type resilient buckets 4 idle_timer 0"
795	check_nexthop "id 102" \
796		"id 102 group 62,3/63 type resilient buckets 4 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
797	log_test $? 0 "Nexthop group updated after replace - nECMP"
798	check_nexthop_bucket "list id 102" \
799		"id 102 index 0 nhid 63 id 102 index 1 nhid 62 id 102 index 2 nhid 62 id 102 index 3 nhid 62"
800	log_test $? 0 "Nexthop buckets updated after replace - nECMP"
801}
802
803ipv6_fcnal_runtime()
804{
805	local rc
806
807	echo
808	echo "IPv6 functional runtime"
809	echo "-----------------------"
810
811	#
812	# IPv6 - the basics
813	#
814	run_cmd "$IP nexthop add id 81 via 2001:db8:91::2 dev veth1"
815	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
816	log_test $? 0 "Route add"
817
818	run_cmd "$IP ro delete 2001:db8:101::1/128 nhid 81"
819	log_test $? 0 "Route delete"
820
821	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
822	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
823	log_test $? 0 "Ping with nexthop"
824
825	run_cmd "$IP nexthop add id 82 via 2001:db8:92::2 dev veth3"
826	run_cmd "$IP nexthop add id 122 group 81/82"
827	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
828	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
829	log_test $? 0 "Ping - multipath"
830
831	#
832	# IPv6 with blackhole nexthops
833	#
834	run_cmd "$IP -6 nexthop add id 83 blackhole"
835	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 83"
836	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
837	log_test $? 2 "Ping - blackhole"
838
839	run_cmd "$IP nexthop replace id 83 via 2001:db8:91::2 dev veth1"
840	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
841	log_test $? 0 "Ping - blackhole replaced with gateway"
842
843	run_cmd "$IP -6 nexthop replace id 83 blackhole"
844	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
845	log_test $? 2 "Ping - gateway replaced by blackhole"
846
847	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
848	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
849	if [ $? -eq 0 ]; then
850		run_cmd "$IP nexthop replace id 122 group 83"
851		run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
852		log_test $? 2 "Ping - group with blackhole"
853
854		run_cmd "$IP nexthop replace id 122 group 81/82"
855		run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
856		log_test $? 0 "Ping - group blackhole replaced with gateways"
857	else
858		log_test 2 0 "Ping - multipath failed"
859	fi
860
861	#
862	# device only and gw + dev only mix
863	#
864	run_cmd "$IP -6 nexthop add id 85 dev veth1"
865	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 85"
866	log_test $? 0 "IPv6 route with device only nexthop"
867	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 dev veth1 metric 1024"
868
869	run_cmd "$IP nexthop add id 123 group 81/85"
870	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 123"
871	log_test $? 0 "IPv6 multipath route with nexthop mix - dev only + gw"
872	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"
873
874	#
875	# IPv6 route with v4 nexthop - not allowed
876	#
877	run_cmd "$IP ro delete 2001:db8:101::1/128"
878	run_cmd "$IP nexthop add id 84 via 172.16.1.1 dev veth1"
879	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 84"
880	log_test $? 2 "IPv6 route can not have a v4 gateway"
881
882	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 81"
883	run_cmd "$IP nexthop replace id 81 via 172.16.1.1 dev veth1"
884	log_test $? 2 "Nexthop replace - v6 route, v4 nexthop"
885
886	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
887	run_cmd "$IP nexthop replace id 81 via 172.16.1.1 dev veth1"
888	log_test $? 2 "Nexthop replace of group entry - v6 route, v4 nexthop"
889
890	run_cmd "$IP nexthop add id 86 via 2001:db8:92::2 dev veth3"
891	run_cmd "$IP nexthop add id 87 via 172.16.1.1 dev veth1"
892	run_cmd "$IP nexthop add id 88 via 172.16.1.1 dev veth1"
893	run_cmd "$IP nexthop add id 124 group 86/87/88"
894	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
895	log_test $? 2 "IPv6 route can not have a group with v4 and v6 gateways"
896
897	run_cmd "$IP nexthop del id 88"
898	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
899	log_test $? 2 "IPv6 route can not have a group with v4 and v6 gateways"
900
901	run_cmd "$IP nexthop del id 87"
902	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
903	log_test $? 0 "IPv6 route using a group after removing v4 gateways"
904
905	run_cmd "$IP ro delete 2001:db8:101::1/128"
906	run_cmd "$IP nexthop add id 87 via 172.16.1.1 dev veth1"
907	run_cmd "$IP nexthop add id 88 via 172.16.1.1 dev veth1"
908	run_cmd "$IP nexthop replace id 124 group 86/87/88"
909	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
910	log_test $? 2 "IPv6 route can not have a group with v4 and v6 gateways"
911
912	run_cmd "$IP nexthop replace id 88 via 2001:db8:92::2 dev veth3"
913	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
914	log_test $? 2 "IPv6 route can not have a group with v4 and v6 gateways"
915
916	run_cmd "$IP nexthop replace id 87 via 2001:db8:92::2 dev veth3"
917	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 124"
918	log_test $? 0 "IPv6 route using a group after replacing v4 gateways"
919
920	$IP nexthop flush >/dev/null 2>&1
921
922	#
923	# weird IPv6 cases
924	#
925	run_cmd "$IP nexthop add id 86 via 2001:db8:91::2 dev veth1"
926	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
927
928	# rpfilter and default route
929	$IP nexthop flush >/dev/null 2>&1
930	run_cmd "ip netns exec me ip6tables -t mangle -I PREROUTING 1 -m rpfilter --invert -j DROP"
931	run_cmd "$IP nexthop add id 91 via 2001:db8:91::2 dev veth1"
932	run_cmd "$IP nexthop add id 92 via 2001:db8:92::2 dev veth3"
933	run_cmd "$IP nexthop add id 93 group 91/92"
934	run_cmd "$IP -6 ro add default nhid 91"
935	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
936	log_test $? 0 "Nexthop with default route and rpfilter"
937	run_cmd "$IP -6 ro replace default nhid 93"
938	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
939	log_test $? 0 "Nexthop with multipath default route and rpfilter"
940
941	# TO-DO:
942	# existing route with old nexthop; append route with new nexthop
943	# existing route with old nexthop; replace route with new
944	# existing route with new nexthop; replace route with old
945	# route with src address and using nexthop - not allowed
946}
947
948ipv6_large_grp()
949{
950	local ecmp=32
951
952	echo
953	echo "IPv6 large groups (x$ecmp)"
954	echo "---------------------"
955
956	check_large_grp 6 $ecmp
957
958	$IP nexthop flush >/dev/null 2>&1
959}
960
961ipv6_large_res_grp()
962{
963	echo
964	echo "IPv6 large resilient group (128k buckets)"
965	echo "-----------------------------------------"
966
967	check_nexthop_res_support
968	if [ $? -eq $ksft_skip ]; then
969		return $ksft_skip
970	fi
971
972	check_large_res_grp 6 $((128 * 1024))
973
974	$IP nexthop flush >/dev/null 2>&1
975}
976
977ipv6_del_add_loop1()
978{
979	while :; do
980		$IP nexthop del id 100
981		$IP nexthop add id 100 via 2001:db8:91::2 dev veth1
982	done >/dev/null 2>&1
983}
984
985ipv6_grp_replace_loop()
986{
987	while :; do
988		$IP nexthop replace id 102 group 100/101
989	done >/dev/null 2>&1
990}
991
992ipv6_torture()
993{
994	local pid1
995	local pid2
996	local pid3
997	local pid4
998	local pid5
999
1000	echo
1001	echo "IPv6 runtime torture"
1002	echo "--------------------"
1003	if [ ! -x "$(command -v mausezahn)" ]; then
1004		echo "SKIP: Could not run test; need mausezahn tool"
1005		return
1006	fi
1007
1008	run_cmd "$IP nexthop add id 100 via 2001:db8:91::2 dev veth1"
1009	run_cmd "$IP nexthop add id 101 via 2001:db8:92::2 dev veth3"
1010	run_cmd "$IP nexthop add id 102 group 100/101"
1011	run_cmd "$IP route add 2001:db8:101::1 nhid 102"
1012	run_cmd "$IP route add 2001:db8:101::2 nhid 102"
1013
1014	ipv6_del_add_loop1 &
1015	pid1=$!
1016	ipv6_grp_replace_loop &
1017	pid2=$!
1018	ip netns exec me ping -f 2001:db8:101::1 >/dev/null 2>&1 &
1019	pid3=$!
1020	ip netns exec me ping -f 2001:db8:101::2 >/dev/null 2>&1 &
1021	pid4=$!
1022	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 &
1023	pid5=$!
1024
1025	sleep 300
1026	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
1027	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
1028
1029	# if we did not crash, success
1030	log_test 0 0 "IPv6 torture test"
1031}
1032
1033ipv6_res_grp_replace_loop()
1034{
1035	while :; do
1036		$IP nexthop replace id 102 group 100/101 type resilient
1037	done >/dev/null 2>&1
1038}
1039
1040ipv6_res_torture()
1041{
1042	local pid1
1043	local pid2
1044	local pid3
1045	local pid4
1046	local pid5
1047
1048	echo
1049	echo "IPv6 runtime resilient nexthop group torture"
1050	echo "--------------------------------------------"
1051
1052	check_nexthop_res_support
1053	if [ $? -eq $ksft_skip ]; then
1054		return $ksft_skip
1055	fi
1056
1057	if [ ! -x "$(command -v mausezahn)" ]; then
1058		echo "SKIP: Could not run test; need mausezahn tool"
1059		return
1060	fi
1061
1062	run_cmd "$IP nexthop add id 100 via 2001:db8:91::2 dev veth1"
1063	run_cmd "$IP nexthop add id 101 via 2001:db8:92::2 dev veth3"
1064	run_cmd "$IP nexthop add id 102 group 100/101 type resilient buckets 512 idle_timer 0"
1065	run_cmd "$IP route add 2001:db8:101::1 nhid 102"
1066	run_cmd "$IP route add 2001:db8:101::2 nhid 102"
1067
1068	ipv6_del_add_loop1 &
1069	pid1=$!
1070	ipv6_res_grp_replace_loop &
1071	pid2=$!
1072	ip netns exec me ping -f 2001:db8:101::1 >/dev/null 2>&1 &
1073	pid3=$!
1074	ip netns exec me ping -f 2001:db8:101::2 >/dev/null 2>&1 &
1075	pid4=$!
1076	ip netns exec me mausezahn -6 veth1 \
1077			    -B 2001:db8:101::2 -A 2001:db8:91::1 -c 0 \
1078			    -t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
1079	pid5=$!
1080
1081	sleep 300
1082	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
1083	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
1084
1085	# if we did not crash, success
1086	log_test 0 0 "IPv6 resilient nexthop group torture test"
1087}
1088
1089ipv4_fcnal()
1090{
1091	local rc
1092
1093	echo
1094	echo "IPv4 functional"
1095	echo "----------------------"
1096
1097	#
1098	# basic IPv4 ops - add, get, delete
1099	#
1100	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1101	rc=$?
1102	log_test $rc 0 "Create nexthop with id, gw, dev"
1103	if [ $rc -ne 0 ]; then
1104		echo "Basic IPv4 create fails; can not continue"
1105		return 1
1106	fi
1107
1108	run_cmd "$IP nexthop get id 12"
1109	log_test $? 0 "Get nexthop by id"
1110	check_nexthop "id 12" "id 12 via 172.16.1.2 dev veth1 scope link"
1111
1112	run_cmd "$IP nexthop del id 12"
1113	log_test $? 0 "Delete nexthop by id"
1114	check_nexthop "id 52" ""
1115
1116	#
1117	# gw, device spec
1118	#
1119	# gw validation, no device - fails since dev is required
1120	run_cmd "$IP nexthop add id 12 via 172.16.2.3"
1121	log_test $? 2 "Create nexthop - gw only"
1122
1123	# gw not reachable through given dev
1124	run_cmd "$IP nexthop add id 13 via 172.16.3.2 dev veth1"
1125	log_test $? 2 "Create nexthop - invalid gw+dev combination"
1126
1127	# onlink flag overrides gw+dev lookup
1128	run_cmd "$IP nexthop add id 13 via 172.16.3.2 dev veth1 onlink"
1129	log_test $? 0 "Create nexthop - gw+dev and onlink"
1130
1131	# admin down should delete nexthops
1132	set -e
1133	run_cmd "$IP nexthop add id 15 via 172.16.1.3 dev veth1"
1134	run_cmd "$IP nexthop add id 16 via 172.16.1.4 dev veth1"
1135	run_cmd "$IP nexthop add id 17 via 172.16.1.5 dev veth1"
1136	run_cmd "$IP li set dev veth1 down"
1137	set +e
1138	check_nexthop "dev veth1" ""
1139	log_test $? 0 "Nexthops removed on admin down"
1140}
1141
1142ipv4_grp_fcnal()
1143{
1144	local rc
1145
1146	echo
1147	echo "IPv4 groups functional"
1148	echo "----------------------"
1149
1150	# basic functionality: create a nexthop group, default weight
1151	run_cmd "$IP nexthop add id 11 via 172.16.1.2 dev veth1"
1152	run_cmd "$IP nexthop add id 101 group 11"
1153	log_test $? 0 "Create nexthop group with single nexthop"
1154
1155	# get nexthop group
1156	run_cmd "$IP nexthop get id 101"
1157	log_test $? 0 "Get nexthop group by id"
1158	check_nexthop "id 101" "id 101 group 11"
1159
1160	# delete nexthop group
1161	run_cmd "$IP nexthop del id 101"
1162	log_test $? 0 "Delete nexthop group by id"
1163	check_nexthop "id 101" ""
1164
1165	$IP nexthop flush >/dev/null 2>&1
1166
1167	#
1168	# create group with multiple nexthops
1169	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1170	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1171	run_cmd "$IP nexthop add id 14 via 172.16.1.4 dev veth1"
1172	run_cmd "$IP nexthop add id 15 via 172.16.1.5 dev veth1"
1173	run_cmd "$IP nexthop add id 102 group 12/13/14/15"
1174	log_test $? 0 "Nexthop group with multiple nexthops"
1175	check_nexthop "id 102" "id 102 group 12/13/14/15"
1176
1177	# Delete nexthop in a group and group is updated
1178	run_cmd "$IP nexthop del id 13"
1179	check_nexthop "id 102" "id 102 group 12/14/15"
1180	log_test $? 0 "Nexthop group updated when entry is deleted"
1181
1182	# create group with multiple weighted nexthops
1183	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1184	run_cmd "$IP nexthop add id 103 group 12/13,2/14,3/15,4"
1185	log_test $? 0 "Nexthop group with weighted nexthops"
1186	check_nexthop "id 103" "id 103 group 12/13,2/14,3/15,4"
1187
1188	# Delete nexthop in a weighted group and group is updated
1189	run_cmd "$IP nexthop del id 13"
1190	check_nexthop "id 103" "id 103 group 12/14,3/15,4"
1191	log_test $? 0 "Weighted nexthop group updated when entry is deleted"
1192
1193	# admin down - nexthop is removed from group
1194	run_cmd "$IP li set dev veth1 down"
1195	check_nexthop "dev veth1" ""
1196	log_test $? 0 "Nexthops in groups removed on admin down"
1197
1198	# expect groups to have been deleted as well
1199	check_nexthop "" ""
1200
1201	run_cmd "$IP li set dev veth1 up"
1202
1203	$IP nexthop flush >/dev/null 2>&1
1204
1205	# group with nexthops using different devices
1206	set -e
1207	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1208	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1209	run_cmd "$IP nexthop add id 14 via 172.16.1.4 dev veth1"
1210	run_cmd "$IP nexthop add id 15 via 172.16.1.5 dev veth1"
1211
1212	run_cmd "$IP nexthop add id 22 via 172.16.2.2 dev veth3"
1213	run_cmd "$IP nexthop add id 23 via 172.16.2.3 dev veth3"
1214	run_cmd "$IP nexthop add id 24 via 172.16.2.4 dev veth3"
1215	run_cmd "$IP nexthop add id 25 via 172.16.2.5 dev veth3"
1216	set +e
1217
1218	# multiple groups with same nexthop
1219	run_cmd "$IP nexthop add id 104 group 12"
1220	run_cmd "$IP nexthop add id 105 group 12"
1221	check_nexthop "group" "id 104 group 12 id 105 group 12"
1222	log_test $? 0 "Multiple groups with same nexthop"
1223
1224	run_cmd "$IP nexthop flush groups"
1225	[ $? -ne 0 ] && return 1
1226
1227	# on admin down of veth1, it should be removed from the group
1228	run_cmd "$IP nexthop add id 105 group 12/13/22/23/14"
1229	run_cmd "$IP li set veth1 down"
1230	check_nexthop "id 105" "id 105 group 22/23"
1231	log_test $? 0 "Nexthops in group removed on admin down - mixed group"
1232
1233	run_cmd "$IP nexthop add id 106 group 105/24"
1234	log_test $? 2 "Nexthop group can not have a group as an entry"
1235
1236	# a group can have a blackhole entry only if it is the only
1237	# nexthop in the group. Needed for atomic replace with an
1238	# actual nexthop group
1239	run_cmd "$IP nexthop add id 31 blackhole"
1240	run_cmd "$IP nexthop add id 107 group 31"
1241	log_test $? 0 "Nexthop group with a blackhole entry"
1242
1243	run_cmd "$IP nexthop add id 108 group 31/24"
1244	log_test $? 2 "Nexthop group can not have a blackhole and another nexthop"
1245}
1246
1247ipv4_res_grp_fcnal()
1248{
1249	local rc
1250
1251	echo
1252	echo "IPv4 resilient groups functional"
1253	echo "--------------------------------"
1254
1255	check_nexthop_res_support
1256	if [ $? -eq $ksft_skip ]; then
1257		return $ksft_skip
1258	fi
1259
1260	#
1261	# migration of nexthop buckets - equal weights
1262	#
1263	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1264	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1265	run_cmd "$IP nexthop add id 102 group 12/13 type resilient buckets 2 idle_timer 0"
1266
1267	run_cmd "$IP nexthop del id 13"
1268	check_nexthop "id 102" \
1269		"id 102 group 12 type resilient buckets 2 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1270	log_test $? 0 "Nexthop group updated when entry is deleted"
1271	check_nexthop_bucket "list id 102" \
1272		"id 102 index 0 nhid 12 id 102 index 1 nhid 12"
1273	log_test $? 0 "Nexthop buckets updated when entry is deleted"
1274
1275	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1276	run_cmd "$IP nexthop replace id 102 group 12/13 type resilient buckets 2 idle_timer 0"
1277	check_nexthop "id 102" \
1278		"id 102 group 12/13 type resilient buckets 2 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1279	log_test $? 0 "Nexthop group updated after replace"
1280	check_nexthop_bucket "list id 102" \
1281		"id 102 index 0 nhid 13 id 102 index 1 nhid 12"
1282	log_test $? 0 "Nexthop buckets updated after replace"
1283
1284	$IP nexthop flush >/dev/null 2>&1
1285
1286	#
1287	# migration of nexthop buckets - unequal weights
1288	#
1289	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1290	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1291	run_cmd "$IP nexthop add id 102 group 12,3/13,1 type resilient buckets 4 idle_timer 0"
1292
1293	run_cmd "$IP nexthop del id 13"
1294	check_nexthop "id 102" \
1295		"id 102 group 12,3 type resilient buckets 4 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1296	log_test $? 0 "Nexthop group updated when entry is deleted - nECMP"
1297	check_nexthop_bucket "list id 102" \
1298		"id 102 index 0 nhid 12 id 102 index 1 nhid 12 id 102 index 2 nhid 12 id 102 index 3 nhid 12"
1299	log_test $? 0 "Nexthop buckets updated when entry is deleted - nECMP"
1300
1301	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
1302	run_cmd "$IP nexthop replace id 102 group 12,3/13,1 type resilient buckets 4 idle_timer 0"
1303	check_nexthop "id 102" \
1304		"id 102 group 12,3/13 type resilient buckets 4 idle_timer 0 unbalanced_timer 0 unbalanced_time 0"
1305	log_test $? 0 "Nexthop group updated after replace - nECMP"
1306	check_nexthop_bucket "list id 102" \
1307		"id 102 index 0 nhid 13 id 102 index 1 nhid 12 id 102 index 2 nhid 12 id 102 index 3 nhid 12"
1308	log_test $? 0 "Nexthop buckets updated after replace - nECMP"
1309}
1310
1311ipv4_withv6_fcnal()
1312{
1313	local lladdr
1314
1315	set -e
1316	lladdr=$(get_linklocal veth2 peer)
1317	run_cmd "$IP nexthop add id 11 via ${lladdr} dev veth1"
1318	set +e
1319	run_cmd "$IP ro add 172.16.101.1/32 nhid 11"
1320	log_test $? 0 "IPv6 nexthop with IPv4 route"
1321	check_route "172.16.101.1" "172.16.101.1 nhid 11 via inet6 ${lladdr} dev veth1"
1322
1323	set -e
1324	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
1325	run_cmd "$IP nexthop add id 101 group 11/12"
1326	set +e
1327	run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
1328	log_test $? 0 "IPv6 nexthop with IPv4 route"
1329
1330	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"
1331
1332	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
1333	log_test $? 0 "IPv4 route with IPv6 gateway"
1334	check_route "172.16.101.1" "172.16.101.1 via inet6 ${lladdr} dev veth1"
1335
1336	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 2001:db8:50::1 dev veth1"
1337	log_test $? 2 "IPv4 route with invalid IPv6 gateway"
1338}
1339
1340ipv4_fcnal_runtime()
1341{
1342	local lladdr
1343	local rc
1344
1345	echo
1346	echo "IPv4 functional runtime"
1347	echo "-----------------------"
1348
1349	run_cmd "$IP nexthop add id 21 via 172.16.1.2 dev veth1"
1350	run_cmd "$IP ro add 172.16.101.1/32 nhid 21"
1351	log_test $? 0 "Route add"
1352	check_route "172.16.101.1" "172.16.101.1 nhid 21 via 172.16.1.2 dev veth1"
1353
1354	run_cmd "$IP ro delete 172.16.101.1/32 nhid 21"
1355	log_test $? 0 "Route delete"
1356
1357	#
1358	# scope mismatch
1359	#
1360	run_cmd "$IP nexthop add id 22 via 172.16.1.2 dev veth1"
1361	run_cmd "$IP ro add 172.16.101.1/32 nhid 22 scope host"
1362	log_test $? 2 "Route add - scope conflict with nexthop"
1363
1364	run_cmd "$IP nexthop replace id 22 dev veth3"
1365	run_cmd "$IP ro add 172.16.101.1/32 nhid 22 scope host"
1366	run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
1367	log_test $? 2 "Nexthop replace with invalid scope for existing route"
1368
1369	#
1370	# add route with nexthop and check traffic
1371	#
1372	run_cmd "$IP nexthop replace id 21 via 172.16.1.2 dev veth1"
1373	run_cmd "$IP ro replace 172.16.101.1/32 nhid 21"
1374	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1375	log_test $? 0 "Basic ping"
1376
1377	run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
1378	run_cmd "$IP nexthop add id 122 group 21/22"
1379	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
1380	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1381	log_test $? 0 "Ping - multipath"
1382
1383	run_cmd "$IP ro delete 172.16.101.1/32 nhid 122"
1384
1385	#
1386	# multiple default routes
1387	# - tests fib_select_default
1388	run_cmd "$IP nexthop add id 501 via 172.16.1.2 dev veth1"
1389	run_cmd "$IP ro add default nhid 501"
1390	run_cmd "$IP ro add default via 172.16.1.3 dev veth1 metric 20"
1391	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1392	log_test $? 0 "Ping - multiple default routes, nh first"
1393
1394	# flip the order
1395	run_cmd "$IP ro del default nhid 501"
1396	run_cmd "$IP ro del default via 172.16.1.3 dev veth1 metric 20"
1397	run_cmd "$IP ro add default via 172.16.1.2 dev veth1 metric 20"
1398	run_cmd "$IP nexthop replace id 501 via 172.16.1.3 dev veth1"
1399	run_cmd "$IP ro add default nhid 501 metric 20"
1400	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1401	log_test $? 0 "Ping - multiple default routes, nh second"
1402
1403	run_cmd "$IP nexthop delete nhid 501"
1404	run_cmd "$IP ro del default"
1405
1406	#
1407	# IPv4 with blackhole nexthops
1408	#
1409	run_cmd "$IP nexthop add id 23 blackhole"
1410	run_cmd "$IP ro replace 172.16.101.1/32 nhid 23"
1411	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1412	log_test $? 2 "Ping - blackhole"
1413
1414	run_cmd "$IP nexthop replace id 23 via 172.16.1.2 dev veth1"
1415	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1416	log_test $? 0 "Ping - blackhole replaced with gateway"
1417
1418	run_cmd "$IP nexthop replace id 23 blackhole"
1419	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1420	log_test $? 2 "Ping - gateway replaced by blackhole"
1421
1422	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
1423	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1424	if [ $? -eq 0 ]; then
1425		run_cmd "$IP nexthop replace id 122 group 23"
1426		run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1427		log_test $? 2 "Ping - group with blackhole"
1428
1429		run_cmd "$IP nexthop replace id 122 group 21/22"
1430		run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1431		log_test $? 0 "Ping - group blackhole replaced with gateways"
1432	else
1433		log_test 2 0 "Ping - multipath failed"
1434	fi
1435
1436	#
1437	# device only and gw + dev only mix
1438	#
1439	run_cmd "$IP nexthop add id 85 dev veth1"
1440	run_cmd "$IP ro replace 172.16.101.1/32 nhid 85"
1441	log_test $? 0 "IPv4 route with device only nexthop"
1442	check_route "172.16.101.1" "172.16.101.1 nhid 85 dev veth1"
1443
1444	run_cmd "$IP nexthop add id 123 group 21/85"
1445	run_cmd "$IP ro replace 172.16.101.1/32 nhid 123"
1446	log_test $? 0 "IPv4 multipath route with nexthop mix - dev only + gw"
1447	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"
1448
1449	#
1450	# IPv4 with IPv6
1451	#
1452	set -e
1453	lladdr=$(get_linklocal veth2 peer)
1454	run_cmd "$IP nexthop add id 24 via ${lladdr} dev veth1"
1455	set +e
1456	run_cmd "$IP ro replace 172.16.101.1/32 nhid 24"
1457	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1458	log_test $? 0 "IPv6 nexthop with IPv4 route"
1459
1460	$IP neigh sh | grep -q "${lladdr} dev veth1"
1461	if [ $? -eq 1 ]; then
1462		echo "    WARNING: Neigh entry missing for ${lladdr}"
1463		$IP neigh sh | grep 'dev veth1'
1464	fi
1465
1466	$IP neigh sh | grep -q "172.16.101.1 dev eth1"
1467	if [ $? -eq 0 ]; then
1468		echo "    WARNING: Neigh entry exists for 172.16.101.1"
1469		$IP neigh sh | grep 'dev veth1'
1470	fi
1471
1472	set -e
1473	run_cmd "$IP nexthop add id 25 via 172.16.1.2 dev veth1"
1474	run_cmd "$IP nexthop add id 101 group 24/25"
1475	set +e
1476	run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
1477	log_test $? 0 "IPv4 route with mixed v4-v6 multipath route"
1478
1479	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"
1480
1481	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1482	log_test $? 0 "IPv6 nexthop with IPv4 route"
1483
1484	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
1485	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1486	log_test $? 0 "IPv4 route with IPv6 gateway"
1487
1488	$IP neigh sh | grep -q "${lladdr} dev veth1"
1489	if [ $? -eq 1 ]; then
1490		echo "    WARNING: Neigh entry missing for ${lladdr}"
1491		$IP neigh sh | grep 'dev veth1'
1492	fi
1493
1494	$IP neigh sh | grep -q "172.16.101.1 dev eth1"
1495	if [ $? -eq 0 ]; then
1496		echo "    WARNING: Neigh entry exists for 172.16.101.1"
1497		$IP neigh sh | grep 'dev veth1'
1498	fi
1499
1500	run_cmd "$IP ro del 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
1501	run_cmd "$IP -4 ro add default via inet6 ${lladdr} dev veth1"
1502	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
1503	log_test $? 0 "IPv4 default route with IPv6 gateway"
1504
1505	#
1506	# MPLS as an example of LWT encap
1507	#
1508	run_cmd "$IP nexthop add id 51 encap mpls 101 via 172.16.1.2 dev veth1"
1509	log_test $? 0 "IPv4 route with MPLS encap"
1510	check_nexthop "id 51" "id 51 encap mpls 101 via 172.16.1.2 dev veth1 scope link"
1511	log_test $? 0 "IPv4 route with MPLS encap - check"
1512
1513	run_cmd "$IP nexthop add id 52 encap mpls 102 via inet6 2001:db8:91::2 dev veth1"
1514	log_test $? 0 "IPv4 route with MPLS encap and v6 gateway"
1515	check_nexthop "id 52" "id 52 encap mpls 102 via 2001:db8:91::2 dev veth1 scope link"
1516	log_test $? 0 "IPv4 route with MPLS encap, v6 gw - check"
1517}
1518
1519ipv4_large_grp()
1520{
1521	local ecmp=32
1522
1523	echo
1524	echo "IPv4 large groups (x$ecmp)"
1525	echo "---------------------"
1526
1527	check_large_grp 4 $ecmp
1528
1529	$IP nexthop flush >/dev/null 2>&1
1530}
1531
1532ipv4_large_res_grp()
1533{
1534	echo
1535	echo "IPv4 large resilient group (128k buckets)"
1536	echo "-----------------------------------------"
1537
1538	check_nexthop_res_support
1539	if [ $? -eq $ksft_skip ]; then
1540		return $ksft_skip
1541	fi
1542
1543	check_large_res_grp 4 $((128 * 1024))
1544
1545	$IP nexthop flush >/dev/null 2>&1
1546}
1547
1548sysctl_nexthop_compat_mode_check()
1549{
1550	local sysctlname="net.ipv4.nexthop_compat_mode"
1551	local lprefix=$1
1552
1553	IPE="ip netns exec me"
1554
1555	$IPE sysctl -q $sysctlname 2>&1 >/dev/null
1556	if [ $? -ne 0 ]; then
1557		echo "SKIP: kernel lacks nexthop compat mode sysctl control"
1558		return $ksft_skip
1559	fi
1560
1561	out=$($IPE sysctl $sysctlname 2>/dev/null)
1562	log_test $? 0 "$lprefix default nexthop compat mode check"
1563	check_output "${out}" "$sysctlname = 1"
1564}
1565
1566sysctl_nexthop_compat_mode_set()
1567{
1568	local sysctlname="net.ipv4.nexthop_compat_mode"
1569	local mode=$1
1570	local lprefix=$2
1571
1572	IPE="ip netns exec me"
1573
1574	out=$($IPE sysctl -w $sysctlname=$mode)
1575	log_test $? 0 "$lprefix set compat mode - $mode"
1576	check_output "${out}" "net.ipv4.nexthop_compat_mode = $mode"
1577}
1578
1579ipv6_compat_mode()
1580{
1581	local rc
1582
1583	echo
1584	echo "IPv6 nexthop api compat mode test"
1585	echo "--------------------------------"
1586
1587	sysctl_nexthop_compat_mode_check "IPv6"
1588	if [ $? -eq $ksft_skip ]; then
1589		return $ksft_skip
1590	fi
1591
1592	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1593	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1594	run_cmd "$IP nexthop add id 122 group 62/63"
1595	ipmout=$(start_ip_monitor route)
1596
1597	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 122"
1598	# route add notification should contain expanded nexthops
1599	stop_ip_monitor $ipmout 3
1600	log_test $? 0 "IPv6 compat mode on - route add notification"
1601
1602	# route dump should contain expanded nexthops
1603	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"
1604	log_test $? 0 "IPv6 compat mode on - route dump"
1605
1606	# change in nexthop group should generate route notification
1607	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
1608	ipmout=$(start_ip_monitor route)
1609	run_cmd "$IP nexthop replace id 122 group 62/64"
1610	stop_ip_monitor $ipmout 3
1611
1612	log_test $? 0 "IPv6 compat mode on - nexthop change"
1613
1614	# set compat mode off
1615	sysctl_nexthop_compat_mode_set 0 "IPv6"
1616
1617	run_cmd "$IP -6 ro del 2001:db8:101::1/128 nhid 122"
1618
1619	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
1620	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
1621	run_cmd "$IP nexthop add id 122 group 62/63"
1622	ipmout=$(start_ip_monitor route)
1623
1624	run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 122"
1625	# route add notification should not contain expanded nexthops
1626	stop_ip_monitor $ipmout 1
1627	log_test $? 0 "IPv6 compat mode off - route add notification"
1628
1629	# route dump should not contain expanded nexthops
1630	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 122 metric 1024"
1631	log_test $? 0 "IPv6 compat mode off - route dump"
1632
1633	# change in nexthop group should not generate route notification
1634	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
1635	ipmout=$(start_ip_monitor route)
1636	run_cmd "$IP nexthop replace id 122 group 62/64"
1637	stop_ip_monitor $ipmout 0
1638	log_test $? 0 "IPv6 compat mode off - nexthop change"
1639
1640	# nexthop delete should not generate route notification
1641	ipmout=$(start_ip_monitor route)
1642	run_cmd "$IP nexthop del id 122"
1643	stop_ip_monitor $ipmout 0
1644	log_test $? 0 "IPv6 compat mode off - nexthop delete"
1645
1646	# set compat mode back on
1647	sysctl_nexthop_compat_mode_set 1 "IPv6"
1648}
1649
1650ipv4_compat_mode()
1651{
1652	local rc
1653
1654	echo
1655	echo "IPv4 nexthop api compat mode"
1656	echo "----------------------------"
1657
1658	sysctl_nexthop_compat_mode_check "IPv4"
1659	if [ $? -eq $ksft_skip ]; then
1660		return $ksft_skip
1661	fi
1662
1663	run_cmd "$IP nexthop add id 21 via 172.16.1.2 dev veth1"
1664	run_cmd "$IP nexthop add id 22 via 172.16.1.2 dev veth1"
1665	run_cmd "$IP nexthop add id 122 group 21/22"
1666	ipmout=$(start_ip_monitor route)
1667
1668	run_cmd "$IP ro add 172.16.101.1/32 nhid 122"
1669	stop_ip_monitor $ipmout 3
1670
1671	# route add notification should contain expanded nexthops
1672	log_test $? 0 "IPv4 compat mode on - route add notification"
1673
1674	# route dump should contain expanded nexthops
1675	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"
1676	log_test $? 0 "IPv4 compat mode on - route dump"
1677
1678	# change in nexthop group should generate route notification
1679	run_cmd "$IP nexthop add id 23 via 172.16.1.3 dev veth1"
1680	ipmout=$(start_ip_monitor route)
1681	run_cmd "$IP nexthop replace id 122 group 21/23"
1682	stop_ip_monitor $ipmout 3
1683	log_test $? 0 "IPv4 compat mode on - nexthop change"
1684
1685	sysctl_nexthop_compat_mode_set 0 "IPv4"
1686
1687	# cleanup
1688	run_cmd "$IP ro del 172.16.101.1/32 nhid 122"
1689
1690	ipmout=$(start_ip_monitor route)
1691	run_cmd "$IP ro add 172.16.101.1/32 nhid 122"
1692	stop_ip_monitor $ipmout 1
1693	# route add notification should not contain expanded nexthops
1694	log_test $? 0 "IPv4 compat mode off - route add notification"
1695
1696	# route dump should not contain expanded nexthops
1697	check_route "172.16.101.1" "172.16.101.1 nhid 122"
1698	log_test $? 0 "IPv4 compat mode off - route dump"
1699
1700	# change in nexthop group should not generate route notification
1701	ipmout=$(start_ip_monitor route)
1702	run_cmd "$IP nexthop replace id 122 group 21/22"
1703	stop_ip_monitor $ipmout 0
1704	log_test $? 0 "IPv4 compat mode off - nexthop change"
1705
1706	# nexthop delete should not generate route notification
1707	ipmout=$(start_ip_monitor route)
1708	run_cmd "$IP nexthop del id 122"
1709	stop_ip_monitor $ipmout 0
1710	log_test $? 0 "IPv4 compat mode off - nexthop delete"
1711
1712	sysctl_nexthop_compat_mode_set 1 "IPv4"
1713}
1714
1715ipv4_del_add_loop1()
1716{
1717	while :; do
1718		$IP nexthop del id 100
1719		$IP nexthop add id 100 via 172.16.1.2 dev veth1
1720	done >/dev/null 2>&1
1721}
1722
1723ipv4_grp_replace_loop()
1724{
1725	while :; do
1726		$IP nexthop replace id 102 group 100/101
1727	done >/dev/null 2>&1
1728}
1729
1730ipv4_torture()
1731{
1732	local pid1
1733	local pid2
1734	local pid3
1735	local pid4
1736	local pid5
1737
1738	echo
1739	echo "IPv4 runtime torture"
1740	echo "--------------------"
1741	if [ ! -x "$(command -v mausezahn)" ]; then
1742		echo "SKIP: Could not run test; need mausezahn tool"
1743		return
1744	fi
1745
1746	run_cmd "$IP nexthop add id 100 via 172.16.1.2 dev veth1"
1747	run_cmd "$IP nexthop add id 101 via 172.16.2.2 dev veth3"
1748	run_cmd "$IP nexthop add id 102 group 100/101"
1749	run_cmd "$IP route add 172.16.101.1 nhid 102"
1750	run_cmd "$IP route add 172.16.101.2 nhid 102"
1751
1752	ipv4_del_add_loop1 &
1753	pid1=$!
1754	ipv4_grp_replace_loop &
1755	pid2=$!
1756	ip netns exec me ping -f 172.16.101.1 >/dev/null 2>&1 &
1757	pid3=$!
1758	ip netns exec me ping -f 172.16.101.2 >/dev/null 2>&1 &
1759	pid4=$!
1760	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 &
1761	pid5=$!
1762
1763	sleep 300
1764	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
1765	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
1766
1767	# if we did not crash, success
1768	log_test 0 0 "IPv4 torture test"
1769}
1770
1771ipv4_res_grp_replace_loop()
1772{
1773	while :; do
1774		$IP nexthop replace id 102 group 100/101 type resilient
1775	done >/dev/null 2>&1
1776}
1777
1778ipv4_res_torture()
1779{
1780	local pid1
1781	local pid2
1782	local pid3
1783	local pid4
1784	local pid5
1785
1786	echo
1787	echo "IPv4 runtime resilient nexthop group torture"
1788	echo "--------------------------------------------"
1789
1790	check_nexthop_res_support
1791	if [ $? -eq $ksft_skip ]; then
1792		return $ksft_skip
1793	fi
1794
1795	if [ ! -x "$(command -v mausezahn)" ]; then
1796		echo "SKIP: Could not run test; need mausezahn tool"
1797		return
1798	fi
1799
1800	run_cmd "$IP nexthop add id 100 via 172.16.1.2 dev veth1"
1801	run_cmd "$IP nexthop add id 101 via 172.16.2.2 dev veth3"
1802	run_cmd "$IP nexthop add id 102 group 100/101 type resilient buckets 512 idle_timer 0"
1803	run_cmd "$IP route add 172.16.101.1 nhid 102"
1804	run_cmd "$IP route add 172.16.101.2 nhid 102"
1805
1806	ipv4_del_add_loop1 &
1807	pid1=$!
1808	ipv4_res_grp_replace_loop &
1809	pid2=$!
1810	ip netns exec me ping -f 172.16.101.1 >/dev/null 2>&1 &
1811	pid3=$!
1812	ip netns exec me ping -f 172.16.101.2 >/dev/null 2>&1 &
1813	pid4=$!
1814	ip netns exec me mausezahn veth1 \
1815				-B 172.16.101.2 -A 172.16.1.1 -c 0 \
1816				-t tcp "dp=1-1023, flags=syn" >/dev/null 2>&1 &
1817	pid5=$!
1818
1819	sleep 300
1820	kill -9 $pid1 $pid2 $pid3 $pid4 $pid5
1821	wait $pid1 $pid2 $pid3 $pid4 $pid5 2>/dev/null
1822
1823	# if we did not crash, success
1824	log_test 0 0 "IPv4 resilient nexthop group torture test"
1825}
1826
1827basic()
1828{
1829	echo
1830	echo "Basic functional tests"
1831	echo "----------------------"
1832	run_cmd "$IP nexthop ls"
1833	log_test $? 0 "List with nothing defined"
1834
1835	run_cmd "$IP nexthop get id 1"
1836	log_test $? 2 "Nexthop get on non-existent id"
1837
1838	# attempt to create nh without a device or gw - fails
1839	run_cmd "$IP nexthop add id 1"
1840	log_test $? 2 "Nexthop with no device or gateway"
1841
1842	# attempt to create nh with down device - fails
1843	$IP li set veth1 down
1844	run_cmd "$IP nexthop add id 1 dev veth1"
1845	log_test $? 2 "Nexthop with down device"
1846
1847	# create nh with linkdown device - fails
1848	$IP li set veth1 up
1849	ip -netns peer li set veth2 down
1850	run_cmd "$IP nexthop add id 1 dev veth1"
1851	log_test $? 2 "Nexthop with device that is linkdown"
1852	ip -netns peer li set veth2 up
1853
1854	# device only
1855	run_cmd "$IP nexthop add id 1 dev veth1"
1856	log_test $? 0 "Nexthop with device only"
1857
1858	# create nh with duplicate id
1859	run_cmd "$IP nexthop add id 1 dev veth3"
1860	log_test $? 2 "Nexthop with duplicate id"
1861
1862	# blackhole nexthop
1863	run_cmd "$IP nexthop add id 2 blackhole"
1864	log_test $? 0 "Blackhole nexthop"
1865
1866	# blackhole nexthop can not have other specs
1867	run_cmd "$IP nexthop replace id 2 blackhole dev veth1"
1868	log_test $? 2 "Blackhole nexthop with other attributes"
1869
1870	# blackhole nexthop should not be affected by the state of the loopback
1871	# device
1872	run_cmd "$IP link set dev lo down"
1873	check_nexthop "id 2" "id 2 blackhole"
1874	log_test $? 0 "Blackhole nexthop with loopback device down"
1875
1876	run_cmd "$IP link set dev lo up"
1877
1878	#
1879	# groups
1880	#
1881
1882	run_cmd "$IP nexthop add id 101 group 1"
1883	log_test $? 0 "Create group"
1884
1885	run_cmd "$IP nexthop add id 102 group 2"
1886	log_test $? 0 "Create group with blackhole nexthop"
1887
1888	# multipath group can not have a blackhole as 1 path
1889	run_cmd "$IP nexthop add id 103 group 1/2"
1890	log_test $? 2 "Create multipath group where 1 path is a blackhole"
1891
1892	# multipath group can not have a member replaced by a blackhole
1893	run_cmd "$IP nexthop replace id 2 dev veth3"
1894	run_cmd "$IP nexthop replace id 102 group 1/2"
1895	run_cmd "$IP nexthop replace id 2 blackhole"
1896	log_test $? 2 "Multipath group can not have a member replaced by blackhole"
1897
1898	# attempt to create group with non-existent nexthop
1899	run_cmd "$IP nexthop add id 103 group 12"
1900	log_test $? 2 "Create group with non-existent nexthop"
1901
1902	# attempt to create group with same nexthop
1903	run_cmd "$IP nexthop add id 103 group 1/1"
1904	log_test $? 2 "Create group with same nexthop multiple times"
1905
1906	# replace nexthop with a group - fails
1907	run_cmd "$IP nexthop replace id 2 group 1"
1908	log_test $? 2 "Replace nexthop with nexthop group"
1909
1910	# replace nexthop group with a nexthop - fails
1911	run_cmd "$IP nexthop replace id 101 dev veth1"
1912	log_test $? 2 "Replace nexthop group with nexthop"
1913
1914	# nexthop group with other attributes fail
1915	run_cmd "$IP nexthop add id 104 group 1 dev veth1"
1916	log_test $? 2 "Nexthop group and device"
1917
1918	# Tests to ensure that flushing works as expected.
1919	run_cmd "$IP nexthop add id 105 blackhole proto 99"
1920	run_cmd "$IP nexthop add id 106 blackhole proto 100"
1921	run_cmd "$IP nexthop add id 107 blackhole proto 99"
1922	run_cmd "$IP nexthop flush proto 99"
1923	check_nexthop "id 105" ""
1924	check_nexthop "id 106" "id 106 blackhole proto 100"
1925	check_nexthop "id 107" ""
1926	run_cmd "$IP nexthop flush proto 100"
1927	check_nexthop "id 106" ""
1928
1929	run_cmd "$IP nexthop flush proto 100"
1930	log_test $? 0 "Test proto flush"
1931
1932	run_cmd "$IP nexthop add id 104 group 1 blackhole"
1933	log_test $? 2 "Nexthop group and blackhole"
1934
1935	$IP nexthop flush >/dev/null 2>&1
1936
1937	# Test to ensure that flushing with a multi-part nexthop dump works as
1938	# expected.
1939	local batch_file=$(mktemp)
1940
1941	for i in $(seq 1 $((64 * 1024))); do
1942		echo "nexthop add id $i blackhole" >> $batch_file
1943	done
1944
1945	$IP -b $batch_file
1946	$IP nexthop flush >/dev/null 2>&1
1947	[[ $($IP nexthop | wc -l) -eq 0 ]]
1948	log_test $? 0 "Large scale nexthop flushing"
1949
1950	rm $batch_file
1951}
1952
1953check_nexthop_buckets_balance()
1954{
1955	local nharg=$1; shift
1956	local ret
1957
1958	while (($# > 0)); do
1959		local selector=$1; shift
1960		local condition=$1; shift
1961		local count
1962
1963		count=$($IP -j nexthop bucket ${nharg} ${selector} | jq length)
1964		(( $count $condition ))
1965		ret=$?
1966		if ((ret != 0)); then
1967			return $ret
1968		fi
1969	done
1970
1971	return 0
1972}
1973
1974basic_res()
1975{
1976	echo
1977	echo "Basic resilient nexthop group functional tests"
1978	echo "----------------------------------------------"
1979
1980	check_nexthop_res_support
1981	if [ $? -eq $ksft_skip ]; then
1982		return $ksft_skip
1983	fi
1984
1985	run_cmd "$IP nexthop add id 1 dev veth1"
1986
1987	#
1988	# resilient nexthop group addition
1989	#
1990
1991	run_cmd "$IP nexthop add id 101 group 1 type resilient buckets 8"
1992	log_test $? 0 "Add a nexthop group with default parameters"
1993
1994	run_cmd "$IP nexthop get id 101"
1995	check_nexthop "id 101" \
1996		"id 101 group 1 type resilient buckets 8 idle_timer 120 unbalanced_timer 0 unbalanced_time 0"
1997	log_test $? 0 "Get a nexthop group with default parameters"
1998
1999	run_cmd "$IP nexthop add id 102 group 1 type resilient
2000			buckets 4 idle_timer 100 unbalanced_timer 5"
2001	run_cmd "$IP nexthop get id 102"
2002	check_nexthop "id 102" \
2003		"id 102 group 1 type resilient buckets 4 idle_timer 100 unbalanced_timer 5 unbalanced_time 0"
2004	log_test $? 0 "Get a nexthop group with non-default parameters"
2005
2006	run_cmd "$IP nexthop add id 103 group 1 type resilient buckets 0"
2007	log_test $? 2 "Add a nexthop group with 0 buckets"
2008
2009	#
2010	# resilient nexthop group replacement
2011	#
2012
2013	run_cmd "$IP nexthop replace id 101 group 1 type resilient
2014			buckets 8 idle_timer 240 unbalanced_timer 80"
2015	log_test $? 0 "Replace nexthop group parameters"
2016	check_nexthop "id 101" \
2017		"id 101 group 1 type resilient buckets 8 idle_timer 240 unbalanced_timer 80 unbalanced_time 0"
2018	log_test $? 0 "Get a nexthop group after replacing parameters"
2019
2020	run_cmd "$IP nexthop replace id 101 group 1 type resilient idle_timer 512"
2021	log_test $? 0 "Replace idle timer"
2022	check_nexthop "id 101" \
2023		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 80 unbalanced_time 0"
2024	log_test $? 0 "Get a nexthop group after replacing idle timer"
2025
2026	run_cmd "$IP nexthop replace id 101 group 1 type resilient unbalanced_timer 256"
2027	log_test $? 0 "Replace unbalanced timer"
2028	check_nexthop "id 101" \
2029		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2030	log_test $? 0 "Get a nexthop group after replacing unbalanced timer"
2031
2032	run_cmd "$IP nexthop replace id 101 group 1 type resilient"
2033	log_test $? 0 "Replace with no parameters"
2034	check_nexthop "id 101" \
2035		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2036	log_test $? 0 "Get a nexthop group after replacing no parameters"
2037
2038	run_cmd "$IP nexthop replace id 101 group 1"
2039	log_test $? 2 "Replace nexthop group type - implicit"
2040
2041	run_cmd "$IP nexthop replace id 101 group 1 type mpath"
2042	log_test $? 2 "Replace nexthop group type - explicit"
2043
2044	run_cmd "$IP nexthop replace id 101 group 1 type resilient buckets 1024"
2045	log_test $? 2 "Replace number of nexthop buckets"
2046
2047	check_nexthop "id 101" \
2048		"id 101 group 1 type resilient buckets 8 idle_timer 512 unbalanced_timer 256 unbalanced_time 0"
2049	log_test $? 0 "Get a nexthop group after replacing with invalid parameters"
2050
2051	#
2052	# resilient nexthop buckets dump
2053	#
2054
2055	$IP nexthop flush >/dev/null 2>&1
2056	run_cmd "$IP nexthop add id 1 dev veth1"
2057	run_cmd "$IP nexthop add id 2 dev veth3"
2058	run_cmd "$IP nexthop add id 101 group 1/2 type resilient buckets 4"
2059	run_cmd "$IP nexthop add id 201 group 1/2"
2060
2061	check_nexthop_bucket "" \
2062		"id 101 index 0 nhid 2 id 101 index 1 nhid 2 id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2063	log_test $? 0 "Dump all nexthop buckets"
2064
2065	check_nexthop_bucket "list id 101" \
2066		"id 101 index 0 nhid 2 id 101 index 1 nhid 2 id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2067	log_test $? 0 "Dump all nexthop buckets in a group"
2068
2069	(( $($IP -j nexthop bucket list id 101 |
2070	     jq '[.[] | select(.bucket.idle_time > 0 and
2071	                       .bucket.idle_time < 2)] | length') == 4 ))
2072	log_test $? 0 "All nexthop buckets report a positive near-zero idle time"
2073
2074	check_nexthop_bucket "list dev veth1" \
2075		"id 101 index 2 nhid 1 id 101 index 3 nhid 1"
2076	log_test $? 0 "Dump all nexthop buckets with a specific nexthop device"
2077
2078	check_nexthop_bucket "list nhid 2" \
2079		"id 101 index 0 nhid 2 id 101 index 1 nhid 2"
2080	log_test $? 0 "Dump all nexthop buckets with a specific nexthop identifier"
2081
2082	run_cmd "$IP nexthop bucket list id 111"
2083	log_test $? 2 "Dump all nexthop buckets in a non-existent group"
2084
2085	run_cmd "$IP nexthop bucket list id 201"
2086	log_test $? 2 "Dump all nexthop buckets in a non-resilient group"
2087
2088	run_cmd "$IP nexthop bucket list dev bla"
2089	log_test $? 255 "Dump all nexthop buckets using a non-existent device"
2090
2091	run_cmd "$IP nexthop bucket list groups"
2092	log_test $? 255 "Dump all nexthop buckets with invalid 'groups' keyword"
2093
2094	run_cmd "$IP nexthop bucket list fdb"
2095	log_test $? 255 "Dump all nexthop buckets with invalid 'fdb' keyword"
2096
2097	#
2098	# resilient nexthop buckets get requests
2099	#
2100
2101	check_nexthop_bucket "get id 101 index 0" "id 101 index 0 nhid 2"
2102	log_test $? 0 "Get a valid nexthop bucket"
2103
2104	run_cmd "$IP nexthop bucket get id 101 index 999"
2105	log_test $? 2 "Get a nexthop bucket with valid group, but invalid index"
2106
2107	run_cmd "$IP nexthop bucket get id 201 index 0"
2108	log_test $? 2 "Get a nexthop bucket from a non-resilient group"
2109
2110	run_cmd "$IP nexthop bucket get id 999 index 0"
2111	log_test $? 2 "Get a nexthop bucket from a non-existent group"
2112
2113	#
2114	# tests for bucket migration
2115	#
2116
2117	$IP nexthop flush >/dev/null 2>&1
2118
2119	run_cmd "$IP nexthop add id 1 dev veth1"
2120	run_cmd "$IP nexthop add id 2 dev veth3"
2121	run_cmd "$IP nexthop add id 101
2122			group 1/2 type resilient buckets 10
2123			idle_timer 1 unbalanced_timer 20"
2124
2125	check_nexthop_buckets_balance "list id 101" \
2126				      "nhid 1" "== 5" \
2127				      "nhid 2" "== 5"
2128	log_test $? 0 "Initial bucket allocation"
2129
2130	run_cmd "$IP nexthop replace id 101
2131			group 1,2/2,3 type resilient"
2132	check_nexthop_buckets_balance "list id 101" \
2133				      "nhid 1" "== 4" \
2134				      "nhid 2" "== 6"
2135	log_test $? 0 "Bucket allocation after replace"
2136
2137	# Check that increase in idle timer does not make buckets appear busy.
2138	run_cmd "$IP nexthop replace id 101
2139			group 1,2/2,3 type resilient
2140			idle_timer 10"
2141	run_cmd "$IP nexthop replace id 101
2142			group 1/2 type resilient"
2143	check_nexthop_buckets_balance "list id 101" \
2144				      "nhid 1" "== 5" \
2145				      "nhid 2" "== 5"
2146	log_test $? 0 "Buckets migrated after idle timer change"
2147
2148	$IP nexthop flush >/dev/null 2>&1
2149}
2150
2151################################################################################
2152# usage
2153
2154usage()
2155{
2156	cat <<EOF
2157usage: ${0##*/} OPTS
2158
2159        -t <test>   Test(s) to run (default: all)
2160                    (options: $ALL_TESTS)
2161        -4          IPv4 tests only
2162        -6          IPv6 tests only
2163        -p          Pause on fail
2164        -P          Pause after each test before cleanup
2165        -v          verbose mode (show commands and output)
2166
2167    Runtime test
2168	-n num	    Number of nexthops to target
2169	-N    	    Use new style to install routes in DUT
2170
2171done
2172EOF
2173}
2174
2175################################################################################
2176# main
2177
2178while getopts :t:pP46hv o
2179do
2180	case $o in
2181		t) TESTS=$OPTARG;;
2182		4) TESTS=${IPV4_TESTS};;
2183		6) TESTS=${IPV6_TESTS};;
2184		p) PAUSE_ON_FAIL=yes;;
2185		P) PAUSE=yes;;
2186		v) VERBOSE=$(($VERBOSE + 1));;
2187		h) usage; exit 0;;
2188		*) usage; exit 1;;
2189	esac
2190done
2191
2192# make sure we don't pause twice
2193[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
2194
2195if [ "$(id -u)" -ne 0 ];then
2196	echo "SKIP: Need root privileges"
2197	exit $ksft_skip;
2198fi
2199
2200if [ ! -x "$(command -v ip)" ]; then
2201	echo "SKIP: Could not run test without ip tool"
2202	exit $ksft_skip
2203fi
2204
2205ip help 2>&1 | grep -q nexthop
2206if [ $? -ne 0 ]; then
2207	echo "SKIP: iproute2 too old, missing nexthop command"
2208	exit $ksft_skip
2209fi
2210
2211out=$(ip nexthop ls 2>&1 | grep -q "Operation not supported")
2212if [ $? -eq 0 ]; then
2213	echo "SKIP: kernel lacks nexthop support"
2214	exit $ksft_skip
2215fi
2216
2217for t in $TESTS
2218do
2219	case $t in
2220	none) IP="ip -netns peer"; setup; exit 0;;
2221	*) setup; $t; cleanup;;
2222	esac
2223done
2224
2225if [ "$TESTS" != "none" ]; then
2226	printf "\nTests passed: %3d\n" ${nsuccess}
2227	printf "Tests failed: %3d\n"   ${nfail}
2228fi
2229
2230exit $ret
2231