2 # Copyright (c) 2014 Spectra Logic Corporation
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
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.
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.
30 # Authors: Alan Somers (Spectra Logic Corporation)
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.
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.
42 # Create two tap(4) interfaces
43 # Simulate a crossover cable between them by using net/socat
44 # Use nping (from security/nmap) to send an ICMP echo request from one
45 # interface to the other, spoofing the source IP. The source IP must be
46 # spoofed, or else it will already have an entry in the arp table.
47 # Check whether an arp entry exists for the spoofed IP
48 atf_test_case arpresolve_checks_interface_fib cleanup
49 arpresolve_checks_interface_fib_head()
51 atf_set "descr" "arpresolve should check the interface fib, not the default fib, for routes"
52 atf_set "require.user" "root"
53 atf_set "require.config" "fibs"
54 atf_set "require.progs" "socat nping"
56 arpresolve_checks_interface_fib_body()
58 # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
59 # and a non-default fib
63 # Due to bug TBD (regressed by multiple_fibs_on_same_subnet) we need
64 # diffferent subnet masks, or FIB1 won't have a subnet route.
67 # Spoof a MAC that is reserved per RFC7042
68 SPOOF_ADDR="192.0.2.4"
69 SPOOF_MAC="00:00:5E:00:53:00"
71 # Check system configuration
72 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
73 atf_skip "This test requires net.add_addr_allfibs=0"
77 # Configure TAP interfaces
78 setup_tap "$FIB0" ${ADDR0} ${MASK0}
80 setup_tap "$FIB1" ${ADDR1} ${MASK1}
83 # Simulate a crossover cable
84 socat /dev/${TAP0} /dev/${TAP1} &
86 echo ${SOCAT_PID} >> "processes_to_kill"
88 # Send an ICMP echo request with a spoofed source IP
89 setfib 2 nping -c 1 -e ${TAP0} -S ${SPOOF_ADDR} \
90 --source-mac ${SPOOF_MAC} --icmp --icmp-type "echo-request" \
91 --icmp-code 0 --icmp-id 0xdead --icmp-seq 1 --data 0xbeef \
93 # For informational and debugging purposes only, look for the
94 # characteristic error message
95 dmesg | grep "llinfo.*${SPOOF_ADDR}"
96 # Check that the ARP entry exists
97 atf_check -o match:"${SPOOF_ADDR}.*expires" setfib 3 arp ${SPOOF_ADDR}
99 arpresolve_checks_interface_fib_cleanup()
101 if [ -f processes_to_kill ]; then
102 for pid in $(cat processes_to_kill); do
105 rm -f processes_to_kill
111 # Regression test for kern/187549
112 atf_test_case loopback_and_network_routes_on_nondefault_fib cleanup
113 loopback_and_network_routes_on_nondefault_fib_head()
115 atf_set "descr" "When creating and deleting loopback routes, use the interface's fib"
116 atf_set "require.user" "root"
117 atf_set "require.config" "fibs"
120 loopback_and_network_routes_on_nondefault_fib_body()
122 # Configure the TAP interface to use an RFC5737 nonrouteable address
123 # and a non-default fib
128 # Check system configuration
129 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
130 atf_skip "This test requires net.add_addr_allfibs=0"
134 # Configure a TAP interface
135 setup_tap ${FIB0} ${ADDR} ${MASK}
137 # Check whether the host route exists in only the correct FIB
138 setfib ${FIB0} netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
139 if [ 0 -ne $? ]; then
140 setfib ${FIB0} netstat -rn -f inet
141 atf_fail "Host route did not appear in the correct FIB"
143 setfib 0 netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
144 if [ 0 -eq $? ]; then
145 setfib 0 netstat -rn -f inet
146 atf_fail "Host route appeared in the wrong FIB"
149 # Check whether the network route exists in only the correct FIB
150 setfib ${FIB0} netstat -rn -f inet | \
151 grep -q "^${SUBNET}/${MASK}.*${TAPD}"
152 if [ 0 -ne $? ]; then
153 setfib ${FIB0} netstat -rn -f inet
154 atf_fail "Network route did not appear in the correct FIB"
156 setfib 0 netstat -rn -f inet | \
157 grep -q "^${SUBNET}/${MASK}.*${TAPD}"
158 if [ 0 -eq $? ]; then
159 setfib ${FIB0} netstat -rn -f inet
160 atf_fail "Network route appeared in the wrong FIB"
164 loopback_and_network_routes_on_nondefault_fib_cleanup()
170 # Regression test for kern/187552
171 atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup
172 default_route_with_multiple_fibs_on_same_subnet_head()
174 atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default routes"
175 atf_set "require.user" "root"
176 atf_set "require.config" "fibs"
179 default_route_with_multiple_fibs_on_same_subnet_body()
181 # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
182 # and a non-default fib
189 # Check system configuration
190 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
191 atf_skip "This test requires net.add_addr_allfibs=0"
195 # Configure TAP interfaces
196 setup_tap "$FIB0" ${ADDR0} ${MASK}
198 setup_tap "$FIB1" ${ADDR1} ${MASK}
201 # Attempt to add default routes
202 setfib ${FIB0} route add default ${GATEWAY}
203 setfib ${FIB1} route add default ${GATEWAY}
205 # Verify that the default route exists for both fibs, with their
206 # respective interfaces.
207 atf_check -o match:"^default.*${TAP0}$" \
208 setfib ${FIB0} netstat -rn -f inet
209 atf_check -o match:"^default.*${TAP1}$" \
210 setfib ${FIB1} netstat -rn -f inet
213 default_route_with_multiple_fibs_on_same_subnet_cleanup()
219 # Regression test for PR kern/189089
220 # Create two tap interfaces and assign them both the same IP address but with
221 # different netmasks, and both on the default FIB. Then remove one's IP
222 # address. Hopefully the machine won't panic.
223 atf_test_case same_ip_multiple_ifaces_fib0 cleanup
224 same_ip_multiple_ifaces_fib0_head()
226 atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface."
227 atf_set "require.user" "root"
228 atf_set "require.config" "fibs"
230 same_ip_multiple_ifaces_fib0_body()
236 # Unlike most of the tests in this file, this is applicable regardless
237 # of net.add_addr_allfibs
239 # Setup the interfaces, then remove one alias. It should not panic.
240 setup_tap 0 ${ADDR} ${MASK0}
242 setup_tap 0 ${ADDR} ${MASK1}
244 ifconfig ${TAP1} -alias ${ADDR}
246 # Do it again, in the opposite order. It should not panic.
247 setup_tap 0 ${ADDR} ${MASK0}
249 setup_tap 0 ${ADDR} ${MASK1}
251 ifconfig ${TAP0} -alias ${ADDR}
253 same_ip_multiple_ifaces_fib0_cleanup()
258 # Regression test for PR kern/189088
259 # Test that removing an IP address works even if the same IP is assigned to a
260 # different interface, on a different FIB. Tests the same code that whose
261 # panic was regressed by same_ip_multiple_ifaces_fib0.
262 # Create two tap interfaces and assign them both the same IP address but with
263 # different netmasks, and on different FIBs. Then remove one's IP
264 # address. Hopefully the machine won't panic. Also, the IP's hostroute should
265 # dissappear from the correct fib.
266 atf_test_case same_ip_multiple_ifaces cleanup
267 same_ip_multiple_ifaces_head()
269 atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface, on non-default FIBs."
270 atf_set "require.user" "root"
271 atf_set "require.config" "fibs"
273 same_ip_multiple_ifaces_body()
275 atf_expect_fail "kern/189088 Assigning the same IP to multiple interfaces in different FIBs creates a host route for only one"
280 # Unlike most of the tests in this file, this is applicable regardless
281 # of net.add_addr_allfibs
284 # Setup the interfaces, then remove one alias. It should not panic.
285 setup_tap ${FIB0} ${ADDR} ${MASK0}
287 setup_tap ${FIB1} ${ADDR} ${MASK1}
289 ifconfig ${TAP1} -alias ${ADDR}
290 atf_check -o not-match:"^${ADDR}[[:space:]]" \
291 setfib ${FIB1} netstat -rn -f inet
293 # Do it again, in the opposite order. It should not panic.
294 setup_tap ${FIB0} ${ADDR} ${MASK0}
296 setup_tap ${FIB1} ${ADDR} ${MASK1}
298 ifconfig ${TAP0} -alias ${ADDR}
299 atf_check -o not-match:"^${ADDR}[[:space:]]" \
300 setfib ${FIB0} netstat -rn -f inet
302 same_ip_multiple_ifaces_cleanup()
304 # Due to PR kern/189088, we must destroy the interfaces in LIFO order
305 # in order for the routes to be correctly cleaned up.
306 for TAPD in `tail -r "tap_devices_to_cleanup"`; do
307 ifconfig ${TAPD} destroy
311 # Regression test for kern/187550
312 atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
313 subnet_route_with_multiple_fibs_on_same_subnet_head()
315 atf_set "descr" "Multiple FIBs can have subnet routes for the same subnet"
316 atf_set "require.user" "root"
317 atf_set "require.config" "fibs"
320 subnet_route_with_multiple_fibs_on_same_subnet_body()
322 # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
323 # and a non-default fib
329 # Check system configuration
330 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
331 atf_skip "This test requires net.add_addr_allfibs=0"
335 # Configure TAP interfaces
336 setup_tap "$FIB0" ${ADDR0} ${MASK}
337 setup_tap "$FIB1" ${ADDR1} ${MASK}
339 # Check that a subnet route exists on both fibs
340 atf_check -o ignore setfib "$FIB0" route get $ADDR1
341 atf_check -o ignore setfib "$FIB1" route get $ADDR0
344 subnet_route_with_multiple_fibs_on_same_subnet_cleanup()
349 # Test that source address selection works correctly for UDP packets with
350 # SO_DONTROUTE set that are sent on non-default FIBs.
351 # This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host"
352 # Regression test for kern/187553
354 # The root cause was that ifa_ifwithnet() did not have a fib argument. It
355 # would return an address from an interface on any FIB that had a subnet route
356 # for the destination. If more than one were available, it would choose the
357 # most specific. This is most easily tested by creating a FIB without a
358 # default route, then trying to send a UDP packet with SO_DONTROUTE set to an
359 # address which is not routable on that FIB. Absent the fix for this bug,
360 # in_pcbladdr would choose an interface on any FIB with a default route. With
361 # the fix, you will get EUNREACH or ENETUNREACH.
362 atf_test_case udp_dontroute cleanup
365 atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works"
366 atf_set "require.user" "root"
367 atf_set "require.config" "fibs"
372 atf_expect_fail "kern/187553 Source address selection for UDP packets with SO_DONTROUTE uses the default FIB"
373 # Configure the TAP interface to use an RFC5737 nonrouteable address
374 # and a non-default fib
379 # Use a different IP on the same subnet as the target
381 SRCDIR=`atf_get_srcdir`
383 # Check system configuration
384 if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
385 atf_skip "This test requires net.add_addr_allfibs=0"
389 # Configure the TAP interfaces
390 setup_tap ${FIB0} ${ADDR0} ${MASK}
392 setup_tap ${FIB1} ${ADDR1} ${MASK}
394 # Send a UDP packet with SO_DONTROUTE. In the failure case, it will
395 # return ENETUNREACH, or send the packet to the wrong tap
396 atf_check -o ignore setfib ${FIB0} \
397 ${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
400 # Repeat, but this time target the other tap
401 setup_tap ${FIB0} ${ADDR0} ${MASK}
402 setup_tap ${FIB1} ${ADDR1} ${MASK}
405 atf_check -o ignore setfib ${FIB1} \
406 ${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
409 udp_dontroute_cleanup()
415 atf_init_test_cases()
417 atf_add_test_case arpresolve_checks_interface_fib
418 atf_add_test_case loopback_and_network_routes_on_nondefault_fib
419 atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
420 atf_add_test_case same_ip_multiple_ifaces_fib0
421 atf_add_test_case same_ip_multiple_ifaces
422 atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
423 atf_add_test_case udp_dontroute
426 # Looks up one or more fibs from the configuration data and validates them.
427 # Returns the results in the env varilables FIB0, FIB1, etc.
429 # parameter numfibs The number of fibs to lookup
433 net_fibs=`sysctl -n net.fibs`
435 while [ $i -lt "$NUMFIBS" ]; do
436 fib=`atf_config_get "fibs" | \
437 awk -v i=$(( i + 1 )) '{print $i}'`
440 if [ "$fib" -ge "$net_fibs" ]; then
441 atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}"
447 # Creates a new tap(4) interface, registers it for cleanup, and returns the
448 # name via the environment variable TAP
452 while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do
453 if [ "$TAPN" -ge 8 ]; then
454 atf_skip "Could not create a tap(4) interface"
459 local TAPD=tap${TAPN}
460 # Record the TAP device so we can clean it up later
461 echo ${TAPD} >> "tap_devices_to_cleanup"
465 # Create a tap(4) interface, configure it, and register it for cleanup.
469 # Netmask in number of bits (eg 24 or 8)
470 # Return: the tap interface name as the env variable TAP
477 echo setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
478 setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
483 if [ -f tap_devices_to_cleanup ]; then
484 for tap_device in $(cat tap_devices_to_cleanup); do
485 ifconfig "${tap_device}" destroy
487 rm -f tap_devices_to_cleanup