From mboxrd@z Thu Jan 1 00:00:00 1970 From: Mark McLoughlin Subject: [PATCH 08/12] kvm: qemu: Don't require all drivers to use virtio_net_hdr Date: Mon, 11 Aug 2008 21:12:11 +0100 Message-ID: <1218485535-877-9-git-send-email-markmc@redhat.com> References: <1218485535-877-1-git-send-email-markmc@redhat.com> <1218485535-877-2-git-send-email-markmc@redhat.com> <1218485535-877-3-git-send-email-markmc@redhat.com> <1218485535-877-4-git-send-email-markmc@redhat.com> <1218485535-877-5-git-send-email-markmc@redhat.com> <1218485535-877-6-git-send-email-markmc@redhat.com> <1218485535-877-7-git-send-email-markmc@redhat.com> <1218485535-877-8-git-send-email-markmc@redhat.com> Cc: kvm@vger.kernel.org, Mark McLoughlin To: Avi Kivity Return-path: Received: from mail05.svc.cra.dublin.eircom.net ([159.134.118.21]:46844 "HELO mail05.svc.cra.dublin.eircom.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1757539AbYHKUMe (ORCPT ); Mon, 11 Aug 2008 16:12:34 -0400 In-Reply-To: <1218485535-877-8-git-send-email-markmc@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: The virtio-net driver is the only one which wishes to deal with virtio_net_hdr headers, so add a "using_vnet_hdr" flag to allow it to indicate this. Preferably, we'd prefer to only enable IFF_VNET_HDR when we're using virtio-net, but qemu's various abstractions would make this very messy. Signed-off-by: Mark McLoughlin --- qemu/hw/virtio-net.c | 1 + qemu/net.h | 1 + qemu/vl.c | 78 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/qemu/hw/virtio-net.c b/qemu/hw/virtio-net.c index 9b1298e..2298316 100644 --- a/qemu/hw/virtio-net.c +++ b/qemu/hw/virtio-net.c @@ -97,6 +97,7 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev) uint32_t features = (1 << VIRTIO_NET_F_MAC); if (tap_has_vnet_hdr(host)) { + tap_using_vnet_hdr(host, 1); features |= (1 << VIRTIO_NET_F_CSUM); features |= (1 << VIRTIO_NET_F_GUEST_CSUM); features |= (1 << VIRTIO_NET_F_GUEST_TSO4); diff --git a/qemu/net.h b/qemu/net.h index ae1a338..4891669 100644 --- a/qemu/net.h +++ b/qemu/net.h @@ -46,6 +46,7 @@ void qemu_handler_true(void *opaque); void do_info_network(void); int tap_has_vnet_hdr(void *opaque); +void tap_using_vnet_hdr(void *opaque, int using_vnet_hdr); int net_client_init(const char *device, const char *opts); void net_client_uninit(NICInfo *nd); diff --git a/qemu/vl.c b/qemu/vl.c index f5aacf0..9bfe480 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -4347,6 +4347,10 @@ int tap_has_vnet_hdr(void *opaque) return 0; } +void tap_using_vnet_hdr(void *opaque, int using_vnet_hdr) +{ +} + #else /* !defined(_WIN32) */ #ifndef IFF_VNET_HDR @@ -4367,10 +4371,11 @@ typedef struct TAPState { char buf[TAP_BUFSIZE]; int size; unsigned int has_vnet_hdr : 1; + unsigned int using_vnet_hdr : 1; } TAPState; -static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, - int iovcnt) +static ssize_t tap_writev(void *opaque, const struct iovec *iov, + int iovcnt) { TAPState *s = opaque; ssize_t len; @@ -4382,17 +4387,44 @@ static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, return len; } +static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, + int iovcnt) +{ + TAPState *s = opaque; + struct iovec *iov_copy; + struct virtio_net_hdr hdr = { 0, }; + + if (!s->has_vnet_hdr || s->using_vnet_hdr) + return tap_writev(opaque, iov, iovcnt); + + iov_copy = alloca(sizeof(struct iovec) * (iovcnt + 1)); + + iov_copy[0].iov_base = &hdr; + iov_copy[0].iov_len = sizeof(hdr); + + memcpy(&iov_copy[1], iov, sizeof(struct iovec) * iovcnt); + + return tap_writev(opaque, iov_copy, iovcnt + 1); +} + static void tap_receive(void *opaque, const uint8_t *buf, int size) { TAPState *s = opaque; - int ret; - for(;;) { - ret = write(s->fd, buf, size); - if (ret < 0 && (errno == EINTR || errno == EAGAIN)) { - } else { - break; - } + struct virtio_net_hdr hdr = { 0, }; + struct iovec iov[2]; + int i = 0; + + if (s->has_vnet_hdr && !s->using_vnet_hdr) { + iov[i].iov_base = &hdr; + iov[i].iov_len = sizeof(hdr); + i++; } + + iov[i].iov_base = (char *) buf; + iov[i].iov_len = size; + i++; + + tap_writev(opaque, iov, i); } static int tap_can_send(void *opaque) @@ -4421,6 +4453,19 @@ static int tap_can_send(void *opaque) return can_receive; } +static int tap_send_packet(TAPState *s) +{ + uint8_t *buf = s->buf; + int size = s->size; + + if (s->has_vnet_hdr && !s->using_vnet_hdr) { + buf += sizeof(struct virtio_net_hdr); + size -= sizeof(struct virtio_net_hdr); + } + + return qemu_send_packet(s->vc, buf, size); +} + static void tap_send(void *opaque) { TAPState *s = opaque; @@ -4430,7 +4475,7 @@ static void tap_send(void *opaque) int err; /* If noone can receive the packet, buffer it */ - err = qemu_send_packet(s->vc, s->buf, s->size); + err = tap_send_packet(s); if (err == -EAGAIN) return; } @@ -4454,7 +4499,7 @@ static void tap_send(void *opaque) int err; /* If noone can receive the packet, buffer it */ - err = qemu_send_packet(s->vc, s->buf, s->size); + err = tap_send_packet(s); if (err == -EAGAIN) break; } @@ -4469,6 +4514,17 @@ int tap_has_vnet_hdr(void *opaque) return s ? s->has_vnet_hdr : 0; } +void tap_using_vnet_hdr(void *opaque, int using_vnet_hdr) +{ + VLANClientState *vc = opaque; + TAPState *s = vc->opaque; + + if (!s || !s->has_vnet_hdr) + return; + + s->using_vnet_hdr = using_vnet_hdr != 0; +} + #ifdef TUNSETOFFLOAD static void tap_set_offload(VLANClientState *vc, int csum, int tso4, int tso6, int ecn) -- 1.5.4.1