mirror of
https://git.freebsd.org/ports.git
synced 2025-05-15 00:31:51 -04:00
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]
344 lines
9.4 KiB
Text
344 lines
9.4 KiB
Text
--- Makefile.target.orig 2010-01-29 14:39:26.000000000 -0500
|
|
+++ Makefile.target 2010-01-29 14:39:28.000000000 -0500
|
|
@@ -616,6 +616,13 @@ ifdef CONFIG_COREAUDIO
|
|
COCOA_LIBS+=-framework CoreAudio
|
|
endif
|
|
endif
|
|
+ifdef CONFIG_PCAP
|
|
+ifdef CONFIG_WIN32
|
|
+LIBS+=-lwpcap
|
|
+else
|
|
+LIBS+=-lpcap
|
|
+endif
|
|
+endif
|
|
ifdef CONFIG_SLIRP
|
|
CPPFLAGS+=-I$(SRC_PATH)/slirp
|
|
endif
|
|
--- configure.orig 2010-01-29 14:39:26.000000000 -0500
|
|
+++ configure 2010-01-29 14:39:27.000000000 -0500
|
|
@@ -203,6 +203,9 @@ sdl="yes"
|
|
sdl_x11="no"
|
|
xen="yes"
|
|
pkgversion=""
|
|
+pcap="no"
|
|
+pcap_create="no"
|
|
+bpf="no"
|
|
|
|
# OS specific
|
|
if check_define __linux__ ; then
|
|
@@ -428,6 +431,8 @@ for opt do
|
|
;;
|
|
--disable-vnc-sasl) vnc_sasl="no"
|
|
;;
|
|
+ --enable-pcap) pcap="yes"
|
|
+ ;;
|
|
--disable-slirp) slirp="no"
|
|
;;
|
|
--disable-vde) vde="no"
|
|
@@ -925,6 +930,48 @@ EOF
|
|
fi
|
|
|
|
##########################################
|
|
+# pcap probe
|
|
+
|
|
+if test "$pcap" = "yes" ; then
|
|
+ cat > $TMPC << EOF
|
|
+#include <pcap.h>
|
|
+int main(void) { return (pcap_lib_version() == (char *)0 ? 1 : 0); }
|
|
+EOF
|
|
+ if test "$mingw32" = "no" ; then
|
|
+ libpcap=-lpcap
|
|
+ else
|
|
+ libpcap=-lwpcap
|
|
+ fi
|
|
+ if ! $cc $ARCH_CFLAGS -o $TMPE $libpcap $TMPC 2> /dev/null ; then
|
|
+ echo
|
|
+ echo "Error: Could not find pcap"
|
|
+ echo "Make sure to have the pcap libs and headers installed."
|
|
+ echo
|
|
+ exit 1
|
|
+ fi
|
|
+ cat > $TMPC << EOF
|
|
+#include <pcap.h>
|
|
+int main(void)
|
|
+{
|
|
+ char errbuf[PCAP_ERRBUF_SIZE];
|
|
+ return (pcap_create("foo", errbuf) == (pcap_t *)0 ? 1 : 0);
|
|
+}
|
|
+EOF
|
|
+ if $cc $ARCH_CFLAGS -o $TMPE $libpcap $TMPC 2> /dev/null ; then
|
|
+ pcap_create="yes"
|
|
+ fi
|
|
+ cat > $TMPC << EOF
|
|
+#define PCAP_DONT_INCLUDE_PCAP_BPF_H
|
|
+#include <pcap.h>
|
|
+#include <net/bpf.h>
|
|
+int main(void) { return (BPF_MAJOR_VERSION); }
|
|
+EOF
|
|
+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
|
|
+ bpf="yes"
|
|
+ fi
|
|
+fi # test "$pcap"
|
|
+
|
|
+##########################################
|
|
# VNC TLS detection
|
|
if test "$vnc_tls" = "yes" ; then
|
|
cat > $TMPC <<EOF
|
|
@@ -1436,6 +1483,7 @@ if test "$vnc_sasl" = "yes" ; then
|
|
echo " SASL CFLAGS $vnc_sasl_cflags"
|
|
echo " SASL LIBS $vnc_sasl_libs"
|
|
fi
|
|
+echo "pcap support $pcap"
|
|
if test -n "$sparc_cpu"; then
|
|
echo "Target Sparc Arch $sparc_cpu"
|
|
fi
|
|
@@ -1589,6 +1637,16 @@ fi
|
|
if test $profiler = "yes" ; then
|
|
echo "#define CONFIG_PROFILER 1" >> $config_host_h
|
|
fi
|
|
+if test "$pcap" = "yes" ; then
|
|
+ echo "CONFIG_PCAP=yes" >> $config_host_mak
|
|
+ echo "#define CONFIG_PCAP 1" >> $config_host_h
|
|
+ if test "$pcap_create" = "yes" ; then
|
|
+ echo "#define HAVE_PCAP_CREATE 1" >> $config_host_h
|
|
+ fi
|
|
+ if test "$bpf" = "yes" ; then
|
|
+ echo "#define HAVE_BPF 1" >> $config_host_h
|
|
+ fi
|
|
+fi
|
|
if test "$slirp" = "yes" ; then
|
|
echo "CONFIG_SLIRP=y" >> $config_host_mak
|
|
echo "#define CONFIG_SLIRP 1" >> $config_host_h
|
|
Index: net.c
|
|
@@ -688,6 +688,201 @@ static void config_error(Monitor *mon, c
|
|
va_end(ap);
|
|
}
|
|
|
|
+#if defined(CONFIG_PCAP)
|
|
+#if defined(HAVE_BPF)
|
|
+#define PCAP_DONT_INCLUDE_PCAP_BPF_H
|
|
+#include <net/bpf.h>
|
|
+#endif
|
|
+#include <pcap.h>
|
|
+
|
|
+typedef struct PCAPState {
|
|
+ VLANClientState *vc;
|
|
+ pcap_t *handle;
|
|
+ int max_eth_frame_size;
|
|
+} PCAPState;
|
|
+
|
|
+static ssize_t pcap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
|
|
+{
|
|
+ PCAPState *s = (PCAPState *)vc->opaque;
|
|
+
|
|
+ return pcap_inject(s->handle, (u_char*)buf, size);
|
|
+}
|
|
+
|
|
+static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char *pdata)
|
|
+{
|
|
+ VLANClientState *vc = (VLANClientState *)user;
|
|
+
|
|
+ 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)
|
|
+{
|
|
+ PCAPState *s = (PCAPState *)opaque;
|
|
+
|
|
+ for (;;) {
|
|
+ if (pcap_dispatch(s->handle, 0, (pcap_handler)&pcap_callback, (u_char *)s->vc) >= 0)
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void pcap_cleanup(VLANClientState *vc)
|
|
+{
|
|
+ PCAPState *s = vc->opaque;
|
|
+
|
|
+ pcap_close(s->handle);
|
|
+ qemu_free(s);
|
|
+}
|
|
+
|
|
+static int net_pcap_init(VLANState *vlan, const char *model, const char *name, char *ifname)
|
|
+{
|
|
+ PCAPState *s = NULL;
|
|
+ char errbuf[PCAP_ERRBUF_SIZE];
|
|
+#if defined(_WIN32)
|
|
+ HANDLE h;
|
|
+#endif
|
|
+ int i;
|
|
+
|
|
+ s = qemu_mallocz(sizeof(PCAPState));
|
|
+ if (!s)
|
|
+ return -1;
|
|
+
|
|
+ if (ifname == NULL && (ifname = pcap_lookupdev(errbuf)) == NULL) {
|
|
+ fprintf(stderr, "qemu: pcap_lookupdev: %s\n", errbuf);
|
|
+ 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)
|
|
+ /*
|
|
+ * Create pcap handle for the device, set promiscuous mode and activate.
|
|
+ */
|
|
+ s->handle = (void *)pcap_create(ifname, errbuf);
|
|
+ if (!s->handle) {
|
|
+ fprintf(stderr, "qemu: pcap_create: %s\n", errbuf);
|
|
+ goto fail;
|
|
+ }
|
|
+ if (pcap_set_promisc(s->handle, 1) != 0) {
|
|
+ pcap_perror(s->handle, "qemu: pcap_set_promisc:");
|
|
+ goto fail;
|
|
+ }
|
|
+ if (pcap_activate(s->handle) != 0) {
|
|
+ pcap_perror(s->handle, "qemu: pcap_activate:");
|
|
+ goto fail;
|
|
+ }
|
|
+#else
|
|
+ /* Attempt to connect device. */
|
|
+ s->handle = (void *)pcap_open_live(ifname, 65535, 1, 0, errbuf);
|
|
+ if (!s->handle) {
|
|
+ fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf);
|
|
+ goto fail;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ /* Set non-blocking mode. */
|
|
+ if (pcap_setnonblock(s->handle, 1, errbuf) < 0) {
|
|
+ fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf);
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+#if defined(_WIN32)
|
|
+ /*
|
|
+ * Tell the kernel that the packet has to be seen immediately.
|
|
+ */
|
|
+ if (pcap_setmintocopy(s->handle, 0) < 0) {
|
|
+ fprintf(stderr, "qemu: pcap failed to set immediate mode\n");
|
|
+ goto fail;
|
|
+ }
|
|
+#else /* !_WIN32 */
|
|
+#if defined(HAVE_BPF)
|
|
+#if defined(BIOCIMMEDIATE)
|
|
+ /*
|
|
+ * Tell the kernel that the packet has to be seen immediately.
|
|
+ */
|
|
+ {
|
|
+ unsigned int one = 1;
|
|
+ if (ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one) < 0) {
|
|
+ fprintf(stderr, "qemu: pcap failed to set immediate mode\n");
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
+#endif /* BIOCIMMEDIATE */
|
|
+
|
|
+#if defined(BIOCFEEDBACK)
|
|
+ /*
|
|
+ * Tell the kernel that the sent packet has to be fed back.
|
|
+ * This is necessary to connect host and guest.
|
|
+ */
|
|
+ {
|
|
+ unsigned int one = 1;
|
|
+ if (ioctl(pcap_fileno(s->handle), BIOCFEEDBACK, &one) < 0) {
|
|
+ fprintf(stderr, "qemu: pcap failed to set feedback mode\n");
|
|
+ goto fail;
|
|
+ }
|
|
+ }
|
|
+#endif /* BIOCFEEDBACK */
|
|
+#endif /* HAVE_BPF */
|
|
+#endif /* _WIN32 */
|
|
+
|
|
+ s->vc = qemu_new_vlan_client(vlan, model, name, NULL, pcap_receive, NULL, pcap_cleanup, s);
|
|
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str), "pcap redirector");
|
|
+
|
|
+#if defined(_WIN32)
|
|
+ if ((h = pcap_getevent(s->handle)) == NULL) {
|
|
+ fprintf(stderr, "qemu: pcap_getevent failed\n");
|
|
+ goto fail;
|
|
+ }
|
|
+ qemu_add_wait_object(h, pcap_send, s);
|
|
+#else /* !_WIN32 */
|
|
+ if ((i = pcap_get_selectable_fd(s->handle)) < 0) {
|
|
+ fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n");
|
|
+ goto fail;
|
|
+ }
|
|
+ qemu_set_fd_handler(i, pcap_send, NULL, s);
|
|
+#endif /* _WIN32 */
|
|
+
|
|
+ return 0;
|
|
+
|
|
+fail:
|
|
+ if (s) {
|
|
+ if (s->handle)
|
|
+ pcap_close(s->handle);
|
|
+ qemu_free(s);
|
|
+ }
|
|
+
|
|
+ return -1;
|
|
+}
|
|
+#endif /* CONFIG_PCAP */
|
|
+
|
|
#if defined(CONFIG_SLIRP)
|
|
|
|
/* slirp network adapter */
|
|
@@ -2596,6 +2791,16 @@ int net_client_init(Monitor *mon, const
|
|
are wanted */
|
|
ret = 0;
|
|
} else
|
|
+#ifdef CONFIG_PCAP
|
|
+ if (!strcmp(device, "pcap")) {
|
|
+ char ifname[64];
|
|
+ vlan->nb_host_devs++;
|
|
+ if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0)
|
|
+ ret = net_pcap_init(vlan, device, name, NULL);
|
|
+ else
|
|
+ ret = net_pcap_init(vlan, device, name, ifname);
|
|
+ } else
|
|
+#endif
|
|
#ifdef CONFIG_SLIRP
|
|
if (!strcmp(device, "user")) {
|
|
static const char * const slirp_params[] = {
|
|
--- qemu-options.hx.orig 2009-12-02 15:27:02.000000000 -0500
|
|
+++ 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"
|
|
" DHCP server and enabled optional services\n"
|
|
#endif
|
|
+#ifdef CONFIG_PCAP
|
|
+ "-net pcap[,vlan=n][,name=str][,ifname=name]\n"
|
|
+ " connect the host network interface using PCAP to VLAN 'n'\n"
|
|
+#endif
|
|
#ifdef _WIN32
|
|
"-net tap[,vlan=n][,name=str],ifname=name\n"
|
|
" connect the host TAP network interface to VLAN 'n'\n"
|