From: "Sebastian Herbszt" <herbszt@gmx.de>
To: Consul <void@aleksoft.net>, qemu-devel@nongnu.org
Subject: [Qemu-devel] Re: [PATCH] Add pcap-based host network bridge
Date: Sat, 6 Jun 2009 19:13:26 +0200 [thread overview]
Message-ID: <C0648AF8B9CD4DE5A37965D11776A215@FSCPC> (raw)
In-Reply-To: <gvn125$k91$1@ger.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 942 bytes --]
Consul wrote:
> Sebastian Herbszt wrote:
>> Consul wrote:
>>> Sebastian Herbszt wrote:
>>>> That's really too bad. pcap-based networking works flawless on windows.
>>>> Guest <-> host and guest <-> world communication works just fine.
>>>> According to the previous threads about pcap-based networking it also
>>>> should work fine on FreeBSD.
>>>>
>>>
>>> Maybe make it compile conditionally for Windows only? Would you
>>> consider such patch?
>>> It would really be a valuable feature.
>>
>> I did rebase the patch against git master and it still seems to work. I
>> can post it if there
>> is any interest.
>>
>> - Sebastian
>>
>
> Yes, please post.
Find jan-pcap-updated-qdev3.diff attached.
> I also have it rebased in my tree and it still works great.
Is your tree available somewhere?
> Easier to configure than TAP for sure. Maybe if we'll bug the list often
> enough and loud enough, it finally gets through.
- Sebastian
[-- Attachment #2: jan-pcap-updated-qdev3.diff --]
[-- Type: application/octet-stream, Size: 13707 bytes --]
diff --git a/Makefile.target b/Makefile.target
index 27de4b9..7eb84ad 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -734,7 +734,7 @@ vl.o: qemu-options.h
monitor.o: qemu-monitor.h
-$(QEMU_PROG): LIBS += $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS) $(VDE_LIBS) $(CURL_LIBS)
+$(QEMU_PROG): LIBS += $(SDL_LIBS) $(COCOA_LIBS) $(CURSES_LIBS) $(BRLAPI_LIBS) $(VDE_LIBS) $(CURL_LIBS) $(PCAP_LIBS)
$(QEMU_PROG): ARLIBS=../libqemu_common.a libqemu.a $(HWLIB)
$(QEMU_PROG): $(OBJS) ../libqemu_common.a libqemu.a $(HWLIB)
$(call LINK,$(OBJS))
diff --git a/configure b/configure
index 42d46f2..169f8bc 100755
--- a/configure
+++ b/configure
@@ -165,6 +165,7 @@ mingw32="no"
EXESUF=""
slirp="yes"
vde="yes"
+pcap="yes"
fmod_lib=""
fmod_inc=""
oss_lib=""
@@ -432,6 +433,8 @@ for opt do
;;
--disable-vde) vde="no"
;;
+ --disable-pcap) pcap="no"
+ ;;
--disable-kqemu) kqemu="no"
;;
--disable-xen) xen="no"
@@ -634,6 +637,7 @@ echo " --oss-lib path to OSS library"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
echo " --sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
echo " --disable-vde disable support for vde network"
+echo " --disable-pcap disable support for pcap-based network"
echo " --disable-pthread disable pthread support"
echo " --disable-aio disable AIO support"
echo " --enable-io-thread enable IO thread"
@@ -981,6 +985,31 @@ EOF
fi
##########################################
+# pcap libraries probe
+if test "$pcap" = "yes" ; then
+ cat > $TMPC << EOF
+#include <pcap.h>
+int main(void)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ pcap_lookupdev(errbuf);
+ return 0;
+}
+EOF
+ if test "$mingw32" = "yes" ; then
+ PCAP_LIBS=-lwpcap
+ else
+ PCAP_LIBS=-lpcap
+ fi
+ if $cc $ARCH_CFLAGS -o $TMPE $TMPC $PCAP_LIBS > /dev/null 2> /dev/null ; then
+ :
+ else
+ pcap="no"
+ fi
+fi
+
+##########################################
# Sound support libraries probe
audio_drv_probe()
@@ -1374,6 +1403,7 @@ echo "Documentation $build_docs"
echo "uname -r $uname_release"
echo "NPTL support $nptl"
echo "vde support $vde"
+echo "pcap net support $pcap"
echo "AIO support $aio"
echo "IO thread $io_thread"
echo "Install blobs $blobs"
@@ -1587,6 +1617,11 @@ if test "$vde" = "yes" ; then
echo "#define CONFIG_VDE 1" >> $config_h
echo "VDE_LIBS=-lvdeplug" >> $config_mak
fi
+if test "$pcap" = "yes" ; then
+ echo "CONFIG_PCAP=yes" >> $config_mak
+ echo "#define CONFIG_PCAP 1" >> $config_h
+ echo "PCAP_LIBS="$PCAP_LIBS >> $config_mak
+fi
for card in $audio_card_list; do
def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
echo "$def=yes" >> $config_mak
diff --git a/net.c b/net.c
index 2d24a7c..e4b3740 100644
--- a/net.c
+++ b/net.c
@@ -93,6 +93,13 @@
#endif
#endif
+#if defined(CONFIG_PCAP)
+#include <pcap.h>
+#ifdef _WIN32
+#include <remote-ext.h>
+#endif /* _WIN32 */
+#endif /* CONFIG_PCAP */
+
#if defined(__OpenBSD__)
#include <util.h>
#endif
@@ -1176,6 +1183,268 @@ static int net_tap_init(VLANState *vlan, const char *model,
#endif /* !_WIN32 */
+#if defined(CONFIG_PCAP)
+
+#ifdef _WIN32
+#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class" \
+ "\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network" \
+ "\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
+#endif
+
+typedef struct PCAPState {
+ VLANClientState *vc;
+ pcap_t *handle;
+} PCAPState;
+
+static void pcap_receive(void *opaque, const uint8_t *buf, int size)
+{
+ PCAPState *s = (PCAPState *)opaque;
+
+ pcap_sendpacket(s->handle, (u_char*)buf, size);
+}
+
+static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char *pdata)
+{
+ VLANClientState *vc = (VLANClientState *)user;
+
+ qemu_send_packet(vc, pdata, phdr->len);
+}
+
+static void pcap_send(void *opaque)
+{
+ PCAPState *s = (PCAPState *)opaque;
+
+ pcap_dispatch(s->handle, 1, (pcap_handler)&pcap_callback, (u_char *)s->vc);
+}
+
+static void pcap_cleanup(VLANClientState *vc)
+{
+ PCAPState *s = vc->opaque;
+
+#ifndef _WIN32
+ int fd;
+
+ if ((fd = pcap_get_selectable_fd(s->handle)) < 0) {
+ fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n");
+ return;
+ }
+ qemu_set_fd_handler(fd, NULL, NULL, NULL);
+#else
+ HANDLE hand;
+
+ hand = pcap_getevent(s->handle);
+ if ((hand = pcap_getevent(s->handle)) == 0) {
+ fprintf(stderr, "qemu: pcap_getevent failed\n");
+ return;
+ }
+ qemu_del_wait_object(hand, NULL, NULL);
+#endif
+
+ pcap_close(s->handle);
+ qemu_free(s);
+}
+
+#ifdef _WIN32
+static int get_windows_device_name(char *name, int name_size,
+ char *actual_name, int actual_name_size)
+{
+ const char name_string[] = "Name";
+ char connection_string[256];
+ HKEY connection_key;
+ char name_data[256];
+ DWORD name_type;
+ LONG status;
+ DWORD len;
+
+ snprintf(connection_string, sizeof(connection_string),
+ "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, name);
+
+ status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string, 0, KEY_READ,
+ &connection_key);
+
+ if (status == ERROR_SUCCESS) {
+ len = sizeof(name_data);
+ status = RegQueryValueEx(connection_key, name_string, NULL,
+ &name_type, (PBYTE)name_data, &len);
+ if (status != ERROR_SUCCESS || name_type != REG_SZ) {
+ fprintf(stderr, "qemu: error opening registry key: %s\\%s\\%s",
+ NETWORK_CONNECTIONS_KEY, connection_string, name_string);
+ return -1;
+ } else {
+ snprintf(actual_name, actual_name_size, "%s", name_data);
+ }
+
+ RegCloseKey(connection_key);
+
+ }
+ return 0;
+}
+#endif
+
+static int net_pcap_init(VLANState *vlan, const char *model, const char *name,
+ char *ifname)
+{
+ PCAPState *s;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ int fd;
+
+ s = qemu_mallocz(sizeof(PCAPState));
+ if (!s)
+ return -1;
+
+#ifndef _WIN32
+ if (!ifname && !(ifname = pcap_lookupdev(errbuf))) {
+ fprintf(stderr, "qemu: pcap_lookupdev: %s\n", errbuf);
+ goto fail;
+ }
+
+ s->handle = (void*)pcap_open_live(ifname, 65535, 1, 0, errbuf);
+#else
+ {
+ pcap_if_t *found_device = NULL;
+ pcap_if_t *alldevs = NULL;
+ pcap_if_t *device;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ char connection_name_data[256];
+ char name_data[256];
+ char *code_strt;
+
+ /* Retrieve the device list */
+ if (pcap_findalldevs(&alldevs, errbuf) == -1) {
+ fprintf(stderr, "qemu: error in pcap_findalldevs: %s\n", errbuf);
+ goto fail;
+ }
+
+ device = alldevs;
+
+ while (device) {
+ memset(connection_name_data, 0, sizeof(connection_name_data));
+
+ code_strt = strchr(device->name, '{');
+ if (code_strt) {
+ snprintf(name_data, sizeof(name_data), "%s", code_strt);
+
+ get_windows_device_name(name_data, sizeof(name_data),
+ connection_name_data,
+ sizeof(connection_name_data));
+ }
+
+ if (*connection_name_data != 0) {
+ if (ifname) {
+ /*
+ * If an exact match exists, over-ride any found device,
+ * setting exact match device to it.
+ */
+ if (strcmp(connection_name_data, ifname) == 0) {
+ found_device = device;
+ break;
+ }
+
+ /*
+ * Do a partial search, if successful, set this device as
+ * the found one, but continue looping through devices.
+ */
+ if (found_device && strstr(connection_name_data, ifname))
+ found_device = device;
+ } else {
+ /*
+ * If no name specified and network has an address,
+ * autoselect the first device.
+ */
+ if (device->addresses) {
+ found_device = device;
+ break;
+ }
+ }
+ }
+
+ device = device->next;
+ }
+
+ if (!found_device)
+ goto fail;
+
+ ifname = found_device->name;
+
+ s->handle = pcap_open(ifname, 65536,
+ PCAP_OPENFLAG_PROMISCUOUS |
+ PCAP_OPENFLAG_NOCAPTURE_LOCAL |
+ PCAP_OPENFLAG_MAX_RESPONSIVENESS,
+ 0, NULL, errbuf);
+ }
+#endif
+ if (!s->handle) {
+ fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf);
+ goto fail;
+ }
+
+ if (pcap_setnonblock(s->handle, 1, errbuf) < 0) {
+ fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf);
+ goto fail;
+ }
+
+#ifndef _WIN32
+#if defined(BIOCSHDRCMPLT)
+ /*
+ * Tell the kernel that the header is fully-formed when it gets it.
+ * This is required in order to fake the src address.
+ */
+ {
+ unsigned int one = 1;
+ ioctl(pcap_fileno(s->handle), BIOCSHDRCMPLT, &one);
+ }
+#endif /* BIOCSHDRCMPLT */
+
+#if defined(BIOCIMMEDIATE)
+ /*
+ * Tell the kernel that the packet has to be processed immediately.
+ */
+ {
+ unsigned int one = 1;
+ ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one);
+ }
+#endif /* BIOCIMMEDIATE */
+#endif
+
+ s->vc = qemu_new_vlan_client(vlan, model, name, pcap_receive, NULL, pcap_cleanup, s);
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str), "pcap redirector");
+#ifndef _WIN32
+ if ((fd = pcap_get_selectable_fd(s->handle)) < 0) {
+ fprintf(stderr, "qemu: pcap_get_selectable_fd failed\n");
+ goto fail;
+ }
+ qemu_set_fd_handler(fd, pcap_send, NULL, s);
+#else
+ {
+ HANDLE hand;
+
+ hand = pcap_getevent(s->handle);
+ if ((hand = pcap_getevent(s->handle)) == 0) {
+ fprintf(stderr, "qemu: pcap_getevent failed\n");
+ goto fail;
+ }
+ if (qemu_add_wait_object(hand, pcap_send, s) < 0) {
+ fprintf(stderr,
+ "qemu: qemu_add_wait_object for pcap_send failed\n");
+ goto fail;
+ }
+ }
+#endif
+
+ return 0;
+
+fail:
+ if (s) {
+ if (s->handle)
+ pcap_close(s->handle);
+ qemu_free(s);
+ }
+
+ return -1;
+}
+#endif /* CONFIG_PCAP */
+
#if defined(CONFIG_VDE)
typedef struct VDEState {
VLANClientState *vc;
@@ -2025,6 +2294,16 @@ int net_client_init(const char *device, const char *p)
}
} else
#endif
+#ifdef CONFIG_PCAP
+ if (!strcmp(device, "pcap")) {
+ char ifname[64];
+ vlan->nb_host_devs++;
+ if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+ ifname[0] = '\0';
+ }
+ ret = net_pcap_init(vlan, device, name, ifname);
+ } else
+#endif
if (!strcmp(device, "socket")) {
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
int fd;
diff --git a/qemu-options.hx b/qemu-options.hx
index 87af798..9d24473 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -753,6 +753,10 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, \
" Use group 'groupname' and mode 'octalmode' to change default\n"
" ownership and permissions for communication port.\n"
#endif
+#ifdef CONFIG_PCAP
+ "-net pcap[,vlan=n][,name=str][,ifname=name]\n"
+ " connect the host network interface to VLAN 'n' using PCAP\n"
+#endif
"-net dump[,vlan=n][,file=f][,len=n]\n"
" dump traffic on vlan 'n' to file 'f' (max n bytes per packet)\n"
"-net none use it alone to have zero network devices; if no -net option\n"
@@ -875,6 +879,18 @@ vde_switch -F -sock /tmp/myswitch
qemu linux.img -net nic -net vde,sock=/tmp/myswitch
@end example
+@item -net pcap[,vlan=@var{n}][,name=@var{name}][,ifname=@var{name}]
+Connect VLAN @var{n} to the host network interface @var{name} using the pcap
+interface. This will switch the host's interface to promisc mode, enabling the
+guest to receive all packets on this VLAN that the host sees, too. The pcap
+host interface is a handy alternative to a TAP interface, attached via a
+bridge to a host network interface.
+
+Example:
+@example
+qemu linux.img -net nic -net pcap,ifname=eth0
+@end example
+
@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
Dump network traffic on VLAN @var{n} to file @var{file} (@file{qemu-vlan0.pcap} by default).
At most @var{len} bytes (64k by default) per packet are stored. The file format is
next prev parent reply other threads:[~2009-06-06 17:14 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-18 9:33 [Qemu-devel] [PATCH] Add pcap-based host network bridge Jan Kiszka
2009-03-22 20:38 ` Robert Riebisch
2009-03-22 21:38 ` [Qemu-devel] " Sebastian Herbszt
2009-03-24 17:21 ` Jan Kiszka
2009-03-23 2:23 ` [Qemu-devel] " Anthony Liguori
2009-03-24 17:28 ` [Qemu-devel] " Jan Kiszka
2009-03-28 17:26 ` Anthony Liguori
2009-05-11 21:30 ` [Qemu-devel] " Sebastian Herbszt
2009-05-12 8:23 ` [Qemu-devel] " Jan Kiszka
2009-05-12 15:48 ` Lennart Sorensen
2009-05-12 16:34 ` Jan Kiszka
2009-05-12 17:09 ` Lennart Sorensen
2009-05-12 21:45 ` Paul Brook
2009-05-12 21:17 ` Sebastian Herbszt
2009-05-20 17:43 ` Consul
2009-05-28 20:50 ` Sebastian Herbszt
2009-05-28 21:52 ` Consul
2009-06-06 17:13 ` Sebastian Herbszt [this message]
2009-06-06 18:40 ` Alex
2009-06-08 21:27 ` Consul
2009-06-09 20:13 ` Sebastian Herbszt
2009-06-09 21:49 ` Consul
2009-06-10 21:39 ` Sebastian Herbszt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=C0648AF8B9CD4DE5A37965D11776A215@FSCPC \
--to=herbszt@gmx.de \
--cc=qemu-devel@nongnu.org \
--cc=void@aleksoft.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).