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