xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/net/vrf_route_leaking.sh (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/bin/bash
2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0
3*4882a593Smuzhiyun#
4*4882a593Smuzhiyun# Copyright (c) 2019 David Ahern <dsahern@gmail.com>. All rights reserved.
5*4882a593Smuzhiyun# Copyright (c) 2020 Michael Jeanson <mjeanson@efficios.com>. All rights reserved.
6*4882a593Smuzhiyun#
7*4882a593Smuzhiyun# Requires CONFIG_NET_VRF, CONFIG_VETH, CONFIG_BRIDGE and CONFIG_NET_NS.
8*4882a593Smuzhiyun#
9*4882a593Smuzhiyun#
10*4882a593Smuzhiyun# Symmetric routing topology
11*4882a593Smuzhiyun#
12*4882a593Smuzhiyun#                     blue         red
13*4882a593Smuzhiyun# +----+              .253 +----+ .253              +----+
14*4882a593Smuzhiyun# | h1 |-------------------| r1 |-------------------| h2 |
15*4882a593Smuzhiyun# +----+ .1                +----+                .2 +----+
16*4882a593Smuzhiyun#         172.16.1/24                  172.16.2/24
17*4882a593Smuzhiyun#    2001:db8:16:1/64                  2001:db8:16:2/64
18*4882a593Smuzhiyun#
19*4882a593Smuzhiyun#
20*4882a593Smuzhiyun# Route from h1 to h2 and back goes through r1, incoming vrf blue has a route
21*4882a593Smuzhiyun# to the outgoing vrf red for the n2 network and red has a route back to n1.
22*4882a593Smuzhiyun# The red VRF interface has a MTU of 1400.
23*4882a593Smuzhiyun#
24*4882a593Smuzhiyun# The first test sends a ping with a ttl of 1 from h1 to h2 and parses the
25*4882a593Smuzhiyun# output of the command to check that a ttl expired error is received.
26*4882a593Smuzhiyun#
27*4882a593Smuzhiyun# The second test runs traceroute from h1 to h2 and parses the output to check
28*4882a593Smuzhiyun# for a hop on r1.
29*4882a593Smuzhiyun#
30*4882a593Smuzhiyun# The third test sends a ping with a packet size of 1450 from h1 to h2 and
31*4882a593Smuzhiyun# parses the output of the command to check that a fragmentation error is
32*4882a593Smuzhiyun# received.
33*4882a593Smuzhiyun#
34*4882a593Smuzhiyun#
35*4882a593Smuzhiyun# Asymmetric routing topology
36*4882a593Smuzhiyun#
37*4882a593Smuzhiyun# This topology represents a customer setup where the issue with icmp errors
38*4882a593Smuzhiyun# and VRF route leaking was initialy reported. The MTU test isn't done here
39*4882a593Smuzhiyun# because of the lack of a return route in the red VRF.
40*4882a593Smuzhiyun#
41*4882a593Smuzhiyun#                     blue         red
42*4882a593Smuzhiyun#                     .253 +----+ .253
43*4882a593Smuzhiyun#                     +----| r1 |----+
44*4882a593Smuzhiyun#                     |    +----+    |
45*4882a593Smuzhiyun# +----+              |              |              +----+
46*4882a593Smuzhiyun# | h1 |--------------+              +--------------| h2 |
47*4882a593Smuzhiyun# +----+ .1           |              |           .2 +----+
48*4882a593Smuzhiyun#         172.16.1/24 |    +----+    | 172.16.2/24
49*4882a593Smuzhiyun#    2001:db8:16:1/64 +----| r2 |----+ 2001:db8:16:2/64
50*4882a593Smuzhiyun#                     .254 +----+ .254
51*4882a593Smuzhiyun#
52*4882a593Smuzhiyun#
53*4882a593Smuzhiyun# Route from h1 to h2 goes through r1, incoming vrf blue has a route to the
54*4882a593Smuzhiyun# outgoing vrf red for the n2 network but red doesn't have a route back to n1.
55*4882a593Smuzhiyun# Route from h2 to h1 goes through r2.
56*4882a593Smuzhiyun#
57*4882a593Smuzhiyun# The objective is to check that the incoming vrf routing table is selected
58*4882a593Smuzhiyun# to send an ICMP error back to the source when the ttl of a packet reaches 1
59*4882a593Smuzhiyun# while it is forwarded between different vrfs.
60*4882a593Smuzhiyun
61*4882a593SmuzhiyunVERBOSE=0
62*4882a593SmuzhiyunPAUSE_ON_FAIL=no
63*4882a593SmuzhiyunDEFAULT_TTYPE=sym
64*4882a593Smuzhiyun
65*4882a593SmuzhiyunH1_N1=172.16.1.0/24
66*4882a593SmuzhiyunH1_N1_6=2001:db8:16:1::/64
67*4882a593Smuzhiyun
68*4882a593SmuzhiyunH1_N1_IP=172.16.1.1
69*4882a593SmuzhiyunR1_N1_IP=172.16.1.253
70*4882a593SmuzhiyunR2_N1_IP=172.16.1.254
71*4882a593Smuzhiyun
72*4882a593SmuzhiyunH1_N1_IP6=2001:db8:16:1::1
73*4882a593SmuzhiyunR1_N1_IP6=2001:db8:16:1::253
74*4882a593SmuzhiyunR2_N1_IP6=2001:db8:16:1::254
75*4882a593Smuzhiyun
76*4882a593SmuzhiyunH2_N2=172.16.2.0/24
77*4882a593SmuzhiyunH2_N2_6=2001:db8:16:2::/64
78*4882a593Smuzhiyun
79*4882a593SmuzhiyunH2_N2_IP=172.16.2.2
80*4882a593SmuzhiyunR1_N2_IP=172.16.2.253
81*4882a593SmuzhiyunR2_N2_IP=172.16.2.254
82*4882a593Smuzhiyun
83*4882a593SmuzhiyunH2_N2_IP6=2001:db8:16:2::2
84*4882a593SmuzhiyunR1_N2_IP6=2001:db8:16:2::253
85*4882a593SmuzhiyunR2_N2_IP6=2001:db8:16:2::254
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun################################################################################
88*4882a593Smuzhiyun# helpers
89*4882a593Smuzhiyun
90*4882a593Smuzhiyunlog_section()
91*4882a593Smuzhiyun{
92*4882a593Smuzhiyun	echo
93*4882a593Smuzhiyun	echo "###########################################################################"
94*4882a593Smuzhiyun	echo "$*"
95*4882a593Smuzhiyun	echo "###########################################################################"
96*4882a593Smuzhiyun	echo
97*4882a593Smuzhiyun}
98*4882a593Smuzhiyun
99*4882a593Smuzhiyunlog_test()
100*4882a593Smuzhiyun{
101*4882a593Smuzhiyun	local rc=$1
102*4882a593Smuzhiyun	local expected=$2
103*4882a593Smuzhiyun	local msg="$3"
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun	if [ "${rc}" -eq "${expected}" ]; then
106*4882a593Smuzhiyun		printf "TEST: %-60s  [ OK ]\n" "${msg}"
107*4882a593Smuzhiyun		nsuccess=$((nsuccess+1))
108*4882a593Smuzhiyun	else
109*4882a593Smuzhiyun		ret=1
110*4882a593Smuzhiyun		nfail=$((nfail+1))
111*4882a593Smuzhiyun		printf "TEST: %-60s  [FAIL]\n" "${msg}"
112*4882a593Smuzhiyun		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
113*4882a593Smuzhiyun			echo
114*4882a593Smuzhiyun			echo "hit enter to continue, 'q' to quit"
115*4882a593Smuzhiyun			read -r a
116*4882a593Smuzhiyun			[ "$a" = "q" ] && exit 1
117*4882a593Smuzhiyun		fi
118*4882a593Smuzhiyun	fi
119*4882a593Smuzhiyun}
120*4882a593Smuzhiyun
121*4882a593Smuzhiyunrun_cmd()
122*4882a593Smuzhiyun{
123*4882a593Smuzhiyun	local cmd="$*"
124*4882a593Smuzhiyun	local out
125*4882a593Smuzhiyun	local rc
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun	if [ "$VERBOSE" = "1" ]; then
128*4882a593Smuzhiyun		echo "COMMAND: $cmd"
129*4882a593Smuzhiyun	fi
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun	# shellcheck disable=SC2086
132*4882a593Smuzhiyun	out=$(eval $cmd 2>&1)
133*4882a593Smuzhiyun	rc=$?
134*4882a593Smuzhiyun	if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then
135*4882a593Smuzhiyun		echo "$out"
136*4882a593Smuzhiyun	fi
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun	[ "$VERBOSE" = "1" ] && echo
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun	return $rc
141*4882a593Smuzhiyun}
142*4882a593Smuzhiyun
143*4882a593Smuzhiyunrun_cmd_grep()
144*4882a593Smuzhiyun{
145*4882a593Smuzhiyun	local grep_pattern="$1"
146*4882a593Smuzhiyun	shift
147*4882a593Smuzhiyun	local cmd="$*"
148*4882a593Smuzhiyun	local out
149*4882a593Smuzhiyun	local rc
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun	if [ "$VERBOSE" = "1" ]; then
152*4882a593Smuzhiyun		echo "COMMAND: $cmd"
153*4882a593Smuzhiyun	fi
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun	# shellcheck disable=SC2086
156*4882a593Smuzhiyun	out=$(eval $cmd 2>&1)
157*4882a593Smuzhiyun	if [ "$VERBOSE" = "1" ] && [ -n "$out" ]; then
158*4882a593Smuzhiyun		echo "$out"
159*4882a593Smuzhiyun	fi
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun	echo "$out" | grep -q "$grep_pattern"
162*4882a593Smuzhiyun	rc=$?
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun	[ "$VERBOSE" = "1" ] && echo
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun	return $rc
167*4882a593Smuzhiyun}
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun################################################################################
170*4882a593Smuzhiyun# setup and teardown
171*4882a593Smuzhiyun
172*4882a593Smuzhiyuncleanup()
173*4882a593Smuzhiyun{
174*4882a593Smuzhiyun	local ns
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun	for ns in h1 h2 r1 r2; do
177*4882a593Smuzhiyun		ip netns del $ns 2>/dev/null
178*4882a593Smuzhiyun	done
179*4882a593Smuzhiyun}
180*4882a593Smuzhiyun
181*4882a593Smuzhiyunsetup_vrf()
182*4882a593Smuzhiyun{
183*4882a593Smuzhiyun	local ns=$1
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun	ip -netns "${ns}" rule del pref 0
186*4882a593Smuzhiyun	ip -netns "${ns}" rule add pref 32765 from all lookup local
187*4882a593Smuzhiyun	ip -netns "${ns}" -6 rule del pref 0
188*4882a593Smuzhiyun	ip -netns "${ns}" -6 rule add pref 32765 from all lookup local
189*4882a593Smuzhiyun}
190*4882a593Smuzhiyun
191*4882a593Smuzhiyuncreate_vrf()
192*4882a593Smuzhiyun{
193*4882a593Smuzhiyun	local ns=$1
194*4882a593Smuzhiyun	local vrf=$2
195*4882a593Smuzhiyun	local table=$3
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun	ip -netns "${ns}" link add "${vrf}" type vrf table "${table}"
198*4882a593Smuzhiyun	ip -netns "${ns}" link set "${vrf}" up
199*4882a593Smuzhiyun	ip -netns "${ns}" route add vrf "${vrf}" unreachable default metric 8192
200*4882a593Smuzhiyun	ip -netns "${ns}" -6 route add vrf "${vrf}" unreachable default metric 8192
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun	ip -netns "${ns}" addr add 127.0.0.1/8 dev "${vrf}"
203*4882a593Smuzhiyun	ip -netns "${ns}" -6 addr add ::1 dev "${vrf}" nodad
204*4882a593Smuzhiyun}
205*4882a593Smuzhiyun
206*4882a593Smuzhiyunsetup_sym()
207*4882a593Smuzhiyun{
208*4882a593Smuzhiyun	local ns
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun	# make sure we are starting with a clean slate
211*4882a593Smuzhiyun	cleanup
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun	#
214*4882a593Smuzhiyun	# create nodes as namespaces
215*4882a593Smuzhiyun	#
216*4882a593Smuzhiyun	for ns in h1 h2 r1; do
217*4882a593Smuzhiyun		ip netns add $ns
218*4882a593Smuzhiyun		ip -netns $ns link set lo up
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun		case "${ns}" in
221*4882a593Smuzhiyun		h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
222*4882a593Smuzhiyun		       ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
223*4882a593Smuzhiyun			;;
224*4882a593Smuzhiyun		r1)    ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
225*4882a593Smuzhiyun		       ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
226*4882a593Smuzhiyun		esac
227*4882a593Smuzhiyun	done
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun	#
230*4882a593Smuzhiyun	# create interconnects
231*4882a593Smuzhiyun	#
232*4882a593Smuzhiyun	ip -netns h1 link add eth0 type veth peer name r1h1
233*4882a593Smuzhiyun	ip -netns h1 link set r1h1 netns r1 name eth0 up
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun	ip -netns h2 link add eth0 type veth peer name r1h2
236*4882a593Smuzhiyun	ip -netns h2 link set r1h2 netns r1 name eth1 up
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun	#
239*4882a593Smuzhiyun	# h1
240*4882a593Smuzhiyun	#
241*4882a593Smuzhiyun	ip -netns h1 addr add dev eth0 ${H1_N1_IP}/24
242*4882a593Smuzhiyun	ip -netns h1 -6 addr add dev eth0 ${H1_N1_IP6}/64 nodad
243*4882a593Smuzhiyun	ip -netns h1 link set eth0 up
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun	# h1 to h2 via r1
246*4882a593Smuzhiyun	ip -netns h1    route add ${H2_N2} via ${R1_N1_IP} dev eth0
247*4882a593Smuzhiyun	ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev eth0
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun	#
250*4882a593Smuzhiyun	# h2
251*4882a593Smuzhiyun	#
252*4882a593Smuzhiyun	ip -netns h2 addr add dev eth0 ${H2_N2_IP}/24
253*4882a593Smuzhiyun	ip -netns h2 -6 addr add dev eth0 ${H2_N2_IP6}/64 nodad
254*4882a593Smuzhiyun	ip -netns h2 link set eth0 up
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun	# h2 to h1 via r1
257*4882a593Smuzhiyun	ip -netns h2 route add default via ${R1_N2_IP} dev eth0
258*4882a593Smuzhiyun	ip -netns h2 -6 route add default via ${R1_N2_IP6} dev eth0
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun	#
261*4882a593Smuzhiyun	# r1
262*4882a593Smuzhiyun	#
263*4882a593Smuzhiyun	setup_vrf r1
264*4882a593Smuzhiyun	create_vrf r1 blue 1101
265*4882a593Smuzhiyun	create_vrf r1 red 1102
266*4882a593Smuzhiyun	ip -netns r1 link set mtu 1400 dev eth1
267*4882a593Smuzhiyun	ip -netns r1 link set eth0 vrf blue up
268*4882a593Smuzhiyun	ip -netns r1 link set eth1 vrf red up
269*4882a593Smuzhiyun	ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
270*4882a593Smuzhiyun	ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
271*4882a593Smuzhiyun	ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
272*4882a593Smuzhiyun	ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun	# Route leak from blue to red
275*4882a593Smuzhiyun	ip -netns r1 route add vrf blue ${H2_N2} dev red
276*4882a593Smuzhiyun	ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun	# Route leak from red to blue
279*4882a593Smuzhiyun	ip -netns r1 route add vrf red ${H1_N1} dev blue
280*4882a593Smuzhiyun	ip -netns r1 -6 route add vrf red ${H1_N1_6} dev blue
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun	# Wait for ip config to settle
284*4882a593Smuzhiyun	sleep 2
285*4882a593Smuzhiyun}
286*4882a593Smuzhiyun
287*4882a593Smuzhiyunsetup_asym()
288*4882a593Smuzhiyun{
289*4882a593Smuzhiyun	local ns
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun	# make sure we are starting with a clean slate
292*4882a593Smuzhiyun	cleanup
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun	#
295*4882a593Smuzhiyun	# create nodes as namespaces
296*4882a593Smuzhiyun	#
297*4882a593Smuzhiyun	for ns in h1 h2 r1 r2; do
298*4882a593Smuzhiyun		ip netns add $ns
299*4882a593Smuzhiyun		ip -netns $ns link set lo up
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun		case "${ns}" in
302*4882a593Smuzhiyun		h[12]) ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=0
303*4882a593Smuzhiyun		       ip netns exec $ns sysctl -q -w net.ipv6.conf.all.keep_addr_on_down=1
304*4882a593Smuzhiyun			;;
305*4882a593Smuzhiyun		r[12]) ip netns exec $ns sysctl -q -w net.ipv4.ip_forward=1
306*4882a593Smuzhiyun		       ip netns exec $ns sysctl -q -w net.ipv6.conf.all.forwarding=1
307*4882a593Smuzhiyun		esac
308*4882a593Smuzhiyun	done
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun	#
311*4882a593Smuzhiyun	# create interconnects
312*4882a593Smuzhiyun	#
313*4882a593Smuzhiyun	ip -netns h1 link add eth0 type veth peer name r1h1
314*4882a593Smuzhiyun	ip -netns h1 link set r1h1 netns r1 name eth0 up
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun	ip -netns h1 link add eth1 type veth peer name r2h1
317*4882a593Smuzhiyun	ip -netns h1 link set r2h1 netns r2 name eth0 up
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun	ip -netns h2 link add eth0 type veth peer name r1h2
320*4882a593Smuzhiyun	ip -netns h2 link set r1h2 netns r1 name eth1 up
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun	ip -netns h2 link add eth1 type veth peer name r2h2
323*4882a593Smuzhiyun	ip -netns h2 link set r2h2 netns r2 name eth1 up
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun	#
326*4882a593Smuzhiyun	# h1
327*4882a593Smuzhiyun	#
328*4882a593Smuzhiyun	ip -netns h1 link add br0 type bridge
329*4882a593Smuzhiyun	ip -netns h1 link set br0 up
330*4882a593Smuzhiyun	ip -netns h1 addr add dev br0 ${H1_N1_IP}/24
331*4882a593Smuzhiyun	ip -netns h1 -6 addr add dev br0 ${H1_N1_IP6}/64 nodad
332*4882a593Smuzhiyun	ip -netns h1 link set eth0 master br0 up
333*4882a593Smuzhiyun	ip -netns h1 link set eth1 master br0 up
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun	# h1 to h2 via r1
336*4882a593Smuzhiyun	ip -netns h1    route add ${H2_N2} via ${R1_N1_IP} dev br0
337*4882a593Smuzhiyun	ip -netns h1 -6 route add ${H2_N2_6} via "${R1_N1_IP6}" dev br0
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun	#
340*4882a593Smuzhiyun	# h2
341*4882a593Smuzhiyun	#
342*4882a593Smuzhiyun	ip -netns h2 link add br0 type bridge
343*4882a593Smuzhiyun	ip -netns h2 link set br0 up
344*4882a593Smuzhiyun	ip -netns h2 addr add dev br0 ${H2_N2_IP}/24
345*4882a593Smuzhiyun	ip -netns h2 -6 addr add dev br0 ${H2_N2_IP6}/64 nodad
346*4882a593Smuzhiyun	ip -netns h2 link set eth0 master br0 up
347*4882a593Smuzhiyun	ip -netns h2 link set eth1 master br0 up
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun	# h2 to h1 via r2
350*4882a593Smuzhiyun	ip -netns h2 route add default via ${R2_N2_IP} dev br0
351*4882a593Smuzhiyun	ip -netns h2 -6 route add default via ${R2_N2_IP6} dev br0
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun	#
354*4882a593Smuzhiyun	# r1
355*4882a593Smuzhiyun	#
356*4882a593Smuzhiyun	setup_vrf r1
357*4882a593Smuzhiyun	create_vrf r1 blue 1101
358*4882a593Smuzhiyun	create_vrf r1 red 1102
359*4882a593Smuzhiyun	ip -netns r1 link set mtu 1400 dev eth1
360*4882a593Smuzhiyun	ip -netns r1 link set eth0 vrf blue up
361*4882a593Smuzhiyun	ip -netns r1 link set eth1 vrf red up
362*4882a593Smuzhiyun	ip -netns r1 addr add dev eth0 ${R1_N1_IP}/24
363*4882a593Smuzhiyun	ip -netns r1 -6 addr add dev eth0 ${R1_N1_IP6}/64 nodad
364*4882a593Smuzhiyun	ip -netns r1 addr add dev eth1 ${R1_N2_IP}/24
365*4882a593Smuzhiyun	ip -netns r1 -6 addr add dev eth1 ${R1_N2_IP6}/64 nodad
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun	# Route leak from blue to red
368*4882a593Smuzhiyun	ip -netns r1 route add vrf blue ${H2_N2} dev red
369*4882a593Smuzhiyun	ip -netns r1 -6 route add vrf blue ${H2_N2_6} dev red
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun	# No route leak from red to blue
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun	#
374*4882a593Smuzhiyun	# r2
375*4882a593Smuzhiyun	#
376*4882a593Smuzhiyun	ip -netns r2 addr add dev eth0 ${R2_N1_IP}/24
377*4882a593Smuzhiyun	ip -netns r2 -6 addr add dev eth0 ${R2_N1_IP6}/64 nodad
378*4882a593Smuzhiyun	ip -netns r2 addr add dev eth1 ${R2_N2_IP}/24
379*4882a593Smuzhiyun	ip -netns r2 -6 addr add dev eth1 ${R2_N2_IP6}/64 nodad
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun	# Wait for ip config to settle
382*4882a593Smuzhiyun	sleep 2
383*4882a593Smuzhiyun}
384*4882a593Smuzhiyun
385*4882a593Smuzhiyuncheck_connectivity()
386*4882a593Smuzhiyun{
387*4882a593Smuzhiyun	ip netns exec h1 ping -c1 -w1 ${H2_N2_IP} >/dev/null 2>&1
388*4882a593Smuzhiyun	log_test $? 0 "Basic IPv4 connectivity"
389*4882a593Smuzhiyun	return $?
390*4882a593Smuzhiyun}
391*4882a593Smuzhiyun
392*4882a593Smuzhiyuncheck_connectivity6()
393*4882a593Smuzhiyun{
394*4882a593Smuzhiyun	ip netns exec h1 "${ping6}" -c1 -w1 ${H2_N2_IP6} >/dev/null 2>&1
395*4882a593Smuzhiyun	log_test $? 0 "Basic IPv6 connectivity"
396*4882a593Smuzhiyun	return $?
397*4882a593Smuzhiyun}
398*4882a593Smuzhiyun
399*4882a593Smuzhiyuncheck_traceroute()
400*4882a593Smuzhiyun{
401*4882a593Smuzhiyun	if [ ! -x "$(command -v traceroute)" ]; then
402*4882a593Smuzhiyun		echo "SKIP: Could not run IPV4 test without traceroute"
403*4882a593Smuzhiyun		return 1
404*4882a593Smuzhiyun	fi
405*4882a593Smuzhiyun}
406*4882a593Smuzhiyun
407*4882a593Smuzhiyuncheck_traceroute6()
408*4882a593Smuzhiyun{
409*4882a593Smuzhiyun	if [ ! -x "$(command -v traceroute6)" ]; then
410*4882a593Smuzhiyun		echo "SKIP: Could not run IPV6 test without traceroute6"
411*4882a593Smuzhiyun		return 1
412*4882a593Smuzhiyun	fi
413*4882a593Smuzhiyun}
414*4882a593Smuzhiyun
415*4882a593Smuzhiyunipv4_traceroute()
416*4882a593Smuzhiyun{
417*4882a593Smuzhiyun	local ttype="$1"
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun	log_section "IPv4 ($ttype route): VRF ICMP error route lookup traceroute"
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun	check_traceroute || return
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun	setup_"$ttype"
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun	check_connectivity || return
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun	run_cmd_grep "${R1_N1_IP}" ip netns exec h1 traceroute ${H2_N2_IP}
430*4882a593Smuzhiyun	log_test $? 0 "Traceroute reports a hop on r1"
431*4882a593Smuzhiyun}
432*4882a593Smuzhiyun
433*4882a593Smuzhiyunipv4_traceroute_asym()
434*4882a593Smuzhiyun{
435*4882a593Smuzhiyun	ipv4_traceroute asym
436*4882a593Smuzhiyun}
437*4882a593Smuzhiyun
438*4882a593Smuzhiyunipv6_traceroute()
439*4882a593Smuzhiyun{
440*4882a593Smuzhiyun	local ttype="$1"
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun	log_section "IPv6 ($ttype route): VRF ICMP error route lookup traceroute"
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun	check_traceroute6 || return
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun	setup_"$ttype"
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun	check_connectivity6 || return
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun	run_cmd_grep "${R1_N1_IP6}" ip netns exec h1 traceroute6 ${H2_N2_IP6}
453*4882a593Smuzhiyun	log_test $? 0 "Traceroute6 reports a hop on r1"
454*4882a593Smuzhiyun}
455*4882a593Smuzhiyun
456*4882a593Smuzhiyunipv6_traceroute_asym()
457*4882a593Smuzhiyun{
458*4882a593Smuzhiyun	ipv6_traceroute asym
459*4882a593Smuzhiyun}
460*4882a593Smuzhiyun
461*4882a593Smuzhiyunipv4_ping_ttl()
462*4882a593Smuzhiyun{
463*4882a593Smuzhiyun	local ttype="$1"
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun	log_section "IPv4 ($ttype route): VRF ICMP ttl error route lookup ping"
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun	setup_"$ttype"
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun	check_connectivity || return
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun	run_cmd_grep "Time to live exceeded" ip netns exec h1 ping -t1 -c1 -W2 ${H2_N2_IP}
474*4882a593Smuzhiyun	log_test $? 0 "Ping received ICMP ttl exceeded"
475*4882a593Smuzhiyun}
476*4882a593Smuzhiyun
477*4882a593Smuzhiyunipv4_ping_ttl_asym()
478*4882a593Smuzhiyun{
479*4882a593Smuzhiyun	ipv4_ping_ttl asym
480*4882a593Smuzhiyun}
481*4882a593Smuzhiyun
482*4882a593Smuzhiyunipv4_ping_frag()
483*4882a593Smuzhiyun{
484*4882a593Smuzhiyun	local ttype="$1"
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun	log_section "IPv4 ($ttype route): VRF ICMP fragmentation error route lookup ping"
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun	setup_"$ttype"
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun	check_connectivity || return
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun	run_cmd_grep "Frag needed" ip netns exec h1 ping -s 1450 -Mdo -c1 -W2 ${H2_N2_IP}
495*4882a593Smuzhiyun	log_test $? 0 "Ping received ICMP Frag needed"
496*4882a593Smuzhiyun}
497*4882a593Smuzhiyun
498*4882a593Smuzhiyunipv4_ping_frag_asym()
499*4882a593Smuzhiyun{
500*4882a593Smuzhiyun	ipv4_ping_frag asym
501*4882a593Smuzhiyun}
502*4882a593Smuzhiyun
503*4882a593Smuzhiyunipv6_ping_ttl()
504*4882a593Smuzhiyun{
505*4882a593Smuzhiyun	local ttype="$1"
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun	log_section "IPv6 ($ttype route): VRF ICMP ttl error route lookup ping"
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun	setup_"$ttype"
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun	check_connectivity6 || return
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun	run_cmd_grep "Time exceeded: Hop limit" ip netns exec h1 "${ping6}" -t1 -c1 -W2 ${H2_N2_IP6}
516*4882a593Smuzhiyun	log_test $? 0 "Ping received ICMP Hop limit"
517*4882a593Smuzhiyun}
518*4882a593Smuzhiyun
519*4882a593Smuzhiyunipv6_ping_ttl_asym()
520*4882a593Smuzhiyun{
521*4882a593Smuzhiyun	ipv6_ping_ttl asym
522*4882a593Smuzhiyun}
523*4882a593Smuzhiyun
524*4882a593Smuzhiyunipv6_ping_frag()
525*4882a593Smuzhiyun{
526*4882a593Smuzhiyun	local ttype="$1"
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun	[ "x$ttype" = "x" ] && ttype="$DEFAULT_TTYPE"
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun	log_section "IPv6 ($ttype route): VRF ICMP fragmentation error route lookup ping"
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun	setup_"$ttype"
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun	check_connectivity6 || return
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun	run_cmd_grep "Packet too big" ip netns exec h1 "${ping6}" -s 1450 -Mdo -c1 -W2 ${H2_N2_IP6}
537*4882a593Smuzhiyun	log_test $? 0 "Ping received ICMP Packet too big"
538*4882a593Smuzhiyun}
539*4882a593Smuzhiyun
540*4882a593Smuzhiyunipv6_ping_frag_asym()
541*4882a593Smuzhiyun{
542*4882a593Smuzhiyun	ipv6_ping_frag asym
543*4882a593Smuzhiyun}
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun################################################################################
546*4882a593Smuzhiyun# usage
547*4882a593Smuzhiyun
548*4882a593Smuzhiyunusage()
549*4882a593Smuzhiyun{
550*4882a593Smuzhiyun        cat <<EOF
551*4882a593Smuzhiyunusage: ${0##*/} OPTS
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun	-4          Run IPv4 tests only
554*4882a593Smuzhiyun	-6          Run IPv6 tests only
555*4882a593Smuzhiyun        -t TEST     Run only TEST
556*4882a593Smuzhiyun	-p          Pause on fail
557*4882a593Smuzhiyun	-v          verbose mode (show commands and output)
558*4882a593SmuzhiyunEOF
559*4882a593Smuzhiyun}
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun################################################################################
562*4882a593Smuzhiyun# main
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun# Some systems don't have a ping6 binary anymore
565*4882a593Smuzhiyuncommand -v ping6 > /dev/null 2>&1 && ping6=$(command -v ping6) || ping6=$(command -v ping)
566*4882a593Smuzhiyun
567*4882a593SmuzhiyunTESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_ttl_asym ipv4_traceroute_asym"
568*4882a593SmuzhiyunTESTS_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_frag ipv6_ping_ttl_asym ipv6_traceroute_asym"
569*4882a593Smuzhiyun
570*4882a593Smuzhiyunret=0
571*4882a593Smuzhiyunnsuccess=0
572*4882a593Smuzhiyunnfail=0
573*4882a593Smuzhiyun
574*4882a593Smuzhiyunwhile getopts :46t:pvh o
575*4882a593Smuzhiyundo
576*4882a593Smuzhiyun	case $o in
577*4882a593Smuzhiyun		4) TESTS=ipv4;;
578*4882a593Smuzhiyun		6) TESTS=ipv6;;
579*4882a593Smuzhiyun		t) TESTS=$OPTARG;;
580*4882a593Smuzhiyun		p) PAUSE_ON_FAIL=yes;;
581*4882a593Smuzhiyun		v) VERBOSE=1;;
582*4882a593Smuzhiyun		h) usage; exit 0;;
583*4882a593Smuzhiyun		*) usage; exit 1;;
584*4882a593Smuzhiyun	esac
585*4882a593Smuzhiyundone
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun#
588*4882a593Smuzhiyun# show user test config
589*4882a593Smuzhiyun#
590*4882a593Smuzhiyunif [ -z "$TESTS" ]; then
591*4882a593Smuzhiyun        TESTS="$TESTS_IPV4 $TESTS_IPV6"
592*4882a593Smuzhiyunelif [ "$TESTS" = "ipv4" ]; then
593*4882a593Smuzhiyun        TESTS="$TESTS_IPV4"
594*4882a593Smuzhiyunelif [ "$TESTS" = "ipv6" ]; then
595*4882a593Smuzhiyun        TESTS="$TESTS_IPV6"
596*4882a593Smuzhiyunfi
597*4882a593Smuzhiyun
598*4882a593Smuzhiyunfor t in $TESTS
599*4882a593Smuzhiyundo
600*4882a593Smuzhiyun	case $t in
601*4882a593Smuzhiyun	ipv4_ping_ttl|ping)              ipv4_ping_ttl;;&
602*4882a593Smuzhiyun	ipv4_ping_ttl_asym|ping)         ipv4_ping_ttl_asym;;&
603*4882a593Smuzhiyun	ipv4_traceroute|traceroute)      ipv4_traceroute;;&
604*4882a593Smuzhiyun	ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;&
605*4882a593Smuzhiyun	ipv4_ping_frag|ping)             ipv4_ping_frag;;&
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun	ipv6_ping_ttl|ping)              ipv6_ping_ttl;;&
608*4882a593Smuzhiyun	ipv6_ping_ttl_asym|ping)         ipv6_ping_ttl_asym;;&
609*4882a593Smuzhiyun	ipv6_traceroute|traceroute)      ipv6_traceroute;;&
610*4882a593Smuzhiyun	ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;&
611*4882a593Smuzhiyun	ipv6_ping_frag|ping)             ipv6_ping_frag;;&
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun	# setup namespaces and config, but do not run any tests
614*4882a593Smuzhiyun	setup_sym|setup)                 setup_sym; exit 0;;
615*4882a593Smuzhiyun	setup_asym)                      setup_asym; exit 0;;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun	help)                       echo "Test names: $TESTS"; exit 0;;
618*4882a593Smuzhiyun	esac
619*4882a593Smuzhiyundone
620*4882a593Smuzhiyun
621*4882a593Smuzhiyuncleanup
622*4882a593Smuzhiyun
623*4882a593Smuzhiyunprintf "\nTests passed: %3d\n" ${nsuccess}
624*4882a593Smuzhiyunprintf "Tests failed: %3d\n"   ${nfail}
625*4882a593Smuzhiyun
626*4882a593Smuzhiyunexit $ret
627