Module Name:    src
Committed By:   pooka
Date:           Sun Jul  4 19:30:59 UTC 2010

Added Files:
        src/tests/net/icmp: Atffile Makefile t_forward.c

Log Message:
Add test case for PR kern/43548

Due to the nature of the feature under test, this one is a little
different, so let me explain how it works.

The test program forks and bootstraps a rump kernel in both processes.
It then configures shared memory interfaces in both.  shmif is nice
in that it uses a mmaped file as the bus and does not require root
privileges for communication between two (or more) processes.  The
child process then proceeds to increase icmp.returndatabytes as
indicated by the PR, while the parent process sets the global TTL
of the rump kernel to 1 (note: both values only affect the respective
rump kernels, not each other or more importantly the host kernel).
The parent then sends the bad packet which is supposed to be routed
by the child.  If ip_icmp.c was too old, *boom* + fail; otherwise
nothing bad happens and the test exists with success after one
second.

Eventually this test can be extended into a framework for automated
testing of any networking code which requires (arbitrarily complex)
routing setups.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/tests/net/icmp/Atffile src/tests/net/icmp/Makefile \
    src/tests/net/icmp/t_forward.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/tests/net/icmp/Atffile
diff -u /dev/null src/tests/net/icmp/Atffile:1.1
--- /dev/null	Sun Jul  4 19:30:59 2010
+++ src/tests/net/icmp/Atffile	Sun Jul  4 19:30:59 2010
@@ -0,0 +1,6 @@
+Content-Type: application/X-atf-atffile; version="1"
+X-NetBSD-Id: "$NetBSD: Atffile,v 1.1 2010/07/04 19:30:59 pooka Exp $"
+
+prop: test-suite = "NetBSD"
+
+tp-glob: *
Index: src/tests/net/icmp/Makefile
diff -u /dev/null src/tests/net/icmp/Makefile:1.1
--- /dev/null	Sun Jul  4 19:30:59 2010
+++ src/tests/net/icmp/Makefile	Sun Jul  4 19:30:59 2010
@@ -0,0 +1,13 @@
+# $NetBSD: Makefile,v 1.1 2010/07/04 19:30:59 pooka Exp $
+#
+
+.include <bsd.own.mk>
+
+TESTSDIR=	${TESTSBASE}/net/icmp
+
+TESTS_C=	t_forward
+
+LDADD+=		-lrumpnet_shmif -lrumpnet_netinet -lrumpnet_net -lrumpnet
+LDADD+=		-lrump -lrumpuser -lpthread
+
+.include <bsd.test.mk>
Index: src/tests/net/icmp/t_forward.c
diff -u /dev/null src/tests/net/icmp/t_forward.c:1.1
--- /dev/null	Sun Jul  4 19:30:59 2010
+++ src/tests/net/icmp/t_forward.c	Sun Jul  4 19:30:59 2010
@@ -0,0 +1,271 @@
+/*	$NetBSD: t_forward.c,v 1.1 2010/07/04 19:30:59 pooka Exp $	*/
+
+/*-
+ * Copyright (c) 2010 The NetBSD Foundation, Inc.
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
+#ifndef lint
+__RCSID("$NetBSD: t_forward.c,v 1.1 2010/07/04 19:30:59 pooka Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <net/route.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "../../h_macros.h"
+
+static void
+configure_interface(const char *busname, const char *addr, const char *mask,
+	const char *bcast)
+{
+	char ifname[32];
+	struct ifaliasreq ia;
+	struct sockaddr_in *sin;
+	int s, rv, ifnum;
+
+	if ((s = rump_pub_shmif_create(busname, &ifnum)) != 0) {
+		atf_tc_fail("rump_pub_virtif_create(%d)", s);
+	}
+
+	if ((s = rump_sys_socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+		atf_tc_fail_errno("if config socket");
+	}
+	sprintf(ifname, "shmif%d", ifnum);
+
+	/* Address */
+	memset(&ia, 0, sizeof(ia));
+	strcpy(ia.ifra_name, ifname);
+	sin = (struct sockaddr_in *)&ia.ifra_addr;
+	sin->sin_family = AF_INET;
+	sin->sin_len = sizeof(struct sockaddr_in);
+	sin->sin_addr.s_addr = inet_addr(addr);
+
+	/* Netmask */
+	sin = (struct sockaddr_in *)&ia.ifra_mask;
+	sin->sin_family = AF_INET;
+	sin->sin_len = sizeof(struct sockaddr_in);
+	sin->sin_addr.s_addr = inet_addr(mask);
+
+	/* Broadcast address */
+	sin = (struct sockaddr_in *)&ia.ifra_broadaddr;
+	sin->sin_family = AF_INET;
+	sin->sin_len = sizeof(struct sockaddr_in);
+	sin->sin_addr.s_addr = inet_addr(bcast);
+
+	rv = rump_sys_ioctl(s, SIOCAIFADDR, &ia);
+	if (rv) {
+		atf_tc_fail_errno("SIOCAIFADDR");
+	}
+	rump_sys_close(s);
+}
+
+static void
+configure_routing(const char *dst, const char *mask, const char *gw)
+{
+	size_t len;
+	struct {
+		struct rt_msghdr m_rtm;
+		uint8_t m_space[512];
+	} m_rtmsg;
+#define rtm m_rtmsg.m_rtm
+	uint8_t *bp = m_rtmsg.m_space;
+	struct sockaddr_in sinstore;
+	int s, rv;
+
+	s = rump_sys_socket(PF_ROUTE, SOCK_RAW, 0);
+	if (s == -1) {
+		atf_tc_fail_errno("routing socket");
+	}
+
+	memset(&m_rtmsg, 0, sizeof(m_rtmsg));
+	rtm.rtm_type = RTM_ADD;
+	rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
+	rtm.rtm_version = RTM_VERSION;
+	rtm.rtm_seq = 2;
+	rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+
+	/* dst */
+	memset(&sinstore, 0, sizeof(sinstore));
+	sinstore.sin_family = AF_INET;
+	sinstore.sin_len = sizeof(sinstore);
+	sinstore.sin_addr.s_addr = inet_addr(dst);
+	memcpy(bp, &sinstore, sizeof(sinstore));
+	bp += sizeof(sinstore);
+
+	/* gw */
+	memset(&sinstore, 0, sizeof(sinstore));
+	sinstore.sin_family = AF_INET;
+	sinstore.sin_len = sizeof(sinstore);
+	sinstore.sin_addr.s_addr = inet_addr(gw);
+	memcpy(bp, &sinstore, sizeof(sinstore));
+	bp += sizeof(sinstore);
+
+	/* netmask */
+	memset(&sinstore, 0, sizeof(sinstore));
+	sinstore.sin_family = AF_INET;
+	sinstore.sin_len = sizeof(sinstore);
+	sinstore.sin_addr.s_addr = inet_addr(mask);
+	memcpy(bp, &sinstore, sizeof(sinstore));
+	bp += sizeof(sinstore);
+
+	len = bp - (uint8_t *)&m_rtmsg;
+	rtm.rtm_msglen = len;
+
+	rv = rump_sys_write(s, &m_rtmsg, len);
+	if (rv != (int)len) {
+		atf_tc_fail_errno("write routing message");
+	}
+	rump_sys_close(s);
+}
+
+/*
+ * Since our maxttl is in our private namespace, we don't need raw packet
+ * construction like traceroute(8) -- we can just use the global maxttl.
+ */
+static void
+sendttl(void)
+{
+	extern int rumpns_ip_defttl;
+	struct sockaddr_in sin;
+	char payload[1024];
+	int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
+	int nv;
+	int s;
+
+	configure_interface("bus1", "1.0.0.1", "255.255.255.0", "1.0.0.255");
+	configure_routing("0.0.0.0", "0.0.0.0", "1.0.0.2"); /* default router */
+
+	/* set global ttl to 1 */
+	nv = 1;
+	if (rump_sys___sysctl(mib, 4, NULL, NULL, &nv, sizeof(nv)) == -1)
+		atf_tc_fail_errno("set ttl");
+
+	s = rump_sys_socket(PF_INET, SOCK_DGRAM, 0);
+	if (s == -1)
+		atf_tc_fail_errno("create send socket");
+
+	memset(&sin, 0, sizeof(sin));
+	sin.sin_len = sizeof(sin);
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(33434);
+	sin.sin_addr.s_addr = inet_addr("9.9.9.9");
+
+	/* send udp datagram with ttl == 1 */
+	if (rump_sys_sendto(s, payload, sizeof(payload), 0,
+	    (struct sockaddr *)&sin, sizeof(sin)) == -1)
+		atf_tc_fail_errno("sendto");
+}
+
+static void
+router(void)
+{
+	int mib[4] = { CTL_NET, PF_INET, IPPROTO_ICMP,
+		    ICMPCTL_RETURNDATABYTES };
+	int nv;
+
+	/* set returndatabytes to 200 */
+	nv = 200;
+	if (rump_sys___sysctl(mib, 4, NULL, NULL, &nv, sizeof(nv)) == -1)
+		atf_tc_fail_errno("sysctl returndatabytes");
+
+	configure_interface("bus1", "1.0.0.2", "255.255.255.0", "1.0.0.255");
+
+	/*
+	 * Wait for parent to send us the data and for us to have
+	 * a chance to process it.
+	 */
+	sleep(1);
+	exit(0);
+}
+
+ATF_TC(returndatabytes);
+ATF_TC_HEAD(returndatabytes, tc)
+{
+
+	atf_tc_set_md_var(tc, "descr", "icmp.returndatabytes with certain "
+	    "packets can cause kernel panic");
+	atf_tc_set_md_var(tc, "use.fs", "true");
+	atf_tc_set_md_var(tc, "timeout", "4"); /* just in case */
+	/* PR kern/43548 */
+}
+
+ATF_TC_BODY(returndatabytes, tc)
+{
+	pid_t cpid;
+	int status;
+
+	cpid = fork();
+	rump_init();
+
+	switch (cpid) {
+	case -1:
+		atf_tc_fail_errno("fork failed");
+	case 0:
+		router();
+		break;
+	default:
+		sendttl();
+		if (wait(&status) == -1)
+			atf_tc_fail_errno("wait");
+		if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status))
+				atf_tc_fail("child exited with status %d",
+				    WEXITSTATUS(status));
+		} else {
+			atf_tc_fail("child died");
+		}
+	}
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+	ATF_TP_ADD_TC(tp, returndatabytes);
+
+	return atf_no_error();
+}

Reply via email to