From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KE3qh-0005LQ-G5 for qemu-devel@nongnu.org; Wed, 02 Jul 2008 11:02:23 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KE3qf-0005KU-7I for qemu-devel@nongnu.org; Wed, 02 Jul 2008 11:02:22 -0400 Received: from [199.232.76.173] (port=53219 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KE3qe-0005KR-Vu for qemu-devel@nongnu.org; Wed, 02 Jul 2008 11:02:21 -0400 Received: from ns.suse.de ([195.135.220.2]:56975 helo=mx1.suse.de) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1KE3qc-0007I2-Vo for qemu-devel@nongnu.org; Wed, 02 Jul 2008 11:02:20 -0400 Received: from Relay1.suse.de (mail2.suse.de [195.135.221.8]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.suse.de (Postfix) with ESMTP id 12CB041588 for ; Wed, 2 Jul 2008 17:02:14 +0200 (CEST) From: Ulrich Hecht Date: Wed, 2 Jul 2008 17:02:49 +0200 MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_ai5aIeOZq2KZ0Kq" Message-Id: <200807021702.50752.uli@suse.de> Subject: [Qemu-devel] [PATCH] networking using libpcap Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org --Boundary-00=_ai5aIeOZq2KZ0Kq Content-Type: text/plain; charset="iso-8859-1" Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Hi! I just discovered this patch http://lists.freebsd.org/pipermail/freebsd-emulation/2007-February/003107= .html that implements network access using libpcap. Works perfect for me and=20 allows access to the local Ethernet right out of the box, very much=20 unlike tap and bridging. The attached version applies to trunk. CU Uli Index: Makefile.target =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- Makefile.target (revision 4820) +++ Makefile.target (working copy) @@ -619,6 +619,9 @@ ifdef CONFIG_SLIRP CPPFLAGS+=3D-I$(SRC_PATH)/slirp endif +ifdef CONFIG_PCAP +LIBS+=3D-lpcap +endif =20 LIBS+=3D$(AIOLIBS) # specific flags are needed for non soft mmu emulator Index: vl.c =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- vl.c (revision 4820) +++ vl.c (working copy) @@ -102,6 +102,10 @@ int inet_aton(const char *cp, struct in_addr *ia); #endif =20 +#if defined(CONFIG_PCAP) +#include +#endif + #if defined(CONFIG_SLIRP) #include "libslirp.h" #endif @@ -4094,6 +4098,104 @@ =20 #endif /* CONFIG_SLIRP */ =20 +#if defined(CONFIG_PCAP) + +typedef struct PCAPState { + VLANClientState *vc; + pcap_t *handle; +} PCAPState; + +static void pcap_receive(void *opaque, const uint8_t *buf, int size) +{ + PCAPState *s =3D (PCAPState *)opaque; + + pcap_sendpacket(s->handle, (u_char*)buf, size); +} + +static void pcap_callback(u_char *user, struct pcap_pkthdr *phdr, u_char= =20 *pdata) +{ + VLANClientState *vc =3D (VLANClientState *)user; + + qemu_send_packet(vc, pdata, phdr->len); +} + +static void pcap_send(void *opaque) +{ + PCAPState *s =3D (PCAPState *)opaque; + + pcap_dispatch(s->handle, 1, (pcap_handler)&pcap_callback, (u_char=20 *)s->vc); +} + +static int net_pcap_init(VLANState *vlan, char *ifname) +{ + PCAPState *s; + char errbuf[PCAP_ERRBUF_SIZE]; + int fd; + + s =3D qemu_mallocz(sizeof(PCAPState)); + if (!s) + return -1; + + if (ifname =3D=3D NULL && (ifname =3D pcap_lookupdev(errbuf)) =3D=3D= NULL) { + fprintf(stderr, "qemu: pcap_lookupdev: %s\n", errbuf); + goto fail; + } + + /* Attempt to connect device. */ + s->handle =3D (void*)pcap_open_live(ifname, 65535, 1, 0, errbuf); + if (!s->handle) { + fprintf(stderr, "qemu: pcap_open_live: %s\n", errbuf); + goto fail; + } + + /* Check non-blocking mode. */ + if (pcap_setnonblock(s->handle, 1, errbuf) < 0) { + fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf); + goto fail; + } + +#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 =3D 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 =3D 1; + ioctl(pcap_fileno(s->handle), BIOCIMMEDIATE, &one); + } +#endif /* BIOCIMMEDIATE */ + + s->vc =3D qemu_new_vlan_client(vlan, pcap_receive, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "pcap=20 redirector"); + if ((fd =3D 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); + + return 0; + +fail: + if (s) { + if (s->handle) + pcap_close(s->handle); + qemu_free(s); + } + + return -1; +} +#endif /* CONFIG_PCAP */ + #if !defined(_WIN32) =20 typedef struct TAPState { @@ -4978,6 +5080,15 @@ ret =3D net_slirp_init(vlan); } else #endif +#ifdef CONFIG_PCAP + if (!strcmp(device, "pcap")) { + char ifname[64]; + if (get_param_value(ifname, sizeof(ifname), "ifname", p) <=3D 0) + ret =3D net_pcap_init(vlan, NULL); + else + ret =3D net_pcap_init(vlan, ifname); + } else +#endif #ifdef _WIN32 if (!strcmp(device, "tap")) { char ifname[64]; @@ -7381,6 +7492,10 @@ " connect the user mode network stack to=20 VLAN 'n' and send\n" " hostname 'host' to DHCP clients\n" #endif +#ifdef CONFIG_PCAP + "-net pcap[,vlan=3Dn][,ifname=3Dname]\n" + " connect the host network interface using=20 PCAP to VLAN 'n'\n" +#endif #ifdef _WIN32 "-net tap[,vlan=3Dn],ifname=3Dname\n" " connect the host TAP network interface to=20 VLAN 'n'\n" Index: configure =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- configure (revision 4820) +++ configure (working copy) @@ -89,6 +89,7 @@ EXESUF=3D"" gdbstub=3D"yes" slirp=3D"yes" +pcap=3D"yes" fmod_lib=3D"" fmod_inc=3D"" vnc_tls=3D"yes" @@ -280,6 +281,8 @@ ;; --disable-slirp) slirp=3D"no" ;; + --disable-pcap) pcap=3D"no" + ;; --disable-kqemu) kqemu=3D"no" ;; --disable-brlapi) brlapi=3D"no" @@ -1032,6 +1035,10 @@ echo "CONFIG_SLIRP=3Dyes" >> $config_mak echo "#define CONFIG_SLIRP 1" >> $config_h fi +if test "$pcap" =3D "yes" ; then + echo "CONFIG_PCAP=3Dyes" >> $config_mak + echo "#define CONFIG_PCAP 1" >> $config_h +fi for card in $audio_card_list; do def=3DCONFIG_`echo $card | tr '[:lower:]' '[:upper:]'` echo "$def=3Dyes" >> $config_mak --=20 SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG N=FCrnberg) --Boundary-00=_ai5aIeOZq2KZ0Kq Content-Type: text/x-diff; charset="iso 8859-15"; name="patch-qemu-pcap.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="patch-qemu-pcap.diff" Index: Makefile.target =================================================================== --- Makefile.target (revision 4820) +++ Makefile.target (working copy) @@ -619,6 +619,9 @@ ifdef CONFIG_SLIRP CPPFLAGS+=-I$(SRC_PATH)/slirp endif +ifdef CONFIG_PCAP +LIBS+=-lpcap +endif LIBS+=$(AIOLIBS) # specific flags are needed for non soft mmu emulator Index: vl.c =================================================================== --- vl.c (revision 4820) +++ vl.c (working copy) @@ -102,6 +102,10 @@ int inet_aton(const char *cp, struct in_addr *ia); #endif +#if defined(CONFIG_PCAP) +#include +#endif + #if defined(CONFIG_SLIRP) #include "libslirp.h" #endif @@ -4094,6 +4098,104 @@ #endif /* CONFIG_SLIRP */ +#if defined(CONFIG_PCAP) + +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 int net_pcap_init(VLANState *vlan, char *ifname) +{ + PCAPState *s; + char errbuf[PCAP_ERRBUF_SIZE]; + int fd; + + 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; + } + + /* 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; + } + + /* Check non-blocking mode. */ + if (pcap_setnonblock(s->handle, 1, errbuf) < 0) { + fprintf(stderr, "qemu: pcap_setnonblock: %s\n", errbuf); + goto fail; + } + +#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 */ + + s->vc = qemu_new_vlan_client(vlan, pcap_receive, NULL, s); + snprintf(s->vc->info_str, sizeof(s->vc->info_str), "pcap redirector"); + 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); + + return 0; + +fail: + if (s) { + if (s->handle) + pcap_close(s->handle); + qemu_free(s); + } + + return -1; +} +#endif /* CONFIG_PCAP */ + #if !defined(_WIN32) typedef struct TAPState { @@ -4978,6 +5080,15 @@ ret = net_slirp_init(vlan); } else #endif +#ifdef CONFIG_PCAP + if (!strcmp(device, "pcap")) { + char ifname[64]; + if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) + ret = net_pcap_init(vlan, NULL); + else + ret = net_pcap_init(vlan, ifname); + } else +#endif #ifdef _WIN32 if (!strcmp(device, "tap")) { char ifname[64]; @@ -7381,6 +7492,10 @@ " connect the user mode network stack to VLAN 'n' and send\n" " hostname 'host' to DHCP clients\n" #endif +#ifdef CONFIG_PCAP + "-net pcap[,vlan=n][,ifname=name]\n" + " connect the host network interface using PCAP to VLAN 'n'\n" +#endif #ifdef _WIN32 "-net tap[,vlan=n],ifname=name\n" " connect the host TAP network interface to VLAN 'n'\n" Index: configure =================================================================== --- configure (revision 4820) +++ configure (working copy) @@ -89,6 +89,7 @@ EXESUF="" gdbstub="yes" slirp="yes" +pcap="yes" fmod_lib="" fmod_inc="" vnc_tls="yes" @@ -280,6 +281,8 @@ ;; --disable-slirp) slirp="no" ;; + --disable-pcap) pcap="no" + ;; --disable-kqemu) kqemu="no" ;; --disable-brlapi) brlapi="no" @@ -1032,6 +1035,10 @@ echo "CONFIG_SLIRP=yes" >> $config_mak echo "#define CONFIG_SLIRP 1" >> $config_h fi +if test "$pcap" = "yes" ; then + echo "CONFIG_PCAP=yes" >> $config_mak + echo "#define CONFIG_PCAP 1" >> $config_h +fi for card in $audio_card_list; do def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'` echo "$def=yes" >> $config_mak --Boundary-00=_ai5aIeOZq2KZ0Kq--