xref: /linux/tools/testing/selftests/net/fib-onlink-tests.sh (revision 0a80e38d0fe1fe7b59c1e93ad908c4148a15926a)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# IPv4 and IPv6 onlink tests
5
6source lib.sh
7PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
8VERBOSE=0
9
10# Network interfaces
11# - odd in current namespace; even in peer ns
12declare -A NETIFS
13# default VRF
14NETIFS[p1]=veth1
15NETIFS[p2]=veth2
16NETIFS[p3]=veth3
17NETIFS[p4]=veth4
18# VRF
19NETIFS[p5]=veth5
20NETIFS[p6]=veth6
21NETIFS[p7]=veth7
22NETIFS[p8]=veth8
23
24# /24 network
25declare -A V4ADDRS
26V4ADDRS[p1]=169.254.1.1
27V4ADDRS[p2]=169.254.1.2
28V4ADDRS[p3]=169.254.3.1
29V4ADDRS[p4]=169.254.3.2
30V4ADDRS[p5]=169.254.5.1
31V4ADDRS[p6]=169.254.5.2
32V4ADDRS[p7]=169.254.7.1
33V4ADDRS[p8]=169.254.7.2
34
35# /64 network
36declare -A V6ADDRS
37V6ADDRS[p1]=2001:db8:101::1
38V6ADDRS[p2]=2001:db8:101::2
39V6ADDRS[p3]=2001:db8:301::1
40V6ADDRS[p4]=2001:db8:301::2
41V6ADDRS[p5]=2001:db8:501::1
42V6ADDRS[p6]=2001:db8:501::2
43V6ADDRS[p7]=2001:db8:701::1
44V6ADDRS[p8]=2001:db8:701::2
45
46# Test networks:
47# [1] = default table
48# [2] = VRF
49#
50# /32 host routes
51declare -A TEST_NET4
52TEST_NET4[1]=169.254.101
53TEST_NET4[2]=169.254.102
54# /128 host routes
55declare -A TEST_NET6
56TEST_NET6[1]=2001:db8:101
57TEST_NET6[2]=2001:db8:102
58
59# connected gateway
60CONGW[1]=169.254.1.254
61CONGW[2]=169.254.3.254
62CONGW[3]=169.254.5.254
63
64# recursive gateway
65RECGW4[1]=169.254.11.254
66RECGW4[2]=169.254.12.254
67RECGW6[1]=2001:db8:11::64
68RECGW6[2]=2001:db8:12::64
69
70# for v4 mapped to v6
71declare -A TEST_NET4IN6IN6
72TEST_NET4IN6[1]=10.1.1.254
73TEST_NET4IN6[2]=10.2.1.254
74
75# mcast address
76MCAST6=ff02::1
77
78VRF=lisa
79VRF_TABLE=1101
80PBR_TABLE=101
81
82################################################################################
83# utilities
84
85log_test()
86{
87	local rc=$1
88	local expected=$2
89	local msg="$3"
90
91	if [ ${rc} -eq ${expected} ]; then
92		nsuccess=$((nsuccess+1))
93		printf "    TEST: %-50s  [ OK ]\n" "${msg}"
94	else
95		nfail=$((nfail+1))
96		printf "    TEST: %-50s  [FAIL]\n" "${msg}"
97		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
98			echo
99			echo "hit enter to continue, 'q' to quit"
100			read a
101			[ "$a" = "q" ] && exit 1
102		fi
103	fi
104}
105
106log_section()
107{
108	echo
109	echo "######################################################################"
110	echo "TEST SECTION: $*"
111	echo "######################################################################"
112}
113
114log_subsection()
115{
116	echo
117	echo "#########################################"
118	echo "TEST SUBSECTION: $*"
119}
120
121run_cmd()
122{
123	local cmd="$1"
124	local out
125	local rc
126
127	if [ "$VERBOSE" = "1" ]; then
128		printf "    COMMAND: $cmd\n"
129	fi
130
131	out=$(eval $cmd 2>&1)
132	rc=$?
133	if [ "$VERBOSE" = "1" -a -n "$out" ]; then
134		echo "    $out"
135	fi
136
137	[ "$VERBOSE" = "1" ] && echo
138
139	return $rc
140}
141
142get_linklocal()
143{
144	local dev=$1
145	local pfx
146	local addr
147
148	addr=$(${pfx} ${IP} -6 -br addr show dev ${dev} | \
149	awk '{
150		for (i = 3; i <= NF; ++i) {
151			if ($i ~ /^fe80/)
152				print $i
153		}
154	}'
155	)
156	addr=${addr/\/*}
157
158	[ -z "$addr" ] && return 1
159
160	echo $addr
161
162	return 0
163}
164
165################################################################################
166#
167
168setup()
169{
170	echo
171	echo "########################################"
172	echo "Configuring interfaces"
173
174	set -e
175
176	# create namespaces
177	setup_ns ns1
178	IP="ip -netns $ns1"
179	setup_ns ns2
180
181	# add vrf table
182	${IP} li add ${VRF} type vrf table ${VRF_TABLE}
183	${IP} li set ${VRF} up
184	${IP} ro add table ${VRF_TABLE} unreachable default metric 8192
185	${IP} -6 ro add table ${VRF_TABLE} unreachable default metric 8192
186
187	# create test interfaces
188	${IP} li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]}
189	${IP} li add ${NETIFS[p3]} type veth peer name ${NETIFS[p4]}
190	${IP} li add ${NETIFS[p5]} type veth peer name ${NETIFS[p6]}
191	${IP} li add ${NETIFS[p7]} type veth peer name ${NETIFS[p8]}
192
193	# enslave vrf interfaces
194	for n in 5 7; do
195		${IP} li set ${NETIFS[p${n}]} vrf ${VRF}
196	done
197
198	# add addresses
199	for n in 1 3 5 7; do
200		${IP} li set ${NETIFS[p${n}]} up
201		${IP} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]}
202		${IP} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad
203	done
204
205	# move peer interfaces to namespace and add addresses
206	for n in 2 4 6 8; do
207		${IP} li set ${NETIFS[p${n}]} netns ${ns2} up
208		ip -netns $ns2 addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]}
209		ip -netns $ns2 addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} nodad
210	done
211
212	${IP} -6 ro add default via ${V6ADDRS[p3]/::[0-9]/::64}
213	${IP} -6 ro add table ${VRF_TABLE} default via ${V6ADDRS[p7]/::[0-9]/::64}
214
215	set +e
216}
217
218################################################################################
219# IPv4 tests
220#
221
222run_ip()
223{
224	local table="$1"
225	local prefix="$2"
226	local gw="$3"
227	local dev="$4"
228	local exp_rc="$5"
229	local desc="$6"
230
231	# dev arg may be empty
232	[ -n "${dev}" ] && dev="dev ${dev}"
233
234	run_cmd "${IP} ro add table ${table} ${prefix}/32 via ${gw} ${dev} onlink"
235	log_test $? ${exp_rc} "${desc}"
236}
237
238run_ip_mpath()
239{
240	local table="$1"
241	local prefix="$2"
242	local nh1="$3"
243	local nh2="$4"
244	local exp_rc="$5"
245	local desc="$6"
246
247	# dev arg may be empty
248	[ -n "${dev}" ] && dev="dev ${dev}"
249
250	run_cmd "${IP} ro add table ${table} ${prefix}/32 \
251		nexthop via ${nh1} nexthop via ${nh2}"
252	log_test $? ${exp_rc} "${desc}"
253}
254
255valid_onlink_ipv4()
256{
257	# - unicast connected, unicast recursive
258	#
259	log_subsection "default VRF - main table"
260
261	run_ip 254 ${TEST_NET4[1]}.1 ${CONGW[1]} ${NETIFS[p1]} 0 "unicast connected"
262	run_ip 254 ${TEST_NET4[1]}.2 ${RECGW4[1]} ${NETIFS[p1]} 0 "unicast recursive"
263
264	log_subsection "VRF ${VRF}"
265
266	run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected"
267	run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive"
268
269	log_subsection "VRF device, PBR table"
270
271	run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected"
272	run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive"
273
274	# multipath version
275	#
276	log_subsection "default VRF - main table - multipath"
277
278	run_ip_mpath 254 ${TEST_NET4[1]}.5 \
279		"${CONGW[1]} dev ${NETIFS[p1]} onlink" \
280		"${CONGW[2]} dev ${NETIFS[p3]} onlink" \
281		0 "unicast connected - multipath"
282
283	run_ip_mpath 254 ${TEST_NET4[1]}.6 \
284		"${RECGW4[1]} dev ${NETIFS[p1]} onlink" \
285		"${RECGW4[2]} dev ${NETIFS[p3]} onlink" \
286		0 "unicast recursive - multipath"
287
288	run_ip_mpath 254 ${TEST_NET4[1]}.7 \
289		"${CONGW[1]} dev ${NETIFS[p1]}"        \
290		"${CONGW[2]} dev ${NETIFS[p3]} onlink" \
291		0 "unicast connected - multipath onlink first only"
292
293	run_ip_mpath 254 ${TEST_NET4[1]}.8 \
294		"${CONGW[1]} dev ${NETIFS[p1]} onlink" \
295		"${CONGW[2]} dev ${NETIFS[p3]}"        \
296		0 "unicast connected - multipath onlink second only"
297}
298
299invalid_onlink_ipv4()
300{
301	run_ip 254 ${TEST_NET4[1]}.11 ${V4ADDRS[p1]} ${NETIFS[p1]} 2 \
302		"Invalid gw - local unicast address"
303
304	run_ip ${VRF_TABLE} ${TEST_NET4[2]}.11 ${V4ADDRS[p5]} ${NETIFS[p5]} 2 \
305		"Invalid gw - local unicast address, VRF"
306
307	run_ip 254 ${TEST_NET4[1]}.101 ${V4ADDRS[p1]} "" 2 "No nexthop device given"
308
309	run_ip 254 ${TEST_NET4[1]}.102 ${V4ADDRS[p3]} ${NETIFS[p1]} 2 \
310		"Gateway resolves to wrong nexthop device"
311
312	run_ip ${VRF_TABLE} ${TEST_NET4[2]}.103 ${V4ADDRS[p7]} ${NETIFS[p5]} 2 \
313		"Gateway resolves to wrong nexthop device - VRF"
314}
315
316################################################################################
317# IPv6 tests
318#
319
320run_ip6()
321{
322	local table="$1"
323	local prefix="$2"
324	local gw="$3"
325	local dev="$4"
326	local exp_rc="$5"
327	local desc="$6"
328
329	# dev arg may be empty
330	[ -n "${dev}" ] && dev="dev ${dev}"
331
332	run_cmd "${IP} -6 ro add table ${table} ${prefix}/128 via ${gw} ${dev} onlink"
333	log_test $? ${exp_rc} "${desc}"
334}
335
336run_ip6_mpath()
337{
338	local table="$1"
339	local prefix="$2"
340	local opts="$3"
341	local nh1="$4"
342	local nh2="$5"
343	local exp_rc="$6"
344	local desc="$7"
345
346	run_cmd "${IP} -6 ro add table ${table} ${prefix}/128 ${opts} \
347		nexthop via ${nh1} nexthop via ${nh2}"
348	log_test $? ${exp_rc} "${desc}"
349}
350
351valid_onlink_ipv6()
352{
353	# - unicast connected, unicast recursive, v4-mapped
354	#
355	log_subsection "default VRF - main table"
356
357	run_ip6 254 ${TEST_NET6[1]}::1 ${V6ADDRS[p1]/::*}::64 ${NETIFS[p1]} 0 "unicast connected"
358	run_ip6 254 ${TEST_NET6[1]}::2 ${RECGW6[1]} ${NETIFS[p1]} 0 "unicast recursive"
359	run_ip6 254 ${TEST_NET6[1]}::3 ::ffff:${TEST_NET4IN6[1]} ${NETIFS[p1]} 0 "v4-mapped"
360
361	log_subsection "VRF ${VRF}"
362
363	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::1 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected"
364	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::2 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive"
365	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::3 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped"
366
367	log_subsection "VRF device, PBR table"
368
369	run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected"
370	run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive"
371	run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped"
372
373	# multipath version
374	#
375	log_subsection "default VRF - main table - multipath"
376
377	run_ip6_mpath 254 ${TEST_NET6[1]}::4 "onlink" \
378		"${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \
379		"${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \
380		0 "unicast connected - multipath onlink"
381
382	run_ip6_mpath 254 ${TEST_NET6[1]}::5 "onlink" \
383		"${RECGW6[1]} dev ${NETIFS[p1]}" \
384		"${RECGW6[2]} dev ${NETIFS[p3]}" \
385		0 "unicast recursive - multipath onlink"
386
387	run_ip6_mpath 254 ${TEST_NET6[1]}::6 "onlink" \
388		"::ffff:${TEST_NET4IN6[1]} dev ${NETIFS[p1]}" \
389		"::ffff:${TEST_NET4IN6[2]} dev ${NETIFS[p3]}" \
390		0 "v4-mapped - multipath onlink"
391
392	run_ip6_mpath 254 ${TEST_NET6[1]}::7 "" \
393		"${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \
394		"${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \
395		0 "unicast connected - multipath onlink both nexthops"
396
397	run_ip6_mpath 254 ${TEST_NET6[1]}::8 "" \
398		"${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \
399		"${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \
400		0 "unicast connected - multipath onlink first only"
401
402	run_ip6_mpath 254 ${TEST_NET6[1]}::9 "" \
403		"${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}"        \
404		"${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \
405		0 "unicast connected - multipath onlink second only"
406}
407
408invalid_onlink_ipv6()
409{
410	local lladdr
411
412	lladdr=$(get_linklocal ${NETIFS[p1]}) || return 1
413
414	run_ip6 254 ${TEST_NET6[1]}::11 ${V6ADDRS[p1]} ${NETIFS[p1]} 2 \
415		"Invalid gw - local unicast address"
416	run_ip6 254 ${TEST_NET6[1]}::12 ${lladdr} ${NETIFS[p1]} 2 \
417		"Invalid gw - local linklocal address"
418	run_ip6 254 ${TEST_NET6[1]}::12 ${MCAST6} ${NETIFS[p1]} 2 \
419		"Invalid gw - multicast address"
420
421	lladdr=$(get_linklocal ${NETIFS[p5]}) || return 1
422	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::11 ${V6ADDRS[p5]} ${NETIFS[p5]} 2 \
423		"Invalid gw - local unicast address, VRF"
424	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${lladdr} ${NETIFS[p5]} 2 \
425		"Invalid gw - local linklocal address, VRF"
426	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${MCAST6} ${NETIFS[p5]} 2 \
427		"Invalid gw - multicast address, VRF"
428
429	run_ip6 254 ${TEST_NET6[1]}::101 ${V6ADDRS[p1]} "" 2 \
430		"No nexthop device given"
431
432	# default VRF validation is done against LOCAL table
433	# run_ip6 254 ${TEST_NET6[1]}::102 ${V6ADDRS[p3]/::[0-9]/::64} ${NETIFS[p1]} 2 \
434	#	"Gateway resolves to wrong nexthop device"
435
436	run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::103 ${V6ADDRS[p7]/::[0-9]/::64} ${NETIFS[p5]} 2 \
437		"Gateway resolves to wrong nexthop device - VRF"
438}
439
440run_onlink_tests()
441{
442	log_section "IPv4 onlink"
443	log_subsection "Valid onlink commands"
444	valid_onlink_ipv4
445	log_subsection "Invalid onlink commands"
446	invalid_onlink_ipv4
447
448	log_section "IPv6 onlink"
449	log_subsection "Valid onlink commands"
450	valid_onlink_ipv6
451	log_subsection "Invalid onlink commands"
452	invalid_onlink_ipv6
453}
454
455################################################################################
456# usage
457
458usage()
459{
460	cat <<EOF
461usage: ${0##*/} OPTS
462
463        -p          Pause on fail
464        -v          verbose mode (show commands and output)
465EOF
466}
467
468################################################################################
469# main
470
471nsuccess=0
472nfail=0
473
474while getopts :t:pPhv o
475do
476	case $o in
477		p) PAUSE_ON_FAIL=yes;;
478		v) VERBOSE=$(($VERBOSE + 1));;
479		h) usage; exit 0;;
480		*) usage; exit 1;;
481	esac
482done
483
484setup
485run_onlink_tests
486cleanup_ns ${ns1} ${ns2}
487
488if [ "$TESTS" != "none" ]; then
489	printf "\nTests passed: %3d\n" ${nsuccess}
490	printf "Tests failed: %3d\n"   ${nfail}
491fi
492