Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/share/examples/rump/virtual_ip_router Add an example for a r...
details: https://anonhg.NetBSD.org/src/rev/1bdf25f5ee37
branches: trunk
changeset: 753437:1bdf25f5ee37
user: pooka <pooka%NetBSD.org@localhost>
date: Mon Mar 29 02:01:47 2010 +0000
description:
Add an example for a rump router cluster setup along with a README.
some contributions to the code from Martti Kuparinen
diffstat:
share/examples/rump/virtual_ip_router/README.txt | 107 ++++++++++
share/examples/rump/virtual_ip_router/rumprouter.c | 207 +++++++++++++++++++++
2 files changed, 314 insertions(+), 0 deletions(-)
diffs (truncated from 322 to 300 lines):
diff -r d206076e5864 -r 1bdf25f5ee37 share/examples/rump/virtual_ip_router/README.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/share/examples/rump/virtual_ip_router/README.txt Mon Mar 29 02:01:47 2010 +0000
@@ -0,0 +1,107 @@
+ $NetBSD: README.txt,v 1.1 2010/03/29 02:01:47 pooka Exp $
+
+Using rump it is possible to build a router test setup consisting
+of thousands of NetBSD IP stacks within a single host OS, one
+networking stack per application process. Each IP stack instance
+has its own set of interfaces, addresses and routing tables. These
+instances may or may not share the same code, i.e. it is possible
+to do compatibility testing of new features. The advantage over
+using full-fledged virtual OS setups (qemu, Xen, etc.) is scalability:
+the rump IP router base runtime takes less than 500kB of memory
+per instance.
+
+The code is _ONLY AN EXAMPLE_ as opposed a fully featured test kit.
+Some code tweaking is probably required to make this do what you
+want. Usage examples follow.
+
+To use one single rump networking stack instance with access to
+two real networks, you need tap and bridge on the host system (yes,
+this involves some memory copies. the resulting router setup can
+still saturate a GigE, though. it should not be difficult to bring
+performance to be ~the same as an in-kernel stack, but haven't
+managed to implement that yet).
+
+Anyway, the following can be done with the current code:
+
+/*
+ * Usage:
+ *
+ * # ifconfig yourrealif0 up
+ * # ifconfig tap0 create
+ * # ifconfig tap0 up
+ * # ifconfig bridge0 create
+ * # brconfig bridge0 add tap0 add yourrealif0
+ * # brconfig bridge0 up
+ * #
+ * # ifconfig yourrealif1 up
+ * # ifconfig tap1 create
+ * # ifconfig tap1 up
+ * # ifconfig bridge1 create
+ * # brconfig bridge1 add tap1 add yourrealif1
+ * # brconfig bridge1 up
+ * #
+ * # ./router virt0 192.168.1.1 255.255.255.0 192.168.1.255 \
+ * # virt1 192.168.2.1 255.255.255.0 192.168.2.255
+ *
+ * This will bind virtN to tapN and act as a router.
+ */
+
+As brilliant ascii art, it would look something like this:
+
+ network network
+ ^ ^
+ | |
+ /----v-------------\ /------------v----\
+ kernel | realif0 <-> tap0 | | tap1 -> realif1 |
+ \---------------^--/ \---^-------------/
+-------------------------|-------------------|--------------------
+ /----v-------------------v----\
+ user | virt0 <-> rump IP <-> virt1 |
+ \-----------------------------/
+
+(ok, no more drawing)
+
+The addresses configured to the rump virt0 and virt1 interfaces
+will be visible on the physical network, and their traffic can be
+examined with e.g. wireshark. You can also use wireshark on
+tap0/tap1.
+
+The alternate approach is to use purely internal simulation. The
+shmif rump driver uses a memory-mapped file as an ethernet "bus"
+between multiple rump networking stack instances. Just use
+rump_pub_shmif_create() in the code. This can also of course be
+combined with the tap setup, and you can have setups where border
+nodes talk to an internal mesh of shmif's. Semi-drawn, it looks
+like this:
+
+net1 <-> virt0, shm0 <-> shm1, shm2 <-> .... <-> shmN, virt1 <-> net1
+ (rump0) (rump1) .... (rumpN)
+
+Linear setups (where router n talks to exactly router n-1 and n+1)
+can be easily autogenerated. Here's a snippet of executed commands
+I used to start a few hundred routers (NOTE! the usage of the
+example code is different!):
+
+./a.out 10.0.0.1 10.0.0.255 /tmp/rumpshm_0 0 10.0.1.2 10.0.1.255 /tmp/rumpshm_1 10.0.1.1
+./a.out 10.0.1.1 10.0.1.255 /tmp/rumpshm_1 10.0.1.2 10.0.2.2 10.0.2.255 /tmp/rumpshm_2 10.0.2.1
+./a.out 10.0.2.1 10.0.2.255 /tmp/rumpshm_2 10.0.2.2 10.0.3.2 10.0.3.255 /tmp/rumpshm_3 10.0.3.1
+./a.out 10.0.3.1 10.0.3.255 /tmp/rumpshm_3 10.0.3.2 10.0.4.2 10.0.4.255 /tmp/rumpshm_4 10.0.4.1
+....
+./a.out 10.0.252.1 10.0.252.255 /tmp/rumpshm_252 10.0.252.2 10.0.253.2 10.0.253.
+255 /tmp/rumpshm_253 10.0.253.1
+./a.out 10.0.253.1 10.0.253.255 /tmp/rumpshm_253 10.0.253.2 10.0.255.1 10.0.255.
+255 /tmp/rumpshm_255 0
+
+Unfortunately I lost script used to produce that, but the algorithm
+is quickly obvious.
+
+Easy but slightly more interesting setups, such as a M^N matrix
+(hyper-matrix?) are also possible, but left as an exercise to the
+reader.
+
+Compiling the router depends a little on what networking domain
+and what interface you want to use for testing. The very basic
+setup with IP+virtif will get you quite far:
+
+cc rumprouter.c -lrumpnet_virtif -lrumpnet_netinet -lrumpnet_net -lrumpnet \
+ -lrump -lrumpuser -lpthread
diff -r d206076e5864 -r 1bdf25f5ee37 share/examples/rump/virtual_ip_router/rumprouter.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/share/examples/rump/virtual_ip_router/rumprouter.c Mon Mar 29 02:01:47 2010 +0000
@@ -0,0 +1,207 @@
+/* $NetBSD: rumprouter.c,v 1.1 2010/03/29 02:01:47 pooka Exp $ */
+
+/*
+ * Copyright (c) 2008 Antti Kantee. All Rights Reserved.
+ *
+ * Development of this software was supported by then
+ * Finnish Cultural Foundation.
+ *
+ * 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 ``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/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <net/route.h>
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/sockio.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/route.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DP if (1) printf
+#else
+#define DP if (0) printf
+#endif
+
+static void
+configure_interface(const char *ifname, const char *addr, const char *mask,
+ const char *bcast)
+{
+ struct ifaliasreq ia;
+ struct sockaddr_in *sin;
+ int s, rv;
+
+ DP("Entering %s\n", __FUNCTION__);
+
+ DP("Create an interface(%s)\n", ifname);
+ s = atoi(ifname + strlen(ifname) - 1); /* XXX FIXME XXX */
+ if ((s = rump_pub_virtif_create(s)) != 0) {
+ err(1, "rump_pub_virtif_create(%d)", s);
+ }
+
+ DP("Get a socket for configuring the interface\n");
+ if ((s = rump_sys_socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(1, "rump_sys_socket");
+ }
+
+ /* 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);
+
+ DP("Set the addresses\n");
+ rv = rump_sys_ioctl(s, SIOCAIFADDR, &ia);
+ if (rv) {
+ err(1, "SIOCAIFADDR");
+ }
+ rump_sys_close(s);
+ DP("Done with %s\n", __FUNCTION__);
+}
+
+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;
+ } m_rtmsg;
+#define rtm m_rtmsg.m_rtm
+ uint8_t *bp = &m_rtmsg.m_space;
+ struct sockaddr_in sinstore;
+ int s, rv;
+
+ DP("Entering %s\n", __FUNCTION__);
+
+ DP("Open a routing socket\n");
+ s = rump_sys_socket(PF_INET, SOCK_DGRAM, 0);
+ if (s == -1) {
+ err(1, "rump_sys_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;
+
+ DP("Set the route\n");
+ rv = rump_sys_write(s, &m_rtmsg, len);
+ if (rv != (int)len) {
+ err(1, "rump_sys_write");
+ }
+ rump_sys_close(s);
+ DP("Done with %s\n", __FUNCTION__);
+}
+
+static void
+usage(const char *argv0)
+{
+ printf("Usage: %s if1 if2 [route]\n", argv0);
+ printf("\n");
+ printf("where both \"if1\" and \"if2\" are\n");
+ printf("\n");
+ printf("ifname address netmask broadcast\n");
+ printf("\n");
Home |
Main Index |
Thread Index |
Old Index