1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Various combinations of VRF with xfrms and qdisc.
5
6source lib.sh
7PAUSE_ON_FAIL=no
8VERBOSE=0
9ret=0
10
11HOST1_4=192.168.1.1
12HOST2_4=192.168.1.2
13HOST1_6=2001:db8:1::1
14HOST2_6=2001:db8:1::2
15
16XFRM1_4=10.0.1.1
17XFRM2_4=10.0.1.2
18XFRM1_6=fc00:1000::1
19XFRM2_6=fc00:1000::2
20IF_ID=123
21
22VRF=red
23TABLE=300
24
25AUTH_1=0xd94fcfea65fddf21dc6e0d24a0253508
26AUTH_2=0xdc6e0d24a0253508d94fcfea65fddf21
27ENC_1=0xfc46c20f8048be9725930ff3fb07ac2a91f0347dffeacf62
28ENC_2=0x3fb07ac2a91f0347dffeacf62fc46c20f8048be9725930ff
29SPI_1=0x02122b77
30SPI_2=0x2b770212
31
32which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
33
34################################################################################
35#
36log_test()
37{
38	local rc=$1
39	local expected=$2
40	local msg="$3"
41
42	if [ ${rc} -eq ${expected} ]; then
43		printf "TEST: %-60s  [ OK ]\n" "${msg}"
44		nsuccess=$((nsuccess+1))
45	else
46		ret=1
47		nfail=$((nfail+1))
48		printf "TEST: %-60s  [FAIL]\n" "${msg}"
49		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
50			echo
51			echo "hit enter to continue, 'q' to quit"
52			read a
53			[ "$a" = "q" ] && exit 1
54		fi
55	fi
56}
57
58run_cmd_host1()
59{
60	local cmd="$*"
61	local out
62	local rc
63
64	if [ "$VERBOSE" = "1" ]; then
65		printf "    COMMAND: $cmd\n"
66	fi
67
68	out=$(eval ip netns exec $host1 $cmd 2>&1)
69	rc=$?
70	if [ "$VERBOSE" = "1" ]; then
71		if [ -n "$out" ]; then
72			echo
73			echo "    $out"
74		fi
75		echo
76	fi
77
78	return $rc
79}
80
81################################################################################
82# create namespaces for hosts and sws
83
84create_vrf()
85{
86	local ns=$1
87	local vrf=$2
88	local table=$3
89
90	if [ -n "${ns}" ]; then
91		ns="-netns ${ns}"
92	fi
93
94	ip ${ns} link add ${vrf} type vrf table ${table}
95	ip ${ns} link set ${vrf} up
96	ip ${ns} route add vrf ${vrf} unreachable default metric 8192
97	ip ${ns} -6 route add vrf ${vrf} unreachable default metric 8192
98
99	ip ${ns} addr add 127.0.0.1/8 dev ${vrf}
100	ip ${ns} -6 addr add ::1 dev ${vrf} nodad
101
102	ip ${ns} ru del pref 0
103	ip ${ns} ru add pref 32765 from all lookup local
104	ip ${ns} -6 ru del pref 0
105	ip ${ns} -6 ru add pref 32765 from all lookup local
106}
107
108create_ns()
109{
110	local ns=$1
111	local addr=$2
112	local addr6=$3
113
114	[ -z "${addr}" ] && addr="-"
115	[ -z "${addr6}" ] && addr6="-"
116
117	if [ "${addr}" != "-" ]; then
118		ip -netns ${ns} addr add dev lo ${addr}
119	fi
120	if [ "${addr6}" != "-" ]; then
121		ip -netns ${ns} -6 addr add dev lo ${addr6}
122	fi
123
124	ip -netns ${ns} ro add unreachable default metric 8192
125	ip -netns ${ns} -6 ro add unreachable default metric 8192
126
127	ip netns exec ${ns} sysctl -qw net.ipv4.ip_forward=1
128	ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.keep_addr_on_down=1
129	ip netns exec ${ns} sysctl -qw net.ipv6.conf.all.forwarding=1
130	ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.forwarding=1
131	ip netns exec ${ns} sysctl -qw net.ipv6.conf.default.accept_dad=0
132}
133
134# create veth pair to connect namespaces and apply addresses.
135connect_ns()
136{
137	local ns1=$1
138	local ns1_dev=$2
139	local ns1_addr=$3
140	local ns1_addr6=$4
141	local ns2=$5
142	local ns2_dev=$6
143	local ns2_addr=$7
144	local ns2_addr6=$8
145	local ns1arg
146	local ns2arg
147
148	if [ -n "${ns1}" ]; then
149		ns1arg="-netns ${ns1}"
150	fi
151	if [ -n "${ns2}" ]; then
152		ns2arg="-netns ${ns2}"
153	fi
154
155	ip ${ns1arg} li add ${ns1_dev} type veth peer name tmp
156	ip ${ns1arg} li set ${ns1_dev} up
157	ip ${ns1arg} li set tmp netns ${ns2} name ${ns2_dev}
158	ip ${ns2arg} li set ${ns2_dev} up
159
160	if [ "${ns1_addr}" != "-" ]; then
161		ip ${ns1arg} addr add dev ${ns1_dev} ${ns1_addr}
162		ip ${ns2arg} addr add dev ${ns2_dev} ${ns2_addr}
163	fi
164
165	if [ "${ns1_addr6}" != "-" ]; then
166		ip ${ns1arg} addr add dev ${ns1_dev} ${ns1_addr6} nodad
167		ip ${ns2arg} addr add dev ${ns2_dev} ${ns2_addr6} nodad
168	fi
169}
170
171################################################################################
172
173cleanup()
174{
175	cleanup_ns $host1 $host2
176}
177
178setup()
179{
180	setup_ns host1 host2
181	create_ns "$host1"
182	create_ns "$host2"
183
184	connect_ns "$host1" eth0 ${HOST1_4}/24 ${HOST1_6}/64 \
185	           "$host2" eth0 ${HOST2_4}/24 ${HOST2_6}/64
186
187	create_vrf "$host1" ${VRF} ${TABLE}
188	ip -netns $host1 link set dev eth0 master ${VRF}
189}
190
191cleanup_xfrm()
192{
193	for ns in $host1 $host2
194	do
195		for x in state policy
196		do
197			ip -netns ${ns} xfrm ${x} flush
198			ip -6 -netns ${ns} xfrm ${x} flush
199		done
200	done
201}
202
203setup_xfrm()
204{
205	local h1_4=$1
206	local h2_4=$2
207	local h1_6=$3
208	local h2_6=$4
209	local devarg="$5"
210
211	#
212	# policy
213	#
214
215	# host1 - IPv4 out
216	ip -netns $host1 xfrm policy add \
217	  src ${h1_4} dst ${h2_4} ${devarg} dir out \
218	  tmpl src ${HOST1_4} dst ${HOST2_4} proto esp mode tunnel
219
220	# host2 - IPv4 in
221	ip -netns $host2 xfrm policy add \
222	  src ${h1_4} dst ${h2_4} dir in \
223	  tmpl src ${HOST1_4} dst ${HOST2_4} proto esp mode tunnel
224
225	# host1 - IPv4 in
226	ip -netns $host1 xfrm policy add \
227	  src ${h2_4} dst ${h1_4} ${devarg} dir in \
228	  tmpl src ${HOST2_4} dst ${HOST1_4} proto esp mode tunnel
229
230	# host2 - IPv4 out
231	ip -netns $host2 xfrm policy add \
232	  src ${h2_4} dst ${h1_4} dir out \
233	  tmpl src ${HOST2_4} dst ${HOST1_4} proto esp mode tunnel
234
235
236	# host1 - IPv6 out
237	ip -6 -netns $host1 xfrm policy add \
238	  src ${h1_6} dst ${h2_6} ${devarg} dir out \
239	  tmpl src ${HOST1_6} dst ${HOST2_6} proto esp mode tunnel
240
241	# host2 - IPv6 in
242	ip -6 -netns $host2 xfrm policy add \
243	  src ${h1_6} dst ${h2_6} dir in \
244	  tmpl src ${HOST1_6} dst ${HOST2_6} proto esp mode tunnel
245
246	# host1 - IPv6 in
247	ip -6 -netns $host1 xfrm policy add \
248	  src ${h2_6} dst ${h1_6} ${devarg} dir in \
249	  tmpl src ${HOST2_6} dst ${HOST1_6} proto esp mode tunnel
250
251	# host2 - IPv6 out
252	ip -6 -netns $host2 xfrm policy add \
253	  src ${h2_6} dst ${h1_6} dir out \
254	  tmpl src ${HOST2_6} dst ${HOST1_6} proto esp mode tunnel
255
256	#
257	# state
258	#
259	ip -netns $host1 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
260	    proto esp spi ${SPI_1} reqid 0 mode tunnel \
261	    replay-window 4 replay-oseq 0x4 \
262	    auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
263	    enc 'cbc(aes)' ${ENC_1} \
264	    sel src ${h1_4} dst ${h2_4} ${devarg}
265
266	ip -netns $host2 xfrm state add src ${HOST1_4} dst ${HOST2_4} \
267	    proto esp spi ${SPI_1} reqid 0 mode tunnel \
268	    replay-window 4 replay-oseq 0x4 \
269	    auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
270	    enc 'cbc(aes)' ${ENC_1} \
271	    sel src ${h1_4} dst ${h2_4}
272
273
274	ip -netns $host1 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
275	    proto esp spi ${SPI_2} reqid 0 mode tunnel \
276	    replay-window 4 replay-oseq 0x4 \
277	    auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
278	    enc 'cbc(aes)' ${ENC_2} \
279	    sel src ${h2_4} dst ${h1_4} ${devarg}
280
281	ip -netns $host2 xfrm state add src ${HOST2_4} dst ${HOST1_4} \
282	    proto esp spi ${SPI_2} reqid 0 mode tunnel \
283	    replay-window 4 replay-oseq 0x4 \
284	    auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
285	    enc 'cbc(aes)' ${ENC_2} \
286	    sel src ${h2_4} dst ${h1_4}
287
288
289	ip -6 -netns $host1 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
290	    proto esp spi ${SPI_1} reqid 0 mode tunnel \
291	    replay-window 4 replay-oseq 0x4 \
292	    auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
293	    enc 'cbc(aes)' ${ENC_1} \
294	    sel src ${h1_6} dst ${h2_6} ${devarg}
295
296	ip -6 -netns $host2 xfrm state add src ${HOST1_6} dst ${HOST2_6} \
297	    proto esp spi ${SPI_1} reqid 0 mode tunnel \
298	    replay-window 4 replay-oseq 0x4 \
299	    auth-trunc 'hmac(sha1)' ${AUTH_1} 96 \
300	    enc 'cbc(aes)' ${ENC_1} \
301	    sel src ${h1_6} dst ${h2_6}
302
303
304	ip -6 -netns $host1 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
305	    proto esp spi ${SPI_2} reqid 0 mode tunnel \
306	    replay-window 4 replay-oseq 0x4 \
307	    auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
308	    enc 'cbc(aes)' ${ENC_2} \
309	    sel src ${h2_6} dst ${h1_6} ${devarg}
310
311	ip -6 -netns $host2 xfrm state add src ${HOST2_6} dst ${HOST1_6} \
312	    proto esp spi ${SPI_2} reqid 0 mode tunnel \
313	    replay-window 4 replay-oseq 0x4 \
314	    auth-trunc 'hmac(sha1)' ${AUTH_2} 96 \
315	    enc 'cbc(aes)' ${ENC_2} \
316	    sel src ${h2_6} dst ${h1_6}
317}
318
319cleanup_xfrm_dev()
320{
321	ip -netns $host1 li del xfrm0
322	ip -netns $host2 addr del ${XFRM2_4}/24 dev eth0
323	ip -netns $host2 addr del ${XFRM2_6}/64 dev eth0
324}
325
326setup_xfrm_dev()
327{
328	local vrfarg="vrf ${VRF}"
329
330	ip -netns $host1 li add type xfrm dev eth0 if_id ${IF_ID}
331	ip -netns $host1 li set xfrm0 ${vrfarg} up
332	ip -netns $host1 addr add ${XFRM1_4}/24 dev xfrm0
333	ip -netns $host1 addr add ${XFRM1_6}/64 dev xfrm0
334
335	ip -netns $host2 addr add ${XFRM2_4}/24 dev eth0
336	ip -netns $host2 addr add ${XFRM2_6}/64 dev eth0
337
338	setup_xfrm ${XFRM1_4} ${XFRM2_4} ${XFRM1_6} ${XFRM2_6} "if_id ${IF_ID}"
339}
340
341run_tests()
342{
343	cleanup_xfrm
344
345	# no IPsec
346	run_cmd_host1 ip vrf exec ${VRF} ping -c1 -w1 ${HOST2_4}
347	log_test $? 0 "IPv4 no xfrm policy"
348	run_cmd_host1 ip vrf exec ${VRF} ${ping6} -c1 -w1 ${HOST2_6}
349	log_test $? 0 "IPv6 no xfrm policy"
350
351	# xfrm without VRF in sel
352	setup_xfrm ${HOST1_4} ${HOST2_4} ${HOST1_6} ${HOST2_6}
353	run_cmd_host1 ip vrf exec ${VRF} ping -c1 -w1 ${HOST2_4}
354	log_test $? 0 "IPv4 xfrm policy based on address"
355	run_cmd_host1 ip vrf exec ${VRF} ${ping6} -c1 -w1 ${HOST2_6}
356	log_test $? 0 "IPv6 xfrm policy based on address"
357	cleanup_xfrm
358
359	# xfrm with VRF in sel
360	# Known failure: ipv4 resets the flow oif after the lookup. Fix is
361	# not straightforward.
362	# setup_xfrm ${HOST1_4} ${HOST2_4} ${HOST1_6} ${HOST2_6} "dev ${VRF}"
363	# run_cmd_host1 ip vrf exec ${VRF} ping -c1 -w1 ${HOST2_4}
364	# log_test $? 0 "IPv4 xfrm policy with VRF in selector"
365	run_cmd_host1 ip vrf exec ${VRF} ${ping6} -c1 -w1 ${HOST2_6}
366	log_test $? 0 "IPv6 xfrm policy with VRF in selector"
367	cleanup_xfrm
368
369	# xfrm with enslaved device in sel
370	# Known failures: combined with the above, __xfrm{4,6}_selector_match
371	# needs to consider both l3mdev and enslaved device index.
372	# setup_xfrm ${HOST1_4} ${HOST2_4} ${HOST1_6} ${HOST2_6} "dev eth0"
373	# run_cmd_host1 ip vrf exec ${VRF} ping -c1 -w1 ${HOST2_4}
374	# log_test $? 0 "IPv4 xfrm policy with enslaved device in selector"
375	# run_cmd_host1 ip vrf exec ${VRF} ${ping6} -c1 -w1 ${HOST2_6}
376	# log_test $? 0 "IPv6 xfrm policy with enslaved device in selector"
377	# cleanup_xfrm
378
379	# xfrm device
380	setup_xfrm_dev
381	run_cmd_host1 ip vrf exec ${VRF} ping -c1 -w1 ${XFRM2_4}
382	log_test $? 0 "IPv4 xfrm policy with xfrm device"
383	run_cmd_host1 ip vrf exec ${VRF} ${ping6} -c1 -w1 ${XFRM2_6}
384	log_test $? 0 "IPv6 xfrm policy with xfrm device"
385	cleanup_xfrm_dev
386}
387
388################################################################################
389# usage
390
391usage()
392{
393        cat <<EOF
394usage: ${0##*/} OPTS
395
396        -p          Pause on fail
397        -v          verbose mode (show commands and output)
398
399done
400EOF
401}
402
403################################################################################
404# main
405
406while getopts :pv o
407do
408	case $o in
409		p) PAUSE_ON_FAIL=yes;;
410		v) VERBOSE=$(($VERBOSE + 1));;
411		h) usage; exit 0;;
412		*) usage; exit 1;;
413	esac
414done
415
416cleanup 2>/dev/null
417setup
418
419echo
420echo "No qdisc on VRF device"
421run_tests
422
423run_cmd_host1 tc qdisc add dev ${VRF} root netem delay 100ms
424echo
425echo "netem qdisc on VRF device"
426run_tests
427
428printf "\nTests passed: %3d\n" ${nsuccess}
429printf "Tests failed: %3d\n"   ${nfail}
430
431exit $ret
432