]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - tests/sys/netinet/fibs_test.sh
MFC changes relating to running multiple interfaces on different fibs but
[FreeBSD/stable/10.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 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()
50 {
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"
55 }
56 arpresolve_checks_interface_fib_body()
57 {
58         # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
59         # and a non-default fib
60         ADDR0="192.0.2.2"
61         ADDR1="192.0.2.3"
62         SUBNET="192.0.2.0"
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.
65         MASK0="24"
66         MASK1="25"
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"
70
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"
74         fi
75         get_fibs 2
76
77         # Configure TAP interfaces
78         setup_tap "$FIB0" ${ADDR0} ${MASK0}
79         TAP0=$TAP
80         setup_tap "$FIB1" ${ADDR1} ${MASK1}
81         TAP1=$TAP
82
83         # Simulate a crossover cable
84         socat /dev/${TAP0} /dev/${TAP1} &
85         SOCAT_PID=$!
86         echo ${SOCAT_PID} >> "processes_to_kill"
87
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 \
92                 ${ADDR1}
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}
98 }
99 arpresolve_checks_interface_fib_cleanup()
100 {
101         for PID in `cat "processes_to_kill"`; do
102                 kill $PID
103         done
104         cleanup_tap
105 }
106
107
108 # Regression test for kern/187549
109 atf_test_case loopback_and_network_routes_on_nondefault_fib cleanup
110 loopback_and_network_routes_on_nondefault_fib_head()
111 {
112         atf_set "descr" "When creating and deleting loopback routes, use the interface's fib"
113         atf_set "require.user" "root"
114         atf_set "require.config" "fibs"
115 }
116
117 loopback_and_network_routes_on_nondefault_fib_body()
118 {
119         atf_expect_fail "kern/187549 Host and network routes for a new interface appear in the wrong FIB"
120         # Configure the TAP interface to use an RFC5737 nonrouteable address
121         # and a non-default fib
122         ADDR="192.0.2.2"
123         SUBNET="192.0.2.0"
124         MASK="24"
125
126         # Check system configuration
127         if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
128                 atf_skip "This test requires net.add_addr_allfibs=0"
129         fi
130         get_fibs 1
131
132         # Configure a TAP interface
133         setup_tap ${FIB0} ${ADDR} ${MASK}
134
135         # Check whether the host route exists in only the correct FIB
136         setfib ${FIB0} netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
137         if [ 0 -ne $? ]; then
138                 setfib ${FIB0} netstat -rn -f inet
139                 atf_fail "Host route did not appear in the correct FIB"
140         fi
141         setfib 0 netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
142         if [ 0 -eq $? ]; then
143                 setfib 0 netstat -rn -f inet
144                 atf_fail "Host route appeared in the wrong FIB"
145         fi
146
147         # Check whether the network route exists in only the correct FIB
148         setfib ${FIB0} netstat -rn -f inet | \
149                 grep -q "^${SUBNET}/${MASK}.*${TAPD}"
150         if [ 0 -ne $? ]; then
151                 setfib ${FIB0} netstat -rn -f inet
152                 atf_fail "Network route did not appear in the correct FIB"
153         fi
154         setfib 0 netstat -rn -f inet | \
155                 grep -q "^${SUBNET}/${MASK}.*${TAPD}"
156         if [ 0 -eq $? ]; then
157                 setfib ${FIB0} netstat -rn -f inet
158                 atf_fail "Network route appeared in the wrong FIB"
159         fi
160 }
161
162 loopback_and_network_routes_on_nondefault_fib_cleanup()
163 {
164         cleanup_tap
165 }
166
167
168 # Regression test for kern/187552
169 atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup
170 default_route_with_multiple_fibs_on_same_subnet_head()
171 {
172         atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default routes"
173         atf_set "require.user" "root"
174         atf_set "require.config" "fibs"
175 }
176
177 default_route_with_multiple_fibs_on_same_subnet_body()
178 {
179         # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
180         # and a non-default fib
181         ADDR0="192.0.2.2"
182         ADDR1="192.0.2.3"
183         GATEWAY="192.0.2.1"
184         SUBNET="192.0.2.0"
185         MASK="24"
186
187         # Check system configuration
188         if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
189                 atf_skip "This test requires net.add_addr_allfibs=0"
190         fi
191         get_fibs 2
192
193         # Configure TAP interfaces
194         setup_tap "$FIB0" ${ADDR0} ${MASK}
195         TAP0=$TAP
196         setup_tap "$FIB1" ${ADDR1} ${MASK}
197         TAP1=$TAP
198
199         # Attempt to add default routes
200         setfib ${FIB0} route add default ${GATEWAY}
201         setfib ${FIB1} route add default ${GATEWAY}
202
203         # Verify that the default route exists for both fibs, with their
204         # respective interfaces.
205         atf_check -o match:"^default.*${TAP0}$" \
206                 setfib ${FIB0} netstat -rn -f inet
207         atf_check -o match:"^default.*${TAP1}$" \
208                 setfib ${FIB1} netstat -rn -f inet
209 }
210
211 default_route_with_multiple_fibs_on_same_subnet_cleanup()
212 {
213         cleanup_tap
214 }
215
216
217 # Regression test for kern/187550
218 atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
219 subnet_route_with_multiple_fibs_on_same_subnet_head()
220 {
221         atf_set "descr" "Multiple FIBs can have subnet routes for the same subnet"
222         atf_set "require.user" "root"
223         atf_set "require.config" "fibs"
224 }
225
226 subnet_route_with_multiple_fibs_on_same_subnet_body()
227 {
228         # Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
229         # and a non-default fib
230         ADDR0="192.0.2.2"
231         ADDR1="192.0.2.3"
232         SUBNET="192.0.2.0"
233         MASK="24"
234
235         # Check system configuration
236         if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
237                 atf_skip "This test requires net.add_addr_allfibs=0"
238         fi
239         get_fibs 2
240
241         # Configure TAP interfaces
242         setup_tap "$FIB0" ${ADDR0} ${MASK}
243         setup_tap "$FIB1" ${ADDR1} ${MASK}
244
245         # Check that a subnet route exists on both fibs
246         atf_check -o ignore setfib "$FIB0" route get $ADDR1
247         atf_check -o ignore setfib "$FIB1" route get $ADDR0
248 }
249
250 subnet_route_with_multiple_fibs_on_same_subnet_cleanup()
251 {
252         cleanup_tap
253 }
254
255 # Test that source address selection works correctly for UDP packets with
256 # SO_DONTROUTE set that are sent on non-default FIBs.
257 # This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host"
258 # Regression test for kern/187553
259 #
260 # The root cause was that ifa_ifwithnet() did not have a fib argument.  It
261 # would return an address from an interface on any FIB that had a subnet route
262 # for the destination.  If more than one were available, it would choose the
263 # most specific.  This is most easily tested by creating a FIB without a
264 # default route, then trying to send a UDP packet with SO_DONTROUTE set to an
265 # address which is not routable on that FIB.  Absent the fix for this bug,
266 # in_pcbladdr would choose an interface on any FIB with a default route.  With
267 # the fix, you will get EUNREACH or ENETUNREACH.
268 atf_test_case udp_dontroute cleanup
269 udp_dontroute_head()
270 {
271         atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works"
272         atf_set "require.user" "root"
273         atf_set "require.config" "fibs"
274 }
275
276 udp_dontroute_body()
277 {
278         atf_expect_fail "kern/187553 Source address selection for UDP packets with SO_DONTROUTE uses the default FIB"
279         # Configure the TAP interface to use an RFC5737 nonrouteable address
280         # and a non-default fib
281         ADDR0="192.0.2.2"
282         ADDR1="192.0.2.3"
283         SUBNET="192.0.2.0"
284         MASK="24"
285         # Use a different IP on the same subnet as the target
286         TARGET="192.0.2.100"
287         SRCDIR=`atf_get_srcdir`
288
289         # Check system configuration
290         if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
291                 atf_skip "This test requires net.add_addr_allfibs=0"
292         fi
293         get_fibs 2
294
295         # Configure the TAP interfaces
296         setup_tap ${FIB0} ${ADDR0} ${MASK}
297         TARGET_TAP=${TAP}
298         setup_tap ${FIB1} ${ADDR1} ${MASK}
299
300         # Send a UDP packet with SO_DONTROUTE.  In the failure case, it will
301         # return ENETUNREACH, or send the packet to the wrong tap
302         atf_check -o ignore setfib ${FIB0} \
303                 ${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
304         cleanup_tap
305
306         # Repeat, but this time target the other tap
307         setup_tap ${FIB0} ${ADDR0} ${MASK}
308         setup_tap ${FIB1} ${ADDR1} ${MASK}
309         TARGET_TAP=${TAP}
310
311         atf_check -o ignore setfib ${FIB1} \
312                 ${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
313 }
314
315 udp_dontroute_cleanup()
316 {
317         cleanup_tap
318 }
319
320
321 atf_init_test_cases()
322 {
323         atf_add_test_case arpresolve_checks_interface_fib
324         atf_add_test_case loopback_and_network_routes_on_nondefault_fib
325         atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
326         atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
327         atf_add_test_case udp_dontroute
328 }
329
330 # Looks up one or more fibs from the configuration data and validates them.
331 # Returns the results in the env varilables FIB0, FIB1, etc.
332
333 # parameter numfibs     The number of fibs to lookup
334 get_fibs()
335 {
336         NUMFIBS=$1
337         net_fibs=`sysctl -n net.fibs`
338         i=0
339         while [ $i -lt "$NUMFIBS" ]; do
340                 fib=`atf_config_get "fibs" | \
341                         awk -v i=$(( i + 1 )) '{print $i}'`
342                 echo "fib is ${fib}"
343                 eval FIB${i}=${fib}
344                 if [ "$fib" -ge "$net_fibs" ]; then
345                         atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}"
346                 fi
347                 i=$(( $i + 1 ))
348         done
349 }
350
351 # Creates a new tap(4) interface, registers it for cleanup, and returns the
352 # name via the environment variable TAP
353 get_tap()
354 {
355         local TAPN=0
356         while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do
357                 if [ "$TAPN" -ge 8 ]; then
358                         atf_skip "Could not create a tap(4) interface"
359                 else
360                         TAPN=$(($TAPN + 1))
361                 fi
362         done
363         local TAPD=tap${TAPN}
364         # Record the TAP device so we can clean it up later
365         echo ${TAPD} >> "tap_devices_to_cleanup"
366         TAP=${TAPD}
367 }
368
369 # Create a tap(4) interface, configure it, and register it for cleanup.
370 # parameters:
371 # fib
372 # IP address
373 # Netmask in number of bits (eg 24 or 8)
374 # Return: the tap interface name as the env variable TAP
375 setup_tap()
376 {
377         local FIB=$1
378         local ADDR=$2
379         local MASK=$3
380         get_tap
381         echo setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
382         setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
383 }
384
385 cleanup_tap()
386 {
387         for TAPD in `cat "tap_devices_to_cleanup"`; do
388                 ifconfig ${TAPD} destroy
389         done
390         rm "tap_devices_to_cleanup"
391 }