[Simh] [PATCH] tun/tap networking support

ucsavl at gmail.com ucsavl at gmail.com
Wed Apr 28 20:05:02 EDT 2010


This patch lets simh read/write the ethernet frames from/into
a file descriptor, instead of injecting them with pcap into an interface.

That file descriptor could be obtained by opening a tun/tap device
(ex. 'att xq tap:tap0' on linux does the necessary magic of opening
/dev/net/tun, attaching it to 'tap0' and setting ethernet mode),
opening some other path in the filesystem, or it could be opened by a
helper program and passed down to simh via an environment variable.

The main advantage of this is being able to run simh with networking
as a regular user.

to build it:
$ make USE_TAP_NETWORK=1

to use it, run as root:
# tunctl -u regular_user -t tap0

then configure the host as if tap0 were a real interface and simh a real
machine connected to it (ex. enable forwarding+NAT, run dhcp on tap0, etc).

finally, running as regular_user:
$ vax
...
sim> att xq tap:tap0

diff -Nrup simhv38-1-orig/makefile simhv38-1/makefile
--- simhv38-1-orig/makefile	2008-11-19 21:53:48.000000000 +0200
+++ simhv38-1/makefile	2010-04-28 04:53:02.000000000 +0300
@@ -13,8 +13,9 @@ ifeq ($(WIN32),)
     endif
   endif
   CC = gcc -std=c99 -U__STRICT_ANSI__ -g $(OS_CCDEFS) -I .
-  ifeq ($(USE_NETWORK),)
-  else
+  ifneq ($(USE_TAP_NETWORK),)
+    NETWORK_OPT = -DUSE_NETWORK -DUSE_TAP_NETWORK sim_ether_tap.c opentap.c
+  else ifneq ($(USE_NETWORK),)
     NETWORK_OPT = -DUSE_NETWORK -isystem /usr/local/include /usr/local/lib/libpcap.a
   endif
 else
@@ -35,7 +36,6 @@ BIN = BIN/
 SIM = scp.c sim_console.c sim_fio.c sim_timer.c sim_sock.c \
 	sim_tmxr.c sim_ether.c sim_tape.c
 
-
 #
 # Emulator source files and compile time options
 #
