- Welcome usable qemu pcap networking! :)

1. Fix packet delays. [1]
  2. Truncate oversize packets according to host interface's MTU
     to avoid e.g. Linux guests panic'ing.
     Note:  This is only necessary as a stopgap measure for cases like
     host inferfaces using TSO (it still causes retransmissions),
     the better workaround is to disable the feature on the host
     interface while using qemu's pcap code.
- Add note about pcap to pkg-message.s
- Bump PORTREVISIONs.

Submitted by:	jkim [1]
This commit is contained in:
Juergen Lock 2010-02-04 20:27:30 +00:00
parent b3743b6bd3
commit 47de8e10d8
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=249241
6 changed files with 186 additions and 112 deletions

View file

@ -7,6 +7,7 @@
PORTNAME= qemu PORTNAME= qemu
PORTVERSION= 0.12.2 PORTVERSION= 0.12.2
PORTREVISION= 1
CATEGORIES= emulators CATEGORIES= emulators
MASTER_SITES= ${MASTER_SITE_SAVANNAH}:release \ MASTER_SITES= ${MASTER_SITE_SAVANNAH}:release \
${MASTER_SITE_LOCAL}:snapshot \ ${MASTER_SITE_LOCAL}:snapshot \

View file

@ -1,4 +1,5 @@
Index: configure --- configure.orig 2010-01-29 14:36:00.000000000 -0500
+++ configure 2010-01-29 14:36:00.000000000 -0500
@@ -257,6 +257,9 @@ pkgversion="" @@ -257,6 +257,9 @@ pkgversion=""
check_utests="no" check_utests="no"
user_pie="no" user_pie="no"
@ -84,7 +85,8 @@ Index: configure
if test "$slirp" = "yes" ; then if test "$slirp" = "yes" ; then
echo "CONFIG_SLIRP=y" >> $config_host_mak echo "CONFIG_SLIRP=y" >> $config_host_mak
QEMU_CFLAGS="-I\$(SRC_PATH)/slirp $QEMU_CFLAGS" QEMU_CFLAGS="-I\$(SRC_PATH)/slirp $QEMU_CFLAGS"
Index: net.h --- net.h.orig 2010-01-29 14:36:00.000000000 -0500
+++ net.h 2010-01-29 14:36:00.000000000 -0500
@@ -33,7 +33,8 @@ typedef enum { @@ -33,7 +33,8 @@ typedef enum {
NET_CLIENT_TYPE_TAP, NET_CLIENT_TYPE_TAP,
NET_CLIENT_TYPE_SOCKET, NET_CLIENT_TYPE_SOCKET,
@ -96,16 +98,19 @@ Index: net.h
typedef int (NetCanReceive)(VLANClientState *); typedef int (NetCanReceive)(VLANClientState *);
Index: net.c Index: net.c
@@ -36,6 +36,8 @@ @@ -36,6 +36,11 @@
#include "qemu-common.h" #include "qemu-common.h"
#include "qemu_socket.h" #include "qemu_socket.h"
+#include <sys/ioctl.h> +#include <sys/ioctl.h>
+#ifdef __FreeBSD__
+#include <net/if.h>
+#endif
+ +
static QTAILQ_HEAD(, VLANState) vlans; static QTAILQ_HEAD(, VLANState) vlans;
static QTAILQ_HEAD(, VLANClientState) non_vlan_clients; static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
@@ -820,6 +822,212 @@ static int net_init_nic(QemuOpts *opts, @@ -820,6 +825,228 @@ static int net_init_nic(QemuOpts *opts,
return idx; return idx;
} }
@ -119,6 +124,7 @@ Index: net.c
+typedef struct PCAPState { +typedef struct PCAPState {
+ VLANClientState nc; + VLANClientState nc;
+ pcap_t *handle; + pcap_t *handle;
+ int max_eth_frame_size;
+} PCAPState; +} PCAPState;
+ +
+static ssize_t pcap_receive(VLANClientState *nc, const uint8_t *buf, size_t size) +static ssize_t pcap_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
@ -128,27 +134,33 @@ Index: net.c
+ return pcap_inject(s->handle, (u_char*)buf, size); + return pcap_inject(s->handle, (u_char*)buf, size);
+} +}
+ +
+#define MAX_ETH_FRAME_SIZE 1514
+
+static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char *pdata) +static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char *pdata)
+{ +{
+ VLANClientState *vc = (VLANClientState *)user; + VLANClientState *nc = (VLANClientState *)user;
+ int len = phdr->len;
+ +
+ if (len > MAX_ETH_FRAME_SIZE) { + int len = phdr->len;
+#ifdef __FreeBSD__
+ PCAPState *s = DO_UPCAST(PCAPState, nc, nc);
+ int max_eth_frame_size = s->max_eth_frame_size;
+
+ if (len > max_eth_frame_size) {
+ fprintf(stderr, + fprintf(stderr,
+ "pcap_send: packet size > %d (%d), truncating\n", + "pcap_send: packet size > %d (%d), truncating\n",
+ MAX_ETH_FRAME_SIZE, len); + max_eth_frame_size, len);
+ len = MAX_ETH_FRAME_SIZE; + len = max_eth_frame_size;
+ } + }
+ qemu_send_packet(vc, pdata, len); +#endif
+ qemu_send_packet(nc, pdata, len);
+} +}
+ +
+static void pcap_send(void *opaque) +static void pcap_send(void *opaque)
+{ +{
+ PCAPState *s = (PCAPState *)opaque; + PCAPState *s = (PCAPState *)opaque;
+ +
+ pcap_dispatch(s->handle, 1, (pcap_handler)&pcap_callback, (u_char *)&s->nc); + for (;;) {
+ if (pcap_dispatch(s->handle, 0, (pcap_handler)&pcap_callback, (u_char *)&s->nc) >= 0)
+ break;
+ }
+} +}
+ +
+static void pcap_cleanup(VLANClientState *nc) +static void pcap_cleanup(VLANClientState *nc)
@ -162,10 +174,6 @@ Index: net.c
+ .type = NET_CLIENT_TYPE_PCAP, + .type = NET_CLIENT_TYPE_PCAP,
+ .size = sizeof(PCAPState), + .size = sizeof(PCAPState),
+ .receive = pcap_receive, + .receive = pcap_receive,
+#if 0
+ .receive_raw = tap_receive_raw,
+ .receive_iov = tap_receive_iov,
+#endif
+ .cleanup = pcap_cleanup, + .cleanup = pcap_cleanup,
+}; +};
+ +
@ -181,52 +189,65 @@ Index: net.c
+ +
+ s = qemu_mallocz(sizeof(PCAPState)); + s = qemu_mallocz(sizeof(PCAPState));
+ nc = qemu_new_net_client(&net_pcap_info, vlan, NULL, model, name); + nc = qemu_new_net_client(&net_pcap_info, vlan, NULL, model, name);
+#if 0
+ nc = qemu_new_vlan_client(NET_CLIENT_TYPE_PCAP,
+ vlan, NULL, model, name, NULL,
+ pcap_receive, NULL, NULL,
+ pcap_cleanup, s);
+#endif
+ +
+ s = DO_UPCAST(PCAPState, nc, nc); + s = DO_UPCAST(PCAPState, nc, nc);
+ if (!s) + if (!s)
+ return -1; + return -1;
+ +
+ if (ifname == NULL && (ifname = pcap_lookupdev(errbuf)) == NULL) { + if (ifname == NULL && (ifname = pcap_lookupdev(errbuf)) == NULL) {
+ fprintf(stderr, "qemu: pcap_create: %s\n", errbuf); + fprintf(stderr, "qemu: pcap_create: %s\n", errbuf);
+ goto fail; + goto fail;
+ } + }
+ +
+#ifdef __FreeBSD__
+ /*
+ * We want to avoid passing oversize packets to the guest, which
+ * at least on FreeBSD can happen if the host interface uses tso
+ * (seen with an em(4) in this case) - so find out the host
+ * interface's mtu and assume the guest is configured the same.
+ */
+ s->max_eth_frame_size = 1514;
+ i = socket(AF_INET, SOCK_DGRAM, 0);
+ if (i >= 0) {
+ struct ifreq ifr;
+
+ (void) memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(i, SIOCGIFMTU, &ifr) != -1)
+ s->max_eth_frame_size = ifr.ifr_mtu + 14;
+ close(i);
+ }
+#endif
+#if defined(CONFIG_PCAP_CREATE) || defined(_WIN32) +#if defined(CONFIG_PCAP_CREATE) || defined(_WIN32)
+ /* + /*
+ * Create pcap handle for the device, set promiscuous mode and activate. + * Create pcap handle for the device, set promiscuous mode and activate.
+ */ + */
+ s->handle = (void *)pcap_create(ifname, errbuf); + s->handle = (void *)pcap_create(ifname, errbuf);
+ if (!s->handle) { + if (!s->handle) {
+ fprintf(stderr, "qemu: pcap_create: %s\n", errbuf); + fprintf(stderr, "qemu: pcap_create: %s\n", errbuf);
+ goto fail; + goto fail;
+ } + }
+ if (pcap_set_promisc(s->handle, 1) != 0) { + if (pcap_set_promisc(s->handle, 1) != 0) {
+ pcap_perror(s->handle, "qemu: pcap_set_promisc:"); + pcap_perror(s->handle, "qemu: pcap_set_promisc:");
+ goto fail; + goto fail;
+ } + }
+ if (pcap_activate(s->handle) != 0) { + if (pcap_activate(s->handle) != 0) {
+ pcap_perror(s->handle, "qemu: pcap_activate:"); + pcap_perror(s->handle, "qemu: pcap_activate:");
+ goto fail; + goto fail;
+ } + }
+#else +#else
+ /* Attempt to connect device. */ + /* Attempt to connect device. */
+ s->handle = (void *)pcap_open_live(ifname, 65535, 1, 0, errbuf); + s->handle = (void *)pcap_open_live(ifname, 65535, 1, 0, errbuf);
+ if (!s->handle) { + if (!s->handle) {
+ fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf); + fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf);
+ goto fail; + goto fail;
+ } + }
+#endif +#endif
+ +
+ /* Set non-blocking mode. */ + /* Set non-blocking mode. */
+ if (pcap_setnonblock(s->handle, 1, errbuf) < 0) { + if (pcap_setnonblock(s->handle, 1, errbuf) < 0) {
+ fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf); + fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf);
+ goto fail; + goto fail;
+ } + }
+ +
+#if defined(_WIN32) +#if defined(_WIN32)
@ -234,8 +255,8 @@ Index: net.c
+ * Tell the kernel that the packet has to be seen immediately. + * Tell the kernel that the packet has to be seen immediately.
+ */ + */
+ if (pcap_setmintocopy(s->handle, 0) < 0) { + if (pcap_setmintocopy(s->handle, 0) < 0) {
+ fprintf(stderr, "qemu: pcap failed to set immediate mode\n"); + fprintf(stderr, "qemu: pcap failed to set immediate mode\n");
+ goto fail; + goto fail;
+ } + }
+#else /* !_WIN32 */ +#else /* !_WIN32 */
+#if defined(CONFIG_BPF) +#if defined(CONFIG_BPF)
@ -244,11 +265,11 @@ Index: net.c
+ * Tell the kernel that the packet has to be seen immediately. + * Tell the kernel that the packet has to be seen immediately.
+ */ + */
+ { + {
+ unsigned int one = 1; + unsigned int one = 1;
+ if (ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one) < 0) { + if (ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one) < 0) {
+ fprintf(stderr, "qemu: pcap failed to set immediate mode\n"); + fprintf(stderr, "qemu: pcap failed to set immediate mode\n");
+ goto fail; + goto fail;
+ } + }
+ } + }
+#endif /* BIOCIMMEDIATE */ +#endif /* BIOCIMMEDIATE */
+ +
@ -258,11 +279,11 @@ Index: net.c
+ * This is necessary to connect host and guest. + * This is necessary to connect host and guest.
+ */ + */
+ { + {
+ unsigned int one = 1; + unsigned int one = 1;
+ if (ioctl(pcap_fileno(s->handle), BIOCFEEDBACK, &one) < 0) { + if (ioctl(pcap_fileno(s->handle), BIOCFEEDBACK, &one) < 0) {
+ fprintf(stderr, "qemu: pcap failed to set feedback mode\n"); + fprintf(stderr, "qemu: pcap failed to set feedback mode\n");
+ goto fail; + goto fail;
+ } + }
+ } + }
+#endif /* BIOCFEEDBACK */ +#endif /* BIOCFEEDBACK */
+#endif /* CONFIG_BPF */ +#endif /* CONFIG_BPF */
@ -272,14 +293,14 @@ Index: net.c
+ +
+#if defined(_WIN32) +#if defined(_WIN32)
+ if ((h = pcap_getevent(s->handle)) == NULL) { + if ((h = pcap_getevent(s->handle)) == NULL) {
+ fprintf(stderr, "qemu: pcap_getevent failed\n"); + fprintf(stderr, "qemu: pcap_getevent failed\n");
+ goto fail; + goto fail;
+ } + }
+ qemu_add_wait_object(h, pcap_send, s); + qemu_add_wait_object(h, pcap_send, s);
+#else /* !_WIN32 */ +#else /* !_WIN32 */
+ if ((i = pcap_get_selectable_fd(s->handle)) < 0) { + if ((i = pcap_get_selectable_fd(s->handle)) < 0) {
+ fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n"); + fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n");
+ goto fail; + goto fail;
+ } + }
+ qemu_set_fd_handler(i, pcap_send, NULL, s); + qemu_set_fd_handler(i, pcap_send, NULL, s);
+#endif /* _WIN32 */ +#endif /* _WIN32 */
@ -288,9 +309,9 @@ Index: net.c
+ +
+fail: +fail:
+ if (s) { + if (s) {
+ if (s->handle) + if (s->handle)
+ pcap_close(s->handle); + pcap_close(s->handle);
+ qemu_free(s); + qemu_free(s);
+ } + }
+ +
+ return -1; + return -1;
@ -318,7 +339,7 @@ Index: net.c
#define NET_COMMON_PARAMS_DESC \ #define NET_COMMON_PARAMS_DESC \
{ \ { \
.name = "type", \ .name = "type", \
@@ -980,6 +1188,20 @@ static struct { @@ -980,6 +1207,20 @@ static struct {
#endif /* _WIN32 */ #endif /* _WIN32 */
{ /* end of list */ } { /* end of list */ }
}, },
@ -339,9 +360,9 @@ Index: net.c
}, { }, {
.type = "socket", .type = "socket",
.init = net_init_socket, .init = net_init_socket,
--- qemu-options.hx.orig 2009-08-28 16:46:21.000000000 -0400 --- qemu-options.hx.orig 2010-01-14 17:18:00.000000000 -0500
+++ qemu-options.hx 2009-09-02 16:20:14.000000000 -0400 +++ qemu-options.hx 2010-01-29 14:36:00.000000000 -0500
@@ -783,6 +783,10 @@ @@ -799,6 +799,10 @@ DEF("smb", HAS_ARG, QEMU_OPTION_smb, "")
DEF("net", HAS_ARG, QEMU_OPTION_net, DEF("net", HAS_ARG, QEMU_OPTION_net,
"-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n" "-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v]\n"
" create a new Network Interface Card and connect it to VLAN 'n'\n" " create a new Network Interface Card and connect it to VLAN 'n'\n"

View file

@ -122,6 +122,13 @@ if a guest cannot eject it itself.)
- The default configuration location (qemu-ifup script etc.) has been - The default configuration location (qemu-ifup script etc.) has been
changed from /etc to PREFIX/etc (usually /usr/local/etc). Move your changed from /etc to PREFIX/etc (usually /usr/local/etc). Move your
files accordingly. files accordingly.
- The pcap code (-net nic... -net pcap,ifname=...) should work properly
now, with only one exception: Advanced features like TSO used on the host
interface can cause oversize packets which now do get truncated to avoid
confusing/panicing guests but of course still will cause retransmissions.
So if you see slow throughput and `pcap_send: packet size > ..., truncating'
messages on qemu's tty try disabling TSO etc on the host interface at least
while using pcap.
- kqemu is no longer supported in qemu upstream after the 0.11 branch - kqemu is no longer supported in qemu upstream after the 0.11 branch
was created, which means also not in this version. (Linux has moved was created, which means also not in this version. (Linux has moved
on to kvm now for qemu(-like) virtualization needs, so if you want qemu on to kvm now for qemu(-like) virtualization needs, so if you want qemu

View file

@ -7,6 +7,7 @@
PORTNAME= qemu PORTNAME= qemu
PORTVERSION= 0.11.1 PORTVERSION= 0.11.1
PORTREVISION= 1
CATEGORIES= emulators CATEGORIES= emulators
MASTER_SITES= ${MASTER_SITE_SAVANNAH} \ MASTER_SITES= ${MASTER_SITE_SAVANNAH} \
http://bellard.org/qemu/ http://bellard.org/qemu/

View file

@ -1,6 +1,6 @@
--- Makefile.target.orig 2008-07-18 15:18:11.000000000 -0400 --- Makefile.target.orig 2010-01-29 14:39:26.000000000 -0500
+++ Makefile.target 2008-07-18 15:23:11.000000000 -0400 +++ Makefile.target 2010-01-29 14:39:28.000000000 -0500
@@ -619,6 +619,13 @@ @@ -616,6 +616,13 @@ ifdef CONFIG_COREAUDIO
COCOA_LIBS+=-framework CoreAudio COCOA_LIBS+=-framework CoreAudio
endif endif
endif endif
@ -14,8 +14,9 @@
ifdef CONFIG_SLIRP ifdef CONFIG_SLIRP
CPPFLAGS+=-I$(SRC_PATH)/slirp CPPFLAGS+=-I$(SRC_PATH)/slirp
endif endif
Index: configure --- configure.orig 2010-01-29 14:39:26.000000000 -0500
@@ -203,6 +203,9 @@ +++ configure 2010-01-29 14:39:27.000000000 -0500
@@ -203,6 +203,9 @@ sdl="yes"
sdl_x11="no" sdl_x11="no"
xen="yes" xen="yes"
pkgversion="" pkgversion=""
@ -25,7 +26,7 @@ Index: configure
# OS specific # OS specific
if check_define __linux__ ; then if check_define __linux__ ; then
@@ -428,6 +431,8 @@ @@ -428,6 +431,8 @@ for opt do
;; ;;
--disable-vnc-sasl) vnc_sasl="no" --disable-vnc-sasl) vnc_sasl="no"
;; ;;
@ -34,7 +35,7 @@ Index: configure
--disable-slirp) slirp="no" --disable-slirp) slirp="no"
;; ;;
--disable-vde) vde="no" --disable-vde) vde="no"
@@ -925,6 +930,48 @@ @@ -925,6 +930,48 @@ EOF
fi fi
########################################## ##########################################
@ -83,7 +84,7 @@ Index: configure
# VNC TLS detection # VNC TLS detection
if test "$vnc_tls" = "yes" ; then if test "$vnc_tls" = "yes" ; then
cat > $TMPC <<EOF cat > $TMPC <<EOF
@@ -1436,6 +1484,7 @@ @@ -1436,6 +1483,7 @@ if test "$vnc_sasl" = "yes" ; then
echo " SASL CFLAGS $vnc_sasl_cflags" echo " SASL CFLAGS $vnc_sasl_cflags"
echo " SASL LIBS $vnc_sasl_libs" echo " SASL LIBS $vnc_sasl_libs"
fi fi
@ -91,7 +92,7 @@ Index: configure
if test -n "$sparc_cpu"; then if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu" echo "Target Sparc Arch $sparc_cpu"
fi fi
@@ -1589,6 +1638,16 @@ @@ -1589,6 +1637,16 @@ fi
if test $profiler = "yes" ; then if test $profiler = "yes" ; then
echo "#define CONFIG_PROFILER 1" >> $config_host_h echo "#define CONFIG_PROFILER 1" >> $config_host_h
fi fi
@ -109,7 +110,7 @@ Index: configure
echo "CONFIG_SLIRP=y" >> $config_host_mak echo "CONFIG_SLIRP=y" >> $config_host_mak
echo "#define CONFIG_SLIRP 1" >> $config_host_h echo "#define CONFIG_SLIRP 1" >> $config_host_h
Index: net.c Index: net.c
@@ -688,6 +688,166 @@ @@ -688,6 +688,201 @@ static void config_error(Monitor *mon, c
va_end(ap); va_end(ap);
} }
@ -123,6 +124,7 @@ Index: net.c
+typedef struct PCAPState { +typedef struct PCAPState {
+ VLANClientState *vc; + VLANClientState *vc;
+ pcap_t *handle; + pcap_t *handle;
+ int max_eth_frame_size;
+} PCAPState; +} PCAPState;
+ +
+static ssize_t pcap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) +static ssize_t pcap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
@ -136,14 +138,29 @@ Index: net.c
+{ +{
+ VLANClientState *vc = (VLANClientState *)user; + VLANClientState *vc = (VLANClientState *)user;
+ +
+ qemu_send_packet(vc, pdata, phdr->len); + int len = phdr->len;
+#ifdef __FreeBSD__
+ PCAPState *s = vc->opaque;
+ int max_eth_frame_size = s->max_eth_frame_size;
+
+ if (len > max_eth_frame_size) {
+ fprintf(stderr,
+ "pcap_send: packet size > %d (%d), truncating\n",
+ max_eth_frame_size, len);
+ len = max_eth_frame_size;
+ }
+#endif
+ qemu_send_packet(vc, pdata, len);
+} +}
+ +
+static void pcap_send(void *opaque) +static void pcap_send(void *opaque)
+{ +{
+ PCAPState *s = (PCAPState *)opaque; + PCAPState *s = (PCAPState *)opaque;
+ +
+ pcap_dispatch(s->handle, 1, (pcap_handler)&pcap_callback, (u_char *)s->vc); + for (;;) {
+ if (pcap_dispatch(s->handle, 0, (pcap_handler)&pcap_callback, (u_char *)s->vc) >= 0)
+ break;
+ }
+} +}
+ +
+static void pcap_cleanup(VLANClientState *vc) +static void pcap_cleanup(VLANClientState *vc)
@ -165,43 +182,62 @@ Index: net.c
+ +
+ s = qemu_mallocz(sizeof(PCAPState)); + s = qemu_mallocz(sizeof(PCAPState));
+ if (!s) + if (!s)
+ return -1; + return -1;
+ +
+ if (ifname == NULL && (ifname = pcap_lookupdev(errbuf)) == NULL) { + if (ifname == NULL && (ifname = pcap_lookupdev(errbuf)) == NULL) {
+ fprintf(stderr, "qemu: pcap_lookupdev: %s\n", errbuf); + fprintf(stderr, "qemu: pcap_lookupdev: %s\n", errbuf);
+ goto fail; + goto fail;
+ } + }
+ +
+#ifdef __FreeBSD__
+ /*
+ * We want to avoid passing oversize packets to the guest, which
+ * at least on FreeBSD can happen if the host interface uses tso
+ * (seen with an em(4) in this case) - so find out the host
+ * interface's mtu and assume the guest is configured the same.
+ */
+ s->max_eth_frame_size = 1514;
+ i = socket(AF_INET, SOCK_DGRAM, 0);
+ if (i >= 0) {
+ struct ifreq ifr;
+
+ (void) memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(i, SIOCGIFMTU, &ifr) != -1)
+ s->max_eth_frame_size = ifr.ifr_mtu + 14;
+ close(i);
+ }
+#endif
+#if defined(HAVE_PCAP_CREATE) || defined(_WIN32) +#if defined(HAVE_PCAP_CREATE) || defined(_WIN32)
+ /* + /*
+ * Create pcap handle for the device, set promiscuous mode and activate. + * Create pcap handle for the device, set promiscuous mode and activate.
+ */ + */
+ s->handle = (void *)pcap_create(ifname, errbuf); + s->handle = (void *)pcap_create(ifname, errbuf);
+ if (!s->handle) { + if (!s->handle) {
+ fprintf(stderr, "qemu: pcap_create: %s\n", errbuf); + fprintf(stderr, "qemu: pcap_create: %s\n", errbuf);
+ goto fail; + goto fail;
+ } + }
+ if (pcap_set_promisc(s->handle, 1) != 0) { + if (pcap_set_promisc(s->handle, 1) != 0) {
+ pcap_perror(s->handle, "qemu: pcap_set_promisc:"); + pcap_perror(s->handle, "qemu: pcap_set_promisc:");
+ goto fail; + goto fail;
+ } + }
+ if (pcap_activate(s->handle) != 0) { + if (pcap_activate(s->handle) != 0) {
+ pcap_perror(s->handle, "qemu: pcap_activate:"); + pcap_perror(s->handle, "qemu: pcap_activate:");
+ goto fail; + goto fail;
+ } + }
+#else +#else
+ /* Attempt to connect device. */ + /* Attempt to connect device. */
+ s->handle = (void *)pcap_open_live(ifname, 65535, 1, 0, errbuf); + s->handle = (void *)pcap_open_live(ifname, 65535, 1, 0, errbuf);
+ if (!s->handle) { + if (!s->handle) {
+ fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf); + fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf);
+ goto fail; + goto fail;
+ } + }
+#endif +#endif
+ +
+ /* Set non-blocking mode. */ + /* Set non-blocking mode. */
+ if (pcap_setnonblock(s->handle, 1, errbuf) < 0) { + if (pcap_setnonblock(s->handle, 1, errbuf) < 0) {
+ fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf); + fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf);
+ goto fail; + goto fail;
+ } + }
+ +
+#if defined(_WIN32) +#if defined(_WIN32)
@ -209,8 +245,8 @@ Index: net.c
+ * Tell the kernel that the packet has to be seen immediately. + * Tell the kernel that the packet has to be seen immediately.
+ */ + */
+ if (pcap_setmintocopy(s->handle, 0) < 0) { + if (pcap_setmintocopy(s->handle, 0) < 0) {
+ fprintf(stderr, "qemu: pcap failed to set immediate mode\n"); + fprintf(stderr, "qemu: pcap failed to set immediate mode\n");
+ goto fail; + goto fail;
+ } + }
+#else /* !_WIN32 */ +#else /* !_WIN32 */
+#if defined(HAVE_BPF) +#if defined(HAVE_BPF)
@ -219,11 +255,11 @@ Index: net.c
+ * Tell the kernel that the packet has to be seen immediately. + * Tell the kernel that the packet has to be seen immediately.
+ */ + */
+ { + {
+ unsigned int one = 1; + unsigned int one = 1;
+ if (ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one) < 0) { + if (ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one) < 0) {
+ fprintf(stderr, "qemu: pcap failed to set immediate mode\n"); + fprintf(stderr, "qemu: pcap failed to set immediate mode\n");
+ goto fail; + goto fail;
+ } + }
+ } + }
+#endif /* BIOCIMMEDIATE */ +#endif /* BIOCIMMEDIATE */
+ +
@ -233,11 +269,11 @@ Index: net.c
+ * This is necessary to connect host and guest. + * This is necessary to connect host and guest.
+ */ + */
+ { + {
+ unsigned int one = 1; + unsigned int one = 1;
+ if (ioctl(pcap_fileno(s->handle), BIOCFEEDBACK, &one) < 0) { + if (ioctl(pcap_fileno(s->handle), BIOCFEEDBACK, &one) < 0) {
+ fprintf(stderr, "qemu: pcap failed to set feedback mode\n"); + fprintf(stderr, "qemu: pcap failed to set feedback mode\n");
+ goto fail; + goto fail;
+ } + }
+ } + }
+#endif /* BIOCFEEDBACK */ +#endif /* BIOCFEEDBACK */
+#endif /* HAVE_BPF */ +#endif /* HAVE_BPF */
@ -248,14 +284,14 @@ Index: net.c
+ +
+#if defined(_WIN32) +#if defined(_WIN32)
+ if ((h = pcap_getevent(s->handle)) == NULL) { + if ((h = pcap_getevent(s->handle)) == NULL) {
+ fprintf(stderr, "qemu: pcap_getevent failed\n"); + fprintf(stderr, "qemu: pcap_getevent failed\n");
+ goto fail; + goto fail;
+ } + }
+ qemu_add_wait_object(h, pcap_send, s); + qemu_add_wait_object(h, pcap_send, s);
+#else /* !_WIN32 */ +#else /* !_WIN32 */
+ if ((i = pcap_get_selectable_fd(s->handle)) < 0) { + if ((i = pcap_get_selectable_fd(s->handle)) < 0) {
+ fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n"); + fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n");
+ goto fail; + goto fail;
+ } + }
+ qemu_set_fd_handler(i, pcap_send, NULL, s); + qemu_set_fd_handler(i, pcap_send, NULL, s);
+#endif /* _WIN32 */ +#endif /* _WIN32 */
@ -264,9 +300,9 @@ Index: net.c
+ +
+fail: +fail:
+ if (s) { + if (s) {
+ if (s->handle) + if (s->handle)
+ pcap_close(s->handle); + pcap_close(s->handle);
+ qemu_free(s); + qemu_free(s);
+ } + }
+ +
+ return -1; + return -1;
@ -276,25 +312,26 @@ Index: net.c
#if defined(CONFIG_SLIRP) #if defined(CONFIG_SLIRP)
/* slirp network adapter */ /* slirp network adapter */
@@ -2598,6 +2758,16 @@ @@ -2596,6 +2791,16 @@ int net_client_init(Monitor *mon, const
are wanted */ are wanted */
ret = 0; ret = 0;
} else } else
+#ifdef CONFIG_PCAP +#ifdef CONFIG_PCAP
+ if (!strcmp(device, "pcap")) { + if (!strcmp(device, "pcap")) {
+ char ifname[64]; + char ifname[64];
+ vlan->nb_host_devs++; + vlan->nb_host_devs++;
+ if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) + if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0)
+ ret = net_pcap_init(vlan, device, name, NULL); + ret = net_pcap_init(vlan, device, name, NULL);
+ else + else
+ ret = net_pcap_init(vlan, device, name, ifname); + ret = net_pcap_init(vlan, device, name, ifname);
+ } else + } else
+#endif +#endif
#ifdef CONFIG_SLIRP #ifdef CONFIG_SLIRP
if (!strcmp(device, "user")) { if (!strcmp(device, "user")) {
static const char * const slirp_params[] = { static const char * const slirp_params[] = {
Index: qemu-options.hx --- qemu-options.hx.orig 2009-12-02 15:27:02.000000000 -0500
@@ -782,6 +782,10 @@ +++ qemu-options.hx 2010-01-29 14:39:27.000000000 -0500
@@ -782,6 +782,10 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
" connect the user mode network stack to VLAN 'n', configure its\n" " connect the user mode network stack to VLAN 'n', configure its\n"
" DHCP server and enabled optional services\n" " DHCP server and enabled optional services\n"
#endif #endif

View file

@ -145,6 +145,13 @@ if a guest cannot eject it itself.)
- The default configuration location (qemu-ifup script etc.) has been - The default configuration location (qemu-ifup script etc.) has been
changed from /etc to PREFIX/etc (usually /usr/local/etc). Move your changed from /etc to PREFIX/etc (usually /usr/local/etc). Move your
files accordingly. files accordingly.
- The pcap code (-net nic... -net pcap,ifname=...) should work properly
now, with only one exception: Advanced features like TSO used on the host
interface can cause oversize packets which now do get truncated to avoid
confusing/panicing guests but of course still will cause retransmissions.
So if you see slow throughput and `pcap_send: packet size > ..., truncating'
messages on qemu's tty try disabling TSO etc on the host interface at least
while using pcap.
- kqemu still works in the 0.11 branch, but is disabled by default now - kqemu still works in the 0.11 branch, but is disabled by default now
so you'll have to pass -enable-kqemu (or -kernel-kqemu as with the so you'll have to pass -enable-kqemu (or -kernel-kqemu as with the
previous versions) if you want to use it. previous versions) if you want to use it.