xref: /linux/tools/testing/selftests/net/fib_tests.sh (revision 59fff63cc2b75dcfe08f9eeb4b2187d73e53843d)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This test is for checking IPv4 and IPv6 FIB behavior in response to
5# different events.
6
7ret=0
8# Kselftest framework requirement - SKIP code is 4.
9ksft_skip=4
10
11# all tests in this script. Can be overridden with -t option
12TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
13       ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics \
14       ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr \
15       ipv6_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh fib6_gc_test \
16       ipv4_mpath_list ipv6_mpath_list"
17
18VERBOSE=0
19PAUSE_ON_FAIL=no
20PAUSE=no
21IP="$(which ip) -netns ns1"
22NS_EXEC="$(which ip) netns exec ns1"
23
24which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
25
26log_test()
27{
28	local rc=$1
29	local expected=$2
30	local msg="$3"
31
32	if [ ${rc} -eq ${expected} ]; then
33		printf "    TEST: %-60s  [ OK ]\n" "${msg}"
34		nsuccess=$((nsuccess+1))
35	else
36		ret=1
37		nfail=$((nfail+1))
38		printf "    TEST: %-60s  [FAIL]\n" "${msg}"
39		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
40		echo
41			echo "hit enter to continue, 'q' to quit"
42			read a
43			[ "$a" = "q" ] && exit 1
44		fi
45	fi
46
47	if [ "${PAUSE}" = "yes" ]; then
48		echo
49		echo "hit enter to continue, 'q' to quit"
50		read a
51		[ "$a" = "q" ] && exit 1
52	fi
53}
54
55setup()
56{
57	set -e
58	ip netns add ns1
59	ip netns set ns1 auto
60	$IP link set dev lo up
61	ip netns exec ns1 sysctl -qw net.ipv4.ip_forward=1
62	ip netns exec ns1 sysctl -qw net.ipv6.conf.all.forwarding=1
63
64	$IP link add dummy0 type dummy
65	$IP link set dev dummy0 up
66	$IP address add 198.51.100.1/24 dev dummy0
67	$IP -6 address add 2001:db8:1::1/64 dev dummy0
68	set +e
69
70}
71
72cleanup()
73{
74	$IP link del dev dummy0 &> /dev/null
75	ip netns del ns1 &> /dev/null
76	ip netns del ns2 &> /dev/null
77}
78
79get_linklocal()
80{
81	local dev=$1
82	local addr
83
84	addr=$($IP -6 -br addr show dev ${dev} | \
85	awk '{
86		for (i = 3; i <= NF; ++i) {
87			if ($i ~ /^fe80/)
88				print $i
89		}
90	}'
91	)
92	addr=${addr/\/*}
93
94	[ -z "$addr" ] && return 1
95
96	echo $addr
97
98	return 0
99}
100
101fib_unreg_unicast_test()
102{
103	echo
104	echo "Single path route test"
105
106	setup
107
108	echo "    Start point"
109	$IP route get fibmatch 198.51.100.2 &> /dev/null
110	log_test $? 0 "IPv4 fibmatch"
111	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
112	log_test $? 0 "IPv6 fibmatch"
113
114	set -e
115	$IP link del dev dummy0
116	set +e
117
118	echo "    Nexthop device deleted"
119	$IP route get fibmatch 198.51.100.2 &> /dev/null
120	log_test $? 2 "IPv4 fibmatch - no route"
121	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
122	log_test $? 2 "IPv6 fibmatch - no route"
123
124	cleanup
125}
126
127fib_unreg_multipath_test()
128{
129
130	echo
131	echo "Multipath route test"
132
133	setup
134
135	set -e
136	$IP link add dummy1 type dummy
137	$IP link set dev dummy1 up
138	$IP address add 192.0.2.1/24 dev dummy1
139	$IP -6 address add 2001:db8:2::1/64 dev dummy1
140
141	$IP route add 203.0.113.0/24 \
142		nexthop via 198.51.100.2 dev dummy0 \
143		nexthop via 192.0.2.2 dev dummy1
144	$IP -6 route add 2001:db8:3::/64 \
145		nexthop via 2001:db8:1::2 dev dummy0 \
146		nexthop via 2001:db8:2::2 dev dummy1
147	set +e
148
149	echo "    Start point"
150	$IP route get fibmatch 203.0.113.1 &> /dev/null
151	log_test $? 0 "IPv4 fibmatch"
152	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
153	log_test $? 0 "IPv6 fibmatch"
154
155	set -e
156	$IP link del dev dummy0
157	set +e
158
159	echo "    One nexthop device deleted"
160	$IP route get fibmatch 203.0.113.1 &> /dev/null
161	log_test $? 2 "IPv4 - multipath route removed on delete"
162
163	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
164	# In IPv6 we do not flush the entire multipath route.
165	log_test $? 0 "IPv6 - multipath down to single path"
166
167	set -e
168	$IP link del dev dummy1
169	set +e
170
171	echo "    Second nexthop device deleted"
172	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
173	log_test $? 2 "IPv6 - no route"
174
175	cleanup
176}
177
178fib_unreg_test()
179{
180	fib_unreg_unicast_test
181	fib_unreg_multipath_test
182}
183
184fib_down_unicast_test()
185{
186	echo
187	echo "Single path, admin down"
188
189	setup
190
191	echo "    Start point"
192	$IP route get fibmatch 198.51.100.2 &> /dev/null
193	log_test $? 0 "IPv4 fibmatch"
194	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
195	log_test $? 0 "IPv6 fibmatch"
196
197	set -e
198	$IP link set dev dummy0 down
199	set +e
200
201	echo "    Route deleted on down"
202	$IP route get fibmatch 198.51.100.2 &> /dev/null
203	log_test $? 2 "IPv4 fibmatch"
204	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
205	log_test $? 2 "IPv6 fibmatch"
206
207	cleanup
208}
209
210fib_down_multipath_test_do()
211{
212	local down_dev=$1
213	local up_dev=$2
214
215	$IP route get fibmatch 203.0.113.1 \
216		oif $down_dev &> /dev/null
217	log_test $? 2 "IPv4 fibmatch on down device"
218	$IP -6 route get fibmatch 2001:db8:3::1 \
219		oif $down_dev &> /dev/null
220	log_test $? 2 "IPv6 fibmatch on down device"
221
222	$IP route get fibmatch 203.0.113.1 \
223		oif $up_dev &> /dev/null
224	log_test $? 0 "IPv4 fibmatch on up device"
225	$IP -6 route get fibmatch 2001:db8:3::1 \
226		oif $up_dev &> /dev/null
227	log_test $? 0 "IPv6 fibmatch on up device"
228
229	$IP route get fibmatch 203.0.113.1 | \
230		grep $down_dev | grep -q "dead linkdown"
231	log_test $? 0 "IPv4 flags on down device"
232	$IP -6 route get fibmatch 2001:db8:3::1 | \
233		grep $down_dev | grep -q "dead linkdown"
234	log_test $? 0 "IPv6 flags on down device"
235
236	$IP route get fibmatch 203.0.113.1 | \
237		grep $up_dev | grep -q "dead linkdown"
238	log_test $? 1 "IPv4 flags on up device"
239	$IP -6 route get fibmatch 2001:db8:3::1 | \
240		grep $up_dev | grep -q "dead linkdown"
241	log_test $? 1 "IPv6 flags on up device"
242}
243
244fib_down_multipath_test()
245{
246	echo
247	echo "Admin down multipath"
248
249	setup
250
251	set -e
252	$IP link add dummy1 type dummy
253	$IP link set dev dummy1 up
254
255	$IP address add 192.0.2.1/24 dev dummy1
256	$IP -6 address add 2001:db8:2::1/64 dev dummy1
257
258	$IP route add 203.0.113.0/24 \
259		nexthop via 198.51.100.2 dev dummy0 \
260		nexthop via 192.0.2.2 dev dummy1
261	$IP -6 route add 2001:db8:3::/64 \
262		nexthop via 2001:db8:1::2 dev dummy0 \
263		nexthop via 2001:db8:2::2 dev dummy1
264	set +e
265
266	echo "    Verify start point"
267	$IP route get fibmatch 203.0.113.1 &> /dev/null
268	log_test $? 0 "IPv4 fibmatch"
269
270	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
271	log_test $? 0 "IPv6 fibmatch"
272
273	set -e
274	$IP link set dev dummy0 down
275	set +e
276
277	echo "    One device down, one up"
278	fib_down_multipath_test_do "dummy0" "dummy1"
279
280	set -e
281	$IP link set dev dummy0 up
282	$IP link set dev dummy1 down
283	set +e
284
285	echo "    Other device down and up"
286	fib_down_multipath_test_do "dummy1" "dummy0"
287
288	set -e
289	$IP link set dev dummy0 down
290	set +e
291
292	echo "    Both devices down"
293	$IP route get fibmatch 203.0.113.1 &> /dev/null
294	log_test $? 2 "IPv4 fibmatch"
295	$IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null
296	log_test $? 2 "IPv6 fibmatch"
297
298	$IP link del dev dummy1
299	cleanup
300}
301
302fib_down_test()
303{
304	fib_down_unicast_test
305	fib_down_multipath_test
306}
307
308# Local routes should not be affected when carrier changes.
309fib_carrier_local_test()
310{
311	echo
312	echo "Local carrier tests - single path"
313
314	setup
315
316	set -e
317	$IP link set dev dummy0 carrier on
318	set +e
319
320	echo "    Start point"
321	$IP route get fibmatch 198.51.100.1 &> /dev/null
322	log_test $? 0 "IPv4 fibmatch"
323	$IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
324	log_test $? 0 "IPv6 fibmatch"
325
326	$IP route get fibmatch 198.51.100.1 | \
327		grep -q "linkdown"
328	log_test $? 1 "IPv4 - no linkdown flag"
329	$IP -6 route get fibmatch 2001:db8:1::1 | \
330		grep -q "linkdown"
331	log_test $? 1 "IPv6 - no linkdown flag"
332
333	set -e
334	$IP link set dev dummy0 carrier off
335	sleep 1
336	set +e
337
338	echo "    Carrier off on nexthop"
339	$IP route get fibmatch 198.51.100.1 &> /dev/null
340	log_test $? 0 "IPv4 fibmatch"
341	$IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null
342	log_test $? 0 "IPv6 fibmatch"
343
344	$IP route get fibmatch 198.51.100.1 | \
345		grep -q "linkdown"
346	log_test $? 1 "IPv4 - linkdown flag set"
347	$IP -6 route get fibmatch 2001:db8:1::1 | \
348		grep -q "linkdown"
349	log_test $? 1 "IPv6 - linkdown flag set"
350
351	set -e
352	$IP address add 192.0.2.1/24 dev dummy0
353	$IP -6 address add 2001:db8:2::1/64 dev dummy0
354	set +e
355
356	echo "    Route to local address with carrier down"
357	$IP route get fibmatch 192.0.2.1 &> /dev/null
358	log_test $? 0 "IPv4 fibmatch"
359	$IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null
360	log_test $? 0 "IPv6 fibmatch"
361
362	$IP route get fibmatch 192.0.2.1 | \
363		grep -q "linkdown"
364	log_test $? 1 "IPv4 linkdown flag set"
365	$IP -6 route get fibmatch 2001:db8:2::1 | \
366		grep -q "linkdown"
367	log_test $? 1 "IPv6 linkdown flag set"
368
369	cleanup
370}
371
372fib_carrier_unicast_test()
373{
374	ret=0
375
376	echo
377	echo "Single path route carrier test"
378
379	setup
380
381	set -e
382	$IP link set dev dummy0 carrier on
383	set +e
384
385	echo "    Start point"
386	$IP route get fibmatch 198.51.100.2 &> /dev/null
387	log_test $? 0 "IPv4 fibmatch"
388	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
389	log_test $? 0 "IPv6 fibmatch"
390
391	$IP route get fibmatch 198.51.100.2 | \
392		grep -q "linkdown"
393	log_test $? 1 "IPv4 no linkdown flag"
394	$IP -6 route get fibmatch 2001:db8:1::2 | \
395		grep -q "linkdown"
396	log_test $? 1 "IPv6 no linkdown flag"
397
398	set -e
399	$IP link set dev dummy0 carrier off
400	sleep 1
401	set +e
402
403	echo "    Carrier down"
404	$IP route get fibmatch 198.51.100.2 &> /dev/null
405	log_test $? 0 "IPv4 fibmatch"
406	$IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null
407	log_test $? 0 "IPv6 fibmatch"
408
409	$IP route get fibmatch 198.51.100.2 | \
410		grep -q "linkdown"
411	log_test $? 0 "IPv4 linkdown flag set"
412	$IP -6 route get fibmatch 2001:db8:1::2 | \
413		grep -q "linkdown"
414	log_test $? 0 "IPv6 linkdown flag set"
415
416	set -e
417	$IP address add 192.0.2.1/24 dev dummy0
418	$IP -6 address add 2001:db8:2::1/64 dev dummy0
419	set +e
420
421	echo "    Second address added with carrier down"
422	$IP route get fibmatch 192.0.2.2 &> /dev/null
423	log_test $? 0 "IPv4 fibmatch"
424	$IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null
425	log_test $? 0 "IPv6 fibmatch"
426
427	$IP route get fibmatch 192.0.2.2 | \
428		grep -q "linkdown"
429	log_test $? 0 "IPv4 linkdown flag set"
430	$IP -6 route get fibmatch 2001:db8:2::2 | \
431		grep -q "linkdown"
432	log_test $? 0 "IPv6 linkdown flag set"
433
434	cleanup
435}
436
437fib_carrier_test()
438{
439	fib_carrier_local_test
440	fib_carrier_unicast_test
441}
442
443fib_rp_filter_test()
444{
445	echo
446	echo "IPv4 rp_filter tests"
447
448	setup
449
450	set -e
451	ip netns add ns2
452	ip netns set ns2 auto
453
454	ip -netns ns2 link set dev lo up
455
456	$IP link add name veth1 type veth peer name veth2
457	$IP link set dev veth2 netns ns2
458	$IP address add 192.0.2.1/24 dev veth1
459	ip -netns ns2 address add 192.0.2.1/24 dev veth2
460	$IP link set dev veth1 up
461	ip -netns ns2 link set dev veth2 up
462
463	$IP link set dev lo address 52:54:00:6a:c7:5e
464	$IP link set dev veth1 address 52:54:00:6a:c7:5e
465	ip -netns ns2 link set dev lo address 52:54:00:6a:c7:5e
466	ip -netns ns2 link set dev veth2 address 52:54:00:6a:c7:5e
467
468	# 1. (ns2) redirect lo's egress to veth2's egress
469	ip netns exec ns2 tc qdisc add dev lo parent root handle 1: fq_codel
470	ip netns exec ns2 tc filter add dev lo parent 1: protocol arp basic \
471		action mirred egress redirect dev veth2
472	ip netns exec ns2 tc filter add dev lo parent 1: protocol ip basic \
473		action mirred egress redirect dev veth2
474
475	# 2. (ns1) redirect veth1's ingress to lo's ingress
476	$NS_EXEC tc qdisc add dev veth1 ingress
477	$NS_EXEC tc filter add dev veth1 ingress protocol arp basic \
478		action mirred ingress redirect dev lo
479	$NS_EXEC tc filter add dev veth1 ingress protocol ip basic \
480		action mirred ingress redirect dev lo
481
482	# 3. (ns1) redirect lo's egress to veth1's egress
483	$NS_EXEC tc qdisc add dev lo parent root handle 1: fq_codel
484	$NS_EXEC tc filter add dev lo parent 1: protocol arp basic \
485		action mirred egress redirect dev veth1
486	$NS_EXEC tc filter add dev lo parent 1: protocol ip basic \
487		action mirred egress redirect dev veth1
488
489	# 4. (ns2) redirect veth2's ingress to lo's ingress
490	ip netns exec ns2 tc qdisc add dev veth2 ingress
491	ip netns exec ns2 tc filter add dev veth2 ingress protocol arp basic \
492		action mirred ingress redirect dev lo
493	ip netns exec ns2 tc filter add dev veth2 ingress protocol ip basic \
494		action mirred ingress redirect dev lo
495
496	$NS_EXEC sysctl -qw net.ipv4.conf.all.rp_filter=1
497	$NS_EXEC sysctl -qw net.ipv4.conf.all.accept_local=1
498	$NS_EXEC sysctl -qw net.ipv4.conf.all.route_localnet=1
499	ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=1
500	ip netns exec ns2 sysctl -qw net.ipv4.conf.all.accept_local=1
501	ip netns exec ns2 sysctl -qw net.ipv4.conf.all.route_localnet=1
502	set +e
503
504	run_cmd "ip netns exec ns2 ping -w1 -c1 192.0.2.1"
505	log_test $? 0 "rp_filter passes local packets"
506
507	run_cmd "ip netns exec ns2 ping -w1 -c1 127.0.0.1"
508	log_test $? 0 "rp_filter passes loopback packets"
509
510	cleanup
511}
512
513################################################################################
514# Tests on nexthop spec
515
516# run 'ip route add' with given spec
517add_rt()
518{
519	local desc="$1"
520	local erc=$2
521	local vrf=$3
522	local pfx=$4
523	local gw=$5
524	local dev=$6
525	local cmd out rc
526
527	[ "$vrf" = "-" ] && vrf="default"
528	[ -n "$gw" ] && gw="via $gw"
529	[ -n "$dev" ] && dev="dev $dev"
530
531	cmd="$IP route add vrf $vrf $pfx $gw $dev"
532	if [ "$VERBOSE" = "1" ]; then
533		printf "\n    COMMAND: $cmd\n"
534	fi
535
536	out=$(eval $cmd 2>&1)
537	rc=$?
538	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
539		echo "    $out"
540	fi
541	log_test $rc $erc "$desc"
542}
543
544fib4_nexthop()
545{
546	echo
547	echo "IPv4 nexthop tests"
548
549	echo "<<< write me >>>"
550}
551
552fib6_nexthop()
553{
554	local lldummy=$(get_linklocal dummy0)
555	local llv1=$(get_linklocal dummy0)
556
557	if [ -z "$lldummy" ]; then
558		echo "Failed to get linklocal address for dummy0"
559		return 1
560	fi
561	if [ -z "$llv1" ]; then
562		echo "Failed to get linklocal address for veth1"
563		return 1
564	fi
565
566	echo
567	echo "IPv6 nexthop tests"
568
569	add_rt "Directly connected nexthop, unicast address" 0 \
570		- 2001:db8:101::/64 2001:db8:1::2
571	add_rt "Directly connected nexthop, unicast address with device" 0 \
572		- 2001:db8:102::/64 2001:db8:1::2 "dummy0"
573	add_rt "Gateway is linklocal address" 0 \
574		- 2001:db8:103::1/64 $llv1 "veth0"
575
576	# fails because LL address requires a device
577	add_rt "Gateway is linklocal address, no device" 2 \
578		- 2001:db8:104::1/64 $llv1
579
580	# local address can not be a gateway
581	add_rt "Gateway can not be local unicast address" 2 \
582		- 2001:db8:105::/64 2001:db8:1::1
583	add_rt "Gateway can not be local unicast address, with device" 2 \
584		- 2001:db8:106::/64 2001:db8:1::1 "dummy0"
585	add_rt "Gateway can not be a local linklocal address" 2 \
586		- 2001:db8:107::1/64 $lldummy "dummy0"
587
588	# VRF tests
589	add_rt "Gateway can be local address in a VRF" 0 \
590		- 2001:db8:108::/64 2001:db8:51::2
591	add_rt "Gateway can be local address in a VRF, with device" 0 \
592		- 2001:db8:109::/64 2001:db8:51::2 "veth0"
593	add_rt "Gateway can be local linklocal address in a VRF" 0 \
594		- 2001:db8:110::1/64 $llv1 "veth0"
595
596	add_rt "Redirect to VRF lookup" 0 \
597		- 2001:db8:111::/64 "" "red"
598
599	add_rt "VRF route, gateway can be local address in default VRF" 0 \
600		red 2001:db8:112::/64 2001:db8:51::1
601
602	# local address in same VRF fails
603	add_rt "VRF route, gateway can not be a local address" 2 \
604		red 2001:db8:113::1/64 2001:db8:2::1
605	add_rt "VRF route, gateway can not be a local addr with device" 2 \
606		red 2001:db8:114::1/64 2001:db8:2::1 "dummy1"
607}
608
609# Default VRF:
610#   dummy0 - 198.51.100.1/24 2001:db8:1::1/64
611#   veth0  - 192.0.2.1/24    2001:db8:51::1/64
612#
613# VRF red:
614#   dummy1 - 192.168.2.1/24 2001:db8:2::1/64
615#   veth1  - 192.0.2.2/24   2001:db8:51::2/64
616#
617#  [ dummy0   veth0 ]--[ veth1   dummy1 ]
618
619fib_nexthop_test()
620{
621	setup
622
623	set -e
624
625	$IP -4 rule add pref 32765 table local
626	$IP -4 rule del pref 0
627	$IP -6 rule add pref 32765 table local
628	$IP -6 rule del pref 0
629
630	$IP link add red type vrf table 1
631	$IP link set red up
632	$IP -4 route add vrf red unreachable default metric 4278198272
633	$IP -6 route add vrf red unreachable default metric 4278198272
634
635	$IP link add veth0 type veth peer name veth1
636	$IP link set dev veth0 up
637	$IP address add 192.0.2.1/24 dev veth0
638	$IP -6 address add 2001:db8:51::1/64 dev veth0
639
640	$IP link set dev veth1 vrf red up
641	$IP address add 192.0.2.2/24 dev veth1
642	$IP -6 address add 2001:db8:51::2/64 dev veth1
643
644	$IP link add dummy1 type dummy
645	$IP link set dev dummy1 vrf red up
646	$IP address add 192.168.2.1/24 dev dummy1
647	$IP -6 address add 2001:db8:2::1/64 dev dummy1
648	set +e
649
650	sleep 1
651	fib4_nexthop
652	fib6_nexthop
653
654	(
655	$IP link del dev dummy1
656	$IP link del veth0
657	$IP link del red
658	) 2>/dev/null
659	cleanup
660}
661
662fib6_notify_test()
663{
664	setup
665
666	echo
667	echo "Fib6 info length calculation in route notify test"
668	set -e
669
670	for i in 10 20 30 40 50 60 70;
671	do
672		$IP link add dummy_$i type dummy
673		$IP link set dev dummy_$i up
674		$IP -6 address add 2001:$i::1/64 dev dummy_$i
675	done
676
677	$NS_EXEC ip monitor route &> errors.txt &
678	sleep 2
679
680	$IP -6 route add 2001::/64 \
681                nexthop via 2001:10::2 dev dummy_10 \
682                nexthop encap ip6 dst 2002::20 via 2001:20::2 dev dummy_20 \
683                nexthop encap ip6 dst 2002::30 via 2001:30::2 dev dummy_30 \
684                nexthop encap ip6 dst 2002::40 via 2001:40::2 dev dummy_40 \
685                nexthop encap ip6 dst 2002::50 via 2001:50::2 dev dummy_50 \
686                nexthop encap ip6 dst 2002::60 via 2001:60::2 dev dummy_60 \
687                nexthop encap ip6 dst 2002::70 via 2001:70::2 dev dummy_70
688
689	set +e
690
691	err=`cat errors.txt |grep "Message too long"`
692	if [ -z "$err" ];then
693		ret=0
694	else
695		ret=1
696	fi
697
698	log_test $ret 0 "ipv6 route add notify"
699
700	{ kill %% && wait %%; } 2>/dev/null
701
702	#rm errors.txt
703
704	cleanup &> /dev/null
705}
706
707
708fib_notify_test()
709{
710	setup
711
712	echo
713	echo "Fib4 info length calculation in route notify test"
714
715	set -e
716
717	for i in 10 20 30 40 50 60 70;
718	do
719		$IP link add dummy_$i type dummy
720		$IP link set dev dummy_$i up
721		$IP address add 20.20.$i.2/24 dev dummy_$i
722	done
723
724	$NS_EXEC ip monitor route &> errors.txt &
725	sleep 2
726
727        $IP route add 10.0.0.0/24 \
728                nexthop via 20.20.10.1 dev dummy_10 \
729                nexthop encap ip dst 192.168.10.20 via 20.20.20.1 dev dummy_20 \
730                nexthop encap ip dst 192.168.10.30 via 20.20.30.1 dev dummy_30 \
731                nexthop encap ip dst 192.168.10.40 via 20.20.40.1 dev dummy_40 \
732                nexthop encap ip dst 192.168.10.50 via 20.20.50.1 dev dummy_50 \
733                nexthop encap ip dst 192.168.10.60 via 20.20.60.1 dev dummy_60 \
734                nexthop encap ip dst 192.168.10.70 via 20.20.70.1 dev dummy_70
735
736	set +e
737
738	err=`cat errors.txt |grep "Message too long"`
739	if [ -z "$err" ];then
740		ret=0
741	else
742		ret=1
743	fi
744
745	log_test $ret 0 "ipv4 route add notify"
746
747	{ kill %% && wait %%; } 2>/dev/null
748
749	rm  errors.txt
750
751	cleanup &> /dev/null
752}
753
754fib6_gc_test()
755{
756	setup
757
758	echo
759	echo "Fib6 garbage collection test"
760	set -e
761
762	EXPIRE=3
763
764	# Check expiration of routes every $EXPIRE seconds (GC)
765	$NS_EXEC sysctl -wq net.ipv6.route.gc_interval=$EXPIRE
766
767	$IP link add dummy_10 type dummy
768	$IP link set dev dummy_10 up
769	$IP -6 address add 2001:10::1/64 dev dummy_10
770
771	$NS_EXEC sysctl -wq net.ipv6.route.flush=1
772
773	# Temporary routes
774	for i in $(seq 1 1000); do
775	    # Expire route after $EXPIRE seconds
776	    $IP -6 route add 2001:20::$i \
777		via 2001:10::2 dev dummy_10 expires $EXPIRE
778	done
779	sleep $(($EXPIRE * 2))
780	N_EXP_SLEEP=$($IP -6 route list |grep expires|wc -l)
781	if [ $N_EXP_SLEEP -ne 0 ]; then
782	    echo "FAIL: expected 0 routes with expires, got $N_EXP_SLEEP"
783	    ret=1
784	else
785	    ret=0
786	fi
787
788	# Permanent routes
789	for i in $(seq 1 5000); do
790	    $IP -6 route add 2001:30::$i \
791		via 2001:10::2 dev dummy_10
792	done
793	# Temporary routes
794	for i in $(seq 1 1000); do
795	    # Expire route after $EXPIRE seconds
796	    $IP -6 route add 2001:20::$i \
797		via 2001:10::2 dev dummy_10 expires $EXPIRE
798	done
799	sleep $(($EXPIRE * 2))
800	N_EXP_SLEEP=$($IP -6 route list |grep expires|wc -l)
801	if [ $N_EXP_SLEEP -ne 0 ]; then
802	    echo "FAIL: expected 0 routes with expires," \
803		 "got $N_EXP_SLEEP (5000 permanent routes)"
804	    ret=1
805	else
806	    ret=0
807	fi
808
809	set +e
810
811	log_test $ret 0 "ipv6 route garbage collection"
812
813	cleanup &> /dev/null
814}
815
816fib_suppress_test()
817{
818	echo
819	echo "FIB rule with suppress_prefixlength"
820	setup
821
822	$IP link add dummy1 type dummy
823	$IP link set dummy1 up
824	$IP -6 route add default dev dummy1
825	$IP -6 rule add table main suppress_prefixlength 0
826	ping -f -c 1000 -W 1 1234::1 >/dev/null 2>&1
827	$IP -6 rule del table main suppress_prefixlength 0
828	$IP link del dummy1
829
830	# If we got here without crashing, we're good.
831	log_test 0 0 "FIB rule suppress test"
832
833	cleanup
834}
835
836################################################################################
837# Tests on route add and replace
838
839run_cmd()
840{
841	local cmd="$1"
842	local out
843	local stderr="2>/dev/null"
844
845	if [ "$VERBOSE" = "1" ]; then
846		printf "    COMMAND: $cmd\n"
847		stderr=
848	fi
849
850	out=$(eval $cmd $stderr)
851	rc=$?
852	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
853		echo "    $out"
854	fi
855
856	[ "$VERBOSE" = "1" ] && echo
857
858	return $rc
859}
860
861check_expected()
862{
863	local out="$1"
864	local expected="$2"
865	local rc=0
866
867	[ "${out}" = "${expected}" ] && return 0
868
869	if [ -z "${out}" ]; then
870		if [ "$VERBOSE" = "1" ]; then
871			printf "\nNo route entry found\n"
872			printf "Expected:\n"
873			printf "    ${expected}\n"
874		fi
875		return 1
876	fi
877
878	# tricky way to convert output to 1-line without ip's
879	# messy '\'; this drops all extra white space
880	out=$(echo ${out})
881	if [ "${out}" != "${expected}" ]; then
882		rc=1
883		if [ "${VERBOSE}" = "1" ]; then
884			printf "    Unexpected route entry. Have:\n"
885			printf "        ${out}\n"
886			printf "    Expected:\n"
887			printf "        ${expected}\n\n"
888		fi
889	fi
890
891	return $rc
892}
893
894# add route for a prefix, flushing any existing routes first
895# expected to be the first step of a test
896add_route6()
897{
898	local pfx="$1"
899	local nh="$2"
900	local out
901
902	if [ "$VERBOSE" = "1" ]; then
903		echo
904		echo "    ##################################################"
905		echo
906	fi
907
908	run_cmd "$IP -6 ro flush ${pfx}"
909	[ $? -ne 0 ] && exit 1
910
911	out=$($IP -6 ro ls match ${pfx})
912	if [ -n "$out" ]; then
913		echo "Failed to flush routes for prefix used for tests."
914		exit 1
915	fi
916
917	run_cmd "$IP -6 ro add ${pfx} ${nh}"
918	if [ $? -ne 0 ]; then
919		echo "Failed to add initial route for test."
920		exit 1
921	fi
922}
923
924# add initial route - used in replace route tests
925add_initial_route6()
926{
927	add_route6 "2001:db8:104::/64" "$1"
928}
929
930check_route6()
931{
932	local pfx
933	local expected="$1"
934	local out
935	local rc=0
936
937	set -- $expected
938	pfx=$1
939
940	out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
941	check_expected "${out}" "${expected}"
942}
943
944route_cleanup()
945{
946	$IP li del red 2>/dev/null
947	$IP li del dummy1 2>/dev/null
948	$IP li del veth1 2>/dev/null
949	$IP li del veth3 2>/dev/null
950
951	cleanup &> /dev/null
952}
953
954route_setup()
955{
956	route_cleanup
957	setup
958
959	[ "${VERBOSE}" = "1" ] && set -x
960	set -e
961
962	ip netns add ns2
963	ip netns set ns2 auto
964	ip -netns ns2 link set dev lo up
965	ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
966	ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
967
968	$IP li add veth1 type veth peer name veth2
969	$IP li add veth3 type veth peer name veth4
970
971	$IP li set veth1 up
972	$IP li set veth3 up
973	$IP li set veth2 netns ns2 up
974	$IP li set veth4 netns ns2 up
975	ip -netns ns2 li add dummy1 type dummy
976	ip -netns ns2 li set dummy1 up
977
978	$IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
979	$IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
980	$IP addr add 172.16.101.1/24 dev veth1
981	$IP addr add 172.16.103.1/24 dev veth3
982
983	ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
984	ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
985	ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
986
987	ip -netns ns2 addr add 172.16.101.2/24 dev veth2
988	ip -netns ns2 addr add 172.16.103.2/24 dev veth4
989	ip -netns ns2 addr add 172.16.104.1/24 dev dummy1
990
991	set +e
992}
993
994# assumption is that basic add of a single path route works
995# otherwise just adding an address on an interface is broken
996ipv6_rt_add()
997{
998	local rc
999
1000	echo
1001	echo "IPv6 route add / append tests"
1002
1003	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1004	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1005	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
1006	log_test $? 2 "Attempt to add duplicate route - gw"
1007
1008	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1009	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1010	run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
1011	log_test $? 2 "Attempt to add duplicate route - dev only"
1012
1013	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1014	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1015	run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
1016	log_test $? 2 "Attempt to add duplicate route - reject route"
1017
1018	# route append with same prefix adds a new route
1019	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1020	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1021	run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
1022	check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1023	log_test $? 0 "Append nexthop to existing route - gw"
1024
1025	# insert mpath directly
1026	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1027	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1028	log_test $? 0 "Add multipath route"
1029
1030	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1031	run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1032	log_test $? 2 "Attempt to add duplicate multipath route"
1033
1034	# insert of a second route without append but different metric
1035	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
1036	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
1037	rc=$?
1038	if [ $rc -eq 0 ]; then
1039		run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
1040		rc=$?
1041	fi
1042	log_test $rc 0 "Route add with different metrics"
1043
1044	run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
1045	rc=$?
1046	if [ $rc -eq 0 ]; then
1047		check_route6 "2001:db8:104::/64 via 2001:db8:103::3 dev veth3 metric 256 2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
1048		rc=$?
1049	fi
1050	log_test $rc 0 "Route delete with metric"
1051}
1052
1053ipv6_rt_replace_single()
1054{
1055	# single path with single path
1056	#
1057	add_initial_route6 "via 2001:db8:101::2"
1058	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
1059	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
1060	log_test $? 0 "Single path with single path"
1061
1062	# single path with multipath
1063	#
1064	add_initial_route6 "nexthop via 2001:db8:101::2"
1065	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
1066	check_route6 "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::3 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1067	log_test $? 0 "Single path with multipath"
1068
1069	# single path with single path using MULTIPATH attribute
1070	#
1071	add_initial_route6 "via 2001:db8:101::2"
1072	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
1073	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
1074	log_test $? 0 "Single path with single path via multipath attribute"
1075
1076	# route replace fails - invalid nexthop
1077	add_initial_route6 "via 2001:db8:101::2"
1078	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
1079	if [ $? -eq 0 ]; then
1080		# previous command is expected to fail so if it returns 0
1081		# that means the test failed.
1082		log_test 0 1 "Invalid nexthop"
1083	else
1084		check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
1085		log_test $? 0 "Invalid nexthop"
1086	fi
1087
1088	# replace non-existent route
1089	# - note use of change versus replace since ip adds NLM_F_CREATE
1090	#   for replace
1091	add_initial_route6 "via 2001:db8:101::2"
1092	run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
1093	log_test $? 2 "Single path - replace of non-existent route"
1094}
1095
1096ipv6_rt_replace_mpath()
1097{
1098	# multipath with multipath
1099	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1100	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
1101	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::3 dev veth1 weight 1 nexthop via 2001:db8:103::3 dev veth3 weight 1"
1102	log_test $? 0 "Multipath with multipath"
1103
1104	# multipath with single
1105	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1106	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
1107	check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
1108	log_test $? 0 "Multipath with single path"
1109
1110	# multipath with single
1111	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1112	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
1113	check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
1114	log_test $? 0 "Multipath with single path via multipath attribute"
1115
1116	# multipath with dev-only
1117	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1118	run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1"
1119	check_route6 "2001:db8:104::/64 dev veth1 metric 1024"
1120	log_test $? 0 "Multipath with dev-only"
1121
1122	# route replace fails - invalid nexthop 1
1123	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1124	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
1125	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1126	log_test $? 0 "Multipath - invalid first nexthop"
1127
1128	# route replace fails - invalid nexthop 2
1129	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1130	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
1131	check_route6  "2001:db8:104::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1132	log_test $? 0 "Multipath - invalid second nexthop"
1133
1134	# multipath non-existent route
1135	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1136	run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
1137	log_test $? 2 "Multipath - replace of non-existent route"
1138}
1139
1140ipv6_rt_replace()
1141{
1142	echo
1143	echo "IPv6 route replace tests"
1144
1145	ipv6_rt_replace_single
1146	ipv6_rt_replace_mpath
1147}
1148
1149ipv6_rt_dsfield()
1150{
1151	echo
1152	echo "IPv6 route with dsfield tests"
1153
1154	run_cmd "$IP -6 route flush 2001:db8:102::/64"
1155
1156	# IPv6 doesn't support routing based on dsfield
1157	run_cmd "$IP -6 route add 2001:db8:102::/64 dsfield 0x04 via 2001:db8:101::2"
1158	log_test $? 2 "Reject route with dsfield"
1159}
1160
1161ipv6_route_test()
1162{
1163	route_setup
1164
1165	ipv6_rt_add
1166	ipv6_rt_replace
1167	ipv6_rt_dsfield
1168
1169	route_cleanup
1170}
1171
1172ip_addr_metric_check()
1173{
1174	ip addr help 2>&1 | grep -q metric
1175	if [ $? -ne 0 ]; then
1176		echo "iproute2 command does not support metric for addresses. Skipping test"
1177		return 1
1178	fi
1179
1180	return 0
1181}
1182
1183ipv6_addr_metric_test()
1184{
1185	local rc
1186
1187	echo
1188	echo "IPv6 prefix route tests"
1189
1190	ip_addr_metric_check || return 1
1191
1192	setup
1193
1194	set -e
1195	$IP li add dummy1 type dummy
1196	$IP li add dummy2 type dummy
1197	$IP li set dummy1 up
1198	$IP li set dummy2 up
1199
1200	# default entry is metric 256
1201	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
1202	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
1203	set +e
1204
1205	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
1206	log_test $? 0 "Default metric"
1207
1208	set -e
1209	run_cmd "$IP -6 addr flush dev dummy1"
1210	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
1211	set +e
1212
1213	check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
1214	log_test $? 0 "User specified metric on first device"
1215
1216	set -e
1217	run_cmd "$IP -6 addr flush dev dummy2"
1218	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
1219	set +e
1220
1221	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1222	log_test $? 0 "User specified metric on second device"
1223
1224	run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
1225	rc=$?
1226	if [ $rc -eq 0 ]; then
1227		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1228		rc=$?
1229	fi
1230	log_test $rc 0 "Delete of address on first device"
1231
1232	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
1233	rc=$?
1234	if [ $rc -eq 0 ]; then
1235		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1236		rc=$?
1237	fi
1238	log_test $rc 0 "Modify metric of address"
1239
1240	# verify prefix route removed on down
1241	run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
1242	run_cmd "$IP li set dev dummy2 down"
1243	rc=$?
1244	if [ $rc -eq 0 ]; then
1245		out=$($IP -6 ro ls match 2001:db8:104::/64)
1246		check_expected "${out}" ""
1247		rc=$?
1248	fi
1249	log_test $rc 0 "Prefix route removed on link down"
1250
1251	# verify prefix route re-inserted with assigned metric
1252	run_cmd "$IP li set dev dummy2 up"
1253	rc=$?
1254	if [ $rc -eq 0 ]; then
1255		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1256		rc=$?
1257	fi
1258	log_test $rc 0 "Prefix route with metric on link up"
1259
1260	# verify peer metric added correctly
1261	set -e
1262	run_cmd "$IP -6 addr flush dev dummy2"
1263	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
1264	set +e
1265
1266	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
1267	log_test $? 0 "Set metric with peer route on local side"
1268	check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
1269	log_test $? 0 "Set metric with peer route on peer side"
1270
1271	set -e
1272	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
1273	set +e
1274
1275	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
1276	log_test $? 0 "Modify metric and peer address on local side"
1277	check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
1278	log_test $? 0 "Modify metric and peer address on peer side"
1279
1280	$IP li del dummy1
1281	$IP li del dummy2
1282	cleanup
1283}
1284
1285ipv6_route_metrics_test()
1286{
1287	local rc
1288
1289	echo
1290	echo "IPv6 routes with metrics"
1291
1292	route_setup
1293
1294	#
1295	# single path with metrics
1296	#
1297	run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
1298	rc=$?
1299	if [ $rc -eq 0 ]; then
1300		check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
1301		rc=$?
1302	fi
1303	log_test $rc 0 "Single path route with mtu metric"
1304
1305
1306	#
1307	# multipath via separate routes with metrics
1308	#
1309	run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
1310	run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
1311	rc=$?
1312	if [ $rc -eq 0 ]; then
1313		check_route6 "2001:db8:112::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1314		rc=$?
1315	fi
1316	log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
1317
1318	# second route is coalesced to first to make a multipath route.
1319	# MTU of the second path is hidden from display!
1320	run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
1321	run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
1322	rc=$?
1323	if [ $rc -eq 0 ]; then
1324		check_route6 "2001:db8:113::/64 metric 1024 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1325		rc=$?
1326	fi
1327	log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
1328
1329	run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
1330	if [ $? -eq 0 ]; then
1331		check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
1332		log_test $? 0 "    MTU of second leg"
1333	fi
1334
1335	#
1336	# multipath with metrics
1337	#
1338	run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1339	rc=$?
1340	if [ $rc -eq 0 ]; then
1341		check_route6  "2001:db8:115::/64 metric 1024 mtu 1400 nexthop via 2001:db8:101::2 dev veth1 weight 1 nexthop via 2001:db8:103::2 dev veth3 weight 1"
1342		rc=$?
1343	fi
1344	log_test $rc 0 "Multipath route with mtu metric"
1345
1346	$IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
1347	run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
1348	log_test $? 0 "Using route with mtu metric"
1349
1350	run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
1351	log_test $? 2 "Invalid metric (fails metric_convert)"
1352
1353	route_cleanup
1354}
1355
1356# add route for a prefix, flushing any existing routes first
1357# expected to be the first step of a test
1358add_route()
1359{
1360	local pfx="$1"
1361	local nh="$2"
1362	local out
1363
1364	if [ "$VERBOSE" = "1" ]; then
1365		echo
1366		echo "    ##################################################"
1367		echo
1368	fi
1369
1370	run_cmd "$IP ro flush ${pfx}"
1371	[ $? -ne 0 ] && exit 1
1372
1373	out=$($IP ro ls match ${pfx})
1374	if [ -n "$out" ]; then
1375		echo "Failed to flush routes for prefix used for tests."
1376		exit 1
1377	fi
1378
1379	run_cmd "$IP ro add ${pfx} ${nh}"
1380	if [ $? -ne 0 ]; then
1381		echo "Failed to add initial route for test."
1382		exit 1
1383	fi
1384}
1385
1386# add initial route - used in replace route tests
1387add_initial_route()
1388{
1389	add_route "172.16.104.0/24" "$1"
1390}
1391
1392check_route()
1393{
1394	local pfx
1395	local expected="$1"
1396	local out
1397
1398	set -- $expected
1399	pfx=$1
1400	[ "${pfx}" = "unreachable" ] && pfx=$2
1401
1402	out=$($IP ro ls match ${pfx})
1403	check_expected "${out}" "${expected}"
1404}
1405
1406# assumption is that basic add of a single path route works
1407# otherwise just adding an address on an interface is broken
1408ipv4_rt_add()
1409{
1410	local rc
1411
1412	echo
1413	echo "IPv4 route add / append tests"
1414
1415	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1416	add_route "172.16.104.0/24" "via 172.16.101.2"
1417	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1418	log_test $? 2 "Attempt to add duplicate route - gw"
1419
1420	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1421	add_route "172.16.104.0/24" "via 172.16.101.2"
1422	run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1423	log_test $? 2 "Attempt to add duplicate route - dev only"
1424
1425	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1426	add_route "172.16.104.0/24" "via 172.16.101.2"
1427	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1428	log_test $? 2 "Attempt to add duplicate route - reject route"
1429
1430	# iproute2 prepend only sets NLM_F_CREATE
1431	# - adds a new route; does NOT convert existing route to ECMP
1432	add_route "172.16.104.0/24" "via 172.16.101.2"
1433	run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1434	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3 172.16.104.0/24 via 172.16.101.2 dev veth1"
1435	log_test $? 0 "Add new nexthop for existing prefix"
1436
1437	# route append with same prefix adds a new route
1438	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1439	add_route "172.16.104.0/24" "via 172.16.101.2"
1440	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1441	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.2 dev veth3"
1442	log_test $? 0 "Append nexthop to existing route - gw"
1443
1444	add_route "172.16.104.0/24" "via 172.16.101.2"
1445	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1446	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1447	log_test $? 0 "Append nexthop to existing route - dev only"
1448
1449	add_route "172.16.104.0/24" "via 172.16.101.2"
1450	run_cmd "$IP ro append unreachable 172.16.104.0/24"
1451	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1452	log_test $? 0 "Append nexthop to existing route - reject route"
1453
1454	run_cmd "$IP ro flush 172.16.104.0/24"
1455	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1456	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1457	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1458	log_test $? 0 "Append nexthop to existing reject route - gw"
1459
1460	run_cmd "$IP ro flush 172.16.104.0/24"
1461	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1462	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1463	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1464	log_test $? 0 "Append nexthop to existing reject route - dev only"
1465
1466	# insert mpath directly
1467	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1468	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1469	log_test $? 0 "add multipath route"
1470
1471	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1472	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1473	log_test $? 2 "Attempt to add duplicate multipath route"
1474
1475	# insert of a second route without append but different metric
1476	add_route "172.16.104.0/24" "via 172.16.101.2"
1477	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1478	rc=$?
1479	if [ $rc -eq 0 ]; then
1480		run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1481		rc=$?
1482	fi
1483	log_test $rc 0 "Route add with different metrics"
1484
1485	run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1486	rc=$?
1487	if [ $rc -eq 0 ]; then
1488		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 via 172.16.103.3 dev veth3 metric 256"
1489		rc=$?
1490	fi
1491	log_test $rc 0 "Route delete with metric"
1492}
1493
1494ipv4_rt_replace_single()
1495{
1496	# single path with single path
1497	#
1498	add_initial_route "via 172.16.101.2"
1499	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1500	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1501	log_test $? 0 "Single path with single path"
1502
1503	# single path with multipath
1504	#
1505	add_initial_route "nexthop via 172.16.101.2"
1506	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1507	check_route "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1508	log_test $? 0 "Single path with multipath"
1509
1510	# single path with reject
1511	#
1512	add_initial_route "nexthop via 172.16.101.2"
1513	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1514	check_route "unreachable 172.16.104.0/24"
1515	log_test $? 0 "Single path with reject route"
1516
1517	# single path with single path using MULTIPATH attribute
1518	#
1519	add_initial_route "via 172.16.101.2"
1520	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1521	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1522	log_test $? 0 "Single path with single path via multipath attribute"
1523
1524	# route replace fails - invalid nexthop
1525	add_initial_route "via 172.16.101.2"
1526	run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1527	if [ $? -eq 0 ]; then
1528		# previous command is expected to fail so if it returns 0
1529		# that means the test failed.
1530		log_test 0 1 "Invalid nexthop"
1531	else
1532		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1533		log_test $? 0 "Invalid nexthop"
1534	fi
1535
1536	# replace non-existent route
1537	# - note use of change versus replace since ip adds NLM_F_CREATE
1538	#   for replace
1539	add_initial_route "via 172.16.101.2"
1540	run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1541	log_test $? 2 "Single path - replace of non-existent route"
1542}
1543
1544ipv4_rt_replace_mpath()
1545{
1546	# multipath with multipath
1547	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1548	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1549	check_route  "172.16.104.0/24 nexthop via 172.16.101.3 dev veth1 weight 1 nexthop via 172.16.103.3 dev veth3 weight 1"
1550	log_test $? 0 "Multipath with multipath"
1551
1552	# multipath with single
1553	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1554	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1555	check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1556	log_test $? 0 "Multipath with single path"
1557
1558	# multipath with single
1559	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1560	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1561	check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1562	log_test $? 0 "Multipath with single path via multipath attribute"
1563
1564	# multipath with reject
1565	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1566	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1567	check_route "unreachable 172.16.104.0/24"
1568	log_test $? 0 "Multipath with reject route"
1569
1570	# route replace fails - invalid nexthop 1
1571	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1572	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
1573	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1574	log_test $? 0 "Multipath - invalid first nexthop"
1575
1576	# route replace fails - invalid nexthop 2
1577	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1578	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1579	check_route  "172.16.104.0/24 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1580	log_test $? 0 "Multipath - invalid second nexthop"
1581
1582	# multipath non-existent route
1583	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1584	run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1585	log_test $? 2 "Multipath - replace of non-existent route"
1586}
1587
1588ipv4_rt_replace()
1589{
1590	echo
1591	echo "IPv4 route replace tests"
1592
1593	ipv4_rt_replace_single
1594	ipv4_rt_replace_mpath
1595}
1596
1597# checks that cached input route on VRF port is deleted
1598# when VRF is deleted
1599ipv4_local_rt_cache()
1600{
1601	run_cmd "ip addr add 10.0.0.1/32 dev lo"
1602	run_cmd "ip netns add test-ns"
1603	run_cmd "ip link add veth-outside type veth peer name veth-inside"
1604	run_cmd "ip link add vrf-100 type vrf table 1100"
1605	run_cmd "ip link set veth-outside master vrf-100"
1606	run_cmd "ip link set veth-inside netns test-ns"
1607	run_cmd "ip link set veth-outside up"
1608	run_cmd "ip link set vrf-100 up"
1609	run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
1610	run_cmd "ip netns exec test-ns ip link set veth-inside up"
1611	run_cmd "ip netns exec test-ns ip addr add 10.1.1.1/32 dev veth-inside"
1612	run_cmd "ip netns exec test-ns ip route add 10.0.0.1/32 dev veth-inside"
1613	run_cmd "ip netns exec test-ns ip route add default via 10.0.0.1"
1614	run_cmd "ip netns exec test-ns ping 10.0.0.1 -c 1 -i 1"
1615	run_cmd "ip link delete vrf-100"
1616
1617	# if we do not hang test is a success
1618	log_test $? 0 "Cached route removed from VRF port device"
1619}
1620
1621ipv4_rt_dsfield()
1622{
1623	echo
1624	echo "IPv4 route with dsfield tests"
1625
1626	run_cmd "$IP route flush 172.16.102.0/24"
1627
1628	# New routes should reject dsfield options that interfere with ECN
1629	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x01 via 172.16.101.2"
1630	log_test $? 2 "Reject route with dsfield 0x01"
1631
1632	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x02 via 172.16.101.2"
1633	log_test $? 2 "Reject route with dsfield 0x02"
1634
1635	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x03 via 172.16.101.2"
1636	log_test $? 2 "Reject route with dsfield 0x03"
1637
1638	# A generic route that doesn't take DSCP into account
1639	run_cmd "$IP route add 172.16.102.0/24 via 172.16.101.2"
1640
1641	# A more specific route for DSCP 0x10
1642	run_cmd "$IP route add 172.16.102.0/24 dsfield 0x10 via 172.16.103.2"
1643
1644	# DSCP 0x10 should match the specific route, no matter the ECN bits
1645	$IP route get fibmatch 172.16.102.1 dsfield 0x10 | \
1646		grep -q "via 172.16.103.2"
1647	log_test $? 0 "IPv4 route with DSCP and ECN:Not-ECT"
1648
1649	$IP route get fibmatch 172.16.102.1 dsfield 0x11 | \
1650		grep -q "via 172.16.103.2"
1651	log_test $? 0 "IPv4 route with DSCP and ECN:ECT(1)"
1652
1653	$IP route get fibmatch 172.16.102.1 dsfield 0x12 | \
1654		grep -q "via 172.16.103.2"
1655	log_test $? 0 "IPv4 route with DSCP and ECN:ECT(0)"
1656
1657	$IP route get fibmatch 172.16.102.1 dsfield 0x13 | \
1658		grep -q "via 172.16.103.2"
1659	log_test $? 0 "IPv4 route with DSCP and ECN:CE"
1660
1661	# Unknown DSCP should match the generic route, no matter the ECN bits
1662	$IP route get fibmatch 172.16.102.1 dsfield 0x14 | \
1663		grep -q "via 172.16.101.2"
1664	log_test $? 0 "IPv4 route with unknown DSCP and ECN:Not-ECT"
1665
1666	$IP route get fibmatch 172.16.102.1 dsfield 0x15 | \
1667		grep -q "via 172.16.101.2"
1668	log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(1)"
1669
1670	$IP route get fibmatch 172.16.102.1 dsfield 0x16 | \
1671		grep -q "via 172.16.101.2"
1672	log_test $? 0 "IPv4 route with unknown DSCP and ECN:ECT(0)"
1673
1674	$IP route get fibmatch 172.16.102.1 dsfield 0x17 | \
1675		grep -q "via 172.16.101.2"
1676	log_test $? 0 "IPv4 route with unknown DSCP and ECN:CE"
1677
1678	# Null DSCP should match the generic route, no matter the ECN bits
1679	$IP route get fibmatch 172.16.102.1 dsfield 0x00 | \
1680		grep -q "via 172.16.101.2"
1681	log_test $? 0 "IPv4 route with no DSCP and ECN:Not-ECT"
1682
1683	$IP route get fibmatch 172.16.102.1 dsfield 0x01 | \
1684		grep -q "via 172.16.101.2"
1685	log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(1)"
1686
1687	$IP route get fibmatch 172.16.102.1 dsfield 0x02 | \
1688		grep -q "via 172.16.101.2"
1689	log_test $? 0 "IPv4 route with no DSCP and ECN:ECT(0)"
1690
1691	$IP route get fibmatch 172.16.102.1 dsfield 0x03 | \
1692		grep -q "via 172.16.101.2"
1693	log_test $? 0 "IPv4 route with no DSCP and ECN:CE"
1694}
1695
1696ipv4_route_test()
1697{
1698	route_setup
1699
1700	ipv4_rt_add
1701	ipv4_rt_replace
1702	ipv4_local_rt_cache
1703	ipv4_rt_dsfield
1704
1705	route_cleanup
1706}
1707
1708ipv4_addr_metric_test()
1709{
1710	local rc
1711
1712	echo
1713	echo "IPv4 prefix route tests"
1714
1715	ip_addr_metric_check || return 1
1716
1717	setup
1718
1719	set -e
1720	$IP li add dummy1 type dummy
1721	$IP li add dummy2 type dummy
1722	$IP li set dummy1 up
1723	$IP li set dummy2 up
1724
1725	# default entry is metric 256
1726	run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1727	run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1728	set +e
1729
1730	check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2"
1731	log_test $? 0 "Default metric"
1732
1733	set -e
1734	run_cmd "$IP addr flush dev dummy1"
1735	run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1736	set +e
1737
1738	check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257"
1739	log_test $? 0 "User specified metric on first device"
1740
1741	set -e
1742	run_cmd "$IP addr flush dev dummy2"
1743	run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1744	set +e
1745
1746	check_route "172.16.104.0/24 dev dummy1 proto kernel scope link src 172.16.104.1 metric 257 172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1747	log_test $? 0 "User specified metric on second device"
1748
1749	run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1750	rc=$?
1751	if [ $rc -eq 0 ]; then
1752		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1753		rc=$?
1754	fi
1755	log_test $rc 0 "Delete of address on first device"
1756
1757	run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1758	rc=$?
1759	if [ $rc -eq 0 ]; then
1760		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1761		rc=$?
1762	fi
1763	log_test $rc 0 "Modify metric of address"
1764
1765	# verify prefix route removed on down
1766	run_cmd "$IP li set dev dummy2 down"
1767	rc=$?
1768	if [ $rc -eq 0 ]; then
1769		out=$($IP ro ls match 172.16.104.0/24)
1770		check_expected "${out}" ""
1771		rc=$?
1772	fi
1773	log_test $rc 0 "Prefix route removed on link down"
1774
1775	# verify prefix route re-inserted with assigned metric
1776	run_cmd "$IP li set dev dummy2 up"
1777	rc=$?
1778	if [ $rc -eq 0 ]; then
1779		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1780		rc=$?
1781	fi
1782	log_test $rc 0 "Prefix route with metric on link up"
1783
1784	# explicitly check for metric changes on edge scenarios
1785	run_cmd "$IP addr flush dev dummy2"
1786	run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
1787	run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
1788	rc=$?
1789	if [ $rc -eq 0 ]; then
1790		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
1791		rc=$?
1792	fi
1793	log_test $rc 0 "Modify metric of .0/24 address"
1794
1795	run_cmd "$IP addr flush dev dummy2"
1796	run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
1797	rc=$?
1798	if [ $rc -eq 0 ]; then
1799		check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
1800		rc=$?
1801	fi
1802	log_test $rc 0 "Set metric of address with peer route"
1803
1804	run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
1805	rc=$?
1806	if [ $rc -eq 0 ]; then
1807		check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
1808		rc=$?
1809	fi
1810	log_test $rc 0 "Modify metric and peer address for peer route"
1811
1812	$IP li del dummy1
1813	$IP li del dummy2
1814	cleanup
1815}
1816
1817ipv4_route_metrics_test()
1818{
1819	local rc
1820
1821	echo
1822	echo "IPv4 route add / append tests"
1823
1824	route_setup
1825
1826	run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
1827	rc=$?
1828	if [ $rc -eq 0 ]; then
1829		check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
1830		rc=$?
1831	fi
1832	log_test $rc 0 "Single path route with mtu metric"
1833
1834
1835	run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1836	rc=$?
1837	if [ $rc -eq 0 ]; then
1838		check_route "172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
1839		rc=$?
1840	fi
1841	log_test $rc 0 "Multipath route with mtu metric"
1842
1843	$IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
1844	run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
1845	log_test $? 0 "Using route with mtu metric"
1846
1847	run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
1848	log_test $? 2 "Invalid metric (fails metric_convert)"
1849
1850	route_cleanup
1851}
1852
1853ipv4_del_addr_test()
1854{
1855	echo
1856	echo "IPv4 delete address route tests"
1857
1858	setup
1859
1860	set -e
1861	$IP li add dummy1 type dummy
1862	$IP li set dummy1 up
1863	$IP li add dummy2 type dummy
1864	$IP li set dummy2 up
1865	$IP li add red type vrf table 1111
1866	$IP li set red up
1867	$IP ro add vrf red unreachable default
1868	$IP li set dummy2 vrf red
1869
1870	$IP addr add dev dummy1 172.16.104.1/24
1871	$IP addr add dev dummy1 172.16.104.11/24
1872	$IP addr add dev dummy1 172.16.104.12/24
1873	$IP addr add dev dummy1 172.16.104.13/24
1874	$IP addr add dev dummy2 172.16.104.1/24
1875	$IP addr add dev dummy2 172.16.104.11/24
1876	$IP addr add dev dummy2 172.16.104.12/24
1877	$IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1878	$IP route add 172.16.106.0/24 dev lo src 172.16.104.12
1879	$IP route add table 0 172.16.107.0/24 via 172.16.104.2 src 172.16.104.13
1880	$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1881	$IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
1882	set +e
1883
1884	# removing address from device in vrf should only remove route from vrf table
1885	echo "    Regular FIB info"
1886
1887	$IP addr del dev dummy2 172.16.104.11/24
1888	$IP ro ls vrf red | grep -q 172.16.105.0/24
1889	log_test $? 1 "Route removed from VRF when source address deleted"
1890
1891	$IP ro ls | grep -q 172.16.105.0/24
1892	log_test $? 0 "Route in default VRF not removed"
1893
1894	$IP addr add dev dummy2 172.16.104.11/24
1895	$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1896
1897	$IP addr del dev dummy1 172.16.104.11/24
1898	$IP ro ls | grep -q 172.16.105.0/24
1899	log_test $? 1 "Route removed in default VRF when source address deleted"
1900
1901	$IP ro ls vrf red | grep -q 172.16.105.0/24
1902	log_test $? 0 "Route in VRF is not removed by address delete"
1903
1904	# removing address from device in vrf should only remove route from vrf
1905	# table even when the associated fib info only differs in table ID
1906	echo "    Identical FIB info with different table ID"
1907
1908	$IP addr del dev dummy2 172.16.104.12/24
1909	$IP ro ls vrf red | grep -q 172.16.106.0/24
1910	log_test $? 1 "Route removed from VRF when source address deleted"
1911
1912	$IP ro ls | grep -q 172.16.106.0/24
1913	log_test $? 0 "Route in default VRF not removed"
1914
1915	$IP addr add dev dummy2 172.16.104.12/24
1916	$IP route add vrf red 172.16.106.0/24 dev lo src 172.16.104.12
1917
1918	$IP addr del dev dummy1 172.16.104.12/24
1919	$IP ro ls | grep -q 172.16.106.0/24
1920	log_test $? 1 "Route removed in default VRF when source address deleted"
1921
1922	$IP ro ls vrf red | grep -q 172.16.106.0/24
1923	log_test $? 0 "Route in VRF is not removed by address delete"
1924
1925	# removing address from device in default vrf should remove route from
1926	# the default vrf even when route was inserted with a table ID of 0.
1927	echo "    Table ID 0"
1928
1929	$IP addr del dev dummy1 172.16.104.13/24
1930	$IP ro ls | grep -q 172.16.107.0/24
1931	log_test $? 1 "Route removed in default VRF when source address deleted"
1932
1933	$IP li del dummy1
1934	$IP li del dummy2
1935	cleanup
1936}
1937
1938ipv6_del_addr_test()
1939{
1940	echo
1941	echo "IPv6 delete address route tests"
1942
1943	setup
1944
1945	set -e
1946	for i in $(seq 6); do
1947		$IP li add dummy${i} up type dummy
1948	done
1949
1950	$IP li add red up type vrf table 1111
1951	$IP ro add vrf red unreachable default
1952	for i in $(seq 4 6); do
1953		$IP li set dummy${i} vrf red
1954	done
1955
1956	$IP addr add dev dummy1 fe80::1/128
1957	$IP addr add dev dummy1 2001:db8:101::1/64
1958	$IP addr add dev dummy1 2001:db8:101::10/64
1959	$IP addr add dev dummy1 2001:db8:101::11/64
1960	$IP addr add dev dummy1 2001:db8:101::12/64
1961	$IP addr add dev dummy1 2001:db8:101::13/64
1962	$IP addr add dev dummy1 2001:db8:101::14/64
1963	$IP addr add dev dummy1 2001:db8:101::15/64
1964	$IP addr add dev dummy2 fe80::1/128
1965	$IP addr add dev dummy2 2001:db8:101::1/64
1966	$IP addr add dev dummy2 2001:db8:101::11/64
1967	$IP addr add dev dummy3 fe80::1/128
1968
1969	$IP addr add dev dummy4 2001:db8:101::1/64
1970	$IP addr add dev dummy4 2001:db8:101::10/64
1971	$IP addr add dev dummy4 2001:db8:101::11/64
1972	$IP addr add dev dummy4 2001:db8:101::12/64
1973	$IP addr add dev dummy4 2001:db8:101::13/64
1974	$IP addr add dev dummy4 2001:db8:101::14/64
1975	$IP addr add dev dummy5 2001:db8:101::1/64
1976	$IP addr add dev dummy5 2001:db8:101::11/64
1977
1978	# Single device using src address
1979	$IP route add 2001:db8:110::/64 dev dummy3 src 2001:db8:101::10
1980	# Two devices with the same source address
1981	$IP route add 2001:db8:111::/64 dev dummy3 src 2001:db8:101::11
1982	# VRF with single device using src address
1983	$IP route add vrf red 2001:db8:110::/64 dev dummy6 src 2001:db8:101::10
1984	# VRF with two devices using src address
1985	$IP route add vrf red 2001:db8:111::/64 dev dummy6 src 2001:db8:101::11
1986	# src address and nexthop dev in same VRF
1987	$IP route add 2001:db8:112::/64 dev dummy3 src 2001:db8:101::12
1988	$IP route add vrf red 2001:db8:112::/64 dev dummy6 src 2001:db8:101::12
1989	# src address and nexthop device in different VRF
1990	$IP route add 2001:db8:113::/64 dev lo src 2001:db8:101::13
1991	$IP route add vrf red 2001:db8:113::/64 dev lo src 2001:db8:101::13
1992	# table ID 0
1993	$IP route add table 0 2001:db8:115::/64 via 2001:db8:101::2 src 2001:db8:101::15
1994	# Link local source route
1995	$IP route add 2001:db8:116::/64 dev dummy2 src fe80::1
1996	$IP route add 2001:db8:117::/64 dev dummy3 src fe80::1
1997	set +e
1998
1999	echo "    Single device using src address"
2000
2001	$IP addr del dev dummy1 2001:db8:101::10/64
2002	$IP -6 route show | grep -q "src 2001:db8:101::10 "
2003	log_test $? 1 "Prefsrc removed when src address removed on other device"
2004
2005	echo "    Two devices with the same source address"
2006
2007	$IP addr del dev dummy1 2001:db8:101::11/64
2008	$IP -6 route show | grep -q "src 2001:db8:101::11 "
2009	log_test $? 0 "Prefsrc not removed when src address exist on other device"
2010
2011	$IP addr del dev dummy2 2001:db8:101::11/64
2012	$IP -6 route show | grep -q "src 2001:db8:101::11 "
2013	log_test $? 1 "Prefsrc removed when src address removed on all devices"
2014
2015	echo "    VRF with single device using src address"
2016
2017	$IP addr del dev dummy4 2001:db8:101::10/64
2018	$IP -6 route show vrf red | grep -q "src 2001:db8:101::10 "
2019	log_test $? 1 "Prefsrc removed when src address removed on other device"
2020
2021	echo "    VRF with two devices using src address"
2022
2023	$IP addr del dev dummy4 2001:db8:101::11/64
2024	$IP -6 route show vrf red | grep -q "src 2001:db8:101::11 "
2025	log_test $? 0 "Prefsrc not removed when src address exist on other device"
2026
2027	$IP addr del dev dummy5 2001:db8:101::11/64
2028	$IP -6 route show vrf red | grep -q "src 2001:db8:101::11 "
2029	log_test $? 1 "Prefsrc removed when src address removed on all devices"
2030
2031	echo "    src address and nexthop dev in same VRF"
2032
2033	$IP addr del dev dummy4 2001:db8:101::12/64
2034	$IP -6 route show vrf red | grep -q "src 2001:db8:101::12 "
2035	log_test $? 1 "Prefsrc removed from VRF when source address deleted"
2036	$IP -6 route show | grep -q " src 2001:db8:101::12 "
2037	log_test $? 0 "Prefsrc in default VRF not removed"
2038
2039	$IP addr add dev dummy4 2001:db8:101::12/64
2040	$IP route replace vrf red 2001:db8:112::/64 dev dummy6 src 2001:db8:101::12
2041	$IP addr del dev dummy1 2001:db8:101::12/64
2042	$IP -6 route show vrf red | grep -q "src 2001:db8:101::12 "
2043	log_test $? 0 "Prefsrc not removed from VRF when source address exist"
2044	$IP -6 route show | grep -q " src 2001:db8:101::12 "
2045	log_test $? 1 "Prefsrc in default VRF removed"
2046
2047	echo "    src address and nexthop device in different VRF"
2048
2049	$IP addr del dev dummy4 2001:db8:101::13/64
2050	$IP -6 route show vrf red | grep -q "src 2001:db8:101::13 "
2051	log_test $? 0 "Prefsrc not removed from VRF when nexthop dev in diff VRF"
2052	$IP -6 route show | grep -q "src 2001:db8:101::13 "
2053	log_test $? 0 "Prefsrc not removed in default VRF"
2054
2055	$IP addr add dev dummy4 2001:db8:101::13/64
2056	$IP addr del dev dummy1 2001:db8:101::13/64
2057	$IP -6 route show vrf red | grep -q "src 2001:db8:101::13 "
2058	log_test $? 1 "Prefsrc removed from VRF when nexthop dev in diff VRF"
2059	$IP -6 route show | grep -q "src 2001:db8:101::13 "
2060	log_test $? 1 "Prefsrc removed in default VRF"
2061
2062	echo "    Table ID 0"
2063
2064	$IP addr del dev dummy1 2001:db8:101::15/64
2065	$IP -6 route show | grep -q "src 2001:db8:101::15"
2066	log_test $? 1 "Prefsrc removed from default VRF when source address deleted"
2067
2068	echo "    Link local source route"
2069	$IP addr del dev dummy1 fe80::1/128
2070	$IP -6 route show | grep -q "2001:db8:116::/64 dev dummy2 src fe80::1"
2071	log_test $? 0 "Prefsrc not removed when delete ll addr from other dev"
2072	$IP addr del dev dummy2 fe80::1/128
2073	$IP -6 route show | grep -q "2001:db8:116::/64 dev dummy2 src fe80::1"
2074	log_test $? 1 "Prefsrc removed when delete ll addr"
2075	$IP -6 route show | grep -q "2001:db8:117::/64 dev dummy3 src fe80::1"
2076	log_test $? 0 "Prefsrc not removed when delete ll addr from other dev"
2077	$IP addr add dev dummy1 fe80::1/128
2078	$IP addr del dev dummy3 fe80::1/128
2079	$IP -6 route show | grep -q "2001:db8:117::/64 dev dummy3 src fe80::1"
2080	log_test $? 1 "Prefsrc removed even ll addr still exist on other dev"
2081
2082	for i in $(seq 6); do
2083		$IP li del dummy${i}
2084	done
2085	cleanup
2086}
2087
2088ipv4_route_v6_gw_test()
2089{
2090	local rc
2091
2092	echo
2093	echo "IPv4 route with IPv6 gateway tests"
2094
2095	route_setup
2096	sleep 2
2097
2098	#
2099	# single path route
2100	#
2101	run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
2102	rc=$?
2103	log_test $rc 0 "Single path route with IPv6 gateway"
2104	if [ $rc -eq 0 ]; then
2105		check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
2106	fi
2107
2108	run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
2109	log_test $rc 0 "Single path route with IPv6 gateway - ping"
2110
2111	run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
2112	rc=$?
2113	log_test $rc 0 "Single path route delete"
2114	if [ $rc -eq 0 ]; then
2115		check_route "172.16.112.0/24"
2116	fi
2117
2118	#
2119	# multipath - v6 then v4
2120	#
2121	run_cmd "$IP ro add 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
2122	rc=$?
2123	log_test $rc 0 "Multipath route add - v6 nexthop then v4"
2124	if [ $rc -eq 0 ]; then
2125		check_route "172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1 nexthop via 172.16.103.2 dev veth3 weight 1"
2126	fi
2127
2128	run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
2129	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
2130
2131	run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
2132	log_test $? 0 "    Multipath route delete exact match"
2133
2134	#
2135	# multipath - v4 then v6
2136	#
2137	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
2138	rc=$?
2139	log_test $rc 0 "Multipath route add - v4 nexthop then v6"
2140	if [ $rc -eq 0 ]; then
2141		check_route "172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 weight 1 nexthop via inet6 2001:db8:101::2 dev veth1 weight 1"
2142	fi
2143
2144	run_cmd "$IP ro del 172.16.104.0/24 nexthop via inet6 2001:db8:101::2 dev veth1 nexthop via 172.16.103.2 dev veth3"
2145	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
2146
2147	run_cmd "$IP ro del 172.16.104.0/24 nexthop via 172.16.103.2 dev veth3 nexthop via inet6 2001:db8:101::2 dev veth1"
2148	log_test $? 0 "    Multipath route delete exact match"
2149
2150	route_cleanup
2151}
2152
2153socat_check()
2154{
2155	if [ ! -x "$(command -v socat)" ]; then
2156		echo "socat command not found. Skipping test"
2157		return 1
2158	fi
2159
2160	return 0
2161}
2162
2163iptables_check()
2164{
2165	iptables -t mangle -L OUTPUT &> /dev/null
2166	if [ $? -ne 0 ]; then
2167		echo "iptables configuration not supported. Skipping test"
2168		return 1
2169	fi
2170
2171	return 0
2172}
2173
2174ip6tables_check()
2175{
2176	ip6tables -t mangle -L OUTPUT &> /dev/null
2177	if [ $? -ne 0 ]; then
2178		echo "ip6tables configuration not supported. Skipping test"
2179		return 1
2180	fi
2181
2182	return 0
2183}
2184
2185ipv4_mangle_test()
2186{
2187	local rc
2188
2189	echo
2190	echo "IPv4 mangling tests"
2191
2192	socat_check || return 1
2193	iptables_check || return 1
2194
2195	route_setup
2196	sleep 2
2197
2198	local tmp_file=$(mktemp)
2199	ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
2200
2201	# Add a FIB rule and a route that will direct our connection to the
2202	# listening server.
2203	$IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
2204	$IP route add table 123 172.16.101.0/24 dev veth1
2205
2206	# Add an unreachable route to the main table that will block our
2207	# connection in case the FIB rule is not hit.
2208	$IP route add unreachable 172.16.101.2/32
2209
2210	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
2211	log_test $? 0 "    Connection with correct parameters"
2212
2213	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=11111"
2214	log_test $? 1 "    Connection with incorrect parameters"
2215
2216	# Add a mangling rule and make sure connection is still successful.
2217	$NS_EXEC iptables -t mangle -A OUTPUT -j MARK --set-mark 1
2218
2219	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
2220	log_test $? 0 "    Connection with correct parameters - mangling"
2221
2222	# Delete the mangling rule and make sure connection is still
2223	# successful.
2224	$NS_EXEC iptables -t mangle -D OUTPUT -j MARK --set-mark 1
2225
2226	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
2227	log_test $? 0 "    Connection with correct parameters - no mangling"
2228
2229	# Verify connections were indeed successful on server side.
2230	[[ $(cat $tmp_file | wc -l) -eq 3 ]]
2231	log_test $? 0 "    Connection check - server side"
2232
2233	$IP route del unreachable 172.16.101.2/32
2234	$IP route del table 123 172.16.101.0/24 dev veth1
2235	$IP rule del pref 100
2236
2237	{ kill %% && wait %%; } 2>/dev/null
2238	rm $tmp_file
2239
2240	route_cleanup
2241}
2242
2243ipv6_mangle_test()
2244{
2245	local rc
2246
2247	echo
2248	echo "IPv6 mangling tests"
2249
2250	socat_check || return 1
2251	ip6tables_check || return 1
2252
2253	route_setup
2254	sleep 2
2255
2256	local tmp_file=$(mktemp)
2257	ip netns exec ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
2258
2259	# Add a FIB rule and a route that will direct our connection to the
2260	# listening server.
2261	$IP -6 rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
2262	$IP -6 route add table 123 2001:db8:101::/64 dev veth1
2263
2264	# Add an unreachable route to the main table that will block our
2265	# connection in case the FIB rule is not hit.
2266	$IP -6 route add unreachable 2001:db8:101::2/128
2267
2268	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
2269	log_test $? 0 "    Connection with correct parameters"
2270
2271	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=11111"
2272	log_test $? 1 "    Connection with incorrect parameters"
2273
2274	# Add a mangling rule and make sure connection is still successful.
2275	$NS_EXEC ip6tables -t mangle -A OUTPUT -j MARK --set-mark 1
2276
2277	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
2278	log_test $? 0 "    Connection with correct parameters - mangling"
2279
2280	# Delete the mangling rule and make sure connection is still
2281	# successful.
2282	$NS_EXEC ip6tables -t mangle -D OUTPUT -j MARK --set-mark 1
2283
2284	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
2285	log_test $? 0 "    Connection with correct parameters - no mangling"
2286
2287	# Verify connections were indeed successful on server side.
2288	[[ $(cat $tmp_file | wc -l) -eq 3 ]]
2289	log_test $? 0 "    Connection check - server side"
2290
2291	$IP -6 route del unreachable 2001:db8:101::2/128
2292	$IP -6 route del table 123 2001:db8:101::/64 dev veth1
2293	$IP -6 rule del pref 100
2294
2295	{ kill %% && wait %%; } 2>/dev/null
2296	rm $tmp_file
2297
2298	route_cleanup
2299}
2300
2301ip_neigh_get_check()
2302{
2303	ip neigh help 2>&1 | grep -q 'ip neigh get'
2304	if [ $? -ne 0 ]; then
2305		echo "iproute2 command does not support neigh get. Skipping test"
2306		return 1
2307	fi
2308
2309	return 0
2310}
2311
2312ipv4_bcast_neigh_test()
2313{
2314	local rc
2315
2316	echo
2317	echo "IPv4 broadcast neighbour tests"
2318
2319	ip_neigh_get_check || return 1
2320
2321	setup
2322
2323	set -e
2324	run_cmd "$IP neigh add 192.0.2.111 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
2325	run_cmd "$IP neigh add 192.0.2.255 lladdr 00:11:22:33:44:55 nud perm dev dummy0"
2326
2327	run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
2328	run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
2329
2330	run_cmd "$IP address add 192.0.2.1/24 broadcast 192.0.2.111 dev dummy0"
2331
2332	run_cmd "$IP neigh add 203.0.113.111 nud failed dev dummy0"
2333	run_cmd "$IP neigh add 203.0.113.255 nud failed dev dummy0"
2334
2335	run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
2336	run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
2337
2338	run_cmd "$IP address add 203.0.113.1/24 broadcast 203.0.113.111 dev dummy0"
2339	set +e
2340
2341	run_cmd "$IP neigh get 192.0.2.111 dev dummy0"
2342	log_test $? 0 "Resolved neighbour for broadcast address"
2343
2344	run_cmd "$IP neigh get 192.0.2.255 dev dummy0"
2345	log_test $? 0 "Resolved neighbour for network broadcast address"
2346
2347	run_cmd "$IP neigh get 203.0.113.111 dev dummy0"
2348	log_test $? 2 "Unresolved neighbour for broadcast address"
2349
2350	run_cmd "$IP neigh get 203.0.113.255 dev dummy0"
2351	log_test $? 2 "Unresolved neighbour for network broadcast address"
2352
2353	cleanup
2354}
2355
2356mpath_dep_check()
2357{
2358	if [ ! -x "$(command -v mausezahn)" ]; then
2359		echo "mausezahn command not found. Skipping test"
2360		return 1
2361	fi
2362
2363	if [ ! -x "$(command -v jq)" ]; then
2364		echo "jq command not found. Skipping test"
2365		return 1
2366	fi
2367
2368	if [ ! -x "$(command -v bc)" ]; then
2369		echo "bc command not found. Skipping test"
2370		return 1
2371	fi
2372
2373	if [ ! -x "$(command -v perf)" ]; then
2374		echo "perf command not found. Skipping test"
2375		return 1
2376	fi
2377
2378	perf list fib:* | grep -q fib_table_lookup
2379	if [ $? -ne 0 ]; then
2380		echo "IPv4 FIB tracepoint not found. Skipping test"
2381		return 1
2382	fi
2383
2384	perf list fib6:* | grep -q fib6_table_lookup
2385	if [ $? -ne 0 ]; then
2386		echo "IPv6 FIB tracepoint not found. Skipping test"
2387		return 1
2388	fi
2389
2390	return 0
2391}
2392
2393link_stats_get()
2394{
2395	local ns=$1; shift
2396	local dev=$1; shift
2397	local dir=$1; shift
2398	local stat=$1; shift
2399
2400	ip -n $ns -j -s link show dev $dev \
2401		| jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
2402}
2403
2404list_rcv_eval()
2405{
2406	local file=$1; shift
2407	local expected=$1; shift
2408
2409	local count=$(tail -n 1 $file | jq '.["counter-value"] | tonumber | floor')
2410	local ratio=$(echo "scale=2; $count / $expected" | bc -l)
2411	local res=$(echo "$ratio >= 0.95" | bc)
2412	[[ $res -eq 1 ]]
2413	log_test $? 0 "Multipath route hit ratio ($ratio)"
2414}
2415
2416ipv4_mpath_list_test()
2417{
2418	echo
2419	echo "IPv4 multipath list receive tests"
2420
2421	mpath_dep_check || return 1
2422
2423	route_setup
2424
2425	set -e
2426	run_cmd "ip netns exec ns1 ethtool -K veth1 tcp-segmentation-offload off"
2427
2428	run_cmd "ip netns exec ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
2429	run_cmd "ip netns exec ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
2430	run_cmd "ip netns exec ns2 ethtool -K veth2 generic-receive-offload on"
2431	run_cmd "ip -n ns2 link add name nh1 up type dummy"
2432	run_cmd "ip -n ns2 link add name nh2 up type dummy"
2433	run_cmd "ip -n ns2 address add 172.16.201.1/24 dev nh1"
2434	run_cmd "ip -n ns2 address add 172.16.202.1/24 dev nh2"
2435	run_cmd "ip -n ns2 neigh add 172.16.201.2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
2436	run_cmd "ip -n ns2 neigh add 172.16.202.2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
2437	run_cmd "ip -n ns2 route add 203.0.113.0/24
2438		nexthop via 172.16.201.2 nexthop via 172.16.202.2"
2439	run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.fib_multipath_hash_policy=1"
2440	run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.veth2.rp_filter=0"
2441	run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.all.rp_filter=0"
2442	run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.conf.default.rp_filter=0"
2443	set +e
2444
2445	local dmac=$(ip -n ns2 -j link show dev veth2 | jq -r '.[]["address"]')
2446	local tmp_file=$(mktemp)
2447	local cmd="ip netns exec ns1 mausezahn veth1 -a own -b $dmac
2448		-A 172.16.101.1 -B 203.0.113.1 -t udp 'sp=12345,dp=0-65535' -q"
2449
2450	# Packets forwarded in a list using a multipath route must not reuse a
2451	# cached result so that a flow always hits the same nexthop. In other
2452	# words, the FIB lookup tracepoint needs to be triggered for every
2453	# packet.
2454	local t0_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
2455	run_cmd "perf stat -a -e fib:fib_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
2456	local t1_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
2457	local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
2458	list_rcv_eval $tmp_file $diff
2459
2460	rm $tmp_file
2461	route_cleanup
2462}
2463
2464ipv6_mpath_list_test()
2465{
2466	echo
2467	echo "IPv6 multipath list receive tests"
2468
2469	mpath_dep_check || return 1
2470
2471	route_setup
2472
2473	set -e
2474	run_cmd "ip netns exec ns1 ethtool -K veth1 tcp-segmentation-offload off"
2475
2476	run_cmd "ip netns exec ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
2477	run_cmd "ip netns exec ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
2478	run_cmd "ip netns exec ns2 ethtool -K veth2 generic-receive-offload on"
2479	run_cmd "ip -n ns2 link add name nh1 up type dummy"
2480	run_cmd "ip -n ns2 link add name nh2 up type dummy"
2481	run_cmd "ip -n ns2 -6 address add 2001:db8:201::1/64 dev nh1"
2482	run_cmd "ip -n ns2 -6 address add 2001:db8:202::1/64 dev nh2"
2483	run_cmd "ip -n ns2 -6 neigh add 2001:db8:201::2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
2484	run_cmd "ip -n ns2 -6 neigh add 2001:db8:202::2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
2485	run_cmd "ip -n ns2 -6 route add 2001:db8:301::/64
2486		nexthop via 2001:db8:201::2 nexthop via 2001:db8:202::2"
2487	run_cmd "ip netns exec ns2 sysctl -qw net.ipv6.fib_multipath_hash_policy=1"
2488	set +e
2489
2490	local dmac=$(ip -n ns2 -j link show dev veth2 | jq -r '.[]["address"]')
2491	local tmp_file=$(mktemp)
2492	local cmd="ip netns exec ns1 mausezahn -6 veth1 -a own -b $dmac
2493		-A 2001:db8:101::1 -B 2001:db8:301::1 -t udp 'sp=12345,dp=0-65535' -q"
2494
2495	# Packets forwarded in a list using a multipath route must not reuse a
2496	# cached result so that a flow always hits the same nexthop. In other
2497	# words, the FIB lookup tracepoint needs to be triggered for every
2498	# packet.
2499	local t0_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
2500	run_cmd "perf stat -a -e fib6:fib6_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
2501	local t1_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
2502	local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
2503	list_rcv_eval $tmp_file $diff
2504
2505	rm $tmp_file
2506	route_cleanup
2507}
2508
2509################################################################################
2510# usage
2511
2512usage()
2513{
2514	cat <<EOF
2515usage: ${0##*/} OPTS
2516
2517        -t <test>   Test(s) to run (default: all)
2518                    (options: $TESTS)
2519        -p          Pause on fail
2520        -P          Pause after each test before cleanup
2521        -v          verbose mode (show commands and output)
2522EOF
2523}
2524
2525################################################################################
2526# main
2527
2528trap cleanup EXIT
2529
2530while getopts :t:pPhv o
2531do
2532	case $o in
2533		t) TESTS=$OPTARG;;
2534		p) PAUSE_ON_FAIL=yes;;
2535		P) PAUSE=yes;;
2536		v) VERBOSE=$(($VERBOSE + 1));;
2537		h) usage; exit 0;;
2538		*) usage; exit 1;;
2539	esac
2540done
2541
2542PEER_CMD="ip netns exec ${PEER_NS}"
2543
2544# make sure we don't pause twice
2545[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
2546
2547if [ "$(id -u)" -ne 0 ];then
2548	echo "SKIP: Need root privileges"
2549	exit $ksft_skip;
2550fi
2551
2552if [ ! -x "$(command -v ip)" ]; then
2553	echo "SKIP: Could not run test without ip tool"
2554	exit $ksft_skip
2555fi
2556
2557ip route help 2>&1 | grep -q fibmatch
2558if [ $? -ne 0 ]; then
2559	echo "SKIP: iproute2 too old, missing fibmatch"
2560	exit $ksft_skip
2561fi
2562
2563# start clean
2564cleanup &> /dev/null
2565
2566for t in $TESTS
2567do
2568	case $t in
2569	fib_unreg_test|unregister)	fib_unreg_test;;
2570	fib_down_test|down)		fib_down_test;;
2571	fib_carrier_test|carrier)	fib_carrier_test;;
2572	fib_rp_filter_test|rp_filter)	fib_rp_filter_test;;
2573	fib_nexthop_test|nexthop)	fib_nexthop_test;;
2574	fib_notify_test|ipv4_notify)	fib_notify_test;;
2575	fib6_notify_test|ipv6_notify)	fib6_notify_test;;
2576	fib_suppress_test|suppress)	fib_suppress_test;;
2577	ipv6_route_test|ipv6_rt)	ipv6_route_test;;
2578	ipv4_route_test|ipv4_rt)	ipv4_route_test;;
2579	ipv6_addr_metric)		ipv6_addr_metric_test;;
2580	ipv4_addr_metric)		ipv4_addr_metric_test;;
2581	ipv4_del_addr)			ipv4_del_addr_test;;
2582	ipv6_del_addr)			ipv6_del_addr_test;;
2583	ipv6_route_metrics)		ipv6_route_metrics_test;;
2584	ipv4_route_metrics)		ipv4_route_metrics_test;;
2585	ipv4_route_v6_gw)		ipv4_route_v6_gw_test;;
2586	ipv4_mangle)			ipv4_mangle_test;;
2587	ipv6_mangle)			ipv6_mangle_test;;
2588	ipv4_bcast_neigh)		ipv4_bcast_neigh_test;;
2589	fib6_gc_test|ipv6_gc)		fib6_gc_test;;
2590	ipv4_mpath_list)		ipv4_mpath_list_test;;
2591	ipv6_mpath_list)		ipv6_mpath_list_test;;
2592
2593	help) echo "Test names: $TESTS"; exit 0;;
2594	esac
2595done
2596
2597if [ "$TESTS" != "none" ]; then
2598	printf "\nTests passed: %3d\n" ${nsuccess}
2599	printf "Tests failed: %3d\n"   ${nfail}
2600fi
2601
2602exit $ret
2603