From: Yuri Benditovich <address@hidden>
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 <address@hidden>
---
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;
}