All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.