xref: /freebsd/tests/sys/netinet/fibs_test.sh (revision d0b2dbfa)
1#
2#  Copyright (c) 2014 Spectra Logic Corporation
3#  All rights reserved.
4#
5#  Redistribution and use in source and binary forms, with or without
6#  modification, are permitted provided that the following conditions
7#  are met:
8#  1. Redistributions of source code must retain the above copyright
9#     notice, this list of conditions, and the following disclaimer,
10#     without modification.
11#  2. Redistributions in binary form must reproduce at minimum a disclaimer
12#     substantially similar to the "NO WARRANTY" disclaimer below
13#     ("Disclaimer") and any redistribution must be conditioned upon
14#     including a substantially similar Disclaimer requirement for further
15#     binary redistribution.
16#
17#  NO WARRANTY
18#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22#  HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26#  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27#  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28#  POSSIBILITY OF SUCH DAMAGES.
29#
30#  Authors: Alan Somers         (Spectra Logic Corporation)
31#
32
33# All of the tests in this file requires the test-suite config variable "fibs"
34# to be defined to a space-delimited list of FIBs that may be used for testing.
35
36# arpresolve should check the interface fib for routes to a target when
37# creating an ARP table entry.  This is a regression for kern/167947, where
38# arpresolve only checked the default route.
39#
40# Outline:
41# Create two connected epair(4) interfaces
42# Use nping (from security/nmap) to send an ICMP echo request from one
43# interface to the other, spoofing the source IP.  The source IP must be
44# spoofed, or else it will already have an entry in the arp table.
45# Check whether an arp entry exists for the spoofed IP
46atf_test_case arpresolve_checks_interface_fib cleanup
47arpresolve_checks_interface_fib_head()
48{
49	atf_set "descr" "arpresolve should check the interface fib, not the default fib, for routes"
50	atf_set "require.user" "root"
51	atf_set "require.config" "fibs"
52	atf_set "require.progs" "nping"
53}
54arpresolve_checks_interface_fib_body()
55{
56	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
57	# and a non-default fib
58	ADDR0="192.0.2.2"
59	ADDR1="192.0.2.3"
60	SUBNET="192.0.2.0"
61	# Due to bug TBD (regressed by multiple_fibs_on_same_subnet) we need
62	# diffferent subnet masks, or FIB1 won't have a subnet route.
63	MASK0="24"
64	MASK1="25"
65	# Spoof a MAC that is reserved per RFC7042
66	SPOOF_ADDR="192.0.2.4"
67	SPOOF_MAC="00:00:5E:00:53:00"
68
69	# Check system configuration
70	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
71		atf_skip "This test requires net.add_addr_allfibs=0"
72	fi
73	get_fibs 2
74
75	# Configure epair interfaces
76	get_epair
77	setup_iface "$EPAIRA" "$FIB0" inet ${ADDR0} ${MASK0}
78	setup_iface "$EPAIRB" "$FIB1" inet ${ADDR1} ${MASK1}
79
80	# Send an ICMP echo request with a spoofed source IP
81	setfib "$FIB0" nping -c 1 -e ${EPAIRA} -S ${SPOOF_ADDR} \
82		--source-mac ${SPOOF_MAC} --icmp --icmp-type "echo-request" \
83		--icmp-code 0 --icmp-id 0xdead --icmp-seq 1 --data 0xbeef \
84		${ADDR1}
85	# For informational and debugging purposes only, look for the
86	# characteristic error message
87	dmesg | grep "llinfo.*${SPOOF_ADDR}"
88	# Check that the ARP entry exists
89	atf_check -o match:"${SPOOF_ADDR}.*expires" setfib "$FIB1" arp ${SPOOF_ADDR}
90}
91arpresolve_checks_interface_fib_cleanup()
92{
93	cleanup_ifaces
94}
95
96
97# Regression test for kern/187549
98atf_test_case loopback_and_network_routes_on_nondefault_fib cleanup
99loopback_and_network_routes_on_nondefault_fib_head()
100{
101	atf_set "descr" "When creating and deleting loopback IPv4 routes, use the interface's fib"
102	atf_set "require.user" "root"
103	atf_set "require.config" "fibs"
104}
105
106loopback_and_network_routes_on_nondefault_fib_body()
107{
108	# Configure the TAP interface to use an RFC5737 nonrouteable address
109	# and a non-default fib
110	ADDR="192.0.2.2"
111	SUBNET="192.0.2.0"
112	MASK="24"
113
114	# Check system configuration
115	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
116		atf_skip "This test requires net.add_addr_allfibs=0"
117	fi
118	get_fibs 1
119
120	# Configure a TAP interface
121	setup_tap ${FIB0} inet ${ADDR} ${MASK}
122
123	# Check whether the host route exists in only the correct FIB
124	setfib ${FIB0} netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
125	if [ 0 -ne $? ]; then
126		setfib ${FIB0} netstat -rn -f inet
127		atf_fail "Host route did not appear in the correct FIB"
128	fi
129	setfib 0 netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
130	if [ 0 -eq $? ]; then
131		setfib 0 netstat -rn -f inet
132		atf_fail "Host route appeared in the wrong FIB"
133	fi
134
135	# Check whether the network route exists in only the correct FIB
136	setfib ${FIB0} netstat -rn -f inet | \
137		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
138	if [ 0 -ne $? ]; then
139		setfib ${FIB0} netstat -rn -f inet
140		atf_fail "Network route did not appear in the correct FIB"
141	fi
142	setfib 0 netstat -rn -f inet | \
143		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
144	if [ 0 -eq $? ]; then
145		setfib 0 netstat -rn -f inet
146		atf_fail "Network route appeared in the wrong FIB"
147	fi
148}
149
150loopback_and_network_routes_on_nondefault_fib_cleanup()
151{
152	cleanup_ifaces
153}
154
155atf_test_case loopback_and_network_routes_on_nondefault_fib_inet6 cleanup
156loopback_and_network_routes_on_nondefault_fib_inet6_head()
157{
158	atf_set "descr" "When creating and deleting loopback IPv6 routes, use the interface's fib"
159	atf_set "require.user" "root"
160	atf_set "require.config" "fibs"
161}
162
163loopback_and_network_routes_on_nondefault_fib_inet6_body()
164{
165	# Configure the TAP interface to use a nonrouteable RFC3849
166	# address and a non-default fib
167	ADDR="2001:db8::2"
168	SUBNET="2001:db8::"
169	MASK="64"
170
171	# Check system configuration
172	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
173		atf_skip "This test requires net.add_addr_allfibs=0"
174	fi
175	get_fibs 1
176
177	# Configure a TAP interface
178	setup_tap ${FIB0} inet6 ${ADDR} ${MASK}
179
180	# Check whether the host route exists in only the correct FIB
181	setfib ${FIB0} netstat -rn -f inet6 | grep -q "^${ADDR}.*UHS.*lo0"
182	if [ 0 -ne $? ]; then
183		setfib ${FIB0} netstat -rn -f inet6
184		atf_fail "Host route did not appear in the correct FIB"
185	fi
186	setfib 0 netstat -rn -f inet6 | grep -q "^${ADDR}.*UHS.*lo0"
187	if [ 0 -eq $? ]; then
188		setfib 0 netstat -rn -f inet6
189		atf_fail "Host route appeared in the wrong FIB"
190	fi
191
192	# Check whether the network route exists in only the correct FIB
193	setfib ${FIB0} netstat -rn -f inet6 | \
194		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
195	if [ 0 -ne $? ]; then
196		setfib ${FIB0} netstat -rn -f inet6
197		atf_fail "Network route did not appear in the correct FIB"
198	fi
199	setfib 0 netstat -rn -f inet6 | \
200		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
201	if [ 0 -eq $? ]; then
202		setfib 0 netstat -rn -f inet6
203		atf_fail "Network route appeared in the wrong FIB"
204	fi
205}
206
207loopback_and_network_routes_on_nondefault_fib_inet6_cleanup()
208{
209	cleanup_ifaces
210}
211
212
213# Regression test for kern/187552
214atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup
215default_route_with_multiple_fibs_on_same_subnet_head()
216{
217	atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default IPv4 routes"
218	atf_set "require.user" "root"
219	atf_set "require.config" "fibs"
220}
221
222default_route_with_multiple_fibs_on_same_subnet_body()
223{
224	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
225	# and a non-default fib
226	ADDR0="192.0.2.2"
227	ADDR1="192.0.2.3"
228	GATEWAY="192.0.2.1"
229	SUBNET="192.0.2.0"
230	MASK="24"
231
232	# Check system configuration
233	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
234		atf_skip "This test requires net.add_addr_allfibs=0"
235	fi
236	get_fibs 2
237
238	# Configure TAP interfaces
239	setup_tap "$FIB0" inet ${ADDR0} ${MASK}
240	TAP0=$TAP
241	setup_tap "$FIB1" inet ${ADDR1} ${MASK}
242	TAP1=$TAP
243
244	# Attempt to add default routes
245	setfib ${FIB0} route add default ${GATEWAY}
246	setfib ${FIB1} route add default ${GATEWAY}
247
248	# Verify that the default route exists for both fibs, with their
249	# respective interfaces.
250	atf_check -o match:"^default.*${TAP0}$" \
251		setfib ${FIB0} netstat -rn -f inet
252	atf_check -o match:"^default.*${TAP1}$" \
253		setfib ${FIB1} netstat -rn -f inet
254}
255
256default_route_with_multiple_fibs_on_same_subnet_cleanup()
257{
258	cleanup_ifaces
259}
260
261atf_test_case default_route_with_multiple_fibs_on_same_subnet_inet6 cleanup
262default_route_with_multiple_fibs_on_same_subnet_inet6_head()
263{
264	atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default IPv6 routes"
265	atf_set "require.user" "root"
266	atf_set "require.config" "fibs"
267}
268
269default_route_with_multiple_fibs_on_same_subnet_inet6_body()
270{
271	# Configure the TAP interfaces to use nonrouteable RFC3849
272	# addresses and non-default FIBs
273	ADDR0="2001:db8::2"
274	ADDR1="2001:db8::3"
275	GATEWAY="2001:db8::1"
276	SUBNET="2001:db8::"
277	MASK="64"
278
279	# Check system configuration
280	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
281		atf_skip "This test requires net.add_addr_allfibs=0"
282	fi
283	get_fibs 2
284
285	# Configure TAP interfaces
286	setup_tap "$FIB0" inet6 ${ADDR0} ${MASK}
287	TAP0=$TAP
288	setup_tap "$FIB1" inet6 ${ADDR1} ${MASK}
289	TAP1=$TAP
290
291	# Attempt to add default routes
292	setfib ${FIB0} route -6 add default ${GATEWAY}
293	setfib ${FIB1} route -6 add default ${GATEWAY}
294
295	# Verify that the default route exists for both fibs, with their
296	# respective interfaces.
297	atf_check -o match:"^default.*${TAP0}$" \
298		setfib ${FIB0} netstat -rn -f inet6
299	atf_check -o match:"^default.*${TAP1}$" \
300		setfib ${FIB1} netstat -rn -f inet6
301}
302
303default_route_with_multiple_fibs_on_same_subnet_inet6_cleanup()
304{
305	cleanup_ifaces
306}
307
308
309# Regression test for PR kern/189089
310# Create two tap interfaces and assign them both the same IP address but with
311# different netmasks, and both on the default FIB.  Then remove one's IP
312# address.  Hopefully the machine won't panic.
313atf_test_case same_ip_multiple_ifaces_fib0 cleanup
314same_ip_multiple_ifaces_fib0_head()
315{
316	atf_set "descr" "Can remove an IPv4 alias from an interface when the same IPv4 is also assigned to another interface."
317	atf_set "require.user" "root"
318	atf_set "require.config" "fibs"
319}
320same_ip_multiple_ifaces_fib0_body()
321{
322	ADDR="192.0.2.2"
323	MASK0="24"
324	MASK1="32"
325
326	# Unlike most of the tests in this file, this is applicable regardless
327	# of net.add_addr_allfibs
328
329	# Setup the interfaces, then remove one alias.  It should not panic.
330	setup_tap 0 inet ${ADDR} ${MASK0}
331	TAP0=${TAP}
332	setup_tap 0 inet ${ADDR} ${MASK1}
333	TAP1=${TAP}
334	ifconfig ${TAP1} -alias ${ADDR}
335
336	# Do it again, in the opposite order.  It should not panic.
337	setup_tap 0 inet ${ADDR} ${MASK0}
338	TAP0=${TAP}
339	setup_tap 0 inet ${ADDR} ${MASK1}
340	TAP1=${TAP}
341	ifconfig ${TAP0} -alias ${ADDR}
342}
343same_ip_multiple_ifaces_fib0_cleanup()
344{
345	cleanup_ifaces
346}
347
348# Regression test for PR kern/189088
349# Test that removing an IP address works even if the same IP is assigned to a
350# different interface, on a different FIB.  Tests the same code that whose
351# panic was regressed by same_ip_multiple_ifaces_fib0.
352# Create two tap interfaces and assign them both the same IP address but with
353# different netmasks, and on different FIBs.  Then remove one's IP
354# address.  Hopefully the machine won't panic.  Also, the IP's hostroute should
355# dissappear from the correct fib.
356atf_test_case same_ip_multiple_ifaces cleanup
357same_ip_multiple_ifaces_head()
358{
359	atf_set "descr" "Can remove an IPv4 alias from an interface when the same address is also assigned to another interface, on non-default FIBs."
360	atf_set "require.user" "root"
361	atf_set "require.config" "fibs"
362}
363same_ip_multiple_ifaces_body()
364{
365	atf_expect_fail "kern/189088 Assigning the same IP to multiple interfaces in different FIBs creates a host route for only one"
366	ADDR="192.0.2.2"
367	MASK0="24"
368	MASK1="32"
369
370	# Unlike most of the tests in this file, this is applicable regardless
371	# of net.add_addr_allfibs
372	get_fibs 2
373
374	# Setup the interfaces, then remove one alias.  It should not panic.
375	setup_tap ${FIB0} inet ${ADDR} ${MASK0}
376	TAP0=${TAP}
377	setup_tap ${FIB1} inet ${ADDR} ${MASK1}
378	TAP1=${TAP}
379	ifconfig ${TAP1} -alias ${ADDR}
380	atf_check -o not-match:"^${ADDR}[[:space:]]" \
381		setfib ${FIB1} netstat -rn -f inet
382
383	# Do it again, in the opposite order.  It should not panic.
384	setup_tap ${FIB0} inet ${ADDR} ${MASK0}
385	TAP0=${TAP}
386	setup_tap ${FIB1} inet ${ADDR} ${MASK1}
387	TAP1=${TAP}
388	ifconfig ${TAP0} -alias ${ADDR}
389	atf_check -o not-match:"^${ADDR}[[:space:]]" \
390		setfib ${FIB0} netstat -rn -f inet
391}
392same_ip_multiple_ifaces_cleanup()
393{
394	# Due to PR kern/189088, we must destroy the interfaces in LIFO order
395	# in order for the routes to be correctly cleaned up.
396	for TAPD in `tail -r "ifaces_to_cleanup"`; do
397		echo ifconfig ${TAPD} destroy
398		ifconfig ${TAPD} destroy
399	done
400}
401
402atf_test_case same_ip_multiple_ifaces_inet6 cleanup
403same_ip_multiple_ifaces_inet6_head()
404{
405	atf_set "descr" "Can remove an IPv6 alias from an interface when the same address is also assigned to another interface, on non-default FIBs."
406	atf_set "require.user" "root"
407	atf_set "require.config" "fibs"
408}
409same_ip_multiple_ifaces_inet6_body()
410{
411	ADDR="2001:db8::2"
412	MASK0="64"
413	MASK1="128"
414
415	# Unlike most of the tests in this file, this is applicable regardless
416	# of net.add_addr_allfibs
417	get_fibs 2
418
419	# Setup the interfaces, then remove one alias.  It should not panic.
420	setup_tap ${FIB0} inet6 ${ADDR} ${MASK0}
421	TAP0=${TAP}
422	setup_tap ${FIB1} inet6 ${ADDR} ${MASK1}
423	TAP1=${TAP}
424	atf_check -s exit:0 ifconfig ${TAP1} inet6 ${ADDR} -alias
425	atf_check -o not-match:"^${ADDR}[[:space:]]" \
426		setfib ${FIB1} netstat -rn -f inet6
427	ifconfig ${TAP1} destroy
428	ifconfig ${TAP0} destroy
429
430	# Do it again, in the opposite order.  It should not panic.
431	setup_tap ${FIB0} inet6 ${ADDR} ${MASK0}
432	TAP0=${TAP}
433	setup_tap ${FIB1} inet6 ${ADDR} ${MASK1}
434	TAP1=${TAP}
435	atf_check -s exit:0 ifconfig ${TAP0} inet6 ${ADDR} -alias
436	atf_check -o not-match:"^${ADDR}[[:space:]]" \
437		setfib ${FIB0} netstat -rn -f inet6
438}
439same_ip_multiple_ifaces_inet6_cleanup()
440{
441	cleanup_ifaces
442}
443
444atf_test_case slaac_on_nondefault_fib6 cleanup
445slaac_on_nondefault_fib6_head()
446{
447	atf_set "descr" "SLAAC correctly installs routes on non-default FIBs"
448	atf_set "require.user" "root"
449	atf_set "require.config" "fibs" "allow_sysctl_side_effects"
450}
451slaac_on_nondefault_fib6_body()
452{
453	# Configure the epair interfaces to use nonrouteable RFC3849
454	# addresses and non-default FIBs
455	PREFIX="2001:db8:$(printf "%x" `jot -r 1 0 65535`):$(printf "%x" `jot -r 1 0 65535`)"
456	ADDR="$PREFIX::2"
457	GATEWAY="$PREFIX::1"
458	SUBNET="$PREFIX:"
459	MASK="64"
460
461	# Check system configuration
462	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
463		atf_skip "This test requires net.add_addr_allfibs=0"
464	fi
465	get_fibs 2
466
467	sysctl -n "net.inet6.ip6.rfc6204w3" >> "rfc6204w3.state"
468	sysctl -n "net.inet6.ip6.forwarding" >> "forwarding.state"
469	# Enable forwarding so the kernel will send RAs
470	sysctl net.inet6.ip6.forwarding=1
471	# Enable RFC6204W3 mode so the kernel will enable default router
472	# selection while also forwarding packets
473	sysctl net.inet6.ip6.rfc6204w3=1
474
475	# Configure epair interfaces
476	get_epair
477	setup_iface "$EPAIRA" "$FIB0" inet6 ${ADDR} ${MASK}
478	echo setfib $FIB1 ifconfig "$EPAIRB" inet6 -ifdisabled accept_rtadv fib $FIB1 up
479	setfib $FIB1 ifconfig "$EPAIRB" inet6 -ifdisabled accept_rtadv fib $FIB1 up
480	rtadvd -p rtadvd.pid -C rtadvd.sock -c /dev/null "$EPAIRA"
481	rtsol "$EPAIRB"
482
483	# Check SLAAC address
484	atf_check -o match:"inet6 ${SUBNET}.*prefixlen ${MASK}.*autoconf" \
485		ifconfig "$EPAIRB"
486	# Check local route
487	atf_check -o match:"${SUBNET}.*\<UHS\>.*lo0" \
488		netstat -rnf inet6 -F $FIB1
489	# Check subnet route
490	atf_check -o match:"${SUBNET}:/${MASK}.*\<U\>.*$EPAIRB" \
491		netstat -rnf inet6 -F $FIB1
492	# Check default route
493	atf_check -o match:"default.*\<UG\>.*$EPAIRB" \
494		netstat -rnf inet6 -F $FIB1
495
496	# Check that none of the above routes appeared on other routes
497	for fib in $( seq 0 $(($(sysctl -n net.fibs) - 1))); do
498		if [ "$fib" = "$FIB1" -o "$fib" = "$FIB0" ]; then
499			continue
500		fi
501		atf_check -o not-match:"${SUBNET}.*\<UHS\>.*lo0" \
502			netstat -rnf inet6 -F $fib
503		atf_check -o not-match:"${SUBNET}:/${MASK}.*\<U\>.*$EPAIRB" \
504			netstat -rnf inet6 -F $fib
505		atf_check -o not-match:"default.*\<UG\>.*$EPAIRB" \
506			netstat -rnf inet6 -F $fib
507	done
508}
509slaac_on_nondefault_fib6_cleanup()
510{
511	if [ -f "rtadvd.pid" ]; then
512		# rtadvd can take a long time to shutdown.  Use SIGKILL to kill
513		# it right away.  The downside to using SIGKILL is that it
514		# won't send final RAs to all interfaces, but we don't care
515		# because we're about to destroy its interface anyway.
516		pkill -kill -F rtadvd.pid
517		rm -f rtadvd.pid
518	fi
519	cleanup_ifaces
520	if [ -f "forwarding.state" ] ; then
521		sysctl "net.inet6.ip6.forwarding"=`cat "forwarding.state"`
522		rm "forwarding.state"
523	fi
524	if [ -f "rfc6204w3.state" ] ; then
525		sysctl "net.inet6.ip6.rfc6204w3"=`cat "rfc6204w3.state"`
526		rm "rfc6204w3.state"
527	fi
528}
529
530# Regression test for kern/187550
531atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
532subnet_route_with_multiple_fibs_on_same_subnet_head()
533{
534	atf_set "descr" "Multiple FIBs can have IPv4 subnet routes for the same subnet"
535	atf_set "require.user" "root"
536	atf_set "require.config" "fibs"
537}
538
539subnet_route_with_multiple_fibs_on_same_subnet_body()
540{
541	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
542	# and a non-default fib
543	ADDR0="192.0.2.2"
544	ADDR1="192.0.2.3"
545	SUBNET="192.0.2.0"
546	MASK="24"
547
548	# Check system configuration
549	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
550		atf_skip "This test requires net.add_addr_allfibs=0"
551	fi
552	get_fibs 2
553
554	# Configure TAP interfaces
555	setup_tap "$FIB0" inet ${ADDR0} ${MASK}
556	setup_tap "$FIB1" inet ${ADDR1} ${MASK}
557
558	# Check that a subnet route exists on both fibs
559	atf_check -o ignore setfib "$FIB0" route get $ADDR1
560	atf_check -o ignore setfib "$FIB1" route get $ADDR0
561}
562
563subnet_route_with_multiple_fibs_on_same_subnet_cleanup()
564{
565	cleanup_ifaces
566}
567
568atf_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6 cleanup
569subnet_route_with_multiple_fibs_on_same_subnet_inet6_head()
570{
571	atf_set "descr" "Multiple FIBs can have IPv6 subnet routes for the same subnet"
572	atf_set "require.user" "root"
573	atf_set "require.config" "fibs"
574}
575
576subnet_route_with_multiple_fibs_on_same_subnet_inet6_body()
577{
578	# Configure the TAP interfaces to use a RFC3849 nonrouteable addresses
579	# and a non-default fib
580	ADDR0="2001:db8::2"
581	ADDR1="2001:db8::3"
582	SUBNET="2001:db8::"
583	MASK="64"
584
585	# Check system configuration
586	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
587		atf_skip "This test requires net.add_addr_allfibs=0"
588	fi
589	get_fibs 2
590
591	# Configure TAP interfaces
592	setup_tap "$FIB0" inet6 ${ADDR0} ${MASK}
593	setup_tap "$FIB1" inet6 ${ADDR1} ${MASK}
594
595	# Check that a subnet route exists on both fibs
596	atf_check -o ignore setfib "$FIB0" route -6 get $ADDR1
597	atf_check -o ignore setfib "$FIB1" route -6 get $ADDR0
598}
599
600subnet_route_with_multiple_fibs_on_same_subnet_inet6_cleanup()
601{
602	cleanup_ifaces
603}
604
605# Test that source address selection works correctly for UDP packets with
606# SO_DONTROUTE set that are sent on non-default FIBs.
607# This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host"
608# Regression test for kern/187553
609#
610# The root cause was that ifa_ifwithnet() did not have a fib argument.  It
611# would return an address from an interface on any FIB that had a subnet route
612# for the destination.  If more than one were available, it would choose the
613# most specific.  This is most easily tested by creating a FIB without a
614# default route, then trying to send a UDP packet with SO_DONTROUTE set to an
615# address which is not routable on that FIB.  Absent the fix for this bug,
616# in_pcbladdr would choose an interface on any FIB with a default route.  With
617# the fix, you will get EUNREACH or ENETUNREACH.
618atf_test_case udp_dontroute cleanup
619udp_dontroute_head()
620{
621	atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works"
622	atf_set "require.user" "root"
623	atf_set "require.config" "fibs"
624}
625
626udp_dontroute_body()
627{
628	# Configure the TAP interface to use an RFC5737 nonrouteable address
629	# and a non-default fib
630	ADDR0="192.0.2.2"
631	ADDR1="192.0.2.3"
632	SUBNET="192.0.2.0"
633	MASK="24"
634	# Use a different IP on the same subnet as the target
635	TARGET="192.0.2.100"
636	SRCDIR=`atf_get_srcdir`
637
638	# Check system configuration
639	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
640		atf_skip "This test requires net.add_addr_allfibs=0"
641	fi
642	get_fibs 2
643
644	# Configure the TAP interfaces
645	setup_tap ${FIB0} inet ${ADDR0} ${MASK}
646	TARGET_TAP=${TAP}
647	setup_tap ${FIB1} inet ${ADDR1} ${MASK}
648
649	# Send a UDP packet with SO_DONTROUTE.  In the failure case, it will
650	# return ENETUNREACH, or send the packet to the wrong tap
651	atf_check -o ignore setfib ${FIB0} \
652		${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
653	cleanup_ifaces
654
655	# Repeat, but this time target the other tap
656	setup_tap ${FIB0} inet ${ADDR0} ${MASK}
657	setup_tap ${FIB1} inet ${ADDR1} ${MASK}
658	TARGET_TAP=${TAP}
659
660	atf_check -o ignore setfib ${FIB1} \
661		${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
662}
663
664udp_dontroute_cleanup()
665{
666	cleanup_ifaces
667}
668
669atf_test_case udp_dontroute6 cleanup
670udp_dontroute6_head()
671{
672	atf_set "descr" "Source address selection for UDP IPv6 packets with SO_DONTROUTE on non-default FIBs works"
673	atf_set "require.user" "root"
674	atf_set "require.config" "fibs"
675}
676
677udp_dontroute6_body()
678{
679	if [ "$(atf_config_get ci false)" = "true" ]; then
680		atf_skip "https://bugs.freebsd.org/244172"
681	fi
682	# Configure the TAP interface to use an RFC3849 nonrouteable address
683	# and a non-default fib
684	ADDR0="2001:db8::2"
685	ADDR1="2001:db8::3"
686	SUBNET="2001:db8::"
687	MASK="64"
688	# Use a different IP on the same subnet as the target
689	TARGET="2001:db8::100"
690	SRCDIR=`atf_get_srcdir`
691
692	# Check system configuration
693	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
694		atf_skip "This test requires net.add_addr_allfibs=0"
695	fi
696	get_fibs 2
697
698	# Configure the TAP interfaces.  Use no_dad so the addresses will be
699	# ready right away and won't be marked as tentative until DAD
700	# completes.
701	setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad
702	TARGET_TAP=${TAP}
703	setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad
704
705	# Send a UDP packet with SO_DONTROUTE.  In the failure case, it will
706	# return ENETUNREACH, or send the packet to the wrong tap
707	atf_check -o ignore setfib ${FIB0} \
708		${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP}
709	cleanup_ifaces
710
711	# Repeat, but this time target the other tap
712	setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad
713	setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad
714	TARGET_TAP=${TAP}
715
716	atf_check -o ignore setfib ${FIB1} \
717		${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP}
718}
719
720udp_dontroute6_cleanup()
721{
722	cleanup_ifaces
723}
724
725
726atf_init_test_cases()
727{
728	atf_add_test_case arpresolve_checks_interface_fib
729	atf_add_test_case loopback_and_network_routes_on_nondefault_fib
730	atf_add_test_case loopback_and_network_routes_on_nondefault_fib_inet6
731	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
732	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet_inet6
733	atf_add_test_case same_ip_multiple_ifaces_fib0
734	atf_add_test_case same_ip_multiple_ifaces
735	atf_add_test_case same_ip_multiple_ifaces_inet6
736	atf_add_test_case slaac_on_nondefault_fib6
737	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
738	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6
739	atf_add_test_case udp_dontroute
740	atf_add_test_case udp_dontroute6
741}
742
743# Looks up one or more fibs from the configuration data and validates them.
744# Returns the results in the env varilables FIB0, FIB1, etc.
745
746# parameter numfibs	The number of fibs to lookup
747get_fibs()
748{
749	NUMFIBS=$1
750	net_fibs=`sysctl -n net.fibs`
751	i=0
752	while [ $i -lt "$NUMFIBS" ]; do
753		fib=`atf_config_get "fibs" | \
754			awk -v i=$(( i + 1 )) '{print $i}'`
755		echo "fib is ${fib}"
756		eval FIB${i}=${fib}
757		if [ "$fib" -ge "$net_fibs" ]; then
758			atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}"
759		fi
760		i=$(( $i + 1 ))
761	done
762}
763
764# Creates a new pair of connected epair(4) interface, registers them for
765# cleanup, and returns their namen via the environment variables EPAIRA and
766# EPAIRB
767get_epair()
768{
769	local EPAIRD
770
771	if  (which pfctl && pfctl -s info | grep -q 'Status: Enabled') ||
772	    [ `sysctl -n net.inet.ip.fw.enable` = "1" ] ||
773	    (which ipf && ipf -V); then
774		atf_skip "firewalls interfere with this test"
775	fi
776
777	if EPAIRD=`ifconfig epair create`; then
778		# Record the epair device so we can clean it up later
779		echo ${EPAIRD} >> "ifaces_to_cleanup"
780		EPAIRA=${EPAIRD}
781		EPAIRB=${EPAIRD%a}b
782	else
783		atf_skip "Could not create epair(4) interfaces"
784	fi
785}
786
787# Creates a new tap(4) interface, registers it for cleanup, and returns the
788# name via the environment variable TAP
789get_tap()
790{
791	local TAPD
792
793	if TAPD=`ifconfig tap create`; then
794		# Record the TAP device so we can clean it up later
795		echo ${TAPD} >> "ifaces_to_cleanup"
796		TAP=${TAPD}
797	else
798		atf_skip "Could not create a tap(4) interface"
799	fi
800}
801
802# Configure an ethernet interface
803# parameters:
804# Interface name
805# fib
806# Protocol (inet or inet6)
807# IP address
808# Netmask in number of bits (eg 24 or 8)
809# Extra flags
810# Return: None
811setup_iface()
812{
813	local IFACE=$1
814	local FIB=$2
815	local PROTO=$3
816	local ADDR=$4
817	local MASK=$5
818	local FLAGS=$6
819	echo setfib ${FIB} \
820		ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
821	setfib ${FIB} ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
822}
823
824# Create a tap(4) interface, configure it, and register it for cleanup.
825# parameters:
826# fib
827# Protocol (inet or inet6)
828# IP address
829# Netmask in number of bits (eg 24 or 8)
830# Extra flags
831# Return: the tap interface name as the env variable TAP
832setup_tap()
833{
834	get_tap
835	setup_iface "$TAP" "$@"
836}
837
838cleanup_ifaces()
839{
840	if [ -f ifaces_to_cleanup ]; then
841		for iface in $(cat ifaces_to_cleanup); do
842			echo ifconfig "${iface}" destroy
843			ifconfig "${iface}" destroy 2>/dev/null || true
844		done
845		rm -f ifaces_to_cleanup
846	fi
847}
848