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