qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Mark McLoughlin <markmc@redhat.com>
To: qemu-devel@nongnu.org
Cc: Mark McLoughlin <markmc@redhat.com>
Subject: [Qemu-devel] [PATCH 04/19] net: enable IFF_VNET_HDR on tap fds if available
Date: Thu, 22 Oct 2009 17:43:35 +0100	[thread overview]
Message-ID: <1256229830-28066-5-git-send-email-markmc@redhat.com> (raw)
In-Reply-To: <1256229830-28066-1-git-send-email-markmc@redhat.com>

For now, we just add an empty header before writing and strip the header
after reading.

We really only want IFF_VNET_HDR when virtio_net is using it, but it
would significantly complicate matters to try and do that. There should
be little or no performance impact with always adding headers.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net.c       |   83 +++++++++++++++++++++++++++++++++++++++++++++++++---------
 tap-linux.h |   14 ++++++++++
 2 files changed, 84 insertions(+), 13 deletions(-)

diff --git a/net.c b/net.c
index 728941a..356a280 100644
--- a/net.c
+++ b/net.c
@@ -1245,14 +1245,20 @@ void do_info_usernet(Monitor *mon)
 
 #if !defined(_WIN32)
 
+/* Maximum GSO packet size (64k) plus plenty of room for
+ * the ethernet and virtio_net headers
+ */
+#define TAP_BUFSIZE (4096 + 65536)
+
 typedef struct TAPState {
     VLANClientState *vc;
     int fd;
     char down_script[1024];
     char down_script_arg[128];
-    uint8_t buf[4096];
+    uint8_t buf[TAP_BUFSIZE];
     unsigned int read_poll : 1;
     unsigned int write_poll : 1;
+    unsigned int has_vnet_hdr : 1;
 } TAPState;
 
 static int launch_script(const char *setup_script, const char *ifname, int fd);
