diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2012-09-24 14:52:28 +0200 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2012-10-29 18:25:23 +0200 |
commit | 14761f9cf7fbc6d058c1e51c313a139066eab256 (patch) | |
tree | b992c8e474fbeac234d70a0df894cd4d1621c668 /hw | |
parent | c8d28e7e336869524d166d88f08ad476eadedccb (diff) |
virtio-net: switch tx to safe iov functions
Avoid mangling iovec manually: use safe iov_*
functions.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/virtio-net.c | 31 |
1 files changed, 19 insertions, 12 deletions
diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 59ab6746f0..5206648271 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -715,10 +715,10 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) } while (virtqueue_pop(vq, &elem)) { - ssize_t ret, len = 0; + ssize_t ret, len; unsigned int out_num = elem.out_num; struct iovec *out_sg = &elem.out_sg[0]; - unsigned hdr_len; + struct iovec sg[VIRTQUEUE_MAX_SIZE]; /* hdr_len refers to the header received from the guest */ hdr_len = n->mergeable_rx_bufs ? @@ -730,18 +730,25 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) exit(1); } - /* ignore the header if GSO is not supported */ - if (!n->has_vnet_hdr) { - out_num--; - out_sg++; - len += hdr_len; - } else if (n->mergeable_rx_bufs) { - /* tapfd expects a struct virtio_net_hdr */ - hdr_len -= sizeof(struct virtio_net_hdr); - out_sg->iov_len -= hdr_len; - len += hdr_len; + /* + * If host wants to see the guest header as is, we can + * pass it on unchanged. Otherwise, copy just the parts + * that host is interested in. + */ + assert(n->host_hdr_len <= n->guest_hdr_len); + if (n->host_hdr_len != n->guest_hdr_len) { + unsigned sg_num = iov_copy(sg, ARRAY_SIZE(sg), + out_sg, out_num, + 0, n->host_hdr_len); + sg_num += iov_copy(sg + sg_num, ARRAY_SIZE(sg) - sg_num, + out_sg, out_num, + n->guest_hdr_len, -1); + out_num = sg_num; + out_sg = sg; } + len = hdr_len; + ret = qemu_sendv_packet_async(&n->nic->nc, out_sg, out_num, virtio_net_tx_complete); if (ret == 0) { |