diff options
Diffstat (limited to 'hw/net/virtio-net.c')
-rw-r--r-- | hw/net/virtio-net.c | 282 |
1 files changed, 110 insertions, 172 deletions
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 9179013ac4..044ac95f6f 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -788,93 +788,95 @@ static inline uint64_t virtio_net_supported_guest_offloads(VirtIONet *n) return virtio_net_guest_offloads_by_features(vdev->guest_features); } -static void failover_add_primary(VirtIONet *n, Error **errp) -{ - Error *err = NULL; - - if (n->primary_dev) { - return; - } - - n->primary_device_opts = qemu_opts_find(qemu_find_opts("device"), - n->primary_device_id); - if (n->primary_device_opts) { - n->primary_dev = qdev_device_add(n->primary_device_opts, &err); - if (err) { - qemu_opts_del(n->primary_device_opts); - } - if (n->primary_dev) { - n->primary_bus = n->primary_dev->parent_bus; - if (err) { - qdev_unplug(n->primary_dev, &err); - qdev_set_id(n->primary_dev, ""); - - } - } - } else { - error_setg(errp, "Primary device not found"); - error_append_hint(errp, "Virtio-net failover will not work. Make " - "sure primary device has parameter" - " failover_pair_id=<virtio-net-id>\n"); -} - error_propagate(errp, err); -} +typedef struct { + VirtIONet *n; + char *id; +} FailoverId; -static int is_my_primary(void *opaque, QemuOpts *opts, Error **errp) +/** + * Set the id of the failover primary device + * + * @opaque: FailoverId to setup + * @opts: opts for device we are handling + * @errp: returns an error if this function fails + */ +static int failover_set_primary(void *opaque, QemuOpts *opts, Error **errp) { - VirtIONet *n = opaque; - int ret = 0; - + FailoverId *fid = opaque; const char *standby_id = qemu_opt_get(opts, "failover_pair_id"); - if (standby_id != NULL && (g_strcmp0(standby_id, n->netclient_name) == 0)) { - n->primary_device_id = g_strdup(opts->id); - ret = 1; + if (g_strcmp0(standby_id, fid->n->netclient_name) == 0) { + fid->id = g_strdup(opts->id); + return 1; } - return ret; + return 0; } -static DeviceState *virtio_net_find_primary(VirtIONet *n, Error **errp) +/** + * Find the primary device id for this failover virtio-net + * + * @n: VirtIONet device + * @errp: returns an error if this function fails + */ +static char *failover_find_primary_device_id(VirtIONet *n) { - DeviceState *dev = NULL; Error *err = NULL; + FailoverId fid; - if (qemu_opts_foreach(qemu_find_opts("device"), - is_my_primary, n, &err)) { - if (err) { - error_propagate(errp, err); - return NULL; - } - if (n->primary_device_id) { - dev = qdev_find_recursive(sysbus_get_default(), - n->primary_device_id); - } else { - error_setg(errp, "Primary device id not found"); - return NULL; - } + fid.n = n; + if (!qemu_opts_foreach(qemu_find_opts("device"), + failover_set_primary, &fid, &err)) { + return NULL; } - return dev; + return fid.id; } +/** + * Find the primary device for this failover virtio-net + * + * @n: VirtIONet device + * @errp: returns an error if this function fails + */ +static DeviceState *failover_find_primary_device(VirtIONet *n) +{ + char *id = failover_find_primary_device_id(n); + + if (!id) { + return NULL; + } + return qdev_find_recursive(sysbus_get_default(), id); +} -static DeviceState *virtio_connect_failover_devices(VirtIONet *n, - DeviceState *dev, - Error **errp) +static void failover_add_primary(VirtIONet *n, Error **errp) { - DeviceState *prim_dev = NULL; Error *err = NULL; + QemuOpts *opts; + char *id; + DeviceState *dev = failover_find_primary_device(n); - prim_dev = virtio_net_find_primary(n, &err); - if (prim_dev) { - n->primary_device_id = g_strdup(prim_dev->id); - n->primary_device_opts = prim_dev->opts; - } else { - error_propagate(errp, err); + if (dev) { + return; } - return prim_dev; + id = failover_find_primary_device_id(n); + if (!id) { + return; + } + opts = qemu_opts_find(qemu_find_opts("device"), id); + if (opts) { + dev = qdev_device_add(opts, &err); + if (err) { + qemu_opts_del(opts); + } + } else { + error_setg(errp, "Primary device not found"); + error_append_hint(errp, "Virtio-net failover will not work. Make " + "sure primary device has parameter" + " failover_pair_id=<virtio-net-id>\n"); + } + error_propagate(errp, err); } static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) @@ -929,25 +931,12 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint64_t features) if (virtio_has_feature(features, VIRTIO_NET_F_STANDBY)) { qapi_event_send_failover_negotiated(n->netclient_name); - qatomic_set(&n->primary_should_be_hidden, false); + qatomic_set(&n->failover_primary_hidden, false); failover_add_primary(n, &err); if (err) { - n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); - if (err) { - goto out_err; - } - failover_add_primary(n, &err); - if (err) { - goto out_err; - } + warn_report_err(err); } } - return; - -out_err: - if (err) { - warn_report_err(err); - } } static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, @@ -3095,17 +3084,17 @@ void virtio_net_set_netclient_name(VirtIONet *n, const char *name, n->netclient_type = g_strdup(type); } -static bool failover_unplug_primary(VirtIONet *n) +static bool failover_unplug_primary(VirtIONet *n, DeviceState *dev) { HotplugHandler *hotplug_ctrl; PCIDevice *pci_dev; Error *err = NULL; - hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); + hotplug_ctrl = qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { - pci_dev = PCI_DEVICE(n->primary_dev); + pci_dev = PCI_DEVICE(dev); pci_dev->partially_hotplugged = true; - hotplug_handler_unplug_request(hotplug_ctrl, n->primary_dev, &err); + hotplug_handler_unplug_request(hotplug_ctrl, dev, &err); if (err) { error_report_err(err); return false; @@ -3116,41 +3105,31 @@ static bool failover_unplug_primary(VirtIONet *n) return true; } -static bool failover_replug_primary(VirtIONet *n, Error **errp) +static bool failover_replug_primary(VirtIONet *n, DeviceState *dev, + Error **errp) { Error *err = NULL; HotplugHandler *hotplug_ctrl; - PCIDevice *pdev = PCI_DEVICE(n->primary_dev); + PCIDevice *pdev = PCI_DEVICE(dev); + BusState *primary_bus; if (!pdev->partially_hotplugged) { return true; } - if (!n->primary_device_opts) { - n->primary_device_opts = qemu_opts_from_qdict( - qemu_find_opts("device"), - n->primary_device_dict, errp); - if (!n->primary_device_opts) { - return false; - } - } - n->primary_bus = n->primary_dev->parent_bus; - if (!n->primary_bus) { + primary_bus = dev->parent_bus; + if (!primary_bus) { error_setg(errp, "virtio_net: couldn't find primary bus"); return false; } - qdev_set_parent_bus(n->primary_dev, n->primary_bus, &error_abort); - n->primary_should_be_hidden = false; - if (!qemu_opt_set_bool(n->primary_device_opts, - "partially_hotplugged", true, errp)) { - return false; - } - hotplug_ctrl = qdev_get_hotplug_handler(n->primary_dev); + qdev_set_parent_bus(dev, primary_bus, &error_abort); + qatomic_set(&n->failover_primary_hidden, false); + hotplug_ctrl = qdev_get_hotplug_handler(dev); if (hotplug_ctrl) { - hotplug_handler_pre_plug(hotplug_ctrl, n->primary_dev, &err); + hotplug_handler_pre_plug(hotplug_ctrl, dev, &err); if (err) { goto out; } - hotplug_handler_plug(hotplug_ctrl, n->primary_dev, &err); + hotplug_handler_plug(hotplug_ctrl, dev, &err); } out: @@ -3158,34 +3137,29 @@ out: return !err; } -static void virtio_net_handle_migration_primary(VirtIONet *n, - MigrationState *s) +static void virtio_net_handle_migration_primary(VirtIONet *n, MigrationState *s) { bool should_be_hidden; Error *err = NULL; + DeviceState *dev = failover_find_primary_device(n); - should_be_hidden = qatomic_read(&n->primary_should_be_hidden); - - if (!n->primary_dev) { - n->primary_dev = virtio_connect_failover_devices(n, n->qdev, &err); - if (!n->primary_dev) { - return; - } + if (!dev) { + return; } + should_be_hidden = qatomic_read(&n->failover_primary_hidden); + if (migration_in_setup(s) && !should_be_hidden) { - if (failover_unplug_primary(n)) { - vmstate_unregister(VMSTATE_IF(n->primary_dev), - qdev_get_vmsd(n->primary_dev), - n->primary_dev); - qapi_event_send_unplug_primary(n->primary_device_id); - qatomic_set(&n->primary_should_be_hidden, true); + if (failover_unplug_primary(n, dev)) { + vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); + qapi_event_send_unplug_primary(dev->id); + qatomic_set(&n->failover_primary_hidden, true); } else { warn_report("couldn't unplug primary device"); } } else if (migration_has_failed(s)) { /* We already unplugged the device let's plug it back */ - if (!failover_replug_primary(n, &err)) { + if (!failover_replug_primary(n, dev, &err)) { if (err) { error_report_err(err); } @@ -3200,55 +3174,22 @@ static void virtio_net_migration_state_notifier(Notifier *notifier, void *data) virtio_net_handle_migration_primary(n, s); } -static int virtio_net_primary_should_be_hidden(DeviceListener *listener, - QemuOpts *device_opts) +static bool failover_hide_primary_device(DeviceListener *listener, + QemuOpts *device_opts) { VirtIONet *n = container_of(listener, VirtIONet, primary_listener); - bool match_found = false; - bool hide = false; + const char *standby_id; if (!device_opts) { - return -1; - } - n->primary_device_dict = qemu_opts_to_qdict(device_opts, - n->primary_device_dict); - if (n->primary_device_dict) { - g_free(n->standby_id); - n->standby_id = g_strdup(qdict_get_try_str(n->primary_device_dict, - "failover_pair_id")); - } - if (g_strcmp0(n->standby_id, n->netclient_name) == 0) { - match_found = true; - } else { - match_found = false; - hide = false; - g_free(n->standby_id); - n->primary_device_dict = NULL; - goto out; + return false; } - - n->primary_device_opts = device_opts; - - /* primary_should_be_hidden is set during feature negotiation */ - hide = qatomic_read(&n->primary_should_be_hidden); - - if (n->primary_device_dict) { - g_free(n->primary_device_id); - n->primary_device_id = g_strdup(qdict_get_try_str( - n->primary_device_dict, "id")); - if (!n->primary_device_id) { - warn_report("primary_device_id not set"); - } + standby_id = qemu_opt_get(device_opts, "failover_pair_id"); + if (g_strcmp0(standby_id, n->netclient_name) != 0) { + return false; } -out: - if (match_found && hide) { - return 1; - } else if (match_found && !hide) { - return 0; - } else { - return -1; - } + /* failover_primary_hidden is set during feature negotiation */ + return qatomic_read(&n->failover_primary_hidden); } static void virtio_net_device_realize(DeviceState *dev, Error **errp) @@ -3285,9 +3226,8 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp) } if (n->failover) { - n->primary_listener.should_be_hidden = - virtio_net_primary_should_be_hidden; - qatomic_set(&n->primary_should_be_hidden, true); + n->primary_listener.hide_device = failover_hide_primary_device; + qatomic_set(&n->failover_primary_hidden, true); device_listener_register(&n->primary_listener); n->migration_state.notify = virtio_net_migration_state_notifier; add_migration_state_change_notifier(&n->migration_state); @@ -3426,10 +3366,6 @@ static void virtio_net_device_unrealize(DeviceState *dev) if (n->failover) { device_listener_unregister(&n->primary_listener); - g_free(n->primary_device_id); - g_free(n->standby_id); - qobject_unref(n->primary_device_dict); - n->primary_device_dict = NULL; } max_queues = n->multiqueue ? n->max_queues : 1; @@ -3475,13 +3411,15 @@ static int virtio_net_pre_save(void *opaque) static bool primary_unplug_pending(void *opaque) { DeviceState *dev = opaque; + DeviceState *primary; VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIONet *n = VIRTIO_NET(vdev); if (!virtio_vdev_has_feature(vdev, VIRTIO_NET_F_STANDBY)) { return false; } - return n->primary_dev ? n->primary_dev->pending_deleted_event : false; + primary = failover_find_primary_device(n); + return primary ? primary->pending_deleted_event : false; } static bool dev_unplug_pending(void *opaque) |