diff --git a/tools/test/README b/tools/test/README index 438c1f5170d9..eda43eaa0980 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 000000000000..290f4f8454d6 --- /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 000000000000..61ed615a2a5a --- /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 complaint 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 000000000000..8856dd6d8880 --- /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 + _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 000000000000..51ffc7f38106 --- /dev/null +++ b/tools/test/netfibs/initiator.sh @@ -0,0 +1,1516 @@ +#!/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 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. +# +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 + +################################################################################ +# +# 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 testering. +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 000000000000..3790617b1a49 --- /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 000000000000..27923517ad24 --- /dev/null +++ b/tools/test/netfibs/reflector.sh @@ -0,0 +1,1092 @@ +#!/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 +} + +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. +# +kldload ipfw > /dev/null 2>&1 || kldstat -v | grep -q ipfw +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 + +# 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