From mboxrd@z Thu Jan 1 00:00:00 1970 From: Mark McLoughlin Subject: [PATCH 5/5] kvm: qemu: Add support for partial csums and GSO Date: Fri, 13 Jun 2008 14:58:01 +0100 Message-ID: <1213365481-23460-6-git-send-email-markmc@redhat.com> References: <1213365481-23460-1-git-send-email-markmc@redhat.com> <1213365481-23460-2-git-send-email-markmc@redhat.com> <1213365481-23460-3-git-send-email-markmc@redhat.com> <1213365481-23460-4-git-send-email-markmc@redhat.com> <1213365481-23460-5-git-send-email-markmc@redhat.com> Cc: kvm@vger.kernel.org, Mark McLoughlin To: Anthony Liguori , Avi Kivity , Rusty Russell Return-path: Received: from mail02.svc.cra.dublin.eircom.net ([159.134.118.18]:36566 "HELO mail02.svc.cra.dublin.eircom.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1756225AbYFMN6F (ORCPT ); Fri, 13 Jun 2008 09:58:05 -0400 In-Reply-To: <1213365481-23460-5-git-send-email-markmc@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: Signed-off-by: Mark McLoughlin --- qemu/hw/virtio-net.c | 51 ++++++++++++++++++++++++++++++++++++++++++++----- qemu/net.h | 2 + qemu/vl.c | 24 +++++++++++++++++++++++ 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/qemu/hw/virtio-net.c b/qemu/hw/virtio-net.c index f3ff356..3952e90 100644 --- a/qemu/hw/virtio-net.c +++ b/qemu/hw/virtio-net.c @@ -23,9 +23,18 @@ #define VIRTIO_ID_NET 1 /* The feature bitmap for virtio net */ -#define VIRTIO_NET_F_NO_CSUM 0 -#define VIRTIO_NET_F_MAC 5 -#define VIRTIO_NET_F_GS0 6 +#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */ +#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */ +#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */ +#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */ +#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */ +#define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in. */ +#define VIRTIO_NET_F_GUEST_ECN 9 /* Guest can handle TSO[6] w/ ECN in. */ +#define VIRTIO_NET_F_GUEST_UFO 10 /* Guest can handle UFO in. */ +#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in. */ +#define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in. */ +#define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in. */ +#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */ #define TX_TIMER_INTERVAL (1000 / 500) @@ -43,8 +52,6 @@ struct virtio_net_hdr uint8_t flags; #define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame #define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO) -/* FIXME: Do we need this? If they said they can handle ECN, do they care? */ -#define VIRTIO_NET_HDR_GSO_TCPV4_ECN 2 // GSO frame, IPv4 TCP w/ ECN #define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO) #define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP #define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set @@ -86,7 +93,38 @@ static void virtio_net_update_config(VirtIODevice *vdev, uint8_t *config) static uint32_t virtio_net_get_features(VirtIODevice *vdev) { - return (1 << VIRTIO_NET_F_MAC); + uint32_t features = (1 << VIRTIO_NET_F_MAC); + + if (vdev->vq[0].vringfd > 0) { + features |= (1 << VIRTIO_NET_F_CSUM); + 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); + features |= (1 << VIRTIO_NET_F_GUEST_UFO); + features |= (1 << VIRTIO_NET_F_HOST_TSO4); + features |= (1 << VIRTIO_NET_F_HOST_TSO6); + features |= (1 << VIRTIO_NET_F_HOST_ECN); + /* Kernel can't actually handle UFO in software currently. */ + } + + return features; +} + +static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features) +{ + VirtIONet *n = to_virtio_net(vdev); + VLANClientState *host = n->vc->vlan->first_client; + + if (n->rx_vq->vringfd <= 0 || !host->set_vring_features) + return; + + host->set_vring_features(host, + (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_UFO) & 1); } /* RX */ @@ -325,6 +363,7 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) n->vdev.update_config = virtio_net_update_config; n->vdev.get_features = virtio_net_get_features; + n->vdev.set_features = virtio_net_set_features; n->rx_vq = virtio_add_queue(&n->vdev, 128, virtio_net_handle_rx); n->tx_vq = virtio_add_queue(&n->vdev, 128, virtio_net_handle_tx); memcpy(n->mac, nd->macaddr, 6); diff --git a/qemu/net.h b/qemu/net.h index e8ed926..dd250ae 100644 --- a/qemu/net.h +++ b/qemu/net.h @@ -10,6 +10,7 @@ typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); typedef struct VLANClientState VLANClientState; typedef int (SetVringFDs)(VLANClientState *, int, int); +typedef void (SetVringFeatures)(VLANClientState *, int, int, int, int, int); struct VLANClientState { IOReadHandler *fd_read; @@ -18,6 +19,7 @@ struct VLANClientState { rate-limit the slirp code. */ IOCanRWHandler *fd_can_read; SetVringFDs *set_vring_fds; + SetVringFeatures *set_vring_features; void *opaque; struct VLANClientState *next; struct VLANState *vlan; diff --git a/qemu/vl.c b/qemu/vl.c index d043ccd..249041c 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -4189,6 +4189,29 @@ static int tap_set_vring_fds(VLANClientState *vc, int recv, int xmit) return 1; } + +static void tap_set_vring_features(VLANClientState *vc, int csum, int tso4, + int tso6, int ecn, int ufo) +{ + TAPState *s = vc->opaque; + unsigned int features = 0; + + if (csum) { + features |= TUN_F_CSUM; + if (tso4) + features |= TUN_F_TSO4; + if (tso6) + features |= TUN_F_TSO6; + if ((tso4 || tso6) && ecn) + features |= TUN_F_TSO_ECN; + if (ufo) + features |= TUN_F_UFO; + } + + if (ioctl(s->fd, TUNSETFEATURES, features) != 0) + fprintf(stderr, "TUNSETFEATURES ioctl() failed: %s\n", + strerror(errno)); +} #endif /* fd support */ @@ -4205,6 +4228,7 @@ static TAPState *net_tap_fd_init(VLANState *vlan, int fd) s->vc->fd_readv = tap_readv; #ifdef TUNSETRECVVRING s->vc->set_vring_fds = tap_set_vring_fds; + s->vc->set_vring_features = tap_set_vring_features; #endif qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd); -- 1.5.4.1