]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/netinet/fibs_test.sh
Integrate capsicum-test into the FreeBSD test suite
[FreeBSD/FreeBSD.git] / tests / sys / netinet / fibs_test.sh
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
47 atf_test_case arpresolve_checks_interface_fib cleanup
48 arpresolve_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 }
55 arpresolve_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 }
92 arpresolve_checks_interface_fib_cleanup()
93 {
94         cleanup_ifaces
95 }
96
97
98 # Regression test for kern/187549
99 atf_test_case loopback_and_network_routes_on_nondefault_fib cleanup
100 loopback_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
107 loopback_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
151 loopback_and_network_routes_on_nondefault_fib_cleanup()
152 {
153         cleanup_ifaces
154 }
155
156 atf_test_case loopback_and_network_routes_on_nondefault_fib_inet6 cleanup
157 loopback_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
164 loopback_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
208 loopback_and_network_routes_on_nondefault_fib_inet6_cleanup()
209 {
210         cleanup_ifaces
211 }
212
213
214 # Regression test for kern/187552
215 atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup
216 default_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
223 default_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
257 default_route_with_multiple_fibs_on_same_subnet_cleanup()
258 {
259         cleanup_ifaces
260 }
261
262 atf_test_case default_route_with_multiple_fibs_on_same_subnet_inet6 cleanup
263 default_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
270 default_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
304 default_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.
314 atf_test_case same_ip_multiple_ifaces_fib0 cleanup
315 same_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 }
321 same_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 }
344 same_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.
357 atf_test_case same_ip_multiple_ifaces cleanup
358 same_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 }
364 same_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 }
393 same_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
403 atf_test_case same_ip_multiple_ifaces_inet6 cleanup
404 same_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 }
410 same_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 }
440 same_ip_multiple_ifaces_inet6_cleanup()
441 {
442         cleanup_ifaces
443 }
444
445 atf_test_case slaac_on_nondefault_fib6 cleanup
446 slaac_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 }
452 slaac_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 }
510 slaac_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
532 atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
533 subnet_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
540 subnet_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
564 subnet_route_with_multiple_fibs_on_same_subnet_cleanup()
565 {
566         cleanup_ifaces
567 }
568
569 atf_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6 cleanup
570 subnet_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
577 subnet_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
601 subnet_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.
619 atf_test_case udp_dontroute cleanup
620 udp_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
627 udp_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
665 udp_dontroute_cleanup()
666 {
667         cleanup_ifaces
668 }
669
670 atf_test_case udp_dontroute6 cleanup
671 udp_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
678 udp_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
718 udp_dontroute6_cleanup()
719 {
720         cleanup_ifaces
721 }
722
723
724 atf_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
745 get_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
765 get_epair()
766 {
767         local EPAIRD
768
769         if  (which pfctl && pfctl -s info | grep -q 'Status: Enabled') || 
770             [ `sysctl -n net.inet.ip.fw.enable` = "1" ] ||
771             (which ipf && ipf -V); then
772                 atf_skip "firewalls interfere with this test"
773         fi
774
775         if EPAIRD=`ifconfig epair create`; then
776                 # Record the epair device so we can clean it up later
777                 echo ${EPAIRD} >> "ifaces_to_cleanup"
778                 EPAIRA=${EPAIRD}
779                 EPAIRB=${EPAIRD%a}b
780         else
781                 atf_skip "Could not create epair(4) interfaces"
782         fi
783 }
784
785 # Creates a new tap(4) interface, registers it for cleanup, and returns the
786 # name via the environment variable TAP
787 get_tap()
788 {
789         local TAPD
790
791         if TAPD=`ifconfig tap create`; then
792                 # Record the TAP device so we can clean it up later
793                 echo ${TAPD} >> "ifaces_to_cleanup"
794                 TAP=${TAPD}
795         else
796                 atf_skip "Could not create a tap(4) interface"
797         fi
798 }
799
800 # Configure an ethernet interface
801 # parameters:
802 # Interface name
803 # fib
804 # Protocol (inet or inet6)
805 # IP address
806 # Netmask in number of bits (eg 24 or 8)
807 # Extra flags
808 # Return: None
809 setup_iface()
810 {
811         local IFACE=$1
812         local FIB=$2
813         local PROTO=$3
814         local ADDR=$4
815         local MASK=$5
816         local FLAGS=$6
817         echo setfib ${FIB} \
818                 ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
819         setfib ${FIB} ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
820 }
821
822 # Create a tap(4) interface, configure it, and register it for cleanup.
823 # parameters:
824 # fib
825 # Protocol (inet or inet6)
826 # IP address
827 # Netmask in number of bits (eg 24 or 8)
828 # Extra flags
829 # Return: the tap interface name as the env variable TAP
830 setup_tap()
831 {
832         get_tap
833         setup_iface "$TAP" "$@"
834 }
835
836 cleanup_ifaces()
837 {
838         if [ -f ifaces_to_cleanup ]; then
839                 for iface in $(cat ifaces_to_cleanup); do
840                         echo ifconfig "${iface}" destroy
841                         ifconfig "${iface}" destroy 2>/dev/null || true
842                 done
843                 rm -f ifaces_to_cleanup
844         fi
845 }