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