diff -Nrup simhv38-1-orig/opentap.c simhv38-1/opentap.c
--- simhv38-1-orig/opentap.c	1970-01-01 02:00:00.000000000 +0200
+++ simhv38-1/opentap.c	2010-04-28 04:42:21.000000000 +0300
@@ -0,0 +1,34 @@
+#ifdef __linux
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int opentap(char *fn){
+	int fd;
+	struct ifreq ifr;
+	if(snprintf(ifr.ifr_name, sizeof ifr.ifr_name, "%s", fn)
+			>= sizeof ifr.ifr_name){
+		errno = ENAMETOOLONG;
+		return -1;
+	}
+	if((fd = open("/dev/net/tun", O_RDWR)) == -1)
+		return -1;
+	ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+	if(ioctl(fd, TUNSETIFF, &ifr) == -1){
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
+#else
+int opentap(char *fn){
+	return -1;
+}
+#endif
diff -Nrup simhv38-1-orig/sim_ether.c simhv38-1/sim_ether.c
--- simhv38-1-orig/sim_ether.c	2008-04-24 17:11:42.000000000 +0300
+++ simhv38-1/sim_ether.c	2009-02-20 22:55:54.000000000 +0200
@@ -606,10 +606,17 @@ void ethq_insert(ETH_QUE* que, int32 typ
 }
 
 /*============================================================================*/
+/*                        Simple tap network                                  */
+/*============================================================================*/
+#if defined (USE_TAP_NETWORK)
+
+/* use sim_ether_tap.c */
+
+/*============================================================================*/
 /*                        Non-implemented versions                            */
 /*============================================================================*/
 
-#if !defined (USE_NETWORK) && !defined(USE_SHARED)
+#elif !defined (USE_NETWORK) && !defined(USE_SHARED)
 t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
   {return SCPE_NOFNC;}
 t_stat eth_close (ETH_DEV* dev)
diff -Nrup simhv38-1-orig/sim_ether_tap.c simhv38-1/sim_ether_tap.c
--- simhv38-1-orig/sim_ether_tap.c	1970-01-01 02:00:00.000000000 +0200
+++ simhv38-1/sim_ether_tap.c	2010-04-28 05:46:42.000000000 +0300
@@ -0,0 +1,139 @@
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "sim_ether.h"
+
+extern FILE *sim_log;
+void eth_add_crc32(ETH_PACK* packet);
+int opentap(char*);
+
+static void
+errf(char *fmt, ...)
+{
+	va_list va;
+	va_start(va, fmt);
+	vprintf(fmt, va);
+	if(sim_log) vfprintf(sim_log, fmt, va);
+	va_end(va);
+}
+
+t_stat
+eth_open(ETH_DEV *dev, char *fn, DEVICE *dptr, uint32 dbit)
+{
+	int fd, t;
+	if(!dev || !fn)
+		return SCPE_ARG;
+	if(!strncmp(fn, "fd:", 3)){
+		char *v;
+		if(fn[3] == '$'){
+			if(!(v = getenv(fn + 4))){
+				errf("no such environment variable '%s'\n",
+					fn + 4);
+				return SCPE_OPENERR;
+			}
+		}else
+			v = fn + 3;
+		if(v[0] < '0' || v[0] > '9'){
+			errf("fd should be a number, not '%s'\n", v);
+			return SCPE_OPENERR;
+		}
+		if((fd = dup(atoi(v))) < 0){
+			errf("dup(%s): %s\n", v, strerror(errno));
+			return SCPE_OPENERR;
+		}
+	}else if(!strncmp(fn, "tap:", 4)){
+		if((fd = opentap(fn + 4)) < 0){
+			errf("opentap(%s): %s\n", fn + 4, strerror(errno));
+			return SCPE_OPENERR;
+		}
+	}else{
+		if((fd = open(fn, O_RDWR)) < 0){
+			errf("open(%s): %s\n", fn, strerror(errno));
+			return SCPE_OPENERR;
+		}
+	}
+	t = 1;
+	if(ioctl(fd, FIONBIO, &t)){
+		errf("ioctl(FIONBIO, 1): %s\n", strerror(errno));
+		close(fd);
+		return SCPE_OPENERR;
+	}
+	if(!(dev->name = strdup(fn))){
+		close(fd);
+		return SCPE_MEM;
+	}
+	dev->handle = (void*)fd;
+	dev->need_crc = 0;
+	return SCPE_OK;
+}
+
+t_stat
+eth_close(ETH_DEV *dev)
+{
+	if(!dev) return SCPE_UNATT;
+	close((int)dev->handle);
+	free(dev->name);
+	return SCPE_OK;
+}
+
+t_stat
+eth_write(ETH_DEV *dev, ETH_PACK *packet, ETH_PCALLBACK routine)
+{
+	int fd;
+	if(!dev) return SCPE_UNATT;
+	if(!packet) return SCPE_ARG;
+	fd = (int)dev->handle;
+	if(write(fd, packet->msg, packet->len) < 0)
+		return SCPE_IOERR;
+	if(routine)
+		routine(0);
+	return SCPE_OK;
+}
+
+t_stat
+eth_read(ETH_DEV *dev, ETH_PACK *packet, ETH_PCALLBACK routine)
+{
+	int fd;
+	ssize_t r;
+	if(!dev) return SCPE_UNATT;
+	if(!packet) return SCPE_ARG;
+	fd = (int)dev->handle;
+	r = read(fd, packet->msg, sizeof packet->msg);
+	if(r < 0)
+		return SCPE_IOERR;
+	packet->len = r;
+	if (dev->need_crc)
+		eth_add_crc32(packet);
+	if(routine)
+		routine(0);
+	return SCPE_OK;
+}
+
+t_stat
+eth_filter(ETH_DEV *dev, int addr_count, ETH_MAC *addresses,
+	   ETH_BOOL all_multicast, ETH_BOOL promiscuous)
+{
+	if(!dev) return SCPE_UNATT;
+	return SCPE_OK;
+}
+
+static ETH_LIST dlist[] = {
+	{ 0, "fd:d", "file descriptor 'd'" },
+	{ 0, "fd:$d", "file descriptor from environment variable 'd'" },
+	{ 0, "tap:if", "tun/tap interface 'if'" },
+	{ 0, "/path/to/file", "file path" },
+};
+
+int
+eth_devices(int max, ETH_LIST *list)
+{
+	int i;
+	for(i = 0; i < max && i < sizeof dlist/sizeof*dlist; i++)
+		list[i] = dlist[i];
+	return i;
+}
+



More information about the Simh mailing list