@@ -1311,15 +1317,33 @@ static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
                                int iovcnt)
 {
     TAPState *s = vc->opaque;
+    const struct iovec *iovp = iov;
+    struct iovec iov_copy[iovcnt + 1];
+    struct virtio_net_hdr hdr = { 0, };
 
-    return tap_write_packet(s, iov, iovcnt);
+    if (s->has_vnet_hdr) {
+        iov_copy[0].iov_base = &hdr;
+        iov_copy[0].iov_len =  sizeof(hdr);
+        memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov));
+        iovp = iov_copy;
+        iovcnt++;
+    }
+
+    return tap_write_packet(s, iovp, iovcnt);
 }
 
 static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
 {
     TAPState *s = vc->opaque;
-    struct iovec iov[1];
+    struct iovec iov[2];
     int iovcnt = 0;
+    struct virtio_net_hdr hdr = { 0, };
+
+    if (s->has_vnet_hdr) {
+        iov[iovcnt].iov_base = &hdr;
+        iov[iovcnt].iov_len  = sizeof(hdr);
+        iovcnt++;
+    }
 
     iov[iovcnt].iov_base = (char *)buf;
     iov[iovcnt].iov_len  = size;
@@ -1365,12 +1389,19 @@ static void tap_send(void *opaque)
     int size;
 
     do {
+        uint8_t *buf = s->buf;
+
         size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
         if (size <= 0) {
             break;
         }
 
-        size = qemu_send_packet_async(s->vc, s->buf, size, tap_send_completed);
+        if (s->has_vnet_hdr) {
+            buf  += sizeof(struct virtio_net_hdr);
+            size -= sizeof(struct virtio_net_hdr);
+        }
+
+        size = qemu_send_packet_async(s->vc, buf, size, tap_send_completed);
         if (size == 0) {
             tap_read_poll(s, 0);
         }
@@ -1400,6 +1431,18 @@ static int tap_set_sndbuf(TAPState *s, QemuOpts *opts)
     return 0;
 }
 
+static int tap_probe_vnet_hdr(int fd)
+{
+    struct ifreq ifr;
+
+    if (ioctl(fd, TUNGETIFF, &ifr) != 0) {
+        qemu_error("TUNGETIFF ioctl() failed: %s\n", strerror(errno));
+        return 0;
+    }
+
+    return ifr.ifr_flags & IFF_VNET_HDR;
+}
+
 static void tap_cleanup(VLANClientState *vc)
 {
     TAPState *s = vc->opaque;
@@ -1420,12 +1463,14 @@ static void tap_cleanup(VLANClientState *vc)
 static TAPState *net_tap_fd_init(VLANState *vlan,
                                  const char *model,
                                  const char *name,
-                                 int fd)
+                                 int fd,
+                                 int vnet_hdr)
 {
     TAPState *s;
 
     s = qemu_mallocz(sizeof(TAPState));
     s->fd = fd;
+    s->has_vnet_hdr = vnet_hdr != 0;
     s->vc = qemu_new_vlan_client(vlan, NULL, model, name, NULL,
                                  tap_receive, tap_receive_iov,
                                  tap_cleanup, s);
@@ -1435,7 +1480,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
 }
 
 #if defined (CONFIG_BSD) || defined (__FreeBSD_kernel__)
-static int tap_open(char *ifname, int ifname_size)
+static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
 {
     int fd;
     char *dev;
@@ -1577,7 +1622,7 @@ static int tap_alloc(char *dev, size_t dev_size)
     return tap_fd;
 }
 
-static int tap_open(char *ifname, int ifname_size)
+static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
 {
     char  dev[10]="";
     int fd;
@@ -1590,13 +1635,13 @@ static int tap_open(char *ifname, int ifname_size)
     return fd;
 }
 #elif defined (_AIX)
-static int tap_open(char *ifname, int ifname_size)
+static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
 {
     fprintf (stderr, "no tap on AIX\n");
     return -1;
 }
 #else
-static int tap_open(char *ifname, int ifname_size)
+static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
 {
     struct ifreq ifr;
     int fd, ret;
@@ -1608,6 +1653,17 @@ static int tap_open(char *ifname, int ifname_size)
     }
     memset(&ifr, 0, sizeof(ifr));
     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+
+    {
+        unsigned int features;
+
+        if (ioctl(fd, TUNGETFEATURES, &features) == 0 &&
+            features & IFF_VNET_HDR) {
+            *vnet_hdr = 1;
+            ifr.ifr_flags |= IFF_VNET_HDR;
+        }
+    }
+
     if (ifname[0] != '\0')
         pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
     else
@@ -1673,14 +1729,15 @@ static TAPState *net_tap_init(VLANState *vlan, const char *model,
                               const char *setup_script, const char *down_script)
 {
     TAPState *s;
-    int fd;
+    int fd, vnet_hdr;
     char ifname[128];
 
     if (ifname1 != NULL)
         pstrcpy(ifname, sizeof(ifname), ifname1);
     else
         ifname[0] = '\0';
-    TFR(fd = tap_open(ifname, sizeof(ifname)));
+    vnet_hdr = 0;
+    TFR(fd = tap_open(ifname, sizeof(ifname), &vnet_hdr));
     if (fd < 0)
         return NULL;
 
@@ -1690,7 +1747,7 @@ static TAPState *net_tap_init(VLANState *vlan, const char *model,
         launch_script(setup_script, ifname, fd)) {
         return NULL;
     }
-    s = net_tap_fd_init(vlan, model, name, fd);
+    s = net_tap_fd_init(vlan, model, name, fd, vnet_hdr);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "ifname=%s,script=%s,downscript=%s",
              ifname, setup_script, down_script);
@@ -2644,7 +2701,7 @@ static int net_init_tap(QemuOpts *opts,
 
         fcntl(fd, F_SETFL, O_NONBLOCK);
 
-        s = net_tap_fd_init(vlan, "tap", name, fd);
+        s = net_tap_fd_init(vlan, "tap", name, fd, tap_probe_vnet_hdr(fd));
         if (!s) {
             close(fd);
         }
diff --git a/tap-linux.h b/tap-linux.h
index cd07ea8..8e75348 100644
--- a/tap-linux.h
+++ b/tap-linux.h
@@ -16,14 +16,28 @@
 #ifndef QEMU_TAP_H
 #define QEMU_TAP_H
 
+#include <stdint.h>
 #include <linux/ioctl.h>
 
 /* Ioctl defines */
 #define TUNSETIFF     _IOW('T', 202, int)
+#define TUNGETFEATURES _IOR('T', 207, unsigned int)
+#define TUNGETIFF      _IOR('T', 210, unsigned int)
 #define TUNSETSNDBUF   _IOW('T', 212, int)
 
 /* TUNSETIFF ifr flags */
 #define IFF_TAP		0x0002
 #define IFF_NO_PI	0x1000
+#define IFF_VNET_HDR	0x4000
+
+struct virtio_net_hdr
+{
+    uint8_t flags;
+    uint8_t gso_type;
+    uint16_t hdr_len;
+    uint16_t gso_size;
+    uint16_t csum_start;
+    uint16_t csum_offset;
+};
 
 #endif /* QEMU_TAP_H */
-- 
1.6.2.5

  parent reply	other threads:[~2009-10-22 16:45 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-22 16:43 [Qemu-devel] [PATCH 00/19 v2] Add virtio-net/tap support for partial csums and GSO Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 01/19] net: remove unused includes of if_tun.h and if_tap.h Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 02/19] net: import linux tap ioctl definitions Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 03/19] net: make tap_receive() re-use tap_receive_iov() code Mark McLoughlin
