qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/19]
@ 2009-10-21 11:27 Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 01/19] net: remove unused includes of if_tun.h and if_tap.h Mark McLoughlin
                   ` (18 more replies)
  0 siblings, 19 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel


Hey,
        Over a year ago we added some code to qemu-kvm.git which takes
advantage of the recent tun/tap IFF_VNET_HDR feature in order to allow
virtio-net to send and receive packets with partial checksums and
segmentation offloaded:

  http://article.gmane.org/gmane.comp.emulators.kvm.devel/20440

  "This allows us to pass larger packets and packets with
  partial checkums between the guest and the host, greatly
  increasing the achievable bandwidth."

        Unfortunately, that implementation was quite hacky as it
made some assumptions that would break if e.g. you added another
network client to a vlan where the feature had enabled.

        Now that we have the -netdev parameter, we can more safely
pair the NIC and backend, allowing us to negatiate features like
this.

        What follows is a somewhat cleaned up version of the code
from qemu-kvm.git. Further cleanups are probably possible, but I
think this much is mergeable. Some points of discussion:

  - If you start a guest on a host which supports IFF_VNET_HDR and
    migrate to a host which doesn't support it, we can't just tell
    the guest to stop using GSO.

    We need prevent this by rejecting the migration on the destination
    if IFF_VNET_HDR is required but not available. However, in my
    testing if a load() function returns an error, the migration is
    seen to have completed on the source but failed on the destination.
    Clearly that's wrong, but I haven't investigated further yet.

    Also, we provide a vnet_hdr= arg so that people can prevent the
    feature being used on the source or require that is available on
    the destination.

  - I've slightly abused QemuOpts in 05/19. Comments welcome.

  - The whole mess around adding a 'raw' packet flag for the gratuitous
    ARP packet is gratuitously messy.

  - I'm always enabling IFF_VNET_HDR if it's available. I don't think
    that's a problem, especially compared to what would be required to
    only selectively enable it.

Cheers,
Mark.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 01/19] net: remove unused includes of if_tun.h and if_tap.h
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 02/19] net: import linux tap ioctl definitions Mark McLoughlin
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

Looks like these are just artifacts of vl.c being split up.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 qemu-char.c |    6 ------
 savevm.c    |    6 ------
 vl.c        |    6 ------
 3 files changed, 0 insertions(+), 18 deletions(-)

diff --git a/qemu-char.c b/qemu-char.c
index 8084a67..7b39ace 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -51,12 +51,6 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <net/if.h>
-#ifdef __NetBSD__
-#include <net/if_tap.h>
-#endif
-#ifdef __linux__
-#include <linux/if_tun.h>
-#endif
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <netdb.h>
diff --git a/savevm.c b/savevm.c
index 27a7686..99aa15a 100644
--- a/savevm.c
+++ b/savevm.c
@@ -42,12 +42,6 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <net/if.h>
-#if defined(__NetBSD__)
-#include <net/if_tap.h>
-#endif
-#ifdef __linux__
-#include <linux/if_tun.h>
-#endif
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <netdb.h>
diff --git a/vl.c b/vl.c
index eb2744e..7fa7bdc 100644
--- a/vl.c
+++ b/vl.c
@@ -44,12 +44,6 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <net/if.h>
-#if defined(__NetBSD__)
-#include <net/if_tap.h>
-#endif
-#ifdef __linux__
-#include <linux/if_tun.h>
-#endif
 #include <arpa/inet.h>
 #include <dirent.h>
 #include <netdb.h>
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 02/19] net: import linux tap ioctl definitions
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 01/19] net: remove unused includes of if_tun.h and if_tap.h Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 03/19] net: make tap_receive() re-use tap_receive_iov() code Mark McLoughlin
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

Making features dependent on the availability of newer versions if_tun.h
is going to get seriously clumsy, so let's just import the definitions
we need. It's only a small handful.

If and when we're comfortable depending on 2.6.30 headers, we can remove
this again.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net.c           |   11 +----------
 qemu-options.hx |    8 +-------
 tap-linux.h     |   29 +++++++++++++++++++++++++++++
 3 files changed, 31 insertions(+), 17 deletions(-)
 create mode 100644 tap-linux.h

diff --git a/net.c b/net.c
index 4708080..0e3388b 100644
--- a/net.c
+++ b/net.c
@@ -46,7 +46,7 @@
 #include <net/if_tap.h>
 #endif
 #ifdef __linux__
-#include <linux/if_tun.h>
+#include "tap-linux.h"
 #endif
 #include <arpa/inet.h>
 #include <dirent.h>
@@ -1370,7 +1370,6 @@ static void tap_send(void *opaque)
     } while (size > 0);
 }
 
-#ifdef TUNSETSNDBUF
 /* sndbuf should be set to a value lower than the tx queue
  * capacity of any destination network interface.
  * Ethernet NICs generally have txqueuelen=1000, so 1Mb is
@@ -1393,12 +1392,6 @@ static int tap_set_sndbuf(TAPState *s, QemuOpts *opts)
     }
     return 0;
 }
-#else
-static int tap_set_sndbuf(TAPState *s, QemuOpts *opts)
-{
-    return 0;
-}
-#endif /* TUNSETSNDBUF */
 
 static void tap_cleanup(VLANClientState *vc)
 {
@@ -2972,12 +2965,10 @@ static struct {
                 .name = "downscript",
                 .type = QEMU_OPT_STRING,
                 .help = "script to shut down the interface",
-#ifdef TUNSETSNDBUF
             }, {
                 .name = "sndbuf",
                 .type = QEMU_OPT_SIZE,
                 .help = "send buffer limit"
-#endif
             },
             { /* end of list */ }
         },
diff --git a/qemu-options.hx b/qemu-options.hx
index 20aa242..c745e0c 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -810,21 +810,15 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "-net tap[,vlan=n][,name=str],ifname=name\n"
     "                connect the host TAP network interface to VLAN 'n'\n"
 #else
-    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile]"
-#ifdef TUNSETSNDBUF
-    "[,sndbuf=nbytes]"
-#endif
-    "\n"
+    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes]\n"
     "                connect the host TAP network interface to VLAN 'n' and use the\n"
     "                network scripts 'file' (default=%s)\n"
     "                and 'dfile' (default=%s);\n"
     "                use '[down]script=no' to disable script execution;\n"
     "                use 'fd=h' to connect to an already opened TAP interface\n"
-#ifdef TUNSETSNDBUF
     "                use 'sndbuf=nbytes' to limit the size of the send buffer; the\n"
     "                default of 'sndbuf=1048576' can be disabled using 'sndbuf=0'\n"
 #endif
-#endif
     "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
     "                connect the vlan 'n' to another VLAN using a socket connection\n"
     "-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n"
diff --git a/tap-linux.h b/tap-linux.h
new file mode 100644
index 0000000..cd07ea8
--- /dev/null
+++ b/tap-linux.h
@@ -0,0 +1,29 @@
+/*
+ *  Universal TUN/TAP device driver.
+ *  Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef QEMU_TAP_H
+#define QEMU_TAP_H
+
+#include <linux/ioctl.h>
+
+/* Ioctl defines */
+#define TUNSETIFF     _IOW('T', 202, int)
+#define TUNSETSNDBUF   _IOW('T', 212, int)
+
+/* TUNSETIFF ifr flags */
+#define IFF_TAP		0x0002
+#define IFF_NO_PI	0x1000
+
+#endif /* QEMU_TAP_H */
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 03/19] net: make tap_receive() re-use tap_receive_iov() code
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 01/19] net: remove unused includes of if_tun.h and if_tap.h Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 02/19] net: import linux tap ioctl definitions Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 04/19] net: enable IFF_VNET_HDR on tap fds if available Mark McLoughlin
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

In future we will want to prepend a virtio_net header if the NIC didn't
supply one but IFF_VNET_HDR is enabled on the interface. This is most
easily achived by using writev() in all cases.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net.c |   23 +++++++++++++++--------
 1 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/net.c b/net.c
index 0e3388b..728941a 100644
--- a/net.c
+++ b/net.c
@@ -1291,10 +1291,8 @@ static void tap_writable(void *opaque)
     qemu_flush_queued_packets(s->vc);
 }
 
-static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
-                               int iovcnt)
+static ssize_t tap_write_packet(TAPState *s, const struct iovec *iov, int iovcnt)
 {
-    TAPState *s = vc->opaque;
     ssize_t len;
 
     do {
@@ -1309,16 +1307,25 @@ static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
     return len;
 }
 
+static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
+                               int iovcnt)
+{
+    TAPState *s = vc->opaque;
+
+    return tap_write_packet(s, iov, iovcnt);
+}
+
 static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
 {
     TAPState *s = vc->opaque;
-    ssize_t len;
+    struct iovec iov[1];
+    int iovcnt = 0;
 
-    do {
-        len = write(s->fd, buf, size);
-    } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+    iov[iovcnt].iov_base = (char *)buf;
+    iov[iovcnt].iov_len  = size;
+    iovcnt++;
 
-    return len;
+    return tap_write_packet(s, iov, iovcnt);
 }
 
 static int tap_can_send(void *opaque)
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 04/19] net: enable IFF_VNET_HDR on tap fds if available
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (2 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 03/19] net: make tap_receive() re-use tap_receive_iov() code Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 05/19] net: refactor tap initialization Mark McLoughlin
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

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

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 05/19] net: refactor tap initialization
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (3 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 04/19] net: enable IFF_VNET_HDR on tap fds if available Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 06/19] net: add a vnet_hdr=on|off parameter Mark McLoughlin
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

Re-factor things so that there is only one call site for
net_tap_fd_init().

Two concerns about the QemuOpts usage here - firstly, we set the script
arguments to their default value and, secondly, we set the ifname value
to the name allocated by the kernel if none is supplied. Are we okay
with such things ending up in writeconfig output?

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net.c |   97 +++++++++++++++++++++++++++++++++++------------------------------
 1 files changed, 52 insertions(+), 45 deletions(-)

diff --git a/net.c b/net.c
index 356a280..fccabdb 100644
--- a/net.c
+++ b/net.c
@@ -1475,7 +1475,6 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
                                  tap_receive, tap_receive_iov,
                                  tap_cleanup, s);
     tap_read_poll(s, 1);
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd);
     return s;
 }
 
@@ -1724,38 +1723,34 @@ static int launch_script(const char *setup_script, const char *ifname, int fd)
     return -1;
 }
 
-static TAPState *net_tap_init(VLANState *vlan, const char *model,
-                              const char *name, const char *ifname1,
-                              const char *setup_script, const char *down_script)
+static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
 {
-    TAPState *s;
-    int fd, vnet_hdr;
-    char ifname[128];
+    int fd;
+    char ifname[128] = {0,};
+    const char *setup_script;
 
-    if (ifname1 != NULL)
-        pstrcpy(ifname, sizeof(ifname), ifname1);
-    else
-        ifname[0] = '\0';
-    vnet_hdr = 0;
-    TFR(fd = tap_open(ifname, sizeof(ifname), &vnet_hdr));
-    if (fd < 0)
-        return NULL;
+    if (qemu_opt_get(opts, "ifname")) {
+        pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname"));
+    }
 
-    if (!setup_script || !strcmp(setup_script, "no"))
-        setup_script = "";
-    if (setup_script[0] != '\0' &&
-        launch_script(setup_script, ifname, fd)) {
-        return NULL;
+    *vnet_hdr = 0;
+    TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr));
+    if (fd < 0) {
+        return -1;
     }
-    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);
-    if (down_script && strcmp(down_script, "no")) {
-        snprintf(s->down_script, sizeof(s->down_script), "%s", down_script);
-        snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
+
+    setup_script = qemu_opt_get(opts, "script");
+    if (setup_script &&
+        setup_script[0] != '\0' &&
+        strcmp(setup_script, "no") != 0 &&
+        launch_script(setup_script, ifname, fd)) {
+        close(fd);
+        return -1;
     }
-    return s;
+
+    qemu_opt_set(opts, "ifname", ifname);
+
+    return fd;
 }
 
 #endif /* !_WIN32 */
@@ -2683,10 +2678,9 @@ static int net_init_tap(QemuOpts *opts,
                         VLANState *vlan)
 {
     TAPState *s;
+    int fd, vnet_hdr;
 
     if (qemu_opt_get(opts, "fd")) {
-        int fd;
-
         if (qemu_opt_get(opts, "ifname") ||
             qemu_opt_get(opts, "script") ||
             qemu_opt_get(opts, "downscript")) {
@@ -2701,28 +2695,22 @@ static int net_init_tap(QemuOpts *opts,
 
         fcntl(fd, F_SETFL, O_NONBLOCK);
 
-        s = net_tap_fd_init(vlan, "tap", name, fd, tap_probe_vnet_hdr(fd));
-        if (!s) {
-            close(fd);
-        }
+        vnet_hdr = tap_probe_vnet_hdr(fd);
     } else {
-        const char *ifname, *script, *downscript;
-
-        ifname     = qemu_opt_get(opts, "ifname");
-        script     = qemu_opt_get(opts, "script");
-        downscript = qemu_opt_get(opts, "downscript");
-
-        if (!script) {
-            script = DEFAULT_NETWORK_SCRIPT;
+        if (!qemu_opt_get(opts, "script")) {
+            qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
         }
-        if (!downscript) {
-            downscript = DEFAULT_NETWORK_DOWN_SCRIPT;
+
+        if (!qemu_opt_get(opts, "downscript")) {
+            qemu_opt_set(opts, "downscript", DEFAULT_NETWORK_DOWN_SCRIPT);
         }
 
-        s = net_tap_init(vlan, "tap", name, ifname, script, downscript);
+        fd = net_tap_init(opts, &vnet_hdr);
     }
 
+    s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
     if (!s) {
+        close(fd);
         return -1;
     }
 
@@ -2730,6 +2718,25 @@ static int net_init_tap(QemuOpts *opts,
         return -1;
     }
 
+    if (qemu_opt_get(opts, "fd")) {
+        snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd);
+    } else {
+        const char *ifname, *script, *downscript;
+
+        ifname     = qemu_opt_get(opts, "ifname");
+        script     = qemu_opt_get(opts, "script");
+        downscript = qemu_opt_get(opts, "downscript");
+
+        snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+                 "ifname=%s,script=%s,downscript=%s",
+                 ifname, script, downscript);
+
+        if (strcmp(downscript, "no") != 0) {
+            snprintf(s->down_script, sizeof(s->down_script), "%s", downscript);
+            snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
+        }
+    }
+
     if (vlan) {
         vlan->nb_host_devs++;
     }
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 06/19] net: add a vnet_hdr=on|off parameter
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (4 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 05/19] net: refactor tap initialization Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 07/19] net: add a client type code Mark McLoughlin
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

This allows people to disable the IFF_VNET_HDR flag, e.g. for debugging
purposes or if they know they may migrate the guest to a machine without
IFF_VNET_HDR support.

It also allows making the lack of IFF_VNET_HDR support an error
condition, e.g. in the case where a guest is being migrated from a host
which does support it.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net.c           |   42 ++++++++++++++++++++++++++++++++----------
 qemu-options.hx |    4 +++-
 2 files changed, 35 insertions(+), 11 deletions(-)

diff --git a/net.c b/net.c
index fccabdb..d62ab7b 100644
--- a/net.c
+++ b/net.c
@@ -1479,7 +1479,8 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
 }
 
 #if defined (CONFIG_BSD) || defined (__FreeBSD_kernel__)
-static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
+static int tap_open(char *ifname, int ifname_size,
+                    int *vnet_hdr, int vnet_hdr_required)
 {
     int fd;
     char *dev;
@@ -1621,7 +1622,8 @@ static int tap_alloc(char *dev, size_t dev_size)
     return tap_fd;
 }
 
-static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
+static int tap_open(char *ifname, int ifname_size,
+                    int *vnet_hdr, int vnet_hdr_required)
 {
     char  dev[10]="";
     int fd;
@@ -1634,13 +1636,15 @@ static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
     return fd;
 }
 #elif defined (_AIX)
-static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
+static int tap_open(char *ifname, int ifname_size,
+                    int *vnet_hdr, int vnet_hdr_required)
 {
     fprintf (stderr, "no tap on AIX\n");
     return -1;
 }
 #else
-static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
+static int tap_open(char *ifname, int ifname_size,
+                    int *vnet_hdr, int vnet_hdr_required)
 {
     struct ifreq ifr;
     int fd, ret;
@@ -1653,7 +1657,7 @@ static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
     memset(&ifr, 0, sizeof(ifr));
     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
 
-    {
+    if (*vnet_hdr) {
         unsigned int features;
 
         if (ioctl(fd, TUNGETFEATURES, &features) == 0 &&
@@ -1661,6 +1665,13 @@ static int tap_open(char *ifname, int ifname_size, int *vnet_hdr)
             *vnet_hdr = 1;
             ifr.ifr_flags |= IFF_VNET_HDR;
         }
+
+        if (vnet_hdr_required && !*vnet_hdr) {
+            qemu_error("vnet_hdr=1 requested, but no kernel "
+                       "support for IFF_VNET_HDR available");
+            close(fd);
+            return -1;
+        }
     }
 
     if (ifname[0] != '\0')
@@ -1725,7 +1736,7 @@ static int launch_script(const char *setup_script, const char *ifname, int fd)
 
 static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
 {
-    int fd;
+    int fd, vnet_hdr_required;
     char ifname[128] = {0,};
     const char *setup_script;
 
@@ -1733,8 +1744,14 @@ static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
         pstrcpy(ifname, sizeof(ifname), qemu_opt_get(opts, "ifname"));
     }
 
-    *vnet_hdr = 0;
-    TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr));
+    *vnet_hdr = qemu_opt_get_bool(opts, "vnet_hdr", 1);
+    if (qemu_opt_get(opts, "vnet_hdr")) {
+        vnet_hdr_required = *vnet_hdr;
+    } else {
+        vnet_hdr_required = 0;
+    }
+
+    TFR(fd = tap_open(ifname, sizeof(ifname), vnet_hdr, vnet_hdr_required));
     if (fd < 0) {
         return -1;
     }
@@ -2683,8 +2700,9 @@ static int net_init_tap(QemuOpts *opts,
     if (qemu_opt_get(opts, "fd")) {
         if (qemu_opt_get(opts, "ifname") ||
             qemu_opt_get(opts, "script") ||
-            qemu_opt_get(opts, "downscript")) {
-            qemu_error("ifname=, script= and downscript= is invalid with fd=\n");
+            qemu_opt_get(opts, "downscript") ||
+            qemu_opt_get(opts, "vnet_hdr")) {
+            qemu_error("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=\n");
             return -1;
         }
 
@@ -3040,6 +3058,10 @@ static struct {
                 .name = "sndbuf",
                 .type = QEMU_OPT_SIZE,
                 .help = "send buffer limit"
+            }, {
+                .name = "vnet_hdr",
+                .type = QEMU_OPT_BOOL,
+                .help = "enable the IFF_VNET_HDR flag on the tap interface"
             },
             { /* end of list */ }
         },
diff --git a/qemu-options.hx b/qemu-options.hx
index c745e0c..d78b738 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -810,7 +810,7 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "-net tap[,vlan=n][,name=str],ifname=name\n"
     "                connect the host TAP network interface to VLAN 'n'\n"
 #else
-    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes]\n"
+    "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off]\n"
     "                connect the host TAP network interface to VLAN 'n' and use the\n"
     "                network scripts 'file' (default=%s)\n"
     "                and 'dfile' (default=%s);\n"
@@ -818,6 +818,8 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
     "                use 'fd=h' to connect to an already opened TAP interface\n"
     "                use 'sndbuf=nbytes' to limit the size of the send buffer; the\n"
     "                default of 'sndbuf=1048576' can be disabled using 'sndbuf=0'\n"
+    "                use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag; use\n"
+    "                vnet_hdr=on to make the lack of IFF_VNET_HDR support an error condition\n"
 #endif
     "-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
     "                connect the vlan 'n' to another VLAN using a socket connection\n"
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 07/19] net: add a client type code
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (5 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 06/19] net: add a vnet_hdr=on|off parameter Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 08/19] net: add tap_has_vnet_hdr() and tap_using_vnet_hdr() APIs Mark McLoughlin
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

This is so as to allow APIs which operate on specific client types
without having to add a function table entry which is only implemented
by a single client type.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 hw/dp8393x.c     |    3 ++-
 hw/etraxfs_eth.c |    3 ++-
 hw/mcf_fec.c     |    3 ++-
 hw/mipsnet.c     |    3 ++-
 hw/qdev.c        |    3 ++-
 hw/usb-net.c     |    3 ++-
 hw/xen_nic.c     |    3 ++-
 net.c            |   22 +++++++++++++++-------
 net.h            |   14 +++++++++++++-
 tap-win32.c      |    3 ++-
 10 files changed, 44 insertions(+), 16 deletions(-)

diff --git a/hw/dp8393x.c b/hw/dp8393x.c
index e4caab0..5622170 100644
--- a/hw/dp8393x.c
+++ b/hw/dp8393x.c
@@ -889,7 +889,8 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
     s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s);
     s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
 
-    s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->netdev,
+    s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
+                                          nd->vlan, nd->netdev,
                                           nd->model, nd->name,
                                           nic_can_receive, nic_receive, NULL,
                                           nic_cleanup, s);
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index a411dab..2a583a3 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -590,7 +590,8 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
 	eth->ethregs = cpu_register_io_memory(eth_read, eth_write, eth);
 	cpu_register_physical_memory (base, 0x5c, eth->ethregs);
 
-	eth->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->netdev,
+	eth->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
+                                                nd->vlan, nd->netdev,
                                                 nd->model, nd->name,
                                                 eth_can_receive, eth_receive,
                                                 NULL, eth_cleanup, eth);
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
index f9f437a..0567bcd 100644
--- a/hw/mcf_fec.c
+++ b/hw/mcf_fec.c
@@ -462,7 +462,8 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
                                            mcf_fec_writefn, s);
     cpu_register_physical_memory(base, 0x400, s->mmio_index);
 
-    s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->netdev,
+    s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
+                                          nd->vlan, nd->netdev,
                                           nd->model, nd->name,
                                           mcf_fec_can_receive, mcf_fec_receive,
                                           NULL, mcf_fec_cleanup, s);
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index ea8b570..d32099f 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -263,7 +263,8 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
     s->io_base = base;
     s->irq = irq;
     if (nd) {
-        s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->netdev,
+        s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
+                                              nd->vlan, nd->netdev,
                                               nd->model, nd->name,
                                               mipsnet_can_receive, mipsnet_receive,
                                               NULL, mipsnet_cleanup, s);
diff --git a/hw/qdev.c b/hw/qdev.c
index 20f931c..bc3a0d5 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -370,7 +370,8 @@ VLANClientState *qdev_get_vlan_client(DeviceState *dev,
 {
     NICInfo *nd = dev->nd;
     assert(nd);
-    nd->vc = qemu_new_vlan_client(nd->vlan, nd->netdev,
+    nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
+                                  nd->vlan, nd->netdev,
                                   nd->model, nd->name,
                                   can_receive, receive, receive_iov,
                                   cleanup, opaque);
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 5c753e0..2393812 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1460,7 +1460,8 @@ USBDevice *usb_net_init(NICInfo *nd)
 
     memcpy(s->mac, nd->macaddr, 6);
 
-    s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->netdev,
+    s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
+                                          nd->vlan, nd->netdev,
                                           nd->model, nd->name,
                                           usbnet_can_receive,
                                           usbnet_receive,
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index b09b48a..2a179f0 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -301,7 +301,8 @@ static int net_init(struct XenDevice *xendev)
 	return -1;
 
     vlan = qemu_find_vlan(netdev->xendev.dev, 1);
-    netdev->vs = qemu_new_vlan_client(vlan, NULL, "xen", NULL,
+    netdev->vs = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
+                                      vlan, NULL, "xen", NULL,
                                       net_rx_ok, net_rx_packet, NULL,
                                       NULL, netdev);
     snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str),
diff --git a/net.c b/net.c
index d62ab7b..638ba36 100644
--- a/net.c
+++ b/net.c
@@ -310,7 +310,8 @@ static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
                                        int iovcnt,
                                        void *opaque);
 
-VLANClientState *qemu_new_vlan_client(VLANState *vlan,
+VLANClientState *qemu_new_vlan_client(net_client_type type,
+                                      VLANState *vlan,
                                       VLANClientState *peer,
                                       const char *model,
                                       const char *name,
@@ -324,6 +325,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
 
     vc = qemu_mallocz(sizeof(VLANClientState));
 
+    vc->type = type;
     vc->model = qemu_strdup(model);
     if (name)
         vc->name = qemu_strdup(name);
@@ -865,7 +867,8 @@ static int net_slirp_init(VLANState *vlan, const char *model,
     }
 #endif
 
-    s->vc = qemu_new_vlan_client(vlan, NULL, model, name, NULL,
+    s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP,
+                                 vlan, NULL, model, name, NULL,
                                  slirp_receive, NULL,
                                  net_slirp_cleanup, s);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
@@ -1471,7 +1474,8 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
     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,
+    s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP,
+                                 vlan, NULL, model, name, NULL,
                                  tap_receive, tap_receive_iov,
                                  tap_cleanup, s);
     tap_read_poll(s, 1);
@@ -1830,7 +1834,8 @@ static int net_vde_init(VLANState *vlan, const char *model,
         free(s);
         return -1;
     }
-    s->vc = qemu_new_vlan_client(vlan, NULL, model, name, NULL,
+    s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_VDE,
+                                 vlan, NULL, model, name, NULL,
                                  vde_receive, NULL,
                                  vde_cleanup, s);
     qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
@@ -2070,7 +2075,8 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
     s = qemu_mallocz(sizeof(NetSocketState));
     s->fd = fd;
 
-    s->vc = qemu_new_vlan_client(vlan, NULL, model, name, NULL,
+    s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET,
+                                 vlan, NULL, model, name, NULL,
                                  net_socket_receive_dgram, NULL,
                                  net_socket_cleanup, s);
     qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
@@ -2099,7 +2105,8 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
     NetSocketState *s;
     s = qemu_mallocz(sizeof(NetSocketState));
     s->fd = fd;
-    s->vc = qemu_new_vlan_client(vlan, NULL, model, name, NULL,
+    s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET,
+                                 vlan, NULL, model, name, NULL,
                                  net_socket_receive, NULL,
                                  net_socket_cleanup, s);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
@@ -2381,7 +2388,8 @@ static int net_dump_init(VLANState *vlan, const char *device,
         return -1;
     }
 
-    s->pcap_vc = qemu_new_vlan_client(vlan, NULL, device, name, NULL,
+    s->pcap_vc = qemu_new_vlan_client(NET_CLIENT_TYPE_DUMP,
+                                      vlan, NULL, device, name, NULL,
                                       dump_receive, NULL,
                                       net_dump_cleanup, s);
     snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str),
diff --git a/net.h b/net.h
index 439de2a..aefeef4 100644
--- a/net.h
+++ b/net.h
@@ -9,6 +9,16 @@
 
 /* VLANs support */
 
+typedef enum {
+    NET_CLIENT_TYPE_NONE,
+    NET_CLIENT_TYPE_NIC,
+    NET_CLIENT_TYPE_SLIRP,
+    NET_CLIENT_TYPE_TAP,
+    NET_CLIENT_TYPE_SOCKET,
+    NET_CLIENT_TYPE_VDE,
+    NET_CLIENT_TYPE_DUMP
+} net_client_type;
+
 typedef int (NetCanReceive)(VLANClientState *);
 typedef ssize_t (NetReceive)(VLANClientState *, const uint8_t *, size_t);
 typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int);
@@ -16,6 +26,7 @@ typedef void (NetCleanup) (VLANClientState *);
 typedef void (LinkStatusChanged)(VLANClientState *);
 
 struct VLANClientState {
+    net_client_type type;
     NetReceive *receive;
     NetReceiveIOV *receive_iov;
     /* Packets may still be sent if this returns zero.  It's used to
@@ -43,7 +54,8 @@ struct VLANState {
 };
 
 VLANState *qemu_find_vlan(int id, int allocate);
-VLANClientState *qemu_new_vlan_client(VLANState *vlan,
+VLANClientState *qemu_new_vlan_client(net_client_type type,
+                                      VLANState *vlan,
                                       VLANClientState *peer,
                                       const char *model,
                                       const char *name,
diff --git a/tap-win32.c b/tap-win32.c
index e4fdde8..e2bac3e 100644
--- a/tap-win32.c
+++ b/tap-win32.c
@@ -677,7 +677,8 @@ int tap_win32_init(VLANState *vlan, const char *model,
         return -1;
     }
 
-    s->vc = qemu_new_vlan_client(vlan, NULL, model, name,
+    s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP,
+                                 vlan, NULL, model, name,
                                  NULL, tap_receive,
                                  NULL, tap_cleanup, s);
 
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 08/19] net: add tap_has_vnet_hdr() and tap_using_vnet_hdr() APIs
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (6 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 07/19] net: add a client type code Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 09/19] net: add flags parameter to packet queue interface Mark McLoughlin
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

These lamely named functions allow virtio-net to query whether
IFF_VNET_HDR is enabled on a tap interface and inform the tap code
that virtio-net will supply packets with a vnet header.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net.c |   39 +++++++++++++++++++++++++++++++++++----
 net.h |    3 +++
 2 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/net.c b/net.c
index 638ba36..56d979b 100644
--- a/net.c
+++ b/net.c
@@ -1246,7 +1246,15 @@ void do_info_usernet(Monitor *mon)
 
 #endif /* CONFIG_SLIRP */
 
-#if !defined(_WIN32)
+#if defined(_WIN32)
+int tap_has_vnet_hdr(VLANClientState *vc)
+{
+    return 0;
+}
+void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr)
+{
+}
+#else /* !defined(_WIN32) */
 
 /* Maximum GSO packet size (64k) plus plenty of room for
  * the ethernet and virtio_net headers
@@ -1262,6 +1270,7 @@ typedef struct TAPState {
     unsigned int read_poll : 1;
     unsigned int write_poll : 1;
     unsigned int has_vnet_hdr : 1;
+    unsigned int using_vnet_hdr : 1;
 } TAPState;
 
 static int launch_script(const char *setup_script, const char *ifname, int fd);
@@ -1324,7 +1333,7 @@ static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
     struct iovec iov_copy[iovcnt + 1];
     struct virtio_net_hdr hdr = { 0, };
 
-    if (s->has_vnet_hdr) {
+    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
         iov_copy[0].iov_base = &hdr;
         iov_copy[0].iov_len =  sizeof(hdr);
         memcpy(&iov_copy[1], iov, iovcnt * sizeof(*iov));
@@ -1342,7 +1351,7 @@ static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
     int iovcnt = 0;
     struct virtio_net_hdr hdr = { 0, };
 
-    if (s->has_vnet_hdr) {
+    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
         iov[iovcnt].iov_base = &hdr;
         iov[iovcnt].iov_len  = sizeof(hdr);
         iovcnt++;
@@ -1399,7 +1408,7 @@ static void tap_send(void *opaque)
             break;
         }
 
-        if (s->has_vnet_hdr) {
+        if (s->has_vnet_hdr && !s->using_vnet_hdr) {
             buf  += sizeof(struct virtio_net_hdr);
             size -= sizeof(struct virtio_net_hdr);
         }
@@ -1434,6 +1443,27 @@ static int tap_set_sndbuf(TAPState *s, QemuOpts *opts)
     return 0;
 }
 
+int tap_has_vnet_hdr(VLANClientState *vc)
+{
+    TAPState *s = vc->opaque;
+
+    assert(vc->type == NET_CLIENT_TYPE_TAP);
+
+    return s->has_vnet_hdr;
+}
+
+void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr)
+{
+    TAPState *s = vc->opaque;
+
+    using_vnet_hdr = using_vnet_hdr != 0;
+
+    assert(vc->type == NET_CLIENT_TYPE_TAP);
+    assert(s->has_vnet_hdr == using_vnet_hdr);
+
+    s->using_vnet_hdr = using_vnet_hdr;
+}
+
 static int tap_probe_vnet_hdr(int fd)
 {
     struct ifreq ifr;
@@ -1474,6 +1504,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
     s = qemu_mallocz(sizeof(TAPState));
     s->fd = fd;
     s->has_vnet_hdr = vnet_hdr != 0;
+    s->using_vnet_hdr = 0;
     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP,
                                  vlan, NULL, model, name, NULL,
                                  tap_receive, tap_receive_iov,
diff --git a/net.h b/net.h
index aefeef4..5f28860 100644
--- a/net.h
+++ b/net.h
@@ -165,4 +165,7 @@ VLANClientState *qdev_get_vlan_client(DeviceState *dev,
                                       NetCleanup *cleanup,
                                       void *opaque);
 
+int tap_has_vnet_hdr(VLANClientState *vc);
+void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr);
+
 #endif
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 09/19] net: add flags parameter to packet queue interface
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (7 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 08/19] net: add tap_has_vnet_hdr() and tap_using_vnet_hdr() APIs Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 10/19] net: add an API for 'raw' packets Mark McLoughlin
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

This allows for the addition of a raw flag, and leaves the way open
for other flags too.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net-queue.c |   26 ++++++++++++++++++--------
 net-queue.h |    6 ++++++
 net.c       |   14 ++++++++++++--
 3 files changed, 36 insertions(+), 10 deletions(-)

diff --git a/net-queue.c b/net-queue.c
index 75457f0..f6b01e9 100644
--- a/net-queue.c
+++ b/net-queue.c
@@ -41,6 +41,7 @@
 struct NetPacket {
     QTAILQ_ENTRY(NetPacket) entry;
     VLANClientState *sender;
+    unsigned flags;
     int size;
     NetPacketSent *sent_cb;
     uint8_t data[0];
@@ -89,6 +90,7 @@ void qemu_del_net_queue(NetQueue *queue)
 
 static ssize_t qemu_net_queue_append(NetQueue *queue,
                                      VLANClientState *sender,
+                                     unsigned flags,
                                      const uint8_t *buf,
                                      size_t size,
                                      NetPacketSent *sent_cb)
@@ -97,6 +99,7 @@ static ssize_t qemu_net_queue_append(NetQueue *queue,
 
     packet = qemu_malloc(sizeof(NetPacket) + size);
     packet->sender = sender;
+    packet->flags = flags;
     packet->size = size;
     packet->sent_cb = sent_cb;
     memcpy(packet->data, buf, size);
@@ -108,6 +111,7 @@ static ssize_t qemu_net_queue_append(NetQueue *queue,
 
 static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
                                          VLANClientState *sender,
+                                         unsigned flags,
                                          const struct iovec *iov,
                                          int iovcnt,
                                          NetPacketSent *sent_cb)
@@ -123,6 +127,7 @@ static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
     packet = qemu_malloc(sizeof(NetPacket) + max_len);
     packet->sender = sender;
     packet->sent_cb = sent_cb;
+    packet->flags = flags;
     packet->size = 0;
 
     for (i = 0; i < iovcnt; i++) {
@@ -139,13 +144,14 @@ static ssize_t qemu_net_queue_append_iov(NetQueue *queue,
 
 static ssize_t qemu_net_queue_deliver(NetQueue *queue,
                                       VLANClientState *sender,
+                                      unsigned flags,
                                       const uint8_t *data,
                                       size_t size)
 {
     ssize_t ret = -1;
 
     queue->delivering = 1;
-    ret = queue->deliver(sender, data, size, queue->opaque);
+    ret = queue->deliver(sender, flags, data, size, queue->opaque);
     queue->delivering = 0;
 
     return ret;
@@ -153,13 +159,14 @@ static ssize_t qemu_net_queue_deliver(NetQueue *queue,
 
 static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
                                           VLANClientState *sender,
+                                          unsigned flags,
                                           const struct iovec *iov,
                                           int iovcnt)
 {
     ssize_t ret = -1;
 
     queue->delivering = 1;
-    ret = queue->deliver_iov(sender, iov, iovcnt, queue->opaque);
+    ret = queue->deliver_iov(sender, flags, iov, iovcnt, queue->opaque);
     queue->delivering = 0;
 
     return ret;
@@ -167,6 +174,7 @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
 
 ssize_t qemu_net_queue_send(NetQueue *queue,
                             VLANClientState *sender,
+                            unsigned flags,
                             const uint8_t *data,
                             size_t size,
                             NetPacketSent *sent_cb)
@@ -174,12 +182,12 @@ ssize_t qemu_net_queue_send(NetQueue *queue,
     ssize_t ret;
 
     if (queue->delivering) {
-        return qemu_net_queue_append(queue, sender, data, size, NULL);
+        return qemu_net_queue_append(queue, sender, flags, data, size, NULL);
     }
 
-    ret = qemu_net_queue_deliver(queue, sender, data, size);
+    ret = qemu_net_queue_deliver(queue, sender, flags, data, size);
     if (ret == 0 && sent_cb != NULL) {
-        qemu_net_queue_append(queue, sender, data, size, sent_cb);
+        qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
         return 0;
     }
 
@@ -190,6 +198,7 @@ ssize_t qemu_net_queue_send(NetQueue *queue,
 
 ssize_t qemu_net_queue_send_iov(NetQueue *queue,
                                 VLANClientState *sender,
+                                unsigned flags,
                                 const struct iovec *iov,
                                 int iovcnt,
                                 NetPacketSent *sent_cb)
@@ -197,12 +206,12 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue,
     ssize_t ret;
 
     if (queue->delivering) {
-        return qemu_net_queue_append_iov(queue, sender, iov, iovcnt, NULL);
+        return qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, NULL);
     }
 
-    ret = qemu_net_queue_deliver_iov(queue, sender, iov, iovcnt);
+    ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt);
     if (ret == 0 && sent_cb != NULL) {
-        qemu_net_queue_append_iov(queue, sender, iov, iovcnt, sent_cb);
+        qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
         return 0;
     }
 
@@ -234,6 +243,7 @@ void qemu_net_queue_flush(NetQueue *queue)
 
         ret = qemu_net_queue_deliver(queue,
                                      packet->sender,
+                                     packet->flags,
                                      packet->data,
                                      packet->size);
         if (ret == 0 && packet->sent_cb != NULL) {
diff --git a/net-queue.h b/net-queue.h
index ea17df6..343760e 100644
--- a/net-queue.h
+++ b/net-queue.h
@@ -32,15 +32,19 @@ typedef struct NetQueue NetQueue;
 typedef void (NetPacketSent) (VLANClientState *sender, ssize_t ret);
 
 typedef ssize_t (NetPacketDeliver) (VLANClientState *sender,
+                                    unsigned flags,
                                     const uint8_t *buf,
                                     size_t size,
                                     void *opaque);
 
 typedef ssize_t (NetPacketDeliverIOV) (VLANClientState *sender,
+                                       unsigned flags,
                                        const struct iovec *iov,
                                        int iovcnt,
                                        void *opaque);
 
+#define QEMU_NET_PACKET_FLAG_NONE  0
+
 NetQueue *qemu_new_net_queue(NetPacketDeliver *deliver,
                              NetPacketDeliverIOV *deliver_iov,
                              void *opaque);
@@ -48,12 +52,14 @@ void qemu_del_net_queue(NetQueue *queue);
 
 ssize_t qemu_net_queue_send(NetQueue *queue,
                             VLANClientState *sender,
+                            unsigned flags,
                             const uint8_t *data,
                             size_t size,
                             NetPacketSent *sent_cb);
 
 ssize_t qemu_net_queue_send_iov(NetQueue *queue,
                                 VLANClientState *sender,
+                                unsigned flags,
                                 const struct iovec *iov,
                                 int iovcnt,
                                 NetPacketSent *sent_cb);
diff --git a/net.c b/net.c
index 56d979b..30dc402 100644
--- a/net.c
+++ b/net.c
@@ -302,10 +302,12 @@ static char *assign_name(VLANClientState *vc1, const char *model)
 }
 
 static ssize_t qemu_deliver_packet(VLANClientState *sender,
+                                   unsigned flags,
                                    const uint8_t *data,
                                    size_t size,
                                    void *opaque);
 static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
+                                       unsigned flags,
                                        const struct iovec *iov,
                                        int iovcnt,
                                        void *opaque);
@@ -450,6 +452,7 @@ int qemu_can_send_packet(VLANClientState *sender)
 }
 
 static ssize_t qemu_deliver_packet(VLANClientState *sender,
+                                   unsigned flags,
                                    const uint8_t *data,
                                    size_t size,
                                    void *opaque)
@@ -464,6 +467,7 @@ static ssize_t qemu_deliver_packet(VLANClientState *sender,
 }
 
 static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender,
+                                        unsigned flags,
                                         const uint8_t *buf,
                                         size_t size,
                                         void *opaque)
@@ -543,7 +547,9 @@ ssize_t qemu_send_packet_async(VLANClientState *sender,
         queue = sender->vlan->send_queue;
     }
 
-    return qemu_net_queue_send(queue, sender, buf, size, sent_cb);
+    return qemu_net_queue_send(queue, sender,
+                               QEMU_NET_PACKET_FLAG_NONE,
+                               buf, size, sent_cb);
 }
 
 void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
@@ -580,6 +586,7 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
 }
 
 static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
+                                       unsigned flags,
                                        const struct iovec *iov,
                                        int iovcnt,
                                        void *opaque)
@@ -598,6 +605,7 @@ static ssize_t qemu_deliver_packet_iov(VLANClientState *sender,
 }
 
 static ssize_t qemu_vlan_deliver_packet_iov(VLANClientState *sender,
+                                            unsigned flags,
                                             const struct iovec *iov,
                                             int iovcnt,
                                             void *opaque)
@@ -646,7 +654,9 @@ ssize_t qemu_sendv_packet_async(VLANClientState *sender,
         queue = sender->vlan->send_queue;
     }
 
-    return qemu_net_queue_send_iov(queue, sender, iov, iovcnt, sent_cb);
+    return qemu_net_queue_send_iov(queue, sender,
+                                   QEMU_NET_PACKET_FLAG_NONE,
+                                   iov, iovcnt, sent_cb);
 }
 
 ssize_t
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 10/19] net: add an API for 'raw' packets
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (8 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 09/19] net: add flags parameter to packet queue interface Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 11/19] net: add receive_raw parameter to qemu_new_vlan_client() Mark McLoughlin
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

In the case where a NIC and backend agree on a packet header format,
this API allows injecting packets which lack the agreed upon header.

We need this for sending our gratuitous ARP.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net-queue.h |    1 +
 net.c       |   37 +++++++++++++++++++++++++++++--------
 net.h       |    2 ++
 3 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/net-queue.h b/net-queue.h
index 343760e..a31958e 100644
--- a/net-queue.h
+++ b/net-queue.h
@@ -44,6 +44,7 @@ typedef ssize_t (NetPacketDeliverIOV) (VLANClientState *sender,
                                        void *opaque);
 
 #define QEMU_NET_PACKET_FLAG_NONE  0
+#define QEMU_NET_PACKET_FLAG_RAW  (1<<0)
 
 NetQueue *qemu_new_net_queue(NetPacketDeliver *deliver,
                              NetPacketDeliverIOV *deliver_iov,
diff --git a/net.c b/net.c
index 30dc402..50d2f83 100644
--- a/net.c
+++ b/net.c
@@ -463,7 +463,10 @@ static ssize_t qemu_deliver_packet(VLANClientState *sender,
         return size;
     }
 
-    return vc->receive(vc, data, size);
+    if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw)
+        return vc->receive_raw(vc, data, size);
+    else
+        return vc->receive(vc, data, size);
 }
 
 static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender,
@@ -488,7 +491,10 @@ static ssize_t qemu_vlan_deliver_packet(VLANClientState *sender,
             continue;
         }
 
-        len = vc->receive(vc, buf, size);
+        if (flags & QEMU_NET_PACKET_FLAG_RAW && vc->receive_raw)
+            len = vc->receive_raw(vc, buf, size);
+        else
+            len = vc->receive(vc, buf, size);
 
         ret = (ret >= 0) ? ret : len;
     }
@@ -526,9 +532,10 @@ void qemu_flush_queued_packets(VLANClientState *vc)
     qemu_net_queue_flush(queue);
 }
 
-ssize_t qemu_send_packet_async(VLANClientState *sender,
-                               const uint8_t *buf, int size,
-                               NetPacketSent *sent_cb)
+static ssize_t qemu_send_packet_async_with_flags(VLANClientState *sender,
+                                                 unsigned flags,
+                                                 const uint8_t *buf, int size,
+                                                 NetPacketSent *sent_cb)
 {
     NetQueue *queue;
 
@@ -547,9 +554,15 @@ ssize_t qemu_send_packet_async(VLANClientState *sender,
         queue = sender->vlan->send_queue;
     }
 
-    return qemu_net_queue_send(queue, sender,
-                               QEMU_NET_PACKET_FLAG_NONE,
-                               buf, size, sent_cb);
+    return qemu_net_queue_send(queue, sender, flags, buf, size, sent_cb);
+}
+
+ssize_t qemu_send_packet_async(VLANClientState *sender,
+                               const uint8_t *buf, int size,
+                               NetPacketSent *sent_cb)
+{
+    return qemu_send_packet_async_with_flags(sender, QEMU_NET_PACKET_FLAG_NONE,
+                                             buf, size, sent_cb);
 }
 
 void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
@@ -557,6 +570,12 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
     qemu_send_packet_async(vc, buf, size, NULL);
 }
 
+ssize_t qemu_send_packet_raw(VLANClientState *vc, const uint8_t *buf, int size)
+{
+    return qemu_send_packet_async_with_flags(vc, QEMU_NET_PACKET_FLAG_RAW,
+                                             buf, size, NULL);
+}
+
 static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
                                int iovcnt)
 {
@@ -626,6 +645,8 @@ static ssize_t qemu_vlan_deliver_packet_iov(VLANClientState *sender,
             continue;
         }
 
+        assert(!(flags & QEMU_NET_PACKET_FLAG_RAW));
+
         if (vc->receive_iov) {
             len = vc->receive_iov(vc, iov, iovcnt);
         } else {
diff --git a/net.h b/net.h
index 5f28860..53d813c 100644
--- a/net.h
+++ b/net.h
@@ -28,6 +28,7 @@ typedef void (LinkStatusChanged)(VLANClientState *);
 struct VLANClientState {
     net_client_type type;
     NetReceive *receive;
+    NetReceive *receive_raw;
     NetReceiveIOV *receive_iov;
     /* Packets may still be sent if this returns zero.  It's used to
        rate-limit the slirp code.  */
@@ -72,6 +73,7 @@ ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
 ssize_t qemu_sendv_packet_async(VLANClientState *vc, const struct iovec *iov,
                                 int iovcnt, NetPacketSent *sent_cb);
 void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+ssize_t qemu_send_packet_raw(VLANClientState *vc, const uint8_t *buf, int size);
 ssize_t qemu_send_packet_async(VLANClientState *vc, const uint8_t *buf,
                                int size, NetPacketSent *sent_cb);
 void qemu_purge_queued_packets(VLANClientState *vc);
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 11/19] net: add receive_raw parameter to qemu_new_vlan_client()
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (9 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 10/19] net: add an API for 'raw' packets Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 12/19] net: use qemu_send_packet_raw() in qemu_announce_self() Mark McLoughlin
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

Trivial patch to allow supplying a receive_raw function.

A future cleanup should combine this function pointer parameters into a
table.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 hw/dp8393x.c     |    2 +-
 hw/etraxfs_eth.c |    2 +-
 hw/mcf_fec.c     |    2 +-
 hw/mipsnet.c     |    2 +-
 hw/qdev.c        |    3 ++-
 hw/usb-net.c     |    2 +-
 hw/xen_nic.c     |    2 +-
 net.c            |   14 ++++++++------
 net.h            |    1 +
 tap-win32.c      |    2 +-
 10 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/hw/dp8393x.c b/hw/dp8393x.c
index 5622170..ae8b16e 100644
--- a/hw/dp8393x.c
+++ b/hw/dp8393x.c
@@ -892,7 +892,7 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
     s->vc = nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
                                           nd->vlan, nd->netdev,
                                           nd->model, nd->name,
-                                          nic_can_receive, nic_receive, NULL,
+                                          nic_can_receive, nic_receive, NULL, NULL,
                                           nic_cleanup, s);
 
     qemu_format_nic_info_str(s->vc, nd->macaddr);
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 2a583a3..ffe7082 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -594,7 +594,7 @@ void *etraxfs_eth_init(NICInfo *nd, target_phys_addr_t base, int phyaddr)
                                                 nd->vlan, nd->netdev,
                                                 nd->model, nd->name,
                                                 eth_can_receive, eth_receive,
-                                                NULL, eth_cleanup, eth);
+                                                NULL, NULL, eth_cleanup, eth);
 	eth->vc->opaque = eth;
 	eth->vc->link_status_changed = eth_set_link;
 
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
index 0567bcd..9f0d0f4 100644
--- a/hw/mcf_fec.c
+++ b/hw/mcf_fec.c
@@ -466,7 +466,7 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
                                           nd->vlan, nd->netdev,
                                           nd->model, nd->name,
                                           mcf_fec_can_receive, mcf_fec_receive,
-                                          NULL, mcf_fec_cleanup, s);
+                                          NULL, NULL, mcf_fec_cleanup, s);
     memcpy(s->macaddr, nd->macaddr, 6);
     qemu_format_nic_info_str(s->vc, s->macaddr);
 }
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index d32099f..65e1d59 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -267,7 +267,7 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
                                               nd->vlan, nd->netdev,
                                               nd->model, nd->name,
                                               mipsnet_can_receive, mipsnet_receive,
-                                              NULL, mipsnet_cleanup, s);
+                                              NULL, NULL, mipsnet_cleanup, s);
     } else {
         s->vc = NULL;
     }
diff --git a/hw/qdev.c b/hw/qdev.c
index bc3a0d5..38ac037 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -373,7 +373,8 @@ VLANClientState *qdev_get_vlan_client(DeviceState *dev,
     nd->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
                                   nd->vlan, nd->netdev,
                                   nd->model, nd->name,
-                                  can_receive, receive, receive_iov,
+                                  can_receive, receive,
+                                  NULL, receive_iov,
                                   cleanup, opaque);
     return nd->vc;
 }
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 2393812..9c6549c 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1465,7 +1465,7 @@ USBDevice *usb_net_init(NICInfo *nd)
                                           nd->model, nd->name,
                                           usbnet_can_receive,
                                           usbnet_receive,
-                                          NULL,
+                                          NULL, NULL,
                                           usbnet_cleanup, s);
 
     qemu_format_nic_info_str(s->vc, s->mac);
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index 2a179f0..75599d6 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -303,7 +303,7 @@ static int net_init(struct XenDevice *xendev)
     vlan = qemu_find_vlan(netdev->xendev.dev, 1);
     netdev->vs = qemu_new_vlan_client(NET_CLIENT_TYPE_NIC,
                                       vlan, NULL, "xen", NULL,
-                                      net_rx_ok, net_rx_packet, NULL,
+                                      net_rx_ok, net_rx_packet, NULL, NULL,
                                       NULL, netdev);
     snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str),
              "nic: xenbus vif macaddr=%s", netdev->mac);
diff --git a/net.c b/net.c
index 50d2f83..56d9de7 100644
--- a/net.c
+++ b/net.c
@@ -319,6 +319,7 @@ VLANClientState *qemu_new_vlan_client(net_client_type type,
                                       const char *name,
                                       NetCanReceive *can_receive,
                                       NetReceive *receive,
+                                      NetReceive *receive_raw,
                                       NetReceiveIOV *receive_iov,
                                       NetCleanup *cleanup,
                                       void *opaque)
@@ -335,6 +336,7 @@ VLANClientState *qemu_new_vlan_client(net_client_type type,
         vc->name = assign_name(vc, model);
     vc->can_receive = can_receive;
     vc->receive = receive;
+    vc->receive_raw = receive_raw;
     vc->receive_iov = receive_iov;
     vc->cleanup = cleanup;
     vc->opaque = opaque;
@@ -900,7 +902,7 @@ static int net_slirp_init(VLANState *vlan, const char *model,
 
     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SLIRP,
                                  vlan, NULL, model, name, NULL,
-                                 slirp_receive, NULL,
+                                 slirp_receive, NULL, NULL,
                                  net_slirp_cleanup, s);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n');
@@ -1538,7 +1540,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
     s->using_vnet_hdr = 0;
     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP,
                                  vlan, NULL, model, name, NULL,
-                                 tap_receive, tap_receive_iov,
+                                 tap_receive, NULL, tap_receive_iov,
                                  tap_cleanup, s);
     tap_read_poll(s, 1);
     return s;
@@ -1898,7 +1900,7 @@ static int net_vde_init(VLANState *vlan, const char *model,
     }
     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_VDE,
                                  vlan, NULL, model, name, NULL,
-                                 vde_receive, NULL,
+                                 vde_receive, NULL, NULL,
                                  vde_cleanup, s);
     qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d",
@@ -2139,7 +2141,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
 
     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET,
                                  vlan, NULL, model, name, NULL,
-                                 net_socket_receive_dgram, NULL,
+                                 net_socket_receive_dgram, NULL, NULL,
                                  net_socket_cleanup, s);
     qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
 
@@ -2169,7 +2171,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
     s->fd = fd;
     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_SOCKET,
                                  vlan, NULL, model, name, NULL,
-                                 net_socket_receive, NULL,
+                                 net_socket_receive, NULL, NULL,
                                  net_socket_cleanup, s);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "socket: fd=%d", fd);
@@ -2452,7 +2454,7 @@ static int net_dump_init(VLANState *vlan, const char *device,
 
     s->pcap_vc = qemu_new_vlan_client(NET_CLIENT_TYPE_DUMP,
                                       vlan, NULL, device, name, NULL,
-                                      dump_receive, NULL,
+                                      dump_receive, NULL, NULL,
                                       net_dump_cleanup, s);
     snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str),
              "dump to %s (len=%d)", filename, len);
diff --git a/net.h b/net.h
index 53d813c..6255e2b 100644
--- a/net.h
+++ b/net.h
@@ -62,6 +62,7 @@ VLANClientState *qemu_new_vlan_client(net_client_type type,
                                       const char *name,
                                       NetCanReceive *can_receive,
                                       NetReceive *receive,
+                                      NetReceive *receive_raw,
                                       NetReceiveIOV *receive_iov,
                                       NetCleanup *cleanup,
                                       void *opaque);
diff --git a/tap-win32.c b/tap-win32.c
index e2bac3e..7d92df2 100644
--- a/tap-win32.c
+++ b/tap-win32.c
@@ -680,7 +680,7 @@ int tap_win32_init(VLANState *vlan, const char *model,
     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP,
                                  vlan, NULL, model, name,
                                  NULL, tap_receive,
-                                 NULL, tap_cleanup, s);
+                                 NULL, NULL, tap_cleanup, s);
 
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "tap: ifname=%s", ifname);
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 12/19] net: use qemu_send_packet_raw() in qemu_announce_self()
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (10 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 11/19] net: add receive_raw parameter to qemu_new_vlan_client() Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 13/19] net: implement tap support for receive_raw() Mark McLoughlin
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin, Gleb Natapov

From: Gleb Natapov <gleb@redhat.com>

Use qemu_send_packet_raw to send gratuitous arp. This will ensure that
vnet header is handled properly.

Also, avoid sending the gratuitous packet to the guest. There doesn't
appear to be any reason for doing that and the code will currently just
crash if the NIC is not associated with a vlan.

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 savevm.c |    7 +------
 1 files changed, 1 insertions(+), 6 deletions(-)

diff --git a/savevm.c b/savevm.c
index 99aa15a..ac1ef42 100644
--- a/savevm.c
+++ b/savevm.c
@@ -114,8 +114,6 @@ static int announce_self_create(uint8_t *buf,
 static void qemu_announce_self_once(void *opaque)
 {
     int i, len;
-    VLANState *vlan;
-    VLANClientState *vc;
     uint8_t buf[256];
     static int count = SELF_ANNOUNCE_ROUNDS;
     QEMUTimer *timer = *(QEMUTimer **)opaque;
@@ -124,10 +122,7 @@ static void qemu_announce_self_once(void *opaque)
         if (!nd_table[i].used)
             continue;
         len = announce_self_create(buf, nd_table[i].macaddr);
-        vlan = nd_table[i].vlan;
-        QTAILQ_FOREACH(vc, &vlan->clients, next) {
-            vc->receive(vc, buf, len);
-        }
+        qemu_send_packet_raw(nd_table[i].vc, buf, len);
     }
     if (count--) {
 	    qemu_mod_timer(timer, qemu_get_clock(rt_clock) + 100);
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 13/19] net: implement tap support for receive_raw()
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (11 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 12/19] net: use qemu_send_packet_raw() in qemu_announce_self() Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 14/19] virtio-net: add vnet_hdr support Mark McLoughlin
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

tap_receive_raw() always prepends a vnet header if IFF_VNET_HDR is
enabled.

tap_receive() only prepends when the a header is required but the NIC
doesn't supply one.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net.c |   23 +++++++++++++++++++----
 1 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/net.c b/net.c
index 56d9de7..b44495d 100644
--- a/net.c
+++ b/net.c
@@ -1377,14 +1377,14 @@ static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
     return tap_write_packet(s, iovp, iovcnt);
 }
 
-static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+static ssize_t tap_receive_raw(VLANClientState *vc, const uint8_t *buf, size_t size)
 {
     TAPState *s = vc->opaque;
     struct iovec iov[2];
     int iovcnt = 0;
     struct virtio_net_hdr hdr = { 0, };
 
-    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
+    if (s->has_vnet_hdr) {
         iov[iovcnt].iov_base = &hdr;
         iov[iovcnt].iov_len  = sizeof(hdr);
         iovcnt++;
@@ -1397,6 +1397,21 @@ static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
     return tap_write_packet(s, iov, iovcnt);
 }
 
+static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
+{
+    TAPState *s = vc->opaque;
+    struct iovec iov[1];
+
+    if (s->has_vnet_hdr && !s->using_vnet_hdr) {
+        return tap_receive_raw(vc, buf, size);
+    }
+
+    iov[0].iov_base = (char *)buf;
+    iov[0].iov_len  = size;
+
+    return tap_write_packet(s, iov, 1);
+}
+
 static int tap_can_send(void *opaque)
 {
     TAPState *s = opaque;
@@ -1540,8 +1555,8 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
     s->using_vnet_hdr = 0;
     s->vc = qemu_new_vlan_client(NET_CLIENT_TYPE_TAP,
                                  vlan, NULL, model, name, NULL,
-                                 tap_receive, NULL, tap_receive_iov,
-                                 tap_cleanup, s);
+                                 tap_receive, tap_receive_raw,
+                                 tap_receive_iov, tap_cleanup, s);
     tap_read_poll(s, 1);
     return s;
 }
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 14/19] virtio-net: add vnet_hdr support
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (12 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 13/19] net: implement tap support for receive_raw() Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 15/19] net: add tap_set_offload() Mark McLoughlin
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

With '-netdev tap,id=foo -nic model=virtio,netdev=foo' virtio-net can
detect that its peer (i.e. the tap backend) supports vnet headers
and advertise to the guest that it can send packets with partial
checksums and/or TSO packets.

One complication is that if we're migrating and the source host
supports IFF_VNET_HDR but the destination host doesn't, we can't then
stop the guest from using those features. In this scenario, we just
fail the migration.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 hw/virtio-net.c |   49 ++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 218f985..5ce4b42 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -120,8 +120,20 @@ static void virtio_net_reset(VirtIODevice *vdev)
     memset(n->vlans, 0, MAX_VLAN >> 3);
 }
 
+static int peer_has_vnet_hdr(VirtIONet *n)
+{
+    if (!n->vc->peer)
+        return 0;
+
+    if (n->vc->peer->type != NET_CLIENT_TYPE_TAP)
+        return 0;
+
+    return tap_has_vnet_hdr(n->vc->peer);
+}
+
 static uint32_t virtio_net_get_features(VirtIODevice *vdev)
 {
+    VirtIONet *n = to_virtio_net(vdev);
     uint32_t features = (1 << VIRTIO_NET_F_MAC) |
                         (1 << VIRTIO_NET_F_MRG_RXBUF) |
                         (1 << VIRTIO_NET_F_STATUS) |
@@ -130,6 +142,15 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev)
                         (1 << VIRTIO_NET_F_CTRL_VLAN) |
                         (1 << VIRTIO_NET_F_CTRL_RX_EXTRA);
 
+    if (peer_has_vnet_hdr(n)) {
+        tap_using_vnet_hdr(n->vc->peer, 1);
+
+        features |= (1 << VIRTIO_NET_F_CSUM);
+        features |= (1 << VIRTIO_NET_F_HOST_TSO4);
+        features |= (1 << VIRTIO_NET_F_HOST_TSO6);
+        features |= (1 << VIRTIO_NET_F_HOST_ECN);
+    }
+
     return features;
 }
 
@@ -359,6 +380,11 @@ static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
     hdr->flags = 0;
     hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
 
+    if (peer_has_vnet_hdr(n)) {
+        memcpy(hdr, buf, sizeof(*hdr));
+        offset = sizeof(*hdr);
+    }
+
     /* We only ever receive a struct virtio_net_hdr from the tapfd,
      * but we may be passing along a larger header to the guest.
      */
@@ -378,6 +404,10 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
     if (n->promisc)
         return 1;
 
+    if (peer_has_vnet_hdr(n)) {
+        ptr += sizeof(struct virtio_net_hdr);
+    }
+
     if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
         int vid = be16_to_cpup((uint16_t *)(ptr + 14)) & 0xfff;
         if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
@@ -510,7 +540,6 @@ static void virtio_net_tx_complete(VLANClientState *vc, ssize_t len)
 static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
 {
     VirtQueueElement elem;
-    int has_vnet_hdr = 0;
 
     if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
         return;
@@ -537,7 +566,7 @@ static void virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
         }
 
         /* ignore the header if GSO is not supported */
-        if (!has_vnet_hdr) {
+        if (!peer_has_vnet_hdr(n)) {
             out_num--;
             out_sg++;
             len += hdr_len;
@@ -610,7 +639,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
     qemu_put_be32(f, n->mac_table.in_use);
     qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
     qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
-    qemu_put_be32(f, 0); /* vnet-hdr placeholder */
+    qemu_put_be32(f, peer_has_vnet_hdr(n));
     qemu_put_byte(f, n->mac_table.multi_overflow);
     qemu_put_byte(f, n->mac_table.uni_overflow);
     qemu_put_byte(f, n->alluni);
@@ -662,10 +691,16 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
     if (version_id >= 6)
         qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
 
-    if (version_id >= 7 && qemu_get_be32(f)) {
-        fprintf(stderr,
-                "virtio-net: saved image requires vnet header support\n");
-        exit(1);
+    if (version_id >= 7) {
+        if (qemu_get_be32(f) && !peer_has_vnet_hdr(n)) {
+            fprintf(stderr,
+                    "virtio-net: saved image requires vnet_hdr=on\n");
+            return -1;
+        }
+
+        if (peer_has_vnet_hdr(n)) {
+            tap_using_vnet_hdr(n->vc->peer, 1);
+        }
     }
 
     if (version_id >= 9) {
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 15/19] net: add tap_set_offload()
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (13 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 14/19] virtio-net: add vnet_hdr support Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 16/19] virtio-net: enable tap offload if guest supports it Mark McLoughlin
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

This API allows virtio-net to enable various offload features on a
tap interface - e.g. to tell the host kernel it can pass up partial
checksums to userspace.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 net.c       |   24 ++++++++++++++++++++++++
 net.h       |    1 +
 tap-linux.h |    7 +++++++
 3 files changed, 32 insertions(+), 0 deletions(-)

diff --git a/net.c b/net.c
index b44495d..746a3d6 100644
--- a/net.c
+++ b/net.c
@@ -1287,6 +1287,9 @@ int tap_has_vnet_hdr(VLANClientState *vc)
 void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr)
 {
 }
+void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn)
+{
+}
 #else /* !defined(_WIN32) */
 
 /* Maximum GSO packet size (64k) plus plenty of room for
@@ -1524,6 +1527,27 @@ static int tap_probe_vnet_hdr(int fd)
     return ifr.ifr_flags & IFF_VNET_HDR;
 }
 
+void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn)
+{
+    TAPState *s = vc->opaque;
+    unsigned int offload = 0;
+
+    if (csum) {
+        offload |= TUN_F_CSUM;
+        if (tso4)
+            offload |= TUN_F_TSO4;
+        if (tso6)
+            offload |= TUN_F_TSO6;
+        if ((tso4 || tso6) && ecn)
+            offload |= TUN_F_TSO_ECN;
+    }
+
+    if (ioctl(s->fd, TUNSETOFFLOAD, offload) != 0) {
+        fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n",
+                strerror(errno));
+    }
+}
+
 static void tap_cleanup(VLANClientState *vc)
 {
     TAPState *s = vc->opaque;
diff --git a/net.h b/net.h
index 6255e2b..a0f0359 100644
--- a/net.h
+++ b/net.h
@@ -170,5 +170,6 @@ VLANClientState *qdev_get_vlan_client(DeviceState *dev,
 
 int tap_has_vnet_hdr(VLANClientState *vc);
 void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr);
+void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn);
 
 #endif
diff --git a/tap-linux.h b/tap-linux.h
index 8e75348..241cf83 100644
--- a/tap-linux.h
+++ b/tap-linux.h
@@ -22,6 +22,7 @@
 /* Ioctl defines */
 #define TUNSETIFF     _IOW('T', 202, int)
 #define TUNGETFEATURES _IOR('T', 207, unsigned int)
+#define TUNSETOFFLOAD  _IOW('T', 208, unsigned int)
 #define TUNGETIFF      _IOR('T', 210, unsigned int)
 #define TUNSETSNDBUF   _IOW('T', 212, int)
 
@@ -30,6 +31,12 @@
 #define IFF_NO_PI	0x1000
 #define IFF_VNET_HDR	0x4000
 
+/* Features for GSO (TUNSETOFFLOAD). */
+#define TUN_F_CSUM	0x01	/* You can hand me unchecksummed packets. */
+#define TUN_F_TSO4	0x02	/* I can handle TSO for IPv4 packets */
+#define TUN_F_TSO6	0x04	/* I can handle TSO for IPv6 packets */
+#define TUN_F_TSO_ECN	0x08	/* I can handle TSO with ECN bits. */
+
 struct virtio_net_hdr
 {
     uint8_t flags;
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 16/19] virtio-net: enable tap offload if guest supports it
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (14 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 15/19] net: add tap_set_offload() Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 17/19] Work around dhclient brokenness Mark McLoughlin
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

We query the guest's feature set to see if it supports offload and,
if so, we enable those features on the tap interface.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 hw/virtio-net.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 5ce4b42..19d00a6 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -149,6 +149,11 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev)
         features |= (1 << VIRTIO_NET_F_HOST_TSO4);
         features |= (1 << VIRTIO_NET_F_HOST_TSO6);
         features |= (1 << VIRTIO_NET_F_HOST_ECN);
+
+        features |= (1 << VIRTIO_NET_F_GUEST_CSUM);
+        features |= (1 << VIRTIO_NET_F_GUEST_TSO4);
+        features |= (1 << VIRTIO_NET_F_GUEST_TSO6);
+        features |= (1 << VIRTIO_NET_F_GUEST_ECN);
     }
 
     return features;
@@ -174,6 +179,14 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
     VirtIONet *n = to_virtio_net(vdev);
 
     n->mergeable_rx_bufs = !!(features & (1 << VIRTIO_NET_F_MRG_RXBUF));
+
+    if (peer_has_vnet_hdr(n)) {
+        tap_set_offload(n->vc->peer,
+                        (features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
+                        (features >> VIRTIO_NET_F_GUEST_ECN)  & 1);
+    }
 }
 
 static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
@@ -700,6 +713,11 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
 
         if (peer_has_vnet_hdr(n)) {
             tap_using_vnet_hdr(n->vc->peer, 1);
+            tap_set_offload(n->vc->peer,
+                            (n->vdev.features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
+                            (n->vdev.features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
+                            (n->vdev.features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
+                            (n->vdev.features >> VIRTIO_NET_F_GUEST_ECN)  & 1);
         }
     }
 
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 17/19] Work around dhclient brokenness
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (15 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 16/19] virtio-net: enable tap offload if guest supports it Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 18/19] Enable UFO on virtio-net and tap devices Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 19/19] virtio-net: add tap_has_ufo flag to saved state Mark McLoughlin
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin, Anthony Liguori

From: Anthony Liguori <aliguori@us.ibm.com>

With the latest GSO/csum offload patches, any guest using an unpatched version
of dhclient (any Ubuntu guest, for instance), will no longer be able to get
a DHCP address.

dhclient is actually at fault here.  It uses AF_PACKET to receive DHCP responses
but does not check auxdata to see if the packet has a valid csum.  This causes
it to throw out the DHCP responses it gets from the virtio interface as there
is not a valid checksum.

Fedora has carried a patch to fix their dhclient (it's needed for Xen too) but
this patch has not made it into a release of dhclient.  AFAIK, the patch is in
the dhclient CVS but I cannot confirm since their CVS is not public.

This patch, suggested by Rusty, looks for UDP packets (of a normal MTU) and
explicitly adds a checksum to them if they are missing one.

This allows unpatched dhclients to continue to work without needing to update
the guest kernels.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 hw/virtio-net.c |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 19d00a6..4590594 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -369,6 +369,34 @@ static int virtio_net_can_receive(VLANClientState *vc)
     return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE);
 }
 
+/* dhclient uses AF_PACKET but doesn't pass auxdata to the kernel so
+ * it never finds out that the packets don't have valid checksums.  This
+ * causes dhclient to get upset.  Fedora's carried a patch for ages to
+ * fix this with Xen but it hasn't appeared in an upstream release of
+ * dhclient yet.
+ *
+ * To avoid breaking existing guests, we catch udp packets and add
+ * checksums.  This is terrible but it's better than hacking the guest
+ * kernels.
+ *
+ * N.B. if we introduce a zero-copy API, this operation is no longer free so
+ * we should provide a mechanism to disable it to avoid polluting the host
+ * cache.
+ */
+static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
+                                        const uint8_t *buf, size_t size)
+{
+    if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
+        (size > 27 && size < 1500) && /* normal sized MTU */
+        (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
+        (buf[23] == 17) && /* ip.protocol == UDP */
+        (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
+        /* FIXME this cast is evil */
+        net_checksum_calculate((uint8_t *)buf, size);
+        hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
+    }
+}
+
 static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count)
 {
     int offset, i;
@@ -396,6 +424,7 @@ static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
     if (peer_has_vnet_hdr(n)) {
         memcpy(hdr, buf, sizeof(*hdr));
         offset = sizeof(*hdr);
+        work_around_broken_dhclient(hdr, buf + offset, size - offset);
     }
 
     /* We only ever receive a struct virtio_net_hdr from the tapfd,
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 18/19] Enable UFO on virtio-net and tap devices
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (16 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 17/19] Work around dhclient brokenness Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 19/19] virtio-net: add tap_has_ufo flag to saved state Mark McLoughlin
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin, Sridhar Samudrala

From: Sridhar Samudrala <sri@us.ibm.com>

Enable UFO on the host tap device if supported and allow setting UFO
on virtio-net in the guest.

Signed-off-by: Sridhar Samudrala <sri@us.ibm.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 hw/virtio-net.c |   11 +++++++++--
 net.c           |   36 ++++++++++++++++++++++++++++++++----
 net.h           |    3 ++-
 tap-linux.h     |    1 +
 4 files changed, 44 insertions(+), 7 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 4590594..3349800 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -154,6 +154,11 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev)
         features |= (1 << VIRTIO_NET_F_GUEST_TSO4);
         features |= (1 << VIRTIO_NET_F_GUEST_TSO6);
         features |= (1 << VIRTIO_NET_F_GUEST_ECN);
+
+        if (tap_has_ufo(n->vc->peer)) {
+            features |= (1 << VIRTIO_NET_F_GUEST_UFO);
+            features |= (1 << VIRTIO_NET_F_HOST_UFO);
+        }
     }
 
     return features;
@@ -185,7 +190,8 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
                         (features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
                         (features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
                         (features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
-                        (features >> VIRTIO_NET_F_GUEST_ECN)  & 1);
+                        (features >> VIRTIO_NET_F_GUEST_ECN)  & 1,
+                        (features >> VIRTIO_NET_F_GUEST_UFO)  & 1);
     }
 }
 
@@ -746,7 +752,8 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
                             (n->vdev.features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
                             (n->vdev.features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
                             (n->vdev.features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
-                            (n->vdev.features >> VIRTIO_NET_F_GUEST_ECN)  & 1);
+                            (n->vdev.features >> VIRTIO_NET_F_GUEST_ECN)  & 1,
+                            (n->vdev.features >> VIRTIO_NET_F_GUEST_UFO)  & 1);
         }
     }
 
diff --git a/net.c b/net.c
index 746a3d6..3e54c53 100644
--- a/net.c
+++ b/net.c
@@ -1280,6 +1280,10 @@ void do_info_usernet(Monitor *mon)
 #endif /* CONFIG_SLIRP */
 
 #if defined(_WIN32)
+int tap_has_ufo(VLANClientState *vc)
+{
+    return 0;
+}
 int tap_has_vnet_hdr(VLANClientState *vc)
 {
     return 0;
@@ -1287,7 +1291,8 @@ int tap_has_vnet_hdr(VLANClientState *vc)
 void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr)
 {
 }
-void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn)
+void tap_set_offload(VLANClientState *vc, int csum, int tso4,
+                     int tso6, int ecn, int ufo)
 {
 }
 #else /* !defined(_WIN32) */
@@ -1307,6 +1312,7 @@ typedef struct TAPState {
     unsigned int write_poll : 1;
     unsigned int has_vnet_hdr : 1;
     unsigned int using_vnet_hdr : 1;
+    unsigned int has_ufo: 1;
 } TAPState;
 
 static int launch_script(const char *setup_script, const char *ifname, int fd);
@@ -1494,6 +1500,15 @@ static int tap_set_sndbuf(TAPState *s, QemuOpts *opts)
     return 0;
 }
 
+int tap_has_ufo(VLANClientState *vc)
+{
+    TAPState *s = vc->opaque;
+
+    assert(vc->type == NET_CLIENT_TYPE_TAP);
+
+    return s->has_ufo;
+}
+
 int tap_has_vnet_hdr(VLANClientState *vc)
 {
     TAPState *s = vc->opaque;
@@ -1527,7 +1542,8 @@ static int tap_probe_vnet_hdr(int fd)
     return ifr.ifr_flags & IFF_VNET_HDR;
 }
 
-void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn)
+void tap_set_offload(VLANClientState *vc, int csum, int tso4,
+                     int tso6, int ecn, int ufo)
 {
     TAPState *s = vc->opaque;
     unsigned int offload = 0;
@@ -1540,11 +1556,16 @@ void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn)
             offload |= TUN_F_TSO6;
         if ((tso4 || tso6) && ecn)
             offload |= TUN_F_TSO_ECN;
+        if (ufo)
+            offload |= TUN_F_UFO;
     }
 
     if (ioctl(s->fd, TUNSETOFFLOAD, offload) != 0) {
-        fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n",
-                strerror(errno));
+        offload &= ~TUN_F_UFO;
+        if (ioctl(s->fd, TUNSETOFFLOAD, offload) != 0) {
+            fprintf(stderr, "TUNSETOFFLOAD ioctl() failed: %s\n",
+                    strerror(errno));
+        }
     }
 }
 
@@ -1572,6 +1593,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
                                  int vnet_hdr)
 {
     TAPState *s;
+    unsigned int offload;
 
     s = qemu_mallocz(sizeof(TAPState));
     s->fd = fd;
@@ -1581,6 +1603,12 @@ static TAPState *net_tap_fd_init(VLANState *vlan,
                                  vlan, NULL, model, name, NULL,
                                  tap_receive, tap_receive_raw,
                                  tap_receive_iov, tap_cleanup, s);
+    s->has_ufo = 0;
+    /* Check if tap supports UFO */
+    offload = TUN_F_CSUM | TUN_F_UFO;
+    if (ioctl(s->fd, TUNSETOFFLOAD, offload) == 0)
+       s->has_ufo = 1;
+    tap_set_offload(s->vc, 0, 0, 0, 0, 0);
     tap_read_poll(s, 1);
     return s;
 }
diff --git a/net.h b/net.h
index a0f0359..7e6cbf4 100644
--- a/net.h
+++ b/net.h
@@ -168,8 +168,9 @@ VLANClientState *qdev_get_vlan_client(DeviceState *dev,
                                       NetCleanup *cleanup,
                                       void *opaque);
 
+int tap_has_ufo(VLANClientState *vc);
 int tap_has_vnet_hdr(VLANClientState *vc);
 void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr);
-void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn);
+void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn, int ufo);
 
 #endif
diff --git a/tap-linux.h b/tap-linux.h
index 241cf83..d81c650 100644
--- a/tap-linux.h
+++ b/tap-linux.h
@@ -36,6 +36,7 @@
 #define TUN_F_TSO4	0x02	/* I can handle TSO for IPv4 packets */
 #define TUN_F_TSO6	0x04	/* I can handle TSO for IPv6 packets */
 #define TUN_F_TSO_ECN	0x08	/* I can handle TSO with ECN bits. */
+#define TUN_F_UFO	0x10	/* I can handle UFO packets */
 
 struct virtio_net_hdr
 {
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 19/19] virtio-net: add tap_has_ufo flag to saved state
  2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
                   ` (17 preceding siblings ...)
  2009-10-21 11:27 ` [Qemu-devel] [PATCH 18/19] Enable UFO on virtio-net and tap devices Mark McLoughlin
@ 2009-10-21 11:27 ` Mark McLoughlin
  18 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-21 11:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

