From 205439870b0bf1396412b2dd4ae5dda032a5a69e Mon Sep 17 00:00:00 2001 From: bz Date: Mon, 5 Mar 2012 19:13:18 +0000 Subject: [PATCH] MFC r231858: Add regression tests scripts for multi-IP FIBs exercising the send, receive and forward path tagging packets with both the ifconfig fib option or using ipfw, running ICMP6, TCP/v6 and UDP/v6 tests and testing both setfib(2) as well as the SO_SETFIB socket option. At 16 FIBs a total of over 64k return codes/replies/stati are checked, sometimes multiple times (in different ways, e.g. the reflected request as well as ipfw counter values). The scripts need two or three machines to run and are thus not added to the tools/regression framework but only to tools/test. MFC r232114: Update scripts to work around two sh(1) bugs found in stable/8: 1) _x=$((_x + 1)) does not work while x=$((x + 1)) does. 2) Parameter Expansion, esp. "${x%%bar}" does not work if quoted. Correct typos and improve some details forwarding.sh already had in initiator, esp. related to ipfw accepting if the default is deny. Add an extra stat call to the "delay" function in addition to the touch which together is still a lot faster than sleep 1 but seems to help a lot more to mitigate the unrelated kernel race seen. Sponsored by: Cisco Systems, Inc. git-svn-id: svn://svn.freebsd.org/base/stable/9@232566 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- tools/test/README | 1 + tools/test/netfibs/Makefile | 7 + tools/test/netfibs/README | 64 ++ tools/test/netfibs/forwarding.sh | 1652 ++++++++++++++++++++++++++++++ tools/test/netfibs/initiator.sh | 1521 +++++++++++++++++++++++++++ tools/test/netfibs/reflect.c | 365 +++++++ tools/test/netfibs/reflector.sh | 1098 ++++++++++++++++++++ 7 files changed, 4708 insertions(+) create mode 100644 tools/test/netfibs/Makefile create mode 100644 tools/test/netfibs/README create mode 100755 tools/test/netfibs/forwarding.sh create mode 100755 tools/test/netfibs/initiator.sh create mode 100644 tools/test/netfibs/reflect.c create mode 100755 tools/test/netfibs/reflector.sh diff --git a/tools/test/README b/tools/test/README index 438c1f517..eda43eaa0 100644 --- a/tools/test/README +++ b/tools/test/README @@ -10,5 +10,6 @@ Please make a subdir per program, and add a brief description to this file. devrandom Programs to test /dev/*random. dtrace DTrace test suite malloc A program to test and benchmark malloc(). +netfibs Programs to test multi-FIB network stacks. posixshm A program to test POSIX shared memory. testfloat Programs to test floating-point implementations diff --git a/tools/test/netfibs/Makefile b/tools/test/netfibs/Makefile new file mode 100644 index 000000000..290f4f845 --- /dev/null +++ b/tools/test/netfibs/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +PROG= reflect +NO_MAN= +WARNS?= 6 + +.include diff --git a/tools/test/netfibs/README b/tools/test/netfibs/README new file mode 100644 index 000000000..64c238895 --- /dev/null +++ b/tools/test/netfibs/README @@ -0,0 +1,64 @@ +# $FreeBSD$ + +This directory holds scripts and a support program for multiple test cases +exercising multi-IP FIBs. At this time only IPv6 test cases are provided. + +Makefile +reflect.c + + Makefile just builds reflect, a program to echo data on a TCP or UDP + socket in very simplistic ways. It has a couple of options to provide + an address or port, a FIB to bind to or a FIB to add to a reflected + message as well as some "magic" keyword handling to let the intiators + control it. + +initiator.sh and reflector.sh + + intiator.sh runs two local test cases, one which shows a documented + limitation. + + All further tests are either exercising the sending or receiving of + ICMP6, TCP or UDP packets with multiple FIBs. initiator.sh and + reflector.sh must run on two different nodes both having a network + interface in the same broadcast domain (be it cross-over or on a + bridge/switch). The tests will use the IPv6 benchmarking working + group (BMWG) prefix. The prefix is hard coded into some tests. + Control messages will synchronize reflector with initiator. The + reflector needs the reflect binary. Apart from that the scripts + depend on ping6, netcat, awk, tr and ipfw. The interface to use can + be set from the environment. The commands can be run like: + + env IFACE=ifname sh intiator.sh + env IFACE=ifname sh reflector.sh + + Both scripts also support a DEBUG environment variable for additional + output. A special value of 42 will enable sh(1) xtrace printing. + + The output format is modeled after Test::Harness Perl as used in + tools/regression/ but not always compliant following the test case name. + + NOTE: at the time of writing reflector.sh can trigger kernel races + unrelated to multi-FIB test leading to a panic(9). "delay" calls + are used to mitigate the problem some but are not always good enough. + It is suggested to run one test case at a time manually disabling + the others in both scripts. + +forwarding.sh + + forwarding.sh tests FIBs in the forwarding path, making sure that + packets tagged on input are leaving on the correct FIB. + The script must be run on three nodes with both edge nodes (left + and right) being connected to the middle node on separate interfaces. + + The script operates on the same principles and requirements as the + two afore described ones. Environment options equally apply, with + the middle node also taking an IFACEFAR variable to name the interface + to the right. See the ASCII art at the beginning of the script for + details. The script needs to be told which node it is running with + the first argument: + + env IFACE=ifname sh forwarding.sh left + env IFACE=leftifname IFACEFAR=rightifname sh forwarding.sh middle + env IFACE=ifname sh forwarding.sh right + +# end diff --git a/tools/test/netfibs/forwarding.sh b/tools/test/netfibs/forwarding.sh new file mode 100755 index 000000000..3d63d7454 --- /dev/null +++ b/tools/test/netfibs/forwarding.sh @@ -0,0 +1,1652 @@ +#!/bin/sh +#- +# Copyright (c) 2012 Cisco Systems, Inc. +# All rights reserved. +# +# This software was developed by Bjoern Zeeb under contract to +# Cisco Systems, Inc.. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +# Test setup: +# +# left ------------------------- middle ------------------------- right +# IFACE IFACE IFACEFAR IFACE +# LEFTADDR MIDDLELEFTADDR MIDDLERIGHTADDR RIGHTADDR +# forwarding=1 +# initiator FIB tests reflector + +# We will use the RFC5180 (and Errata) benchmarking working group prefix +# 2001:0002::/48 for testing. +PREFIX="2001:2:" + +# Set IFACE to the real interface you want to run the test on. +# IFACEFAR is only relevant on the middle (forwarding) node and will be the +# 'right' side (far end) one. +: ${IFACE:=lo0} +: ${IFACEFAR:=lo0} + +# Number of seconds to wait for peer node to synchronize for test. +: ${WAITS:=120} + +# Control port we use to exchange messages between nodes to sync. tests, etc. +: ${CTRLPORT:=6666} + +# Get the number of FIBs from the kernel. +RT_NUMFIBS=`sysctl -n net.fibs` + +# This is the initiator and connected middle node. +LEFTADDR="2001:2:fe00::1" +MIDDLELEFTADDR="2001:2:fe00::2" +# This is the far end middle node and receiver side. +MIDDLERIGHTADDR="2001:2:ff00::1" +RIGHTADDR="2001:2:ff00::2" + +# By default all commands must succeed. Individual tests may disable this +# temporary. +set -e + +# Debug magic. +case "${DEBUG}" in +42) set -x ;; +esac + + +################################################################################ +# +# Input validation. +# + +node=$1 +case ${node} in +left) ;; +middle) ;; +right) ;; +*) echo "ERROR: invalid node name '${node}'. Must be left, middle or" \ + " right" >&1 + exit 1 + ;; +esac + +################################################################################ +# +# Helper functions. +# +check_rc() +{ + local _rc _exp _testno _testname _msg _r + _rc=$1 + _exp=$2 + _testno=$3 + _testname="$4" + _msg="$5" + + _r="not ok" + if test ${_rc} -eq ${_exp}; then + _r="ok" + fi + echo "${_r} ${_testno} ${_testname} # ${_msg} ${_rc} ${_exp}" +} + +print_debug() +{ + local _msg + _msg="$*" + + case ${DEBUG} in + ''|0) ;; + *) echo "DEBUG: ${_msg}" >&2 ;; + esac +} + +die() +{ + local _msg + _msg="$*" + + echo "ERROR: ${_msg}" >&2 + exit 1 +} + + +################################################################################ +# +# Functions to configure networking and do a basic reachability check. +# + +setup_networking() +{ + + print_debug "Setting up networking" + case ${node} in + left) ifconfig ${IFACE} inet6 ${LEFTADDR}/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 ${LEFTADDR}/64 alias up + ifconfig ${IFACE} fib 0 + sysctl net.inet6.ip6.forwarding=0 > /dev/null + route delete -net -inet6 default > /dev/null 2>&1 || true + route delete -host -inet6 ${RIGHTADDR} ${MIDDLELEFTADDR} \ + > /dev/null 2>&1 || true + route add -host -inet6 ${RIGHTADDR} ${MIDDLELEFTADDR} \ + > /dev/null + route delete -host -inet6 ${MIDDLERIGHTADDR} ${MIDDLELEFTADDR} \ + > /dev/null 2>&1 || true + route add -host -inet6 ${MIDDLERIGHTADDR} ${MIDDLELEFTADDR} \ + > /dev/null 2>&1 || true + ;; + middle) ifconfig ${IFACE} inet6 ${MIDDLELEFTADDR}/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 ${MIDDLELEFTADDR}/64 alias up + ifconfig ${IFACE} fib 0 + ifconfig ${IFACEFAR} inet6 ${MIDDLERIGHTADDR}/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACEFAR} inet6 ${MIDDLERIGHTADDR}/64 alias up + ifconfig ${IFACEFAR} fib 0 + sysctl net.inet6.ip6.forwarding=1 > /dev/null + ;; + right) ifconfig ${IFACE} inet6 ${RIGHTADDR}/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 ${RIGHTADDR}/64 alias up + ifconfig ${IFACE} fib 0 + sysctl net.inet6.ip6.forwarding=0 > /dev/null + route delete -net -inet6 default > /dev/null 2>&1 || true + route delete -host -inet6 ${LEFTADDR} ${MIDDLERIGHTADDR} \ + > /dev/null 2>&1 || true + route add -host -inet6 ${LEFTADDR} ${MIDDLERIGHTADDR} \ + > /dev/null + route delete -host -inet6 ${MIDDLELEFTADDR} ${MIDDLERIGHTADDR} \ + > /dev/null 2>&1 || true + route add -host -inet6 ${MIDDLELEFTADDR} ${MIDDLERIGHTADDR} \ + > /dev/null + ;; + esac + + # Let things settle. + print_debug "Waiting 4 seconds for things to settle" + sleep 4 +} + +cleanup_networking() +{ + + case ${node} in + left) ifconfig ${IFACE} inet6 ${LEFTADDR}/64 -alias + ;; + middle) ifconfig ${IFACE} inet6 ${MIDDLELEFTADDR}/64 -alias + ifconfig ${IFACEFAR} inet6 ${MIDDLERIGHTADDR}/64 -alias + sysctl net.inet6.ip6.forwarding=0 > /dev/null + ;; + right) ifconfig ${IFACE} inet6 ${RIGHTADDR}/64 -alias + ;; + esac + print_debug "Cleaned up networking" +} + +_reachability_check() +{ + local _addr _rc + _addr="$1" + + ping6 -n -c1 ${_addr} > /dev/null 2>&1 + _rc=$? + case ${_rc} in + 0) ;; + *) print_debug "cannot ping6 ${_addr}, rc=${_rc}" + return 1 + ;; + esac + return 0 +} + +reachability_check() +{ + local _i rc + + # Try to reach all control addresses on other nodes. + # We need to loop for a while as we cannot expect all to be up + # the very same moment. + i=1 + rc=42 + while test ${rc} -ne 0 -a ${i} -le ${WAITS}; do + print_debug "${i}/${WAITS} trying to ping6 control addresses." + rc=0 + set +e + case ${node} in + left) _reachability_check ${MIDDLELEFTADDR} + rc=$((rc + $?)) + _reachability_check ${MIDDLERIGHTADDR} + rc=$((rc + $?)) + _reachability_check ${RIGHTADDR} + rc=$((rc + $?)) + ;; + middle) _reachability_check ${LEFTADDR} + rc=$((rc + $?)) + _reachability_check ${RIGHTADDR} + rc=$((rc + $?)) + ;; + right) _reachability_check ${MIDDLERIGHTADDR} + rc=$((rc + $?)) + _reachability_check ${MIDDLELEFTADDR} + rc=$((rc + $?)) + _reachability_check ${LEFTADDR} + rc=$((rc + $?)) + ;; + esac + set -e + sleep 1 + i=$((i + 1)) + done +} + +################################################################################ +# +# "Greeting" handling to sync notes to the agreed upon next test case. +# +send_control_msg() +{ + local _case _addr i rc _msg _keyword _fibs + _case="$1" + _addr="$2" + + set +e + i=0 + rc=-1 + while test ${i} -lt ${WAITS} -a ${rc} -ne 0; do + print_debug "Sending control msg #${i} to peer ${_addr}" + _msg=`echo "${_case} ${RT_NUMFIBS}" | \ + nc -6 -w 1 ${_addr} ${CTRLPORT}` + rc=$? + i=$((i + 1)) + # Might sleep longer in total but better than to DoS + # and not get anywhere. + sleep 1 + done + set -e + + read _keyword _fibs < /dev/null 2>&1 + _ec=$? + # We need to normalize the exit code of ping6. + case ${_ec} in + 0) ;; + *) _ec=1 ;; + esac + check_rc ${_ec} ${_rc} ${_testno} "${_txt}" "FIB ${i} ${_addr}" + testno=$((testno + 1)) + i=$((i + 1)) + done + set -e +} + +test_ulp_reflect_one() +{ + local _txt _opts port fib + _txt="$1" + _opts="$2" + port=$3 + fib=$4 + + print_debug "./reflect -p $((port + 1 + fib)) -t ${_txt}" "${_opts}" + ./reflect -p $((port + 1 + fib)) -t ${_txt} ${_opts} + print_debug "reflect '${_txt}' terminated without error." +} + +test_ulp_reflect_multiple() +{ + local _maxfibs _txt _opts i _jobs _p + _maxfibs=$1 + _txt="$2" + _opts="$3" + + i=0 + _jobs="" + while test ${i} -lt ${_maxfibs}; do + print_debug "./reflect -p $((CTRLPORT + 1000 + i))" \ + "-t ${_txt} ${_opts} -N -f ${i} &" + ./reflect -p $((CTRLPORT + 1000 + i)) \ + -t ${_txt} ${_opts} -N -f ${i} & + _p=$! + _jobs="${_jobs}${_p} " + i=$((i + 1)) + done + + # Start OOB control connection for START/DONE. + testrx_run_one "${_txt}" "${_opts}" + print_debug "KILL ${_jobs}" + for i in ${_jobs}; do + kill ${i} || true + done + #killall reflect || true + print_debug "reflects for '${_txt}' terminated without error." +} + +nc_send_recv() +{ + local _loops _msg _expreply _addr _port _opts i + _loops=$1 + _msg="$2" + _expreply="$3" + _addr=$4 + _port=$5 + _opts="$6" + + i=0 + while test ${i} -lt ${_loops}; do + i=$((i + 1)) + print_debug "e ${_msg} | nc -6 -w1 ${_opts} ${_addr} ${_port}" + _reply=`echo "${_msg}" | nc -6 -w1 ${_opts} ${_addr} ${_port}` + if test "${_reply}" != "${_expreply}"; then + if test ${i} -lt ${_loops}; then + sleep 1 + else + # Must let caller decide how to handle the error. + # die "Got invalid reply from peer." \ + # "Expected '${_expreply}', got '${_reply}'" + return 1 + fi + else + break + fi + done + return 0 +} + +test_ulp() +{ + local maxfibs _msg _addr port fib i _txt testno _rc _reply + maxfibs=$1 + _msg="$2" + _addr=$3 + port=$4 + fib=$5 + + printf "1..%d\n" $((${maxfibs} * 2)) + testno=1 + i=0 + while test ${i} -lt ${maxfibs}; do + + if test ${i} -eq $((${maxfibs} - 1)); then + # Last one; signal DONE. + _txt="DONE ${_msg}_${i}" + else + _txt="DONE ${_msg}_${i}" + fi + + eval _rc="\${rc_${i}}" + + # Test TCP. + nc_send_recv ${maxfibs} "${_txt}" "${_txt}" ${_addr} \ + $((${port} + 1 + fib)) "" + check_rc $? ${_rc} ${testno} "${_msg}_${i}_tcp" \ + "[${_addr}]:$((${port} + 1 + fib)) ${_reply}" + testno=$((testno + 1)) + sleep 1 + + # Test UDP. + nc_send_recv ${maxfibs} "${_txt}" "${_txt}" ${_addr} \ + $((${port} + 1 + fib)) "-u" + check_rc $? ${_rc} ${testno} "${_msg}_${i}_udp" \ + "[${_addr}]:$((${port} + 1 + fib)) ${_reply}" + sleep 1 + + i=$((i + 1)) + testno=$((testno + 1)) + done +} + +setup_ipfw_count() +{ + local i port maxfib _p _fib _ofib + port=$1 + maxfib=$2 + _fib=$3 + _ofib=$4 + + i=0 + while test ${i} -lt ${maxfib}; do + + case ${_ofib} in + -1) _p=$((port + 1 + i)) ;; + *) _p=$((port + 1 + maxfib - 1 - i)) ;; + esac + + # Only count ICMP6 echo replies. + ipfw add $((10000 + i)) count ipv6-icmp from any to any \ + icmp6types 129 fib ${i} via ${IFACE} out > /dev/null + ipfw add $((10000 + i)) count tcp from any to any \ + src-port ${_p} fib ${i} via ${IFACE} out > /dev/null + ipfw add $((10000 + i)) count udp from any to any \ + src-port ${_p} fib ${i} via ${IFACE} out > /dev/null + + # Only count ICMP6 echo requests. + ipfw add $((20000 + i)) count ipv6-icmp from any to any \ + icmp6types 128 fib ${i} via ${IFACEFAR} out > /dev/null + ipfw add $((20000 + i)) count tcp from any to any \ + dst-port $((${port} + 1 + i)) fib ${i} \ + via ${IFACEFAR} out > /dev/null + ipfw add $((20000 + i)) count udp from any to any \ + dst-port $((${port} + 1 + i)) fib ${i} \ + via ${IFACEFAR} out > /dev/null + + i=$((i + 1)) + done +} + +report_ipfw_count() +{ + local _fib _o i _rstr _c _req _p _opts base + _o="$2" + + case ${DEBUG} in + ''|0) ;; + *) ipfw show ;; + esac + + _rstr="RESULTS " + for base in 10000 20000; do + for _o in i t u; do + case ${base} in + 10000) _rstr="${_rstr}\nLEFT " ;; + 20000) _rstr="${_rstr}\nRIGHT " ;; + esac + case ${_o} in + i) _rstr="${_rstr}ICMP6 " ;; + t) _rstr="${_rstr}TCP " ;; + u) _rstr="${_rstr}UDP " ;; + esac + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + + case "${_o}" in + i) _c=`ipfw show $((${base} + i)) | \ + awk '/ ipv6-icmp / { print $2 }'` ;; + t) _c=`ipfw show $((${base} + i)) | \ + awk '/ tcp / { print $2 }'` ;; + u) _c=`ipfw show $((${base} + i)) | \ + awk '/ udp / { print $2 }'` ;; + esac + _rstr="${_rstr}${i} ${_c}," + + i=$((i + 1)) + done + done + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + ipfw delete $((${base} + i)) > /dev/null 2>&1 || true + i=$((i + 1)) + done + done + + # We do not care about the request. + _req=`printf "${_rstr}" | nc -6 -l $((${CTRLPORT} - 1))` + print_debug "$? -- ${_req} -- ${_rstr}" +} + +fetch_ipfw_count() +{ + local _n _reply _line _edge _type _fib _count _rc _ec _status + _n="$1" + + # Leave node some time to build result set. + sleep 3 + + print_debug "Asking for ipfw count results..." + set +e + nc_send_recv 1 "RESULT REQUEST" "" ${MIDDLELEFTADDR} \ + $((${CTRLPORT} - 1)) "" + set -e + case "${_reply}" in + RESULTS\ *) ;; + *) die "Got invalid reply from peer." \ + "Expected 'RESULTS ...', got '${_reply}'" ;; + esac + + # Trim "RESULTS " + _reply=${_reply#* } + + # FIBs * {left, right} * {icmp6, tcp, udp} + printf "1..%d\n" $((RT_NUMFIBS * 2 * 3)) + testno=1 + while read _line; do + print_debug "_line == ${_line}" + _edge=${_line%% *} + _line=${_line#* } + _type=${_line%% *} + _line=${_line#* } + + while read _fib _count; do + eval _em="\${rc_${_n}_${_edge}_${_type}_${_fib}}" + : ${_em:=-42} + if test ${_count} -gt 0; then + _rc=1 + else + _rc=0 + fi + if test ${_rc} -eq ${_em}; then + _status="ok" + else + _status="not ok" + fi + printf "%s %d %s # count=%s _rc=%d _em=%d\n" \ + "${_status}" ${testno} "${_n}_${_edge}_${_type}_${_fib}" \ + ${_count} ${_rc} ${_em} + testno=$((testno + 1)) + done < /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}" + report_ipfw_count +} + +_fwd_default_fib_symmetric_right() +{ + local _n + _n="$1" + + wait_remote_ready "START_${_n}" + + # No need to do anything for ICMPv6. + # Start reflect for TCP and UDP. + test_ulp_reflect_one "${_n}_tcp" "-N -T TCP6" 0 ${CTRLPORT} + test_ulp_reflect_one "${_n}_udp" "-N -T UDP6" 0 ${CTRLPORT} + + wait_remote_ready "STOP_${_n}" +} + +fwd_default_fib_symmetric() +{ + local _n + + _n="fwd_default_fib_symmetric" + + print_debug "${_n}" + case ${node} in + left) _fwd_default_fib_symmetric_left ${_n} ;; + middle) _fwd_default_fib_symmetric_middle ${_n} ;; + right) _fwd_default_fib_symmetric_right ${_n} ;; + esac +} + +_fwd_default_fib_symmetric_middle_ifconfig() +{ + local _n + _n="$1" + + ifconfig ${IFACE} fib 0 + ifconfig ${IFACEFAR} fib 0 + setup_ipfw_count ${CTRLPORT} ${RT_NUMFIBS} 0 -1 + wait_remote_ready "START_${_n}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}" + report_ipfw_count +} + +fwd_default_fib_symmetric_ifconfig() +{ + local _n + + _n="fwd_default_fib_symmetric_ifconfig" + + print_debug "${_n}" + case ${node} in + left) _fwd_default_fib_symmetric_left ${_n} ;; + middle) _fwd_default_fib_symmetric_middle_ifconfig ${_n} ;; + right) _fwd_default_fib_symmetric_right ${_n} ;; + esac +} + +_fwd_default_fib_symmetric_middle_ipfw() +{ + local _n + _n="$1" + + ipfw add 100 setfib 0 ipv6-icmp from any to any \ + icmp6types 128 via ${IFACE} in > /dev/null + ipfw add 100 setfib 0 ip6 from any to any \ + proto tcp dst-port ${CTRLPORT} via ${IFACE} in > /dev/null + ipfw add 100 setfib 0 ip6 from any to any \ + proto udp dst-port ${CTRLPORT} via ${IFACE} in > /dev/null + + ipfw add 100 setfib 0 ipv6-icmp from any to any \ + icmp6types 128 via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib 0 tcp from any to any \ + dst-port ${CTRLPORT} via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib 0 udp from any to any \ + dst-port ${CTRLPORT} via ${IFACEFAR} in > /dev/null + + setup_ipfw_count ${CTRLPORT} ${RT_NUMFIBS} 0 -1 + wait_remote_ready "START_${_n}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}" + report_ipfw_count + + ipfw delete 100 > /dev/null +} + +fwd_default_fib_symmetric_ipfw() +{ + local _n + + _n="fwd_default_fib_symmetric_ipfw" + + print_debug "${_n}" + case ${node} in + left) _fwd_default_fib_symmetric_left ${_n} ;; + middle) _fwd_default_fib_symmetric_middle_ipfw ${_n} ;; + right) _fwd_default_fib_symmetric_right ${_n} ;; + esac +} + +################################################################################ + +_fwd_fib_symmetric_results() +{ + local _n _fib i _edge _type _rc + _n="$1" + _fib=$2 + + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + for _edge in "LEFT" "RIGHT"; do + for _type in "ICMP6" "TCP" "UDP"; do + + case ${i} in + ${_fib}) eval rc_${_n}_${_edge}_${_type}_${i}=1 + #print_debug \ + # "rc_${_n}_${_edge}_${_type}_${i}=1" + ;; + *) eval rc_${_n}_${_edge}_${_type}_${i}=0 + #print_debug \ + # "rc_${_n}_${_edge}_${_type}_${i}=0" + ;; + esac + + done + done + i=$((i + 1)) + done +} + +_fwd_fib_symmetric_left() +{ + local _n _maxfib i + _n="$1" + _maxfib=$2 + + # Setup expected return code + i=0 + while test ${i} -lt ${_maxfib}; do + eval rc_${i}=0 + i=$((i + 1)) + done + + # Initiate probes for ICMP6, TCP and UDP. + i=0 + while test ${i} -lt ${_maxfib}; do + + sleep 1 + + send_control_msgs "START_${_n}_${i}" + + test_icmp6 1 ${RIGHTADDR} "${_n}_${i}_icmp6" + test_ulp 1 "${_n}_${i}" ${RIGHTADDR} ${CTRLPORT} ${i} + + send_control_msgs "STOP_${_n}_${i}" + _fwd_fib_symmetric_results "${_n}_${i}" ${i} + fetch_ipfw_count "${_n}_${i}" + i=$((i + 1)) + done +} + +_fwd_fib_symmetric_right() +{ + local _n _maxfib i + _n="$1" + _maxfib=$2 + + i=0 + while test ${i} -lt ${_maxfib}; do + wait_remote_ready "START_${_n}_${i}" + + # No need to do anything for ICMPv6. + # Start reflect for TCP and UDP. + test_ulp_reflect_one "${_n}_tcp" "-N -T TCP6" ${i} ${CTRLPORT} + test_ulp_reflect_one "${_n}_udp" "-N -T UDP6" ${i} ${CTRLPORT} + + wait_remote_ready "STOP_${_n}_${i}" + i=$((i + 1)) + done +} + +_fwd_fib_symmetric_middle_ifconfig() +{ + local _n _maxfib i + _n="$1" + _maxfib=$2 + + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACE} fib ${i} + ifconfig ${IFACEFAR} fib ${i} + setup_ipfw_count ${CTRLPORT} ${_maxfib} ${i} -1 + wait_remote_ready "START_${_n}_${i}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}_${i}" + report_ipfw_count + i=$((i + 1)) + done +} + +_fwd_fib_symmetric_middle_ipfw() +{ + local _n _maxfib i _port + _n="$1" + _maxfib=$2 + + i=0 + while test ${i} -lt ${_maxfib}; do + _port=$((CTRLPORT + 1 + i)) + ipfw add 100 setfib ${i} ipv6-icmp from any to any \ + icmp6types 128 via ${IFACE} in > /dev/null + ipfw add 100 setfib ${i} tcp from any to any \ + dst-port ${_port} via ${IFACE} in > /dev/null + ipfw add 100 setfib ${i} udp from any to any \ + dst-port ${_port} via ${IFACE} in > /dev/null + + ipfw add 100 setfib ${i} ipv6-icmp from any to any \ + icmp6types 129 via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib ${i} tcp from any to any \ + src-port ${_port} via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib ${i} udp from any to any \ + src-port ${_port} via ${IFACEFAR} in > /dev/null + + setup_ipfw_count ${CTRLPORT} ${_maxfib} ${i} -1 + wait_remote_ready "START_${_n}_${i}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}_${i}" + report_ipfw_count + + ipfw delete 100 > /dev/null + i=$((i + 1)) + done +} + +fwd_fib_symmetric_ifconfig() +{ + local _maxfib _n + _maxfib=$1 + + _n="fwd_fib_symmetric_ifconfig" + + print_debug "${_n} ${_maxfib}" + case ${node} in + left) _fwd_fib_symmetric_left ${_n} ${_maxfib} ;; + middle) _fwd_fib_symmetric_middle_ifconfig ${_n} ${_maxfib} ;; + right) _fwd_fib_symmetric_right ${_n} ${_maxfib} ;; + esac +} + +fwd_fib_symmetric_ipfw() +{ + local _maxfib _n + _maxfib=$1 + + _n="fwd_fib_symmetric_ipfw" + + print_debug "${_n} ${_maxfib}" + case ${node} in + left) _fwd_fib_symmetric_left ${_n} ${_maxfib} ;; + middle) _fwd_fib_symmetric_middle_ipfw ${_n} ${_maxfib} ;; + right) _fwd_fib_symmetric_right ${_n} ${_maxfib} ;; + esac +} + +################################################################################ + +_fwd_fib_asymmetric_results() +{ + local _n fib maxfib i _edge _type _rc + _n="$1" + fib=$2 + maxfib=$3 + + i=0 + while test ${i} -lt ${maxfib}; do + _edge="RIGHT" + for _type in "ICMP6" "TCP" "UDP"; do + + case ${i} in + ${fib}) eval rc_${_n}_${_edge}_${_type}_${i}=1 + #print_debug \ + # "rc_${_n}_${_edge}_${_type}_${i}=1" + ;; + *) eval rc_${_n}_${_edge}_${_type}_${i}=0 + #print_debug \ + # "rc_${_n}_${_edge}_${_type}_${i}=0" + ;; + esac + + done + i=$((i + 1)) + done + fib=$((maxfib - 1 - fib)) + i=0 + while test ${i} -lt ${maxfib}; do + _edge="LEFT" + for _type in "ICMP6" "TCP" "UDP"; do + + case ${i} in + ${fib}) eval rc_${_n}_${_edge}_${_type}_${i}=1 + #print_debug \ + # "rc_${_n}_${_edge}_${_type}_${i}=1" + ;; + *) eval rc_${_n}_${_edge}_${_type}_${i}=0 + #print_debug \ + # "rc_${_n}_${_edge}_${_type}_${i}=0" + ;; + esac + + done + i=$((i + 1)) + done +} + +_fwd_fib_asymmetric_left() +{ + local _n _maxfib i + _n="$1" + _maxfib=$2 + + # Setup expected return code + i=0 + while test ${i} -lt ${_maxfib}; do + eval rc_${i}=0 + i=$((i + 1)) + done + + # Initiate probes for ICMP6, TCP and UDP. + i=0 + while test ${i} -lt ${_maxfib}; do + + sleep 1 + + send_control_msgs "START_${_n}_${i}" + + test_icmp6 1 ${RIGHTADDR} "${_n}_${i}_icmp6" + test_ulp 1 "${_n}_${i}" ${RIGHTADDR} ${CTRLPORT} ${i} + + send_control_msgs "STOP_${_n}_${i}" + _fwd_fib_asymmetric_results "${_n}_${i}" ${i} ${_maxfib} + fetch_ipfw_count "${_n}_${i}" + i=$((i + 1)) + done +} + +_fwd_fib_asymmetric_middle_ifconfig() +{ + local _n maxfib i + _n="$1" + maxfib=$2 + + i=0 + while test ${i} -lt ${maxfib}; do + ifconfig ${IFACE} fib ${i} + ifconfig ${IFACEFAR} fib $((${maxfib} - 1 - ${i})) + setup_ipfw_count ${CTRLPORT} ${maxfib} ${i} \ + $((${maxfib} - 1 - ${i})) + wait_remote_ready "START_${_n}_${i}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}_${i}" + report_ipfw_count + i=$((i + 1)) + done +} + +_fwd_fib_asymmetric_middle_ipfw() +{ + local _n maxfib i j _port + _n="$1" + maxfib=$2 + + i=0 + while test ${i} -lt ${maxfib}; do + + _port=$((CTRLPORT + 1 + i)) + ipfw add 100 setfib ${i} ipv6-icmp from any to any \ + icmp6types 128 via ${IFACE} in > /dev/null + ipfw add 100 setfib ${i} tcp from any to any \ + dst-port ${_port} via ${IFACE} in > /dev/null + ipfw add 100 setfib ${i} udp from any to any \ + dst-port ${_port} via ${IFACE} in > /dev/null + + j=$((${maxfib} - 1 - ${i})) + ipfw add 100 setfib ${j} ipv6-icmp from any to any \ + icmp6types 129 via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib ${j} tcp from any to any \ + src-port ${_port} via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib ${j} udp from any to any \ + src-port ${_port} via ${IFACEFAR} in > /dev/null + + setup_ipfw_count ${CTRLPORT} ${maxfib} ${i} ${j} + wait_remote_ready "START_${_n}_${i}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}_${i}" + report_ipfw_count + + ipfw delete 100 > /dev/null + i=$((i + 1)) + done +} + +fwd_fib_asymmetric_ifconfig() +{ + local _maxfib _n + _maxfib=$1 + + _n="fwd_fib_asymmetric_ifconfig" + + print_debug "${_n} ${_maxfib}" + case ${node} in + left) _fwd_fib_asymmetric_left ${_n} ${_maxfib} ;; + middle) _fwd_fib_asymmetric_middle_ifconfig ${_n} ${_maxfib} ;; + right) _fwd_fib_symmetric_right ${_n} ${_maxfib} ;; + esac +} + +fwd_fib_asymmetric_ipfw() +{ + local _maxfib _n + _maxfib=$1 + + _n="fwd_fib_asymmetric_ipfw" + + print_debug "${_n} ${_maxfib}" + case ${node} in + left) _fwd_fib_asymmetric_left ${_n} ${_maxfib} ;; + middle) _fwd_fib_asymmetric_middle_ipfw ${_n} ${_maxfib} ;; + right) _fwd_fib_symmetric_right ${_n} ${_maxfib} ;; + esac +} + +################################################################################ + +_fwd_fib_symmetric_destructive_left() +{ + local _n _maxfib i _addr + _n="$1" + _maxfib=$2 + + # Setup expected return code + i=0 + while test ${i} -lt ${_maxfib}; do + eval rc_${i}=0 + i=$((i + 1)) + done + + # Add default route. + route add -net -inet6 default ${MIDDLELEFTADDR} > /dev/null + + # Initiate probes for ICMP6, TCP and UDP. + i=0 + while test ${i} -lt ${_maxfib}; do + + sleep 1 + + send_control_msgs "START_${_n}_${i}" + + _addr="2001:2:${i}::2" + test_icmp6 1 ${_addr} "${_n}_${i}_icmp6" + test_ulp 1 "${_n}_${i}" ${_addr} ${CTRLPORT} ${i} + + send_control_msgs "STOP_${_n}_${i}" + _fwd_fib_symmetric_results "${_n}_${i}" ${i} + fetch_ipfw_count "${_n}_${i}" + i=$((i + 1)) + done + + # Cleanup networking. + route delete -net -inet6 default > /dev/null +} + +_fwd_fib_symmetric_destructive_right() +{ + local _n _maxfib i _addr + _n="$1" + _maxfib=$2 + + # Setup networking (ideally we'd use the link-local). + route add -net -inet6 default ${MIDDLERIGHTADDR} > /dev/null 2>&1 + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 alias + i=$((i + 1)) + done + + i=0 + while test ${i} -lt ${_maxfib}; do + wait_remote_ready "START_${_n}_${i}" + + # No need to do anything for ICMPv6. + # Start reflect for TCP and UDP. + _addr="2001:2:${i}::2" + test_ulp_reflect_one "${_n}_tcp" "-N -T TCP6 -A ${_addr}" \ + ${i} ${CTRLPORT} + test_ulp_reflect_one "${_n}_udp" "-N -T UDP6 -A ${_addr}" \ + ${i} ${CTRLPORT} + + wait_remote_ready "STOP_${_n}_${i}" + i=$((i + 1)) + done + + # Cleanup networking again. + route delete -net -inet6 default > /dev/null 2>&1 + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias + i=$((i + 1)) + done + +} + + +_fwd_fib_symmetric_destructive_middle_setup_networking() +{ + local _maxfib i j + _maxfib=$1 + + # Setup networking. + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACEFAR} inet6 2001:2:${i}::1/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACEFAR} inet6 2001:2:${i}::1/64 alias + j=0 + while test ${j} -lt ${_maxfib}; do + # Only work on all other FIBs. + if test ${j} -ne ${i}; then + setfib -F ${j} route delete -net -inet6 \ + 2001:2:${i}::/64 > /dev/null + fi + j=$((j + 1)) + done + i=$((i + 1)) + done +} + +_fwd_fib_symmetric_destructive_middle_cleanup_networking() +{ + local _maxfib i + _maxfib=$1 + + # Cleanup networking again. + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACEFAR} inet6 2001:2:${i}::1/64 -alias + i=$((i + 1)) + done +} + +_fwd_fib_symmetric_destructive_middle_ifconfig() +{ + local _n _maxfib i + _n="$1" + _maxfib=$2 + + _fwd_fib_symmetric_destructive_middle_setup_networking ${_maxfib} + + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACE} fib ${i} + ifconfig ${IFACEFAR} fib ${i} + setup_ipfw_count ${CTRLPORT} ${_maxfib} ${i} -1 + wait_remote_ready "START_${_n}_${i}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}_${i}" + report_ipfw_count + i=$((i + 1)) + done + + _fwd_fib_symmetric_destructive_middle_cleanup_networking ${_maxfib} +} + +_fwd_fib_symmetric_destructive_middle_ipfw() +{ + local _n _maxfib i _port + _n="$1" + _maxfib=$2 + + _fwd_fib_symmetric_destructive_middle_setup_networking ${_maxfib} + + i=0 + while test ${i} -lt ${_maxfib}; do + _port=$((CTRLPORT + 1 + i)) + ipfw add 100 setfib ${i} ipv6-icmp from any to any \ + icmp6types 128 via ${IFACE} in > /dev/null + ipfw add 100 setfib ${i} tcp from any to any \ + dst-port ${_port} via ${IFACE} in > /dev/null + ipfw add 100 setfib ${i} udp from any to any \ + dst-port ${_port} via ${IFACE} in > /dev/null + + ipfw add 100 setfib ${i} ipv6-icmp from any to any \ + icmp6types 129 via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib ${i} tcp from any to any \ + src-port ${_port} via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib ${i} udp from any to any \ + src-port ${_port} via ${IFACEFAR} in > /dev/null + + setup_ipfw_count ${CTRLPORT} ${_maxfib} ${i} -1 + wait_remote_ready "START_${_n}_${i}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}_${i}" + report_ipfw_count + + ipfw delete 100 > /dev/null + i=$((i + 1)) + done + + _fwd_fib_symmetric_destructive_middle_cleanup_networking ${_maxfib} +} + +fwd_fib_symmetric_destructive_ifconfig() +{ + local _maxfib _n + _maxfib=$1 + + _n="fwd_fib_symmetric_destructive_ifconfig" + + print_debug "${_n} ${_maxfib}" + case ${node} in + left) _fwd_fib_symmetric_destructive_left ${_n} ${_maxfib} ;; + middle) _fwd_fib_symmetric_destructive_middle_ifconfig \ + ${_n} ${_maxfib} ;; + right) _fwd_fib_symmetric_destructive_right ${_n} ${_maxfib} ;; + esac +} + +fwd_fib_symmetric_destructive_ipfw() +{ + local _maxfib _n + _maxfib=$1 + + _n="fwd_fib_symmetric_destructive_ipfw" + + print_debug "${_n} ${_maxfib}" + case ${node} in + left) _fwd_fib_symmetric_destructive_left ${_n} ${_maxfib} ;; + middle) _fwd_fib_symmetric_destructive_middle_ipfw \ + ${_n} ${_maxfib} ;; + right) _fwd_fib_symmetric_destructive_right ${_n} ${_maxfib} ;; + esac +} + +################################################################################ + +_fwd_fib_symmetric_destructive_defroute_left() +{ + local _n _maxfib i _addr + _n="$1" + _maxfib=$2 + + # Setup expected return code + i=0 + while test ${i} -lt ${_maxfib}; do + eval rc_${i}=0 + i=$((i + 1)) + done + + # Add default route. + route delete -net -inet6 default > /dev/null 2>&1 || true + route add -net -inet6 default ${MIDDLELEFTADDR} > /dev/null + + # Initiate probes for ICMP6, TCP and UDP. + _addr="2001:2:1234::2" + i=0 + while test ${i} -lt ${_maxfib}; do + + sleep 1 + + send_control_msgs "START_${_n}_${i}" + + test_icmp6 1 "${_addr}" "${_n}_${i}_icmp6" + test_ulp 1 "${_n}_${i}" "${_addr}" ${CTRLPORT} ${i} + + send_control_msgs "STOP_${_n}_${i}" + _fwd_fib_symmetric_results "${_n}_${i}" ${i} + fetch_ipfw_count "${_n}_${i}" + i=$((i + 1)) + done + + # Cleanup networking. + route delete -net -inet6 default > /dev/null 2>&1 +} + +_fwd_fib_symmetric_destructive_defroute_right() +{ + local _n _maxfib i _addr + _n="$1" + _maxfib=$2 + + # Setup networking (ideally we'd use the link-local). + route delete -net -inet6 default > /dev/null 2>&1 || true + route add -net -inet6 default ${MIDDLERIGHTADDR} > /dev/null 2>&1 + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 alias + i=$((i + 1)) + done + _addr="2001:2:1234::2" + ifconfig lo0 inet6 ${_addr}/128 alias + + i=0 + while test ${i} -lt ${_maxfib}; do + wait_remote_ready "START_${_n}_${i}" + + # No need to do anything for ICMPv6. + # Start reflect for TCP and UDP. + test_ulp_reflect_one "${_n}_tcp" "-N -T TCP6 -A ${_addr}" \ + ${i} ${CTRLPORT} + test_ulp_reflect_one "${_n}_udp" "-N -T UDP6 -A ${_addr}" \ + ${i} ${CTRLPORT} + + wait_remote_ready "STOP_${_n}_${i}" + i=$((i + 1)) + done + + # Cleanup networking again. + route delete -net -inet6 default > /dev/null 2>&1 + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias + i=$((i + 1)) + done + ifconfig lo0 inet6 ${_addr}/128 -alias + +} + +_fwd_fib_symmetric_destructive_defroute_middle_setup_networking() +{ + local _maxfib i j + _maxfib=$1 + + # Setup networking. + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACEFAR} inet6 2001:2:${i}::1/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACEFAR} inet6 2001:2:${i}::1/64 alias + j=0 + while test ${j} -lt ${_maxfib}; do + # Only work on all other FIBs. + if test ${j} -ne ${i}; then + setfib -F ${j} route delete -net -inet6 \ + 2001:2:${i}::/64 > /dev/null + fi + j=$((j + 1)) + done + setfib -F ${i} route delete -net -inet6 \ + 2001:2:1234::2 2001:2:${i}::2 > /dev/null 2>&1 || true + setfib -F ${i} route add -net -inet6 \ + 2001:2:1234::2 2001:2:${i}::2 > /dev/null + i=$((i + 1)) + done +} + +_fwd_fib_symmetric_destructive_defroute_middle_cleanup_networking() +{ + local _maxfib i + _maxfib=$1 + + # Cleanup networking again. + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACEFAR} inet6 2001:2:${i}::1/64 -alias + setfib -F ${i} route delete -net -inet6 \ + 2001:2:1234::2 2001:2:${i}::2 > /dev/null + i=$((i + 1)) + done +} + +_fwd_fib_symmetric_destructive_defroute_middle_ifconfig() +{ + local _n _maxfib i + _n="$1" + _maxfib=$2 + + _fwd_fib_symmetric_destructive_defroute_middle_setup_networking \ + ${_maxfib} + + i=0 + while test ${i} -lt ${_maxfib}; do + ifconfig ${IFACE} fib ${i} + ifconfig ${IFACEFAR} fib ${i} + setup_ipfw_count ${CTRLPORT} ${_maxfib} ${i} -1 + wait_remote_ready "START_${_n}_${i}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}_${i}" + report_ipfw_count + i=$((i + 1)) + done + + _fwd_fib_symmetric_destructive_defroute_middle_cleanup_networking \ + ${_maxfib} +} + +_fwd_fib_symmetric_destructive_defroute_middle_ipfw() +{ + local _n _maxfib i _port + _n="$1" + _maxfib=$2 + + _fwd_fib_symmetric_destructive_defroute_middle_setup_networking \ + ${_maxfib} + + i=0 + while test ${i} -lt ${_maxfib}; do + _port=$((CTRLPORT + 1 + i)) + ipfw add 100 setfib ${i} ipv6-icmp from any to any \ + icmp6types 128 via ${IFACE} in > /dev/null + ipfw add 100 setfib ${i} tcp from any to any \ + dst-port ${_port} via ${IFACE} in > /dev/null + ipfw add 100 setfib ${i} udp from any to any \ + dst-port ${_port} via ${IFACE} in > /dev/null + + ipfw add 100 setfib ${i} ipv6-icmp from any to any \ + icmp6types 129 via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib ${i} tcp from any to any \ + src-port ${_port} via ${IFACEFAR} in > /dev/null + ipfw add 100 setfib ${i} udp from any to any \ + src-port ${_port} via ${IFACEFAR} in > /dev/null + + setup_ipfw_count ${CTRLPORT} ${_maxfib} ${i} -1 + wait_remote_ready "START_${_n}_${i}" + ipfw -q zero > /dev/null + # Nothing to do for the middle node testing the default. + sleep 1 + wait_remote_ready "STOP_${_n}_${i}" + report_ipfw_count + + ipfw delete 100 > /dev/null + i=$((i + 1)) + done + + _fwd_fib_symmetric_destructive_defroute_middle_cleanup_networking \ + ${_maxfib} +} + +fwd_fib_symmetric_destructive_defroute_ifconfig() +{ + local _maxfib _n + _maxfib=$1 + + _n="fwd_fib_symmetric_destructive_defroute_ifconfig" + + print_debug "${_n} ${_maxfib}" + case ${node} in + left) _fwd_fib_symmetric_destructive_defroute_left \ + ${_n} ${_maxfib} ;; + middle) _fwd_fib_symmetric_destructive_defroute_middle_ifconfig \ + ${_n} ${_maxfib} ;; + right) _fwd_fib_symmetric_destructive_defroute_right \ + ${_n} ${_maxfib} ;; + esac +} + +fwd_fib_symmetric_destructive_defroute_ipfw() +{ + local _maxfib _n + _maxfib=$1 + + _n="fwd_fib_symmetric_destructive_defroute_ipfw" + + print_debug "${_n} ${_maxfib}" + case ${node} in + left) _fwd_fib_symmetric_destructive_defroute_left \ + ${_n} ${_maxfib} ;; + middle) _fwd_fib_symmetric_destructive_defroute_middle_ipfw \ + ${_n} ${_maxfib} ;; + right) _fwd_fib_symmetric_destructive_defroute_right \ + ${_n} ${_maxfib} ;; + esac +} + +################################################################################ +# +# MAIN +# + +# Same for all hosts. +if test `sysctl -n security.jail.jailed` -eq 0; then + kldload ipfw > /dev/null 2>&1 || kldstat -v | grep -q ipfw +fi +ipfw -f flush > /dev/null 2>&1 || die "please load ipfw in base system" +ipfw add 65000 permit ip from any to any > /dev/null 2>&1 + +# Per host setup. +setup_networking +reachability_check + +# +# Tests +# + +fwd_default_fib_symmetric +fwd_default_fib_symmetric_ifconfig +fwd_default_fib_symmetric_ipfw + +fwd_fib_symmetric_ifconfig ${RT_NUMFIBS} +fwd_fib_symmetric_ipfw ${RT_NUMFIBS} + +fwd_fib_asymmetric_ifconfig ${RT_NUMFIBS} +fwd_fib_asymmetric_ipfw ${RT_NUMFIBS} + +fwd_fib_symmetric_destructive_ifconfig ${RT_NUMFIBS} +fwd_fib_symmetric_destructive_ipfw ${RT_NUMFIBS} + +fwd_fib_symmetric_destructive_defroute_ifconfig ${RT_NUMFIBS} +fwd_fib_symmetric_destructive_defroute_ipfw ${RT_NUMFIBS} + +# Per host cleanup. +cleanup_networking + +# end diff --git a/tools/test/netfibs/initiator.sh b/tools/test/netfibs/initiator.sh new file mode 100755 index 000000000..d64c5eedc --- /dev/null +++ b/tools/test/netfibs/initiator.sh @@ -0,0 +1,1521 @@ +#!/bin/sh +#- +# Copyright (c) 2012 Cisco Systems, Inc. +# All rights reserved. +# +# This software was developed by Bjoern Zeeb under contract to +# Cisco Systems, Inc.. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +# We will use the RFC5180 (and Errata) benchmarking working group prefix +# 2001:0002::/48 for testing. +PREFIX="2001:2:" + +# Set IFACE to the real interface you want to run the test on. +: ${IFACE:=lo0} + +# Number of seconds to wait for peer node to synchronize for test. +: ${WAITS:=120} + +# Control port we use to exchange messages between nodes to sync. tests, etc. +: ${CTRLPORT:=6666} + +# Get the number of FIBs from the kernel. +RT_NUMFIBS=`sysctl -n net.fibs` + +OURADDR="2001:2:ff00::1" +PEERADDR="2001:2:ff00::2" +PEERLINKLOCAL="" + +# By default all commands must succeed. Individual tests may disable this +# temporary. +set -e + +# Debug magic. +case "${DEBUG}" in +42) set -x ;; +esac + + + +# +# Helper functions. +# +check_rc() +{ + local _rc _exp _testno _testname _msg _r + _rc=$1 + _exp=$2 + _testno=$3 + _testname="$4" + _msg="$5" + + _r="not ok" + if test ${_rc} -eq ${_exp}; then + _r="ok" + fi + echo "${_r} ${_testno} ${_testname} # ${_msg} ${_rc} ${_exp}" +} + +print_debug() +{ + local _msg + _msg="$*" + + case ${DEBUG} in + ''|0) ;; + *) echo "DEBUG: ${_msg}" >&2 ;; + esac +} + +die() +{ + local _msg + _msg="$*" + + echo "ERROR: ${_msg}" >&2 + exit 1 +} + +# +# Test functions. +# + +# Make sure the local link-local and global addresses are reachable +# from all FIBs. +check_local_addr() +{ + local _l i testno + + print_debug "Setting up interface ${IFACE}" + ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up + _l=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'` + + # Let things settle. + print_debug "Waiting 4 seconds for things to settle" + sleep 4 + + printf "1..%d\n" `expr 2 \* ${RT_NUMFIBS}` + testno=1 + i=0 + set +e + while test ${i} -lt ${RT_NUMFIBS}; do + print_debug "Testing FIB ${i}" + + setfib -F${i} ping6 -n -c1 ${_l} > /dev/null 2>&1 + check_rc $? 0 ${testno} "check_local_addr_${i}_l" \ + "FIB ${i} ${_l}" + testno=$((testno + 1)) + + setfib -F${i} ping6 -n -c1 ${OURADDR} > /dev/null 2>&1 + check_rc $? 0 ${testno} "check_local_addr_${i}_a" \ + "FIB ${i} ${OURADDR}" + testno=$((testno + 1)) + + i=$((i + 1)) + done + set -e + ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias +} + + +# Cloned tun(4) devices behave differently on FIB 0 vs. FIB 1..n after creation +# (they also do in IPv4). +check_local_tun() +{ + local _l i testno IFACE _msg + + IFACE=tun42 + print_debug "Setting up interface ${IFACE}" + ifconfig ${IFACE} create + ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up + _l=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'` + + # Let things settle. + print_debug "Waiting 4 seconds for things to settle" + sleep 4 + + printf "1..%d\n" `expr 2 \* ${RT_NUMFIBS}` + testno=1 + _msg="" + i=0 + set +e + while test ${i} -lt ${RT_NUMFIBS}; do + print_debug "Testing FIB ${i}" + if test ${i} -gt 0; then + # Flag the well known behaviour as such. + _msg="TODO " + fi + + setfib -F${i} ping6 -n -c1 ${_l} > /dev/null 2>&1 + check_rc $? 0 ${testno} "check_local_addr_${i}_l" \ + "${_msg}FIB ${i} ${_l}" + testno=$((testno + 1)) + + setfib -F${i} ping6 -n -c1 ${OURADDR} > /dev/null 2>&1 + check_rc $? 0 ${testno} "check_local_addr_${i}_a" \ + "${_msg}FIB ${i} ${OURADDR}" + testno=$((testno + 1)) + + i=$((i + 1)) + done + set -e + ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias + ifconfig ${IFACE} destroy +} + +check_remote_up() +{ + local _l i testno + + print_debug "Setting up interface ${IFACE}" + ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up + _l=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'` + + # Let things settle. + print_debug "Waiting 4 seconds for things to settle" + sleep 4 + + + +} + +send_greeting() +{ + local _l _greeting _keyword _fib _fibs _linklocal + + print_debug "Setting up interface ${IFACE}" + ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up + _l=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'` + + # Let things settle. + print_debug "Waiting 4 seconds for things to settle" + sleep 4 + + # Cleanup firewall and install rules to always allow NS/NA to succeed. + # The latter is needed to allow indvidiual less specific later rules + # from test cases to just disallow any IPv6 traffic on a matching FIB. + ipfw -f flush > /dev/null 2>&1 + ipfw add 65000 permit ip from any to any > /dev/null 2>&1 + ipfw add 5 permit ipv6-icmp from any to any icmp6types 135,136 fib 0 \ + via ${IFACE} out > /dev/null 2>&1 + + set +e + i=0 + rc=-1 + while test ${i} -lt ${WAITS} -a ${rc} -ne 0; do + print_debug "Sending greeting #${i} to peer" + _greeting=`echo "SETUP ${RT_NUMFIBS} ${_l}" | \ + nc -6 -w 1 ${PEERADDR} ${CTRLPORT}` + rc=$? + i=$((i + 1)) + # Might sleep longer in total but better than to DoS + # and not get anywhere. + sleep 1 + done + set -e + + read _keyword _fibs _linklocal < /dev/null 2>&1 + + print_debug "Removing address from interface ${IFACE}" + ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias +} + +testtx_icmp6() +{ + local _n _transfer i testno _txt _fibtxt _rc _ec _p + _n="$1" + _transfer=$2 + + printf "1..%d\n" `expr 2 \* ${RT_NUMFIBS}` + testno=1 + set +e + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + _txt="${_n}${i}" + print_debug "Testing ${_txt}" + _fibtxt=`echo "${_txt}" | hd -v | cut -b11-60 | tr -d ' \r\n'` + + eval _rc="\${rc_${i}_l}" + setfib -F${i} ping6 -n -c1 -p ${_fibtxt} \ + ${PEERLINKLOCAL} > /dev/null 2>&1 + _ec=$? + # We need to normalize the exit code of ping6. + case ${_ec} in + 0) ;; + *) _ec=1 ;; + esac + check_rc ${_ec} ${_rc} ${testno} "${_txt}_l" \ + "FIB ${i} ${PEERLINKLOCAL}" + testno=$((testno + 1)) + + # If doing multiple transfer networks, replace PEERADDR. + _p="${PEERADDR}" + case ${_transfer} in + 1) PEERADDR=2001:2:${i}::2 ;; + esac + + eval _rc="\${rc_${i}_a}" + setfib -F${i} ping6 -n -c1 -p ${_fibtxt} ${PEERADDR} \ + > /dev/null 2>&1 + _ec=$? + # We need to normalize the exit code of ping6. + case ${_ec} in + 0) ;; + *) _ec=1 ;; + esac + check_rc ${_ec} ${_rc} ${testno} "${_txt}_a" \ + "FIB ${i} ${PEERADDR}" + testno=$((testno + 1)) + + # Restore PEERADDR. + PEERADDR="${_p}" + + i=$((i + 1)) + done + set -e +} + +nc_send_recv() +{ + local _fib _loops _msg _expreply _addr _port _opts i + _fib=$1 + _loops=$2 + _msg="$3" + _expreply="$4" + _addr=$5 + _port=$6 + _opts="$7" + + i=0 + while test ${i} -lt ${_loops}; do + i=$((i + 1)) + case "${USE_SOSETFIB}" in + 1) + _reply=`echo "${_msg}" | \ + nc -V ${_fib} ${_opts} ${_addr} ${_port}` + ;; + *) + _reply=`echo "${_msg}" | \ + setfib -F${_fib} nc ${_opts} ${_addr} ${_port}` + ;; + esac + if test "${_reply}" != "${_expreply}"; then + if test ${i} -lt ${_loops}; then + sleep 1 + else + # Must let caller decide how to handle the error. + # die "Got invalid reply from peer." \ + # "Expected '${_expreply}', got '${_reply}'" + return 1 + fi + else + break + fi + done + return 0 +} + +testtx_tcp_udp() +{ + local _n _o _f testno i _fibtxt + _n="$1" + _o="$2" + _f="$3" + + printf "1..%d\n" `expr 2 \* ${RT_NUMFIBS}` + testno=1 + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + print_debug "Testing ${_f} ${i}" + + eval _rc="\${rc_${i}_l}" + _fibtxt="${_n}_${i}_l ${_f} ${i} ${PEERLINKLOCAL}" + nc_send_recv ${i} 1 "${_fibtxt}" "${_fibtxt}" ${PEERLINKLOCAL} \ + ${CTRLPORT} "-6 ${_o} -w1" + check_rc $? ${_rc} ${testno} "${_fibtxt}" + testno=$((testno + 1)) + + eval _rc="\${rc_${i}_a}" + _fibtxt="${_n}_${i}_a ${_f} ${i} ${PEERADDR}" + nc_send_recv ${i} 1 "${_fibtxt}" "${_fibtxt}" ${PEERADDR} \ + ${CTRLPORT} "-6 ${_o} -w1" + check_rc $? ${_rc} ${testno} "${_fibtxt}" + testno=$((testno + 1)) + + i=$((i + 1)) + done +} + +# setfib TCP|UDP/IPv6 test on link-local and global address of peer from all FIBs. +testtx_ulp6_connected() +{ + local _fibtxt _reply _n _o _rc _fib _f _opts + _n=$1 + _o="$2" + _fib=$3 + + case "${USE_SOSETFIB}" in + 1) _f="SO_SETFIB" ;; + *) _f="SETFIB" ;; + esac + + if test "${_o}" == "-i" -a "${_f}" == "SO_SETFIB"; then + print_debug "Skipping icmp6 tests for SO_SETFIB." + return 0 + fi + + # Clear the neighbor table to get deterministic runs. + ndp -cn > /dev/null 2>&1 + + case "${_o}" in + -i) _opts="" ;; # Use TCP for START/DONE. + *) _opts="${_o}" ;; + esac + + set +e + # Let peer know that we are about to start. + _msg="START ${_n}" + nc_send_recv ${_fib} ${WAITS} "${_msg}" "${_msg}" ${PEERADDR} \ + ${CTRLPORT} "-6 ${_opts} -w1" + case $? in + 0) ;; + *) die "Got invalid reply from peer." \ + "Expected '${_msg}', got '${_reply}'" ;; + esac + + case "${_o}" in + -i) testtx_icmp6 "${_n}" ;; + *) testtx_tcp_udp "${_n}" "${_o}" "${_f}" ;; + esac + + # Let peer know that we are done with this test to move to next. + # This must immediately succeed. + _msg="DONE ${_n}" + nc_send_recv ${_fib} ${WAITS} "${_msg}" "${_msg}" ${PEERADDR} \ + ${CTRLPORT} "-6 ${_opts} -w1" + case $? in + 0) ;; + *) die "Got invalid reply from peer." \ + "Expected '${_msg}', got '${_reply}'" ;; + esac + set -e + + print_debug "Successfully received status update '${_reply}'." +} + +################################################################################ +# +# ping6|TCP/UDP connect link-local and global address of peer from all FIBs. +# Default reachability test. +# +testtx_icmp6_connected() +{ + local i + + # Setup expected return values. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + eval rc_${i}_l=0 + eval rc_${i}_a=0 + i=$((i + 1)) + done + + testtx_ulp6_connected "testtx_icmp6_connected" "-i" 0 +} + +testtx_tcp6_connected() +{ + local i + + # Setup expected return values. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + eval rc_${i}_l=0 + eval rc_${i}_a=0 + i=$((i + 1)) + done + + testtx_ulp6_connected testtx_tcp6_connected "" 0 +} + +testtx_udp6_connected() +{ + local i + + # Setup expected return values. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + eval rc_${i}_l=0 + eval rc_${i}_a=0 + i=$((i + 1)) + done + + testtx_ulp6_connected testtx_udp6_connected "-u" 0 +} + +################################################################################ +# +# Use ipfw to return unreach messages for all but one FIB. Rotate over all. +# Making sure error messages are properly returned. +# +testtx_ulp6_connected_blackhole() +{ + local fib i _n _o + _n="$1" + _o="$2" + + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + + print_debug "${_n} ${fib}" + + # Setup expected return values. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + ipfw delete $((100 + i)) > /dev/null 2>&1 || true + case ${i} in + ${fib}) + eval rc_${i}_l=0 + eval rc_${i}_a=0 + ;; + *) eval rc_${i}_l=1 + eval rc_${i}_a=1 + ipfw add $((100 + i)) unreach6 admin-prohib \ + ip6 from any to any fib ${i} via ${IFACE} \ + out > /dev/null 2>&1 + ;; + esac + i=$((i + 1)) + done + + testtx_ulp6_connected "${_n}${fib}" "${_o}" ${fib} + case ${DEBUG} in + ''|0) ;; + *) ipfw show ;; + esac + fib=$((fib + 1)) + done + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + ipfw delete $((100 + fib)) > /dev/null 2>&1 || true + fib=$((fib + 1)) + done +} + +testtx_icmp6_connected_blackhole() +{ + + testtx_ulp6_connected_blackhole \ + "testtx_icmp6_connected_blackhole" "-i" +} + +testtx_tcp6_connected_blackhole() +{ + + testtx_ulp6_connected_blackhole \ + "testtx_tcp6_connected_blackhole" "" +} + +testtx_udp6_connected_blackhole() +{ + + testtx_ulp6_connected_blackhole \ + "testtx_udp6_connected_blackhole" "-u" +} + +################################################################################ +# +# Setup a different transfer net on each FIB. Delete all but one connected +# route in all FIBs (e.g. FIB 0 uses prefix 0, FIB 1 uses prefix 1 , ...). +# +# Need to tag NS/NA incoming to the right FIB given the default FIB does not +# know about the prefix and thus cannot do proper source address lookups for +# replying otherwise. Use ipfw. +# +testtx_ulp6_connected_transfernets() +{ + local fib i _n _o _p + _n="$1" + _o="$2" + + # Setup transfer networks and firewall. + ipfw delete 10 > /dev/null 2>&1 || true + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 alias + ipfw add 10 setfib ${fib} ipv6-icmp from 2001:2:${fib}::/64 \ + to any ip6 icmp6types 135,136 via ${IFACE} in \ + > /dev/null 2>&1 + # Remove connected routes from all but matching FIB. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + case ${i} in + ${fib});; + *) setfib -F${i} route delete -inet6 \ + -net 2001:2:${fib}:: > /dev/null 2>&1 + ;; + esac + i=$((i + 1)) + done + fib=$((fib + 1)) + done + + # Save PEERADDR + _p=${PEERADDR} + + # Run tests. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + PEERADDR=2001:2:${fib}::2 + + print_debug "${_n} ${fib}" + + # Setup expected return values. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + eval rc_${i}_l=0 + case ${i} in + ${fib}) + eval rc_${i}_a=0 + ;; + *) eval rc_${i}_a=1 + ;; + esac + i=$((i + 1)) + done + + testtx_ulp6_connected "${_n}${fib}" "${_o}" ${fib} + fib=$((fib + 1)) + done + + # Restore PEERADDR + PEERADDR=${_p} + + # Cleanup transfer networks and firewall. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 -alias + fib=$((fib + 1)) + done + ipfw delete 10 > /dev/null 2>&1 +} + +testtx_icmp6_connected_transfernets() +{ + + testtx_ulp6_connected_transfernets \ + "testtx_icmp6_connected_transfernets" "-i" +} + +testtx_tcp6_connected_transfernets() +{ + + testtx_ulp6_connected_transfernets \ + "testtx_tcp6_connected_transfernets" "" +} + +testtx_udp6_connected_transfernets() +{ + + testtx_ulp6_connected_transfernets \ + "testtx_udp6_connected_transfernets" "-u" +} + +################################################################################ +# +# Setup a different transfernet on each FIB. Delete all but one connected +# route in all FIBs (e.g. FIB 0 uses prefix 0, FIB 1 uses prefix 1 , ...). +# +# Need to tag NS/NA incoming to the right FIB given the default FIB does not +# know about the prefix and thus cannot do proper source address lookups for +# replying otherwise. Use ifconfig IFACE fib. +# +testtx_ulp6_connected_ifconfig_transfernets() +{ + local fib i _n _o _p + _n="$1" + _o="$2" + + # Setup transfer networks. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 alias + # Remove connected routes from all but matching FIB. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + case ${i} in + ${fib});; + *) setfib -F${i} route delete -inet6 \ + -net 2001:2:${fib}:: > /dev/null 2>&1 + ;; + esac + i=$((i + 1)) + done + fib=$((fib + 1)) + done + + # Save PEERADDR + _p=${PEERADDR} + + # Run tests. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + PEERADDR=2001:2:${fib}::2 + + print_debug "${_n} ${fib}" + + # Setup expected return values. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + eval rc_${i}_l=0 + case ${i} in + ${fib}) + eval rc_${i}_a=0 + ;; + *) eval rc_${i}_a=1 + ;; + esac + i=$((i + 1)) + done + + ifconfig ${IFACE} fib ${fib} + + testtx_ulp6_connected "${_n}${fib}" "${_o}" ${fib} + fib=$((fib + 1)) + done + + # Restore PEERADDR + PEERADDR=${_p} + + # Cleanup transfer networks. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 -alias + fib=$((fib + 1)) + done + ifconfig ${IFACE} fib 0 +} + +testtx_icmp6_connected_ifconfig_transfernets() +{ + + testtx_ulp6_connected_ifconfig_transfernets \ + "testtx_icmp6_connected_ifconfig_transfernets" "-i" +} + + +testtx_tcp6_connected_ifconfig_transfernets() +{ + + testtx_ulp6_connected_ifconfig_transfernets \ + "testtx_tcp6_connected_ifconfig_transfernets" "" +} + +testtx_udp6_connected_ifconfig_transfernets() +{ + + testtx_ulp6_connected_ifconfig_transfernets \ + "testtx_udp6_connected_ifconfig_transfernets" "-u" +} + +################################################################################ +# +# Make destination reachable through the same default route in each FIB only. +# Run standard reachability test. +# +testtx_ulp6_gateway() +{ + local fib i _n _o _p + _n="$1" + _o="$2" + + # Setup default gateway and expected error codes. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + setfib -F${fib} route delete -inet6 -net default \ + > /dev/null 2>&1 || true + setfib -F${fib} route add -inet6 -net default ${PEERADDR} \ + > /dev/null 2>&1 + case "${_o}" in + -i) eval rc_${fib}_l=0 ;; # ICMPv6 will succeed + *) eval rc_${fib}_l=1 ;; + esac + eval rc_${fib}_a=0 + fib=$((fib + 1)) + done + + # Save PEERADDR + _p=${PEERADDR} + PEERADDR="2001:2:ff01::2" + + # Run tests. + print_debug "${_n}" + testtx_ulp6_connected "${_n}" "${_o}" 0 + + # Restore PEERADDR + PEERADDR=${_p} + + # Cleanup transfer networks. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + setfib -F${fib} route delete -inet6 -net default \ + > /dev/null 2>&1 + fib=$((fib + 1)) + done +} + +testtx_icmp6_gateway() +{ + + testtx_ulp6_gateway "testtx_icmp6_gateway" "-i" +} + +testtx_tcp6_gateway() +{ + + testtx_ulp6_gateway "testtx_tcp6_gateway" "" +} + +testtx_udp6_gateway() +{ + + testtx_ulp6_gateway "testtx_udp6_gateway" "-u" +} + +################################################################################ +# +# Make destination reachable through a different default route in each FIB. +# Generate a dedicated transfer network for that in each FIB. Delete all but +# one connected route in all FIBs (e.g. FIB 0 uses prefix 0, ...). +# +# Have a default route present in each FIB all time. +# +# Need to tag NS/NA incoming to the right FIB given the default FIB does not +# know about the prefix and thus cannot do proper source address lookups for +# replying otherwise. Use ipfw. +# +# +testtx_ulp6_transfernets_gateways() +{ + local fib i _n _o _p + _n="$1" + _o="$2" + + # Setup transfer networks, default routes, and firewall. + fib=0 + ipfw delete 10 > /dev/null 2>&1 || true + while test ${fib} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 alias \ + > /dev/null 2>&1 + ipfw add 10 setfib ${fib} ipv6-icmp \ + from 2001:2:${fib}::/64 to any ip6 icmp6types 135,136 \ + via ${IFACE} in > /dev/null 2>&1 + # Remove connected routes from all but matching FIB. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + case ${i} in + ${fib});; + *) setfib -F${i} route delete -inet6 \ + -net 2001:2:${fib}:: > /dev/null 2>&1 + ;; + esac + i=$((i + 1)) + done + # Add default route. + setfib -F${fib} route delete -inet6 -net default \ + > /dev/null 2>&1 || true + setfib -F${fib} route add -inet6 -net default \ + 2001:2:${fib}::2 > /dev/null 2>&1 + fib=$((fib + 1)) + done + + # Save PEERADDR + _p=${PEERADDR} + PEERADDR="2001:2:ff01::2" + + # Setup expected return values. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + case "${_o}" in + -i) eval rc_${i}_l=0 ;; # ICMPv6 will succeed + *) eval rc_${i}_l=1 ;; + esac + eval rc_${i}_a=0 + i=$((i + 1)) + done + + # Run tests. + print_debug "${_n}" + testtx_ulp6_connected "${_n}" "${_o}" 0 + + # Restore PEERADDR + PEERADDR=${_p} + + # Cleanup default routes, transfer networks, and firewall. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + setfib -F${fib} route delete -inet6 -net default \ + > /dev/null 2>&1 + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 -alias \ + > /dev/null 2>&1 + fib=$((fib + 1)) + done + ipfw delete 10 > /dev/null 2>&1 +} + +testtx_icmp6_transfernets_gateways() +{ + + testtx_ulp6_transfernets_gateways \ + "testtx_icmp6_transfernets_gateways" "-i" +} + +testtx_tcp6_transfernets_gateways() +{ + + testtx_ulp6_transfernets_gateways \ + "testtx_tcp6_transfernets_gateways" "" +} + +testtx_udp6_transfernets_gateways() +{ + + testtx_ulp6_transfernets_gateways \ + "testtx_udp6_transfernets_gateways" "-u" +} + +################################################################################ +# +# Make destination reachable through a different default route in each FIB. +# Generate a dedicated transfer network for that in each FIB. Delete all but +# one connected route in all FIBs (e.g. FIB 0 uses prefix 0, ...). +# +# Only have a default route present in 1 FIB at a time. +# +# Need to tag NS/NA incoming to the right FIB given the default FIB does not +# know about the prefix and thus cannot do proper source address lookups for +# replying otherwise. Use ipfw. +# +testtx_ulp6_transfernets_gateway() +{ + local fib i _n _o _p + _n="$1" + _o="$2" + + # Setup transfer networks, default routes, and firewall. + fib=0 + ipfw delete 10 > /dev/null 2>&1 || true + while test ${fib} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 -alias \ + > /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 alias \ + > /dev/null 2>&1 + ipfw add 10 setfib ${fib} ipv6-icmp \ + from 2001:2:${fib}::/64 to any ip6 icmp6types 135,136 \ + via ${IFACE} in > /dev/null 2>&1 + # Remove connected routes from all but matching FIB. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + case ${i} in + ${fib});; + *) setfib -F${i} route delete -inet6 \ + -net 2001:2:${fib}:: > /dev/null 2>&1 + ;; + esac + i=$((i + 1)) + done + fib=$((fib + 1)) + done + + # Save PEERADDR + _p=${PEERADDR} + PEERADDR="2001:2:ff01::2" + + # Run tests. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + + print_debug "${_n} ${fib}" + + # Setup expected return values. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + case "${_o}" in + -i) eval rc_${i}_l=0 ;; # ICMPv6 will succeed + *) eval rc_${i}_l=1 ;; + esac + case ${i} in + ${fib}) + eval rc_${i}_a=0 + ;; + *) eval rc_${i}_a=1 + ;; + esac + i=$((i + 1)) + done + + # Add default route. + setfib -F${fib} route delete -inet6 -net default \ + > /dev/null 2>&1 || true + setfib -F${fib} route add -inet6 -net default \ + 2001:2:${fib}::2 > /dev/null 2>&1 + + testtx_ulp6_connected "${_n}${fib}" "${_o}" ${fib} + + # Delete default route again. + setfib -F${fib} route delete -inet6 -net default \ + > /dev/null 2>&1 + fib=$((fib + 1)) + done + + # Restore PEERADDR + PEERADDR=${_p} + + # Cleanup default routes, transfer networks, and firewall. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + setfib -F${fib} route delete -inet6 -net default \ + > /dev/null 2>&1 + ifconfig ${IFACE} inet6 2001:2:${fib}::1/64 -alias \ + > /dev/null 2>&1 + fib=$((fib + 1)) + done + ipfw delete 10 > /dev/null 2>&1 +} + +testtx_icmp6_transfernets_gateway() +{ + + testtx_ulp6_transfernets_gateway \ + "testtx_icmp6_transfernets_gateway" "-i" +} + + +testtx_tcp6_transfernets_gateway() +{ + + testtx_ulp6_transfernets_gateway \ + "testtx_tcp6_transfernets_gateway" "" +} + +testtx_udp6_transfernets_gateway() +{ + + testtx_ulp6_transfernets_gateway \ + "testtx_udp6_transfernets_gateway" "-u" +} + + +################################################################################ +# +# RX tests (Remotely originated connections). The FIB tests happens on peer. +# +# # For IPFW, IFCONFIG +# # For each FIB +# # Send OOB well known to work START, wait for reflect +# # Send probe, wait for reply with FIB# or RST/ICMP6 unreach +# # (in case of ICMP6 use magic like ipfw count and OOB reply) +# # Send OOB well known to work DONE, wait for reflect +# # Compare real with expected results. +# +testrx_results() +{ + local _r _n _fib i count _instances _transfer _o + _fib="$1" + _n="$2" + _r="$3" + _instances=$4 + _transfer=$5 + _o="$6" + + print_debug "testrx_results ${_fib} ${_n} ${_r} ${_instances}" + + # Trim "RESULT " + _r=${_r#* } + + echo "1..${RT_NUMFIBS}" + while read i count; do + if test ${_instances} -gt 1; then + if test ${count} -gt 0; then + echo "ok ${i} ${_n}result_${i} #" \ + "FIB ${i} ${count} (tested)" + else + echo "not ok ${i} ${_n}result_${i} #" \ + "FIB ${i} ${count} (tested)" + fi + else + case ${i} in + ${_fib}) + if test ${count} -gt 0; then + echo "ok ${i} ${_n}result_${i} #" \ + "FIB ${i} ${count} (tested)" + else + echo "not ok ${i} ${_n}result_${i} #" \ + "FIB ${i} ${count} (tested)" + fi + ;; + *) if test ${count} -eq 0; then + echo "ok ${i} ${_n}result_${i} #" \ + "FIB ${i} ${count}" + else + echo "not ok ${i} ${_n}result_${i} #" \ + "FIB ${i} ${count}" + fi + ;; + esac + fi + i=$((i + 1)) + done < /dev/null 2>&1 || true + ifconfig ${IFACE} inet6 2001:2:${i}::1/64 alias + i=$((i + 1)) + done +} + +testrx_cleanup_transfer_networks() +{ + local i + + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${i}::1/64 -alias \ + > /dev/null 2>&1 + i=$((i + 1)) + done +} + + +testrx_run_test() +{ + local _n _t _fib _o _txt _msg i _reply _instances _destructive _transfer + _n="$1" + _t="$2" + _fib=$3 + _o="$4" + _instances=$5 + _detsructive=$6 + _transfer=$7 + + # Netcat options (for UDP basically). + case "${_o}" in + -i) _opts="" ;; # Use TCP for START/DONE. + *) _opts="${_o}" ;; + esac + + # Combined test case base name. + case ${USE_SOSETFIB} in + 0) _f="setfib" ;; + 1) _f="so_setfib" ;; + *) die "Unexpected value for SO_SETFIB: ${SO_SETFIB}" ;; + esac + _txt="${_n}_${_f}_${_t}_${_fib}_${_instances}_${_detsructive}_${_transfer}" + + print_debug "Starting test '${_txt}' (for ${_instances} instances)." + + case ${_transfer} in + 1) testrx_setup_transfer_networks ;; + esac + + # Let the other side a chance to get ready as well. + sleep 1 + + set +e + # Let peer know that we are about to start. + _msg="START ${_txt}" + nc_send_recv ${_fib} ${WAITS} "${_msg}" "${_msg}" ${PEERADDR} \ + ${CTRLPORT} "-6 ${_opts} -w1" + case $? in + 0) ;; + *) die "Got invalid reply from peer." \ + "Expected '${_msg}', got '${_reply}'" ;; + esac + + # Let the other side a chance to get ready as well. + sleep 1 + + # Send probe. + case "${_o}" in + -i) testtx_icmp6 "${_txt}_" ${_transfer} ;; + *) testrx_tcp_udp "${_txt}" "${_o}" "${_fib}" ${_instances} \ + ${_transfer} ;; + esac + + # Let peer know that we are done with this test to move to next. + # This must immediately succeed. + _msg="DONE ${_txt}" + nc_send_recv ${_fib} ${WAITS} "${_msg}" "${_msg}" ${PEERADDR} \ + ${CTRLPORT} "-6 ${_opts} -w1" + case $? in + 0) ;; + *) die "Got invalid reply from peer." \ + "Expected '${_msg}', got '${_reply}'" ;; + esac + + # Collect and validate the results. Always use TCP. + sleep 1 + set +e + nc_send_recv ${_fib} 1 "RESULT REQUEST" "" ${PEERADDR} \ + ${CTRLPORT} "-6 -w1" + case "${_reply}" in + RESULT\ *) testrx_results ${_fib} "${_txt}_" "${_reply}" ${_instances} \ + ${_transfer} "${_o}" + ;; + *) die "Got invalid reply from peer." \ + "Expected 'RESULT ...', got '${_reply}'" ;; + esac + set -e + + case ${_transfer} in + 1) testrx_cleanup_transfer_networks ;; + esac + + print_debug "Successfully received status update '${_reply}'." +} + +testrx_main_setup_rc() +{ + local _n _t _fib _o _instances _destructive _transfer i + _n="$1" + _t="$2" + _fib=$3 + _o="$4" + _instances=$5 + _destructive=$6 + _transfer=$7 + + # Setup expected return values. + if test ${_destructive} -eq 0; then + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + eval rc_${i}_l=0 + eval rc_${i}_a=0 + i=$((i + 1)) + done + else + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + eval rc_${i}_l=0 + case ${i} in + ${_fib}) eval rc_${i}_a=0 ;; + *) # ICMP6 cannot be distinguished and will + # always work in single transfer network. + case "${_o}" in + -i) case ${_transfer} in + 0) eval rc_${i}_a=0 ;; + 1) eval rc_${i}_a=1 ;; + esac + ;; + *) if test ${_instances} -eq 1 -a \ + ${_transfer} -eq 0; then + eval rc_${i}_a=0 + else + eval rc_${i}_a=1 + fi + ;; + esac + ;; + esac + i=$((i + 1)) + done + fi + + print_debug "${_n}_${t}_${_fib} ${_instances} ${_destructive}" \ + "${_transfer}" + testrx_run_test "${_n}" "${t}" ${_fib} "${_o}" ${_instances} \ + ${_destructive} ${_transfer} +} + +testrx_main() +{ + local _n _o s t fib _instances _destructive _transfer + _n="$1" + _o="$2" + _instances=$3 + + : ${_instances:=1} + + print_debug "${_n}" + for _transfer in 1 0; do + for _destructive in 0 1; do + for t in ipfw ifconfig; do + + print_debug "${_n}_${t}" + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + + testrx_main_setup_rc "${_n}" "${t}" \ + ${fib} "${_o}" ${_instances} \ + ${_destructive} ${_transfer} + + fib=$((fib + 1)) + done + done + done + done +} + +################################################################################ +# +# +# + +testrx_icmp6_same_addr_one_fib_a_time() +{ + + testrx_main \ + "testrx_icmp6_same_addr_one_fib_a_time" "-i" +} + +testrx_tcp6_same_addr_one_fib_a_time() +{ + + testrx_main \ + "testrx_tcp6_same_addr_one_fib_a_time" "" +} + + +testrx_udp6_same_addr_one_fib_a_time() +{ + + testrx_main \ + "testrx_udp6_same_addr_one_fib_a_time" "-u" +} + + +################################################################################ + +testrx_tcp6_same_addr_all_fibs_a_time() +{ + + testrx_main \ + "testrx_tcp6_same_addr_all_fibs_a_time" "" ${RT_NUMFIBS} +} + +testrx_udp6_same_addr_all_fibs_a_time() +{ + + testrx_main \ + "testrx_udp6_same_addr_all_fibs_a_time" "-u" ${RT_NUMFIBS} +} + + +################################################################################ +# +# Prereqs. +# +if test `sysctl -n security.jail.jailed` -eq 0; then + kldload ipfw > /dev/null 2>&1 || kldstat -v | grep -q ipfw + + # Reduce the time we wait in case of no reply to 2s. + sysctl net.inet.tcp.keepinit=2000 > /dev/null 2>&1 +fi +ipfw -f flush > /dev/null 2>&1 || die "please load ipfw in base system" +ipfw add 65000 permit ip from any to any > /dev/null 2>&1 + +################################################################################ +# +# Run tests. +# + +# 64 cases at 16 FIBs. +check_local_addr +check_local_tun + +send_greeting + +# Initiator testing. +for uso in 0 1; do + + USE_SOSETFIB=${uso} + + # Only run ICMP6 tests for the first loop. + # 160 cases at 16 FIBs. + test ${uso} -ne 0 || testtx_icmp6_connected && sleep 1 + testtx_tcp6_connected && sleep 1 + testtx_udp6_connected && sleep 1 + + # 2560 cases at 16 FIBs. + test ${uso} -ne 0 || testtx_icmp6_connected_blackhole && sleep 1 + testtx_tcp6_connected_blackhole && sleep 1 + testtx_udp6_connected_blackhole && sleep 1 + + # 2560 cases at 16 FIBs. + test ${uso} -ne 0 || testtx_icmp6_connected_transfernets && sleep 1 + testtx_tcp6_connected_transfernets && sleep 1 + testtx_udp6_connected_transfernets && sleep 1 + + # 2560 cases at 16 FIBs. + test ${uso} -ne 0 || \ + testtx_icmp6_connected_ifconfig_transfernets && sleep 1 + testtx_tcp6_connected_ifconfig_transfernets && sleep 1 + testtx_udp6_connected_ifconfig_transfernets && sleep 1 + + # 160 cases at 16 FIBs. + test ${uso} -ne 0 || testtx_icmp6_gateway && sleep 1 + testtx_tcp6_gateway && sleep 1 + testtx_udp6_gateway && sleep 1 + + # 160 cases at 16 FIBs. + test ${uso} -ne 0 || testtx_icmp6_transfernets_gateways && sleep 1 + testtx_tcp6_transfernets_gateways && sleep 1 + testtx_udp6_transfernets_gateways && sleep 1 + + # 2560 cases at 16 FIBs. + test ${uso} -ne 0 || testtx_icmp6_transfernets_gateway && sleep 1 + testtx_tcp6_transfernets_gateway && sleep 1 + testtx_udp6_transfernets_gateway && sleep 1 +done + +# Receiver testing. +for uso in 0 1; do + + USE_SOSETFIB=${uso} + + # Only expect ICMP6 tests for the first loop. + # 6144 cases at 16 FIBs. + test ${uso} -ne 0 || testrx_icmp6_same_addr_one_fib_a_time && sleep 1 + # 12288 cases at 16 FIBs. + testrx_tcp6_same_addr_one_fib_a_time && sleep 1 + # 12288 cases at 16 FIBs. + testrx_udp6_same_addr_one_fib_a_time && sleep 1 + + # 12288 cases at 16 FIBs. + testrx_tcp6_same_addr_all_fibs_a_time && sleep 1 + # 12288 cases at 16 FIBs. + testrx_udp6_same_addr_all_fibs_a_time && sleep 1 + +done + +cleanup + +# end diff --git a/tools/test/netfibs/reflect.c b/tools/test/netfibs/reflect.c new file mode 100644 index 000000000..3790617b1 --- /dev/null +++ b/tools/test/netfibs/reflect.c @@ -0,0 +1,365 @@ +/*- + * Copyright (c) 2012 Cisco Systems, Inc. + * All rights reserved. + * + * This software was developed by Bjoern Zeeb under contract to + * Cisco Systems, Inc.. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include + +#include + +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +static char *testcase; +static int accepts; +static int debug; +static u_int fib = -1; +static u_int reflectfib = -1; +static uint16_t port = 6666; +static char *addr; +static int nostart; + +static int +reflect_conn(int s, char *buf, size_t buflen, ssize_t l, struct sockaddr *sa, + socklen_t salen) +{ + ssize_t m; + + if (l == -1) + err(EX_OSERR, "read()"); + if (l == 0) + errx(EX_NOINPUT, "EOF"); + if ((size_t)l > (buflen - 1)) + errx(EX_DATAERR, "Input too long"); + /* Nuke the \n from echo | netcat. */ + buf[l-1] = '\0'; + + /* + * Match three cases: (1) START, (2) DONE, (3) anything else. + * For anything but START and DONE we just reflect everything. + */ + /* + * We expected a "START testcase" on first connect. Otherwise it means + * that we are out of sync. Exit to not produce weird results. + */ + if (accepts == 0 && nostart == 0) { + if (strncmp(buf, "START ", 6) != 0) + errx(EX_PROTOCOL, "Not received START on first " + "connect: %s", buf); + if (l < 8) + errx(EX_PROTOCOL, "START without test case name: %s", + buf); + if (strcmp(buf+6, testcase) != 0) + errx(EX_PROTOCOL, "START test case does not match " + "'%s': '%s'", testcase, buf+6); + } + /* If debug is on, log. */ + if (debug > 0) + fprintf(stderr, "<< %s: %s\n", testcase, buf); + + if (reflectfib != (u_int)-1) + l = snprintf(buf, sizeof(buf), "FIB %u\n", reflectfib); + + /* If debug is on, log. */ + if (debug > 0) { + buf[l-1] = '\0'; + fprintf(stderr, ">> %s: %s\n", testcase, buf); + } + + /* Reflect data with \n again. */ + buf[l-1] = '\n'; + + if (sa != NULL) { + m = sendto(s, buf, l, 0, sa, salen); + } else + m = write(s, buf, l); + /* XXX This is simplified handling. */ + if (m == -1 && sa != NULL && errno == EHOSTUNREACH) + warn("ignored expected: sendto(%s, %zd)", buf, l); + else if (m == -1 && (sa == NULL || errno != EHOSTUNREACH)) + err(EX_OSERR, "write(%s, %zd)", buf, l); + else if (m != l) + err(EX_OSERR, "short write(%s, %zd) %zd", buf, l, m); + + + accepts++; + + /* See if we got an end signal. */ + if (strncmp(buf, "DONE", 4) == 0) + return (-2); + return (0); +} + +static int +reflect_tcp6_conn(int as) +{ + char buf[1500]; + ssize_t l; + int error, s; + + s = accept(as, NULL, NULL); + if (s == -1) + err(EX_OSERR, "accept()"); + + l = read(s, buf, sizeof(buf)); + error = reflect_conn(s, buf, sizeof(buf), l, NULL, 0); + close(s); + + return (error); +} + +static int +reflect_udp6_conn(int s) +{ + char buf[1500]; + struct sockaddr_in6 from; + socklen_t fromlen; + ssize_t l; + int error; + + fromlen = sizeof(from); + l = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&from, + &fromlen); +#if 0 + if (l != -1) { + rc = connect(s, (struct sockaddr *)&from, fromlen); + if (rc == -1) { + if (inet_ntop(PF_INET6, &from, buf, sizeof(buf)) == NULL) + buf[0] = '\0'; + err(EX_OSERR, "connect(%d, %s, %u)", s, buf, fromlen); + } + } +#endif + error = reflect_conn(s, buf, sizeof(buf), l, (struct sockaddr *)&from, + fromlen); +#if 0 + if (l != -1) { + /* Undo the connect binding again. */ + fromlen = sizeof(from); + bzero(&from, fromlen); + from.sin6_len = fromlen; + from.sin6_family = AF_INET6; + from.sin6_port = htons(port); /* This only gives us a ::1:port ::1:port binding */ + rc = connect(s, (struct sockaddr *)&from, fromlen); + if (rc == -1) { + if (inet_ntop(PF_INET6, &from.sin6_addr, buf, + sizeof(buf)) == NULL) + buf[0] = '\0'; + err(EX_OSERR, "un-connect(%d, %s, %u)", s, buf, fromlen); + } + } +#endif + + return (error); +} + +static int +reflect_6(int domain, int type) +{ + struct sockaddr_in6 sin6; + fd_set rset; + int i, rc, s; + + /* Get us a listen socket. */ + s = socket(domain, type, 0); + if (s == -1) + err(EX_OSERR, "socket()"); + + /* + * In case a FIB was given on cmd line, set it. Let the kernel do the + * the bounds check. + */ + if (fib != (u_int)-1) { + rc = setsockopt(s, SOL_SOCKET, SO_SETFIB, &fib, sizeof(fib)); + if (rc == -1) + err(EX_OSERR, "setsockopt(SO_SETFIB)"); + } + + /* Allow re-use. Otherwise restarting for the next test might error. */ + i = 1; + rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); + if (rc == -1) + err(EX_OSERR, "setsockopt(SO_REUSEADDR)"); + i = 1; + rc = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &i, sizeof(i)); + if (rc == -1) + err(EX_OSERR, "setsockopt(SO_REUSEPORT)"); + + /* Bind address and port or just port. */ + sin6.sin6_len = sizeof(sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(port); + sin6.sin6_flowinfo = 0; + bzero(&sin6.sin6_addr, sizeof(sin6.sin6_addr)); + if (addr != NULL) { + rc = inet_pton(PF_INET6, addr, &sin6.sin6_addr); + if (rc == 0) + errx(EX_USAGE, "inet_pton()"); + else if (rc == -1) + err(EX_OSERR, "inet_pton()"); + else if (rc != 1) + errx(EX_SOFTWARE, "inet_pton()"); + } + sin6.sin6_scope_id = 0; + rc = bind(s, (struct sockaddr *)&sin6, sizeof(sin6)); + if (rc == -1) + err(EX_OSERR, "bind(%d)", s); + + if (type == SOCK_STREAM) { + rc = listen(s, port); + if (rc == -1) + err(EX_OSERR, "listen(%d, %u)", s, port); + } + + /* + * We shall never do more than one connection in parallel so can keep + * it simple. + */ + do { + FD_ZERO(&rset); + FD_SET(s, &rset); + rc = select(s + 1, &rset, NULL, NULL, NULL); + if (rc == -1 && errno != EINTR) + err(EX_OSERR, "select()"); + + if (rc == 0 || errno == EINTR) + continue; + + if (rc != 1) + errx(EX_OSERR, "select() miscounted 1 to %d", rc); + if (!FD_ISSET(s, &rset)) + errx(EX_OSERR, "select() did not return our socket"); + + if (type == SOCK_STREAM) + rc = reflect_tcp6_conn(s); + else if (type == SOCK_DGRAM) + rc = reflect_udp6_conn(s); + else + errx(EX_SOFTWARE, "Unsupported socket type %d", type); + } while (rc == 0); + /* Turn end flagging into no error. */ + if (rc == -2) + rc = 0; + + /* Close listen socket. */ + close(s); + + return (rc); +} + +static int +reflect_tcp6(void) +{ + + return (reflect_6(PF_INET6, SOCK_STREAM)); +} + +static int +reflect_udp6(void) +{ + + return (reflect_6(PF_INET6, SOCK_DGRAM)); +} + +int +main(int argc, char *argv[]) +{ + long long l; + char *dummy, *afname; + int ch, rc; + + afname = NULL; + while ((ch = getopt(argc, argv, "A:dF:f:Np:t:T:")) != -1) { + switch (ch) { + case 'A': + addr = optarg; + break; + case 'd': + debug++; + break; + case 'F': + l = strtoll(optarg, &dummy, 10); + if (*dummy != '\0' || l < 0) + errx(EX_USAGE, "Invalid FIB number"); + fib = (u_int)l; + break; + case 'f': + l = strtoll(optarg, &dummy, 10); + if (*dummy != '\0' || l < 0) + errx(EX_USAGE, "Invalid FIB number"); + reflectfib = (u_int)l; + break; + case 'N': + nostart=1; + break; + case 'p': + l = strtoll(optarg, &dummy, 10); + if (*dummy != '\0' || l < 0) + errx(EX_USAGE, "Invalid port number"); + port = (uint16_t)l; + break; + case 't': + testcase = optarg; + break; + case 'T': + afname = optarg; + break; + case '?': + default: + errx(EX_USAGE, "Unknown command line option at '%c'", + optopt); + /* NOTREACHED */ + } + } + + if (testcase == NULL) + errx(EX_USAGE, "Mandatory option -t not given"); + if (afname == NULL) + errx(EX_USAGE, "Mandatory option -T not given"); + + if (strcmp(afname, "TCP6") == 0) + rc = reflect_tcp6(); + else if (strcmp(afname, "UDP6") == 0) + rc = reflect_udp6(); + else + errx(EX_USAGE, "Mandatory option -T %s not a valid option", + afname); + + return (rc); +} diff --git a/tools/test/netfibs/reflector.sh b/tools/test/netfibs/reflector.sh new file mode 100755 index 000000000..3f8c43ae4 --- /dev/null +++ b/tools/test/netfibs/reflector.sh @@ -0,0 +1,1098 @@ +#!/bin/sh +#- +# Copyright (c) 2012 Cisco Systems, Inc. +# All rights reserved. +# +# This software was developed by Bjoern Zeeb under contract to +# Cisco Systems, Inc.. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +# We will use the RFC5180 (and Errata) benchmarking working group prefix +# 2001:0002::/48 for testing. +PREFIX="2001:2:" + +# Set IFACE to the real interface you want to run the test on. +: ${IFACE:=lo0} + +# Control port we use to exchange messages between nodes to sync. tests, etc. +: ${CTRLPORT:=6666} + +# Get the number of FIBs from the kernel. +RT_NUMFIBS=`sysctl -n net.fibs` + +PEERADDR="2001:2:ff00::1" +OURADDR="2001:2:ff00::2" + +OURLINKLOCAL="" +PEERLINKLOCAL="" + +# By default all commands must succeed. Individual tests may disable this +# temporary. +set -e + +# Debug magic. +case "${DEBUG}" in +42) set -x ;; +esac + + + +# +# Helper functions. +# + +# Function to avoid prelist races adding and deleting prefixes too quickly. +delay() +{ + + # sleep 1 is too long. + touch /tmp/foo || true + stat /tmp/foo > /dev/null 2>&1 || true +} + +check_rc() +{ + local _rc _exp _testno _testname _msg _r + _rc=$1 + _exp=$2 + _testno=$3 + _testname="$4" + _msg="$5" + + _r="not ok" + if test ${_rc} -eq ${_exp}; then + _r="ok" + fi + echo "${_r} ${_testno} ${_testname} # ${_msg} ${_rc}" +} + +print_debug() +{ + local _msg + _msg="$*" + + case ${DEBUG} in + ''|0) ;; + *) echo "DEBUG: ${_msg}" >&2 ;; + esac +} + +die() +{ + local _msg + _msg="$*" + + echo "ERROR: ${_msg}" >&2 + exit 1 +} + +# +# Test functions. +# + +# Setup our side and wait for the peer to tell us that it is ready. +wait_remote_ready() +{ + local _greeting _keyword _fibs _linklocal i + + print_debug "Setting up interface ${IFACE}" + ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias > /dev/null 2>&1 || true + delay + ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias \ + > /dev/null 2>&1 || true + delay + i=$((i + 1)) + done + OURLINKLOCAL=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'` + + # Let things settle. + print_debug "Waiting 4 seconds for things to settle" + sleep 4 + + # Wait for the remote to connect and start things. + # We tell it the magic keyword, our number of FIBs and our link-local. + # It already knows our global address. + _greeting=`echo "SETUP ${RT_NUMFIBS} ${OURLINKLOCAL}" | \ + nc -6 -l ${CTRLPORT}` + + read _keyword _fibs _linklocal < /dev/null 2>&1 || true + delay + ifconfig lo0 inet6 2001:2:ff01::2 alias + + _opts="" + case ${DEBUG} in + ''|0) ;; + 42) _opts="-d -d" ;; + *) _opts="-d" ;; + esac + + print_debug "./reflect -p ${CTRLPORT} -T ${_o} " \ + "-t ${_n} ${_opts} -A 2001:2:ff01::2" + ./reflect -p ${CTRLPORT} -T ${_o} \ + -t ${_n} ${_opts} -A 2001:2:ff01::2 + print_debug "reflect terminated without error." + + ifconfig lo0 inet6 2001:2:ff01::2 -alias + delay +} + +testtx_icmp6_gateway() +{ + + testtx_ulp6_gateway "testtx_icmp6_gateway" "TCP6" +} + +testtx_tcp6_gateway() +{ + + testtx_ulp6_gateway "testtx_tcp6_gateway" "TCP6" +} + +testtx_udp6_gateway() +{ + + testtx_ulp6_gateway "testtx_udp6_gateway" "UDP6" +} + +################################################################################ +# +testtx_ulp6_transfernets_gateways() +{ + local _opts fib _n _o + _n="$1" + _o="$2" + + _opts="" + case ${DEBUG} in + ''|0) ;; + 42) _opts="-d -d" ;; + *) _opts="-d" ;; + esac + + # Setup transfer networks. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + setfib -F${fib} \ + ifconfig ${IFACE} inet6 2001:2:${fib}::2/64 alias + fib=$((fib + 1)) + done + + # Setup out listener IP. + ifconfig lo0 inet6 2001:2:ff01::2 -alias > /dev/null 2>&1 || true + delay + ifconfig lo0 inet6 2001:2:ff01::2 alias + + # Reflect requests. + print_debug "./reflect -p ${CTRLPORT} -T ${_o} " \ + "-t ${_n} ${_opts} -A 2001:2:ff01::2" + ./reflect -p ${CTRLPORT} -T ${_o} \ + -t ${_n} ${_opts} -A 2001:2:ff01::2 + print_debug "reflect terminated without error." + + # Cleanup transfer networks and listener IP. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + setfib -F${fib} \ + ifconfig ${IFACE} inet6 2001:2:${fib}::2/64 -alias + delay + fib=$((fib + 1)) + done + ifconfig lo0 inet6 2001:2:ff01::2 -alias +} + +testtx_icmp6_transfernets_gateways() +{ + + testtx_ulp6_transfernets_gateways \ + "testtx_icmp6_transfernets_gateways" "TCP6" +} + +testtx_tcp6_transfernets_gateways() +{ + + testtx_ulp6_transfernets_gateways \ + "testtx_tcp6_transfernets_gateways" "TCP6" +} + +testtx_udp6_transfernets_gateways() +{ + + testtx_ulp6_transfernets_gateways \ + "testtx_udp6_transfernets_gateways" "UDP6" +} + + +################################################################################ +# +testtx_ulp6_transfernets_gateway() +{ + local _opts fib _n _o + _n="$1" + _o="$2" + + _opts="" + case ${DEBUG} in + ''|0) ;; + 42) _opts="-d -d" ;; + *) _opts="-d" ;; + esac + + # Setup transfer networks. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + setfib -F${fib} \ + ifconfig ${IFACE} inet6 2001:2:${fib}::2/64 alias + fib=$((fib + 1)) + done + + # Setup out listener IP. + ifconfig lo0 inet6 2001:2:ff01::2 -alias > /dev/null 2>&1 || true + delay + ifconfig lo0 inet6 2001:2:ff01::2 alias + + # Reflect requests. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + print_debug "./reflect -p ${CTRLPORT} -T ${_o} " \ + "-t ${_n}${fib} ${_opts} -A 2001:2:ff01::2" + ./reflect -p ${CTRLPORT} -T ${_o} \ + -t ${_n}${fib} ${_opts} -A 2001:2:ff01::2 + print_debug "reflect terminated without error." + fib=$((fib + 1)) + done + + # Cleanup transfer networks and listener IP. + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + setfib -F${fib} \ + ifconfig ${IFACE} inet6 2001:2:${fib}::2/64 -alias + delay + fib=$((fib + 1)) + done + ifconfig lo0 inet6 2001:2:ff01::2 -alias +} + +testtx_icmp6_transfernets_gateway() +{ + + testtx_ulp6_transfernets_gateway \ + "testtx_icmp6_transfernets_gateway" "TCP6" +} + +testtx_tcp6_transfernets_gateway() +{ + + testtx_ulp6_transfernets_gateway \ + "testtx_tcp6_transfernets_gateway" "TCP6" +} + +testtx_udp6_transfernets_gateway() +{ + + testtx_ulp6_transfernets_gateway \ + "testtx_udp6_transfernets_gateway" "UDP6" +} + +################################################################################ +# +# We are receiver, but the FIBs are with us this time. +# +# + +# # For IPFW, IFCONFIG +# # For each FIB +# # Send OOB well known to work START, wait for reflect +# # Send probe, wait for reply with FIB# or RST/ICMP6 unreach +# # (in case of ICMP6 use magic like ipfw count and OOB reply) +# # Send OOB well known to work DONE, wait for reflect +# # Compare real with expected results. +# + +textrx_ipfw_setup() +{ + local _fib _transfer i _p _o + _fib=$1 + _transfer=$2 + + # ICMP6 would need content inspection to distinguish FIB, we can + # only differentiate by address. + # For the default single-address cases always set to current FIB. + ipfw add 100 setfib ${_fib} ipv6-icmp \ + from ${PEERADDR} to ${OURADDR} \ + via ${IFACE} in > /dev/null 2>&1 + ipfw add 100 setfib ${_fib} ipv6-icmp \ + from ${PEERLINKLOCAL%\%*} to ${OURLINKLOCAL%\%*} \ + via ${IFACE} in > /dev/null 2>&1 + + # Always also do a setfib for the control port so that OOB + # signaling workes even if we remove connected subnets. + ipfw add 200 setfib ${_fib} ip6 from ${PEERADDR} to ${OURADDR} \ + dst-port ${CTRLPORT} via ${IFACE} in > /dev/null 2>&1 + + # Save addresses + _p="${PEERADDR}" + _o="${OURADDR}" + + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + + # If doing multiple transfer networks, replace PEERADDR. + case ${_transfer} in + 1) PEERADDR=2001:2:${i}::1 + OURADDR=2001:2:${i}::2 + ;; + esac + + if test ${_instances} -gt 1 -o ${_transfer} -eq 1; then + ipfw add 400 setfib ${_fib} ipv6-icmp \ + from ${PEERADDR} to ${OURADDR} \ + icmp6types 128 \ + via ${IFACE} in > /dev/null 2>&1 + fi + + case ${i} in + ${_fib}) + ipfw add 400 setfib ${_fib} ip6 \ + from ${PEERADDR} to ${OURADDR} \ + dst-port $((CTRLPORT + 1000 + i)) \ + via ${IFACE} in > /dev/null 2>&1 + ipfw add 400 setfib ${_fib} ip6 \ + from ${PEERLINKLOCAL%\%*} to ${OURLINKLOCAL%\%*} \ + dst-port $((CTRLPORT + 1000 + i)) \ + via ${IFACE} in > /dev/null 2>&1 + if test ${_instances} -le 1 -o ${_transfer} -ne 1; then + ipfw add 400 setfib ${_fib} ipv6-icmp \ + from ${PEERADDR} to ${OURADDR} \ + icmp6types 128 \ + via ${IFACE} in > /dev/null 2>&1 + fi + ;; + esac + + i=$((i + 1)) + done + + # Restore addresses. + PEERADDR="${_p}" + OURADDR="${_o}" + + case ${DEBUG} in + ''|0) ;; + *) ipfw show ;; + esac +} + +textrx_ifconfig_setup() +{ + local _fib + _fib=$1 + + ifconfig ${IFACE} fib ${_fib} > /dev/null 2>&1 +} + +textrx_ipfw_cleanup() +{ + local i + + case ${DEBUG} in + ''|0) ;; + *) ipfw show ;; + esac + + ipfw delete 100 > /dev/null 2>&1 || true + ipfw delete 200 > /dev/null 2>&1 || true + ipfw delete 400 > /dev/null 2>&1 || true + + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + + ipfw delete $((1000 + i)) > /dev/null 2>&1 || true + i=$((i + 1)) + done +} + +textrx_ifconfig_cleanup() +{ + + ifconfig ${IFACE} fib 0 > /dev/null 2>&1 +} + +textrx_count_setup() +{ + local i + + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + + # Count ICMP6 echo replies. + ipfw add $((500 + i)) count ipv6-icmp from any to any \ + icmp6types 129 fib ${i} via ${IFACE} out > /dev/null 2>&1 + ipfw add $((500 + i)) count tcp from any to any \ + fib ${i} via ${IFACE} out > /dev/null 2>&1 + ipfw add $((500 + i)) count udp from any to any \ + fib ${i} via ${IFACE} out > /dev/null 2>&1 + i=$((i + 1)) + done +} + +textrx_count_results() +{ + local _fib _o i _rstr _c _req _p _opts + _fib=$1 + _o="$2" + + case ${DEBUG} in + ''|0) ;; + *) ipfw show ;; + esac + + _rstr="" + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + + case "${_o}" in + "-i") _c=`ipfw show $((500 + i)) | awk '/ ipv6-icmp / { print $2 }'` ;; + "-u") _c=`ipfw show $((500 + i)) | awk '/ udp / { print $2 }'` ;; + *) _c=`ipfw show $((500 + i)) | awk '/ tcp / { print $2 }'` ;; + esac + _rstr="${_rstr}${i} ${_c}," + + ipfw delete $((500 + i)) > /dev/null 2>&1 || true + i=$((i + 1)) + done + + # We do not care about the request. + _req=`echo "RESULT ${_rstr}" | nc -V ${_fib} -6 -l ${CTRLPORT}` + print_debug "$? -- ${_req} -- RESULT ${_rstr}" +} + +testrx_remove_connected() +{ + local _fib _transfer i j _prefix + _fib=$1 + _transfer=$2 + + if test ${_transfer} -eq 1; then + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + j=0 + while test ${j} -lt ${RT_NUMFIBS}; do + _prefix="2001:2:${j}::" + + case ${j} in + ${_fib});; + *) print_debug "setfib -F${i} route delete" \ + "-inet6 -net ${_prefix}" + setfib -F${i} route delete -inet6 -net \ + ${_prefix} > /dev/null 2>&1 + ;; + esac + j=$((j + 1)) + done + i=$((i + 1)) + done + + else + _prefix=${OURADDR%2} # Luckily we know the details. + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + + case ${i} in + ${_fib});; + *) print_debug "setfib -F${i} route delete" \ + "-inet6 -net ${_prefix}" + setfib -F${i} route delete -inet6 -net \ + ${_prefix} > /dev/null 2>&1 + ;; + esac + + i=$((i + 1)) + done + fi +} + +testrx_cleanup_connected() +{ + local _fib _transfer i _prefix + _fib=$1 + _transfer=$2 + + if test ${_transfer} -eq 1; then + + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + setfib -F${i} \ + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias \ + > /dev/null 2>&1 + delay + i=$((i + 1)) + done + + else + # Use the hammer removing the address and adding it again to get + # the connected subnet back to all FIBs. Hard to do otherwise. + ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias || true + delay + ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up + fi +} + +testrx_setup_transfer_networks() +{ + local i + + i=0 + while test ${i} -lt ${RT_NUMFIBS}; do + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias \ + > /dev/null 2>&1 || true + delay + ifconfig ${IFACE} inet6 2001:2:${i}::2/64 alias + i=$((i + 1)) + done +} + +testrx_run_one() +{ + local _fib _txt _opts + _fib=$1 + _txt="$2" + _opts="$3" + + case ${USE_SOSETFIB} in + 0) print_debug "setfib -F${_fib} ./reflect -p ${CTRLPORT}" \ + "-t ${_txt} ${_opts}" + setfib -F${_fib} ./reflect -p ${CTRLPORT} -t ${_txt} ${_opts} + ;; + 1) print_debug "./reflect -F${_fib} -p ${CTRLPORT} -t ${_txt}" \ + "${_opts}" + ./reflect -F${_fib} -p ${CTRLPORT} -t ${_txt} ${_opts} + ;; + *) die "Invalid value for USE_SOSETFIB: ${USE_SOSETFIB}" ;; + esac + print_debug "reflect '${_txt}' terminated without error." +} + +testrx_run_multiple() +{ + local _fib _txt _opts i _jobs _p _w + _fib=$1 + _txt="$2" + _opts="$3" + + i=0 + _jobs="" + while test ${i} -lt ${RT_NUMFIBS}; do + case ${USE_SOSETFIB} in + 0) print_debug "setfib -F${i} ./reflect" \ + "-p $((CTRLPORT + 1000 + i))" \ + "-t ${_txt} ${_opts} -N -f ${i} &" + setfib -F${i} ./reflect -p $((CTRLPORT + 1000 + i)) \ + -t ${_txt} ${_opts} -N -f ${i} & + ;; + 1) print_debug "./reflect -F ${i}" \ + "-p $((CTRLPORT + 1000 + i))" \ + "-t ${_txt} ${_opts} -N -f ${i} &" + ./reflect -F ${i} -p $((CTRLPORT + 1000 + i)) \ + -t ${_txt} ${_opts} -N -f ${i} & + ;; + *) die "Invalid value for USE_SOSETFIB: ${USE_SOSETFIB}" ;; + esac + _p=$! + _jobs="${_jobs}${_p} " + case ${i} in + ${_fib}) _w=${_p} ;; + esac + i=$((i + 1)) + done + + # Start OOB control connection for START/DONE. + testrx_run_one ${_fib} "${_txt}" "${_opts}" + print_debug "KILL ${_jobs}" + for i in ${_jobs}; do + kill ${i} || true + done + #killall reflect || true + print_debug "reflects for '${_txt}' terminated without error." +} + +testrx_run_test() +{ + local _n _t _fib _o _txt i _f _instance _destructive _transfer + _n="$1" + _t="$2" + _fib=$3 + _o="$4" + _instances=$5 + _destructive=$6 + _transfer=$7 + + : ${_destructive:=0} + + _opts="" + case ${DEBUG} in + ''|0) ;; + 42) _opts="-d -d" ;; + *) _opts="-d" ;; + esac + + # Convert netcat options to reflect aguments. + case "${_o}" in + -i) _opts="${_opts} -T TCP6" ;; # Use TCP for START/DONE. + -u) _opts="${_opts} -T UDP6" ;; + *) _opts="${_opts} -T TCP6" ;; + esac + + # Combined test case base name. + case ${USE_SOSETFIB} in + 0) _f="setfib" ;; + 1) _f="so_setfib" ;; + *) die "Unexpected value for SO_SETFIB: ${SO_SETFIB}" ;; + esac + + _txt="${_n}_${_f}_${_t}_${_fib}_${_instances}_${_destructive}_${_transfer}" + + case ${_transfer} in + 1) testrx_setup_transfer_networks ;; + esac + + case "${_t}" in + ipfw) textrx_ipfw_setup ${_fib} ${_transfer} ${_instances} ;; + ifconfig) textrx_ifconfig_setup ${_fib} ;; + *) die "Invalid type in ${_txt}" ;; + esac + + # Setup unresponsive FIBs. + case ${_destructive} in + 1) testrx_remove_connected ${_fib} ${_transfer} ;; + esac + + # Setup to get result counts. + textrx_count_setup + + # Run just one / one per FIB (with incremental ports). + #case ${_instances} in + #1) testrx_run_one ${_fib} "${_txt}" "${_opts}" ;; + #*) testrx_run_multiple ${_fib} "${_txt}" "${_opts}" ;; + #esac + testrx_run_multiple ${_fib} "${_txt}" "${_opts}" ${_transfer} + + # Export result counts. + textrx_count_results ${_fib} "${_o}" + + # Cleanup unresponsive FIBs or multiple prefixes. + if test ${_destructive} -eq 1 -o ${_transfer} -eq 1; then + testrx_cleanup_connected ${_fib} ${_transfer} + fi + + case "${_t}" in + ipfw) textrx_ipfw_cleanup ;; + ifconfig) textrx_ifconfig_cleanup ;; + *) die "Invalid type in ${_txt}" ;; + esac +} + +testrx_main() +{ + local _n _o s t fib _instances _destructive + _n="$1" + _o="$2" + _instances=$3 + + : ${_instances:=1} + + print_debug "${_n}" + for _transfer in 1 0; do + for _destructive in 0 1; do + for t in ipfw ifconfig; do + + print_debug "${_n}_${t}" + fib=0 + while test ${fib} -lt ${RT_NUMFIBS}; do + + print_debug "${_n}_${t}_${fib}" \ + "${_instances} ${_destructive}" \ + "${_transfer}" + testrx_run_test "${_n}" "${t}" ${fib} \ + "${_o}" ${_instances} \ + ${_destructive} ${_transfer} + + fib=$((fib + 1)) + done + done + done + done +} + +################################################################################ +# +# Probe all FIBs with one "active" one a time. +# +testrx_icmp6_same_addr_one_fib_a_time() +{ + + testrx_main "testrx_icmp6_same_addr_one_fib_a_time" "-i" +} + +testrx_tcp6_same_addr_one_fib_a_time() +{ + + testrx_main "testrx_tcp6_same_addr_one_fib_a_time" "" +} + +testrx_udp6_same_addr_one_fib_a_time() +{ + + testrx_main "testrx_udp6_same_addr_one_fib_a_time" "-u" +} + +################################################################################ +# +# Probe all FIBs with all "active" all time. +# +testrx_tcp6_same_addr_all_fibs_a_time() +{ + + testrx_main "testrx_tcp6_same_addr_all_fibs_a_time" "" ${RT_NUMFIBS} +} + +testrx_udp6_same_addr_all_fibs_a_time() +{ + + testrx_main "testrx_udp6_same_addr_all_fibs_a_time" "-u" ${RT_NUMFIBS} +} + + +################################################################################ +# +# Prereqs. +# +if test `sysctl -n security.jail.jailed` -eq 0; then + kldload ipfw > /dev/null 2>&1 || kldstat -v | grep -q ipfw +fi +ipfw -f flush > /dev/null 2>&1 || die "please load ipfw in base system" +ipfw add 65000 permit ip from any to any > /dev/null 2>&1 +killall reflect || true + +################################################################################ +# +# Run tests. +# +wait_remote_ready + +# We are receiver reflecting the input back. +for uso in 0 1; do + + # Only run ICMP6 tests for the first loop. + test ${uso} -ne 0 || testtx_icmp6_connected + testtx_tcp6_connected + testtx_udp6_connected + + test ${uso} -ne 0 || testtx_icmp6_connected_blackhole + testtx_tcp6_connected_blackhole + testtx_udp6_connected_blackhole + + test ${uso} -ne 0 || testtx_icmp6_connected_transfernets + testtx_tcp6_connected_transfernets + testtx_udp6_connected_transfernets + + test ${uso} -ne 0 || testtx_icmp6_connected_ifconfig_transfernets + testtx_tcp6_connected_ifconfig_transfernets + testtx_udp6_connected_ifconfig_transfernets + + test ${uso} -ne 0 || testtx_icmp6_gateway + testtx_tcp6_gateway + testtx_udp6_gateway + + test ${uso} -ne 0 || testtx_icmp6_transfernets_gateways + testtx_tcp6_transfernets_gateways + testtx_udp6_transfernets_gateways + + test ${uso} -ne 0 || testtx_icmp6_transfernets_gateway + testtx_tcp6_transfernets_gateway + testtx_udp6_transfernets_gateway +done + +ipfw -f flush > /dev/null 2>&1 +ipfw add 65000 permit ip from any to any > /dev/null 2>&1 + +# We are receiver, but the FIBs are with us this time. +for uso in 0 1; do + + USE_SOSETFIB=${uso} + + # Only expect ICMP6 tests for the first loop. + test ${uso} -ne 0 || testrx_icmp6_same_addr_one_fib_a_time + testrx_tcp6_same_addr_one_fib_a_time + testrx_udp6_same_addr_one_fib_a_time + + testrx_tcp6_same_addr_all_fibs_a_time + testrx_udp6_same_addr_all_fibs_a_time + +done + +cleanup + +# end -- 2.45.0