aboutsummaryrefslogtreecommitdiff
path: root/hw/net/virtio-net.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/net/virtio-net.c')
-rw-r--r--hw/net/virtio-net.c282
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)