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_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"
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
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
658fib_suppress_test()
659{
660	echo
661	echo "FIB rule with suppress_prefixlength"
662	setup
663
664	$IP link add dummy1 type dummy
665	$IP link set dummy1 up
666	$IP -6 route add default dev dummy1
667	$IP -6 rule add table main suppress_prefixlength 0
668	ping -f -c 1000 -W 1 1234::1 >/dev/null 2>&1
669	$IP -6 rule del table main suppress_prefixlength 0
670	$IP link del dummy1
671
672	# If we got here without crashing, we're good.
673	log_test 0 0 "FIB rule suppress test"
674
675	cleanup
676}
677
678################################################################################
679# Tests on route add and replace
680
681run_cmd()
682{
683	local cmd="$1"
684	local out
685	local stderr="2>/dev/null"
686
687	if [ "$VERBOSE" = "1" ]; then
688		printf "    COMMAND: $cmd\n"
689		stderr=
690	fi
691
692	out=$(eval $cmd $stderr)
693	rc=$?
694	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
695		echo "    $out"
696	fi
697
698	[ "$VERBOSE" = "1" ] && echo
699
700	return $rc
701}
702
703check_expected()
704{
705	local out="$1"
706	local expected="$2"
707	local rc=0
708
709	[ "${out}" = "${expected}" ] && return 0
710
711	if [ -z "${out}" ]; then
712		if [ "$VERBOSE" = "1" ]; then
713			printf "\nNo route entry found\n"
714			printf "Expected:\n"
715			printf "    ${expected}\n"
716		fi
717		return 1
718	fi
719
720	# tricky way to convert output to 1-line without ip's
721	# messy '\'; this drops all extra white space
722	out=$(echo ${out})
723	if [ "${out}" != "${expected}" ]; then
724		rc=1
725		if [ "${VERBOSE}" = "1" ]; then
726			printf "    Unexpected route entry. Have:\n"
727			printf "        ${out}\n"
728			printf "    Expected:\n"
729			printf "        ${expected}\n\n"
730		fi
731	fi
732
733	return $rc
734}
735
736# add route for a prefix, flushing any existing routes first
737# expected to be the first step of a test
738add_route6()
739{
740	local pfx="$1"
741	local nh="$2"
742	local out
743
744	if [ "$VERBOSE" = "1" ]; then
745		echo
746		echo "    ##################################################"
747		echo
748	fi
749
750	run_cmd "$IP -6 ro flush ${pfx}"
751	[ $? -ne 0 ] && exit 1
752
753	out=$($IP -6 ro ls match ${pfx})
754	if [ -n "$out" ]; then
755		echo "Failed to flush routes for prefix used for tests."
756		exit 1
757	fi
758
759	run_cmd "$IP -6 ro add ${pfx} ${nh}"
760	if [ $? -ne 0 ]; then
761		echo "Failed to add initial route for test."
762		exit 1
763	fi
764}
765
766# add initial route - used in replace route tests
767add_initial_route6()
768{
769	add_route6 "2001:db8:104::/64" "$1"
770}
771
772check_route6()
773{
774	local pfx
775	local expected="$1"
776	local out
777	local rc=0
778
779	set -- $expected
780	pfx=$1
781
782	out=$($IP -6 ro ls match ${pfx} | sed -e 's/ pref medium//')
783	check_expected "${out}" "${expected}"
784}
785
786route_cleanup()
787{
788	$IP li del red 2>/dev/null
789	$IP li del dummy1 2>/dev/null
790	$IP li del veth1 2>/dev/null
791	$IP li del veth3 2>/dev/null
792
793	cleanup &> /dev/null
794}
795
796route_setup()
797{
798	route_cleanup
799	setup
800
801	[ "${VERBOSE}" = "1" ] && set -x
802	set -e
803
804	ip netns add ns2
805	ip netns set ns2 auto
806	ip -netns ns2 link set dev lo up
807	ip netns exec ns2 sysctl -qw net.ipv4.ip_forward=1
808	ip netns exec ns2 sysctl -qw net.ipv6.conf.all.forwarding=1
809
810	$IP li add veth1 type veth peer name veth2
811	$IP li add veth3 type veth peer name veth4
812
813	$IP li set veth1 up
814	$IP li set veth3 up
815	$IP li set veth2 netns ns2 up
816	$IP li set veth4 netns ns2 up
817	ip -netns ns2 li add dummy1 type dummy
818	ip -netns ns2 li set dummy1 up
819
820	$IP -6 addr add 2001:db8:101::1/64 dev veth1 nodad
821	$IP -6 addr add 2001:db8:103::1/64 dev veth3 nodad
822	$IP addr add 172.16.101.1/24 dev veth1
823	$IP addr add 172.16.103.1/24 dev veth3
824
825	ip -netns ns2 -6 addr add 2001:db8:101::2/64 dev veth2 nodad
826	ip -netns ns2 -6 addr add 2001:db8:103::2/64 dev veth4 nodad
827	ip -netns ns2 -6 addr add 2001:db8:104::1/64 dev dummy1 nodad
828
829	ip -netns ns2 addr add 172.16.101.2/24 dev veth2
830	ip -netns ns2 addr add 172.16.103.2/24 dev veth4
831	ip -netns ns2 addr add 172.16.104.1/24 dev dummy1
832
833	set +e
834}
835
836# assumption is that basic add of a single path route works
837# otherwise just adding an address on an interface is broken
838ipv6_rt_add()
839{
840	local rc
841
842	echo
843	echo "IPv6 route add / append tests"
844
845	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
846	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
847	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2"
848	log_test $? 2 "Attempt to add duplicate route - gw"
849
850	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
851	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
852	run_cmd "$IP -6 ro add 2001:db8:104::/64 dev veth3"
853	log_test $? 2 "Attempt to add duplicate route - dev only"
854
855	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
856	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
857	run_cmd "$IP -6 ro add unreachable 2001:db8:104::/64"
858	log_test $? 2 "Attempt to add duplicate route - reject route"
859
860	# route append with same prefix adds a new route
861	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
862	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
863	run_cmd "$IP -6 ro append 2001:db8:104::/64 via 2001:db8:103::2"
864	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"
865	log_test $? 0 "Append nexthop to existing route - gw"
866
867	# insert mpath directly
868	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
869	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"
870	log_test $? 0 "Add multipath route"
871
872	add_route6 "2001:db8:104::/64" "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
873	run_cmd "$IP -6 ro add 2001:db8:104::/64 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
874	log_test $? 2 "Attempt to add duplicate multipath route"
875
876	# insert of a second route without append but different metric
877	add_route6 "2001:db8:104::/64" "via 2001:db8:101::2"
878	run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::2 metric 512"
879	rc=$?
880	if [ $rc -eq 0 ]; then
881		run_cmd "$IP -6 ro add 2001:db8:104::/64 via 2001:db8:103::3 metric 256"
882		rc=$?
883	fi
884	log_test $rc 0 "Route add with different metrics"
885
886	run_cmd "$IP -6 ro del 2001:db8:104::/64 metric 512"
887	rc=$?
888	if [ $rc -eq 0 ]; then
889		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"
890		rc=$?
891	fi
892	log_test $rc 0 "Route delete with metric"
893}
894
895ipv6_rt_replace_single()
896{
897	# single path with single path
898	#
899	add_initial_route6 "via 2001:db8:101::2"
900	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:103::2"
901	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
902	log_test $? 0 "Single path with single path"
903
904	# single path with multipath
905	#
906	add_initial_route6 "nexthop via 2001:db8:101::2"
907	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::2"
908	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"
909	log_test $? 0 "Single path with multipath"
910
911	# single path with single path using MULTIPATH attribute
912	#
913	add_initial_route6 "via 2001:db8:101::2"
914	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:103::2"
915	check_route6 "2001:db8:104::/64 via 2001:db8:103::2 dev veth3 metric 1024"
916	log_test $? 0 "Single path with single path via multipath attribute"
917
918	# route replace fails - invalid nexthop
919	add_initial_route6 "via 2001:db8:101::2"
920	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:104::2"
921	if [ $? -eq 0 ]; then
922		# previous command is expected to fail so if it returns 0
923		# that means the test failed.
924		log_test 0 1 "Invalid nexthop"
925	else
926		check_route6 "2001:db8:104::/64 via 2001:db8:101::2 dev veth1 metric 1024"
927		log_test $? 0 "Invalid nexthop"
928	fi
929
930	# replace non-existent route
931	# - note use of change versus replace since ip adds NLM_F_CREATE
932	#   for replace
933	add_initial_route6 "via 2001:db8:101::2"
934	run_cmd "$IP -6 ro change 2001:db8:105::/64 via 2001:db8:101::2"
935	log_test $? 2 "Single path - replace of non-existent route"
936}
937
938ipv6_rt_replace_mpath()
939{
940	# multipath with multipath
941	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
942	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
943	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"
944	log_test $? 0 "Multipath with multipath"
945
946	# multipath with single
947	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
948	run_cmd "$IP -6 ro replace 2001:db8:104::/64 via 2001:db8:101::3"
949	check_route6  "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
950	log_test $? 0 "Multipath with single path"
951
952	# multipath with single
953	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
954	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3"
955	check_route6 "2001:db8:104::/64 via 2001:db8:101::3 dev veth1 metric 1024"
956	log_test $? 0 "Multipath with single path via multipath attribute"
957
958	# multipath with dev-only
959	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
960	run_cmd "$IP -6 ro replace 2001:db8:104::/64 dev veth1"
961	check_route6 "2001:db8:104::/64 dev veth1 metric 1024"
962	log_test $? 0 "Multipath with dev-only"
963
964	# route replace fails - invalid nexthop 1
965	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
966	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:111::3 nexthop via 2001:db8:103::3"
967	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"
968	log_test $? 0 "Multipath - invalid first nexthop"
969
970	# route replace fails - invalid nexthop 2
971	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
972	run_cmd "$IP -6 ro replace 2001:db8:104::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:113::3"
973	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"
974	log_test $? 0 "Multipath - invalid second nexthop"
975
976	# multipath non-existent route
977	add_initial_route6 "nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
978	run_cmd "$IP -6 ro change 2001:db8:105::/64 nexthop via 2001:db8:101::3 nexthop via 2001:db8:103::3"
979	log_test $? 2 "Multipath - replace of non-existent route"
980}
981
982ipv6_rt_replace()
983{
984	echo
985	echo "IPv6 route replace tests"
986
987	ipv6_rt_replace_single
988	ipv6_rt_replace_mpath
989}
990
991ipv6_route_test()
992{
993	route_setup
994
995	ipv6_rt_add
996	ipv6_rt_replace
997
998	route_cleanup
999}
1000
1001ip_addr_metric_check()
1002{
1003	ip addr help 2>&1 | grep -q metric
1004	if [ $? -ne 0 ]; then
1005		echo "iproute2 command does not support metric for addresses. Skipping test"
1006		return 1
1007	fi
1008
1009	return 0
1010}
1011
1012ipv6_addr_metric_test()
1013{
1014	local rc
1015
1016	echo
1017	echo "IPv6 prefix route tests"
1018
1019	ip_addr_metric_check || return 1
1020
1021	setup
1022
1023	set -e
1024	$IP li add dummy1 type dummy
1025	$IP li add dummy2 type dummy
1026	$IP li set dummy1 up
1027	$IP li set dummy2 up
1028
1029	# default entry is metric 256
1030	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64"
1031	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64"
1032	set +e
1033
1034	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 256 2001:db8:104::/64 dev dummy2 proto kernel metric 256"
1035	log_test $? 0 "Default metric"
1036
1037	set -e
1038	run_cmd "$IP -6 addr flush dev dummy1"
1039	run_cmd "$IP -6 addr add dev dummy1 2001:db8:104::1/64 metric 257"
1040	set +e
1041
1042	check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 256 2001:db8:104::/64 dev dummy1 proto kernel metric 257"
1043	log_test $? 0 "User specified metric on first device"
1044
1045	set -e
1046	run_cmd "$IP -6 addr flush dev dummy2"
1047	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::2/64 metric 258"
1048	set +e
1049
1050	check_route6 "2001:db8:104::/64 dev dummy1 proto kernel metric 257 2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1051	log_test $? 0 "User specified metric on second device"
1052
1053	run_cmd "$IP -6 addr del dev dummy1 2001:db8:104::1/64 metric 257"
1054	rc=$?
1055	if [ $rc -eq 0 ]; then
1056		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 258"
1057		rc=$?
1058	fi
1059	log_test $rc 0 "Delete of address on first device"
1060
1061	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::2/64 metric 259"
1062	rc=$?
1063	if [ $rc -eq 0 ]; then
1064		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1065		rc=$?
1066	fi
1067	log_test $rc 0 "Modify metric of address"
1068
1069	# verify prefix route removed on down
1070	run_cmd "ip netns exec ns1 sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1"
1071	run_cmd "$IP li set dev dummy2 down"
1072	rc=$?
1073	if [ $rc -eq 0 ]; then
1074		out=$($IP -6 ro ls match 2001:db8:104::/64)
1075		check_expected "${out}" ""
1076		rc=$?
1077	fi
1078	log_test $rc 0 "Prefix route removed on link down"
1079
1080	# verify prefix route re-inserted with assigned metric
1081	run_cmd "$IP li set dev dummy2 up"
1082	rc=$?
1083	if [ $rc -eq 0 ]; then
1084		check_route6 "2001:db8:104::/64 dev dummy2 proto kernel metric 259"
1085		rc=$?
1086	fi
1087	log_test $rc 0 "Prefix route with metric on link up"
1088
1089	# verify peer metric added correctly
1090	set -e
1091	run_cmd "$IP -6 addr flush dev dummy2"
1092	run_cmd "$IP -6 addr add dev dummy2 2001:db8:104::1 peer 2001:db8:104::2 metric 260"
1093	set +e
1094
1095	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 260"
1096	log_test $? 0 "Set metric with peer route on local side"
1097	check_route6 "2001:db8:104::2 dev dummy2 proto kernel metric 260"
1098	log_test $? 0 "Set metric with peer route on peer side"
1099
1100	set -e
1101	run_cmd "$IP -6 addr change dev dummy2 2001:db8:104::1 peer 2001:db8:104::3 metric 261"
1102	set +e
1103
1104	check_route6 "2001:db8:104::1 dev dummy2 proto kernel metric 261"
1105	log_test $? 0 "Modify metric and peer address on local side"
1106	check_route6 "2001:db8:104::3 dev dummy2 proto kernel metric 261"
1107	log_test $? 0 "Modify metric and peer address on peer side"
1108
1109	$IP li del dummy1
1110	$IP li del dummy2
1111	cleanup
1112}
1113
1114ipv6_route_metrics_test()
1115{
1116	local rc
1117
1118	echo
1119	echo "IPv6 routes with metrics"
1120
1121	route_setup
1122
1123	#
1124	# single path with metrics
1125	#
1126	run_cmd "$IP -6 ro add 2001:db8:111::/64 via 2001:db8:101::2 mtu 1400"
1127	rc=$?
1128	if [ $rc -eq 0 ]; then
1129		check_route6  "2001:db8:111::/64 via 2001:db8:101::2 dev veth1 metric 1024 mtu 1400"
1130		rc=$?
1131	fi
1132	log_test $rc 0 "Single path route with mtu metric"
1133
1134
1135	#
1136	# multipath via separate routes with metrics
1137	#
1138	run_cmd "$IP -6 ro add 2001:db8:112::/64 via 2001:db8:101::2 mtu 1400"
1139	run_cmd "$IP -6 ro append 2001:db8:112::/64 via 2001:db8:103::2"
1140	rc=$?
1141	if [ $rc -eq 0 ]; then
1142		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"
1143		rc=$?
1144	fi
1145	log_test $rc 0 "Multipath route via 2 single routes with mtu metric on first"
1146
1147	# second route is coalesced to first to make a multipath route.
1148	# MTU of the second path is hidden from display!
1149	run_cmd "$IP -6 ro add 2001:db8:113::/64 via 2001:db8:101::2"
1150	run_cmd "$IP -6 ro append 2001:db8:113::/64 via 2001:db8:103::2 mtu 1400"
1151	rc=$?
1152	if [ $rc -eq 0 ]; then
1153		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"
1154		rc=$?
1155	fi
1156	log_test $rc 0 "Multipath route via 2 single routes with mtu metric on 2nd"
1157
1158	run_cmd "$IP -6 ro del 2001:db8:113::/64 via 2001:db8:101::2"
1159	if [ $? -eq 0 ]; then
1160		check_route6 "2001:db8:113::/64 via 2001:db8:103::2 dev veth3 metric 1024 mtu 1400"
1161		log_test $? 0 "    MTU of second leg"
1162	fi
1163
1164	#
1165	# multipath with metrics
1166	#
1167	run_cmd "$IP -6 ro add 2001:db8:115::/64 mtu 1400 nexthop via 2001:db8:101::2 nexthop via 2001:db8:103::2"
1168	rc=$?
1169	if [ $rc -eq 0 ]; then
1170		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"
1171		rc=$?
1172	fi
1173	log_test $rc 0 "Multipath route with mtu metric"
1174
1175	$IP -6 ro add 2001:db8:104::/64 via 2001:db8:101::2 mtu 1300
1176	run_cmd "ip netns exec ns1 ${ping6} -w1 -c1 -s 1500 2001:db8:104::1"
1177	log_test $? 0 "Using route with mtu metric"
1178
1179	run_cmd "$IP -6 ro add 2001:db8:114::/64 via  2001:db8:101::2  congctl lock foo"
1180	log_test $? 2 "Invalid metric (fails metric_convert)"
1181
1182	route_cleanup
1183}
1184
1185# add route for a prefix, flushing any existing routes first
1186# expected to be the first step of a test
1187add_route()
1188{
1189	local pfx="$1"
1190	local nh="$2"
1191	local out
1192
1193	if [ "$VERBOSE" = "1" ]; then
1194		echo
1195		echo "    ##################################################"
1196		echo
1197	fi
1198
1199	run_cmd "$IP ro flush ${pfx}"
1200	[ $? -ne 0 ] && exit 1
1201
1202	out=$($IP ro ls match ${pfx})
1203	if [ -n "$out" ]; then
1204		echo "Failed to flush routes for prefix used for tests."
1205		exit 1
1206	fi
1207
1208	run_cmd "$IP ro add ${pfx} ${nh}"
1209	if [ $? -ne 0 ]; then
1210		echo "Failed to add initial route for test."
1211		exit 1
1212	fi
1213}
1214
1215# add initial route - used in replace route tests
1216add_initial_route()
1217{
1218	add_route "172.16.104.0/24" "$1"
1219}
1220
1221check_route()
1222{
1223	local pfx
1224	local expected="$1"
1225	local out
1226
1227	set -- $expected
1228	pfx=$1
1229	[ "${pfx}" = "unreachable" ] && pfx=$2
1230
1231	out=$($IP ro ls match ${pfx})
1232	check_expected "${out}" "${expected}"
1233}
1234
1235# assumption is that basic add of a single path route works
1236# otherwise just adding an address on an interface is broken
1237ipv4_rt_add()
1238{
1239	local rc
1240
1241	echo
1242	echo "IPv4 route add / append tests"
1243
1244	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1245	add_route "172.16.104.0/24" "via 172.16.101.2"
1246	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2"
1247	log_test $? 2 "Attempt to add duplicate route - gw"
1248
1249	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1250	add_route "172.16.104.0/24" "via 172.16.101.2"
1251	run_cmd "$IP ro add 172.16.104.0/24 dev veth3"
1252	log_test $? 2 "Attempt to add duplicate route - dev only"
1253
1254	# route add same prefix - fails with EEXISTS b/c ip adds NLM_F_EXCL
1255	add_route "172.16.104.0/24" "via 172.16.101.2"
1256	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1257	log_test $? 2 "Attempt to add duplicate route - reject route"
1258
1259	# iproute2 prepend only sets NLM_F_CREATE
1260	# - adds a new route; does NOT convert existing route to ECMP
1261	add_route "172.16.104.0/24" "via 172.16.101.2"
1262	run_cmd "$IP ro prepend 172.16.104.0/24 via 172.16.103.2"
1263	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"
1264	log_test $? 0 "Add new nexthop for existing prefix"
1265
1266	# route append with same prefix adds a new route
1267	# - iproute2 sets NLM_F_CREATE | NLM_F_APPEND
1268	add_route "172.16.104.0/24" "via 172.16.101.2"
1269	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1270	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"
1271	log_test $? 0 "Append nexthop to existing route - gw"
1272
1273	add_route "172.16.104.0/24" "via 172.16.101.2"
1274	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1275	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 172.16.104.0/24 dev veth3 scope link"
1276	log_test $? 0 "Append nexthop to existing route - dev only"
1277
1278	add_route "172.16.104.0/24" "via 172.16.101.2"
1279	run_cmd "$IP ro append unreachable 172.16.104.0/24"
1280	check_route "172.16.104.0/24 via 172.16.101.2 dev veth1 unreachable 172.16.104.0/24"
1281	log_test $? 0 "Append nexthop to existing route - reject route"
1282
1283	run_cmd "$IP ro flush 172.16.104.0/24"
1284	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1285	run_cmd "$IP ro append 172.16.104.0/24 via 172.16.103.2"
1286	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 via 172.16.103.2 dev veth3"
1287	log_test $? 0 "Append nexthop to existing reject route - gw"
1288
1289	run_cmd "$IP ro flush 172.16.104.0/24"
1290	run_cmd "$IP ro add unreachable 172.16.104.0/24"
1291	run_cmd "$IP ro append 172.16.104.0/24 dev veth3"
1292	check_route "unreachable 172.16.104.0/24 172.16.104.0/24 dev veth3 scope link"
1293	log_test $? 0 "Append nexthop to existing reject route - dev only"
1294
1295	# insert mpath directly
1296	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1297	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"
1298	log_test $? 0 "add multipath route"
1299
1300	add_route "172.16.104.0/24" "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1301	run_cmd "$IP ro add 172.16.104.0/24 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1302	log_test $? 2 "Attempt to add duplicate multipath route"
1303
1304	# insert of a second route without append but different metric
1305	add_route "172.16.104.0/24" "via 172.16.101.2"
1306	run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.2 metric 512"
1307	rc=$?
1308	if [ $rc -eq 0 ]; then
1309		run_cmd "$IP ro add 172.16.104.0/24 via 172.16.103.3 metric 256"
1310		rc=$?
1311	fi
1312	log_test $rc 0 "Route add with different metrics"
1313
1314	run_cmd "$IP ro del 172.16.104.0/24 metric 512"
1315	rc=$?
1316	if [ $rc -eq 0 ]; then
1317		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"
1318		rc=$?
1319	fi
1320	log_test $rc 0 "Route delete with metric"
1321}
1322
1323ipv4_rt_replace_single()
1324{
1325	# single path with single path
1326	#
1327	add_initial_route "via 172.16.101.2"
1328	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.103.2"
1329	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1330	log_test $? 0 "Single path with single path"
1331
1332	# single path with multipath
1333	#
1334	add_initial_route "nexthop via 172.16.101.2"
1335	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.2"
1336	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"
1337	log_test $? 0 "Single path with multipath"
1338
1339	# single path with reject
1340	#
1341	add_initial_route "nexthop via 172.16.101.2"
1342	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1343	check_route "unreachable 172.16.104.0/24"
1344	log_test $? 0 "Single path with reject route"
1345
1346	# single path with single path using MULTIPATH attribute
1347	#
1348	add_initial_route "via 172.16.101.2"
1349	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.103.2"
1350	check_route "172.16.104.0/24 via 172.16.103.2 dev veth3"
1351	log_test $? 0 "Single path with single path via multipath attribute"
1352
1353	# route replace fails - invalid nexthop
1354	add_initial_route "via 172.16.101.2"
1355	run_cmd "$IP ro replace 172.16.104.0/24 via 2001:db8:104::2"
1356	if [ $? -eq 0 ]; then
1357		# previous command is expected to fail so if it returns 0
1358		# that means the test failed.
1359		log_test 0 1 "Invalid nexthop"
1360	else
1361		check_route "172.16.104.0/24 via 172.16.101.2 dev veth1"
1362		log_test $? 0 "Invalid nexthop"
1363	fi
1364
1365	# replace non-existent route
1366	# - note use of change versus replace since ip adds NLM_F_CREATE
1367	#   for replace
1368	add_initial_route "via 172.16.101.2"
1369	run_cmd "$IP ro change 172.16.105.0/24 via 172.16.101.2"
1370	log_test $? 2 "Single path - replace of non-existent route"
1371}
1372
1373ipv4_rt_replace_mpath()
1374{
1375	# multipath with multipath
1376	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1377	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1378	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"
1379	log_test $? 0 "Multipath with multipath"
1380
1381	# multipath with single
1382	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1383	run_cmd "$IP ro replace 172.16.104.0/24 via 172.16.101.3"
1384	check_route  "172.16.104.0/24 via 172.16.101.3 dev veth1"
1385	log_test $? 0 "Multipath with single path"
1386
1387	# multipath with single
1388	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1389	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3"
1390	check_route "172.16.104.0/24 via 172.16.101.3 dev veth1"
1391	log_test $? 0 "Multipath with single path via multipath attribute"
1392
1393	# multipath with reject
1394	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1395	run_cmd "$IP ro replace unreachable 172.16.104.0/24"
1396	check_route "unreachable 172.16.104.0/24"
1397	log_test $? 0 "Multipath with reject route"
1398
1399	# route replace fails - invalid nexthop 1
1400	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1401	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.111.3 nexthop via 172.16.103.3"
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 "Multipath - invalid first nexthop"
1404
1405	# route replace fails - invalid nexthop 2
1406	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1407	run_cmd "$IP ro replace 172.16.104.0/24 nexthop via 172.16.101.3 nexthop via 172.16.113.3"
1408	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"
1409	log_test $? 0 "Multipath - invalid second nexthop"
1410
1411	# multipath non-existent route
1412	add_initial_route "nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1413	run_cmd "$IP ro change 172.16.105.0/24 nexthop via 172.16.101.3 nexthop via 172.16.103.3"
1414	log_test $? 2 "Multipath - replace of non-existent route"
1415}
1416
1417ipv4_rt_replace()
1418{
1419	echo
1420	echo "IPv4 route replace tests"
1421
1422	ipv4_rt_replace_single
1423	ipv4_rt_replace_mpath
1424}
1425
1426# checks that cached input route on VRF port is deleted
1427# when VRF is deleted
1428ipv4_local_rt_cache()
1429{
1430	run_cmd "ip addr add 10.0.0.1/32 dev lo"
1431	run_cmd "ip netns add test-ns"
1432	run_cmd "ip link add veth-outside type veth peer name veth-inside"
1433	run_cmd "ip link add vrf-100 type vrf table 1100"
1434	run_cmd "ip link set veth-outside master vrf-100"
1435	run_cmd "ip link set veth-inside netns test-ns"
1436	run_cmd "ip link set veth-outside up"
1437	run_cmd "ip link set vrf-100 up"
1438	run_cmd "ip route add 10.1.1.1/32 dev veth-outside table 1100"
1439	run_cmd "ip netns exec test-ns ip link set veth-inside up"
1440	run_cmd "ip netns exec test-ns ip addr add 10.1.1.1/32 dev veth-inside"
1441	run_cmd "ip netns exec test-ns ip route add 10.0.0.1/32 dev veth-inside"
1442	run_cmd "ip netns exec test-ns ip route add default via 10.0.0.1"
1443	run_cmd "ip netns exec test-ns ping 10.0.0.1 -c 1 -i 1"
1444	run_cmd "ip link delete vrf-100"
1445
1446	# if we do not hang test is a success
1447	log_test $? 0 "Cached route removed from VRF port device"
1448}
1449
1450ipv4_route_test()
1451{
1452	route_setup
1453
1454	ipv4_rt_add
1455	ipv4_rt_replace
1456	ipv4_local_rt_cache
1457
1458	route_cleanup
1459}
1460
1461ipv4_addr_metric_test()
1462{
1463	local rc
1464
1465	echo
1466	echo "IPv4 prefix route tests"
1467
1468	ip_addr_metric_check || return 1
1469
1470	setup
1471
1472	set -e
1473	$IP li add dummy1 type dummy
1474	$IP li add dummy2 type dummy
1475	$IP li set dummy1 up
1476	$IP li set dummy2 up
1477
1478	# default entry is metric 256
1479	run_cmd "$IP addr add dev dummy1 172.16.104.1/24"
1480	run_cmd "$IP addr add dev dummy2 172.16.104.2/24"
1481	set +e
1482
1483	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"
1484	log_test $? 0 "Default metric"
1485
1486	set -e
1487	run_cmd "$IP addr flush dev dummy1"
1488	run_cmd "$IP addr add dev dummy1 172.16.104.1/24 metric 257"
1489	set +e
1490
1491	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"
1492	log_test $? 0 "User specified metric on first device"
1493
1494	set -e
1495	run_cmd "$IP addr flush dev dummy2"
1496	run_cmd "$IP addr add dev dummy2 172.16.104.2/24 metric 258"
1497	set +e
1498
1499	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"
1500	log_test $? 0 "User specified metric on second device"
1501
1502	run_cmd "$IP addr del dev dummy1 172.16.104.1/24 metric 257"
1503	rc=$?
1504	if [ $rc -eq 0 ]; then
1505		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 258"
1506		rc=$?
1507	fi
1508	log_test $rc 0 "Delete of address on first device"
1509
1510	run_cmd "$IP addr change dev dummy2 172.16.104.2/24 metric 259"
1511	rc=$?
1512	if [ $rc -eq 0 ]; then
1513		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1514		rc=$?
1515	fi
1516	log_test $rc 0 "Modify metric of address"
1517
1518	# verify prefix route removed on down
1519	run_cmd "$IP li set dev dummy2 down"
1520	rc=$?
1521	if [ $rc -eq 0 ]; then
1522		out=$($IP ro ls match 172.16.104.0/24)
1523		check_expected "${out}" ""
1524		rc=$?
1525	fi
1526	log_test $rc 0 "Prefix route removed on link down"
1527
1528	# verify prefix route re-inserted with assigned metric
1529	run_cmd "$IP li set dev dummy2 up"
1530	rc=$?
1531	if [ $rc -eq 0 ]; then
1532		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.2 metric 259"
1533		rc=$?
1534	fi
1535	log_test $rc 0 "Prefix route with metric on link up"
1536
1537	# explicitly check for metric changes on edge scenarios
1538	run_cmd "$IP addr flush dev dummy2"
1539	run_cmd "$IP addr add dev dummy2 172.16.104.0/24 metric 259"
1540	run_cmd "$IP addr change dev dummy2 172.16.104.0/24 metric 260"
1541	rc=$?
1542	if [ $rc -eq 0 ]; then
1543		check_route "172.16.104.0/24 dev dummy2 proto kernel scope link src 172.16.104.0 metric 260"
1544		rc=$?
1545	fi
1546	log_test $rc 0 "Modify metric of .0/24 address"
1547
1548	run_cmd "$IP addr flush dev dummy2"
1549	run_cmd "$IP addr add dev dummy2 172.16.104.1/32 peer 172.16.104.2 metric 260"
1550	rc=$?
1551	if [ $rc -eq 0 ]; then
1552		check_route "172.16.104.2 dev dummy2 proto kernel scope link src 172.16.104.1 metric 260"
1553		rc=$?
1554	fi
1555	log_test $rc 0 "Set metric of address with peer route"
1556
1557	run_cmd "$IP addr change dev dummy2 172.16.104.1/32 peer 172.16.104.3 metric 261"
1558	rc=$?
1559	if [ $rc -eq 0 ]; then
1560		check_route "172.16.104.3 dev dummy2 proto kernel scope link src 172.16.104.1 metric 261"
1561		rc=$?
1562	fi
1563	log_test $rc 0 "Modify metric and peer address for peer route"
1564
1565	$IP li del dummy1
1566	$IP li del dummy2
1567	cleanup
1568}
1569
1570ipv4_route_metrics_test()
1571{
1572	local rc
1573
1574	echo
1575	echo "IPv4 route add / append tests"
1576
1577	route_setup
1578
1579	run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 mtu 1400"
1580	rc=$?
1581	if [ $rc -eq 0 ]; then
1582		check_route "172.16.111.0/24 via 172.16.101.2 dev veth1 mtu 1400"
1583		rc=$?
1584	fi
1585	log_test $rc 0 "Single path route with mtu metric"
1586
1587
1588	run_cmd "$IP ro add 172.16.112.0/24 mtu 1400 nexthop via 172.16.101.2 nexthop via 172.16.103.2"
1589	rc=$?
1590	if [ $rc -eq 0 ]; then
1591		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"
1592		rc=$?
1593	fi
1594	log_test $rc 0 "Multipath route with mtu metric"
1595
1596	$IP ro add 172.16.104.0/24 via 172.16.101.2 mtu 1300
1597	run_cmd "ip netns exec ns1 ping -w1 -c1 -s 1500 172.16.104.1"
1598	log_test $? 0 "Using route with mtu metric"
1599
1600	run_cmd "$IP ro add 172.16.111.0/24 via 172.16.101.2 congctl lock foo"
1601	log_test $? 2 "Invalid metric (fails metric_convert)"
1602
1603	route_cleanup
1604}
1605
1606ipv4_del_addr_test()
1607{
1608	echo
1609	echo "IPv4 delete address route tests"
1610
1611	setup
1612
1613	set -e
1614	$IP li add dummy1 type dummy
1615	$IP li set dummy1 up
1616	$IP li add dummy2 type dummy
1617	$IP li set dummy2 up
1618	$IP li add red type vrf table 1111
1619	$IP li set red up
1620	$IP ro add vrf red unreachable default
1621	$IP li set dummy2 vrf red
1622
1623	$IP addr add dev dummy1 172.16.104.1/24
1624	$IP addr add dev dummy1 172.16.104.11/24
1625	$IP addr add dev dummy2 172.16.104.1/24
1626	$IP addr add dev dummy2 172.16.104.11/24
1627	$IP route add 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1628	$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1629	set +e
1630
1631	# removing address from device in vrf should only remove route from vrf table
1632	$IP addr del dev dummy2 172.16.104.11/24
1633	$IP ro ls vrf red | grep -q 172.16.105.0/24
1634	log_test $? 1 "Route removed from VRF when source address deleted"
1635
1636	$IP ro ls | grep -q 172.16.105.0/24
1637	log_test $? 0 "Route in default VRF not removed"
1638
1639	$IP addr add dev dummy2 172.16.104.11/24
1640	$IP route add vrf red 172.16.105.0/24 via 172.16.104.2 src 172.16.104.11
1641
1642	$IP addr del dev dummy1 172.16.104.11/24
1643	$IP ro ls | grep -q 172.16.105.0/24
1644	log_test $? 1 "Route removed in default VRF when source address deleted"
1645
1646	$IP ro ls vrf red | grep -q 172.16.105.0/24
1647	log_test $? 0 "Route in VRF is not removed by address delete"
1648
1649	$IP li del dummy1
1650	$IP li del dummy2
1651	cleanup
1652}
1653
1654
1655ipv4_route_v6_gw_test()
1656{
1657	local rc
1658
1659	echo
1660	echo "IPv4 route with IPv6 gateway tests"
1661
1662	route_setup
1663	sleep 2
1664
1665	#
1666	# single path route
1667	#
1668	run_cmd "$IP ro add 172.16.104.0/24 via inet6 2001:db8:101::2"
1669	rc=$?
1670	log_test $rc 0 "Single path route with IPv6 gateway"
1671	if [ $rc -eq 0 ]; then
1672		check_route "172.16.104.0/24 via inet6 2001:db8:101::2 dev veth1"
1673	fi
1674
1675	run_cmd "ip netns exec ns1 ping -w1 -c1 172.16.104.1"
1676	log_test $rc 0 "Single path route with IPv6 gateway - ping"
1677
1678	run_cmd "$IP ro del 172.16.104.0/24 via inet6 2001:db8:101::2"
1679	rc=$?
1680	log_test $rc 0 "Single path route delete"
1681	if [ $rc -eq 0 ]; then
1682		check_route "172.16.112.0/24"
1683	fi
1684
1685	#
1686	# multipath - v6 then v4
1687	#
1688	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"
1689	rc=$?
1690	log_test $rc 0 "Multipath route add - v6 nexthop then v4"
1691	if [ $rc -eq 0 ]; then
1692		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"
1693	fi
1694
1695	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"
1696	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1697
1698	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"
1699	log_test $? 0 "    Multipath route delete exact match"
1700
1701	#
1702	# multipath - v4 then v6
1703	#
1704	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"
1705	rc=$?
1706	log_test $rc 0 "Multipath route add - v4 nexthop then v6"
1707	if [ $rc -eq 0 ]; then
1708		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"
1709	fi
1710
1711	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"
1712	log_test $? 2 "    Multipath route delete - nexthops in wrong order"
1713
1714	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"
1715	log_test $? 0 "    Multipath route delete exact match"
1716
1717	route_cleanup
1718}
1719
1720socat_check()
1721{
1722	if [ ! -x "$(command -v socat)" ]; then
1723		echo "socat command not found. Skipping test"
1724		return 1
1725	fi
1726
1727	return 0
1728}
1729
1730iptables_check()
1731{
1732	iptables -t mangle -L OUTPUT &> /dev/null
1733	if [ $? -ne 0 ]; then
1734		echo "iptables configuration not supported. Skipping test"
1735		return 1
1736	fi
1737
1738	return 0
1739}
1740
1741ip6tables_check()
1742{
1743	ip6tables -t mangle -L OUTPUT &> /dev/null
1744	if [ $? -ne 0 ]; then
1745		echo "ip6tables configuration not supported. Skipping test"
1746		return 1
1747	fi
1748
1749	return 0
1750}
1751
1752ipv4_mangle_test()
1753{
1754	local rc
1755
1756	echo
1757	echo "IPv4 mangling tests"
1758
1759	socat_check || return 1
1760	iptables_check || return 1
1761
1762	route_setup
1763	sleep 2
1764
1765	local tmp_file=$(mktemp)
1766	ip netns exec ns2 socat UDP4-LISTEN:54321,fork $tmp_file &
1767
1768	# Add a FIB rule and a route that will direct our connection to the
1769	# listening server.
1770	$IP rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1771	$IP route add table 123 172.16.101.0/24 dev veth1
1772
1773	# Add an unreachable route to the main table that will block our
1774	# connection in case the FIB rule is not hit.
1775	$IP route add unreachable 172.16.101.2/32
1776
1777	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1778	log_test $? 0 "    Connection with correct parameters"
1779
1780	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=11111"
1781	log_test $? 1 "    Connection with incorrect parameters"
1782
1783	# Add a mangling rule and make sure connection is still successful.
1784	$NS_EXEC iptables -t mangle -A OUTPUT -j MARK --set-mark 1
1785
1786	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1787	log_test $? 0 "    Connection with correct parameters - mangling"
1788
1789	# Delete the mangling rule and make sure connection is still
1790	# successful.
1791	$NS_EXEC iptables -t mangle -D OUTPUT -j MARK --set-mark 1
1792
1793	run_cmd "echo a | $NS_EXEC socat STDIN UDP4:172.16.101.2:54321,sourceport=12345"
1794	log_test $? 0 "    Connection with correct parameters - no mangling"
1795
1796	# Verify connections were indeed successful on server side.
1797	[[ $(cat $tmp_file | wc -l) -eq 3 ]]
1798	log_test $? 0 "    Connection check - server side"
1799
1800	$IP route del unreachable 172.16.101.2/32
1801	$IP route del table 123 172.16.101.0/24 dev veth1
1802	$IP rule del pref 100
1803
1804	{ kill %% && wait %%; } 2>/dev/null
1805	rm $tmp_file
1806
1807	route_cleanup
1808}
1809
1810ipv6_mangle_test()
1811{
1812	local rc
1813
1814	echo
1815	echo "IPv6 mangling tests"
1816
1817	socat_check || return 1
1818	ip6tables_check || return 1
1819
1820	route_setup
1821	sleep 2
1822
1823	local tmp_file=$(mktemp)
1824	ip netns exec ns2 socat UDP6-LISTEN:54321,fork $tmp_file &
1825
1826	# Add a FIB rule and a route that will direct our connection to the
1827	# listening server.
1828	$IP -6 rule add pref 100 ipproto udp sport 12345 dport 54321 table 123
1829	$IP -6 route add table 123 2001:db8:101::/64 dev veth1
1830
1831	# Add an unreachable route to the main table that will block our
1832	# connection in case the FIB rule is not hit.
1833	$IP -6 route add unreachable 2001:db8:101::2/128
1834
1835	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1836	log_test $? 0 "    Connection with correct parameters"
1837
1838	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=11111"
1839	log_test $? 1 "    Connection with incorrect parameters"
1840
1841	# Add a mangling rule and make sure connection is still successful.
1842	$NS_EXEC ip6tables -t mangle -A OUTPUT -j MARK --set-mark 1
1843
1844	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1845	log_test $? 0 "    Connection with correct parameters - mangling"
1846
1847	# Delete the mangling rule and make sure connection is still
1848	# successful.
1849	$NS_EXEC ip6tables -t mangle -D OUTPUT -j MARK --set-mark 1
1850
1851	run_cmd "echo a | $NS_EXEC socat STDIN UDP6:[2001:db8:101::2]:54321,sourceport=12345"
1852	log_test $? 0 "    Connection with correct parameters - no mangling"
1853
1854	# Verify connections were indeed successful on server side.
1855	[[ $(cat $tmp_file | wc -l) -eq 3 ]]
1856	log_test $? 0 "    Connection check - server side"
1857
1858	$IP -6 route del unreachable 2001:db8:101::2/128
1859	$IP -6 route del table 123 2001:db8:101::/64 dev veth1
1860	$IP -6 rule del pref 100
1861
1862	{ kill %% && wait %%; } 2>/dev/null
1863	rm $tmp_file
1864
1865	route_cleanup
1866}
1867
1868################################################################################
1869# usage
1870
1871usage()
1872{
1873	cat <<EOF
1874usage: ${0##*/} OPTS
1875
1876        -t <test>   Test(s) to run (default: all)
1877                    (options: $TESTS)
1878        -p          Pause on fail
1879        -P          Pause after each test before cleanup
1880        -v          verbose mode (show commands and output)
1881EOF
1882}
1883
1884################################################################################
1885# main
1886
1887while getopts :t:pPhv o
1888do
1889	case $o in
1890		t) TESTS=$OPTARG;;
1891		p) PAUSE_ON_FAIL=yes;;
1892		P) PAUSE=yes;;
1893		v) VERBOSE=$(($VERBOSE + 1));;
1894		h) usage; exit 0;;
1895		*) usage; exit 1;;
1896	esac
1897done
1898
1899PEER_CMD="ip netns exec ${PEER_NS}"
1900
1901# make sure we don't pause twice
1902[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
1903
1904if [ "$(id -u)" -ne 0 ];then
1905	echo "SKIP: Need root privileges"
1906	exit $ksft_skip;
1907fi
1908
1909if [ ! -x "$(command -v ip)" ]; then
1910	echo "SKIP: Could not run test without ip tool"
1911	exit $ksft_skip
1912fi
1913
1914ip route help 2>&1 | grep -q fibmatch
1915if [ $? -ne 0 ]; then
1916	echo "SKIP: iproute2 too old, missing fibmatch"
1917	exit $ksft_skip
1918fi
1919
1920# start clean
1921cleanup &> /dev/null
1922
1923for t in $TESTS
1924do
1925	case $t in
1926	fib_unreg_test|unregister)	fib_unreg_test;;
1927	fib_down_test|down)		fib_down_test;;
1928	fib_carrier_test|carrier)	fib_carrier_test;;
1929	fib_rp_filter_test|rp_filter)	fib_rp_filter_test;;
1930	fib_nexthop_test|nexthop)	fib_nexthop_test;;
1931	fib_suppress_test|suppress)	fib_suppress_test;;
1932	ipv6_route_test|ipv6_rt)	ipv6_route_test;;
1933	ipv4_route_test|ipv4_rt)	ipv4_route_test;;
1934	ipv6_addr_metric)		ipv6_addr_metric_test;;
1935	ipv4_addr_metric)		ipv4_addr_metric_test;;
1936	ipv4_del_addr)			ipv4_del_addr_test;;
1937	ipv6_route_metrics)		ipv6_route_metrics_test;;
1938	ipv4_route_metrics)		ipv4_route_metrics_test;;
1939	ipv4_route_v6_gw)		ipv4_route_v6_gw_test;;
1940	ipv4_mangle)			ipv4_mangle_test;;
1941	ipv6_mangle)			ipv6_mangle_test;;
1942
1943	help) echo "Test names: $TESTS"; exit 0;;
1944	esac
1945done
1946
1947if [ "$TESTS" != "none" ]; then
1948	printf "\nTests passed: %3d\n" ${nsuccess}
1949	printf "Tests failed: %3d\n"   ${nfail}
1950fi
1951
1952exit $ret
1953