diff mbox

[3/3] net: virtio-net discards TX data after link down

Message ID 1478506829-9208-4-git-send-email-yuri.benditovich@daynix.com
State New
Headers show

Commit Message

Yuri Benditovich Nov. 7, 2016, 8:20 a.m. UTC
From: Yuri Benditovich <yuri.benditovich@daynix.com>

https://bugzilla.redhat.com/show_bug.cgi?id=1295637
Upon set_link monitor command or upon netdev deletion
virtio-net sends link down indication to the guest
and stops vhost if one is used.
Guest driver can still submit data for TX until it
recognizes link loss. If these packets not returned by
the host, the Windows guest will never be able to finish
disable/removal/shutdown.
Now each packet sent by guest after NIC indicated link
down will be completed immediately.

Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
---
 hw/net/virtio-net.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

Comments

Jason Wang Nov. 8, 2016, 6:48 a.m. UTC | #1
On 2016年11月07日 16:20, yuri.benditovich@daynix.com wrote:
> From: Yuri Benditovich <yuri.benditovich@daynix.com>
>
> https://bugzilla.redhat.com/show_bug.cgi?id=1295637
> Upon set_link monitor command or upon netdev deletion
> virtio-net sends link down indication to the guest
> and stops vhost if one is used.
> Guest driver can still submit data for TX until it
> recognizes link loss. If these packets not returned by
> the host, the Windows guest will never be able to finish
> disable/removal/shutdown.
> Now each packet sent by guest after NIC indicated link
> down will be completed immediately.
>
> Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
> ---
>   hw/net/virtio-net.c | 15 +++++++++++++++
>   1 file changed, 15 insertions(+)
>
> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
> index 06bfe4b..6158de0 100644
> --- a/hw/net/virtio-net.c
> +++ b/hw/net/virtio-net.c
> @@ -1200,6 +1200,16 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
>       return size;
>   }
>   
> +static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq)
> +{
> +    VirtQueueElement *elem;
> +    while ((elem = virtqueue_pop(vq, sizeof(VirtQueueElement)))) {
> +        virtqueue_push(vq, elem, 0);
> +        virtio_notify(vdev, vq);
> +        g_free(elem);
> +    }
> +}
> +
>   static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
>   
>   static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
> @@ -1345,6 +1355,11 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
>       VirtIONet *n = VIRTIO_NET(vdev);
>       VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
>   
> +    if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) {
> +        virtio_net_drop_tx_queue_data(vdev, vq);
> +        return;
> +    }
> +
>       if (unlikely(q->tx_waiting)) {
>           return;
>       }

This doesn't work for tx timer, you may want to do the modification on 
virtio_net_flush_tx().

What's more, when link_down is true, qemu_send_packet_async() will 
return size of iov, can we do some check there?

Thanks
Yuri Benditovich Nov. 8, 2016, 8:26 a.m. UTC | #2
On Tue, Nov 8, 2016 at 8:48 AM, Jason Wang <jasowang@redhat.com> wrote:

>
>
> On 2016年11月07日 16:20, yuri.benditovich@daynix.com wrote:
>
>> From: Yuri Benditovich <yuri.benditovich@daynix.com>
>>
>> https://bugzilla.redhat.com/show_bug.cgi?id=1295637
>> Upon set_link monitor command or upon netdev deletion
>> virtio-net sends link down indication to the guest
>> and stops vhost if one is used.
>> Guest driver can still submit data for TX until it
>> recognizes link loss. If these packets not returned by
>> the host, the Windows guest will never be able to finish
>> disable/removal/shutdown.
>> Now each packet sent by guest after NIC indicated link
>> down will be completed immediately.
>>
>> Signed-off-by: Yuri Benditovich <yuri.benditovich@daynix.com>
>> ---
>>   hw/net/virtio-net.c | 15 +++++++++++++++
>>   1 file changed, 15 insertions(+)
>>
>> diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
>> index 06bfe4b..6158de0 100644
>> --- a/hw/net/virtio-net.c
>> +++ b/hw/net/virtio-net.c
>> @@ -1200,6 +1200,16 @@ static ssize_t virtio_net_receive(NetClientState
>> *nc, const uint8_t *buf, size_t
>>       return size;
>>   }
>>   +static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev,
>> VirtQueue *vq)
>> +{
>> +    VirtQueueElement *elem;
>> +    while ((elem = virtqueue_pop(vq, sizeof(VirtQueueElement)))) {
>> +        virtqueue_push(vq, elem, 0);
>> +        virtio_notify(vdev, vq);
>> +        g_free(elem);
>> +    }
>> +}
>> +
>>   static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
>>     static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
>> @@ -1345,6 +1355,11 @@ static void virtio_net_handle_tx_bh(VirtIODevice
>> *vdev, VirtQueue *vq)
>>       VirtIONet *n = VIRTIO_NET(vdev);
>>       VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
>>   +    if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) {
>> +        virtio_net_drop_tx_queue_data(vdev, vq);
>> +        return;
>> +    }
>> +
>>       if (unlikely(q->tx_waiting)) {
>>           return;
>>       }
>>
>
> This doesn't work for tx timer, you may want to do the modification on
> virtio_net_flush_tx().
>
> What's more, when link_down is true, qemu_send_packet_async() will return
> size of iov, can we do some check there?
>
> Thanks
>

I will prepare v2 with support for timer configuration. But in case of
vhost virtio_net_flush_tx() never called and without vhost I did not
succeed to reproduce the problem.
diff mbox

Patch

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 06bfe4b..6158de0 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1200,6 +1200,16 @@  static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t
     return size;
 }
 
+static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtQueueElement *elem;
+    while ((elem = virtqueue_pop(vq, sizeof(VirtQueueElement)))) {
+        virtqueue_push(vq, elem, 0);
+        virtio_notify(vdev, vq);
+        g_free(elem);
+    }
+}
+
 static int32_t virtio_net_flush_tx(VirtIONetQueue *q);
 
 static void virtio_net_tx_complete(NetClientState *nc, ssize_t len)
@@ -1345,6 +1355,11 @@  static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
     VirtIONet *n = VIRTIO_NET(vdev);
     VirtIONetQueue *q = &n->vqs[vq2q(virtio_get_queue_index(vq))];
 
+    if (unlikely((n->status & VIRTIO_NET_S_LINK_UP) == 0)) {
+        virtio_net_drop_tx_queue_data(vdev, vq);
+        return;
+    }
+
     if (unlikely(q->tx_waiting)) {
         return;
     }