* [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
@ 2015-07-15 7:56 Jason Wang
2015-07-15 8:00 ` Paolo Bonzini
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Jason Wang @ 2015-07-15 7:56 UTC (permalink / raw)
To: mst, qemu-devel; +Cc: pbonzini, Jason Wang, clg, qemu-stable
Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
("virtio-net: byteswap virtio-net header") breaks any layout by
requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
copying header to temporary buffer if swap is needed, and then use
this buffer as part of out_sg.
Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
("virtio-net: byteswap virtio-net header")
Cc: qemu-stable@nongnu.org
Cc: clg@fr.ibm.com
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
Changes from V1:
- avoid header copying if there's no need to do header swap
- don't write the header back
---
hw/net/virtio-net.c | 17 ++++++++++++++---
include/hw/virtio/virtio-access.h | 9 +++++++++
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index e3c2db3..12322bd 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
ssize_t ret, len;
unsigned int out_num = elem.out_num;
struct iovec *out_sg = &elem.out_sg[0];
- struct iovec sg[VIRTQUEUE_MAX_SIZE];
+ struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
+ struct virtio_net_hdr hdr;
if (out_num < 1) {
error_report("virtio-net header not in first element");
@@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
}
if (n->has_vnet_hdr) {
- if (out_sg[0].iov_len < n->guest_hdr_len) {
+ if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
error_report("virtio-net header incorrect");
exit(1);
}
- virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
+ if (virtio_needs_swap(vdev)) {
+ iov_to_buf(out_sg, out_num, 0, &hdr, sizeof(hdr));
+ virtio_net_hdr_swap(vdev, (void *) &hdr);
+ sg2[0].iov_base = &hdr;
+ sg2[0].iov_len = sizeof(hdr);
+ out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
+ out_sg, out_num,
+ sizeof(hdr), -1);
+ out_num += 1;
+ out_sg = sg2;
+ }
}
/*
diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
index cee5dd7..1ec1dfd 100644
--- a/include/hw/virtio/virtio-access.h
+++ b/include/hw/virtio/virtio-access.h
@@ -143,6 +143,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
}
}
+static inline bool virtio_needs_swap(VirtIODevice *vdev)
+{
+#ifdef HOST_WORDS_BIGENDIAN
+ return virtio_access_is_big_endian(vdev) ? false : true;
+#else
+ return virtio_access_is_big_endian(vdev) ? true : false;
+#endif
+}
+
static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
{
#ifdef HOST_WORDS_BIGENDIAN
--
2.1.4
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
2015-07-15 7:56 [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout Jason Wang
@ 2015-07-15 8:00 ` Paolo Bonzini
2015-07-15 11:23 ` Michael S. Tsirkin
2015-07-16 6:42 ` Michael S. Tsirkin
2 siblings, 0 replies; 9+ messages in thread
From: Paolo Bonzini @ 2015-07-15 8:00 UTC (permalink / raw)
To: Jason Wang, mst, qemu-devel; +Cc: clg, qemu-stable
On 15/07/2015 09:56, Jason Wang wrote:
> Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> ("virtio-net: byteswap virtio-net header") breaks any layout by
> requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
> copying header to temporary buffer if swap is needed, and then use
> this buffer as part of out_sg.
>
> Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> ("virtio-net: byteswap virtio-net header")
> Cc: qemu-stable@nongnu.org
> Cc: clg@fr.ibm.com
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> Changes from V1:
> - avoid header copying if there's no need to do header swap
> - don't write the header back
> ---
> hw/net/virtio-net.c | 17 ++++++++++++++---
> include/hw/virtio/virtio-access.h | 9 +++++++++
> 2 files changed, 23 insertions(+), 3 deletions(-)
>
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index e3c2db3..12322bd 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> ssize_t ret, len;
> unsigned int out_num = elem.out_num;
> struct iovec *out_sg = &elem.out_sg[0];
> - struct iovec sg[VIRTQUEUE_MAX_SIZE];
> + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
> + struct virtio_net_hdr hdr;
>
> if (out_num < 1) {
> error_report("virtio-net header not in first element");
> @@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> }
>
> if (n->has_vnet_hdr) {
> - if (out_sg[0].iov_len < n->guest_hdr_len) {
> + if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
> error_report("virtio-net header incorrect");
> exit(1);
> }
> - virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
> + if (virtio_needs_swap(vdev)) {
> + iov_to_buf(out_sg, out_num, 0, &hdr, sizeof(hdr));
> + virtio_net_hdr_swap(vdev, (void *) &hdr);
> + sg2[0].iov_base = &hdr;
> + sg2[0].iov_len = sizeof(hdr);
> + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
> + out_sg, out_num,
> + sizeof(hdr), -1);
> + out_num += 1;
> + out_sg = sg2;
> + }
> }
>
> /*
> diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
> index cee5dd7..1ec1dfd 100644
> --- a/include/hw/virtio/virtio-access.h
> +++ b/include/hw/virtio/virtio-access.h
> @@ -143,6 +143,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
> }
> }
>
> +static inline bool virtio_needs_swap(VirtIODevice *vdev)
> +{
> +#ifdef HOST_WORDS_BIGENDIAN
> + return virtio_access_is_big_endian(vdev) ? false : true;
> +#else
> + return virtio_access_is_big_endian(vdev) ? true : false;
> +#endif
> +}
> +
> static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
> {
> #ifdef HOST_WORDS_BIGENDIAN
>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
2015-07-15 7:56 [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout Jason Wang
2015-07-15 8:00 ` Paolo Bonzini
@ 2015-07-15 11:23 ` Michael S. Tsirkin
2015-07-16 5:54 ` Jason Wang
2015-07-16 6:42 ` Michael S. Tsirkin
2 siblings, 1 reply; 9+ messages in thread
From: Michael S. Tsirkin @ 2015-07-15 11:23 UTC (permalink / raw)
To: Jason Wang; +Cc: pbonzini, clg, qemu-devel, qemu-stable
On Wed, Jul 15, 2015 at 03:56:07PM +0800, Jason Wang wrote:
> Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> ("virtio-net: byteswap virtio-net header") breaks any layout by
> requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
> copying header to temporary buffer if swap is needed, and then use
> this buffer as part of out_sg.
>
> Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> ("virtio-net: byteswap virtio-net header")
> Cc: qemu-stable@nongnu.org
> Cc: clg@fr.ibm.com
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> Changes from V1:
> - avoid header copying if there's no need to do header swap
> - don't write the header back
> ---
> hw/net/virtio-net.c | 17 ++++++++++++++---
> include/hw/virtio/virtio-access.h | 9 +++++++++
> 2 files changed, 23 insertions(+), 3 deletions(-)
>
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index e3c2db3..12322bd 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> ssize_t ret, len;
> unsigned int out_num = elem.out_num;
> struct iovec *out_sg = &elem.out_sg[0];
> - struct iovec sg[VIRTQUEUE_MAX_SIZE];
> + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
> + struct virtio_net_hdr hdr;
>
> if (out_num < 1) {
> error_report("virtio-net header not in first element");
> @@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> }
>
> if (n->has_vnet_hdr) {
> - if (out_sg[0].iov_len < n->guest_hdr_len) {
> + if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
> error_report("virtio-net header incorrect");
> exit(1);
> }
> - virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
> + if (virtio_needs_swap(vdev)) {
> + iov_to_buf(out_sg, out_num, 0, &hdr, sizeof(hdr));
> + virtio_net_hdr_swap(vdev, (void *) &hdr);
> + sg2[0].iov_base = &hdr;
> + sg2[0].iov_len = sizeof(hdr);
> + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
> + out_sg, out_num,
> + sizeof(hdr), -1);
> + out_num += 1;
> + out_sg = sg2;
> + }
> }
>
> /*
I guess this works but iov cpy is pretty expensive.
- When using the tun backend, we can just set VNETBE/VNETLE
correctly and avoid swaps in userspace.
It's easy to probe for - why don't we do this?
- OTOH when not using the tun backend, offloads are
generally disabled, so the swap isn't needed
since header is going to be all 0s.
- what's left is old kernels when using tun.
how about probing for that explicitly?
In other words, virtio_net_needs_swap as opposed to
the generic virtio_needs_swap.
> diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
> index cee5dd7..1ec1dfd 100644
> --- a/include/hw/virtio/virtio-access.h
> +++ b/include/hw/virtio/virtio-access.h
> @@ -143,6 +143,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
> }
> }
>
> +static inline bool virtio_needs_swap(VirtIODevice *vdev)
> +{
> +#ifdef HOST_WORDS_BIGENDIAN
> + return virtio_access_is_big_endian(vdev) ? false : true;
> +#else
> + return virtio_access_is_big_endian(vdev) ? true : false;
> +#endif
> +}
> +
> static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
> {
> #ifdef HOST_WORDS_BIGENDIAN
> --
> 2.1.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
2015-07-15 11:23 ` Michael S. Tsirkin
@ 2015-07-16 5:54 ` Jason Wang
2015-07-16 6:19 ` Michael S. Tsirkin
0 siblings, 1 reply; 9+ messages in thread
From: Jason Wang @ 2015-07-16 5:54 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: pbonzini, clg, qemu-devel, qemu-stable
On 07/15/2015 07:23 PM, Michael S. Tsirkin wrote:
> On Wed, Jul 15, 2015 at 03:56:07PM +0800, Jason Wang wrote:
>> Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
>> ("virtio-net: byteswap virtio-net header") breaks any layout by
>> requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
>> copying header to temporary buffer if swap is needed, and then use
>> this buffer as part of out_sg.
>>
>> Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
>> ("virtio-net: byteswap virtio-net header")
>> Cc: qemu-stable@nongnu.org
>> Cc: clg@fr.ibm.com
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>> Changes from V1:
>> - avoid header copying if there's no need to do header swap
>> - don't write the header back
>> ---
>> hw/net/virtio-net.c | 17 ++++++++++++++---
>> include/hw/virtio/virtio-access.h | 9 +++++++++
>> 2 files changed, 23 insertions(+), 3 deletions(-)
>>
>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>> index e3c2db3..12322bd 100644
>> --- a/hw/net/virtio-net.c
>> +++ b/hw/net/virtio-net.c
>> @@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
>> ssize_t ret, len;
>> unsigned int out_num = elem.out_num;
>> struct iovec *out_sg = &elem.out_sg[0];
>> - struct iovec sg[VIRTQUEUE_MAX_SIZE];
>> + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
>> + struct virtio_net_hdr hdr;
>>
>> if (out_num < 1) {
>> error_report("virtio-net header not in first element");
>> @@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
>> }
>>
>> if (n->has_vnet_hdr) {
>> - if (out_sg[0].iov_len < n->guest_hdr_len) {
>> + if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
>> error_report("virtio-net header incorrect");
>> exit(1);
>> }
>> - virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
>> + if (virtio_needs_swap(vdev)) {
>> + iov_to_buf(out_sg, out_num, 0, &hdr, sizeof(hdr));
>> + virtio_net_hdr_swap(vdev, (void *) &hdr);
>> + sg2[0].iov_base = &hdr;
>> + sg2[0].iov_len = sizeof(hdr);
>> + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
>> + out_sg, out_num,
>> + sizeof(hdr), -1);
>> + out_num += 1;
>> + out_sg = sg2;
>> + }
>> }
>>
>> /*
> I guess this works but iov cpy is pretty expensive.
>
> - When using the tun backend, we can just set VNETBE/VNETLE
> correctly and avoid swaps in userspace.
> It's easy to probe for - why don't we do this?
We need to fix stable branches first. And if we do this for 2.4, if
running on a older kernel which does not support VNETBE/VNETLE, do we
want to fail the initialization? If yes, it breaks backward
compatibility. If no, we still need the swap here.
>
> - OTOH when not using the tun backend, offloads are
> generally disabled, so the swap isn't needed
> since header is going to be all 0s.
I agree it's better to check backend (e.g host_hdr_len) before trying to
do the swap.
>
> - what's left is old kernels when using tun.
> how about probing for that explicitly?
> In other words, virtio_net_needs_swap as opposed to
> the generic virtio_needs_swap.
So we still need swap anyway. How about apply this patch first for
stable and 2.4 and probe the VNETBE/VNETLE explicitly on top for 2.5?
>
>
>> diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
>> index cee5dd7..1ec1dfd 100644
>> --- a/include/hw/virtio/virtio-access.h
>> +++ b/include/hw/virtio/virtio-access.h
>> @@ -143,6 +143,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
>> }
>> }
>>
>> +static inline bool virtio_needs_swap(VirtIODevice *vdev)
>> +{
>> +#ifdef HOST_WORDS_BIGENDIAN
>> + return virtio_access_is_big_endian(vdev) ? false : true;
>> +#else
>> + return virtio_access_is_big_endian(vdev) ? true : false;
>> +#endif
>> +}
>> +
>> static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
>> {
>> #ifdef HOST_WORDS_BIGENDIAN
>> --
>> 2.1.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
2015-07-16 5:54 ` Jason Wang
@ 2015-07-16 6:19 ` Michael S. Tsirkin
0 siblings, 0 replies; 9+ messages in thread
From: Michael S. Tsirkin @ 2015-07-16 6:19 UTC (permalink / raw)
To: Jason Wang; +Cc: pbonzini, clg, qemu-devel, qemu-stable
On Thu, Jul 16, 2015 at 01:54:38PM +0800, Jason Wang wrote:
>
>
> On 07/15/2015 07:23 PM, Michael S. Tsirkin wrote:
> > On Wed, Jul 15, 2015 at 03:56:07PM +0800, Jason Wang wrote:
> >> Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> >> ("virtio-net: byteswap virtio-net header") breaks any layout by
> >> requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
> >> copying header to temporary buffer if swap is needed, and then use
> >> this buffer as part of out_sg.
> >>
> >> Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> >> ("virtio-net: byteswap virtio-net header")
> >> Cc: qemu-stable@nongnu.org
> >> Cc: clg@fr.ibm.com
> >> Signed-off-by: Jason Wang <jasowang@redhat.com>
> >> ---
> >> Changes from V1:
> >> - avoid header copying if there's no need to do header swap
> >> - don't write the header back
> >> ---
> >> hw/net/virtio-net.c | 17 ++++++++++++++---
> >> include/hw/virtio/virtio-access.h | 9 +++++++++
> >> 2 files changed, 23 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> >> index e3c2db3..12322bd 100644
> >> --- a/hw/net/virtio-net.c
> >> +++ b/hw/net/virtio-net.c
> >> @@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> >> ssize_t ret, len;
> >> unsigned int out_num = elem.out_num;
> >> struct iovec *out_sg = &elem.out_sg[0];
> >> - struct iovec sg[VIRTQUEUE_MAX_SIZE];
> >> + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
> >> + struct virtio_net_hdr hdr;
> >>
> >> if (out_num < 1) {
> >> error_report("virtio-net header not in first element");
> >> @@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> >> }
> >>
> >> if (n->has_vnet_hdr) {
> >> - if (out_sg[0].iov_len < n->guest_hdr_len) {
> >> + if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
> >> error_report("virtio-net header incorrect");
> >> exit(1);
> >> }
> >> - virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
> >> + if (virtio_needs_swap(vdev)) {
> >> + iov_to_buf(out_sg, out_num, 0, &hdr, sizeof(hdr));
> >> + virtio_net_hdr_swap(vdev, (void *) &hdr);
> >> + sg2[0].iov_base = &hdr;
> >> + sg2[0].iov_len = sizeof(hdr);
> >> + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
> >> + out_sg, out_num,
> >> + sizeof(hdr), -1);
> >> + out_num += 1;
> >> + out_sg = sg2;
> >> + }
> >> }
> >>
> >> /*
> > I guess this works but iov cpy is pretty expensive.
> >
> > - When using the tun backend, we can just set VNETBE/VNETLE
> > correctly and avoid swaps in userspace.
> > It's easy to probe for - why don't we do this?
>
> We need to fix stable branches first. And if we do this for 2.4, if
> running on a older kernel which does not support VNETBE/VNETLE, do we
> want to fail the initialization? If yes, it breaks backward
> compatibility. If no, we still need the swap here.
>
> >
> > - OTOH when not using the tun backend, offloads are
> > generally disabled, so the swap isn't needed
> > since header is going to be all 0s.
>
> I agree it's better to check backend (e.g host_hdr_len) before trying to
> do the swap.
>
> >
> > - what's left is old kernels when using tun.
> > how about probing for that explicitly?
> > In other words, virtio_net_needs_swap as opposed to
> > the generic virtio_needs_swap.
>
> So we still need swap anyway. How about apply this patch first for
> stable and 2.4 and probe the VNETBE/VNETLE explicitly on top for 2.5?
I'm fine with it being a patch on top, but I think it's preferable
to use VNETBE/VNETLE even in 2.4 if that's available.
> >
> >
> >> diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
> >> index cee5dd7..1ec1dfd 100644
> >> --- a/include/hw/virtio/virtio-access.h
> >> +++ b/include/hw/virtio/virtio-access.h
> >> @@ -143,6 +143,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
> >> }
> >> }
> >>
> >> +static inline bool virtio_needs_swap(VirtIODevice *vdev)
> >> +{
> >> +#ifdef HOST_WORDS_BIGENDIAN
> >> + return virtio_access_is_big_endian(vdev) ? false : true;
> >> +#else
> >> + return virtio_access_is_big_endian(vdev) ? true : false;
> >> +#endif
> >> +}
> >> +
> >> static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
> >> {
> >> #ifdef HOST_WORDS_BIGENDIAN
> >> --
> >> 2.1.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
2015-07-15 7:56 [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout Jason Wang
2015-07-15 8:00 ` Paolo Bonzini
2015-07-15 11:23 ` Michael S. Tsirkin
@ 2015-07-16 6:42 ` Michael S. Tsirkin
2015-07-16 6:49 ` Jason Wang
2 siblings, 1 reply; 9+ messages in thread
From: Michael S. Tsirkin @ 2015-07-16 6:42 UTC (permalink / raw)
To: Jason Wang; +Cc: pbonzini, clg, qemu-devel, qemu-stable
On Wed, Jul 15, 2015 at 03:56:07PM +0800, Jason Wang wrote:
> Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> ("virtio-net: byteswap virtio-net header") breaks any layout by
> requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
> copying header to temporary buffer if swap is needed, and then use
> this buffer as part of out_sg.
>
> Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> ("virtio-net: byteswap virtio-net header")
> Cc: qemu-stable@nongnu.org
> Cc: clg@fr.ibm.com
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> Changes from V1:
> - avoid header copying if there's no need to do header swap
> - don't write the header back
> ---
> hw/net/virtio-net.c | 17 ++++++++++++++---
> include/hw/virtio/virtio-access.h | 9 +++++++++
> 2 files changed, 23 insertions(+), 3 deletions(-)
>
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index e3c2db3..12322bd 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> ssize_t ret, len;
> unsigned int out_num = elem.out_num;
> struct iovec *out_sg = &elem.out_sg[0];
> - struct iovec sg[VIRTQUEUE_MAX_SIZE];
> + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
> + struct virtio_net_hdr hdr;
>
> if (out_num < 1) {
> error_report("virtio-net header not in first element");
> @@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> }
>
> if (n->has_vnet_hdr) {
> - if (out_sg[0].iov_len < n->guest_hdr_len) {
> + if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
> error_report("virtio-net header incorrect");
> exit(1);
> }
this scans the iov unnecessarily. How about checking return
code from iov_to_buf instead?
> - virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
> + if (virtio_needs_swap(vdev)) {
> + iov_to_buf(out_sg, out_num, 0, &hdr, sizeof(hdr));
> + virtio_net_hdr_swap(vdev, (void *) &hdr);
> + sg2[0].iov_base = &hdr;
> + sg2[0].iov_len = sizeof(hdr);
> + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
> + out_sg, out_num,
> + sizeof(hdr), -1);
This might truncate packet if it does not fit in 1024 anymore.
It might be better to just drop it.
> + out_num += 1;
> + out_sg = sg2;
> + }
> }
>
> /*
> diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
> index cee5dd7..1ec1dfd 100644
> --- a/include/hw/virtio/virtio-access.h
> +++ b/include/hw/virtio/virtio-access.h
> @@ -143,6 +143,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
> }
> }
>
> +static inline bool virtio_needs_swap(VirtIODevice *vdev)
> +{
> +#ifdef HOST_WORDS_BIGENDIAN
> + return virtio_access_is_big_endian(vdev) ? false : true;
> +#else
> + return virtio_access_is_big_endian(vdev) ? true : false;
> +#endif
> +}
> +
> static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
> {
> #ifdef HOST_WORDS_BIGENDIAN
> --
> 2.1.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
2015-07-16 6:42 ` Michael S. Tsirkin
@ 2015-07-16 6:49 ` Jason Wang
2015-07-16 7:29 ` Michael S. Tsirkin
0 siblings, 1 reply; 9+ messages in thread
From: Jason Wang @ 2015-07-16 6:49 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: pbonzini, clg, qemu-devel, qemu-stable
On 07/16/2015 02:42 PM, Michael S. Tsirkin wrote:
> On Wed, Jul 15, 2015 at 03:56:07PM +0800, Jason Wang wrote:
>> Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
>> ("virtio-net: byteswap virtio-net header") breaks any layout by
>> requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
>> copying header to temporary buffer if swap is needed, and then use
>> this buffer as part of out_sg.
>>
>> Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
>> ("virtio-net: byteswap virtio-net header")
>> Cc: qemu-stable@nongnu.org
>> Cc: clg@fr.ibm.com
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>> Changes from V1:
>> - avoid header copying if there's no need to do header swap
>> - don't write the header back
>> ---
>> hw/net/virtio-net.c | 17 ++++++++++++++---
>> include/hw/virtio/virtio-access.h | 9 +++++++++
>> 2 files changed, 23 insertions(+), 3 deletions(-)
>>
>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>> index e3c2db3..12322bd 100644
>> --- a/hw/net/virtio-net.c
>> +++ b/hw/net/virtio-net.c
>> @@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
>> ssize_t ret, len;
>> unsigned int out_num = elem.out_num;
>> struct iovec *out_sg = &elem.out_sg[0];
>> - struct iovec sg[VIRTQUEUE_MAX_SIZE];
>> + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
>> + struct virtio_net_hdr hdr;
>>
>> if (out_num < 1) {
>> error_report("virtio-net header not in first element");
>> @@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
>> }
>>
>> if (n->has_vnet_hdr) {
>> - if (out_sg[0].iov_len < n->guest_hdr_len) {
>> + if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
>> error_report("virtio-net header incorrect");
>> exit(1);
>> }
> this scans the iov unnecessarily. How about checking return
> code from iov_to_buf instead?
Looks ok since hdr is very short anyway.
>
>> - virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
>> + if (virtio_needs_swap(vdev)) {
>> + iov_to_buf(out_sg, out_num, 0, &hdr, sizeof(hdr));
>> + virtio_net_hdr_swap(vdev, (void *) &hdr);
>> + sg2[0].iov_base = &hdr;
>> + sg2[0].iov_len = sizeof(hdr);
>> + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
>> + out_sg, out_num,
>> + sizeof(hdr), -1);
>
> This might truncate packet if it does not fit in 1024 anymore.
> It might be better to just drop it.
Ok, will do this in V3.
>
>> + out_num += 1;
>> + out_sg = sg2;
>> + }
>> }
>>
>> /*
>> diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
>> index cee5dd7..1ec1dfd 100644
>> --- a/include/hw/virtio/virtio-access.h
>> +++ b/include/hw/virtio/virtio-access.h
>> @@ -143,6 +143,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
>> }
>> }
>>
>> +static inline bool virtio_needs_swap(VirtIODevice *vdev)
>> +{
>> +#ifdef HOST_WORDS_BIGENDIAN
>> + return virtio_access_is_big_endian(vdev) ? false : true;
>> +#else
>> + return virtio_access_is_big_endian(vdev) ? true : false;
>> +#endif
>> +}
>> +
>> static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
>> {
>> #ifdef HOST_WORDS_BIGENDIAN
>> --
>> 2.1.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
2015-07-16 6:49 ` Jason Wang
@ 2015-07-16 7:29 ` Michael S. Tsirkin
2015-07-16 8:00 ` Jason Wang
0 siblings, 1 reply; 9+ messages in thread
From: Michael S. Tsirkin @ 2015-07-16 7:29 UTC (permalink / raw)
To: Jason Wang; +Cc: pbonzini, clg, qemu-devel, qemu-stable
On Thu, Jul 16, 2015 at 02:49:48PM +0800, Jason Wang wrote:
>
>
> On 07/16/2015 02:42 PM, Michael S. Tsirkin wrote:
> > On Wed, Jul 15, 2015 at 03:56:07PM +0800, Jason Wang wrote:
> >> Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> >> ("virtio-net: byteswap virtio-net header") breaks any layout by
> >> requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
> >> copying header to temporary buffer if swap is needed, and then use
> >> this buffer as part of out_sg.
> >>
> >> Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
> >> ("virtio-net: byteswap virtio-net header")
> >> Cc: qemu-stable@nongnu.org
> >> Cc: clg@fr.ibm.com
> >> Signed-off-by: Jason Wang <jasowang@redhat.com>
> >> ---
> >> Changes from V1:
> >> - avoid header copying if there's no need to do header swap
> >> - don't write the header back
> >> ---
> >> hw/net/virtio-net.c | 17 ++++++++++++++---
> >> include/hw/virtio/virtio-access.h | 9 +++++++++
> >> 2 files changed, 23 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> >> index e3c2db3..12322bd 100644
> >> --- a/hw/net/virtio-net.c
> >> +++ b/hw/net/virtio-net.c
> >> @@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> >> ssize_t ret, len;
> >> unsigned int out_num = elem.out_num;
> >> struct iovec *out_sg = &elem.out_sg[0];
> >> - struct iovec sg[VIRTQUEUE_MAX_SIZE];
> >> + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
> >> + struct virtio_net_hdr hdr;
> >>
> >> if (out_num < 1) {
> >> error_report("virtio-net header not in first element");
> >> @@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
> >> }
> >>
> >> if (n->has_vnet_hdr) {
> >> - if (out_sg[0].iov_len < n->guest_hdr_len) {
> >> + if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
> >> error_report("virtio-net header incorrect");
> >> exit(1);
> >> }
> > this scans the iov unnecessarily. How about checking return
> > code from iov_to_buf instead?
>
> Looks ok since hdr is very short anyway.
but iov_size scans the whole iov, not just the header.
> >
> >> - virtio_net_hdr_swap(vdev, (void *) out_sg[0].iov_base);
> >> + if (virtio_needs_swap(vdev)) {
> >> + iov_to_buf(out_sg, out_num, 0, &hdr, sizeof(hdr));
> >> + virtio_net_hdr_swap(vdev, (void *) &hdr);
> >> + sg2[0].iov_base = &hdr;
> >> + sg2[0].iov_len = sizeof(hdr);
> >> + out_num = iov_copy(&sg2[1], ARRAY_SIZE(sg2) - 1,
> >> + out_sg, out_num,
> >> + sizeof(hdr), -1);
> >
> > This might truncate packet if it does not fit in 1024 anymore.
> > It might be better to just drop it.
>
> Ok, will do this in V3.
>
> >
> >> + out_num += 1;
> >> + out_sg = sg2;
> >> + }
> >> }
> >>
> >> /*
> >> diff --git a/include/hw/virtio/virtio-access.h b/include/hw/virtio/virtio-access.h
> >> index cee5dd7..1ec1dfd 100644
> >> --- a/include/hw/virtio/virtio-access.h
> >> +++ b/include/hw/virtio/virtio-access.h
> >> @@ -143,6 +143,15 @@ static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
> >> }
> >> }
> >>
> >> +static inline bool virtio_needs_swap(VirtIODevice *vdev)
> >> +{
> >> +#ifdef HOST_WORDS_BIGENDIAN
> >> + return virtio_access_is_big_endian(vdev) ? false : true;
> >> +#else
> >> + return virtio_access_is_big_endian(vdev) ? true : false;
> >> +#endif
> >> +}
> >> +
> >> static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
> >> {
> >> #ifdef HOST_WORDS_BIGENDIAN
> >> --
> >> 2.1.4
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout
2015-07-16 7:29 ` Michael S. Tsirkin
@ 2015-07-16 8:00 ` Jason Wang
0 siblings, 0 replies; 9+ messages in thread
From: Jason Wang @ 2015-07-16 8:00 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: pbonzini, clg, qemu-devel, qemu-stable
On 07/16/2015 03:29 PM, Michael S. Tsirkin wrote:
> On Thu, Jul 16, 2015 at 02:49:48PM +0800, Jason Wang wrote:
>> >
>> >
>> > On 07/16/2015 02:42 PM, Michael S. Tsirkin wrote:
>>> > > On Wed, Jul 15, 2015 at 03:56:07PM +0800, Jason Wang wrote:
>>>> > >> Commit 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
>>>> > >> ("virtio-net: byteswap virtio-net header") breaks any layout by
>>>> > >> requiring out_sg[0].iov_len >= n->guest_hdr_len. Fixing this by
>>>> > >> copying header to temporary buffer if swap is needed, and then use
>>>> > >> this buffer as part of out_sg.
>>>> > >>
>>>> > >> Fixes 032a74a1c0fcdd5fd1c69e56126b4c857ee36611
>>>> > >> ("virtio-net: byteswap virtio-net header")
>>>> > >> Cc: qemu-stable@nongnu.org
>>>> > >> Cc: clg@fr.ibm.com
>>>> > >> Signed-off-by: Jason Wang <jasowang@redhat.com>
>>>> > >> ---
>>>> > >> Changes from V1:
>>>> > >> - avoid header copying if there's no need to do header swap
>>>> > >> - don't write the header back
>>>> > >> ---
>>>> > >> hw/net/virtio-net.c | 17 ++++++++++++++---
>>>> > >> include/hw/virtio/virtio-access.h | 9 +++++++++
>>>> > >> 2 files changed, 23 insertions(+), 3 deletions(-)
>>>> > >>
>>>> > >> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>>>> > >> index e3c2db3..12322bd 100644
>>>> > >> --- a/hw/net/virtio-net.c
>>>> > >> +++ b/hw/net/virtio-net.c
>>>> > >> @@ -1142,7 +1142,8 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
>>>> > >> ssize_t ret, len;
>>>> > >> unsigned int out_num = elem.out_num;
>>>> > >> struct iovec *out_sg = &elem.out_sg[0];
>>>> > >> - struct iovec sg[VIRTQUEUE_MAX_SIZE];
>>>> > >> + struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE];
>>>> > >> + struct virtio_net_hdr hdr;
>>>> > >>
>>>> > >> if (out_num < 1) {
>>>> > >> error_report("virtio-net header not in first element");
>>>> > >> @@ -1150,11 +1151,21 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q)
>>>> > >> }
>>>> > >>
>>>> > >> if (n->has_vnet_hdr) {
>>>> > >> - if (out_sg[0].iov_len < n->guest_hdr_len) {
>>>> > >> + if (iov_size(out_sg, out_num) < n->guest_hdr_len) {
>>>> > >> error_report("virtio-net header incorrect");
>>>> > >> exit(1);
>>>> > >> }
>>> > > this scans the iov unnecessarily. How about checking return
>>> > > code from iov_to_buf instead?
>> >
>> > Looks ok since hdr is very short anyway.
> but iov_size scans the whole iov, not just the header.
>
Right.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2015-07-16 8:00 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-15 7:56 [Qemu-devel] [PATCH V2] virtio-net: unbreak any layout Jason Wang
2015-07-15 8:00 ` Paolo Bonzini
2015-07-15 11:23 ` Michael S. Tsirkin
2015-07-16 5:54 ` Jason Wang
2015-07-16 6:19 ` Michael S. Tsirkin
2015-07-16 6:42 ` Michael S. Tsirkin
2015-07-16 6:49 ` Jason Wang
2015-07-16 7:29 ` Michael S. Tsirkin
2015-07-16 8:00 ` Jason Wang
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).