qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC PATCH 2/2] net/virtio: add failover support


From: Jens Freimann
Subject: [Qemu-devel] [RFC PATCH 2/2] net/virtio: add failover support
Date: Fri, 22 Mar 2019 14:44:47 +0100

From: Sameeh Jubran <address@hidden>

---
 hw/net/virtio-net.c            | 95 ++++++++++++++++++++++++++++++++++
 include/hw/virtio/virtio-net.h |  7 +++
 2 files changed, 102 insertions(+)

diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 7e2c2a6f6a..880420a673 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -12,6 +12,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/atomic.h"
 #include "qemu/iov.h"
 #include "hw/virtio/virtio.h"
 #include "net/net.h"
@@ -19,6 +20,7 @@
 #include "net/tap.h"
 #include "qemu/error-report.h"
 #include "qemu/timer.h"
+#include "qemu/option.h"
 #include "hw/virtio/virtio-net.h"
 #include "net/vhost_net.h"
 #include "net/announce.h"
@@ -29,6 +31,8 @@
 #include "migration/misc.h"
 #include "standard-headers/linux/ethtool.h"
 #include "trace.h"
+#include "monitor/qdev.h"
+#include "hw/pci/pci.h"
 
 #define VIRTIO_NET_VM_VERSION    11
 
@@ -364,6 +368,9 @@ static void virtio_net_set_status(struct VirtIODevice 
*vdev, uint8_t status)
     }
 }
 
+
+static void virtio_net_primary_plug_timer(void *opaque);
+
 static void virtio_net_set_link_status(NetClientState *nc)
 {
     VirtIONet *n = qemu_get_nic_opaque(nc);
@@ -786,6 +793,14 @@ static void virtio_net_set_features(VirtIODevice *vdev, 
uint64_t features)
     } else {
         memset(n->vlans, 0xff, MAX_VLAN >> 3);
     }
+
+    if (virtio_has_feature(features, VIRTIO_NET_F_STANDBY)) {
+        atomic_set(&n->primary_should_be_hidden, false);
+        if (n->primary_device_timer)
+            timer_mod(n->primary_device_timer,
+                qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+                4000);
+    }
 }
 
 static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
@@ -2626,6 +2641,74 @@ void virtio_net_set_netclient_name(VirtIONet *n, const 
char *name,
     n->netclient_type = g_strdup(type);
 }
 
+static void virtio_net_primary_plug_timer(void *opaque)
+{
+    VirtIONet *n = opaque;
+    Error *err = NULL;
+
+    n->primary_dev = qdev_device_add(n->primary_device_opts, &err);
+    if (!n->primary_dev && err)
+    {
+        if (n->primary_device_timer)
+            timer_mod(n->primary_device_timer,
+                qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+                100);
+    }
+}
+
+static void virtio_net_handle_migration_primary(VirtIONet *n, MigrationState * 
s)
+{
+    Error *err = NULL;
+    bool should_be_hidden = atomic_read(&n->primary_should_be_hidden);
+
+    if (migration_in_setup(s) && !should_be_hidden && n->primary_dev) {
+        /* Request unplug
+         *
+         *
+        */
+        qdev_unplug(n->primary_dev, &err);
+        if (!err)
+        {
+            atomic_set(&n->primary_should_be_hidden, true);
+            n->primary_dev = NULL;
+        }
+    } else if (migration_has_failed(s)) {
+        if (should_be_hidden && !n->primary_dev)
+        {
+            /* We already unplugged the device let's plugged it back */
+            n->primary_dev = qdev_device_add(n->primary_device_opts, &err);
+        }
+        else
+        {
+        }
+    }
+}
+
+static void migration_state_notifier(Notifier *notifier, void *data)
+{
+    MigrationState *s = data;
+    VirtIONet *n = container_of(notifier, VirtIONet, migration_state);
+    virtio_net_handle_migration_primary(n,s);
+}
+
+static void virtio_net_primary_should_be_hidden(DeviceListener *listener, 
QemuOpts *device_opts,
+            bool *match_found, bool *res)
+{
+   VirtIONet *n = container_of(listener, VirtIONet, primary_listener);
+   const char * dev_id = qemu_opts_id(device_opts);
+
+    *match_found = !strcmp(n->net_conf.primary_id_str ,dev_id);
+    if (atomic_read(&n->primary_should_be_hidden) && 
!strcmp(qemu_opt_get(device_opts, "driver"), "vfio-pci")
+    && *match_found)
+    {
+        n->primary_device_opts = device_opts;
+        *res = true;
+        return;
+    }
+
+    *res = false;
+}
+
 static void virtio_net_device_realize(DeviceState *dev, Error **errp)
 {
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@@ -2656,6 +2739,17 @@ static void virtio_net_device_realize(DeviceState *dev, 
Error **errp)
         n->host_features |= (1ULL << VIRTIO_NET_F_SPEED_DUPLEX);
     }
 
+    if (n->net_conf.primary_id_str) {
+        n->primary_listener.should_be_hidden = 
virtio_net_primary_should_be_hidden;
+        atomic_set(&n->primary_should_be_hidden, true);
+        device_listener_register(&n->primary_listener);
+        n->migration_state.notify = migration_state_notifier;
+        add_migration_state_change_notifier(&n->migration_state);
+        n->host_features |= (1ULL << VIRTIO_NET_F_STANDBY);
+        n->primary_device_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+                                     virtio_net_primary_plug_timer, n);
+    }
+
     virtio_net_set_config_size(n, n->host_features);
     virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
 
@@ -2885,6 +2979,7 @@ static Property virtio_net_properties[] = {
                      true),
     DEFINE_PROP_INT32("speed", VirtIONet, net_conf.speed, SPEED_UNKNOWN),
     DEFINE_PROP_STRING("duplex", VirtIONet, net_conf.duplex_str),
+    DEFINE_PROP_STRING("primary", VirtIONet, net_conf.primary_id_str),
     DEFINE_PROP_END_OF_LIST(),
 };
 
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index b96f0c643f..ec5f387aa9 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -43,6 +43,7 @@ typedef struct virtio_net_conf
     int32_t speed;
     char *duplex_str;
     uint8_t duplex;
+    char *primary_id_str;
 } virtio_net_conf;
 
 /* Coalesced packets type & status */
@@ -185,6 +186,12 @@ struct VirtIONet {
     AnnounceTimer announce_timer;
     bool needs_vnet_hdr_swap;
     bool mtu_bypass_backend;
+    QemuOpts *primary_device_opts;
+    DeviceState *primary_dev;
+    bool primary_should_be_hidden;
+    DeviceListener primary_listener;
+    QEMUTimer *primary_device_timer;
+    Notifier migration_state;
 };
 
 void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
-- 
2.20.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]