Signed-off-by: Vladimir Sementsov-Ogievskiy <vsement...@yandex-team.ru> --- hw/net/virtio-net.c | 100 ++++++++++++++++++++++++++++++++- include/hw/virtio/virtio-net.h | 2 + 2 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 6b5b5dace3..874e349fee 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -38,6 +38,8 @@ #include "qapi/qapi-events-migration.h" #include "hw/virtio/virtio-access.h" #include "migration/misc.h" +#include "migration/migration.h" +#include "migration/options.h" #include "standard-headers/linux/ethtool.h" #include "system/system.h" #include "system/replay.h" @@ -2999,7 +3001,13 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue) n->multiqueue = multiqueue; virtio_net_change_num_queues(n, max * 2 + 1); - virtio_net_set_queue_pairs(n); + /* + * Called from set_features(0) on reset, when on target we + * doesn't have fds yet + */ + if (!n->tap_wait_incoming) { + virtio_net_set_queue_pairs(n); + } } static int virtio_net_pre_load_queues(VirtIODevice *vdev, uint32_t n) @@ -3009,6 +3017,19 @@ static int virtio_net_pre_load_queues(VirtIODevice *vdev, uint32_t n) return 0; } +static int virtio_net_pre_save_device(void *opaque) +{ + VirtIONet *n = opaque; + int i, r; + + for (i = 0; i < n->curr_queue_pairs; i++) { + r = peer_detach(n, i); + assert(!r); + } + + return 0; +} + static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, Error **errp) { @@ -3028,6 +3049,11 @@ static uint64_t virtio_net_get_features(VirtIODevice *vdev, uint64_t features, virtio_add_feature(&features, VIRTIO_NET_F_MAC); + if (n->tap_wait_incoming) { + /* Excessive feature set is OK for early initialization */ + return features; + } + if (!peer_has_vnet_hdr(n)) { virtio_clear_feature(&features, VIRTIO_NET_F_CSUM); virtio_clear_feature(&features, VIRTIO_NET_F_HOST_TSO4); @@ -3494,11 +3520,69 @@ static const VMStateDescription vhost_user_net_backend_state = { } }; +static int virtio_net_tap_save(QEMUFile *f, void *pv, size_t size, + const VMStateField *field, + JSONWriter *vmdesc) +{ + VirtIONet *n = pv; + int i; + + for (i = 0; i < n->max_queue_pairs; i++) { + NetClientState *nc = qemu_get_subqueue(n->nic, i); + assert(nc->peer->info->type == NET_CLIENT_DRIVER_TAP); + + tap_save(nc->peer, f); + } + + return 0; +} + +static int virtio_net_tap_load(QEMUFile *f, void *pv, size_t size, + const VMStateField *field) +{ + VirtIONet *n = pv; + VirtIODevice *vdev = VIRTIO_DEVICE(n); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); + Error *local_err = NULL; + int i; + + for (i = 0; i < n->max_queue_pairs; i++) { + NetClientState *nc = qemu_get_subqueue(n->nic, i); + assert(nc->peer->info->type == NET_CLIENT_DRIVER_TAP); + + tap_load(nc->peer, f); + } + + peer_test_vnet_hdr(n); + n->tap_wait_incoming = false; + + vdev->host_features = vdc->get_features(vdev, vdev->host_features, + &local_err); + if (local_err) { + error_report_err(local_err); + return -EINVAL; + } + + return 0; +} + +static bool virtio_net_is_tap_local(void *opaque, int version_id) +{ + VirtIONet *n = opaque; + NetClientState *nc; + + nc = qemu_get_queue(n->nic); + + return migrate_local_tap() && nc->peer && + nc->peer->info->type == NET_CLIENT_DRIVER_TAP; +} + static const VMStateDescription vmstate_virtio_net_device = { .name = "virtio-net-device", .version_id = VIRTIO_NET_VM_VERSION, .minimum_version_id = VIRTIO_NET_VM_VERSION, .post_load = virtio_net_post_load_device, + .pre_save = virtio_net_pre_save_device, .fields = (const VMStateField[]) { VMSTATE_UINT8_ARRAY(mac, VirtIONet, ETH_ALEN), VMSTATE_STRUCT_POINTER(vqs, VirtIONet, @@ -3525,6 +3609,15 @@ static const VMStateDescription vmstate_virtio_net_device = { * but based on the uint. */ VMSTATE_BUFFER_POINTER_UNSAFE(vlans, VirtIONet, 0, MAX_VLAN >> 3), + { + .name = "tap", + .info = &(const VMStateInfo) { + .name = "virtio-net vhost-user backend state", + .get = virtio_net_tap_load, + .put = virtio_net_tap_save, + }, + .field_exists = virtio_net_is_tap_local, + }, VMSTATE_WITH_TMP(VirtIONet, struct VirtIONetMigTmp, vmstate_virtio_net_has_vnet), VMSTATE_UINT8(mac_table.multi_overflow, VirtIONet), @@ -3954,6 +4047,11 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, 0, ETH_ALEN, VHOST_SET_CONFIG_TYPE_FRONTEND); } + + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_TAP) { + n->tap_wait_incoming = tap_local_incoming(nc->peer); + } + QTAILQ_INIT(&n->rsc_chains); n->qdev = dev; diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 73fdefc0dc..04ae0e4c06 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -231,6 +231,8 @@ struct VirtIONet { struct EBPFRSSContext ebpf_rss; uint32_t nr_ebpf_rss_fds; char **ebpf_rss_fds; + + bool tap_wait_incoming; }; size_t virtio_net_handle_ctrl_iov(VirtIODevice *vdev, -- 2.48.1