diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-09-04 17:39:07 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-09-04 17:39:07 +0100 |
commit | 8cf8c92e7775b9c5e811c55c9b8814168c46c34b (patch) | |
tree | 09b57396fc0a5fb7bab1341b11f62851fd678fd6 | |
parent | 01eb313907dda97313b8fea62e5632fca64f069c (diff) | |
parent | 086abc1ccd0fa5103345adda819e6c6436949579 (diff) | |
download | qemu-8cf8c92e7775b9c5e811c55c9b8814168c46c34b.zip |
Merge remote-tracking branch 'remotes/stefanha/tags/net-pull-request' into staging
Net patches
# gpg: Signature made Thu 04 Sep 2014 17:32:44 BST using RSA key ID 81AB73C8
# gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>"
# gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>"
* remotes/stefanha/tags/net-pull-request:
virtio-net: purge outstanding packets when starting vhost
net: complete all queued packets on VM stop
net: invoke callback when purging queue
virtio: don't call device on !vm_running
virtio-net: don't run bh on vm stopped
net: Forbid dealing with packets when VM is not running
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/net/virtio-net.c | 15 | ||||
-rw-r--r-- | hw/virtio/virtio.c | 9 | ||||
-rw-r--r-- | net/net.c | 40 | ||||
-rw-r--r-- | net/queue.c | 3 |
4 files changed, 64 insertions, 3 deletions
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 365e266b74..826a2a5fca 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -125,10 +125,23 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) return; } if (!n->vhost_started) { - int r; + int r, i; + if (!vhost_net_query(get_vhost_net(nc->peer), vdev)) { return; } + + /* Any packets outstanding? Purge them to avoid touching rings + * when vhost is running. + */ + for (i = 0; i < queues; i++) { + NetClientState *qnc = qemu_get_subqueue(n->nic, i); + + /* Purge both directions: TX and RX. */ + qemu_net_queue_purge(qnc->peer->incoming_queue, qnc); + qemu_net_queue_purge(qnc->incoming_queue, qnc->peer); + } + n->vhost_started = 1; r = vhost_net_start(vdev, n->nic->ncs, queues); if (r < 0) { diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 5c981801f3..ac222385d6 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1108,7 +1108,10 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state) BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK); - vdev->vm_running = running; + + if (running) { + vdev->vm_running = running; + } if (backend_run) { virtio_set_status(vdev, vdev->status); @@ -1121,6 +1124,10 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state) if (!backend_run) { virtio_set_status(vdev, vdev->status); } + + if (!running) { + vdev->vm_running = running; + } } void virtio_init(VirtIODevice *vdev, const char *name, @@ -41,12 +41,14 @@ #include "qapi-visit.h" #include "qapi/opts-visitor.h" #include "qapi/dealloc-visitor.h" +#include "sysemu/sysemu.h" /* Net bridge is currently not supported for W32. */ #if !defined(_WIN32) # define CONFIG_NET_BRIDGE #endif +static VMChangeStateEntry *net_change_state_entry; static QTAILQ_HEAD(, NetClientState) net_clients; const char *host_net_devices[] = { @@ -452,6 +454,12 @@ void qemu_set_vnet_hdr_len(NetClientState *nc, int len) int qemu_can_send_packet(NetClientState *sender) { + int vm_running = runstate_is_running(); + + if (!vm_running) { + return 0; + } + if (!sender->peer) { return 1; } @@ -504,7 +512,8 @@ void qemu_purge_queued_packets(NetClientState *nc) qemu_net_queue_purge(nc->peer->incoming_queue, nc); } -void qemu_flush_queued_packets(NetClientState *nc) +static +void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge) { nc->receive_disabled = 0; @@ -518,9 +527,17 @@ void qemu_flush_queued_packets(NetClientState *nc) * the file descriptor (for tap, for example). */ qemu_notify_event(); + } else if (purge) { + /* Unable to empty the queue, purge remaining packets */ + qemu_net_queue_purge(nc->incoming_queue, nc); } } +void qemu_flush_queued_packets(NetClientState *nc) +{ + qemu_flush_or_purge_queued_packets(nc, false); +} + static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, unsigned flags, const uint8_t *buf, int size, @@ -1168,6 +1185,22 @@ void qmp_set_link(const char *name, bool up, Error **errp) } } +static void net_vm_change_state_handler(void *opaque, int running, + RunState state) +{ + /* Complete all queued packets, to guarantee we don't modify + * state later when VM is not running. + */ + if (!running) { + NetClientState *nc; + NetClientState *tmp; + + QTAILQ_FOREACH_SAFE(nc, &net_clients, next, tmp) { + qemu_flush_or_purge_queued_packets(nc, true); + } + } +} + void net_cleanup(void) { NetClientState *nc; @@ -1183,6 +1216,8 @@ void net_cleanup(void) qemu_del_net_client(nc); } } + + qemu_del_vm_change_state_handler(net_change_state_entry); } void net_check_clients(void) @@ -1268,6 +1303,9 @@ int net_init_clients(void) #endif } + net_change_state_entry = + qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); + QTAILQ_INIT(&net_clients); if (qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, 1) == -1) diff --git a/net/queue.c b/net/queue.c index 859d02a136..f948318718 100644 --- a/net/queue.c +++ b/net/queue.c @@ -233,6 +233,9 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) if (packet->sender == from) { QTAILQ_REMOVE(&queue->packets, packet, entry); queue->nq_count--; + if (packet->sent_cb) { + packet->sent_cb(packet->sender, 0); + } g_free(packet); } } |