xref: /freebsd/tests/sys/netinet/fibs_test.sh (revision 076ad2f8)
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	atf_expect_fail "PR196361 IPv6 network routes don't respect net.add_addr_allfibs=0"
167	# Configure the TAP interface to use a nonrouteable RFC3849
168	# address and a non-default fib
169	ADDR="2001:db8::2"
170	SUBNET="2001:db8::"
171	MASK="64"
172
173	# Check system configuration
174	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
175		atf_skip "This test requires net.add_addr_allfibs=0"
176	fi
177	get_fibs 1
178
179	# Configure a TAP interface
180	setup_tap ${FIB0} inet6 ${ADDR} ${MASK}
181
182	# Check whether the host route exists in only the correct FIB
183	setfib ${FIB0} netstat -rn -f inet6 | grep -q "^${ADDR}.*UHS.*lo0"
184	if [ 0 -ne $? ]; then
185		setfib ${FIB0} netstat -rn -f inet6
186		atf_fail "Host route did not appear in the correct FIB"
187	fi
188	setfib 0 netstat -rn -f inet6 | grep -q "^${ADDR}.*UHS.*lo0"
189	if [ 0 -eq $? ]; then
190		setfib 0 netstat -rn -f inet6
191		atf_fail "Host route appeared in the wrong FIB"
192	fi
193
194	# Check whether the network route exists in only the correct FIB
195	setfib ${FIB0} netstat -rn -f inet6 | \
196		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
197	if [ 0 -ne $? ]; then
198		setfib ${FIB0} netstat -rn -f inet6
199		atf_fail "Network route did not appear in the correct FIB"
200	fi
201	setfib 0 netstat -rn -f inet6 | \
202		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
203	if [ 0 -eq $? ]; then
204		setfib 0 netstat -rn -f inet6
205		atf_fail "Network route appeared in the wrong FIB"
206	fi
207}
208
209loopback_and_network_routes_on_nondefault_fib_inet6_cleanup()
210{
211	cleanup_ifaces
212}
213
214
215# Regression test for kern/187552
216atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup
217default_route_with_multiple_fibs_on_same_subnet_head()
218{
219	atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default IPv4 routes"
220	atf_set "require.user" "root"
221	atf_set "require.config" "fibs"
222}
223
224default_route_with_multiple_fibs_on_same_subnet_body()
225{
226	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
227	# and a non-default fib
228	ADDR0="192.0.2.2"
229	ADDR1="192.0.2.3"
230	GATEWAY="192.0.2.1"
231	SUBNET="192.0.2.0"
232	MASK="24"
233
234	# Check system configuration
235	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
236		atf_skip "This test requires net.add_addr_allfibs=0"
237	fi
238	get_fibs 2
239
240	# Configure TAP interfaces
241	setup_tap "$FIB0" inet ${ADDR0} ${MASK}
242	TAP0=$TAP
243	setup_tap "$FIB1" inet ${ADDR1} ${MASK}
244	TAP1=$TAP
245
246	# Attempt to add default routes
247	setfib ${FIB0} route add default ${GATEWAY}
248	setfib ${FIB1} route add default ${GATEWAY}
249
250	# Verify that the default route exists for both fibs, with their
251	# respective interfaces.
252	atf_check -o match:"^default.*${TAP0}$" \
253		setfib ${FIB0} netstat -rn -f inet
254	atf_check -o match:"^default.*${TAP1}$" \
255		setfib ${FIB1} netstat -rn -f inet
256}
257
258default_route_with_multiple_fibs_on_same_subnet_cleanup()
259{
260	cleanup_ifaces
261}
262
263atf_test_case default_route_with_multiple_fibs_on_same_subnet_inet6 cleanup
264default_route_with_multiple_fibs_on_same_subnet_inet6_head()
265{
266	atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default IPv6 routes"
267	atf_set "require.user" "root"
268	atf_set "require.config" "fibs"
269}
270
271default_route_with_multiple_fibs_on_same_subnet_inet6_body()
272{
273	# Configure the TAP interfaces to use nonrouteable RFC3849
274	# addresses and non-default FIBs
275	ADDR0="2001:db8::2"
276	ADDR1="2001:db8::3"
277	GATEWAY="2001:db8::1"
278	SUBNET="2001:db8::"
279	MASK="64"
280
281	# Check system configuration
282	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
283		atf_skip "This test requires net.add_addr_allfibs=0"
284	fi
285	get_fibs 2
286
287	# Configure TAP interfaces
288	setup_tap "$FIB0" inet6 ${ADDR0} ${MASK}
289	TAP0=$TAP
290	setup_tap "$FIB1" inet6 ${ADDR1} ${MASK}
291	TAP1=$TAP
292
293	# Attempt to add default routes
294	setfib ${FIB0} route -6 add default ${GATEWAY}
295	setfib ${FIB1} route -6 add default ${GATEWAY}
296
297	# Verify that the default route exists for both fibs, with their
298	# respective interfaces.
299	atf_check -o match:"^default.*${TAP0}$" \
300		setfib ${FIB0} netstat -rn -f inet6
301	atf_check -o match:"^default.*${TAP1}$" \
302		setfib ${FIB1} netstat -rn -f inet6
303}
304
305default_route_with_multiple_fibs_on_same_subnet_inet6_cleanup()
306{
307	cleanup_ifaces
308}
309
310
311# Regression test for PR kern/189089
312# Create two tap interfaces and assign them both the same IP address but with
313# different netmasks, and both on the default FIB.  Then remove one's IP
314# address.  Hopefully the machine won't panic.
315atf_test_case same_ip_multiple_ifaces_fib0 cleanup
316same_ip_multiple_ifaces_fib0_head()
317{
318	atf_set "descr" "Can remove an IPv4 alias from an interface when the same IPv4 is also assigned to another interface."
319	atf_set "require.user" "root"
320	atf_set "require.config" "fibs"
321}
322same_ip_multiple_ifaces_fib0_body()
323{
324	ADDR="192.0.2.2"
325	MASK0="24"
326	MASK1="32"
327
328	# Unlike most of the tests in this file, this is applicable regardless
329	# of net.add_addr_allfibs
330
331	# Setup the interfaces, then remove one alias.  It should not panic.
332	setup_tap 0 inet ${ADDR} ${MASK0}
333	TAP0=${TAP}
334	setup_tap 0 inet ${ADDR} ${MASK1}
335	TAP1=${TAP}
336	ifconfig ${TAP1} -alias ${ADDR}
337
338	# Do it again, in the opposite order.  It should not panic.
339	setup_tap 0 inet ${ADDR} ${MASK0}
340	TAP0=${TAP}
341	setup_tap 0 inet ${ADDR} ${MASK1}
342	TAP1=${TAP}
343	ifconfig ${TAP0} -alias ${ADDR}
344}
345same_ip_multiple_ifaces_fib0_cleanup()
346{
347	cleanup_ifaces
348}
349
350# Regression test for PR kern/189088
351# Test that removing an IP address works even if the same IP is assigned to a
352# different interface, on a different FIB.  Tests the same code that whose
353# panic was regressed by same_ip_multiple_ifaces_fib0.
354# Create two tap interfaces and assign them both the same IP address but with
355# different netmasks, and on different FIBs.  Then remove one's IP
356# address.  Hopefully the machine won't panic.  Also, the IP's hostroute should
357# dissappear from the correct fib.
358atf_test_case same_ip_multiple_ifaces cleanup
359same_ip_multiple_ifaces_head()
360{
361	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."
362	atf_set "require.user" "root"
363	atf_set "require.config" "fibs"
364}
365same_ip_multiple_ifaces_body()
366{
367	atf_expect_fail "kern/189088 Assigning the same IP to multiple interfaces in different FIBs creates a host route for only one"
368	ADDR="192.0.2.2"
369	MASK0="24"
370	MASK1="32"
371
372	# Unlike most of the tests in this file, this is applicable regardless
373	# of net.add_addr_allfibs
374	get_fibs 2
375
376	# Setup the interfaces, then remove one alias.  It should not panic.
377	setup_tap ${FIB0} inet ${ADDR} ${MASK0}
378	TAP0=${TAP}
379	setup_tap ${FIB1} inet ${ADDR} ${MASK1}
380	TAP1=${TAP}
381	ifconfig ${TAP1} -alias ${ADDR}
382	atf_check -o not-match:"^${ADDR}[[:space:]]" \
383		setfib ${FIB1} netstat -rn -f inet
384
385	# Do it again, in the opposite order.  It should not panic.
386	setup_tap ${FIB0} inet ${ADDR} ${MASK0}
387	TAP0=${TAP}
388	setup_tap ${FIB1} inet ${ADDR} ${MASK1}
389	TAP1=${TAP}
390	ifconfig ${TAP0} -alias ${ADDR}
391	atf_check -o not-match:"^${ADDR}[[:space:]]" \
392		setfib ${FIB0} netstat -rn -f inet
393}
394same_ip_multiple_ifaces_cleanup()
395{
396	# Due to PR kern/189088, we must destroy the interfaces in LIFO order
397	# in order for the routes to be correctly cleaned up.
398	for TAPD in `tail -r "ifaces_to_cleanup"`; do
399		echo ifconfig ${TAPD} destroy
400		ifconfig ${TAPD} destroy
401	done
402}
403
404atf_test_case same_ip_multiple_ifaces_inet6 cleanup
405same_ip_multiple_ifaces_inet6_head()
406{
407	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."
408	atf_set "require.user" "root"
409	atf_set "require.config" "fibs"
410}
411same_ip_multiple_ifaces_inet6_body()
412{
413	ADDR="2001:db8::2"
414	MASK0="64"
415	MASK1="128"
416
417	# Unlike most of the tests in this file, this is applicable regardless
418	# of net.add_addr_allfibs
419	get_fibs 2
420
421	# Setup the interfaces, then remove one alias.  It should not panic.
422	setup_tap ${FIB0} inet6 ${ADDR} ${MASK0}
423	TAP0=${TAP}
424	setup_tap ${FIB1} inet6 ${ADDR} ${MASK1}
425	TAP1=${TAP}
426	atf_check -s exit:0 ifconfig ${TAP1} inet6 ${ADDR} -alias
427	atf_check -o not-match:"^${ADDR}[[:space:]]" \
428		setfib ${FIB1} netstat -rn -f inet6
429	ifconfig ${TAP1} destroy
430	ifconfig ${TAP0} destroy
431
432	# Do it again, in the opposite order.  It should not panic.
433	setup_tap ${FIB0} inet6 ${ADDR} ${MASK0}
434	TAP0=${TAP}
435	setup_tap ${FIB1} inet6 ${ADDR} ${MASK1}
436	TAP1=${TAP}
437	atf_check -s exit:0 ifconfig ${TAP0} inet6 ${ADDR} -alias
438	atf_check -o not-match:"^${ADDR}[[:space:]]" \
439		setfib ${FIB0} netstat -rn -f inet6
440}
441same_ip_multiple_ifaces_inet6_cleanup()
442{
443	cleanup_ifaces
444}
445
446atf_test_case slaac_on_nondefault_fib6 cleanup
447slaac_on_nondefault_fib6_head()
448{
449	atf_set "descr" "SLAAC correctly installs routes on non-default FIBs"
450	atf_set "require.user" "root"
451	atf_set "require.config" "fibs" "allow_sysctl_side_effects"
452}
453slaac_on_nondefault_fib6_body()
454{
455	# Configure the epair interfaces to use nonrouteable RFC3849
456	# addresses and non-default FIBs
457	ADDR="2001:db8::2"
458	GATEWAY="2001:db8::1"
459	SUBNET="2001:db8:"
460	MASK="64"
461
462	atf_expect_fail "PR196361 IPv6 network routes don't respect net.add_addr_allfibs=0"
463
464	# Check system configuration
465	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
466		atf_skip "This test requires net.add_addr_allfibs=0"
467	fi
468	get_fibs 2
469
470	sysctl -n "net.inet6.ip6.rfc6204w3" >> "rfc6204w3.state"
471	sysctl -n "net.inet6.ip6.forwarding" >> "forwarding.state"
472	# Enable forwarding so the kernel will send RAs
473	sysctl net.inet6.ip6.forwarding=1
474	# Enable RFC6204W3 mode so the kernel will enable default router
475	# selection while also forwarding packets
476	sysctl net.inet6.ip6.rfc6204w3=1
477
478	# Configure epair interfaces
479	get_epair
480	setup_iface "$EPAIRA" "$FIB0" inet6 ${ADDR} ${MASK}
481	echo ifconfig "$EPAIRB" up inet6 fib $FIB1 -ifdisabled accept_rtadv
482	ifconfig "$EPAIRB" inet6 -ifdisabled accept_rtadv fib $FIB1 up
483	rtadvd -p rtadvd.pid -C rtadvd.sock -c /dev/null "$EPAIRA"
484	rtsol "$EPAIRB"
485
486	# Check SLAAC address
487	atf_check -o match:"inet6 ${SUBNET}.*prefixlen ${MASK}.*autoconf" \
488		ifconfig "$EPAIRB"
489	# Check local route
490	atf_check -o match:"${SUBNET}.*\<UHS\>.*lo0" \
491		netstat -rnf inet6 -F $FIB1
492	# Check subnet route
493	atf_check -o match:"${SUBNET}:/${MASK}.*\<U\>.*$EPAIRB" \
494		netstat -rnf inet6 -F $FIB1
495	# Check default route
496	atf_check -o match:"default.*\<UG\>.*$EPAIRB" \
497		netstat -rnf inet6 -F $FIB1
498
499	# Check that none of the above routes appeared on other routes
500	for fib in $( seq 0 $(($(sysctl -n net.fibs) - 1))); do
501		if [ "$fib" = "$FIB1" -o "$fib" = "$FIB0" ]; then
502			continue
503		fi
504		atf_check -o not-match:"${SUBNET}.*\<UHS\>.*lo0" \
505			netstat -rnf inet6 -F $fib
506		atf_check -o not-match:"${SUBNET}:/${MASK}.*\<U\>.*$EPAIRB" \
507			netstat -rnf inet6 -F $fib
508		atf_check -o not-match:"default.*\<UG\>.*$EPAIRB" \
509			netstat -rnf inet6 -F $fib
510	done
511}
512slaac_on_nondefault_fib6_cleanup()
513{
514	cleanup_ifaces
515	if [ -f "rtadvd.pid" ]; then
516		pkill -F rtadvd.pid
517		rm rtadvd.pid
518	fi
519	if [ -f "rfc6204w3.state" ] ; then
520		sysctl "net.inet6.ip6.rfc6204w3"=`cat "rfc6204w3.state"`
521		rm "rfc6204w3.state"
522	fi
523	if [ -f "forwarding.state" ] ; then
524		sysctl "net.inet6.ip6.forwarding"=`cat "forwarding.state"`
525		rm "forwarding.state"
526	fi
527}
528
529# Regression test for kern/187550
530atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
531subnet_route_with_multiple_fibs_on_same_subnet_head()
532{
533	atf_set "descr" "Multiple FIBs can have IPv4 subnet routes for the same subnet"
534	atf_set "require.user" "root"
535	atf_set "require.config" "fibs"
536}
537
538subnet_route_with_multiple_fibs_on_same_subnet_body()
539{
540	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
541	# and a non-default fib
542	ADDR0="192.0.2.2"
543	ADDR1="192.0.2.3"
544	SUBNET="192.0.2.0"
545	MASK="24"
546
547	# Check system configuration
548	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
549		atf_skip "This test requires net.add_addr_allfibs=0"
550	fi
551	get_fibs 2
552
553	# Configure TAP interfaces
554	setup_tap "$FIB0" inet ${ADDR0} ${MASK}
555	setup_tap "$FIB1" inet ${ADDR1} ${MASK}
556
557	# Check that a subnet route exists on both fibs
558	atf_check -o ignore setfib "$FIB0" route get $ADDR1
559	atf_check -o ignore setfib "$FIB1" route get $ADDR0
560}
561
562subnet_route_with_multiple_fibs_on_same_subnet_cleanup()
563{
564	cleanup_ifaces
565}
566
567atf_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6 cleanup
568subnet_route_with_multiple_fibs_on_same_subnet_inet6_head()
569{
570	atf_set "descr" "Multiple FIBs can have IPv6 subnet routes for the same subnet"
571	atf_set "require.user" "root"
572	atf_set "require.config" "fibs"
573}
574
575subnet_route_with_multiple_fibs_on_same_subnet_inet6_body()
576{
577	# Configure the TAP interfaces to use a RFC3849 nonrouteable addresses
578	# and a non-default fib
579	ADDR0="2001:db8::2"
580	ADDR1="2001:db8::3"
581	SUBNET="2001:db8::"
582	MASK="64"
583
584	# Check system configuration
585	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
586		atf_skip "This test requires net.add_addr_allfibs=0"
587	fi
588	get_fibs 2
589
590	# Configure TAP interfaces
591	setup_tap "$FIB0" inet6 ${ADDR0} ${MASK}
592	setup_tap "$FIB1" inet6 ${ADDR1} ${MASK}
593
594	# Check that a subnet route exists on both fibs
595	atf_check -o ignore setfib "$FIB0" route -6 get $ADDR1
596	atf_check -o ignore setfib "$FIB1" route -6 get $ADDR0
597}
598
599subnet_route_with_multiple_fibs_on_same_subnet_inet6_cleanup()
600{
601	cleanup_ifaces
602}
603
604# Test that source address selection works correctly for UDP packets with
605# SO_DONTROUTE set that are sent on non-default FIBs.
606# This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host"
607# Regression test for kern/187553
608#
609# The root cause was that ifa_ifwithnet() did not have a fib argument.  It
610# would return an address from an interface on any FIB that had a subnet route
611# for the destination.  If more than one were available, it would choose the
612# most specific.  This is most easily tested by creating a FIB without a
613# default route, then trying to send a UDP packet with SO_DONTROUTE set to an
614# address which is not routable on that FIB.  Absent the fix for this bug,
615# in_pcbladdr would choose an interface on any FIB with a default route.  With
616# the fix, you will get EUNREACH or ENETUNREACH.
617atf_test_case udp_dontroute cleanup
618udp_dontroute_head()
619{
620	atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works"
621	atf_set "require.user" "root"
622	atf_set "require.config" "fibs"
623}
624
625udp_dontroute_body()
626{
627	# Configure the TAP interface to use an RFC5737 nonrouteable address
628	# and a non-default fib
629	ADDR0="192.0.2.2"
630	ADDR1="192.0.2.3"
631	SUBNET="192.0.2.0"
632	MASK="24"
633	# Use a different IP on the same subnet as the target
634	TARGET="192.0.2.100"
635	SRCDIR=`atf_get_srcdir`
636
637	# Check system configuration
638	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
639		atf_skip "This test requires net.add_addr_allfibs=0"
640	fi
641	get_fibs 2
642
643	# Configure the TAP interfaces
644	setup_tap ${FIB0} inet ${ADDR0} ${MASK}
645	TARGET_TAP=${TAP}
646	setup_tap ${FIB1} inet ${ADDR1} ${MASK}
647
648	# Send a UDP packet with SO_DONTROUTE.  In the failure case, it will
649	# return ENETUNREACH, or send the packet to the wrong tap
650	atf_check -o ignore setfib ${FIB0} \
651		${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
652	cleanup_ifaces
653
654	# Repeat, but this time target the other tap
655	setup_tap ${FIB0} inet ${ADDR0} ${MASK}
656	setup_tap ${FIB1} inet ${ADDR1} ${MASK}
657	TARGET_TAP=${TAP}
658
659	atf_check -o ignore setfib ${FIB1} \
660		${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
661}
662
663udp_dontroute_cleanup()
664{
665	cleanup_ifaces
666}
667
668atf_test_case udp_dontroute6 cleanup
669udp_dontroute6_head()
670{
671	atf_set "descr" "Source address selection for UDP IPv6 packets with SO_DONTROUTE on non-default FIBs works"
672	atf_set "require.user" "root"
673	atf_set "require.config" "fibs"
674}
675
676udp_dontroute6_body()
677{
678	# Configure the TAP interface to use an RFC3849 nonrouteable address
679	# and a non-default fib
680	ADDR0="2001:db8::2"
681	ADDR1="2001:db8::3"
682	SUBNET="2001:db8::"
683	MASK="64"
684	# Use a different IP on the same subnet as the target
685	TARGET="2001:db8::100"
686	SRCDIR=`atf_get_srcdir`
687
688	atf_expect_fail "PR196361 IPv6 network routes don't respect net.add_addr_allfibs=0"
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 TAP 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