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