fibs_test.sh revision 267186
1263445Sasomers#
2263445Sasomers#  Copyright (c) 2014 Spectra Logic Corporation
3263445Sasomers#  All rights reserved.
4265586Sasomers#
5263445Sasomers#  Redistribution and use in source and binary forms, with or without
6263445Sasomers#  modification, are permitted provided that the following conditions
7263445Sasomers#  are met:
8263445Sasomers#  1. Redistributions of source code must retain the above copyright
9263445Sasomers#     notice, this list of conditions, and the following disclaimer,
10263445Sasomers#     without modification.
11263445Sasomers#  2. Redistributions in binary form must reproduce at minimum a disclaimer
12263445Sasomers#     substantially similar to the "NO WARRANTY" disclaimer below
13263445Sasomers#     ("Disclaimer") and any redistribution must be conditioned upon
14263445Sasomers#     including a substantially similar Disclaimer requirement for further
15263445Sasomers#     binary redistribution.
16265586Sasomers#
17263445Sasomers#  NO WARRANTY
18263445Sasomers#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19263445Sasomers#  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20263445Sasomers#  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21263445Sasomers#  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22263445Sasomers#  HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23263445Sasomers#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24263445Sasomers#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25263445Sasomers#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26263445Sasomers#  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27263445Sasomers#  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28263445Sasomers#  POSSIBILITY OF SUCH DAMAGES.
29265586Sasomers#
30263445Sasomers#  Authors: Alan Somers         (Spectra Logic Corporation)
31263445Sasomers#
32263445Sasomers# $FreeBSD: stable/10/tests/sys/netinet/fibs_test.sh 267186 2014-06-06 20:35:40Z asomers $
33263445Sasomers
34263445Sasomers# All of the tests in this file requires the test-suite config variable "fibs"
35263445Sasomers# to be defined to a space-delimited list of FIBs that may be used for testing.
36263445Sasomers
37263445Sasomers# arpresolve should check the interface fib for routes to a target when
38263445Sasomers# creating an ARP table entry.  This is a regression for kern/167947, where
39263445Sasomers# arpresolve only checked the default route.
40263445Sasomers#
41263445Sasomers# Outline:
42263445Sasomers# Create two tap(4) interfaces
43263445Sasomers# Simulate a crossover cable between them by using net/socat
44263445Sasomers# Use nping (from security/nmap) to send an ICMP echo request from one
45263445Sasomers# interface to the other, spoofing the source IP.  The source IP must be
46265586Sasomers# spoofed, or else it will already have an entry in the arp table.
47263445Sasomers# Check whether an arp entry exists for the spoofed IP
48263445Sasomersatf_test_case arpresolve_checks_interface_fib cleanup
49263445Sasomersarpresolve_checks_interface_fib_head()
50263445Sasomers{
51263445Sasomers	atf_set "descr" "arpresolve should check the interface fib, not the default fib, for routes"
52263445Sasomers	atf_set "require.user" "root"
53263445Sasomers	atf_set "require.config" "fibs"
54263445Sasomers	atf_set "require.progs" "socat nping"
55263445Sasomers}
56263445Sasomersarpresolve_checks_interface_fib_body()
57263445Sasomers{
58263445Sasomers	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
59263445Sasomers	# and a non-default fib
60263445Sasomers	ADDR0="192.0.2.2"
61263445Sasomers	ADDR1="192.0.2.3"
62263445Sasomers	SUBNET="192.0.2.0"
63263445Sasomers	# Due to bug TBD (regressed by multiple_fibs_on_same_subnet) we need
64263445Sasomers	# diffferent subnet masks, or FIB1 won't have a subnet route.
65263445Sasomers	MASK0="24"
66263445Sasomers	MASK1="25"
67263445Sasomers	# Spoof a MAC that is reserved per RFC7042
68263445Sasomers	SPOOF_ADDR="192.0.2.4"
69263445Sasomers	SPOOF_MAC="00:00:5E:00:53:00"
70263445Sasomers
71263445Sasomers	# Check system configuration
72263445Sasomers	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
73263445Sasomers		atf_skip "This test requires net.add_addr_allfibs=0"
74263445Sasomers	fi
75263445Sasomers	get_fibs 2
76263445Sasomers
77263445Sasomers	# Configure TAP interfaces
78263445Sasomers	setup_tap "$FIB0" ${ADDR0} ${MASK0}
79263445Sasomers	TAP0=$TAP
80263445Sasomers	setup_tap "$FIB1" ${ADDR1} ${MASK1}
81263445Sasomers	TAP1=$TAP
82263445Sasomers
83263445Sasomers	# Simulate a crossover cable
84263445Sasomers	socat /dev/${TAP0} /dev/${TAP1} &
85263445Sasomers	SOCAT_PID=$!
86263445Sasomers	echo ${SOCAT_PID} >> "processes_to_kill"
87265586Sasomers
88263445Sasomers	# Send an ICMP echo request with a spoofed source IP
89263445Sasomers	setfib 2 nping -c 1 -e ${TAP0} -S ${SPOOF_ADDR} \
90263445Sasomers		--source-mac ${SPOOF_MAC} --icmp --icmp-type "echo-request" \
91263445Sasomers		--icmp-code 0 --icmp-id 0xdead --icmp-seq 1 --data 0xbeef \
92263445Sasomers		${ADDR1}
93263445Sasomers	# For informational and debugging purposes only, look for the
94263445Sasomers	# characteristic error message
95263445Sasomers	dmesg | grep "llinfo.*${SPOOF_ADDR}"
96263445Sasomers	# Check that the ARP entry exists
97263445Sasomers	atf_check -o match:"${SPOOF_ADDR}.*expires" setfib 3 arp ${SPOOF_ADDR}
98263445Sasomers}
99263445Sasomersarpresolve_checks_interface_fib_cleanup()
100263445Sasomers{
101263445Sasomers	for PID in `cat "processes_to_kill"`; do
102263445Sasomers		kill $PID
103263445Sasomers	done
104263445Sasomers	cleanup_tap
105263445Sasomers}
106263445Sasomers
107263445Sasomers
108263445Sasomers# Regression test for kern/187549
109263445Sasomersatf_test_case loopback_and_network_routes_on_nondefault_fib cleanup
110263445Sasomersloopback_and_network_routes_on_nondefault_fib_head()
111263445Sasomers{
112263445Sasomers	atf_set "descr" "When creating and deleting loopback routes, use the interface's fib"
113263445Sasomers	atf_set "require.user" "root"
114263445Sasomers	atf_set "require.config" "fibs"
115263445Sasomers}
116263445Sasomers
117263445Sasomersloopback_and_network_routes_on_nondefault_fib_body()
118263445Sasomers{
119263445Sasomers	atf_expect_fail "kern/187549 Host and network routes for a new interface appear in the wrong FIB"
120263445Sasomers	# Configure the TAP interface to use an RFC5737 nonrouteable address
121263445Sasomers	# and a non-default fib
122263445Sasomers	ADDR="192.0.2.2"
123263445Sasomers	SUBNET="192.0.2.0"
124263445Sasomers	MASK="24"
125263445Sasomers
126263445Sasomers	# Check system configuration
127263445Sasomers	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
128263445Sasomers		atf_skip "This test requires net.add_addr_allfibs=0"
129263445Sasomers	fi
130263445Sasomers	get_fibs 1
131263445Sasomers
132263445Sasomers	# Configure a TAP interface
133263445Sasomers	setup_tap ${FIB0} ${ADDR} ${MASK}
134263445Sasomers
135263445Sasomers	# Check whether the host route exists in only the correct FIB
136263445Sasomers	setfib ${FIB0} netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
137263445Sasomers	if [ 0 -ne $? ]; then
138263445Sasomers		setfib ${FIB0} netstat -rn -f inet
139263445Sasomers		atf_fail "Host route did not appear in the correct FIB"
140263445Sasomers	fi
141263445Sasomers	setfib 0 netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
142263445Sasomers	if [ 0 -eq $? ]; then
143263445Sasomers		setfib 0 netstat -rn -f inet
144263445Sasomers		atf_fail "Host route appeared in the wrong FIB"
145263445Sasomers	fi
146263445Sasomers
147263445Sasomers	# Check whether the network route exists in only the correct FIB
148263445Sasomers	setfib ${FIB0} netstat -rn -f inet | \
149263445Sasomers		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
150263445Sasomers	if [ 0 -ne $? ]; then
151263445Sasomers		setfib ${FIB0} netstat -rn -f inet
152263445Sasomers		atf_fail "Network route did not appear in the correct FIB"
153263445Sasomers	fi
154263445Sasomers	setfib 0 netstat -rn -f inet | \
155263445Sasomers		grep -q "^${SUBNET}/${MASK}.*${TAPD}"
156263445Sasomers	if [ 0 -eq $? ]; then
157263445Sasomers		setfib ${FIB0} netstat -rn -f inet
158263445Sasomers		atf_fail "Network route appeared in the wrong FIB"
159263445Sasomers	fi
160263445Sasomers}
161263445Sasomers
162263445Sasomersloopback_and_network_routes_on_nondefault_fib_cleanup()
163263445Sasomers{
164263445Sasomers	cleanup_tap
165263445Sasomers}
166263445Sasomers
167263445Sasomers
168263445Sasomers# Regression test for kern/187552
169263445Sasomersatf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup
170263445Sasomersdefault_route_with_multiple_fibs_on_same_subnet_head()
171263445Sasomers{
172263445Sasomers	atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default routes"
173263445Sasomers	atf_set "require.user" "root"
174263445Sasomers	atf_set "require.config" "fibs"
175263445Sasomers}
176263445Sasomers
177263445Sasomersdefault_route_with_multiple_fibs_on_same_subnet_body()
178263445Sasomers{
179263445Sasomers	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
180263445Sasomers	# and a non-default fib
181263445Sasomers	ADDR0="192.0.2.2"
182263445Sasomers	ADDR1="192.0.2.3"
183263445Sasomers	GATEWAY="192.0.2.1"
184263445Sasomers	SUBNET="192.0.2.0"
185263445Sasomers	MASK="24"
186263445Sasomers
187263445Sasomers	# Check system configuration
188263445Sasomers	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
189263445Sasomers		atf_skip "This test requires net.add_addr_allfibs=0"
190263445Sasomers	fi
191263445Sasomers	get_fibs 2
192263445Sasomers
193263445Sasomers	# Configure TAP interfaces
194263445Sasomers	setup_tap "$FIB0" ${ADDR0} ${MASK}
195263445Sasomers	TAP0=$TAP
196263445Sasomers	setup_tap "$FIB1" ${ADDR1} ${MASK}
197263445Sasomers	TAP1=$TAP
198263445Sasomers
199263445Sasomers	# Attempt to add default routes
200263445Sasomers	setfib ${FIB0} route add default ${GATEWAY}
201263445Sasomers	setfib ${FIB1} route add default ${GATEWAY}
202263445Sasomers
203263445Sasomers	# Verify that the default route exists for both fibs, with their
204263445Sasomers	# respective interfaces.
205263445Sasomers	atf_check -o match:"^default.*${TAP0}$" \
206263445Sasomers		setfib ${FIB0} netstat -rn -f inet
207263445Sasomers	atf_check -o match:"^default.*${TAP1}$" \
208263445Sasomers		setfib ${FIB1} netstat -rn -f inet
209263445Sasomers}
210263445Sasomers
211263445Sasomersdefault_route_with_multiple_fibs_on_same_subnet_cleanup()
212263445Sasomers{
213263445Sasomers	cleanup_tap
214263445Sasomers}
215263445Sasomers
216263445Sasomers
217263445Sasomers# Regression test for kern/187550
218263445Sasomersatf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
219263445Sasomerssubnet_route_with_multiple_fibs_on_same_subnet_head()
220263445Sasomers{
221263445Sasomers	atf_set "descr" "Multiple FIBs can have subnet routes for the same subnet"
222263445Sasomers	atf_set "require.user" "root"
223263445Sasomers	atf_set "require.config" "fibs"
224263445Sasomers}
225263445Sasomers
226263445Sasomerssubnet_route_with_multiple_fibs_on_same_subnet_body()
227263445Sasomers{
228263445Sasomers	# Configure the TAP interfaces to use a RFC5737 nonrouteable addresses
229263445Sasomers	# and a non-default fib
230263445Sasomers	ADDR0="192.0.2.2"
231263445Sasomers	ADDR1="192.0.2.3"
232263445Sasomers	SUBNET="192.0.2.0"
233263445Sasomers	MASK="24"
234263445Sasomers
235263445Sasomers	# Check system configuration
236263445Sasomers	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
237263445Sasomers		atf_skip "This test requires net.add_addr_allfibs=0"
238263445Sasomers	fi
239263445Sasomers	get_fibs 2
240263445Sasomers
241263445Sasomers	# Configure TAP interfaces
242263445Sasomers	setup_tap "$FIB0" ${ADDR0} ${MASK}
243263445Sasomers	setup_tap "$FIB1" ${ADDR1} ${MASK}
244263445Sasomers
245263445Sasomers	# Check that a subnet route exists on both fibs
246263445Sasomers	atf_check -o ignore setfib "$FIB0" route get $ADDR1
247263445Sasomers	atf_check -o ignore setfib "$FIB1" route get $ADDR0
248263445Sasomers}
249263445Sasomers
250263445Sasomerssubnet_route_with_multiple_fibs_on_same_subnet_cleanup()
251263445Sasomers{
252263445Sasomers	cleanup_tap
253263445Sasomers}
254263445Sasomers
255263445Sasomers# Test that source address selection works correctly for UDP packets with
256263445Sasomers# SO_DONTROUTE set that are sent on non-default FIBs.
257263445Sasomers# This bug was discovered with "setfib 1 netperf -t UDP_STREAM -H some_host"
258263445Sasomers# Regression test for kern/187553
259267186Sasomers#
260267186Sasomers# The root cause was that ifa_ifwithnet() did not have a fib argument.  It
261267186Sasomers# would return an address from an interface on any FIB that had a subnet route
262267186Sasomers# for the destination.  If more than one were available, it would choose the
263267186Sasomers# most specific.  This is most easily tested by creating a FIB without a
264267186Sasomers# default route, then trying to send a UDP packet with SO_DONTROUTE set to an
265267186Sasomers# address which is not routable on that FIB.  Absent the fix for this bug,
266267186Sasomers# in_pcbladdr would choose an interface on any FIB with a default route.  With
267267186Sasomers# the fix, you will get EUNREACH or ENETUNREACH.
268263445Sasomersatf_test_case udp_dontroute cleanup
269263445Sasomersudp_dontroute_head()
270263445Sasomers{
271263445Sasomers	atf_set "descr" "Source address selection for UDP packets with SO_DONTROUTE on non-default FIBs works"
272263445Sasomers	atf_set "require.user" "root"
273263445Sasomers	atf_set "require.config" "fibs"
274263445Sasomers}
275263445Sasomers
276263445Sasomersudp_dontroute_body()
277263445Sasomers{
278263445Sasomers	atf_expect_fail "kern/187553 Source address selection for UDP packets with SO_DONTROUTE uses the default FIB"
279263445Sasomers	# Configure the TAP interface to use an RFC5737 nonrouteable address
280263445Sasomers	# and a non-default fib
281267186Sasomers	ADDR0="192.0.2.2"
282267186Sasomers	ADDR1="192.0.2.3"
283263445Sasomers	SUBNET="192.0.2.0"
284263445Sasomers	MASK="24"
285263445Sasomers	# Use a different IP on the same subnet as the target
286263445Sasomers	TARGET="192.0.2.100"
287267186Sasomers	SRCDIR=`atf_get_srcdir`
288263445Sasomers
289263445Sasomers	# Check system configuration
290263445Sasomers	if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
291263445Sasomers		atf_skip "This test requires net.add_addr_allfibs=0"
292263445Sasomers	fi
293267186Sasomers	get_fibs 2
294263445Sasomers
295267186Sasomers	# Configure the TAP interfaces
296267186Sasomers	setup_tap ${FIB0} ${ADDR0} ${MASK}
297267186Sasomers	TARGET_TAP=${TAP}
298267186Sasomers	setup_tap ${FIB1} ${ADDR1} ${MASK}
299263445Sasomers
300263445Sasomers	# Send a UDP packet with SO_DONTROUTE.  In the failure case, it will
301267186Sasomers	# return ENETUNREACH, or send the packet to the wrong tap
302267186Sasomers	atf_check -o ignore setfib ${FIB0} \
303267186Sasomers		${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
304267186Sasomers	cleanup_tap
305267186Sasomers
306267186Sasomers	# Repeat, but this time target the other tap
307267186Sasomers	setup_tap ${FIB0} ${ADDR0} ${MASK}
308267186Sasomers	setup_tap ${FIB1} ${ADDR1} ${MASK}
309267186Sasomers	TARGET_TAP=${TAP}
310267186Sasomers
311267186Sasomers	atf_check -o ignore setfib ${FIB1} \
312267186Sasomers		${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
313263445Sasomers}
314263445Sasomers
315263445Sasomersudp_dontroute_cleanup()
316263445Sasomers{
317263445Sasomers	cleanup_tap
318263445Sasomers}
319263445Sasomers
320263445Sasomers
321263445Sasomersatf_init_test_cases()
322263445Sasomers{
323263445Sasomers	atf_add_test_case arpresolve_checks_interface_fib
324265586Sasomers	atf_add_test_case loopback_and_network_routes_on_nondefault_fib
325265586Sasomers	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
326265586Sasomers	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
327263445Sasomers	atf_add_test_case udp_dontroute
328263445Sasomers}
329263445Sasomers
330263445Sasomers# Looks up one or more fibs from the configuration data and validates them.
331263445Sasomers# Returns the results in the env varilables FIB0, FIB1, etc.
332263445Sasomers
333263445Sasomers# parameter numfibs	The number of fibs to lookup
334263445Sasomersget_fibs()
335263445Sasomers{
336263445Sasomers	NUMFIBS=$1
337263445Sasomers	net_fibs=`sysctl -n net.fibs`
338263445Sasomers	i=0
339263445Sasomers	while [ $i -lt "$NUMFIBS" ]; do
340263445Sasomers		fib=`atf_config_get "fibs" | \
341263445Sasomers			awk -v i=$(( i + 1 )) '{print $i}'`
342263445Sasomers		echo "fib is ${fib}"
343263445Sasomers		eval FIB${i}=${fib}
344263445Sasomers		if [ "$fib" -ge "$net_fibs" ]; then
345263445Sasomers			atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}"
346263445Sasomers		fi
347263445Sasomers		i=$(( $i + 1 ))
348263445Sasomers	done
349263445Sasomers}
350263445Sasomers
351263445Sasomers# Creates a new tap(4) interface, registers it for cleanup, and returns the
352263445Sasomers# name via the environment variable TAP
353263445Sasomersget_tap()
354263445Sasomers{
355263445Sasomers	local TAPN=0
356263445Sasomers	while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do
357263445Sasomers		if [ "$TAPN" -ge 8 ]; then
358263445Sasomers			atf_skip "Could not create a tap(4) interface"
359263445Sasomers		else
360263445Sasomers			TAPN=$(($TAPN + 1))
361263445Sasomers		fi
362263445Sasomers	done
363263445Sasomers	local TAPD=tap${TAPN}
364263445Sasomers	# Record the TAP device so we can clean it up later
365263445Sasomers	echo ${TAPD} >> "tap_devices_to_cleanup"
366263445Sasomers	TAP=${TAPD}
367263445Sasomers}
368263445Sasomers
369263445Sasomers# Create a tap(4) interface, configure it, and register it for cleanup.
370263445Sasomers# parameters:
371263445Sasomers# fib
372263445Sasomers# IP address
373263445Sasomers# Netmask in number of bits (eg 24 or 8)
374263445Sasomers# Return: the tap interface name as the env variable TAP
375263445Sasomerssetup_tap()
376263445Sasomers{
377263445Sasomers	local FIB=$1
378263445Sasomers	local ADDR=$2
379263445Sasomers	local MASK=$3
380263445Sasomers	get_tap
381263445Sasomers	echo setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
382263445Sasomers	setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
383263445Sasomers}
384263445Sasomers
385263445Sasomerscleanup_tap()
386263445Sasomers{
387263445Sasomers	for TAPD in `cat "tap_devices_to_cleanup"`; do
388263445Sasomers		ifconfig ${TAPD} destroy
389263445Sasomers	done
390267186Sasomers	rm "tap_devices_to_cleanup"
391263445Sasomers}
392