Added support for VDE (Virtual Distributed Ethernet) network packet transport

Fixed filtering for non-pcap network packet transports (i.e. tun/tap, and vde) to properly filter the desired packets.
This commit is contained in:
Mark Pizzolato 2011-10-31 11:51:19 -07:00
parent bfb6e54819
commit fd5de0d005
4 changed files with 1282 additions and 1095 deletions

View file

@ -133,12 +133,36 @@ OSX (Snow Leopard)
Invoke the package installer tuntap_20090913.pkg Invoke the package installer tuntap_20090913.pkg
Click through the various prompts accepting things and eventually installing the package. Click through the various prompts accepting things and eventually installing the package.
# Run simulator and: # Build and Run simulator and:
sim> attach xq tap:tap0 sim> attach xq tap:tap0
sim> ! ifconfig tap0 192.168.6.1 netmask 255.255.255.0 sim> ! ifconfig tap0 192.168.6.1 netmask 255.255.255.0
Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1 and things work. Simulated system uses IP address 192.168.6.2 and host uses 192.167.6.1
As far as I can tell you must run as root for this to work. and things work.
You must run as root for this to work.
-------------------------------------------------------------------------------
An alternative to direct pcap and tun/tap networking on *nix environments is
VDE (Virtual Distributed Ethernet).
Note 1: Using vde based networking is likely more flexible, but it isn't
nearly as efficient. Host OS overhead will always be higher when
vde networking is used as compared to native pcap and/or tun/tap
networking.
Note 2: Root access will likely be needed to configure or start the vde
environment prior to starting a simulator which may use it.
Note 3: Simulators running using VDE networking can run without root
privilege.
Linux (Ubuntu 10.04):
apt-get install libvdeplug-dev
apt-get install vde2
vde_switch -s /tmp/switch1 -tap tap0 -m 666
ifconfig tap0 192.168.6.1 netmask 255.255.255.0 up
# Build and Run simulator and:
sim> attach xq vde:/tmp/switch1 #simulator uses IP address 192.168.6.2
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
@ -354,6 +378,7 @@ Dave
Change Log Change Log
=============================================================================== ===============================================================================
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX 29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX
17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and 17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and
vector assignments vector assignments

View file

@ -13,6 +13,7 @@
# #
ifeq ($(WIN32),) ifeq ($(WIN32),)
#*nix Environments (&& cygwin) #*nix Environments (&& cygwin)
GCC = gcc
ifeq (SunOS,$(shell uname)) ifeq (SunOS,$(shell uname))
TEST = /bin/test TEST = /bin/test
else else
@ -62,13 +63,18 @@ ifeq ($(WIN32),)
NETWORK_CCDEFS = -DUSE_NETWORK NETWORK_CCDEFS = -DUSE_NETWORK
NETWORK_LDFLAGS = -lpcap NETWORK_LDFLAGS = -lpcap
endif endif
ifeq (vde,$(shell if $(TEST) -e /usr/include/libvdeplug.h -a \( -e /usr/lib/libvdeplug.$(LIBEXT) -o -e /usr/lib64/libvdeplug.$(LIBEXT) \); then echo vde; fi))
# Provide support for vde networking
NETWORK_CCDEFS += -DUSE_VDE_NETWORK
NETWORK_LDFLAGS += -lvdeplug
endif
ifeq (tuntap,$(shell if $(TEST) -e /usr/include/linux/if_tun.h; then echo tuntap; fi)) ifeq (tuntap,$(shell if $(TEST) -e /usr/include/linux/if_tun.h; then echo tuntap; fi))
# Provide support for Tap networking on Linux # Provide support for Tap networking on Linux
NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK NETWORK_CCDEFS += -DUSE_TAP_NETWORK
endif endif
ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext; then echo bsdtuntap; fi)) ifeq (bsdtuntap,$(shell if $(TEST) -e /usr/include/net/if_tun.h -o -e /Library/Extensions/tap.kext; then echo bsdtuntap; fi))
# Provide support for Tap networking # Provide support for Tap networking
NETWORK_TAP_CCDEFS = -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP NETWORK_CCDEFS += -DUSE_TAP_NETWORK -DUSE_BSDTUNTAP
endif endif
ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi)) ifneq (binexists,$(shell if $(TEST) -e BIN; then echo binexists; fi))
MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi MKDIRBIN = if $(TEST) ! -e BIN; then mkdir BIN; fi
@ -79,6 +85,7 @@ ifeq ($(WIN32),)
endif endif
else else
#Win32 Environments (via MinGW32) #Win32 Environments (via MinGW32)
GCC = gcc
GCC_Path := $(dir $(shell where gcc.exe)) GCC_Path := $(dir $(shell where gcc.exe))
ifeq ($(NOASYNCH),) ifeq ($(NOASYNCH),)
ifeq (pthreads,$(shell if exist ..\pthreads\Pre-built.2\include\pthread.h echo pthreads)) ifeq (pthreads,$(shell if exist ..\pthreads\Pre-built.2\include\pthread.h echo pthreads))
@ -119,7 +126,7 @@ else
endif endif
CC = gcc -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(NETWORK_TAP_CCDEFS) $(OS_CCDEFS) $(ROMS_OPT) CC = $(GCC) -std=c99 -U__STRICT_ANSI__ -g -I . $(NETWORK_CCDEFS) $(OS_CCDEFS) $(ROMS_OPT)
LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS) LDFLAGS = $(OS_LDFLAGS) $(NETWORK_LDFLAGS)
# #

