Skip to content

Commit

Permalink
net: virtio-net discards TX data after link down
Browse files Browse the repository at this point in the history
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>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
  • Loading branch information
ybendito authored and mstsirkin committed Jan 10, 2017
1 parent 54e1770 commit 283e2c2
Showing 1 changed file with 26 additions and 0 deletions.
26 changes: 26 additions & 0 deletions hw/net/virtio-net.c
Expand Up @@ -218,6 +218,14 @@ static void virtio_net_vnet_endian_status(VirtIONet *n, uint8_t status)
}
}

static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq)
{
unsigned int dropped = virtqueue_drop_all(vq);
if (dropped) {
virtio_notify(vdev, vq);
}
}

static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
{
VirtIONet *n = VIRTIO_NET(vdev);
Expand Down Expand Up @@ -262,6 +270,14 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
} else {
qemu_bh_cancel(q->tx_bh);
}
if ((n->status & VIRTIO_NET_S_LINK_UP) == 0 &&
(queue_status & VIRTIO_CONFIG_S_DRIVER_OK)) {
/* if tx is waiting we are likely have some packets in tx queue
* and disabled notification */
q->tx_waiting = 0;
virtio_queue_set_notification(q->tx_vq, 1);
virtio_net_drop_tx_queue_data(vdev, q->tx_vq);
}
}
}
}
Expand Down Expand Up @@ -1323,6 +1339,11 @@ static void virtio_net_handle_tx_timer(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;
}

/* This happens when device was stopped but VCPU wasn't. */
if (!vdev->vm_running) {
q->tx_waiting = 1;
Expand All @@ -1349,6 +1370,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;
}
Expand Down

0 comments on commit 283e2c2

Please sign in to comment.