If we tell the guest we support UFO and then migrate to host which
doesn't support it, we will find ourselves in grave difficulties.

Prevent this scenario by adding a flag to virtio-net's savevm format
which indicates whether the device requires host UFO support.

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 hw/virtio-net.c |   12 +++++++++++-
 1 files changed, 11 insertions(+), 1 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 3349800..f919952 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -16,7 +16,7 @@
 #include "qemu-timer.h"
 #include "virtio-net.h"
 
-#define VIRTIO_NET_VM_VERSION    10
+#define VIRTIO_NET_VM_VERSION    11
 
 #define MAC_TABLE_ENTRIES    64
 #define MAX_VLAN    (1 << 12)   /* Per 802.1Q definition */
@@ -694,6 +694,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
     qemu_put_byte(f, n->nomulti);
     qemu_put_byte(f, n->nouni);
     qemu_put_byte(f, n->nobcast);
+    qemu_put_byte(f, peer_has_vnet_hdr(n) && tap_has_ufo(n->vc->peer));
 }
 
 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
@@ -769,6 +770,15 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
         n->nobcast = qemu_get_byte(f);
     }
 
+    if (version_id >= 11) {
+        if (qemu_get_byte(f) &&
+            (!peer_has_vnet_hdr(n) || !tap_has_ufo(n->vc->peer))) {
+            fprintf(stderr,
+                    "virtio-net: saved image requires TUN_F_UFO support\n");
+            return -1;
+        }
+    }
+
     /* Find the first multicast entry in the saved MAC filter */
     for (i = 0; i < n->mac_table.in_use; i++) {
         if (n->mac_table.macs[i * ETH_ALEN] & 1) {
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH 19/19] virtio-net: add tap_has_ufo flag to saved state
  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 ` Mark McLoughlin
  0 siblings, 0 replies; 21+ messages in thread
From: Mark McLoughlin @ 2009-10-22 16:43 UTC (permalink / raw)
  To: qemu-devel; +Cc: Mark McLoughlin

If we tell the guest we support UFO and then migrate to host which
doesn't support it, we will find ourselves in grave difficulties.

Prevent this scenario by adding a flag to virtio-net's savevm format
which indicates whether the device requires host UFO support.

[v2:
  - add has_ufo uint8_t field for ease of vmstate conversion
  - use qemu_error()
]

Signed-off-by: Mark McLoughlin <markmc@redhat.com>
---
 hw/virtio-net.c |   23 +++++++++++++++++++++--
 1 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 31ac9ef..15b6f45 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -16,7 +16,7 @@
 #include "qemu-timer.h"
 #include "virtio-net.h"
 
-#define VIRTIO_NET_VM_VERSION    10
+#define VIRTIO_NET_VM_VERSION    11
 
 #define MAC_TABLE_ENTRIES    64
 #define MAX_VLAN    (1 << 12)   /* Per 802.1Q definition */
@@ -33,6 +33,7 @@ typedef struct VirtIONet
     QEMUTimer *tx_timer;
     int tx_timer_active;
     uint32_t has_vnet_hdr;
+    uint8_t has_ufo;
     struct {
         VirtQueueElement elem;
         ssize_t len;
@@ -134,6 +135,16 @@ static int peer_has_vnet_hdr(VirtIONet *n)
     return n->has_vnet_hdr;
 }
 
+static int peer_has_ufo(VirtIONet *n)
+{
+    if (!peer_has_vnet_hdr(n))
+        return 0;
+
+    n->has_ufo = tap_has_ufo(n->vc->peer);
+
+    return n->has_ufo;
+}
+
 static uint32_t virtio_net_get_features(VirtIODevice *vdev)
 {
     VirtIONet *n = to_virtio_net(vdev);
@@ -158,7 +169,7 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev)
         features |= (1 << VIRTIO_NET_F_GUEST_TSO6);
         features |= (1 << VIRTIO_NET_F_GUEST_ECN);
 
-        if (tap_has_ufo(n->vc->peer)) {
+        if (peer_has_ufo(n)) {
             features |= (1 << VIRTIO_NET_F_GUEST_UFO);
             features |= (1 << VIRTIO_NET_F_HOST_UFO);
         }
@@ -697,6 +708,7 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
     qemu_put_byte(f, n->nomulti);
     qemu_put_byte(f, n->nouni);
     qemu_put_byte(f, n->nobcast);
+    qemu_put_byte(f, n->has_ufo);
 }
 
 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
@@ -771,6 +783,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
         n->nobcast = qemu_get_byte(f);
     }
 
+    if (version_id >= 11) {
+        if (qemu_get_byte(f) && !peer_has_ufo(n)) {
+            qemu_error("virtio-net: saved image requires TUN_F_UFO support\n");
+            return -1;
+        }
+    }
+
     /* Find the first multicast entry in the saved MAC filter */
     for (i = 0; i < n->mac_table.in_use; i++) {
         if (n->mac_table.macs[i * ETH_ALEN] & 1) {
-- 
1.6.2.5

^ permalink raw reply related	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2009-10-22 16:50 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-21 11:27 [Qemu-devel] [PATCH 00/19] Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 01/19] net: remove unused includes of if_tun.h and if_tap.h Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 02/19] net: import linux tap ioctl definitions Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 03/19] net: make tap_receive() re-use tap_receive_iov() code Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 04/19] net: enable IFF_VNET_HDR on tap fds if available Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 05/19] net: refactor tap initialization Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 06/19] net: add a vnet_hdr=on|off parameter Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 07/19] net: add a client type code Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 08/19] net: add tap_has_vnet_hdr() and tap_using_vnet_hdr() APIs Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 09/19] net: add flags parameter to packet queue interface Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 10/19] net: add an API for 'raw' packets Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 11/19] net: add receive_raw parameter to qemu_new_vlan_client() Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 12/19] net: use qemu_send_packet_raw() in qemu_announce_self() Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 13/19] net: implement tap support for receive_raw() Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 14/19] virtio-net: add vnet_hdr support Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 15/19] net: add tap_set_offload() Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 16/19] virtio-net: enable tap offload if guest supports it Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 17/19] Work around dhclient brokenness Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 18/19] Enable UFO on virtio-net and tap devices Mark McLoughlin
2009-10-21 11:27 ` [Qemu-devel] [PATCH 19/19] virtio-net: add tap_has_ufo flag to saved state Mark McLoughlin
  -- strict thread matches above, loose matches on Subject: below --
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 19/19] virtio-net: add tap_has_ufo flag to saved state Mark McLoughlin

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).