View file

@ -138,6 +138,15 @@
at open time. This functionality is only useful/needed at open time. This functionality is only useful/needed
on *nix platforms since native sharing of Windows NIC on *nix platforms since native sharing of Windows NIC
devices works with no external magic. devices works with no external magic.
USE_VDE_NETWORK - Specifies that support for vde networking should be
included. This can be leveraged, along with OS bridging
capabilities to share a single LAN interface. It also
can allow a simulator to have useful networking
functionality when running without root access. This
allows device names of the form vde:/tmp/switch to be
specified at open time. This functionality is only
available on *nix platforms since the vde api isn't
available on Windows.
NEED_PCAP_SENDPACKET NEED_PCAP_SENDPACKET
- Specifies that you are using an older version of libpcap - Specifies that you are using an older version of libpcap
@ -151,6 +160,11 @@
Modification history: Modification history:
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX
12-Aug-11 MP Cleaned up payload length determination
Fixed race condition detecting reflections when threaded
reading and writing is enabled
18-Apr-11 MP Fixed race condition with self loopback packets in 18-Apr-11 MP Fixed race condition with self loopback packets in
multithreaded environments multithreaded environments
09-Jan-11 MP Fixed missing crc data when USE_READER_THREAD is defined and 09-Jan-11 MP Fixed missing crc data when USE_READER_THREAD is defined and
@ -793,6 +807,10 @@ void eth_show_dev (FILE* st, ETH_DEV* dev)
#endif #endif
#endif /* USE_TAP_NETWORK */ #endif /* USE_TAP_NETWORK */
#ifdef USE_VDE_NETWORK
#include <libvdeplug.h>
#endif /* USE_VDE_NETWORK */
/* Allows windows to look up user-defined adapter names */ /* Allows windows to look up user-defined adapter names */
#if defined(_WIN32) #if defined(_WIN32)
#include <winreg.h> #include <winreg.h>
@ -1092,10 +1110,12 @@ static void eth_get_nic_hw_addr(ETH_DEV* dev, char *devname)
if (!pcap_mac_if_win32(devname, (UCHAR *)&dev->host_nic_phy_hw_addr)) if (!pcap_mac_if_win32(devname, (UCHAR *)&dev->host_nic_phy_hw_addr))
dev->have_host_nic_phy_addr = 1; dev->have_host_nic_phy_addr = 1;
#elif !defined (__VMS) #elif !defined (__VMS)
{ if (1) {
char command[1024]; char command[1024];
FILE *f; FILE *f;
if (0 == strncmp("vde:", devname, 4))
return;
memset(command, 0, sizeof(command)); memset(command, 0, sizeof(command));
snprintf(command, sizeof(command)-1, "ifconfig %s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F] >NIC.hwaddr", devname); snprintf(command, sizeof(command)-1, "ifconfig %s | grep [0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F] >NIC.hwaddr", devname);
system(command); system(command);
@ -1148,16 +1168,24 @@ int sched_policy;
struct sched_param sched_priority; struct sched_param sched_priority;
#if defined (_WIN32) #if defined (_WIN32)
HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle); HANDLE hWait = pcap_getevent ((pcap_t*)dev->handle);
#endif #else
#if defined (MUST_DO_SELECT)
struct timeval timeout;
int sel_ret; int sel_ret;
int pcap_fd; int do_select = 0;
int select_fd;
if (dev->pcap_mode) switch (dev->eth_api) {
pcap_fd = pcap_get_selectable_fd((pcap_t *)dev->handle); case ETH_API_PCAP:
else #if defined (MUST_DO_SELECT)
pcap_fd = dev->fd_handle; do_select = 1;
select_fd = pcap_get_selectable_fd((pcap_t *)dev->handle);
#endif
break;
case ETH_API_TAP:
case ETH_API_VDE:
do_select = 1;
select_fd = dev->fd_handle;
break;
}
#endif #endif
sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n"); sim_debug(dev->dbit, dev->dptr, "Reader Thread Starting\n");
@ -1169,32 +1197,35 @@ else
++sched_priority.sched_priority; ++sched_priority.sched_priority;
pthread_setschedparam (pthread_self(), sched_policy, &sched_priority); pthread_setschedparam (pthread_self(), sched_policy, &sched_priority);
while ((dev->pcap_mode && dev->handle) || dev->fd_handle) { while (dev->handle) {
#if defined (MUST_DO_SELECT)
fd_set setl;
FD_ZERO(&setl);
FD_SET(pcap_fd, &setl);
timeout.tv_sec = 0;
timeout.tv_usec = 250*1000;
sel_ret = select(1+pcap_fd, &setl, NULL, NULL, &timeout);
if (sel_ret < 0 && errno != EINTR) break;
if (sel_ret > 0) {
#else /* !MUST_DO_SELECT */
#if defined (_WIN32) #if defined (_WIN32)
if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) { if (WAIT_OBJECT_0 == WaitForSingleObject (hWait, 250)) {
#else #else
if (1) { fd_set setl;
#endif struct timeval timeout;
#endif /* MUST_DO_SELECT */
if ((dev->pcap_mode) && (!dev->handle)) if (do_select) {
break; FD_ZERO(&setl);
if ((!dev->pcap_mode) && (!dev->fd_handle)) FD_SET(select_fd, &setl);
timeout.tv_sec = 0;
timeout.tv_usec = 250*1000;
sel_ret = select(1+select_fd, &setl, NULL, NULL, &timeout);
}
else
sel_ret = 1;
if (sel_ret < 0 && errno != EINTR) break;
if (sel_ret > 0) {
#endif /* _WIN32 */
if (!dev->handle)
break; break;
/* dispatch read request queue available packets */ /* dispatch read request queue available packets */
if (dev->pcap_mode) switch (dev->eth_api) {
case ETH_API_PCAP:
status = pcap_dispatch ((pcap_t*)dev->handle, -1, &_eth_callback, (u_char*)dev); status = pcap_dispatch ((pcap_t*)dev->handle, -1, &_eth_callback, (u_char*)dev);
break;
#ifdef USE_TAP_NETWORK #ifdef USE_TAP_NETWORK
else { case ETH_API_TAP:
if (1) {
struct pcap_pkthdr header; struct pcap_pkthdr header;
int len; int len;
u_char buf[ETH_MAX_JUMBO_FRAME]; u_char buf[ETH_MAX_JUMBO_FRAME];
@ -1205,14 +1236,35 @@ else
status = 1; status = 1;
header.caplen = header.len = len; header.caplen = header.len = len;
_eth_callback((u_char *)dev, &header, buf); _eth_callback((u_char *)dev, &header, buf);
} else { }
else
status = 0; status = 0;
} }
} break;
#endif /* USE_TAP_NETWORK */ #endif /* USE_TAP_NETWORK */
#ifdef USE_VDE_NETWORK
case ETH_API_VDE:
if (1) {
struct pcap_pkthdr header;
int len;
u_char buf[ETH_MAX_JUMBO_FRAME];
memset(&header, 0, sizeof(header));
len = vde_recv((VDECONN *)dev->handle, buf, sizeof(buf), 0);
if (len > 0) {
status = 1;
header.caplen = header.len = len;
_eth_callback((u_char *)dev, &header, buf);
}
else
status = 0;
}
break;
#endif /* USE_VDE_NETWORK */
}
if ((status > 0) && (dev->asynch_io)) { if ((status > 0) && (dev->asynch_io)) {
int wakeup_needed; int wakeup_needed;
pthread_mutex_lock (&dev->lock); pthread_mutex_lock (&dev->lock);
wakeup_needed = (dev->read_queue.count != 0); wakeup_needed = (dev->read_queue.count != 0);
pthread_mutex_unlock (&dev->lock); pthread_mutex_unlock (&dev->lock);
@ -1246,7 +1298,7 @@ struct sched_param sched_priority;
sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n"); sim_debug(dev->dbit, dev->dptr, "Writer Thread Starting\n");
pthread_mutex_lock (&dev->writer_lock); pthread_mutex_lock (&dev->writer_lock);
while ((dev->pcap_mode && dev->handle) || dev->fd_handle) { while (dev->handle) {
pthread_cond_wait (&dev->writer_cond, &dev->writer_lock); pthread_cond_wait (&dev->writer_cond, &dev->writer_lock);
while (request = dev->write_requests) { while (request = dev->write_requests) {
/* Pull buffer off request list */ /* Pull buffer off request list */
@ -1330,7 +1382,8 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
savname = eth_getname(num, temp); savname = eth_getname(num, temp);
if (savname == 0) /* didn't translate */ if (savname == 0) /* didn't translate */
return SCPE_OPENERR; return SCPE_OPENERR;
} else { }
else {
/* are they trying to use device description? */ /* are they trying to use device description? */
savname = eth_getname_bydesc(name, temp); savname = eth_getname_bydesc(name, temp);
if (savname == 0) { /* didn't translate */ if (savname == 0) { /* didn't translate */
@ -1343,16 +1396,7 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
/* attempt to connect device */ /* attempt to connect device */
memset(errbuf, 0, sizeof(errbuf)); memset(errbuf, 0, sizeof(errbuf));
if (strncmp("tap:", savname, 4)) { if (0 == strncmp("tap:", savname, 4)) {
dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
if (!dev->handle) { /* can't open device */
msg = "Eth: pcap_open_live error - %s\r\n";
printf (msg, errbuf);
if (sim_log) fprintf (sim_log, msg, errbuf);
return SCPE_OPENERR;
}
dev->pcap_mode = 1;
} else {
int tun = -1; /* TUN/TAP Socket */ int tun = -1; /* TUN/TAP Socket */
int on = 1; int on = 1;
char dev_name[64] = ""; char dev_name[64] = "";
@ -1374,18 +1418,21 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
strcpy(ifr.ifr_name, savname+4); strcpy(ifr.ifr_name, savname+4);
ifr.ifr_flags = IFF_TAP|IFF_NO_PI; ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
// Send interface requests to TUN/TAP driver. /* Send interface requests to TUN/TAP driver. */
if (ioctl(tun, TUNSETIFF, &ifr) >= 0) { if (ioctl(tun, TUNSETIFF, &ifr) >= 0) {
if (ioctl(tun, FIONBIO, &on)) { if (ioctl(tun, FIONBIO, &on)) {
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
close(tun); close(tun);
} else { }
else {
dev->fd_handle = tun; dev->fd_handle = tun;
strcpy(savname, ifr.ifr_name); strcpy(savname, ifr.ifr_name);
} }
} else }
else
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
} else }
else
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
#elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK) #elif defined(USE_BSDTUNTAP) && defined(USE_TAP_NETWORK)
snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4); snprintf(dev_name, sizeof(dev_name)-1, "/dev/%s", savname+4);
@ -1395,7 +1442,8 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
if (ioctl(tun, FIONBIO, &on)) { if (ioctl(tun, FIONBIO, &on)) {
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1); strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
close(tun); close(tun);
} else { }
else {
dev->fd_handle = tun; dev->fd_handle = tun;
strcpy(savname, savname+4); strcpy(savname, savname+4);
} }
@ -1416,12 +1464,48 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
} }
} }
#endif #endif
} else {
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
} }
else
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
#else #else
strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1); strncpy(errbuf, "No support for tap: devices", sizeof(errbuf)-1);
#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */ #endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
if (0 == errbuf[0]) {
dev->eth_api = ETH_API_TAP;
dev->handle = (void *)1; /* Flag used to indicated open */
}
}
else
if (0 == strncmp("vde:", savname, 4)) {
#if defined(USE_VDE_NETWORK)
struct vde_open_args voa;
memset(&voa, 0, sizeof(voa));
if (!strcmp(savname, "vde:vdedevice")) {
msg = "Eth: Must specify actual vde device name (i.e. vde:/tmp/switch)\r\n";
printf (msg, errbuf);
if (sim_log) fprintf (sim_log, msg, errbuf);
return SCPE_OPENERR;
}
if (!(dev->handle = (void*) vde_open(savname+4, "simh", &voa)))
strncpy(errbuf, strerror(errno), sizeof(errbuf)-1);
else {
dev->eth_api = ETH_API_VDE;
dev->fd_handle = vde_datafd((VDECONN*)dev->handle);
}
#else
strncpy(errbuf, "No support for vde: network devices", sizeof(errbuf)-1);
#endif /* !defined(__linux) && !defined(USE_BSDTUNTAP) */
}
else {
dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf);
if (!dev->handle) { /* can't open device */
msg = "Eth: pcap_open_live error - %s\r\n";
printf (msg, errbuf);
if (sim_log) fprintf (sim_log, msg, errbuf);
return SCPE_OPENERR;
}
dev->eth_api = ETH_API_PCAP;
} }
if (errbuf[0]) { if (errbuf[0]) {
msg = "Eth: open error - %s\r\n"; msg = "Eth: open error - %s\r\n";
@ -1447,14 +1531,14 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
#if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__) #if !defined(HAS_PCAP_SENDPACKET) && defined (xBSD) && !defined (__APPLE__)
/* Tell the kernel that the header is fully-formed when it gets it. /* Tell the kernel that the header is fully-formed when it gets it.
This is required in order to fake the src address. */ This is required in order to fake the src address. */
if (dev->pcap_mode) { if (dev->eth_api == ETH_API_PCAP) {
int one = 1; int one = 1;
ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one); ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &one);
} }
#endif /* xBSD */ #endif /* xBSD */
#if defined (USE_READER_THREAD) #if defined (USE_READER_THREAD)
{ if (1) {
pthread_attr_t attr; pthread_attr_t attr;
#if defined(_WIN32) #if defined(_WIN32)
@ -1474,7 +1558,7 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
#else /* !defined (USE_READER_THREAD */ #else /* !defined (USE_READER_THREAD */
#ifdef USE_SETNONBLOCK #ifdef USE_SETNONBLOCK
/* set ethernet device non-blocking so pcap_dispatch() doesn't hang */ /* set ethernet device non-blocking so pcap_dispatch() doesn't hang */
if (dev->pcap_mode && (pcap_setnonblock (dev->handle, 1, errbuf) == -1)) { if ((dev->eth_api == ETH_API_PCAP) && (pcap_setnonblock (dev->handle, 1, errbuf) == -1)) {
msg = "Eth: Failed to set non-blocking: %s\r\n"; msg = "Eth: Failed to set non-blocking: %s\r\n";
printf (msg, errbuf); printf (msg, errbuf);
if (sim_log) fprintf (sim_log, msg, errbuf); if (sim_log) fprintf (sim_log, msg, errbuf);
@ -1482,7 +1566,7 @@ t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
#endif #endif
#endif /* !defined (USE_READER_THREAD */ #endif /* !defined (USE_READER_THREAD */
#if defined (__APPLE__) #if defined (__APPLE__)
if (dev->pcap_mode) { if (dev->eth_api == ETH_API_PCAP) {
/* Deliver packets immediately, needed for OS X 10.6.2 and later /* Deliver packets immediately, needed for OS X 10.6.2 and later
* (Snow-Leopard). * (Snow-Leopard).
* See this thread on libpcap and Mac Os X 10.6 Snow Leopard on * See this thread on libpcap and Mac Os X 10.6 Snow Leopard on
@ -1520,7 +1604,6 @@ t_stat eth_close(ETH_DEV* dev)
pthread_cond_destroy (&dev->writer_cond); pthread_cond_destroy (&dev->writer_cond);
if (1) { if (1) {
struct write_request *buffer; struct write_request *buffer;
while (buffer = dev->write_buffers) { while (buffer = dev->write_buffers) {
dev->write_buffers = buffer->next; dev->write_buffers = buffer->next;
free(buffer); free(buffer);
@ -1533,12 +1616,21 @@ t_stat eth_close(ETH_DEV* dev)
ethq_destroy (&dev->read_queue); /* release FIFO queue */ ethq_destroy (&dev->read_queue); /* release FIFO queue */
#endif #endif
if (dev->pcap_mode) switch (dev->eth_api) {
case ETH_API_PCAP:
pcap_close(pcap); pcap_close(pcap);
break;
#ifdef USE_TAP_NETWORK #ifdef USE_TAP_NETWORK
else case ETH_API_TAP:
close(pcap_fd); close(pcap_fd);
break;
#endif #endif
#ifdef USE_VDE_NETWORK
case ETH_API_VDE:
vde_close((VDECONN*)pcap);
break;
#endif
}
printf (msg, dev->name); printf (msg, dev->name);
if (sim_log) fprintf (sim_log, msg, dev->name); if (sim_log) fprintf (sim_log, msg, dev->name);
@ -1645,13 +1737,28 @@ t_stat _eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
} }
/* dispatch write request (synchronous; no need to save write info to dev) */ /* dispatch write request (synchronous; no need to save write info to dev) */
if (dev->pcap_mode) switch (dev->eth_api) {
case ETH_API_PCAP:
status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len); status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len);
break;
#ifdef USE_TAP_NETWORK #ifdef USE_TAP_NETWORK
else case ETH_API_TAP:
status = ((packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1); status = ((packet->len == write(dev->fd_handle, (void *)packet->msg, packet->len)) ? 0 : -1);
break;
#endif #endif
#ifdef USE_VDE_NETWORK
case ETH_API_VDE:
status = vde_send((VDECONN*)dev->handle, (void *)packet->msg, packet->len, 0);
if ((status == packet->len) || (status == 0))
status = 0;
else
if ((status == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
status = 0;
else
status = 1;
break;
#endif
}
/* On error, correct loopback bookkeeping */ /* On error, correct loopback bookkeeping */
if ((status != 0) && loopback_self_frame) { if ((status != 0) && loopback_self_frame) {
#ifdef USE_READER_THREAD #ifdef USE_READER_THREAD
@ -1710,7 +1817,8 @@ t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
++write_queue_size; ++write_queue_size;
} }
last_request->next = request; last_request->next = request;
} else }
else
dev->write_requests = request; dev->write_requests = request;
if (write_queue_size > dev->write_queue_peak) if (write_queue_size > dev->write_queue_peak)
dev->write_queue_peak = write_queue_size; dev->write_queue_peak = write_queue_size;
@ -1762,12 +1870,14 @@ _eth_hash_validate(ETH_MAC *MultiCastList, int count, ETH_MULTIHASH hash)
lhash[0], lhash[1], lhash[2], lhash[3], lhash[0], lhash[1], lhash[2], lhash[3],
lhash[4], lhash[5], lhash[6], lhash[7]); lhash[4], lhash[5], lhash[6], lhash[7]);
} }
else {
printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n", printf("Should be: %02X %02X %02X %02X %02X %02X %02X %02X\n",
hash[0], hash[1], hash[2], hash[3], hash[0], hash[1], hash[2], hash[3],
hash[4], hash[5], hash[6], hash[7]); hash[4], hash[5], hash[6], hash[7]);
printf("Was: %02X %02X %02X %02X %02X %02X %02X %02X\n", printf("Was: %02X %02X %02X %02X %02X %02X %02X %02X\n",
lhash[0], lhash[1], lhash[2], lhash[3], lhash[0], lhash[1], lhash[2], lhash[3],
lhash[4], lhash[5], lhash[6], lhash[7]); lhash[4], lhash[5], lhash[6], lhash[7]);
}
return 0; return 0;
} }
@ -2000,7 +2110,8 @@ _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
if (payload_len > mtu_payload) { if (payload_len > mtu_payload) {
ip_flags |= IP_MF_FLAG; ip_flags |= IP_MF_FLAG;
IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP)); IP->total_len = htons(((mtu_payload>>3)<<3) + IP_HLEN(IP));
} else { }
else {
IP->total_len = htons(payload_len + IP_HLEN(IP)); IP->total_len = htons(payload_len + IP_HLEN(IP));
} }
IP->flags = htons(ip_flags); IP->flags = htons(ip_flags);
@ -2009,7 +2120,8 @@ _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
header.caplen = header.len = 14 + ntohs(IP->total_len); header.caplen = header.len = 14 + ntohs(IP->total_len);
eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment"); eth_packet_trace (dev, ((u_char *)IP)-14, header.len, "reading Datagram fragment");
#if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET #if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
{ /* Debugging is easier if we read packets directly with pcap if (1) {
/* Debugging is easier if we read packets directly with pcap
(i.e. we can use Wireshark to verify packet contents) (i.e. we can use Wireshark to verify packet contents)
we don't want to do this all the time for 2 reasons: we don't want to do this all the time for 2 reasons:
1) sending through pcap involves kernel transitions and 1) sending through pcap involves kernel transitions and
@ -2050,7 +2162,8 @@ _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
if (payload_len > mtu_payload) { if (payload_len > mtu_payload) {
TCP->data_offset_and_flags = htons(orig_tcp_flags&~(TCP_PSH_FLAG|TCP_FIN_FLAG|TCP_RST_FLAG)); TCP->data_offset_and_flags = htons(orig_tcp_flags&~(TCP_PSH_FLAG|TCP_FIN_FLAG|TCP_RST_FLAG));
IP->total_len = htons(mtu_payload + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); IP->total_len = htons(mtu_payload + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
} else { }
else {
TCP->data_offset_and_flags = htons(orig_tcp_flags); TCP->data_offset_and_flags = htons(orig_tcp_flags);
IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP)); IP->total_len = htons(payload_len + IP_HLEN(IP) + TCP_DATA_OFFSET(TCP));
} }
@ -2061,7 +2174,8 @@ _eth_fix_ip_jumbo_offload(ETH_DEV* dev, const u_char* msg, int len)
header.caplen = header.len = 14 + ntohs(IP->total_len); header.caplen = header.len = 14 + ntohs(IP->total_len);
eth_packet_trace_ex (dev, ((u_char *)IP)-14, header.len, "reading TCP segment", 1, dev->dbit); eth_packet_trace_ex (dev, ((u_char *)IP)-14, header.len, "reading TCP segment", 1, dev->dbit);
#if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET #if ETH_MIN_JUMBO_FRAME < ETH_MAX_PACKET
{ /* Debugging is easier if we read packets directly with pcap if (1) {
/* Debugging is easier if we read packets directly with pcap
(i.e. we can use Wireshark to verify packet contents) (i.e. we can use Wireshark to verify packet contents)
we don't want to do this all the time for 2 reasons: we don't want to do this all the time for 2 reasons:
1) sending through pcap involves kernel transitions and 1) sending through pcap involves kernel transitions and
@ -2155,19 +2269,27 @@ static void
_eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data) _eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data)
{ {
ETH_DEV* dev = (ETH_DEV*) info; ETH_DEV* dev = (ETH_DEV*) info;
#ifdef USE_BPF int to_me;
int to_me = 1; int from_me = 0;
int i;
int bpf_used;
switch (dev->eth_api) {
case ETH_API_PCAP:
#ifdef USE_BPF
bpf_used = 1;
to_me = 1;
/* AUTODIN II hash mode? */ /* AUTODIN II hash mode? */
if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast)) if ((dev->hash_filter) && (data[0] & 0x01) && (!dev->promiscuous) && (!dev->all_multicast))
to_me = _eth_hash_lookup(dev->hash, data); to_me = _eth_hash_lookup(dev->hash, data);
#else /* !USE_BPF */ break;
int to_me = 0; #endif /* USE_BPF */
int from_me = 0; case ETH_API_TAP:
int i; case ETH_API_VDE:
bpf_used = 0;
to_me = 0;
eth_packet_trace (dev, data, header->len, "received"); eth_packet_trace (dev, data, header->len, "received");
f
for (i = 0; i < dev->addr_count; i++) { for (i = 0; i < dev->addr_count; i++) {
if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1; if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1;
if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1; if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1;
@ -2182,7 +2304,8 @@ f
/* AUTODIN II hash mode? */ /* AUTODIN II hash mode? */
if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01)) if ((dev->hash_filter) && (!to_me) && (data[0] & 0x01))
to_me = _eth_hash_lookup(dev->hash, data); to_me = _eth_hash_lookup(dev->hash, data);
#endif /* USE_BPF */ break;
}
/* detect reception of loopback packet to our physical address */ /* detect reception of loopback packet to our physical address */
if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) { if (LOOPBACK_SELF_FRAME(dev->physical_addr, data)) {
@ -2196,20 +2319,15 @@ f
dev->loopback_self_sent--; dev->loopback_self_sent--;
to_me = 0; to_me = 0;
} }
#ifndef USE_BPF
else else
if (!bpf_used)
from_me = 0; from_me = 0;
#endif
#ifdef USE_READER_THREAD #ifdef USE_READER_THREAD
pthread_mutex_unlock (&dev->self_lock); pthread_mutex_unlock (&dev->self_lock);
#endif #endif
} }
#ifdef USE_BPF if (bpf_used ? to_me : (to_me && !from_me)) {
if (to_me) {
#else /* !USE_BPF */
if (to_me && !from_me) {
#endif
if (header->len > ETH_MIN_JUMBO_FRAME) { if (header->len > ETH_MIN_JUMBO_FRAME) {
if (header->len <= header->caplen) /* Whole Frame captured? */ if (header->len <= header->caplen) /* Whole Frame captured? */
_eth_fix_ip_jumbo_offload(dev, data, header->len); _eth_fix_ip_jumbo_offload(dev, data, header->len);
@ -2247,7 +2365,7 @@ f
pthread_mutex_unlock (&dev->lock); pthread_mutex_unlock (&dev->lock);
free(moved_data); free(moved_data);
} }
#else #else /* !USE_READER_THREAD */
/* set data in passed read packet */ /* set data in passed read packet */
dev->read_packet->len = header->len; dev->read_packet->len = header->len;
memcpy(dev->read_packet->msg, data, header->len); memcpy(dev->read_packet->msg, data, header->len);
@ -2298,10 +2416,13 @@ int eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
/* dispatch read request to either receive a filtered packet or timeout */ /* dispatch read request to either receive a filtered packet or timeout */
do { do {
if (dev->pcap_mode) switch (dev->eth_api) {
case ETH_API_PCAP:
status = pcap_dispatch((pcap_t*)dev->handle, 1, &_eth_callback, (u_char*)dev); status = pcap_dispatch((pcap_t*)dev->handle, 1, &_eth_callback, (u_char*)dev);
break;
#ifdef USE_TAP_NETWORK #ifdef USE_TAP_NETWORK
else { case ETH_API_TAP:
if (1) {
struct pcap_pkthdr header; struct pcap_pkthdr header;
int len; int len;
u_char buf[ETH_MAX_JUMBO_FRAME]; u_char buf[ETH_MAX_JUMBO_FRAME];
@ -2312,11 +2433,32 @@ int eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine)
status = 1; status = 1;
header.caplen = header.len = len; header.caplen = header.len = len;
_eth_callback((u_char *)dev, &header, buf); _eth_callback((u_char *)dev, &header, buf);
} else { }
else
status = 0; status = 0;
} }
} break;
#endif /* USE_TAP_NETWORK */ #endif /* USE_TAP_NETWORK */
#ifdef USE_VDE_NETWORK
case ETH_API_VDE:
if (1) {
struct pcap_pkthdr header;
int len;
u_char buf[ETH_MAX_JUMBO_FRAME];
memset(&header, 0, sizeof(header));
len = vde_recv((VDECONN*)dev->handle, buf, sizeof(buf), 0);
if (len > 0) {
status = 1;
header.caplen = header.len = len;
_eth_callback((u_char *)dev, &header, buf);
}
else
status = 0;
}
break;
#endif /* USE_VDE_NETWORK */
}
} while ((status) && (0 == packet->len)); } while ((status) && (0 == packet->len));
#else /* USE_READER_THREAD */ #else /* USE_READER_THREAD */
@ -2484,12 +2626,11 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf); sim_debug(dev->dbit, dev->dptr, "BPF string is: |%s|\n", buf);
/* get netmask, which is required for compiling */ /* get netmask, which is required for compiling */
if (dev->pcap_mode && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0)) { if ((dev->eth_api == ETH_API_PCAP) && (pcap_lookupnet(dev->handle, &bpf_subnet, &bpf_netmask, errbuf)<0))
bpf_netmask = 0; bpf_netmask = 0;
}
#ifdef USE_BPF #ifdef USE_BPF
if (dev->pcap_mode) { if (dev->eth_api == ETH_API_PCAP) {
/* compile filter string */ /* compile filter string */
if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) { if ((status = pcap_compile(dev->handle, &bpf, buf, 1, bpf_netmask)) < 0) {
sprintf(errbuf, "%s", pcap_geterr(dev->handle)); sprintf(errbuf, "%s", pcap_geterr(dev->handle));
@ -2501,7 +2642,8 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
msg = "Eth: BPF string is: |%s|\r\n"; msg = "Eth: BPF string is: |%s|\r\n";
printf (msg, buf); printf (msg, buf);
if (sim_log) fprintf (sim_log, msg, buf); if (sim_log) fprintf (sim_log, msg, buf);
} else { }
else {
/* apply compiled filter string */ /* apply compiled filter string */
if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) { if ((status = pcap_setfilter(dev->handle, &bpf)) < 0) {
sprintf(errbuf, "%s", pcap_geterr(dev->handle)); sprintf(errbuf, "%s", pcap_geterr(dev->handle));
@ -2509,7 +2651,8 @@ t_stat eth_filter_hash(ETH_DEV* dev, int addr_count, ETH_MAC* const addresses,
printf(msg, errbuf); printf(msg, errbuf);
if (sim_log) fprintf (sim_log, msg, errbuf); if (sim_log) fprintf (sim_log, msg, errbuf);
sim_debug(dev->dbit, dev->dptr, "Eth: pcap_setfilter error: %s\n", errbuf); sim_debug(dev->dbit, dev->dptr, "Eth: pcap_setfilter error: %s\n", errbuf);
} else { }
else {
#ifdef USE_SETNONBLOCK #ifdef USE_SETNONBLOCK
/* set file non-blocking */ /* set file non-blocking */
status = pcap_setnonblock (dev->handle, 1, errbuf); status = pcap_setnonblock (dev->handle, 1, errbuf);
@ -2584,9 +2727,8 @@ int eth_host_devices(int used, int max, ETH_LIST* list)
sprintf( regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\" sprintf( regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\"
"{4D36E972-E325-11CE-BFC1-08002BE10318}\\%hs\\Connection", list[i].name+ "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%hs\\Connection", list[i].name+
strlen( "\\Device\\NPF_" ) ); strlen( "\\Device\\NPF_" ) );
if((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, &reghnd)) != ERROR_SUCCESS) { if ((status = RegOpenKeyExA (HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, &reghnd)) != ERROR_SUCCESS)
continue; continue;
}
reglen = sizeof(regval); reglen = sizeof(regval);
/* look for user-defined adapter name, bail if not found */ /* look for user-defined adapter name, bail if not found */
@ -2619,6 +2761,14 @@ int eth_host_devices(int used, int max, ETH_LIST* list)
++used; ++used;
} }
#endif #endif
#ifdef USE_VDE_NETWORK
if (used < max) {
list[used].num = used;
sprintf(list[used].name, "%s", "vde:device");
sprintf(list[used].desc, "%s", "Integrated VDE support");
++used;
}
#endif
return used; return used;
} }
@ -2636,7 +2786,8 @@ int eth_devices(int max, ETH_LIST* list)
char* msg = "Eth: error in pcap_findalldevs: %s\r\n"; char* msg = "Eth: error in pcap_findalldevs: %s\r\n";
printf (msg, errbuf); printf (msg, errbuf);
if (sim_log) fprintf (sim_log, msg, errbuf); if (sim_log) fprintf (sim_log, msg, errbuf);
} else { }
else {
/* copy device list into the passed structure */ /* copy device list into the passed structure */
for (i=0, dev=alldevs; dev; dev=dev->next) { for (i=0, dev=alldevs; dev; dev=dev->next) {
if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue; if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) continue;

View file

@ -28,6 +28,7 @@
Modification history: Modification history:
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
18-Apr-11 MP Fixed race condition with self loopback packets in 18-Apr-11 MP Fixed race condition with self loopback packets in
multithreaded environments multithreaded environments
09-Dec-10 MP Added support to determine if network address conflicts exist 09-Dec-10 MP Added support to determine if network address conflicts exist
@ -89,13 +90,13 @@
#if defined (USE_READER_THREAD) #if defined (USE_READER_THREAD)
#if defined (USE_SETNONBLOCK) #if defined (USE_SETNONBLOCK)
#undef USE_SETNONBLOCK #undef USE_SETNONBLOCK
#endif #endif /* USE_SETNONBLOCK */
#undef PCAP_READ_TIMEOUT #undef PCAP_READ_TIMEOUT
#define PCAP_READ_TIMEOUT 15 #define PCAP_READ_TIMEOUT 15
#if !defined (xBSD) && !defined(_WIN32) && !defined(VMS) #if (!defined (xBSD) && !defined(_WIN32) && !defined(VMS)) || defined (USE_TAP_NETWORK) || defined (USE_VDE_NETWORK)
#define MUST_DO_SELECT #define MUST_DO_SELECT 1
#endif
#endif #endif
#endif /* USE_READER_THREAD */
/* /*
USE_BPF is defined to let this code leverage the libpcap/OS kernel provided USE_BPF is defined to let this code leverage the libpcap/OS kernel provided
@ -175,7 +176,10 @@ struct eth_device {
char* name; /* name of ethernet device */ char* name; /* name of ethernet device */
void* handle; /* handle of implementation-specific device */ void* handle; /* handle of implementation-specific device */
int fd_handle; /* fd to kernel device (where needed) */ int fd_handle; /* fd to kernel device (where needed) */
int pcap_mode; /* Flag indicating if pcap API are being used to move packets */ int eth_api; /* Designator for which API is being used to move packets */
#define ETH_API_PCAP 0 /* Pcap API in use */
#define ETH_API_TAP 1 /* tun/tap API in use */
#define ETH_API_VDE 2 /* VDE API in use */
ETH_PCALLBACK read_callback; /* read callback function */ ETH_PCALLBACK read_callback; /* read callback function */
ETH_PCALLBACK write_callback; /* write callback function */ ETH_PCALLBACK write_callback; /* write callback function */
ETH_PACK* read_packet; /* read packet */ ETH_PACK* read_packet; /* read packet */