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="ipv4_fcnal ipv4_grp_fcnal ipv4_withv6_fcnal ipv4_fcnal_runtime"
23IPV6_TESTS="ipv6_fcnal ipv6_grp_fcnal ipv6_fcnal_runtime"
24
25ALL_TESTS="basic ${IPV4_TESTS} ${IPV6_TESTS}"
26TESTS="${ALL_TESTS}"
27VERBOSE=0
28PAUSE_ON_FAIL=no
29PAUSE=no
30
31nsid=100
32
33################################################################################
34# utilities
35
36log_test()
37{
38	local rc=$1
39	local expected=$2
40	local msg="$3"
41
42	if [ ${rc} -eq ${expected} ]; then
43		printf "TEST: %-60s  [ OK ]\n" "${msg}"
44		nsuccess=$((nsuccess+1))
45	else
46		ret=1
47		nfail=$((nfail+1))
48		printf "TEST: %-60s  [FAIL]\n" "${msg}"
49		if [ "$VERBOSE" = "1" ]; then
50			echo "    rc=$rc, expected $expected"
51		fi
52
53		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
54		echo
55			echo "hit enter to continue, 'q' to quit"
56			read a
57			[ "$a" = "q" ] && exit 1
58		fi
59	fi
60
61	if [ "${PAUSE}" = "yes" ]; then
62		echo
63		echo "hit enter to continue, 'q' to quit"
64		read a
65		[ "$a" = "q" ] && exit 1
66	fi
67
68	[ "$VERBOSE" = "1" ] && echo
69}
70
71run_cmd()
72{
73	local cmd="$1"
74	local out
75	local stderr="2>/dev/null"
76
77	if [ "$VERBOSE" = "1" ]; then
78		printf "COMMAND: $cmd\n"
79		stderr=
80	fi
81
82	out=$(eval $cmd $stderr)
83	rc=$?
84	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
85		echo "    $out"
86	fi
87
88	return $rc
89}
90
91get_linklocal()
92{
93	local dev=$1
94	local ns
95	local addr
96
97	[ -n "$2" ] && ns="-netns $2"
98	addr=$(ip $ns -6 -br addr show dev ${dev} | \
99	awk '{
100		for (i = 3; i <= NF; ++i) {
101			if ($i ~ /^fe80/)
102				print $i
103		}
104	}'
105	)
106	addr=${addr/\/*}
107
108	[ -z "$addr" ] && return 1
109
110	echo $addr
111
112	return 0
113}
114
115create_ns()
116{
117	local n=${1}
118
119	ip netns del ${n} 2>/dev/null
120
121	set -e
122	ip netns add ${n}
123	ip netns set ${n} $((nsid++))
124	ip -netns ${n} addr add 127.0.0.1/8 dev lo
125	ip -netns ${n} link set lo up
126
127	ip netns exec ${n} sysctl -qw net.ipv4.ip_forward=1
128	ip netns exec ${n} sysctl -qw net.ipv4.fib_multipath_use_neigh=1
129	ip netns exec ${n} sysctl -qw net.ipv4.conf.default.ignore_routes_with_linkdown=1
130	ip netns exec ${n} sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
131	ip netns exec ${n} sysctl -qw net.ipv6.conf.all.forwarding=1
132	ip netns exec ${n} sysctl -qw net.ipv6.conf.default.forwarding=1
133	ip netns exec ${n} sysctl -qw net.ipv6.conf.default.ignore_routes_with_linkdown=1
134	ip netns exec ${n} sysctl -qw net.ipv6.conf.all.accept_dad=0
135	ip netns exec ${n} sysctl -qw net.ipv6.conf.default.accept_dad=0
136
137	set +e
138}
139
140setup()
141{
142	cleanup
143
144	create_ns me
145	create_ns peer
146	create_ns remote
147
148	IP="ip -netns me"
149	set -e
150	$IP li add veth1 type veth peer name veth2
151	$IP li set veth1 up
152	$IP addr add 172.16.1.1/24 dev veth1
153	$IP -6 addr add 2001:db8:91::1/64 dev veth1
154
155	$IP li add veth3 type veth peer name veth4
156	$IP li set veth3 up
157	$IP addr add 172.16.2.1/24 dev veth3
158	$IP -6 addr add 2001:db8:92::1/64 dev veth3
159
160	$IP li set veth2 netns peer up
161	ip -netns peer addr add 172.16.1.2/24 dev veth2
162	ip -netns peer -6 addr add 2001:db8:91::2/64 dev veth2
163
164	$IP li set veth4 netns peer up
165	ip -netns peer addr add 172.16.2.2/24 dev veth4
166	ip -netns peer -6 addr add 2001:db8:92::2/64 dev veth4
167
168	ip -netns remote li add veth5 type veth peer name veth6
169	ip -netns remote li set veth5 up
170	ip -netns remote addr add dev veth5 172.16.101.1/24
171	ip -netns remote addr add dev veth5 2001:db8:101::1/64
172	ip -netns remote ro add 172.16.0.0/22 via 172.16.101.2
173	ip -netns remote -6 ro add 2001:db8:90::/40 via 2001:db8:101::2
174
175	ip -netns remote li set veth6 netns peer up
176	ip -netns peer addr add dev veth6 172.16.101.2/24
177	ip -netns peer addr add dev veth6 2001:db8:101::2/64
178	set +e
179}
180
181cleanup()
182{
183	local ns
184
185	for ns in me peer remote; do
186		ip netns del ${ns} 2>/dev/null
187	done
188}
189
190check_output()
191{
192	local out="$1"
193	local expected="$2"
194	local rc=0
195
196	[ "${out}" = "${expected}" ] && return 0
197
198	if [ -z "${out}" ]; then
199		if [ "$VERBOSE" = "1" ]; then
200			printf "\nNo entry found\n"
201			printf "Expected:\n"
202			printf "    ${expected}\n"
203		fi
204		return 1
205	fi
206
207	out=$(echo ${out})
208	if [ "${out}" != "${expected}" ]; then
209		rc=1
210		if [ "${VERBOSE}" = "1" ]; then
211			printf "    Unexpected entry. Have:\n"
212			printf "        ${out}\n"
213			printf "    Expected:\n"
214			printf "        ${expected}\n\n"
215		fi
216	fi
217
218	return $rc
219}
220
221check_nexthop()
222{
223	local nharg="$1"
224	local expected="$2"
225	local out
226
227	out=$($IP nexthop ls ${nharg} 2>/dev/null)
228
229	check_output "${out}" "${expected}"
230}
231
232check_route()
233{
234	local pfx="$1"
235	local expected="$2"
236	local out
237
238	out=$($IP route ls match ${pfx} 2>/dev/null)
239
240	check_output "${out}" "${expected}"
241}
242
243check_route6()
244{
245	local pfx="$1"
246	local expected="$2"
247	local out
248
249	out=$($IP -6 route ls match ${pfx} 2>/dev/null)
250
251	check_output "${out}" "${expected}"
252}
253
254################################################################################
255# basic operations (add, delete, replace) on nexthops and nexthop groups
256#
257# IPv6
258
259ipv6_fcnal()
260{
261	local rc
262
263	echo
264	echo "IPv6"
265	echo "----------------------"
266
267	run_cmd "$IP nexthop add id 52 via 2001:db8:91::2 dev veth1"
268	rc=$?
269	log_test $rc 0 "Create nexthop with id, gw, dev"
270	if [ $rc -ne 0 ]; then
271		echo "Basic IPv6 create fails; can not continue"
272		return 1
273	fi
274
275	run_cmd "$IP nexthop get id 52"
276	log_test $? 0 "Get nexthop by id"
277	check_nexthop "id 52" "id 52 via 2001:db8:91::2 dev veth1"
278
279	run_cmd "$IP nexthop del id 52"
280	log_test $? 0 "Delete nexthop by id"
281	check_nexthop "id 52" ""
282
283	#
284	# gw, device spec
285	#
286	# gw validation, no device - fails since dev required
287	run_cmd "$IP nexthop add id 52 via 2001:db8:92::3"
288	log_test $? 2 "Create nexthop - gw only"
289
290	# gw is not reachable throught given dev
291	run_cmd "$IP nexthop add id 53 via 2001:db8:3::3 dev veth1"
292	log_test $? 2 "Create nexthop - invalid gw+dev combination"
293
294	# onlink arg overrides gw+dev lookup
295	run_cmd "$IP nexthop add id 53 via 2001:db8:3::3 dev veth1 onlink"
296	log_test $? 0 "Create nexthop - gw+dev and onlink"
297
298	# admin down should delete nexthops
299	set -e
300	run_cmd "$IP -6 nexthop add id 55 via 2001:db8:91::3 dev veth1"
301	run_cmd "$IP nexthop add id 56 via 2001:db8:91::4 dev veth1"
302	run_cmd "$IP nexthop add id 57 via 2001:db8:91::5 dev veth1"
303	run_cmd "$IP li set dev veth1 down"
304	set +e
305	check_nexthop "dev veth1" ""
306	log_test $? 0 "Nexthops removed on admin down"
307}
308
309ipv6_grp_fcnal()
310{
311	local rc
312
313	echo
314	echo "IPv6 groups functional"
315	echo "----------------------"
316
317	# basic functionality: create a nexthop group, default weight
318	run_cmd "$IP nexthop add id 61 via 2001:db8:91::2 dev veth1"
319	run_cmd "$IP nexthop add id 101 group 61"
320	log_test $? 0 "Create nexthop group with single nexthop"
321
322	# get nexthop group
323	run_cmd "$IP nexthop get id 101"
324	log_test $? 0 "Get nexthop group by id"
325	check_nexthop "id 101" "id 101 group 61"
326
327	# delete nexthop group
328	run_cmd "$IP nexthop del id 101"
329	log_test $? 0 "Delete nexthop group by id"
330	check_nexthop "id 101" ""
331
332	$IP nexthop flush >/dev/null 2>&1
333	check_nexthop "id 101" ""
334
335	#
336	# create group with multiple nexthops - mix of gw and dev only
337	#
338	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
339	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
340	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
341	run_cmd "$IP nexthop add id 65 dev veth1"
342	run_cmd "$IP nexthop add id 102 group 62/63/64/65"
343	log_test $? 0 "Nexthop group with multiple nexthops"
344	check_nexthop "id 102" "id 102 group 62/63/64/65"
345
346	# Delete nexthop in a group and group is updated
347	run_cmd "$IP nexthop del id 63"
348	check_nexthop "id 102" "id 102 group 62/64/65"
349	log_test $? 0 "Nexthop group updated when entry is deleted"
350
351	# create group with multiple weighted nexthops
352	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
353	run_cmd "$IP nexthop add id 103 group 62/63,2/64,3/65,4"
354	log_test $? 0 "Nexthop group with weighted nexthops"
355	check_nexthop "id 103" "id 103 group 62/63,2/64,3/65,4"
356
357	# Delete nexthop in a weighted group and group is updated
358	run_cmd "$IP nexthop del id 63"
359	check_nexthop "id 103" "id 103 group 62/64,3/65,4"
360	log_test $? 0 "Weighted nexthop group updated when entry is deleted"
361
362	# admin down - nexthop is removed from group
363	run_cmd "$IP li set dev veth1 down"
364	check_nexthop "dev veth1" ""
365	log_test $? 0 "Nexthops in groups removed on admin down"
366
367	# expect groups to have been deleted as well
368	check_nexthop "" ""
369
370	run_cmd "$IP li set dev veth1 up"
371
372	$IP nexthop flush >/dev/null 2>&1
373
374	# group with nexthops using different devices
375	set -e
376	run_cmd "$IP nexthop add id 62 via 2001:db8:91::2 dev veth1"
377	run_cmd "$IP nexthop add id 63 via 2001:db8:91::3 dev veth1"
378	run_cmd "$IP nexthop add id 64 via 2001:db8:91::4 dev veth1"
379	run_cmd "$IP nexthop add id 65 via 2001:db8:91::5 dev veth1"
380
381	run_cmd "$IP nexthop add id 72 via 2001:db8:92::2 dev veth3"
382	run_cmd "$IP nexthop add id 73 via 2001:db8:92::3 dev veth3"
383	run_cmd "$IP nexthop add id 74 via 2001:db8:92::4 dev veth3"
384	run_cmd "$IP nexthop add id 75 via 2001:db8:92::5 dev veth3"
385	set +e
386
387	# multiple groups with same nexthop
388	run_cmd "$IP nexthop add id 104 group 62"
389	run_cmd "$IP nexthop add id 105 group 62"
390	check_nexthop "group" "id 104 group 62 id 105 group 62"
391	log_test $? 0 "Multiple groups with same nexthop"
392
393	run_cmd "$IP nexthop flush groups"
394	[ $? -ne 0 ] && return 1
395
396	# on admin down of veth1, it should be removed from the group
397	run_cmd "$IP nexthop add id 105 group 62/63/72/73/64"
398	run_cmd "$IP li set veth1 down"
399	check_nexthop "id 105" "id 105 group 72/73"
400	log_test $? 0 "Nexthops in group removed on admin down - mixed group"
401
402	run_cmd "$IP nexthop add id 106 group 105/74"
403	log_test $? 2 "Nexthop group can not have a group as an entry"
404
405	# a group can have a blackhole entry only if it is the only
406	# nexthop in the group. Needed for atomic replace with an
407	# actual nexthop group
408	run_cmd "$IP -6 nexthop add id 31 blackhole"
409	run_cmd "$IP nexthop add id 107 group 31"
410	log_test $? 0 "Nexthop group with a blackhole entry"
411
412	run_cmd "$IP nexthop add id 108 group 31/24"
413	log_test $? 2 "Nexthop group can not have a blackhole and another nexthop"
414}
415
416ipv6_fcnal_runtime()
417{
418	local rc
419
420	echo
421	echo "IPv6 functional runtime"
422	echo "-----------------------"
423
424	sleep 5
425
426	#
427	# IPv6 - the basics
428	#
429	run_cmd "$IP nexthop add id 81 via 2001:db8:91::2 dev veth1"
430	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
431	log_test $? 0 "Route add"
432
433	run_cmd "$IP ro delete 2001:db8:101::1/128 nhid 81"
434	log_test $? 0 "Route delete"
435
436	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
437	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
438	log_test $? 0 "Ping with nexthop"
439
440	run_cmd "$IP nexthop add id 82 via 2001:db8:92::2 dev veth3"
441	run_cmd "$IP nexthop add id 122 group 81/82"
442	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
443	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
444	log_test $? 0 "Ping - multipath"
445
446	#
447	# IPv6 with blackhole nexthops
448	#
449	run_cmd "$IP -6 nexthop add id 83 blackhole"
450	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 83"
451	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
452	log_test $? 2 "Ping - blackhole"
453
454	run_cmd "$IP nexthop replace id 83 via 2001:db8:91::2 dev veth1"
455	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
456	log_test $? 0 "Ping - blackhole replaced with gateway"
457
458	run_cmd "$IP -6 nexthop replace id 83 blackhole"
459	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
460	log_test $? 2 "Ping - gateway replaced by blackhole"
461
462	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
463	run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
464	if [ $? -eq 0 ]; then
465		run_cmd "$IP nexthop replace id 122 group 83"
466		run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
467		log_test $? 2 "Ping - group with blackhole"
468
469		run_cmd "$IP nexthop replace id 122 group 81/82"
470		run_cmd "ip netns exec me ping -c1 -w1 2001:db8:101::1"
471		log_test $? 0 "Ping - group blackhole replaced with gateways"
472	else
473		log_test 2 0 "Ping - multipath failed"
474	fi
475
476	#
477	# device only and gw + dev only mix
478	#
479	run_cmd "$IP -6 nexthop add id 85 dev veth1"
480	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 85"
481	log_test $? 0 "IPv6 route with device only nexthop"
482	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 dev veth1"
483
484	run_cmd "$IP nexthop add id 123 group 81/85"
485	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 123"
486	log_test $? 0 "IPv6 multipath route with nexthop mix - dev only + gw"
487	check_route6 "2001:db8:101::1" "2001:db8:101::1 nhid 85 nexthop via 2001:db8:91::2 dev veth1 nexthop dev veth1"
488
489	#
490	# IPv6 route with v4 nexthop - not allowed
491	#
492	run_cmd "$IP ro delete 2001:db8:101::1/128"
493	run_cmd "$IP nexthop add id 84 via 172.16.1.1 dev veth1"
494	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 84"
495	log_test $? 2 "IPv6 route can not have a v4 gateway"
496
497	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 81"
498	run_cmd "$IP nexthop replace id 81 via 172.16.1.1 dev veth1"
499	log_test $? 2 "Nexthop replace - v6 route, v4 nexthop"
500
501	run_cmd "$IP ro replace 2001:db8:101::1/128 nhid 122"
502	run_cmd "$IP nexthop replace id 81 via 172.16.1.1 dev veth1"
503	log_test $? 2 "Nexthop replace of group entry - v6 route, v4 nexthop"
504
505	$IP nexthop flush >/dev/null 2>&1
506
507	#
508	# weird IPv6 cases
509	#
510	run_cmd "$IP nexthop add id 86 via 2001:db8:91::2 dev veth1"
511	run_cmd "$IP ro add 2001:db8:101::1/128 nhid 81"
512
513	# TO-DO:
514	# existing route with old nexthop; append route with new nexthop
515	# existing route with old nexthop; replace route with new
516	# existing route with new nexthop; replace route with old
517	# route with src address and using nexthop - not allowed
518}
519
520ipv4_fcnal()
521{
522	local rc
523
524	echo
525	echo "IPv4 functional"
526	echo "----------------------"
527
528	#
529	# basic IPv4 ops - add, get, delete
530	#
531	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
532	rc=$?
533	log_test $rc 0 "Create nexthop with id, gw, dev"
534	if [ $rc -ne 0 ]; then
535		echo "Basic IPv4 create fails; can not continue"
536		return 1
537	fi
538
539	run_cmd "$IP nexthop get id 12"
540	log_test $? 0 "Get nexthop by id"
541	check_nexthop "id 12" "id 12 via 172.16.1.2 src 172.16.1.1 dev veth1 scope link"
542
543	run_cmd "$IP nexthop del id 12"
544	log_test $? 0 "Delete nexthop by id"
545	check_nexthop "id 52" ""
546
547	#
548	# gw, device spec
549	#
550	# gw validation, no device - fails since dev is required
551	run_cmd "$IP nexthop add id 12 via 172.16.2.3"
552	log_test $? 2 "Create nexthop - gw only"
553
554	# gw not reachable through given dev
555	run_cmd "$IP nexthop add id 13 via 172.16.3.2 dev veth1"
556	log_test $? 2 "Create nexthop - invalid gw+dev combination"
557
558	# onlink flag overrides gw+dev lookup
559	run_cmd "$IP nexthop add id 13 via 172.16.3.2 dev veth1 onlink"
560	log_test $? 0 "Create nexthop - gw+dev and onlink"
561
562	# admin down should delete nexthops
563	set -e
564	run_cmd "$IP nexthop add id 15 via 172.16.1.3 dev veth1"
565	run_cmd "$IP nexthop add id 16 via 172.16.1.4 dev veth1"
566	run_cmd "$IP nexthop add id 17 via 172.16.1.5 dev veth1"
567	run_cmd "$IP li set dev veth1 down"
568	set +e
569	check_nexthop "dev veth1" ""
570	log_test $? 0 "Nexthops removed on admin down"
571}
572
573ipv4_grp_fcnal()
574{
575	local rc
576
577	echo
578	echo "IPv4 groups functional"
579	echo "----------------------"
580
581	# basic functionality: create a nexthop group, default weight
582	run_cmd "$IP nexthop add id 11 via 172.16.1.2 dev veth1"
583	run_cmd "$IP nexthop add id 101 group 11"
584	log_test $? 0 "Create nexthop group with single nexthop"
585
586	# get nexthop group
587	run_cmd "$IP nexthop get id 101"
588	log_test $? 0 "Get nexthop group by id"
589	check_nexthop "id 101" "id 101 group 11"
590
591	# delete nexthop group
592	run_cmd "$IP nexthop del id 101"
593	log_test $? 0 "Delete nexthop group by id"
594	check_nexthop "id 101" ""
595
596	$IP nexthop flush >/dev/null 2>&1
597
598	#
599	# create group with multiple nexthops
600	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
601	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
602	run_cmd "$IP nexthop add id 14 via 172.16.1.4 dev veth1"
603	run_cmd "$IP nexthop add id 15 via 172.16.1.5 dev veth1"
604	run_cmd "$IP nexthop add id 102 group 12/13/14/15"
605	log_test $? 0 "Nexthop group with multiple nexthops"
606	check_nexthop "id 102" "id 102 group 12/13/14/15"
607
608	# Delete nexthop in a group and group is updated
609	run_cmd "$IP nexthop del id 13"
610	check_nexthop "id 102" "id 102 group 12/14/15"
611	log_test $? 0 "Nexthop group updated when entry is deleted"
612
613	# create group with multiple weighted nexthops
614	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
615	run_cmd "$IP nexthop add id 103 group 12/13,2/14,3/15,4"
616	log_test $? 0 "Nexthop group with weighted nexthops"
617	check_nexthop "id 103" "id 103 group 12/13,2/14,3/15,4"
618
619	# Delete nexthop in a weighted group and group is updated
620	run_cmd "$IP nexthop del id 13"
621	check_nexthop "id 103" "id 103 group 12/14,3/15,4"
622	log_test $? 0 "Weighted nexthop group updated when entry is deleted"
623
624	# admin down - nexthop is removed from group
625	run_cmd "$IP li set dev veth1 down"
626	check_nexthop "dev veth1" ""
627	log_test $? 0 "Nexthops in groups removed on admin down"
628
629	# expect groups to have been deleted as well
630	check_nexthop "" ""
631
632	run_cmd "$IP li set dev veth1 up"
633
634	$IP nexthop flush >/dev/null 2>&1
635
636	# group with nexthops using different devices
637	set -e
638	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
639	run_cmd "$IP nexthop add id 13 via 172.16.1.3 dev veth1"
640	run_cmd "$IP nexthop add id 14 via 172.16.1.4 dev veth1"
641	run_cmd "$IP nexthop add id 15 via 172.16.1.5 dev veth1"
642
643	run_cmd "$IP nexthop add id 22 via 172.16.2.2 dev veth3"
644	run_cmd "$IP nexthop add id 23 via 172.16.2.3 dev veth3"
645	run_cmd "$IP nexthop add id 24 via 172.16.2.4 dev veth3"
646	run_cmd "$IP nexthop add id 25 via 172.16.2.5 dev veth3"
647	set +e
648
649	# multiple groups with same nexthop
650	run_cmd "$IP nexthop add id 104 group 12"
651	run_cmd "$IP nexthop add id 105 group 12"
652	check_nexthop "group" "id 104 group 12 id 105 group 12"
653	log_test $? 0 "Multiple groups with same nexthop"
654
655	run_cmd "$IP nexthop flush groups"
656	[ $? -ne 0 ] && return 1
657
658	# on admin down of veth1, it should be removed from the group
659	run_cmd "$IP nexthop add id 105 group 12/13/22/23/14"
660	run_cmd "$IP li set veth1 down"
661	check_nexthop "id 105" "id 105 group 22/23"
662	log_test $? 0 "Nexthops in group removed on admin down - mixed group"
663
664	run_cmd "$IP nexthop add id 106 group 105/24"
665	log_test $? 2 "Nexthop group can not have a group as an entry"
666
667	# a group can have a blackhole entry only if it is the only
668	# nexthop in the group. Needed for atomic replace with an
669	# actual nexthop group
670	run_cmd "$IP nexthop add id 31 blackhole"
671	run_cmd "$IP nexthop add id 107 group 31"
672	log_test $? 0 "Nexthop group with a blackhole entry"
673
674	run_cmd "$IP nexthop add id 108 group 31/24"
675	log_test $? 2 "Nexthop group can not have a blackhole and another nexthop"
676}
677
678ipv4_withv6_fcnal()
679{
680	local lladdr
681
682	set -e
683	lladdr=$(get_linklocal veth2 peer)
684	run_cmd "$IP nexthop add id 11 via ${lladdr} dev veth1"
685	set +e
686	run_cmd "$IP ro add 172.16.101.1/32 nhid 11"
687	log_test $? 0 "IPv6 nexthop with IPv4 route"
688	check_route "172.16.101.1" "172.16.101.1 nhid 11 via ${lladdr} dev veth1"
689
690	set -e
691	run_cmd "$IP nexthop add id 12 via 172.16.1.2 dev veth1"
692	run_cmd "$IP nexthop add id 101 group 11/12"
693	set +e
694	run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
695	log_test $? 0 "IPv6 nexthop with IPv4 route"
696
697	check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
698
699	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
700	log_test $? 0 "IPv4 route with IPv6 gateway"
701	check_route "172.16.101.1" "172.16.101.1 via ${lladdr} dev veth1"
702
703	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 2001:db8:50::1 dev veth1"
704	log_test $? 2 "IPv4 route with invalid IPv6 gateway"
705}
706
707ipv4_fcnal_runtime()
708{
709	local lladdr
710	local rc
711
712	echo
713	echo "IPv4 functional runtime"
714	echo "-----------------------"
715
716	run_cmd "$IP nexthop add id 21 via 172.16.1.2 dev veth1"
717	run_cmd "$IP ro add 172.16.101.1/32 nhid 21"
718	log_test $? 0 "Route add"
719	check_route "172.16.101.1" "172.16.101.1 nhid 21 via 172.16.1.2 dev veth1"
720
721	run_cmd "$IP ro delete 172.16.101.1/32 nhid 21"
722	log_test $? 0 "Route delete"
723
724	#
725	# scope mismatch
726	#
727	run_cmd "$IP nexthop add id 22 via 172.16.1.2 dev veth1"
728	run_cmd "$IP ro add 172.16.101.1/32 nhid 22 scope host"
729	log_test $? 2 "Route add - scope conflict with nexthop"
730
731	run_cmd "$IP nexthop replace id 22 dev veth3"
732	run_cmd "$IP ro add 172.16.101.1/32 nhid 22 scope host"
733	run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
734	log_test $? 2 "Nexthop replace with invalid scope for existing route"
735
736	#
737	# add route with nexthop and check traffic
738	#
739	run_cmd "$IP nexthop replace id 21 via 172.16.1.2 dev veth1"
740	run_cmd "$IP ro replace 172.16.101.1/32 nhid 21"
741	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
742	log_test $? 0 "Basic ping"
743
744	run_cmd "$IP nexthop replace id 22 via 172.16.2.2 dev veth3"
745	run_cmd "$IP nexthop add id 122 group 21/22"
746	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
747	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
748	log_test $? 0 "Ping - multipath"
749
750	#
751	# IPv4 with blackhole nexthops
752	#
753	run_cmd "$IP nexthop add id 23 blackhole"
754	run_cmd "$IP ro replace 172.16.101.1/32 nhid 23"
755	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
756	log_test $? 2 "Ping - blackhole"
757
758	run_cmd "$IP nexthop replace id 23 via 172.16.1.2 dev veth1"
759	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
760	log_test $? 0 "Ping - blackhole replaced with gateway"
761
762	run_cmd "$IP nexthop replace id 23 blackhole"
763	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
764	log_test $? 2 "Ping - gateway replaced by blackhole"
765
766	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
767	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
768	if [ $? -eq 0 ]; then
769		run_cmd "$IP nexthop replace id 122 group 23"
770		run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
771		log_test $? 2 "Ping - group with blackhole"
772
773		run_cmd "$IP nexthop replace id 122 group 21/22"
774		run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
775		log_test $? 0 "Ping - group blackhole replaced with gateways"
776	else
777		log_test 2 0 "Ping - multipath failed"
778	fi
779
780	#
781	# device only and gw + dev only mix
782	#
783	run_cmd "$IP nexthop add id 85 dev veth1"
784	run_cmd "$IP ro replace 172.16.101.1/32 nhid 85"
785	log_test $? 0 "IPv4 route with device only nexthop"
786	check_route "172.16.101.1" "172.16.101.1 nhid 85 dev veth1"
787
788	run_cmd "$IP nexthop add id 122 group 21/85"
789	run_cmd "$IP ro replace 172.16.101.1/32 nhid 122"
790	log_test $? 0 "IPv4 multipath route with nexthop mix - dev only + gw"
791	check_route "172.16.101.1" "172.16.101.1 nhid 85 nexthop via 172.16.1.2 dev veth1 nexthop dev veth1"
792
793	#
794	# IPv4 with IPv6
795	#
796	set -e
797	lladdr=$(get_linklocal veth2 peer)
798	run_cmd "$IP nexthop add id 24 via ${lladdr} dev veth1"
799	set +e
800	run_cmd "$IP ro replace 172.16.101.1/32 nhid 24"
801	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
802	log_test $? 0 "IPv6 nexthop with IPv4 route"
803
804	$IP neigh sh | grep -q "${lladdr} dev veth1"
805	if [ $? -eq 1 ]; then
806		echo "    WARNING: Neigh entry missing for ${lladdr}"
807		$IP neigh sh | grep 'dev veth1'
808	fi
809
810	$IP neigh sh | grep -q "172.16.101.1 dev eth1"
811	if [ $? -eq 0 ]; then
812		echo "    WARNING: Neigh entry exists for 172.16.101.1"
813		$IP neigh sh | grep 'dev veth1'
814	fi
815
816	set -e
817	run_cmd "$IP nexthop add id 25 via 172.16.1.2 dev veth1"
818	run_cmd "$IP nexthop add id 101 group 24/25"
819	set +e
820	run_cmd "$IP ro replace 172.16.101.1/32 nhid 101"
821	log_test $? 0 "IPv4 route with mixed v4-v6 multipath route"
822
823	check_route "172.16.101.1" "172.16.101.1 nhid 101 nexthop via ${lladdr} dev veth1 weight 1 nexthop via 172.16.1.2 dev veth1 weight 1"
824
825	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
826	log_test $? 0 "IPv6 nexthop with IPv4 route"
827
828	run_cmd "$IP ro replace 172.16.101.1/32 via inet6 ${lladdr} dev veth1"
829	run_cmd "ip netns exec me ping -c1 -w1 172.16.101.1"
830	log_test $? 0 "IPv4 route with IPv6 gateway"
831
832	$IP neigh sh | grep -q "${lladdr} dev veth1"
833	if [ $? -eq 1 ]; then
834		echo "    WARNING: Neigh entry missing for ${lladdr}"
835		$IP neigh sh | grep 'dev veth1'
836	fi
837
838	$IP neigh sh | grep -q "172.16.101.1 dev eth1"
839	if [ $? -eq 0 ]; then
840		echo "    WARNING: Neigh entry exists for 172.16.101.1"
841		$IP neigh sh | grep 'dev veth1'
842	fi
843
844	#
845	# MPLS as an example of LWT encap
846	#
847	run_cmd "$IP nexthop add id 51 encap mpls 101 via 172.16.1.2 dev veth1"
848	log_test $? 0 "IPv4 route with MPLS encap"
849	check_nexthop "id 51" "id 51 encap mpls 101 via 172.16.1.2 dev veth1 scope link"
850	log_test $? 0 "IPv4 route with MPLS encap - check"
851
852	run_cmd "$IP nexthop add id 52 encap mpls 102 via inet6 2001:db8:91::2 dev veth1"
853	log_test $? 0 "IPv4 route with MPLS encap and v6 gateway"
854	check_nexthop "id 52" "id 52 encap mpls 102 via 2001:db8:91::2 dev veth1 scope link"
855	log_test $? 0 "IPv4 route with MPLS encap, v6 gw - check"
856}
857
858basic()
859{
860	echo
861	echo "Basic functional tests"
862	echo "----------------------"
863	run_cmd "$IP nexthop ls"
864	log_test $? 0 "List with nothing defined"
865
866	run_cmd "$IP nexthop get id 1"
867	log_test $? 2 "Nexthop get on non-existent id"
868
869	# attempt to create nh without a device or gw - fails
870	run_cmd "$IP nexthop add id 1"
871	log_test $? 2 "Nexthop with no device or gateway"
872
873	# attempt to create nh with down device - fails
874	$IP li set veth1 down
875	run_cmd "$IP nexthop add id 1 dev veth1"
876	log_test $? 2 "Nexthop with down device"
877
878	# create nh with linkdown device - fails
879	$IP li set veth1 up
880	ip -netns peer li set veth2 down
881	run_cmd "$IP nexthop add id 1 dev veth1"
882	log_test $? 2 "Nexthop with device that is linkdown"
883	ip -netns peer li set veth2 up
884
885	# device only
886	run_cmd "$IP nexthop add id 1 dev veth1"
887	log_test $? 0 "Nexthop with device only"
888
889	# create nh with duplicate id
890	run_cmd "$IP nexthop add id 1 dev veth3"
891	log_test $? 2 "Nexthop with duplicate id"
892
893	# blackhole nexthop
894	run_cmd "$IP nexthop add id 2 blackhole"
895	log_test $? 0 "Blackhole nexthop"
896
897	# blackhole nexthop can not have other specs
898	run_cmd "$IP nexthop replace id 2 blackhole dev veth1"
899	log_test $? 2 "Blackhole nexthop with other attributes"
900
901	#
902	# groups
903	#
904
905	run_cmd "$IP nexthop add id 101 group 1"
906	log_test $? 0 "Create group"
907
908	run_cmd "$IP nexthop add id 102 group 2"
909	log_test $? 0 "Create group with blackhole nexthop"
910
911	# multipath group can not have a blackhole as 1 path
912	run_cmd "$IP nexthop add id 103 group 1/2"
913	log_test $? 2 "Create multipath group where 1 path is a blackhole"
914
915	# multipath group can not have a member replaced by a blackhole
916	run_cmd "$IP nexthop replace id 2 dev veth3"
917	run_cmd "$IP nexthop replace id 102 group 1/2"
918	run_cmd "$IP nexthop replace id 2 blackhole"
919	log_test $? 2 "Multipath group can not have a member replaced by blackhole"
920
921	# attempt to create group with non-existent nexthop
922	run_cmd "$IP nexthop add id 103 group 12"
923	log_test $? 2 "Create group with non-existent nexthop"
924
925	# attempt to create group with same nexthop
926	run_cmd "$IP nexthop add id 103 group 1/1"
927	log_test $? 2 "Create group with same nexthop multiple times"
928
929	# replace nexthop with a group - fails
930	run_cmd "$IP nexthop replace id 2 group 1"
931	log_test $? 2 "Replace nexthop with nexthop group"
932
933	# replace nexthop group with a nexthop - fails
934	run_cmd "$IP nexthop replace id 101 dev veth1"
935	log_test $? 2 "Replace nexthop group with nexthop"
936
937	# nexthop group with other attributes fail
938	run_cmd "$IP nexthop add id 104 group 1 dev veth1"
939	log_test $? 2 "Nexthop group and device"
940
941	run_cmd "$IP nexthop add id 104 group 1 blackhole"
942	log_test $? 2 "Nexthop group and blackhole"
943
944	$IP nexthop flush >/dev/null 2>&1
945}
946
947################################################################################
948# usage
949
950usage()
951{
952	cat <<EOF
953usage: ${0##*/} OPTS
954
955        -t <test>   Test(s) to run (default: all)
956                    (options: $ALL_TESTS)
957        -4          IPv4 tests only
958        -6          IPv6 tests only
959        -p          Pause on fail
960        -P          Pause after each test before cleanup
961        -v          verbose mode (show commands and output)
962
963    Runtime test
964	-n num	    Number of nexthops to target
965	-N    	    Use new style to install routes in DUT
966
967done
968EOF
969}
970
971################################################################################
972# main
973
974while getopts :t:pP46hv o
975do
976	case $o in
977		t) TESTS=$OPTARG;;
978		4) TESTS=${IPV4_TESTS};;
979		6) TESTS=${IPV6_TESTS};;
980		p) PAUSE_ON_FAIL=yes;;
981		P) PAUSE=yes;;
982		v) VERBOSE=$(($VERBOSE + 1));;
983		h) usage; exit 0;;
984		*) usage; exit 1;;
985	esac
986done
987
988# make sure we don't pause twice
989[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
990
991if [ "$(id -u)" -ne 0 ];then
992	echo "SKIP: Need root privileges"
993	exit $ksft_skip;
994fi
995
996if [ ! -x "$(command -v ip)" ]; then
997	echo "SKIP: Could not run test without ip tool"
998	exit $ksft_skip
999fi
1000
1001ip help 2>&1 | grep -q nexthop
1002if [ $? -ne 0 ]; then
1003	echo "SKIP: iproute2 too old, missing nexthop command"
1004	exit $ksft_skip
1005fi
1006
1007out=$(ip nexthop ls 2>&1 | grep -q "Operation not supported")
1008if [ $? -eq 0 ]; then
1009	echo "SKIP: kernel lacks nexthop support"
1010	exit $ksft_skip
1011fi
1012
1013for t in $TESTS
1014do
1015	case $t in
1016	none) IP="ip -netns peer"; setup; exit 0;;
1017	*) setup; $t; cleanup;;
1018	esac
1019done
1020
1021if [ "$TESTS" != "none" ]; then
1022	printf "\nTests passed: %3d\n" ${nsuccess}
1023	printf "Tests failed: %3d\n"   ${nfail}
1024fi
1025
1026exit $ret
1027