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