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