[PATCH 3/5] ch: implement network device hot attach

Stefan Kober posted 5 patches 3 weeks ago
[PATCH 3/5] ch: implement network device hot attach
Posted by Stefan Kober 3 weeks ago
On-behalf-of: SAP stefan.kober@sap.com
Signed-off-by: Stefan Kober <stefan.kober@cyberus-technology.de>
---
 src/ch/ch_hotplug.c |  10 +++
 src/ch/ch_monitor.c |   5 +-
 src/ch/ch_monitor.h |   1 -
 src/ch/ch_process.c | 163 +++++++++++++++++++++++++-------------------
 src/ch/ch_process.h |   8 +++
 5 files changed, 111 insertions(+), 76 deletions(-)

diff --git a/src/ch/ch_hotplug.c b/src/ch/ch_hotplug.c
index 902eab839b..25058e08f3 100644
--- a/src/ch/ch_hotplug.c
+++ b/src/ch/ch_hotplug.c
@@ -75,6 +75,16 @@ chDomainAttachDeviceLive(virCHDriver *driver,
         break;
 
     case VIR_DOMAIN_DEVICE_NET:
+        if (chProcessAddNetworkDevice(driver, mon, vm->def, dev->data.net,
+                                      NULL, NULL) < 0) {
+            break;
+        }
+
+        virDomainNetInsert(vm->def, dev->data.net);
+
+        dev->data.net = NULL;
+        ret = 0;
+        break;
     case VIR_DOMAIN_DEVICE_LEASE:
     case VIR_DOMAIN_DEVICE_FS:
     case VIR_DOMAIN_DEVICE_INPUT:
diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c
index 65dc89cfd1..46b31acc76 100644
--- a/src/ch/ch_monitor.c
+++ b/src/ch/ch_monitor.c
@@ -379,7 +379,6 @@ virCHMonitorBuildRngJson(virJSONValue *content, virDomainDef *vmdef)
 /**
  * virCHMonitorBuildNetJson:
  * @net: pointer to a guest network definition
- * @netindex: index of the guest network definition
  * @jsonstr: returned network json
  *
  * Build net json to send to CH
@@ -387,15 +386,13 @@ virCHMonitorBuildRngJson(virJSONValue *content, virDomainDef *vmdef)
  */
 int
 virCHMonitorBuildNetJson(virDomainNetDef *net,
-                         int netindex,
                          char **jsonstr)
 {
     char macaddr[VIR_MAC_STRING_BUFLEN];
     g_autoptr(virJSONValue) net_json = virJSONValueNewObject();
     virDomainNetType actualType = virDomainNetGetActualType(net);
 
-    g_autofree char *id = g_strdup_printf("%s_%d", CH_NET_ID_PREFIX, netindex);
-    if (virJSONValueObjectAppendString(net_json, "id", id) < 0)
+    if (virJSONValueObjectAppendString(net_json, "id", net->info.alias) < 0)
         return -1;
 
     if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET &&
diff --git a/src/ch/ch_monitor.h b/src/ch/ch_monitor.h
index e3fde06f88..a462630be0 100644
--- a/src/ch/ch_monitor.h
+++ b/src/ch/ch_monitor.h
@@ -138,7 +138,6 @@ int virCHMonitorGetIOThreads(virCHMonitor *mon,
                              virDomainIOThreadInfo ***iothreads);
 int
 virCHMonitorBuildNetJson(virDomainNetDef *netdef,
-                         int netindex,
                          char **jsonstr);
 int
 virCHMonitorAddDisk(virCHMonitor* mon,
diff --git a/src/ch/ch_process.c b/src/ch/ch_process.c
index 54b21b0baf..a1f30f09e1 100644
--- a/src/ch/ch_process.c
+++ b/src/ch/ch_process.c
@@ -624,30 +624,24 @@ chCloseFDs(int *fds, size_t nfds)
     return 0;
 }
 
-/**
- * chProcessAddNetworkDevices:
- * @driver: pointer to ch driver object
- * @mon: pointer to the monitor object
- * @vmdef: pointer to domain definition
- * @nicindexes: returned array of FDs of guest interfaces
- * @nnicindexes: returned number of network indexes
- *
- * Send tap fds to CH process via AddNet api. Capture the network indexes of
- * guest interfaces in nicindexes.
- *
- * Returns 0 on success, -1 on error.
- */
-static int
-chProcessAddNetworkDevices(virCHDriver *driver,
-                           virCHMonitor *mon,
-                           virDomainDef *vmdef,
-                           int **nicindexes,
-                           size_t *nnicindexes)
+int
+chProcessAddNetworkDevice(virCHDriver *driver,
+                          virCHMonitor *mon,
+                          virDomainDef *vmdef,
+                          virDomainNetDef *net,
+                          int **nicindexes,
+                          size_t *nnicindexes)
 {
-    size_t i;
     VIR_AUTOCLOSE mon_sockfd = -1;
     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
     g_auto(virBuffer) http_headers = VIR_BUFFER_INITIALIZER;
+    g_autofree int *tapfds = NULL;
+    g_autofree char *payload = NULL;
+    g_autofree char *response = NULL;
+    size_t tapfd_len;
+    size_t payload_len;
+    int saved_errno;
+    int rc;
 
     if (!virBitmapIsBitSet(driver->chCaps, CH_MULTIFD_IN_ADDNET)) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -655,73 +649,100 @@ chProcessAddNetworkDevices(virCHDriver *driver,
         return -1;
     }
 
-    if ((mon_sockfd = chMonitorSocketConnect(mon)) < 0)
+    if ((mon_sockfd = chMonitorSocketConnect(mon)) < 0) {
+        VIR_WARN("chProcessAddNetworkDevices failed");
         return -1;
+    }
 
     virBufferAddLit(&http_headers, "PUT /api/v1/vm.add-net HTTP/1.1\r\n");
     virBufferAddLit(&http_headers, "Host: localhost\r\n");
     virBufferAddLit(&http_headers, "Content-Type: application/json\r\n");
 
-    for (i = 0; i < vmdef->nnets; i++) {
-        g_autofree int *tapfds = NULL;
-        g_autofree char *payload = NULL;
-        g_autofree char *response = NULL;
-        size_t tapfd_len;
-        size_t payload_len;
-        int saved_errno;
-        int rc;
-
-        if (vmdef->nets[i]->driver.virtio.queues == 0) {
-            /* "queues" here refers to queue pairs. When 0, initialize
-             * queue pairs to 1.
-             */
-            vmdef->nets[i]->driver.virtio.queues = 1;
-        }
-        tapfd_len = vmdef->nets[i]->driver.virtio.queues;
 
-        if (virCHDomainValidateActualNetDef(vmdef->nets[i]) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("net definition failed validation"));
-            return -1;
-        }
+    if (net->driver.virtio.queues == 0) {
+        /* "queues" here refers to queue pairs. When 0, initialize
+            * queue pairs to 1.
+            */
+        net->driver.virtio.queues = 1;
+    }
+    tapfd_len = net->driver.virtio.queues;
 
-        tapfds = g_new0(int, tapfd_len);
-        memset(tapfds, -1, (tapfd_len) * sizeof(int));
+    if (virCHDomainValidateActualNetDef(net) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("net definition failed validation"));
+        return -1;
+    }
 
-        /* Connect Guest interfaces */
-        if (virCHConnetNetworkInterfaces(driver, vmdef, vmdef->nets[i], tapfds,
-                                         nicindexes, nnicindexes) < 0)
-            return -1;
+    tapfds = g_new0(int, tapfd_len);
+    memset(tapfds, -1, (tapfd_len) * sizeof(int));
 
-        if (virCHMonitorBuildNetJson(vmdef->nets[i], i, &payload) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("Failed to build net json"));
-            return -1;
-        }
+    /* Connect Guest interfaces */
+    if (virCHConnetNetworkInterfaces(driver, vmdef, net, tapfds,
+                                     nicindexes, nnicindexes) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Failed to connect network interfaces"));
+        return -1;
+    }
 
-        VIR_DEBUG("payload sent with net-add request to CH = %s", payload);
+    chAssignDeviceNetAlias(vmdef, net);
+    if (virCHMonitorBuildNetJson(net, &payload) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Failed to build net json"));
+        return -1;
+    }
 
-        virBufferAsprintf(&buf, "%s", virBufferCurrentContent(&http_headers));
-        virBufferAsprintf(&buf, "Content-Length: %zu\r\n\r\n", strlen(payload));
-        virBufferAsprintf(&buf, "%s", payload);
-        payload_len = virBufferUse(&buf);
-        payload = virBufferContentAndReset(&buf);
+    virBufferAsprintf(&buf, "%s", virBufferCurrentContent(&http_headers));
+    virBufferAsprintf(&buf, "Content-Length: %zu\r\n\r\n", strlen(payload));
+    virBufferAsprintf(&buf, "%s", payload);
+    payload_len = virBufferUse(&buf);
+    payload = virBufferContentAndReset(&buf);
 
-        rc = virSocketSendMsgWithFDs(mon_sockfd, payload, payload_len,
-                                     tapfds, tapfd_len);
-        saved_errno = errno;
+    rc = virSocketSendMsgWithFDs(mon_sockfd, payload, payload_len,
+                                 tapfds, tapfd_len);
+    saved_errno = errno;
 
-        /* Close sent tap fds in Libvirt, as they have been dup()ed in CH */
-        chCloseFDs(tapfds, tapfd_len);
+    /* Close sent tap fds in Libvirt, as they have been dup()ed in CH */
+    chCloseFDs(tapfds, tapfd_len);
 
-        if (rc < 0) {
-            virReportSystemError(saved_errno, "%s",
-                                 _("Failed to send net-add request to CH"));
-            return -1;
-        }
+    if (rc < 0) {
+        virReportSystemError(saved_errno, "%s",
+                                _("Failed to send net-add request to CH"));
+        return -1;
+    }
 
-        if (chSocketProcessHttpResponse(mon_sockfd, true) < 0)
-            return -1;
+    if (chSocketProcessHttpResponse(mon_sockfd, true) < 0)
+        return -1;
+
+    return 0;
+}
+
+/**
+ * chProcessAddNetworkDevices:
+ * @driver: pointer to ch driver object
+ * @mon: pointer to the monitor object
+ * @vmdef: pointer to domain definition
+ * @nicindexes: returned array of FDs of guest interfaces
+ * @nnicindexes: returned number of network indexes
+ *
+ * Send tap fds to CH process via AddNet api. Capture the network indexes of
+ * guest interfaces in nicindexes.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+static int
+chProcessAddNetworkDevices(virCHDriver *driver,
+                           virCHMonitor *mon,
+                           virDomainDef *vmdef,
+                           int **nicindexes,
+                           size_t *nnicindexes)
+{
+    size_t i = 0;
+
+    for (i = 0; i < vmdef->nnets; i++) {
+       if (chProcessAddNetworkDevice(driver, mon, vmdef, vmdef->nets[i],
+                                     nicindexes, nnicindexes) < 0) {
+        return -1;
+       }
     }
 
     return 0;
diff --git a/src/ch/ch_process.h b/src/ch/ch_process.h
index a22790bb5c..e9b1f559d9 100644
--- a/src/ch/ch_process.h
+++ b/src/ch/ch_process.h
@@ -41,3 +41,11 @@ int virCHProcessStartRestore(virCHDriver *driver,
                          const char *from);
 
 int virCHProcessUpdateInfo(virDomainObj *vm);
+
+int
+chProcessAddNetworkDevice(virCHDriver *driver,
+                          virCHMonitor *mon,
+                          virDomainDef *vmdef,
+                          virDomainNetDef *net,
+                          int **nicindexes,
+                          size_t *nnicindexes);
-- 
2.51.0