xref: /freebsd/tests/sys/netinet/fibs_test.sh (revision d93a896ef95946b0bf1219866fcb324b78543444)
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	# Configure the TAP interface to use an RFC3849 nonrouteable address
681	# and a non-default fib
682	ADDR0="2001:db8::2"
683	ADDR1="2001:db8::3"
684	SUBNET="2001:db8::"
685	MASK="64"
686	# Use a different IP on the same subnet as the target
687	TARGET="2001:db8::100"
688	SRCDIR=`atf_get_srcdir`
689
690	# Check system configuration
691	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
692		atf_skip "This test requires net.add_addr_allfibs=0"
693	fi
694	get_fibs 2
695
696	# Configure the TAP interfaces.  Use no_dad so the addresses will be
697	# ready right away and won't be marked as tentative until DAD
698	# completes.
699	setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad
700	TARGET_TAP=${TAP}
701	setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad
702
703	# Send a UDP packet with SO_DONTROUTE.  In the failure case, it will
704	# return ENETUNREACH, or send the packet to the wrong tap
705	atf_check -o ignore setfib ${FIB0} \
706		${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP}
707	cleanup_ifaces
708
709	# Repeat, but this time target the other tap
710	setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad
711	setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad
712	TARGET_TAP=${TAP}
713
714	atf_check -o ignore setfib ${FIB1} \
715		${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP}
716}
717
718udp_dontroute6_cleanup()
719{
720	cleanup_ifaces
721}
722
723
724atf_init_test_cases()
725{
726	atf_add_test_case arpresolve_checks_interface_fib
727	atf_add_test_case loopback_and_network_routes_on_nondefault_fib
728	atf_add_test_case loopback_and_network_routes_on_nondefault_fib_inet6
729	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
730	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet_inet6
731	atf_add_test_case same_ip_multiple_ifaces_fib0
732	atf_add_test_case same_ip_multiple_ifaces
733	atf_add_test_case same_ip_multiple_ifaces_inet6
734	atf_add_test_case slaac_on_nondefault_fib6
735	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
736	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6
737	atf_add_test_case udp_dontroute
738	atf_add_test_case udp_dontroute6
739}
740
741# Looks up one or more fibs from the configuration data and validates them.
742# Returns the results in the env varilables FIB0, FIB1, etc.
743
744# parameter numfibs	The number of fibs to lookup
745get_fibs()
746{
747	NUMFIBS=$1
748	net_fibs=`sysctl -n net.fibs`
749	i=0
750	while [ $i -lt "$NUMFIBS" ]; do
751		fib=`atf_config_get "fibs" | \
752			awk -v i=$(( i + 1 )) '{print $i}'`
753		echo "fib is ${fib}"
754		eval FIB${i}=${fib}
755		if [ "$fib" -ge "$net_fibs" ]; then
756			atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}"
757		fi
758		i=$(( $i + 1 ))
759	done
760}
761
762# Creates a new pair of connected epair(4) interface, registers them for
763# cleanup, and returns their namen via the environment variables EPAIRA and
764# EPAIRB
765get_epair()
766{
767	local EPAIRD
768
769	if EPAIRD=`ifconfig epair create`; then
770		# Record the epair device so we can clean it up later
771		echo ${EPAIRD} >> "ifaces_to_cleanup"
772		EPAIRA=${EPAIRD}
773		EPAIRB=${EPAIRD%a}b
774	else
775		atf_skip "Could not create epair(4) interfaces"
776	fi
777}
778
779# Creates a new tap(4) interface, registers it for cleanup, and returns the
780# name via the environment variable TAP
781get_tap()
782{
783	local TAPD
784
785	if TAPD=`ifconfig tap create`; then
786		# Record the TAP device so we can clean it up later
787		echo ${TAPD} >> "ifaces_to_cleanup"
788		TAP=${TAPD}
789	else
790		atf_skip "Could not create a tap(4) interface"
791	fi
792}
793
794# Configure an ethernet interface
795# parameters:
796# Interface name
797# fib
798# Protocol (inet or inet6)
799# IP address
800# Netmask in number of bits (eg 24 or 8)
801# Extra flags
802# Return: None
803setup_iface()
804{
805	local IFACE=$1
806	local FIB=$2
807	local PROTO=$3
808	local ADDR=$4
809	local MASK=$5
810	local FLAGS=$6
811	echo setfib ${FIB} \
812		ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
813	setfib ${FIB} ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
814}
815
816# Create a tap(4) interface, configure it, and register it for cleanup.
817# parameters:
818# fib
819# Protocol (inet or inet6)
820# IP address
821# Netmask in number of bits (eg 24 or 8)
822# Extra flags
823# Return: the tap interface name as the env variable TAP
824setup_tap()
825{
826	get_tap
827	setup_iface "$TAP" "$@"
828}
829
830cleanup_ifaces()
831{
832	if [ -f ifaces_to_cleanup ]; then
833		for iface in $(cat ifaces_to_cleanup); do
834			echo ifconfig "${iface}" destroy
835			ifconfig "${iface}" destroy 2>/dev/null || true
836		done
837		rm -f ifaces_to_cleanup
838	fi
839}
840