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