Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Feb 2012 04:26:25 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r231858 - in head/tools/test: . netfibs
Message-ID:  <201202170426.q1H4QP02049768@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Fri Feb 17 04:26:24 2012
New Revision: 231858
URL: http://svn.freebsd.org/changeset/base/231858

Log:
  Add regression tests scripts for multi-IP FIBs exercising the send,
  receive and forward path tagging packets with both the ifconfig fib
  option or using ipfw, running ICMP6, TCP/v6 and UDP/v6 tests and
  testing both setfib(2) as well as the SO_SETFIB socket option.
  
  At 16 FIBs a total of over 64k return codes/replies/stati are checked,
  sometimes multiple times (in different ways, e.g. the reflected request
  as well as ipfw counter values).
  
  The scripts need two or three machines to run and are thus not added
  to the tools/regression framework but only to tools/test.
  
  Sponsored by:	Cisco Systems, Inc.

Added:
  head/tools/test/netfibs/
  head/tools/test/netfibs/Makefile   (contents, props changed)
  head/tools/test/netfibs/README   (contents, props changed)
  head/tools/test/netfibs/forwarding.sh   (contents, props changed)
  head/tools/test/netfibs/initiator.sh   (contents, props changed)
  head/tools/test/netfibs/reflect.c   (contents, props changed)
  head/tools/test/netfibs/reflector.sh   (contents, props changed)
Modified:
  head/tools/test/README

Modified: head/tools/test/README
==============================================================================
--- head/tools/test/README	Fri Feb 17 03:46:38 2012	(r231857)
+++ head/tools/test/README	Fri Feb 17 04:26:24 2012	(r231858)
@@ -10,5 +10,6 @@ Please make a subdir per program, and ad
 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

Added: head/tools/test/netfibs/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/test/netfibs/Makefile	Fri Feb 17 04:26:24 2012	(r231858)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+PROG=	reflect
+NO_MAN=
+WARNS?=	6
+
+.include <bsd.prog.mk>

Added: head/tools/test/netfibs/README
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/test/netfibs/README	Fri Feb 17 04:26:24 2012	(r231858)
@@ -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

Added: head/tools/test/netfibs/forwarding.sh
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/tools/test/netfibs/forwarding.sh	Fri Feb 17 04:26:24 2012	(r231858)
@@ -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 <<EOI
+${_msg}
+EOI
+	print_debug "_keyword=${_keyword}"
+	print_debug "_fibs=${_fibs}"
+	case ${_keyword} in
+	${_case});;
+	*)	die "Got invalid keyword from ${_addr} in control message:" \
+		    "${_msg}"
+	;;
+	esac
+	if test ${_fibs} -ne ${RT_NUMFIBS}; then
+		die "Number of FIBs not matching ours (${RT_NUMFIBS}) in" \
+		    "control message from ${_addr}: ${_msg}"
+	fi
+
+	print_debug "Successfully exchanged control message with ${_addr}."
+}
+
+send_control_msgs()
+{
+	local _case _addr
+	_case="$1"
+	
+	# Always start with the far end.  Otherwise we will cut that off when
+	# cleanly taering down things again.
+	for _addr in ${RIGHTADDR} ${MIDDLELEFTADDR}; do
+		send_control_msg "${_case}" ${_addr}
+	done
+
+	# Allow us to flush ipfw counters etc before new packets will arrive.
+	sleep 1
+}
+
+# We are setup.  Wait for the initiator to tell us that it is ready.
+wait_remote_ready()
+{
+        local _case _msg _keyword _fibs
+	_case="$1"
+
+	# Wait for the remote to connect and start things.
+	# We tell it the magic keyword, and our number of FIBs.
+	_msg=`echo "${_case} ${RT_NUMFIBS}" | nc -6 -l ${CTRLPORT}`
+
+	read _keyword _fibs <<EOI
+${_msg}
+EOI
+	print_debug "_keyword=${_keyword}"
+	print_debug "_fibs=${_fibs}"
+	case ${_keyword} in
+	${_case});;
+	*)	die "Got invalid keyword in control message: ${_msg}"
+		;;
+	esac
+	if test ${_fibs} -ne ${RT_NUMFIBS}; then
+		die "Number of FIBs not matching ours (${RT_NUMFIBS}) in" \
+		    "control message: ${_msg}"
+	fi
+
+	print_debug "Successfully received control message."
+}
+
+################################################################################
+#
+# Test case helper functions.
+#
+# Please note that neither on the intiator nor the reflector are FIBs despite
+# a variable name might indicate.  If such a variable is used it mirrors FIB
+# numbers from the middle node to match for test cases.
+#
+test_icmp6()
+{
+	local _maxfibs _addr _n _testno i _rc _ec
+	_maxfibs=$1
+	_addr="$2"
+	_n="$3"
+
+	printf "1..%d\n" ${_maxfibs}
+	_testno=1
+	set +e
+	i=0
+	while test ${i} -lt ${_maxfibs}; do
+		_txt="${_n}_${i}"
+		print_debug "Testing ${_txt}"
+
+		# Generate HEX for ping6 payload.
+		_fibtxt=`echo "${_txt}" | hd -v | cut -b11-60 | tr -d ' \r\n'`
+
+		eval _rc="\${rc_${i}}"
+		ping6 -n -c1 -p ${_fibtxt} ${_addr} > /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 <<EOi
+`printf "${_line}" | tr ',' '\n'`
+EOi
+		
+	done <<EOo
+`printf "${_reply}" | grep -v "^$"`
+EOo
+
+	print_debug "ipfw count results processed"
+}
+
+################################################################################
+#
+# Test cases.
+#
+# In general we set the FIB on in, but count on out.
+#
+
+_fwd_default_fib_symmetric_results()
+{
+	local _n i _edge _type _rc
+	_n="$1"
+
+	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
+				0)	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_default_fib_symmetric_left()
+{
+	local _n
+	_n="$1"
+
+	send_control_msgs "START_${_n}"
+
+	# Setup expected return code
+	rc_0=0
+
+	# Initiate probes for ICMP6, TCP and UDP.
+	test_icmp6 1 ${RIGHTADDR} "${_n}_icmp6"
+	test_ulp 1 "${_n}" ${RIGHTADDR} ${CTRLPORT} 0
+
+	send_control_msgs "STOP_${_n}"
+	_fwd_default_fib_symmetric_results "${_n}"
+	fetch_ipfw_count "${_n}"
+}
+
+_fwd_default_fib_symmetric_middle()
+{
+	local _n
+	_n="$1"
+
+	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_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
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202170426.q1H4QP02049768>