2009-10-22 16:43 ` Mark McLoughlin [this message]
2009-10-22 16:43 ` [Qemu-devel] [PATCH 05/19] net: refactor tap initialization Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 06/19] net: add a vnet_hdr=on|off parameter Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 07/19] net: add a client type code Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 08/19] net: add tap_has_vnet_hdr() and tap_using_vnet_hdr() APIs Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 09/19] net: add flags parameter to packet queue interface Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 10/19] net: add an API for 'raw' packets Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 11/19] net: add receive_raw parameter to qemu_new_vlan_client() Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 12/19] net: use qemu_send_packet_raw() in qemu_announce_self() Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 13/19] net: implement tap support for receive_raw() Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 14/19] virtio-net: add vnet_hdr support Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 15/19] net: add tap_set_offload() Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 16/19] virtio-net: enable tap offload if guest supports it Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 17/19] Work around dhclient brokenness Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 18/19] Enable UFO on virtio-net and tap devices Mark McLoughlin
2009-10-22 16:43 ` [Qemu-devel] [PATCH 19/19] virtio-net: add tap_has_ufo flag to saved state Mark McLoughlin
2009-10-28 14:30 ` Handling merge conflicts [was Re: [Qemu-devel] [PATCH 00/19 v2] Add virtio-net/tap support for partial csums and GSO] Mark McLoughlin
2009-10-28 14:57   ` Gerd Hoffmann
2009-10-28 15:28     ` Anthony Liguori
2009-10-28 16:24       ` Avi Kivity
2009-10-28 16:35         ` Anthony Liguori
2009-10-28 16:36         ` Anthony Liguori
2009-10-29  8:18           ` Avi Kivity
2009-10-28 19:29         ` Gerd Hoffmann
2009-10-28 15:26   ` Anthony Liguori
2009-10-28 16:29     ` Mark McLoughlin
2009-10-28 16:51       ` Anthony Liguori
2009-10-28 19:25       ` Gerd Hoffmann
2009-10-28 19:19     ` Gerd Hoffmann
2009-10-30 10:04 ` [Qemu-devel] [PATCH 00/19 v2] Add virtio-net/tap support for partial csums and GSO Juha.Riihimaki
2009-10-30 16:59   ` Mark McLoughlin
2009-10-30 21:10     ` Alexander Graf
  -- strict thread matches above, loose matches on Subject: below --
2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 04/19] net: enable IFF_VNET_HDR on tap fds if available Mark McLoughlin

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=1256229830-28066-5-git-send-email-markmc@redhat.com \
    --to=markmc@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /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).