[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree

zrouter-src-freebsd at zrouter.org zrouter-src-freebsd at zrouter.org
Fri Mar 2 15:38:40 UTC 2012


details:   http://zrouter.org/hg/FreeBSD/head//rev/22418adf039f
changeset: 371:22418adf039f
user:      ray at terran.dlink.ua
date:      Fri Mar 02 17:01:18 2012 +0200
description:
Update to FreeBSD-HEAD @232391

diffstat:

 head/tools/build/options/WITHOUT_SOURCELESS         |     2 +
 head/tools/build/options/WITHOUT_SOURCELESS_HOST    |     2 +
 head/tools/build/options/WITHOUT_SOURCELESS_UCODE   |     2 +
 head/tools/build/options/WITH_CLANG_EXTRAS          |     2 +
 head/tools/build/options/WITH_CLANG_IS_CC           |     8 +
 head/tools/regression/bin/sh/builtins/hash4.0       |     6 +
 head/tools/regression/lib/libc/gen/test-fmtmsg.c    |   251 ++
 head/tools/regression/sockets/so_setfib/Makefile    |    14 +
 head/tools/regression/sockets/so_setfib/so_setfib.c |   189 ++
 head/tools/regression/sockets/so_setfib/so_setfib.t |    59 +
 head/tools/regression/usb/usb_enum.t                |    30 +
 head/tools/test/hwpmc/pmctest.py                    |    94 +
 head/tools/test/netfibs/Makefile                    |     7 +
 head/tools/test/netfibs/README                      |    64 +
 head/tools/test/netfibs/forwarding.sh               |  1652 +++++++++++++++++++
 head/tools/test/netfibs/initiator.sh                |  1521 +++++++++++++++++
 head/tools/test/netfibs/reflect.c                   |   365 ++++
 head/tools/test/netfibs/reflector.sh                |  1098 ++++++++++++
 head/tools/test/ptrace/Makefile                     |     7 +
 head/tools/test/ptrace/scescx.c                     |   406 ++++
 head/tools/tools/fixwhite/Makefile                  |     7 +
 head/tools/tools/fixwhite/fixwhite.1                |    48 +
 head/tools/tools/fixwhite/fixwhite.c                |   180 ++
 23 files changed, 6014 insertions(+), 0 deletions(-)

diffs (6106 lines):

diff -r 77b2b05d6591 -r 22418adf039f head/tools/build/options/WITHOUT_SOURCELESS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/build/options/WITHOUT_SOURCELESS	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,2 @@
+.\" $FreeBSD: head/tools/build/options/WITHOUT_SOURCELESS 230972 2012-02-04 00:54:43Z rmh $
+Set to not build kernel modules that include sourceless code (either microcode or native code for host CPU).
diff -r 77b2b05d6591 -r 22418adf039f head/tools/build/options/WITHOUT_SOURCELESS_HOST
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/build/options/WITHOUT_SOURCELESS_HOST	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,2 @@
+.\" $FreeBSD: head/tools/build/options/WITHOUT_SOURCELESS_HOST 230972 2012-02-04 00:54:43Z rmh $
+Set to not build kernel modules that include sourceless native code for host CPU.
diff -r 77b2b05d6591 -r 22418adf039f head/tools/build/options/WITHOUT_SOURCELESS_UCODE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/build/options/WITHOUT_SOURCELESS_UCODE	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,2 @@
+.\" $FreeBSD: head/tools/build/options/WITHOUT_SOURCELESS_UCODE 230972 2012-02-04 00:54:43Z rmh $
+Set to not build kernel modules that include sourceless microcode.
diff -r 77b2b05d6591 -r 22418adf039f head/tools/build/options/WITH_CLANG_EXTRAS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/build/options/WITH_CLANG_EXTRAS	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,2 @@
+.\" $FreeBSD: head/tools/build/options/WITH_CLANG_EXTRAS 231057 2012-02-05 23:56:22Z dim $
+Set to build additional clang and llvm tools, such as bugpoint.
diff -r 77b2b05d6591 -r 22418adf039f head/tools/build/options/WITH_CLANG_IS_CC
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/build/options/WITH_CLANG_IS_CC	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,8 @@
+.\" $FreeBSD: head/tools/build/options/WITH_CLANG_IS_CC 232322 2012-02-29 22:58:51Z dim $
+Set to install the Clang C/C++ compiler as
+.Pa /usr/bin/cc
+,
+.Pa /usr/bin/c++
+and
+.Pa /usr/bin/cpp
+.
diff -r 77b2b05d6591 -r 22418adf039f head/tools/regression/bin/sh/builtins/hash4.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/regression/bin/sh/builtins/hash4.0	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,6 @@
+# $FreeBSD: head/tools/regression/bin/sh/builtins/hash4.0 231535 2012-02-11 21:06:45Z jilles $
+
+exec 3>&1
+m=`hash nosuchtool 2>&1 >&3`
+r=$?
+[ "$r" != 0 ] && [ -n "$m" ]
diff -r 77b2b05d6591 -r 22418adf039f head/tools/regression/lib/libc/gen/test-fmtmsg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/regression/lib/libc/gen/test-fmtmsg.c	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,251 @@
+/*-
+ * Copyright (c) 2012 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/tools/regression/lib/libc/gen/test-fmtmsg.c 231984 2012-02-21 23:46:41Z jilles $");
+
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fmtmsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static char *run_test(long classification, const char *label, int severity,
+    const char *text, const char *action, const char *tag);
+
+struct testcase {
+	long classification;
+	const char *label;
+	int severity;
+	const char *text;
+	const char *action;
+	const char *tag;
+	const char *msgverb;
+	const char *result;
+} testcases[] = {
+	{
+		MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		NULL,
+		"BSD:ls: ERROR: illegal option -- z\n"
+		    "TO FIX: refer to manual BSD:ls:001\n"
+	},
+	{
+		MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		"text:severity:action:tag",
+		"illegal option -- z: ERROR\n"
+		    "TO FIX: refer to manual BSD:ls:001\n"
+	},
+	{
+		MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		"text",
+		"illegal option -- z\n"
+	},
+	{
+		MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		"severity:text",
+		"ERROR: illegal option -- z\n"
+	},
+	{
+		MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		"ignore me",
+		"BSD:ls: ERROR: illegal option -- z\n"
+		    "TO FIX: refer to manual BSD:ls:001\n"
+	},
+	{
+		MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		"tag:severity:text:nothing:action",
+		"BSD:ls: ERROR: illegal option -- z\n"
+		    "TO FIX: refer to manual BSD:ls:001\n"
+	},
+	{
+		MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		"",
+		"BSD:ls: ERROR: illegal option -- z\n"
+		    "TO FIX: refer to manual BSD:ls:001\n"
+	},
+	{
+		MM_UTIL | MM_PRINT, MM_NULLLBL, MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		NULL,
+		"ERROR: illegal option -- z\n"
+		    "TO FIX: refer to manual BSD:ls:001\n"
+	},
+	{
+		MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
+		"illegal option -- z", MM_NULLACT, MM_NULLTAG,
+		NULL,
+		"BSD:ls: ERROR: illegal option -- z\n"
+	},
+	{
+		MM_UTIL | MM_NULLMC, "BSD:ls", MM_ERROR,
+		"illegal option -- z", "refer to manual", "BSD:ls:001",
+		NULL,
+		""
+	},
+	{
+		MM_APPL | MM_PRINT, "ABCDEFGHIJ:abcdefghijklmn", MM_INFO,
+		"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+		    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+		    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+		    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+		"refer to manual", "ABCDEFGHIJ:abcdefghijklmn:001",
+		NULL,
+		"ABCDEFGHIJ:abcdefghijklmn: INFO: "
+		    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+		    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+		    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+		    "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
+		    "TO FIX: refer to manual ABCDEFGHIJ:abcdefghijklmn:001\n"
+	},
+	{
+		MM_OPSYS | MM_PRINT, "TEST:test", MM_HALT,
+		"failed", "nothing can help me", "NOTHING",
+		NULL,
+		"TEST:test: HALT: failed\n"
+		    "TO FIX: nothing can help me NOTHING\n"
+	},
+	{
+		MM_OPSYS | MM_PRINT, "TEST:test", MM_WARNING,
+		"failed", "nothing can help me", "NOTHING",
+		NULL,
+		"TEST:test: WARNING: failed\n"
+		    "TO FIX: nothing can help me NOTHING\n"
+	},
+	{
+		MM_OPSYS | MM_PRINT, "TEST:test", MM_NOSEV,
+		"failed", "nothing can help me", "NOTHING",
+		NULL,
+		"TEST:test: failed\n"
+		    "TO FIX: nothing can help me NOTHING\n"
+	}
+};
+
+static char *
+run_test(long classification, const char *label, int severity,
+    const char *text, const char *action, const char *tag)
+{
+	int pip[2];
+	pid_t pid, wpid;
+	char *result, *p;
+	size_t resultsize;
+	ssize_t n;
+	int status;
+
+	if (pipe(pip) == -1)
+		err(2, "pipe");
+	pid = fork();
+	if (pid == -1)
+		err(2, "fork");
+	if (pid == 0) {
+		close(pip[0]);
+		if (pip[1] != STDERR_FILENO &&
+		    dup2(pip[1], STDERR_FILENO) == -1)
+			_exit(2);
+		if (fmtmsg(classification, label, severity, text, action, tag)
+		    != MM_OK)
+			_exit(1);
+		else
+			_exit(0);
+	}
+	close(pip[1]);
+	resultsize = 1024;
+	result = malloc(resultsize);
+	p = result;
+	while ((n = read(pip[0], p, result + resultsize - p - 1)) != 0) {
+		if (n == -1) {
+			if (errno == EINTR)
+				continue;
+			else
+				err(2, "read");
+		}
+		p += n;
+		if (result + resultsize == p - 1) {
+			resultsize *= 2;
+			result = realloc(result, resultsize);
+			if (result == NULL)
+				err(2, "realloc");
+		}
+	}
+	if (memchr(result, '\0', p - result) != NULL) {
+		free(result);
+		return (NULL);
+	}
+	*p = '\0';
+	close(pip[0]);
+	while ((wpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
+		;
+	if (wpid == -1)
+		err(2, "waitpid");
+	if (status != 0) {
+		free(result);
+		return (NULL);
+	}
+	return (result);
+}
+
+int
+main(void)
+{
+	size_t i, n;
+	int errors;
+	char *result;
+	struct testcase *t;
+
+	n = sizeof(testcases) / sizeof(testcases[0]);
+	errors = 0;
+	printf("1..%zu\n", n);
+	for (i = 0; i < n; i++) {
+		t = &testcases[i];
+		if (t->msgverb != NULL)
+			setenv("MSGVERB", t->msgverb, 1);
+		else
+			unsetenv("MSGVERB");
+		result = run_test(t->classification, t->label, t->severity,
+		    t->text, t->action, t->tag);
+		if (result != NULL && strcmp(result, t->result) == 0)
+			printf("ok %zu - correct\n",
+			    i + 1);
+		else {
+			printf("not ok %zu - %s\n",
+			    i + 1, result != NULL ? "incorrect" : "failed");
+			errors = 1;
+		}
+		free(result);
+	}
+
+	return (errors);
+}
diff -r 77b2b05d6591 -r 22418adf039f head/tools/regression/sockets/so_setfib/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/regression/sockets/so_setfib/Makefile	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,14 @@
+# $FreeBSD: head/tools/regression/sockets/so_setfib/Makefile 231855 2012-02-17 03:25:26Z bz $
+
+PROG=	so_setfib
+NO_MAN=
+WARNS?=	6
+
+.ifdef INET6
+CFLAGS+=	-DINET6
+.endif
+.ifdef INET
+CFLAGS+=	-DINET
+.endif
+
+.include <bsd.prog.mk>
diff -r 77b2b05d6591 -r 22418adf039f head/tools/regression/sockets/so_setfib/so_setfib.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/regression/sockets/so_setfib/so_setfib.c	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,189 @@
+/*-
+ * 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: head/tools/regression/sockets/so_setfib/so_setfib.c 231855 2012-02-17 03:25:26Z bz $
+ */
+
+/*
+ * Regression test on SO_SETFIB setsockopt(2).
+ * 
+ * Check that the expected domain(9) families all handle the socket option
+ * correctly and do proper bounds checks.
+ *
+ * Test plan:
+ * 1. Get system wide number of FIBs from sysctl and convert to index (-= 1).
+ * 2. For each protocol family (INET, INET6, ROUTE and LOCAL) open socketes of
+ *    type (STREAM, DGRAM and RAW) as supported.
+ * 3. Do a sequence of -2, -1, 0, .. n, n+1, n+2 SO_SETFIB sockopt calls,
+ *    expecting the first two and last two to fail (valid 0 ... n).
+ * 4. Try 3 random numbers.  Calculate result based on valid range.
+ * 5. Repeat for next domain family and type from (2) on.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static struct t_dom {
+	int		domain;
+	const char	*name;
+} t_dom[] = {
+#ifdef INET6
+	{ .domain = PF_INET6, .name = "PF_INET6" },
+#endif
+#ifdef INET
+	{ .domain = PF_INET, .name = "PF_INET" },
+#endif
+	{ .domain = PF_ROUTE, .name = "PF_ROUTE" },
+	{ .domain = PF_LOCAL, .name = "PF_LOCAL" },
+};
+
+static struct t_type {
+	int		type;
+	const char	*name;
+} t_type[] = {
+	{ .type = SOCK_STREAM, .name = "SOCK_STREAM" },
+	{ .type = SOCK_DGRAM, .name = "SOCK_DGRAM" },
+	{ .type = SOCK_RAW, .name = "SOCK_RAW" },
+};
+
+/*
+ * Number of FIBs as read from net.fibs sysctl - 1.  Initialize to clear out of
+ * bounds value to not accidentally run on a limited range. 
+ */
+static int rt_numfibs = -42;
+
+/* Number of test case. */
+static int testno = 1;
+
+
+/*
+ * Try the setsockopt with given FIB number i on socket s.
+ * Handle result given on error and valid range and errno.
+ */
+static void
+so_setfib(int s, int i, u_int dom, u_int type)
+{
+	int error;
+
+	error = setsockopt(s, SOL_SOCKET, SO_SETFIB, &i, sizeof(i));
+	/* For out of bounds we expect an error. */
+	if (error == -1 && (i < 0 || i > rt_numfibs))
+		printf("ok %d %s_%s_%d\n", testno, t_dom[dom].name,
+		    t_type[type].name, i);
+	else if (error != -1 && (i < 0 || i > rt_numfibs))
+		printf("not ok %d %s_%s_%d # setsockopt(%d, SOL_SOCKET, "
+		    "SO_SETFIB, %d, ..) unexpectedly succeeded\n", testno,
+		    t_dom[dom].name, t_type[type].name, i, s, i);
+	else if (error == 0)
+		printf("ok %d %s_%s_%d\n", testno, t_dom[dom].name,
+		    t_type[type].name, i);
+	else if (errno != EINVAL)
+		printf("not ok %d %s_%s_%d # setsockopt(%d, SOL_SOCKET, "
+		    "SO_SETFIB, %d, ..) unexpected error: %s\n", testno,
+		    t_dom[dom].name, t_type[type].name, i, s, i,
+		    strerror(errno));
+	else
+		printf("not ok %d %s_%s_%d\n", testno, t_dom[dom].name,
+		    t_type[type].name, i);
+
+	/* Test run done, next please. */
+	testno++;
+}
+
+/*
+ * Main test.  Open socket given domain family and type.  For each FIB, out of
+ * bounds FIB numbers and 3 random FIB numbers set the socket option.
+ */
+static void
+t(u_int dom, u_int type)
+{
+	int i, s;
+
+	/* PF_ROUTE only supports RAW socket types, while PF_LOCAL does not. */
+	if (t_dom[dom].domain == PF_ROUTE && t_type[type].type != SOCK_RAW)
+		return;
+	if (t_dom[dom].domain == PF_LOCAL && t_type[type].type == SOCK_RAW)
+		return;
+
+	/* Open socket for given combination. */
+	s = socket(t_dom[dom].domain, t_type[type].type, 0);
+	if (s == -1) {
+		printf("not ok %d %s_%s # socket(): %s\n", testno,
+		    t_dom[dom].name, t_type[type].name, strerror(errno));
+		return;
+	}
+	
+	/* Test FIBs -2, -1, 0, .. n, n + 1, n + 2. */
+	for (i = -2; i <= (rt_numfibs + 2); i++)
+		so_setfib(s, i, dom, type);
+
+	/* Test 3 random FIB numbers. */
+	for (i = 0; i < 3; i++)
+		so_setfib(s, (int)random(), dom, type);
+
+	/* Close socket. */
+	close(s);
+}
+
+/*
+ * Returns 0 if no program error, 1 on sysctlbyname error.
+ * Test results are communicated by printf("[not ]ok <n> ..").
+ */
+int
+main(int argc __unused, char *argv[] __unused)
+{
+	u_int i, j;
+	size_t s;
+
+	/* Initalize randomness. */
+	srandomdev();
+
+	/* Get number of FIBs supported by kernel. */
+	s = sizeof(rt_numfibs);
+	if (sysctlbyname("net.fibs", &rt_numfibs, &s, NULL, 0) == -1)
+		err(1, "sysctlbyname(net.fibs, ..)");
+	/* Adjust from number to index. */
+	rt_numfibs -= 1;
+
+	/* Run tests. */
+	for (i = 0; i < sizeof(t_dom) / sizeof(struct t_dom); i++)
+		for (j = 0; j < sizeof(t_type) / sizeof(struct t_type); j++)
+			t(i, j);
+
+	return (0);
+}
+
+/* end */
diff -r 77b2b05d6591 -r 22418adf039f head/tools/regression/sockets/so_setfib/so_setfib.t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/regression/sockets/so_setfib/so_setfib.t	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,59 @@
+#!/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: head/tools/regression/sockets/so_setfib/so_setfib.t 231855 2012-02-17 03:25:26Z bz $
+#
+
+cd `dirname $0`
+
+EXECUTABLE=`basename $0 .t`
+
+FIBS=`sysctl -n net.fibs`
+INET=`sysctl -n kern.features.inet`
+INET6=`sysctl -n kern.features.inet6`
+
+case "${INET}" in
+1)	OPTS="${OPTS} -DINET" ;;
+*)	INET=0 ;;
+esac
+case "${INET6}" in
+1)	OPTS="${OPTS} -DINET6" ;;
+*)	INET6=0 ;;
+esac
+
+make ${EXECUTABLE} ${OPTS} 2>&1 > /dev/null
+
+# two out of bounds on each side + 3 random
+FIBS=$((2 + FIBS + 2 + 3))
+# ROUTE and LOCAL are 1 domain together given 2 or 1 types only
+TESTS=$(((1 + ${INET} + ${INET6}) * 3 * ${FIBS}))
+
+echo "1..${TESTS}"
+
+exec ./${EXECUTABLE}
diff -r 77b2b05d6591 -r 22418adf039f head/tools/regression/usb/usb_enum.t
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/regression/usb/usb_enum.t	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,30 @@
+#!/bin/sh
+# $FreeBSD: head/tools/regression/usb/usb_enum.t 232364 2012-03-01 20:45:17Z hselasky $
+
+#
+# About:
+# This script implements a simple USB enumeration test
+#
+# Usage:
+# ./usb_enum.t ugenX.Y
+#
+
+echo "1..100"
+
+if [ "$1" = "" ]; then
+# First Root HUB
+DEV="ugen0.1"
+else
+# Custom device
+DEV="$1"
+fi
+
+for N in $(jot 100 1)
+do
+if [ -c /dev/$DEV ] && [ -r /dev/$DEV ] && usbconfig -d $DEV reset ; then
+echo "ok $N"
+else
+echo "not ok $N"
+fi
+done
+
diff -r 77b2b05d6591 -r 22418adf039f head/tools/test/hwpmc/pmctest.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/hwpmc/pmctest.py	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# Copyright (c) 2012, Neville-Neil Consulting
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 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.
+#
+# Neither the name of Neville-Neil Consulting nor the names of its 
+# contributors may be used to endorse or promote products derived from 
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
+# OWNER 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.
+#
+# Author: George V. Neville-Neil
+#
+# $FreeBSD: head/tools/test/hwpmc/pmctest.py 231699 2012-02-14 18:57:10Z gnn $
+
+# Description: A program to run a simple program against every available
+# pmc counter present in a system.
+#
+# To use:
+#
+# pmctest.py -p ls > /dev/null
+#
+# This should result in ls being run with every available counter
+# and the system should neither lock up nor panic.
+#
+# The default is to wait after each counter is tested.  Since the
+# prompt would go to stdout you won't see it, just press return
+# to continue or Ctrl-D to stop.
+
+import sys
+import subprocess
+from subprocess import PIPE
+
+# A list of strings that are not really counters, just
+# name tags that are output by pmccontrol -L
+notcounter = ["IAF", "IAP", "TSC", "UNC", "UCF", "UCP"]
+
+def main():
+
+    from optparse import OptionParser
+    
+    parser = OptionParser()
+    parser.add_option("-p", "--program", dest="program", 
+                      help="program to execute")
+    parser.add_option("-w", "--wait", action="store_true", dest="wait",
+                      default=True, help="wait after each execution")
+
+    (options, args) = parser.parse_args()
+
+    p = subprocess.Popen(["pmccontrol", "-L"], stdout=PIPE)
+    counters = p.communicate()[0]
+
+    if len(counters) <= 0:
+        print "no counters found"
+        sys.exit()
+
+    for counter in counters.split():
+        if counter in notcounter:
+            continue
+        p = subprocess.Popen(["pmcstat", "-p", counter, options.program],
+                             stdout=PIPE)
+        result = p.communicate()[0]
+        print result
+        if (options.wait == True):
+            try:
+                value = raw_input("next?")
+            except EOFError:
+                sys.exit()
+
+# The canonical way to make a python module into a script.
+# Remove if unnecessary.
+ 
+if __name__ == "__main__":
+    main()
diff -r 77b2b05d6591 -r 22418adf039f head/tools/test/netfibs/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/netfibs/Makefile	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,7 @@
+# $FreeBSD: head/tools/test/netfibs/Makefile 231858 2012-02-17 04:26:24Z bz $
+
+PROG=	reflect
+NO_MAN=
+WARNS?=	6
+
+.include <bsd.prog.mk>
diff -r 77b2b05d6591 -r 22418adf039f head/tools/test/netfibs/README
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/netfibs/README	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,64 @@
+# $FreeBSD: head/tools/test/netfibs/README 232114 2012-02-24 14:13:06Z bz $
+
+This directory holds scripts and a support program for multiple test cases
+exercising multi-IP FIBs.  At this time only IPv6 test cases are provided.
+
+Makefile
+reflect.c
+
+	Makefile just builds reflect, a program to echo data on a TCP or UDP
+	socket in very simplistic ways.  It has a couple of options to provide
+	an address or port, a FIB to bind to or a FIB to add to a reflected
+	message as well as some "magic" keyword handling to let the intiators
+	control it.
+
+initiator.sh and reflector.sh
+
+	intiator.sh runs two local test cases, one which shows a documented
+	limitation.
+
+	All further tests are either exercising the sending or receiving of
+	ICMP6, TCP or UDP packets with multiple FIBs.  initiator.sh and
+	reflector.sh must run on two different nodes both having a network
+	interface in the same broadcast domain (be it cross-over or on a
+	bridge/switch).  The tests will use the IPv6 benchmarking working
+	group (BMWG) prefix.  The prefix is hard coded into some tests.
+	Control messages will synchronize reflector with initiator.  The
+	reflector needs the reflect binary.  Apart from that the scripts
+	depend on ping6, netcat, awk, tr and ipfw.  The interface to use can
+	be set from the environment.  The commands can be run like:
+	
+	env IFACE=ifname sh intiator.sh
+	env IFACE=ifname sh reflector.sh
+	
+	Both scripts also support a DEBUG environment variable for additional
+	output.  A special value of 42 will enable sh(1) xtrace printing.
+
+	The output format is modeled after Test::Harness Perl as used in
+	tools/regression/ but not always compliant following the test case name.
+
+	NOTE: at the time of writing reflector.sh can trigger kernel races
+	unrelated to multi-FIB test leading to a panic(9).  "delay" calls
+	are used to mitigate the problem some but are not always good enough.
+	It is suggested to run one test case at a time manually disabling
+	the others in both scripts.
+
+forwarding.sh
+
+	forwarding.sh tests FIBs in the forwarding path, making sure that
+	packets tagged on input are leaving on the correct FIB.
+	The script must be run on three nodes with both edge nodes (left
+	and right) being connected to the middle node on separate interfaces.
+
+	The script operates on the same principles and requirements as the
+	two afore described ones.  Environment options equally apply, with
+	the middle node also taking an IFACEFAR variable to name the interface
+	to the right.   See the ASCII art at the beginning of the script for
+	details. The script needs to be told which node it is running with
+	the first argument:
+
+	env IFACE=ifname sh forwarding.sh left
+	env IFACE=leftifname IFACEFAR=rightifname sh forwarding.sh middle
+	env IFACE=ifname sh forwarding.sh right
+
+# end
diff -r 77b2b05d6591 -r 22418adf039f head/tools/test/netfibs/forwarding.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/netfibs/forwarding.sh	Fri Mar 02 17:01:18 2012 +0200
@@ -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: head/tools/test/netfibs/forwarding.sh 232114 2012-02-24 14:13:06Z bz $
+#
+
+# 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 base
+	_o="$2"
+
+	case ${DEBUG} in
+	''|0)	;;
+	*)	ipfw show ;;
+	esac
+
+	_rstr="RESULTS "
+	for base in 10000 20000; do
+		for _o in i t u; do
+			case ${base} in
+			10000)	_rstr="${_rstr}\nLEFT " ;;
+			20000)	_rstr="${_rstr}\nRIGHT " ;;
+			esac
+			case ${_o} in
+			i)	_rstr="${_rstr}ICMP6 " ;;
+			t)	_rstr="${_rstr}TCP " ;;
+			u)	_rstr="${_rstr}UDP " ;;
+			esac
+			i=0
+			while test ${i} -lt ${RT_NUMFIBS}; do
+
+				case "${_o}" in
+				i)	_c=`ipfw show $((${base} + i)) | \
+					    awk '/ ipv6-icmp / { print $2 }'` ;;
+				t)	_c=`ipfw show $((${base} + i)) | \
+					    awk '/ tcp / { print $2 }'` ;;
+				u)	_c=`ipfw show $((${base} + i)) | \
+					    awk '/ udp / { print $2 }'` ;;
+				esac
+				_rstr="${_rstr}${i} ${_c},"
+
+				i=$((i + 1))
+			done
+		done
+		i=0
+		while test ${i} -lt ${RT_NUMFIBS}; do
+			ipfw delete $((${base} + i)) > /dev/null 2>&1 || true
+			i=$((i + 1))
+		done
+	done
+
+	# We do not care about the request.
+	_req=`printf "${_rstr}" | nc -6 -l $((${CTRLPORT} - 1))`
+	print_debug "$? -- ${_req} -- ${_rstr}"
+}
+
+fetch_ipfw_count()
+{
+	local _n _reply _line _edge _type _fib _count _rc _ec _status
+	_n="$1"
+
+	# Leave node some time to build result set.
+	sleep 3
+
+	print_debug "Asking for ipfw count results..."
+	set +e
+	nc_send_recv 1 "RESULT REQUEST" "" ${MIDDLELEFTADDR} \
+	    $((${CTRLPORT} - 1)) ""
+	set -e
+	case "${_reply}" in
+	RESULTS\ *)	;;
+	*)		die "Got invalid reply from peer." \
+			    "Expected 'RESULTS ...', got '${_reply}'" ;;
+	esac
+
+	# Trim "RESULTS "
+	_reply=${_reply#* }
+
+	# FIBs * {left, right} * {icmp6, tcp, udp}
+	printf "1..%d\n" $((RT_NUMFIBS * 2 * 3))
+	testno=1
+	while read _line; do
+		print_debug "_line == ${_line}"
+		_edge=${_line%% *}
+		_line=${_line#* }
+		_type=${_line%% *}
+		_line=${_line#* }
+
+		while read _fib _count; do
+			eval _em="\${rc_${_n}_${_edge}_${_type}_${_fib}}"
+			: ${_em:=-42}
+			if test ${_count} -gt 0; then
+				_rc=1
+			else
+				_rc=0
+			fi
+			if test ${_rc} -eq ${_em}; then
+				_status="ok"
+			else
+				_status="not ok"
+			fi
+			printf "%s %d %s # count=%s _rc=%d _em=%d\n" \
+			    "${_status}" ${testno} "${_n}_${_edge}_${_type}_${_fib}" \
+			    ${_count} ${_rc} ${_em}
+			testno=$((testno + 1))
+		done <<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
+
+	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 -r 77b2b05d6591 -r 22418adf039f head/tools/test/netfibs/initiator.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/netfibs/initiator.sh	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,1521 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Cisco Systems, Inc.
+# All rights reserved.
+#
+# This software was developed by Bjoern Zeeb under contract to
+# Cisco Systems, Inc..
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD: head/tools/test/netfibs/initiator.sh 232114 2012-02-24 14:13:06Z bz $
+#
+
+# We will use the RFC5180 (and Errata) benchmarking working group prefix
+# 2001:0002::/48 for testing.
+PREFIX="2001:2:"
+
+# Set IFACE to the real interface you want to run the test on.
+: ${IFACE:=lo0}
+
+# Number of seconds to wait for peer node to synchronize for test.
+: ${WAITS:=120}
+
+# Control port we use to exchange messages between nodes to sync. tests, etc.
+: ${CTRLPORT:=6666}
+
+# Get the number of FIBs from the kernel.
+RT_NUMFIBS=`sysctl -n net.fibs`
+
+OURADDR="2001:2:ff00::1"
+PEERADDR="2001:2:ff00::2"
+PEERLINKLOCAL=""
+
+# By default all commands must succeed.  Individual tests may disable this
+# temporary.
+set -e
+
+# Debug magic.
+case "${DEBUG}" in
+42)	set -x ;;
+esac
+
+
+
+#
+# Helper functions.
+#
+check_rc()
+{
+	local _rc _exp _testno _testname _msg _r
+	_rc=$1
+	_exp=$2
+	_testno=$3
+	_testname="$4"
+	_msg="$5"
+
+	_r="not ok"
+	if test ${_rc} -eq ${_exp}; then
+		_r="ok"
+	fi
+	echo "${_r} ${_testno} ${_testname} # ${_msg} ${_rc} ${_exp}"
+}
+
+print_debug()
+{
+	local _msg
+	_msg="$*"
+
+	case ${DEBUG} in
+	''|0)	;;
+	*)	echo "DEBUG: ${_msg}" >&2 ;;
+	esac
+}
+
+die()
+{
+	local _msg
+	_msg="$*"
+
+	echo "ERROR: ${_msg}" >&2
+	exit 1
+}
+
+#
+# Test functions.
+#
+
+# Make sure the local link-local and global addresses are reachable
+# from all FIBs.
+check_local_addr()
+{
+	local _l i testno
+
+	print_debug "Setting up interface ${IFACE}"
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up
+	_l=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'`
+
+	# Let things settle.
+	print_debug "Waiting 4 seconds for things to settle"
+	sleep 4
+
+	printf "1..%d\n" `expr 2 \* ${RT_NUMFIBS}`
+	testno=1
+	i=0
+	set +e
+	while test ${i} -lt ${RT_NUMFIBS}; do
+		print_debug "Testing FIB ${i}"
+
+		setfib -F${i} ping6 -n -c1 ${_l} > /dev/null 2>&1
+		check_rc $? 0 ${testno} "check_local_addr_${i}_l" \
+		    "FIB ${i} ${_l}"
+		testno=$((testno + 1))
+
+		setfib -F${i} ping6 -n -c1 ${OURADDR} > /dev/null 2>&1
+		check_rc $? 0 ${testno} "check_local_addr_${i}_a" \
+		    "FIB ${i} ${OURADDR}"
+		testno=$((testno + 1))
+
+		i=$((i + 1))
+	done
+	set -e
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias
+}
+
+
+# Cloned tun(4) devices behave differently on FIB 0 vs. FIB 1..n after creation
+# (they also do in IPv4).
+check_local_tun()
+{
+	local _l i testno IFACE _msg
+
+	IFACE=tun42
+	print_debug "Setting up interface ${IFACE}"
+	ifconfig ${IFACE} create
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up
+	_l=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'`
+
+	# Let things settle.
+	print_debug "Waiting 4 seconds for things to settle"
+	sleep 4
+
+	printf "1..%d\n" `expr 2 \* ${RT_NUMFIBS}`
+	testno=1
+	_msg=""
+	i=0
+	set +e
+	while test ${i} -lt ${RT_NUMFIBS}; do
+		print_debug "Testing FIB ${i}"
+		if test ${i} -gt 0; then
+			# Flag the well known behaviour as such.
+			_msg="TODO "
+		fi
+
+		setfib -F${i} ping6 -n -c1 ${_l} > /dev/null 2>&1
+		check_rc $? 0 ${testno} "check_local_addr_${i}_l" \
+		    "${_msg}FIB ${i} ${_l}"
+		testno=$((testno + 1))
+
+		setfib -F${i} ping6 -n -c1 ${OURADDR} > /dev/null 2>&1
+		check_rc $? 0 ${testno} "check_local_addr_${i}_a" \
+		    "${_msg}FIB ${i} ${OURADDR}"
+		testno=$((testno + 1))
+
+		i=$((i + 1))
+	done
+	set -e
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias
+	ifconfig ${IFACE} destroy
+}
+
+check_remote_up()
+{
+	local _l i testno
+
+	print_debug "Setting up interface ${IFACE}"
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up
+	_l=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'`
+
+	# Let things settle.
+	print_debug "Waiting 4 seconds for things to settle"
+	sleep 4
+
+
+
+}
+
+send_greeting()
+{
+        local _l _greeting _keyword _fib _fibs _linklocal
+
+	print_debug "Setting up interface ${IFACE}"
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up
+	_l=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'`
+
+	# Let things settle.
+	print_debug "Waiting 4 seconds for things to settle"
+	sleep 4
+
+	# Cleanup firewall and install rules to always allow NS/NA to succeed.
+	# The latter is needed to allow indvidiual less specific later rules
+	# from test cases to just disallow any IPv6 traffic on a matching FIB.
+	ipfw -f flush > /dev/null 2>&1
+	ipfw add 65000 permit ip from any to any > /dev/null 2>&1
+	ipfw add 5 permit ipv6-icmp from any to any icmp6types 135,136 fib 0 \
+	    via ${IFACE} out > /dev/null 2>&1
+
+	set +e
+	i=0
+	rc=-1
+	while test ${i} -lt ${WAITS} -a ${rc} -ne 0; do
+		print_debug "Sending greeting #${i} to peer"
+		_greeting=`echo "SETUP ${RT_NUMFIBS} ${_l}" | \
+		    nc -6 -w 1 ${PEERADDR} ${CTRLPORT}`
+		rc=$?
+		i=$((i + 1))
+		# Might sleep longer in total but better than to DoS
+		# and not get anywhere.
+		sleep 1
+	done
+	set -e
+
+	read _keyword _fibs _linklocal <<EOI
+${_greeting}
+EOI
+	print_debug "_keyword=${_keyword}"
+	print_debug "_fibs=${_fibs}"
+	print_debug "_linklocal=${_linklocal}"
+	case ${_keyword} in
+	SETUP)	;;
+	*)	die "Got invalid keyword in greeting: ${_greeting}"
+	;;
+	esac
+	if test ${_fibs} -ne ${RT_NUMFIBS}; then
+		die "Number of FIBs not matching ours (${RT_NUMFIBS}) in" \
+		    "greeting: ${_greeting}"
+	fi
+	PEERLINKLOCAL=${_linklocal}
+
+	# Swap the zoneid to the local interface scope.
+	PEERLINKLOCAL=${PEERLINKLOCAL%%\%*}"%${IFACE}"
+
+	print_debug "Successfully exchanged greeting. Peer at ${PEERLINKLOCAL}"
+}
+
+cleanup()
+{
+
+	# Cleanup ipfw.
+	ipfw delete 5 > /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 <<EOI
+`echo "${_r}" | tr ',' '\n'`
+EOI
+
+}
+
+testrx_tcp_udp()
+{
+	local _n _o _f testno i _fibtxt _instances _res _port _transfer _p
+	_n="$1"
+	_o="$2"
+	_f="$3"
+	_instances=$4
+	_transfer=$5
+
+	# Unused so far.
+	: ${_instances:=1}
+
+	printf "1..%d\n" `expr 2 \* ${RT_NUMFIBS}`
+	testno=1
+	i=0
+	while test ${i} -lt ${RT_NUMFIBS}; do
+		print_debug "Testing ${_f} ${i}"
+
+		# We are expecting the FIB number (only) to be returned.
+		eval _rc="\${rc_${i}_l}"
+		_fibtxt="${_n}_${i}_l ${_f} ${i} ${PEERLINKLOCAL}"
+		if test ${_instances} -gt 1; then
+			_res="FIB ${i}"
+			_port=$((CTRLPORT + 1000 + i))
+		else
+			_res="${_fibtxt}"
+			_port=${CTRLPORT}
+		fi
+		nc_send_recv ${i} 1 "${_fibtxt}" "${_res}" ${PEERLINKLOCAL} \
+		    ${_port} "-6 ${_o} -w1"
+		check_rc $? ${_rc} ${testno} "${_fibtxt}" "${_reply}"
+		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}"
+		_fibtxt="${_n}_${i}_a ${_f} ${i} ${PEERADDR}"
+		if test ${_instances} -gt 1; then
+			_res="FIB ${i}"
+			_port=$((CTRLPORT + 1000 + i))
+		else
+			_res="${_fibtxt}"
+			_port=${CTRLPORT}
+		fi
+		nc_send_recv ${i} 1 "${_fibtxt}" "${_res}" ${PEERADDR} \
+		    ${_port} "-6 ${_o} -w1"
+		check_rc $? ${_rc} ${testno} "${_fibtxt}" "${_reply}"
+		testno=$((testno + 1))
+
+		# Restore PEERADDR.
+		PEERADDR="${_p}"
+
+		i=$((i + 1))
+	done
+}
+
+
+testrx_setup_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 || true
+		ifconfig ${IFACE} inet6 2001:2:${i}::1/64 alias
+		i=$((i + 1))
+	done
+}
+
+testrx_cleanup_transfer_networks()
+{
+	local i
+
+	i=0
+	while test ${i} -lt ${RT_NUMFIBS}; do
+		ifconfig ${IFACE} inet6 2001:2:${i}::1/64 -alias \
+		    > /dev/null 2>&1
+		i=$((i + 1))
+	done
+}
+
+
+testrx_run_test()
+{
+	local _n _t _fib _o _txt _msg i _reply _instances _destructive _transfer
+	_n="$1"
+	_t="$2"
+	_fib=$3
+	_o="$4"
+	_instances=$5
+	_detsructive=$6
+	_transfer=$7
+
+	# Netcat options (for UDP basically).
+	case "${_o}" in
+	-i)	_opts="" ;;		# Use TCP for START/DONE.
+	*)	_opts="${_o}" ;;
+	esac
+
+	# Combined test case base name.
+	case ${USE_SOSETFIB} in
+	0)	_f="setfib" ;;
+	1)	_f="so_setfib" ;;
+	*)	die "Unexpected value for SO_SETFIB: ${SO_SETFIB}" ;;
+	esac
+	_txt="${_n}_${_f}_${_t}_${_fib}_${_instances}_${_detsructive}_${_transfer}"
+
+	print_debug "Starting test '${_txt}' (for ${_instances} instances)."
+
+	case ${_transfer} in
+	1)	testrx_setup_transfer_networks ;;
+	esac
+
+	# Let the other side a chance to get ready as well.
+	sleep 1
+
+	set +e
+	# Let peer know that we are about to start.
+	_msg="START ${_txt}"
+	nc_send_recv ${_fib} ${WAITS} "${_msg}" "${_msg}" ${PEERADDR} \
+	    ${CTRLPORT} "-6 ${_opts} -w1"
+	case $? in
+	0)	;;
+	*)	die "Got invalid reply from peer." \
+		    "Expected '${_msg}', got '${_reply}'" ;;
+	esac
+
+	# Let the other side a chance to get ready as well.
+	sleep 1
+
+	# Send probe.
+	case "${_o}" in
+	-i)	testtx_icmp6 "${_txt}_" ${_transfer} ;;
+	*)	testrx_tcp_udp "${_txt}" "${_o}" "${_fib}" ${_instances} \
+		    ${_transfer} ;;
+	esac
+
+	# Let peer know that we are done with this test to move to next.
+	# This must immediately succeed.
+	_msg="DONE ${_txt}"
+	nc_send_recv ${_fib} ${WAITS} "${_msg}" "${_msg}" ${PEERADDR} \
+	    ${CTRLPORT} "-6 ${_opts} -w1"
+	case $? in
+	0)	;;
+	*)	die "Got invalid reply from peer." \
+		    "Expected '${_msg}', got '${_reply}'" ;;
+	esac
+
+	# Collect and validate the results.   Always use TCP.
+	sleep 1
+	set +e
+	nc_send_recv ${_fib} 1 "RESULT REQUEST" "" ${PEERADDR} \
+	    ${CTRLPORT} "-6 -w1"
+	case "${_reply}" in
+	RESULT\ *) testrx_results ${_fib} "${_txt}_" "${_reply}" ${_instances} \
+			${_transfer} "${_o}"
+		;;
+	*)	die "Got invalid reply from peer." \
+		    "Expected 'RESULT ...', got '${_reply}'" ;;
+	esac
+	set -e
+
+	case ${_transfer} in
+	1)	testrx_cleanup_transfer_networks ;;
+	esac
+
+	print_debug "Successfully received status update '${_reply}'."
+}
+
+testrx_main_setup_rc()
+{
+	local _n _t _fib _o _instances _destructive _transfer i
+	_n="$1"
+	_t="$2"
+	_fib=$3
+	_o="$4"
+	_instances=$5
+	_destructive=$6
+	_transfer=$7
+
+	# Setup expected return values.
+	if test ${_destructive} -eq 0; then
+		i=0
+		while test ${i} -lt ${RT_NUMFIBS}; do
+			eval rc_${i}_l=0
+			eval rc_${i}_a=0
+			i=$((i + 1))
+		done
+	else
+		i=0
+		while test ${i} -lt ${RT_NUMFIBS}; do
+			eval rc_${i}_l=0
+			case ${i} in
+			${_fib})	eval rc_${i}_a=0 ;;
+			*)	# ICMP6 cannot be distinguished and will
+				# always work in single transfer network.
+				case "${_o}" in
+				-i)	case ${_transfer} in
+					0) eval rc_${i}_a=0 ;;
+					1) eval rc_${i}_a=1 ;;
+					esac
+					;;
+				*)	if test ${_instances} -eq 1 -a \
+					    ${_transfer} -eq 0; then
+						eval rc_${i}_a=0
+					else
+						eval rc_${i}_a=1
+					fi
+					;;
+				esac
+				;;
+			esac
+			i=$((i + 1))
+		done
+	fi
+
+	print_debug "${_n}_${t}_${_fib} ${_instances} ${_destructive}" \
+	    "${_transfer}"
+	testrx_run_test "${_n}" "${t}" ${_fib} "${_o}" ${_instances} \
+	    ${_destructive} ${_transfer}
+}
+
+testrx_main()
+{
+	local _n _o s t fib _instances _destructive _transfer
+	_n="$1"
+	_o="$2"
+	_instances=$3
+
+	: ${_instances:=1}
+
+	print_debug "${_n}"
+	for _transfer in 1 0; do
+		for _destructive in 0 1; do
+			for t in ipfw ifconfig; do
+
+				print_debug "${_n}_${t}"
+				fib=0
+				while test ${fib} -lt ${RT_NUMFIBS}; do
+
+					testrx_main_setup_rc "${_n}" "${t}" \
+					    ${fib} "${_o}" ${_instances} \
+					    ${_destructive} ${_transfer}
+
+					fib=$((fib + 1))
+				done
+			done
+		done
+	done
+}
+
+################################################################################
+#
+#
+#
+
+testrx_icmp6_same_addr_one_fib_a_time()
+{
+
+	testrx_main \
+	    "testrx_icmp6_same_addr_one_fib_a_time" "-i"
+}
+
+testrx_tcp6_same_addr_one_fib_a_time()
+{
+
+	testrx_main \
+	    "testrx_tcp6_same_addr_one_fib_a_time" ""
+}
+
+
+testrx_udp6_same_addr_one_fib_a_time()
+{
+
+	testrx_main \
+	    "testrx_udp6_same_addr_one_fib_a_time" "-u"
+}
+
+
+################################################################################
+
+testrx_tcp6_same_addr_all_fibs_a_time()
+{
+
+	testrx_main \
+	    "testrx_tcp6_same_addr_all_fibs_a_time" "" ${RT_NUMFIBS}
+}
+
+testrx_udp6_same_addr_all_fibs_a_time()
+{
+
+	testrx_main \
+	    "testrx_udp6_same_addr_all_fibs_a_time" "-u" ${RT_NUMFIBS}
+}
+
+
+################################################################################
+#
+# Prereqs.
+#
+if test `sysctl -n security.jail.jailed` -eq 0; then
+	kldload ipfw > /dev/null 2>&1 || kldstat -v | grep -q ipfw 
+
+	# Reduce the time we wait in case of no reply to 2s.
+	sysctl net.inet.tcp.keepinit=2000 > /dev/null 2>&1
+fi
+ipfw -f flush > /dev/null 2>&1 || die "please load ipfw in base system"
+ipfw add 65000 permit ip from any to any > /dev/null 2>&1
+
+################################################################################
+#
+# Run tests.
+#
+
+# 64 cases at 16 FIBs.
+check_local_addr
+check_local_tun
+
+send_greeting
+
+# Initiator testing.
+for uso in 0 1; do
+
+	USE_SOSETFIB=${uso}
+
+	# Only run ICMP6 tests for the first loop.
+	# 160 cases at 16 FIBs.
+	test ${uso} -ne 0 || testtx_icmp6_connected && sleep 1
+	testtx_tcp6_connected && sleep 1
+	testtx_udp6_connected && sleep 1
+
+	# 2560 cases at 16 FIBs.
+	test ${uso} -ne 0 || testtx_icmp6_connected_blackhole && sleep 1
+	testtx_tcp6_connected_blackhole && sleep 1
+	testtx_udp6_connected_blackhole && sleep 1
+
+	# 2560 cases at 16 FIBs.
+	test ${uso} -ne 0 || testtx_icmp6_connected_transfernets && sleep 1
+	testtx_tcp6_connected_transfernets && sleep 1
+	testtx_udp6_connected_transfernets && sleep 1
+
+	# 2560 cases at 16 FIBs.
+	test ${uso} -ne 0 || \
+	    testtx_icmp6_connected_ifconfig_transfernets && sleep 1
+	testtx_tcp6_connected_ifconfig_transfernets && sleep 1
+	testtx_udp6_connected_ifconfig_transfernets && sleep 1
+
+	# 160 cases at 16 FIBs.
+	test ${uso} -ne 0 || testtx_icmp6_gateway && sleep 1
+	testtx_tcp6_gateway && sleep 1
+	testtx_udp6_gateway && sleep 1
+
+	# 160 cases at 16 FIBs.
+	test ${uso} -ne 0 || testtx_icmp6_transfernets_gateways && sleep 1
+	testtx_tcp6_transfernets_gateways && sleep 1
+	testtx_udp6_transfernets_gateways && sleep 1
+
+	# 2560 cases at 16 FIBs.
+	test ${uso} -ne 0 || testtx_icmp6_transfernets_gateway && sleep 1
+	testtx_tcp6_transfernets_gateway && sleep 1
+	testtx_udp6_transfernets_gateway && sleep 1
+done
+
+# Receiver testing.
+for uso in 0 1; do
+
+	USE_SOSETFIB=${uso}
+
+	# Only expect ICMP6 tests for the first loop.
+	# 6144 cases at 16 FIBs.
+	test ${uso} -ne 0 || testrx_icmp6_same_addr_one_fib_a_time && sleep 1
+	# 12288 cases at 16 FIBs.
+	testrx_tcp6_same_addr_one_fib_a_time && sleep 1
+	# 12288 cases at 16 FIBs.
+	testrx_udp6_same_addr_one_fib_a_time && sleep 1
+
+	# 12288 cases at 16 FIBs.
+	testrx_tcp6_same_addr_all_fibs_a_time && sleep 1
+	# 12288 cases at 16 FIBs.
+	testrx_udp6_same_addr_all_fibs_a_time && sleep 1
+
+done
+
+cleanup
+
+# end
diff -r 77b2b05d6591 -r 22418adf039f head/tools/test/netfibs/reflect.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/netfibs/reflect.c	Fri Mar 02 17:01:18 2012 +0200
@@ -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: head/tools/test/netfibs/reflect.c 231858 2012-02-17 04:26:24Z bz $
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+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 <testcase> not given");
+	if (afname == NULL)
+		errx(EX_USAGE, "Mandatory option -T <afname> 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 -r 77b2b05d6591 -r 22418adf039f head/tools/test/netfibs/reflector.sh
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/netfibs/reflector.sh	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,1098 @@
+#!/bin/sh
+#-
+# Copyright (c) 2012 Cisco Systems, Inc.
+# All rights reserved.
+#
+# This software was developed by Bjoern Zeeb under contract to
+# Cisco Systems, Inc..
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD: head/tools/test/netfibs/reflector.sh 232114 2012-02-24 14:13:06Z bz $
+#
+
+# We will use the RFC5180 (and Errata) benchmarking working group prefix
+# 2001:0002::/48 for testing.
+PREFIX="2001:2:"
+
+# Set IFACE to the real interface you want to run the test on.
+: ${IFACE:=lo0}
+
+# Control port we use to exchange messages between nodes to sync. tests, etc.
+: ${CTRLPORT:=6666}
+
+# Get the number of FIBs from the kernel.
+RT_NUMFIBS=`sysctl -n net.fibs`
+
+PEERADDR="2001:2:ff00::1"
+OURADDR="2001:2:ff00::2"
+
+OURLINKLOCAL=""
+PEERLINKLOCAL=""
+
+# By default all commands must succeed.  Individual tests may disable this
+# temporary.
+set -e
+
+# Debug magic.
+case "${DEBUG}" in
+42)	set -x ;;
+esac
+
+
+
+#
+# Helper functions.
+#
+
+# Function to avoid prelist races adding and deleting prefixes too quickly.
+delay()
+{
+
+	# sleep 1 is too long.
+	touch /tmp/foo || true
+	stat /tmp/foo > /dev/null 2>&1 || true
+}
+
+check_rc()
+{
+	local _rc _exp _testno _testname _msg _r
+	_rc=$1
+	_exp=$2
+	_testno=$3
+	_testname="$4"
+	_msg="$5"
+
+	_r="not ok"
+	if test ${_rc} -eq ${_exp}; then
+		_r="ok"
+	fi
+	echo "${_r} ${_testno} ${_testname} # ${_msg} ${_rc}"
+}
+
+print_debug()
+{
+	local _msg
+	_msg="$*"
+
+	case ${DEBUG} in
+	''|0)	;;
+	*)	echo "DEBUG: ${_msg}" >&2 ;;
+	esac
+}
+
+die()
+{
+	local _msg
+	_msg="$*"
+
+	echo "ERROR: ${_msg}" >&2
+	exit 1
+}
+
+#
+# Test functions.
+#
+
+# Setup our side and wait for the peer to tell us that it is ready.
+wait_remote_ready()
+{
+	local _greeting _keyword _fibs _linklocal i
+
+	print_debug "Setting up interface ${IFACE}"
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias > /dev/null 2>&1 || true
+	delay
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up
+	i=0
+	while test ${i} -lt ${RT_NUMFIBS}; do
+		ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias \
+		    > /dev/null 2>&1 || true
+		delay
+		i=$((i + 1))
+	done
+	OURLINKLOCAL=`ifconfig ${IFACE} | awk '/inet6 fe80:/ { print $2 }'`
+
+	# Let things settle.
+	print_debug "Waiting 4 seconds for things to settle"
+	sleep 4
+
+	# Wait for the remote to connect and start things.
+	# We tell it the magic keyword, our number of FIBs and our link-local.
+	# It already knows our global address.
+	_greeting=`echo "SETUP ${RT_NUMFIBS} ${OURLINKLOCAL}" | \
+	    nc -6 -l ${CTRLPORT}`
+
+	read _keyword _fibs _linklocal <<EOI
+${_greeting}
+EOI
+	print_debug "_keyword=${_keyword}"
+	print_debug "_fibs=${_fibs}"
+	print_debug "_linklocal=${_linklocal}"
+	case ${_keyword} in
+	SETUP)	;;
+	*)	die "Got invalid keyword in greeting: ${_greeting}"
+		;;
+	esac
+	if test ${_fibs} -ne ${RT_NUMFIBS}; then
+		die "Number of FIBs not matching ours (${RT_NUMFIBS}) in" \
+		    "greeting: ${_greeting}"
+	fi
+	PEERLINKLOCAL=${_linklocal}
+
+	print_debug "Successfully received greeting. Peer at ${PEERLINKLOCAL}"
+}
+
+cleanup()
+{
+
+	print_debug "Removing address from interface ${IFACE}"
+	ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias
+	delay
+}
+
+################################################################################
+#
+testtx_icmp6_connected()
+{
+	local _opts
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+	print_debug "./reflect -p ${CTRLPORT} -T TCP6 " \
+	    "-t testtx_icmp6_connected ${_opts}"
+	./reflect -p ${CTRLPORT} -T TCP6 -t testtx_icmp6_connected ${_opts}
+	print_debug "reflect terminated without error."
+}
+
+testtx_tcp6_connected()
+{
+	local _opts
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+	print_debug "./reflect -p ${CTRLPORT} -T TCP6 " \
+	    "-t testtx_tcp6_connected ${_opts}"
+	./reflect -p ${CTRLPORT} -T TCP6 -t testtx_tcp6_connected ${_opts}
+	print_debug "reflect terminated without error."
+}
+
+testtx_udp6_connected()
+{
+	local _opts
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+	print_debug "./reflect -p ${CTRLPORT} -T UDP6 " \
+	    "-t testtx_udp6_connected ${_opts}"
+	./reflect -p ${CTRLPORT} -T UDP6 -t testtx_udp6_connected ${_opts}
+	print_debug "reflect terminated without error."
+}
+
+################################################################################
+#
+testtx_icmp6_connected_blackhole()
+{
+	local _opts fib
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		print_debug "./reflect -p ${CTRLPORT} -T TCP6 " \
+		    "-t testtx_icmp6_connected_blackhole${fib} ${_opts}"
+		./reflect -p ${CTRLPORT} -T TCP6 \
+		    -t testtx_icmp6_connected_blackhole${fib} ${_opts}
+		print_debug "reflect terminated without error."
+		fib=$((fib + 1))
+	done
+}
+
+testtx_tcp6_connected_blackhole()
+{
+	local _opts fib
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		print_debug "./reflect -p ${CTRLPORT} -T TCP6 " \
+		    "-t testtx_tcp6_connected_blackhole${fib} ${_opts}"
+		./reflect -p ${CTRLPORT} -T TCP6 \
+		    -t testtx_tcp6_connected_blackhole${fib} ${_opts}
+		print_debug "reflect terminated without error."
+		fib=$((fib + 1))
+	done
+}
+
+testtx_udp6_connected_blackhole()
+{
+	local _opts fib
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		print_debug "./reflect -p ${CTRLPORT} -T UDP6 " \
+		    "-t testtx_udp6_connected_blackhole${fib} ${_opts}"
+		./reflect -p ${CTRLPORT} -T UDP6 \
+		    -t testtx_udp6_connected_blackhole${fib} ${_opts}
+		print_debug "reflect terminated without error."
+		fib=$((fib + 1))
+	done
+}
+
+################################################################################
+#
+testtx_ulp6_connected_transfernets()
+{
+	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
+
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		print_debug "./reflect -p ${CTRLPORT} -T ${_o} -t ${_n}${fib} ${_opts}"
+		./reflect -p ${CTRLPORT} -T ${_o} -t ${_n}${fib} ${_opts}
+		print_debug "reflect terminated without error."
+		fib=$((fib + 1))
+	done
+
+	# Cleanup transfer networks.
+	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
+}
+
+testtx_icmp6_connected_transfernets()
+{
+
+	testtx_ulp6_connected_transfernets \
+	    "testtx_icmp6_connected_transfernets" "TCP6"
+}
+
+testtx_tcp6_connected_transfernets()
+{
+
+	testtx_ulp6_connected_transfernets \
+	    "testtx_tcp6_connected_transfernets" "TCP6"
+}
+
+testtx_udp6_connected_transfernets()
+{
+
+	testtx_ulp6_connected_transfernets \
+	    "testtx_udp6_connected_transfernets" "UDP6"
+}
+
+testtx_icmp6_connected_ifconfig_transfernets()
+{
+
+	testtx_ulp6_connected_transfernets \
+	    "testtx_icmp6_connected_ifconfig_transfernets" "TCP6"
+}
+
+testtx_tcp6_connected_ifconfig_transfernets()
+{
+
+	testtx_ulp6_connected_transfernets \
+	    "testtx_tcp6_connected_ifconfig_transfernets" "TCP6"
+}
+
+testtx_udp6_connected_ifconfig_transfernets()
+{
+
+	testtx_ulp6_connected_transfernets \
+	    "testtx_udp6_connected_ifconfig_transfernets" "UDP6"
+}
+
+################################################################################
+#
+testtx_ulp6_gateway()
+{
+	local _opts _n _o
+	_n="$1"
+	_o="$2"
+
+	ifconfig lo0 inet6 2001:2:ff01::2 -alias > /dev/null 2>&1 || true
+	delay
+	ifconfig lo0 inet6 2001:2:ff01::2 alias
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+
+	print_debug "./reflect -p ${CTRLPORT} -T ${_o} " \
+	    "-t ${_n} ${_opts} -A 2001:2:ff01::2"
+	./reflect -p ${CTRLPORT} -T ${_o} \
+	    -t ${_n} ${_opts} -A 2001:2:ff01::2
+	print_debug "reflect terminated without error."
+
+	ifconfig lo0 inet6 2001:2:ff01::2 -alias
+	delay
+}
+
+testtx_icmp6_gateway()
+{
+
+	testtx_ulp6_gateway "testtx_icmp6_gateway" "TCP6"
+}
+
+testtx_tcp6_gateway()
+{
+
+	testtx_ulp6_gateway "testtx_tcp6_gateway" "TCP6"
+}
+
+testtx_udp6_gateway()
+{
+
+	testtx_ulp6_gateway "testtx_udp6_gateway" "UDP6"
+}
+
+################################################################################
+#
+testtx_ulp6_transfernets_gateways()
+{
+	local _opts fib _n _o
+	_n="$1"
+	_o="$2"
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+
+	# Setup transfer networks.
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		setfib -F${fib} \
+		    ifconfig ${IFACE} inet6 2001:2:${fib}::2/64 alias
+		fib=$((fib + 1))
+	done
+
+	# Setup out listener IP.
+	ifconfig lo0 inet6 2001:2:ff01::2 -alias > /dev/null 2>&1 || true
+	delay
+	ifconfig lo0 inet6 2001:2:ff01::2 alias
+
+	# Reflect requests.
+	print_debug "./reflect -p ${CTRLPORT} -T ${_o} " \
+	    "-t ${_n} ${_opts} -A 2001:2:ff01::2"
+	./reflect -p ${CTRLPORT} -T ${_o} \
+	    -t ${_n} ${_opts} -A 2001:2:ff01::2
+	print_debug "reflect terminated without error."
+
+	# Cleanup transfer networks and listener IP.
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		setfib -F${fib} \
+		    ifconfig ${IFACE} inet6 2001:2:${fib}::2/64 -alias
+		delay
+		fib=$((fib + 1))
+	done
+	ifconfig lo0 inet6 2001:2:ff01::2 -alias
+}
+
+testtx_icmp6_transfernets_gateways()
+{
+
+	testtx_ulp6_transfernets_gateways \
+	    "testtx_icmp6_transfernets_gateways" "TCP6"
+}
+
+testtx_tcp6_transfernets_gateways()
+{
+
+	testtx_ulp6_transfernets_gateways \
+	    "testtx_tcp6_transfernets_gateways" "TCP6"
+}
+
+testtx_udp6_transfernets_gateways()
+{
+
+	testtx_ulp6_transfernets_gateways \
+	    "testtx_udp6_transfernets_gateways" "UDP6"
+}
+
+
+################################################################################
+#
+testtx_ulp6_transfernets_gateway()
+{
+	local _opts fib _n _o
+	_n="$1"
+	_o="$2"
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+
+	# Setup transfer networks.
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		setfib -F${fib} \
+		    ifconfig ${IFACE} inet6 2001:2:${fib}::2/64 alias
+		fib=$((fib + 1))
+	done
+
+	# Setup out listener IP.
+	ifconfig lo0 inet6 2001:2:ff01::2 -alias > /dev/null 2>&1 || true
+	delay
+	ifconfig lo0 inet6 2001:2:ff01::2 alias
+
+	# Reflect requests.
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		print_debug "./reflect -p ${CTRLPORT} -T ${_o} " \
+		    "-t ${_n}${fib} ${_opts} -A 2001:2:ff01::2"
+		./reflect -p ${CTRLPORT} -T ${_o} \
+		    -t ${_n}${fib} ${_opts} -A 2001:2:ff01::2
+		print_debug "reflect terminated without error."
+		fib=$((fib + 1))
+	done
+
+	# Cleanup transfer networks and listener IP.
+	fib=0
+	while test ${fib} -lt ${RT_NUMFIBS}; do
+		setfib -F${fib} \
+		    ifconfig ${IFACE} inet6 2001:2:${fib}::2/64 -alias
+		delay
+		fib=$((fib + 1))
+	done
+	ifconfig lo0 inet6 2001:2:ff01::2 -alias
+}
+
+testtx_icmp6_transfernets_gateway()
+{
+
+	testtx_ulp6_transfernets_gateway \
+	    "testtx_icmp6_transfernets_gateway" "TCP6"
+}
+
+testtx_tcp6_transfernets_gateway()
+{
+
+	testtx_ulp6_transfernets_gateway \
+	    "testtx_tcp6_transfernets_gateway" "TCP6"
+}
+
+testtx_udp6_transfernets_gateway()
+{
+
+	testtx_ulp6_transfernets_gateway \
+	    "testtx_udp6_transfernets_gateway" "UDP6"
+}
+
+################################################################################
+#
+# We are receiver, but the FIBs are with us this time.
+#
+#
+
+#       # For IPFW, IFCONFIG
+#       #   For each FIB
+#       #     Send OOB well known to work START, wait for reflect
+#       #     Send probe, wait for reply with FIB# or RST/ICMP6 unreach
+#       #       (in case of ICMP6 use magic like ipfw count and OOB reply)
+#       #     Send OOB well known to work DONE, wait for reflect   
+#       #     Compare real with expected results.
+#
+
+textrx_ipfw_setup()
+{
+	local _fib _transfer i _p _o
+	_fib=$1
+	_transfer=$2
+
+	# ICMP6 would need content inspection to distinguish FIB, we can
+	# only differentiate by address.
+	# For the default single-address cases always set to current FIB.
+	ipfw add 100 setfib ${_fib} ipv6-icmp \
+	    from ${PEERADDR} to ${OURADDR} \
+	    via ${IFACE} in > /dev/null 2>&1
+	ipfw add 100 setfib ${_fib} ipv6-icmp \
+	    from ${PEERLINKLOCAL%\%*} to ${OURLINKLOCAL%\%*} \
+	    via ${IFACE} in > /dev/null 2>&1
+
+	# Always also do a setfib for the control port so that OOB
+	# signaling workes even if we remove connected subnets.
+	ipfw add 200 setfib ${_fib} ip6 from ${PEERADDR} to ${OURADDR} \
+	    dst-port ${CTRLPORT} via ${IFACE} in > /dev/null 2>&1
+
+	# Save addresses
+	_p="${PEERADDR}"
+	_o="${OURADDR}"
+
+	i=0
+	while test ${i} -lt ${RT_NUMFIBS}; do
+
+		# If doing multiple transfer networks, replace PEERADDR.
+		case ${_transfer} in
+		1)	PEERADDR=2001:2:${i}::1
+			OURADDR=2001:2:${i}::2
+			;;
+		esac
+
+		if test ${_instances} -gt 1 -o ${_transfer} -eq 1; then
+			ipfw add 400 setfib ${_fib} ipv6-icmp \
+			    from ${PEERADDR} to ${OURADDR} \
+			    icmp6types 128 \
+			    via ${IFACE} in > /dev/null 2>&1
+		fi
+		
+		case ${i} in
+		${_fib})
+			ipfw add 400 setfib ${_fib} ip6 \
+			    from ${PEERADDR} to ${OURADDR} \
+			    dst-port $((CTRLPORT + 1000 + i)) \
+			    via ${IFACE} in > /dev/null 2>&1
+			ipfw add 400 setfib ${_fib} ip6 \
+			    from ${PEERLINKLOCAL%\%*} to ${OURLINKLOCAL%\%*} \
+			    dst-port $((CTRLPORT + 1000 + i)) \
+			    via ${IFACE} in > /dev/null 2>&1
+			if test ${_instances} -le 1 -o ${_transfer} -ne 1; then
+				ipfw add 400 setfib ${_fib} ipv6-icmp \
+				    from ${PEERADDR} to ${OURADDR} \
+				    icmp6types 128 \
+				    via ${IFACE} in > /dev/null 2>&1
+			fi
+			;;
+		esac
+
+		i=$((i + 1))
+	done
+
+	# Restore addresses.
+	PEERADDR="${_p}"
+	OURADDR="${_o}"
+
+	case ${DEBUG} in
+	''|0)	;;
+	*)	ipfw show ;;
+	esac
+}
+
+textrx_ifconfig_setup()
+{
+	local _fib
+	_fib=$1
+
+	ifconfig ${IFACE} fib ${_fib} > /dev/null 2>&1
+}
+
+textrx_ipfw_cleanup()
+{
+	local i
+
+	case ${DEBUG} in
+	''|0)	;;
+	*)	ipfw show ;;
+	esac
+
+	ipfw delete 100 > /dev/null 2>&1 || true
+	ipfw delete 200 > /dev/null 2>&1 || true
+	ipfw delete 400 > /dev/null 2>&1 || true
+
+	i=0
+	while test ${i} -lt ${RT_NUMFIBS}; do
+
+		ipfw delete $((1000 + i)) > /dev/null 2>&1 || true
+		i=$((i + 1))
+	done
+}
+
+textrx_ifconfig_cleanup()
+{
+
+	ifconfig ${IFACE} fib 0 > /dev/null 2>&1
+}
+
+textrx_count_setup()
+{
+	local i
+
+	i=0
+	while test ${i} -lt ${RT_NUMFIBS}; do
+
+		# Count ICMP6 echo replies.
+		ipfw add $((500 + i)) count ipv6-icmp from any to any \
+		    icmp6types 129 fib ${i} via ${IFACE} out > /dev/null 2>&1
+		ipfw add $((500 + i)) count tcp from any to any \
+		    fib ${i} via ${IFACE} out > /dev/null 2>&1
+		ipfw add $((500 + i)) count udp from any to any \
+		    fib ${i} via ${IFACE} out > /dev/null 2>&1
+		i=$((i + 1))
+	done
+}
+
+textrx_count_results()
+{
+	local _fib _o i _rstr _c _req _p _opts
+	_fib=$1
+	_o="$2"
+
+	case ${DEBUG} in
+	''|0)	;;
+	*)	ipfw show ;;
+	esac
+
+	_rstr=""
+	i=0
+	while test ${i} -lt ${RT_NUMFIBS}; do
+
+		case "${_o}" in
+		"-i")	_c=`ipfw show $((500 + i)) | awk '/ ipv6-icmp / { print $2 }'` ;;
+		"-u")	_c=`ipfw show $((500 + i)) | awk '/ udp / { print $2 }'` ;;
+		*)	_c=`ipfw show $((500 + i)) | awk '/ tcp / { print $2 }'` ;;
+		esac
+		_rstr="${_rstr}${i} ${_c},"
+
+		ipfw delete $((500 + i)) > /dev/null 2>&1 || true
+		i=$((i + 1))
+	done
+
+	# We do not care about the request.
+	_req=`echo "RESULT ${_rstr}" | nc -V ${_fib} -6 -l ${CTRLPORT}`
+	print_debug "$? -- ${_req} -- RESULT ${_rstr}"
+}
+
+testrx_remove_connected()
+{
+	local _fib _transfer i j _prefix
+	_fib=$1
+	_transfer=$2
+
+	if test ${_transfer} -eq 1; then
+		i=0
+		while test ${i} -lt ${RT_NUMFIBS}; do
+			j=0
+			while test ${j} -lt ${RT_NUMFIBS}; do
+				_prefix="2001:2:${j}::"
+
+				case ${j} in
+				${_fib});;
+				*)	print_debug "setfib -F${i} route delete" \
+					    "-inet6 -net ${_prefix}"
+					setfib -F${i} route delete -inet6 -net \
+					    ${_prefix} > /dev/null 2>&1
+					;;
+				esac
+				j=$((j + 1))
+			done
+			i=$((i + 1))
+		done
+
+	else
+		_prefix=${OURADDR%2}	# Luckily we know the details.
+		i=0
+		while test ${i} -lt ${RT_NUMFIBS}; do
+
+			case ${i} in
+			${_fib});;
+			*)	print_debug "setfib -F${i} route delete" \
+				    "-inet6 -net ${_prefix}"
+				setfib -F${i} route delete -inet6 -net \
+				    ${_prefix} > /dev/null 2>&1
+				;;
+			esac
+
+			i=$((i + 1))
+		done
+	fi
+}
+
+testrx_cleanup_connected()
+{
+	local _fib _transfer i _prefix
+	_fib=$1
+	_transfer=$2
+
+	if test ${_transfer} -eq 1; then
+
+		i=0
+		while test ${i} -lt ${RT_NUMFIBS}; do
+			setfib -F${i} \
+			   ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias \
+			    > /dev/null 2>&1
+			delay
+			i=$((i + 1))
+		done
+
+	else
+		# Use the hammer removing the address and adding it again to get
+		# the connected subnet back to all FIBs.  Hard to do otherwise.
+		ifconfig ${IFACE} inet6 ${OURADDR}/64 -alias || true
+		delay
+		ifconfig ${IFACE} inet6 ${OURADDR}/64 alias up
+	fi
+}
+
+testrx_setup_transfer_networks()
+{
+	local i
+
+	i=0
+	while test ${i} -lt ${RT_NUMFIBS}; do
+		ifconfig ${IFACE} inet6 2001:2:${i}::2/64 -alias \
+		    > /dev/null 2>&1 || true
+		delay
+		ifconfig ${IFACE} inet6 2001:2:${i}::2/64 alias
+		i=$((i + 1))
+	done
+}
+
+testrx_run_one()
+{
+	local _fib _txt _opts
+	_fib=$1
+	_txt="$2"
+	_opts="$3"
+
+	case ${USE_SOSETFIB} in
+	0)	print_debug "setfib -F${_fib} ./reflect -p ${CTRLPORT}" \
+		    "-t ${_txt} ${_opts}"
+		setfib -F${_fib} ./reflect -p ${CTRLPORT} -t ${_txt} ${_opts}
+		;;
+	1)	print_debug "./reflect -F${_fib} -p ${CTRLPORT} -t ${_txt}" \
+		    "${_opts}"
+		./reflect -F${_fib} -p ${CTRLPORT} -t ${_txt} ${_opts}
+		;;
+	*)	die "Invalid value for USE_SOSETFIB: ${USE_SOSETFIB}" ;;
+	esac
+	print_debug "reflect '${_txt}' terminated without error."
+}
+
+testrx_run_multiple()
+{
+	local _fib _txt _opts i _jobs _p _w
+	_fib=$1
+	_txt="$2"
+	_opts="$3"
+
+	i=0
+	_jobs=""
+	while test ${i} -lt ${RT_NUMFIBS}; do
+		case ${USE_SOSETFIB} in
+		0)	print_debug "setfib -F${i} ./reflect" \
+			    "-p $((CTRLPORT + 1000 + i))" \
+			    "-t ${_txt} ${_opts} -N -f ${i} &"
+			setfib -F${i} ./reflect -p $((CTRLPORT + 1000 + i)) \
+			    -t ${_txt} ${_opts} -N -f ${i} &
+			;;
+		1)	print_debug "./reflect -F ${i}" \
+			    "-p $((CTRLPORT + 1000 + i))" \
+			    "-t ${_txt} ${_opts} -N -f ${i} &"
+			./reflect -F ${i} -p $((CTRLPORT + 1000 + i)) \
+			    -t ${_txt} ${_opts} -N -f ${i} &
+			;;
+		*)	die "Invalid value for USE_SOSETFIB: ${USE_SOSETFIB}" ;;
+		esac
+		_p=$!
+		_jobs="${_jobs}${_p} "
+		case ${i} in
+		${_fib}) _w=${_p} ;;
+		esac
+		i=$((i + 1))
+	done
+
+	# Start OOB control connection for START/DONE.
+	testrx_run_one ${_fib} "${_txt}" "${_opts}"
+	print_debug "KILL ${_jobs}"
+	for i in ${_jobs}; do
+		kill ${i} || true
+	done
+	#killall reflect || true
+	print_debug "reflects for '${_txt}' terminated without error."
+}
+
+testrx_run_test()
+{
+	local _n _t _fib _o _txt i _f _instance _destructive _transfer
+	_n="$1"
+	_t="$2"
+	_fib=$3
+	_o="$4"
+	_instances=$5
+	_destructive=$6
+	_transfer=$7
+
+	: ${_destructive:=0}
+
+	_opts=""
+	case ${DEBUG} in
+	''|0)	;;
+	42)	_opts="-d -d" ;;
+	*)	_opts="-d" ;;
+	esac
+
+	# Convert netcat options to reflect aguments.
+	case "${_o}" in
+	-i)	_opts="${_opts} -T TCP6" ;;	# Use TCP for START/DONE.
+	-u)	_opts="${_opts} -T UDP6" ;;
+	*)	_opts="${_opts} -T TCP6" ;;
+	esac
+
+	# Combined test case base name.
+	case ${USE_SOSETFIB} in
+	0)	_f="setfib" ;;
+	1)	_f="so_setfib" ;;
+	*)	die "Unexpected value for SO_SETFIB: ${SO_SETFIB}" ;;
+	esac
+
+        _txt="${_n}_${_f}_${_t}_${_fib}_${_instances}_${_destructive}_${_transfer}"
+
+	case ${_transfer} in
+	1)	testrx_setup_transfer_networks ;;
+	esac
+
+	case "${_t}" in
+	ipfw)		textrx_ipfw_setup ${_fib} ${_transfer} ${_instances} ;;
+	ifconfig)	textrx_ifconfig_setup ${_fib} ;;
+	*)		die "Invalid type in ${_txt}" ;;
+	esac
+
+	# Setup unresponsive FIBs.
+	case ${_destructive} in
+	1)	testrx_remove_connected ${_fib} ${_transfer} ;;
+	esac
+
+	# Setup to get result counts.
+	textrx_count_setup
+
+	# Run just one / one per FIB (with incremental ports).
+	#case ${_instances} in
+	#1)	testrx_run_one ${_fib} "${_txt}" "${_opts}" ;;
+	#*)	testrx_run_multiple ${_fib} "${_txt}" "${_opts}" ;;
+	#esac
+	testrx_run_multiple ${_fib} "${_txt}" "${_opts}" ${_transfer}
+
+	# Export result counts.
+	textrx_count_results ${_fib} "${_o}"
+
+	# Cleanup unresponsive  FIBs or multiple prefixes.
+	if test ${_destructive} -eq 1 -o ${_transfer} -eq 1; then
+		testrx_cleanup_connected ${_fib} ${_transfer}
+	fi
+
+	case "${_t}" in
+	ipfw)		textrx_ipfw_cleanup ;;
+	ifconfig)	textrx_ifconfig_cleanup ;;
+	*)		die "Invalid type in ${_txt}" ;;
+	esac
+}
+
+testrx_main()
+{
+	local _n _o s t fib _instances _destructive
+	_n="$1"
+	_o="$2"
+	_instances=$3
+
+	: ${_instances:=1}
+
+	print_debug "${_n}"
+	for _transfer in 1 0; do
+		for _destructive in 0 1; do
+			for t in ipfw ifconfig; do
+
+				print_debug "${_n}_${t}"
+				fib=0
+				while test ${fib} -lt ${RT_NUMFIBS}; do
+
+					print_debug "${_n}_${t}_${fib}" \
+					    "${_instances} ${_destructive}" \
+					    "${_transfer}"
+					testrx_run_test "${_n}" "${t}" ${fib} \
+					   "${_o}" ${_instances} \
+					   ${_destructive} ${_transfer}
+
+					fib=$((fib + 1))
+				done
+			done
+		done
+	done
+}
+
+################################################################################
+#
+# Probe all FIBs with one "active" one a time.
+#
+testrx_icmp6_same_addr_one_fib_a_time()
+{
+
+	testrx_main "testrx_icmp6_same_addr_one_fib_a_time" "-i"
+}
+
+testrx_tcp6_same_addr_one_fib_a_time()
+{
+
+	testrx_main "testrx_tcp6_same_addr_one_fib_a_time" ""
+}
+
+testrx_udp6_same_addr_one_fib_a_time()
+{
+
+	testrx_main "testrx_udp6_same_addr_one_fib_a_time" "-u"
+}
+
+################################################################################
+#
+# Probe all FIBs with all "active" all time.
+#
+testrx_tcp6_same_addr_all_fibs_a_time()
+{
+
+	testrx_main "testrx_tcp6_same_addr_all_fibs_a_time" "" ${RT_NUMFIBS}
+}
+
+testrx_udp6_same_addr_all_fibs_a_time()
+{
+
+	testrx_main "testrx_udp6_same_addr_all_fibs_a_time" "-u" ${RT_NUMFIBS}
+}
+
+
+################################################################################
+#
+# Prereqs.
+#
+if test `sysctl -n security.jail.jailed` -eq 0; then
+	kldload ipfw > /dev/null 2>&1 || kldstat -v | grep -q ipfw 
+fi
+ipfw -f flush > /dev/null 2>&1 || die "please load ipfw in base system"
+ipfw add 65000 permit ip from any to any > /dev/null 2>&1
+killall reflect || true
+
+################################################################################
+#
+# Run tests.
+#
+wait_remote_ready
+
+# We are receiver reflecting the input back.
+for uso in 0 1; do
+
+	# Only run ICMP6 tests for the first loop.
+	test ${uso} -ne 0 || testtx_icmp6_connected
+	testtx_tcp6_connected
+	testtx_udp6_connected
+
+	test ${uso} -ne 0 || testtx_icmp6_connected_blackhole
+	testtx_tcp6_connected_blackhole
+	testtx_udp6_connected_blackhole
+
+	test ${uso} -ne 0 || testtx_icmp6_connected_transfernets
+	testtx_tcp6_connected_transfernets
+	testtx_udp6_connected_transfernets
+
+	test ${uso} -ne 0 || testtx_icmp6_connected_ifconfig_transfernets
+	testtx_tcp6_connected_ifconfig_transfernets
+	testtx_udp6_connected_ifconfig_transfernets
+
+	test ${uso} -ne 0 || testtx_icmp6_gateway
+	testtx_tcp6_gateway
+	testtx_udp6_gateway
+
+	test ${uso} -ne 0 || testtx_icmp6_transfernets_gateways
+	testtx_tcp6_transfernets_gateways
+	testtx_udp6_transfernets_gateways
+
+	test ${uso} -ne 0 || testtx_icmp6_transfernets_gateway
+	testtx_tcp6_transfernets_gateway
+	testtx_udp6_transfernets_gateway
+done
+
+ipfw -f flush > /dev/null 2>&1
+ipfw add 65000 permit ip from any to any > /dev/null 2>&1
+
+# We are receiver, but the FIBs are with us this time.
+for uso in 0 1; do
+
+	USE_SOSETFIB=${uso}
+	
+	# Only expect ICMP6 tests for the first loop.
+	test ${uso} -ne 0 || testrx_icmp6_same_addr_one_fib_a_time
+	testrx_tcp6_same_addr_one_fib_a_time
+	testrx_udp6_same_addr_one_fib_a_time
+
+	testrx_tcp6_same_addr_all_fibs_a_time
+	testrx_udp6_same_addr_all_fibs_a_time
+
+done
+
+cleanup
+
+# end
diff -r 77b2b05d6591 -r 22418adf039f head/tools/test/ptrace/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/ptrace/Makefile	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,7 @@
+# $FreeBSD: head/tools/test/ptrace/Makefile 231443 2012-02-10 21:33:12Z kib $
+
+PROG=	scescx
+NO_MAN=
+WARNS?=	6
+
+.include <bsd.prog.mk>
diff -r 77b2b05d6591 -r 22418adf039f head/tools/test/ptrace/scescx.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/test/ptrace/scescx.c	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,406 @@
+/*-
+ * Copyright (c) 2011, 2012 Konstantin Belousov <kib at FreeBSD.org>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/tools/test/ptrace/scescx.c 231443 2012-02-10 21:33:12Z kib $");
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define TRACE	">>>> "
+
+static const char *
+decode_wait_status(int status)
+{
+	static char c[128];
+	char b[32];
+	int first;
+
+	c[0] = '\0';
+	first = 1;
+	if (WIFCONTINUED(status)) {
+		first = 0;
+		strlcat(c, "CONT", sizeof(c));
+	}
+	if (WIFEXITED(status)) {
+		if (first)
+			first = 0;
+		else
+			strlcat(c, ",", sizeof(c));
+		snprintf(b, sizeof(b), "EXIT(%d)", WEXITSTATUS(status));
+		strlcat(c, b, sizeof(c));
+	}
+	if (WIFSIGNALED(status)) {
+		if (first)
+			first = 0;
+		else
+			strlcat(c, ",", sizeof(c));
+		snprintf(b, sizeof(b), "SIG(%s)", strsignal(WTERMSIG(status)));
+		strlcat(c, b, sizeof(c));
+		if (WCOREDUMP(status))
+			strlcat(c, ",CORE", sizeof(c));
+	}
+	if (WIFSTOPPED(status)) {
+		if (first)
+			first = 0;
+		else
+			strlcat(c, ",", sizeof(c));
+		snprintf(b, sizeof(b), "SIG(%s)", strsignal(WSTOPSIG(status)));
+		strlcat(c, b, sizeof(c));
+	}
+	return (c);
+}
+
+static const char *
+decode_pl_flags(struct ptrace_lwpinfo *lwpinfo)
+{
+	static char c[128];
+	static struct decode_tag {
+		int flag;
+		const char *desc;
+	} decode[] = {
+		{ PL_FLAG_SA, "SA" },
+		{ PL_FLAG_BOUND, "BOUND" },
+		{ PL_FLAG_SCE, "SCE" },
+		{ PL_FLAG_SCX, "SCX" },
+		{ PL_FLAG_EXEC, "EXEC" },
+		{ PL_FLAG_SI, "SI" },
+		{ PL_FLAG_FORKED, "FORKED" },
+	};
+	char de[32];
+	unsigned first, flags, i;
+
+	c[0] = '\0';
+	first = 1;
+	flags = lwpinfo->pl_flags;
+	for (i = 0; i < sizeof(decode) / sizeof(decode[0]); i++) {
+		if ((flags & decode[i].flag) != 0) {
+			if (first)
+				first = 0;
+			else
+				strlcat(c, ",", sizeof(c));
+			strlcat(c, decode[i].desc, sizeof(c));
+			flags &= ~decode[i].flag;
+		}
+	}
+	for (i = 0; i < sizeof(flags) * NBBY; i++) {
+		if ((flags & (1 << i)) != 0) {
+			if (first)
+				first = 0;
+			else
+				strlcat(c, ",", sizeof(c));
+			snprintf(de, sizeof(de), "<%d>", i);
+			strlcat(c, de, sizeof(c));
+		}
+	}
+	return (c);
+}
+
+static const char *
+decode_pl_event(struct ptrace_lwpinfo *lwpinfo)
+{
+
+	switch (lwpinfo->pl_event) {
+	case PL_EVENT_NONE:
+		return ("NONE");
+
+	case PL_EVENT_SIGNAL:
+		return ("SIG");
+
+	default:
+		return ("UNKNOWN");
+	}
+}
+
+static void
+get_pathname(pid_t pid)
+{
+	char pathname[PATH_MAX];
+	int error, name[4];
+	size_t len;
+
+	name[0] = CTL_KERN;
+	name[1] = KERN_PROC;
+	name[2] = KERN_PROC_PATHNAME;
+	name[3] = pid;
+
+	len = sizeof(pathname);
+	error = sysctl(name, 4, pathname, &len, NULL, 0);
+	if (error < 0) {
+		if (errno != ESRCH) {
+			fprintf(stderr, "sysctl kern.proc.pathname.%d: %s\n",
+			    pid, strerror(errno));
+			return;
+		}
+		fprintf(stderr, "pid %d exited\n", pid);
+		return;
+	}
+	if (len == 0 || strlen(pathname) == 0) {
+		fprintf(stderr, "No cached pathname for process %d\n", pid);
+		return;
+	}
+	printf(TRACE "pid %d path %s\n", pid, pathname);
+}
+
+static void
+wait_info(int pid, int status, struct ptrace_lwpinfo *lwpinfo)
+{
+
+	printf(TRACE "pid %d wait %s", pid,
+	    decode_wait_status(status));
+	if (lwpinfo != NULL) {
+		printf(" event %s flags %s",
+		    decode_pl_event(lwpinfo), decode_pl_flags(lwpinfo));
+	}
+	printf("\n");
+}
+
+static int
+trace_sc(int pid)
+{
+	struct ptrace_lwpinfo lwpinfo;
+	int status;
+
+	if (ptrace(PT_TO_SCE, pid, (caddr_t)1, 0) < 0) {
+		perror("PT_TO_SCE");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+
+	if (waitpid(pid, &status, 0) == -1) {
+		perror("waitpid");
+		return (-1);
+	}
+	if (WIFEXITED(status) || WIFSIGNALED(status)) {
+		wait_info(pid, status, NULL);
+		return (-1);
+	}
+	assert(WIFSTOPPED(status));
+	assert(WSTOPSIG(status) == SIGTRAP);
+
+	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
+		perror("PT_LWPINFO");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+	wait_info(pid, status, &lwpinfo);
+	assert(lwpinfo.pl_flags & PL_FLAG_SCE);
+
+	if (ptrace(PT_TO_SCX, pid, (caddr_t)1, 0) < 0) {
+		perror("PT_TO_SCX");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+
+	if (waitpid(pid, &status, 0) == -1) {
+		perror("waitpid");
+		return (-1);
+	}
+	if (WIFEXITED(status) || WIFSIGNALED(status)) {
+		wait_info(pid, status, NULL);
+		return (-1);
+	}
+	assert(WIFSTOPPED(status));
+	assert(WSTOPSIG(status) == SIGTRAP);
+
+	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
+		perror("PT_LWPINFO");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+	wait_info(pid, status, &lwpinfo);
+	assert(lwpinfo.pl_flags & PL_FLAG_SCX);
+
+	if (lwpinfo.pl_flags & PL_FLAG_EXEC)
+		get_pathname(pid);
+
+	if (lwpinfo.pl_flags & PL_FLAG_FORKED) {
+		printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
+		return (lwpinfo.pl_child_pid);
+	}
+	return (0);
+}
+
+static int
+trace_cont(int pid)
+{
+	struct ptrace_lwpinfo lwpinfo;
+	int status;
+
+	if (ptrace(PT_CONTINUE, pid, (caddr_t)1, 0) < 0) {
+		perror("PT_CONTINUE");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+
+	if (waitpid(pid, &status, 0) == -1) {
+		perror("waitpid");
+		return (-1);
+	}
+	if (WIFEXITED(status) || WIFSIGNALED(status)) {
+		wait_info(pid, status, NULL);
+		return (-1);
+	}
+	assert(WIFSTOPPED(status));
+	assert(WSTOPSIG(status) == SIGTRAP);
+
+	if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)) < 0) {
+		perror("PT_LWPINFO");
+		ptrace(PT_KILL, pid, NULL, 0);
+		return (-1);
+	}
+	wait_info(pid, status, &lwpinfo);
+
+	if ((lwpinfo.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
+	    (PL_FLAG_EXEC | PL_FLAG_SCX))
+		get_pathname(pid);
+
+	if ((lwpinfo.pl_flags & (PL_FLAG_FORKED | PL_FLAG_SCX)) ==
+	    (PL_FLAG_FORKED | PL_FLAG_SCX)) {
+		printf(TRACE "forked child %d\n", lwpinfo.pl_child_pid);
+		return (lwpinfo.pl_child_pid);
+	}
+
+	return (0);
+}
+
+static int trace_syscalls = 1;
+
+static int
+trace(pid_t pid)
+{
+
+	return (trace_syscalls ? trace_sc(pid) : trace_cont(pid));
+}
+
+
+int
+main(int argc, char *argv[])
+{
+	struct ptrace_lwpinfo lwpinfo;
+	int c, status, use_vfork;
+	pid_t pid, pid1;
+
+	trace_syscalls = 1;
+	use_vfork = 0;
+	while ((c = getopt(argc, argv, "csv")) != -1) {
+		switch (c) {
+		case 'c':
+			trace_syscalls = 0;
+			break;
+		case 's':
+			trace_syscalls = 1;
+			break;
+		case 'v':
+			use_vfork = 1;
+			break;
+		default:
+		case '?':
+			fprintf(stderr, "Usage: %s [-c] [-s] [-v]\n", argv[0]);
+			return (2);
+		}
+	}
+
+	if ((pid = fork()) < 0) {
+		perror("fork");
+		return 1;
+	}
+	else if (pid == 0) {
+		if (ptrace(PT_TRACE_ME, 0, NULL, 0) < 0) {
+			perror("PT_TRACE_ME");
+			_exit(1);
+		}
+		kill(getpid(), SIGSTOP);
+		getpid();
+		if ((pid1 = use_vfork ? vfork() : fork()) < 0) {
+			perror("fork1");
+			return (1);
+		} else if (pid1 == 0) {
+			printf("Hi from child %d\n", getpid());
+			execl("/bin/ls", "ls", "/", (char *)NULL);
+		}
+	}
+	else { /* parent */
+		if (waitpid(pid, &status, 0) == -1) {
+			perror("waitpid");
+			return (-1);
+		}
+		assert(WIFSTOPPED(status));
+		assert(WSTOPSIG(status) == SIGSTOP);
+
+		if (ptrace(PT_LWPINFO, pid, (caddr_t)&lwpinfo,
+		    sizeof(lwpinfo)) < 0) {
+			perror("PT_LWPINFO");
+			ptrace(PT_KILL, pid, NULL, 0);
+			return (-1);
+		}
+		wait_info(pid, status, &lwpinfo);
+
+		if (ptrace(PT_FOLLOW_FORK, pid, 0, 1) < 0) {
+			perror("PT_FOLLOW_FORK");
+			ptrace(PT_KILL, pid, NULL, 0);
+			return (2);
+		}
+
+		while ((pid1 = trace(pid)) >= 0) {
+			if (pid1 != 0) {
+				printf(TRACE "attached to pid %d\n", pid1);
+#if 0
+				kill(pid1, SIGCONT);
+#endif
+				if (waitpid(pid1, &status, 0) == -1) {
+					perror("waitpid");
+					return (-1);
+				}
+				printf(TRACE "nested loop, pid %d status %s\n",
+				    pid1, decode_wait_status(status));
+				assert(WIFSTOPPED(status));
+				assert(WSTOPSIG(status) == SIGSTOP);
+				if (ptrace(PT_LWPINFO, pid1, (caddr_t)&lwpinfo,
+				    sizeof(lwpinfo)) < 0) {
+					perror("PT_LWPINFO");
+					ptrace(PT_KILL, pid1, NULL, 0);
+					return (-1);
+				}
+				wait_info(pid1, status, &lwpinfo);
+
+				while (trace(pid1) >= 0)
+					;
+			}
+		}
+
+		ptrace(PT_CONTINUE, pid, (caddr_t)1, 0);
+	}
+	return (0);
+}
diff -r 77b2b05d6591 -r 22418adf039f head/tools/tools/fixwhite/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/tools/fixwhite/Makefile	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,7 @@
+# $FreeBSD: head/tools/tools/fixwhite/Makefile 231071 2012-02-06 10:23:11Z ed $
+
+PROG=	fixwhite
+BINDIR=	/usr/bin
+WARNS=	6
+
+.include <bsd.prog.mk>
diff -r 77b2b05d6591 -r 22418adf039f head/tools/tools/fixwhite/fixwhite.1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/tools/fixwhite/fixwhite.1	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,48 @@
+.\" Copyright (c) 2012 Ed Schouten <ed at FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" 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: head/tools/tools/fixwhite/fixwhite.1 231098 2012-02-06 18:52:40Z ed $
+.\"
+.Dd February 6, 2012
+.Dt FIXWHITE 1
+.Os
+.Sh NAME
+.Nm fixwhite
+.Nd remove unneeded whitespace from text files
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility removes unneeded whitespace from text passed to standard input
+and prints the result to standard output.
+.Pp
+It removes leading and trailing empty lines from the input, as well as
+trailing whitespace characters from ever line of text.
+Multiple successive empty lines are merged together.
+If the whitespace at the beginning of a sentence is exactly a multiple
+of eight spaces, the whitespace is replaced by tabs.
+Also, spaces preceeding tabs will be merged into the tab character.
+.Sh AUTHORS
+.An Ed Schouten Aq ed at FreeBSD.org
diff -r 77b2b05d6591 -r 22418adf039f head/tools/tools/fixwhite/fixwhite.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/tools/tools/fixwhite/fixwhite.c	Fri Mar 02 17:01:18 2012 +0200
@@ -0,0 +1,180 @@
+/*-
+ * Copyright (c) 2012 Ed Schouten <ed at FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/tools/tools/fixwhite/fixwhite.c 231098 2012-02-06 18:52:40Z ed $");
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static char *queue = NULL;
+static size_t queuelen = 0, queuesize = 0;
+static off_t column = 0;
+
+static void
+savebyte(char c)
+{
+
+	if (queuelen >= queuesize) {
+		queuesize += 128;
+		queue = realloc(queue, queuesize);
+		if (queue == NULL) {
+			perror("malloc");
+			exit(1);
+		}
+	}
+	queue[queuelen++] = c;
+
+	switch (c) {
+	case '\n':
+		column = 0;
+		break;
+	case ' ':
+		column++;
+		break;
+	case '\t':
+		column = (column / 8 + 1) * 8;
+		break;
+	}
+}
+
+static bool
+peekbyte(size_t back, char c)
+{
+
+	return (queuelen >= back && queue[queuelen - back] == c);
+}
+
+static void
+savewhite(char c, bool leading)
+{
+	off_t ncolumn;
+
+	switch (c) {
+	case '\n':
+		if (leading) {
+			/* Remove empty lines before input. */
+			queuelen = 0;
+			column = 0;
+		} else {
+			/* Remove trailing whitespace. */
+			while (peekbyte(1, ' ') || peekbyte(1, '\t'))
+				queuelen--;
+			/* Remove redundant empty lines. */
+			if (peekbyte(2, '\n') && peekbyte(1, '\n'))
+				return;
+			savebyte('\n');
+		}
+		break;
+	case ' ':
+		savebyte(' ');
+		break;
+	case '\t':
+		/* Convert preceeding spaces to tabs. */
+		ncolumn = (column / 8 + 1) * 8;
+		while (peekbyte(1, ' ')) {
+			queuelen--;
+			column--;
+		}
+		while (column < ncolumn)
+			savebyte('\t');
+		break;
+	}
+}
+
+static void
+printwhite(void)
+{
+	off_t i;
+
+	/* Merge spaces at the start of a sentence to tabs if possible. */
+	if ((column % 8) == 0) {
+		for (i = 0; i < column; i++)
+			if (!peekbyte(i + 1, ' '))
+				break;
+		if (i == column) {
+			queuelen -= column;
+			for (i = 0; i < column; i += 8)
+				queue[queuelen++] = '\t';
+		}
+	}
+
+	if (fwrite(queue, 1, queuelen, stdout) != queuelen) {
+		perror("write");
+		exit(1);
+	}
+	queuelen = 0;
+}
+
+static char
+readchar(void)
+{
+	int c;
+
+	c = getchar();
+	if (c == EOF && ferror(stdin)) {
+		perror("read");
+		exit(1);
+	}
+	return (c);
+}
+
+static void
+writechar(char c)
+{
+
+	if (putchar(c) == EOF) {
+		perror("write");
+		exit(1);
+	}
+	/* XXX: Multi-byte characters. */
+	column++;
+}
+
+int
+main(void)
+{
+	int c;
+	bool leading = true;
+
+	while ((c = readchar()) != EOF) {
+		if (isspace(c))
+			/* Save whitespace. */
+			savewhite(c, leading);
+		else {
+			/* Reprint whitespace and print regular character. */
+			printwhite();
+			writechar(c);
+			leading = false;
+		}
+	}
+	/* Terminate non-empty files with a newline. */
+	if (!leading)
+		writechar('\n');
+	return (0);
+}


More information about the Zrouter-src-freebsd mailing list