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