[PATCHv2] network: bridge_driver: don't lose transient networks on daemon restart

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

 



Until now tranisent networks weren't really useful as libvirtd wasn't
able to remember them across restarts. This patch adds support for
loading status files of transient networks (that already were generated)
so that the status isn't lost.

This patch chops up virNetworkObjUpdateParseFile and turns it into
virNetworkLoadState and a few friends that will help us to load status
XMLs and refactors the functions that are loading the configs to use
them.
---

Notes:
    Version 2:
    - renamed confDir to statusDir
    - clarified comment about goto
    - removed check if bridge name is present in XML
    - switched removal of inactive transient networks to while loop to avoid re-iteration

 src/conf/network_conf.c     | 207 ++++++++++++++++++++++++++++----------------
 src/conf/network_conf.h     |  10 ++-
 src/libvirt_private.syms    |   2 +-
 src/network/bridge_driver.c |  51 ++++++-----
 4 files changed, 171 insertions(+), 99 deletions(-)

diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 75584a0..18a7d57 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1967,81 +1967,6 @@ cleanup:
     return def;
 }

-int
-virNetworkObjUpdateParseFile(const char *filename,
-                             virNetworkObjPtr net)
-{
-    int ret = -1;
-    xmlDocPtr xml = NULL;
-    xmlNodePtr node = NULL;
-    virNetworkDefPtr tmp = NULL;
-    xmlXPathContextPtr ctxt = NULL;
-
-    xml = virXMLParse(filename, NULL, _("(network status)"));
-    if (!xml)
-        return -1;
-
-    ctxt = xmlXPathNewContext(xml);
-    if (ctxt == NULL) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    node = xmlDocGetRootElement(xml);
-    if (xmlStrEqual(node->name, BAD_CAST "networkstatus")) {
-        /* Newer network status file. Contains useful
-         * info which are not to be found in bare config XML */
-        char *class_id = NULL;
-        char *floor_sum = NULL;
-
-        ctxt->node = node;
-        class_id = virXPathString("string(./class_id[1]/@bitmap)", ctxt);
-        if (class_id) {
-            virBitmapFree(net->class_id);
-            if (virBitmapParse(class_id, 0,
-                               &net->class_id, CLASS_ID_BITMAP_SIZE) < 0) {
-                virReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("Malformed 'class_id' attribute: %s"),
-                               class_id);
-                VIR_FREE(class_id);
-                goto cleanup;
-            }
-        }
-        VIR_FREE(class_id);
-
-        floor_sum = virXPathString("string(./floor[1]/@sum)", ctxt);
-        if (floor_sum &&
-            virStrToLong_ull(floor_sum, NULL, 10, &net->floor_sum) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR,
-                           _("Malformed 'floor_sum' attribute: %s"),
-                           floor_sum);
-            VIR_FREE(floor_sum);
-        }
-        VIR_FREE(floor_sum);
-    }
-
-    node = virXPathNode("//network", ctxt);
-    if (!node) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("Could not find any 'network' element"));
-        goto cleanup;
-    }
-
-    ctxt->node = node;
-    tmp = virNetworkDefParseXML(ctxt);
-
-    if (tmp) {
-        net->newDef = net->def;
-        net->def = tmp;
-    }
-
-    ret = 0;
-
-cleanup:
-    xmlFreeDoc(xml);
-    xmlXPathFreeContext(ctxt);
-    return ret;
-}

 static int
 virNetworkDNSDefFormat(virBufferPtr buf,
@@ -2554,6 +2479,104 @@ cleanup:
     return ret;
 }

+virNetworkObjPtr
+virNetworkLoadState(virNetworkObjListPtr nets,
+                    const char *stateDir,
+                    const char *name)
+{
+    char *configFile = NULL;
+    virNetworkDefPtr def = NULL;
+    virNetworkObjPtr net = NULL;
+    xmlDocPtr xml = NULL;
+    xmlNodePtr node = NULL;
+    xmlXPathContextPtr ctxt = NULL;
+    virBitmapPtr class_id_map = NULL;
+    unsigned long long floor_sum_val = 0;
+
+
+    if ((configFile = virNetworkConfigFile(stateDir, name)) == NULL)
+        goto error;
+
+    if (!(xml = virXMLParseCtxt(configFile, NULL, _("(network status)"), &ctxt)))
+        goto error;
+
+    if (!(node = virXPathNode("//network", ctxt))) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Could not find any 'network' element in status file"));
+        goto error;
+    }
+
+    /* parse the definition first */
+    ctxt->node = node;
+    if (!(def = virNetworkDefParseXML(ctxt)))
+        goto error;
+
+    if (!STREQ(name, def->name)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Network config filename '%s'"
+                         " does not match network name '%s'"),
+                       configFile, def->name);
+        goto error;
+    }
+
+    /* now parse possible status data */
+    node = xmlDocGetRootElement(xml);
+    if (xmlStrEqual(node->name, BAD_CAST "networkstatus")) {
+        /* Newer network status file. Contains useful
+         * info which are not to be found in bare config XML */
+        char *class_id = NULL;
+        char *floor_sum = NULL;
+
+        ctxt->node = node;
+        if ((class_id = virXPathString("string(./class_id[1]/@bitmap)", ctxt))) {
+            if (virBitmapParse(class_id, 0, &class_id_map,
+                               CLASS_ID_BITMAP_SIZE) < 0) {
+                virReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Malformed 'class_id' attribute: %s"),
+                               class_id);
+                VIR_FREE(class_id);
+                goto error;
+            }
+        }
+        VIR_FREE(class_id);
+
+        floor_sum = virXPathString("string(./floor[1]/@sum)", ctxt);
+        if (floor_sum &&
+            virStrToLong_ull(floor_sum, NULL, 10, &floor_sum_val) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Malformed 'floor_sum' attribute: %s"),
+                           floor_sum);
+            VIR_FREE(floor_sum);
+        }
+        VIR_FREE(floor_sum);
+    }
+
+    /* create the object */
+    if (!(net = virNetworkAssignDef(nets, def, true)))
+        goto error;
+    /* do not put any "goto error" below this comment */
+
+    /* assign status data stored in the network object */
+    if (class_id_map) {
+        virBitmapFree(net->class_id);
+        net->class_id = class_id_map;
+    }
+
+    if (floor_sum_val > 0)
+        net->floor_sum = floor_sum_val;
+
+cleanup:
+    VIR_FREE(configFile);
+    xmlFreeDoc(xml);
+    xmlXPathFreeContext(ctxt);
+    return net;
+
+error:
+    virBitmapFree(class_id_map);
+    virNetworkDefFree(def);
+    goto cleanup;
+}
+
 virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
                                       const char *configDir,
                                       const char *autostartDir,
@@ -2612,6 +2635,40 @@ error:
     return NULL;
 }

+
+int
+virNetworkLoadAllState(virNetworkObjListPtr nets,
+                       const char *stateDir)
+{
+    DIR *dir;
+    struct dirent *entry;
+
+    if (!(dir = opendir(stateDir))) {
+        if (errno == ENOENT)
+            return 0;
+
+        virReportSystemError(errno, _("Failed to open dir '%s'"), stateDir);
+        return -1;
+    }
+
+    while ((entry = readdir(dir))) {
+        virNetworkObjPtr net;
+
+        if (entry->d_name[0] == '.')
+            continue;
+
+        if (!virFileStripSuffix(entry->d_name, ".xml"))
+            continue;
+
+        if ((net = virNetworkLoadState(nets, stateDir, entry->d_name)))
+            virNetworkObjUnlock(net);
+    }
+
+    closedir(dir);
+    return 0;
+}
+
+
 int virNetworkLoadAllConfigs(virNetworkObjListPtr nets,
                              const char *configDir,
                              const char *autostartDir)
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 1a86e3d..163478c 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -280,9 +280,6 @@ virNetworkDefPtr virNetworkDefParseString(const char *xmlStr);
 virNetworkDefPtr virNetworkDefParseFile(const char *filename);
 virNetworkDefPtr virNetworkDefParseNode(xmlDocPtr xml,
                                         xmlNodePtr root);
-int virNetworkObjUpdateParseFile(const char *filename,
-                                 virNetworkObjPtr net);
-
 char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags);

 static inline const char *
@@ -318,10 +315,17 @@ virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
                                       const char *autostartDir,
                                       const char *file);

+virNetworkObjPtr virNetworkLoadState(virNetworkObjListPtr nets,
+                                     const char *stateDir,
+                                     const char *name);
+
 int virNetworkLoadAllConfigs(virNetworkObjListPtr nets,
                              const char *configDir,
                              const char *autostartDir);

+int virNetworkLoadAllState(virNetworkObjListPtr nets,
+                           const char *stateDir);
+
 int virNetworkDeleteConfig(const char *configDir,
                            const char *autostartDir,
                            virNetworkObjPtr net);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 30fdcd7..f778e9c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -454,6 +454,7 @@ virNetworkIpDefNetmask;
 virNetworkIpDefPrefix;
 virNetworkList;
 virNetworkLoadAllConfigs;
+virNetworkLoadAllState;
 virNetworkObjAssignDef;
 virNetworkObjFree;
 virNetworkObjGetPersistentDef;
@@ -465,7 +466,6 @@ virNetworkObjSetDefTransient;
 virNetworkObjUnlock;
 virNetworkObjUnsetDefTransient;
 virNetworkObjUpdate;
-virNetworkObjUpdateParseFile;
 virNetworkRemoveInactive;
 virNetworkSaveConfig;
 virNetworkSaveStatus;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 6ea09fa..27dd230 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -180,6 +180,7 @@ networkRemoveInactive(struct network_driver *driver,
     char *radvdconfigfile = NULL;
     char *configfile = NULL;
     char *radvdpidbase = NULL;
+    char *statusfile = NULL;
     dnsmasqContext *dctx = NULL;
     virNetworkDefPtr def = virNetworkObjGetPersistentDef(net);

@@ -201,6 +202,9 @@ networkRemoveInactive(struct network_driver *driver,
     if (!(configfile = networkDnsmasqConfigFileName(def->name)))
         goto no_memory;

+    if (!(statusfile = virNetworkConfigFile(NETWORK_STATE_DIR, def->name)))
+        goto no_memory;
+
     /* dnsmasq */
     dnsmasqDelete(dctx);
     unlink(leasefile);
@@ -210,6 +214,9 @@ networkRemoveInactive(struct network_driver *driver,
     unlink(radvdconfigfile);
     virPidFileDelete(NETWORK_PID_DIR, radvdpidbase);

+    /* remove status file */
+    unlink(statusfile);
+
     /* remove the network definition */
     virNetworkRemoveInactive(&driver->networks, net);

@@ -220,6 +227,7 @@ cleanup:
     VIR_FREE(configfile);
     VIR_FREE(radvdconfigfile);
     VIR_FREE(radvdpidbase);
+    VIR_FREE(statusfile);
     dnsmasqContextFree(dctx);
     return ret;

@@ -253,33 +261,15 @@ networkBridgeDummyNicName(const char *brname)
 }

 static void
-networkFindActiveConfigs(struct network_driver *driver) {
+networkFindActiveConfigs(struct network_driver *driver)
+{
     unsigned int i;

     for (i = 0 ; i < driver->networks.count ; i++) {
         virNetworkObjPtr obj = driver->networks.objs[i];
-        char *config;

         virNetworkObjLock(obj);

-        if ((config = virNetworkConfigFile(NETWORK_STATE_DIR,
-                                           obj->def->name)) == NULL) {
-            virNetworkObjUnlock(obj);
-            continue;
-        }
-
-        if (access(config, R_OK) < 0) {
-            VIR_FREE(config);
-            virNetworkObjUnlock(obj);
-            continue;
-        }
-
-        /* Try and load the live config */
-        if (virNetworkObjUpdateParseFile(config, obj) < 0)
-            VIR_WARN("Unable to update config of '%s' network",
-                     obj->def->name);
-        VIR_FREE(config);
-
         /* If bridge exists, then mark it active */
         if (obj->def->bridge &&
             virNetDevExists(obj->def->bridge) == 1) {
@@ -306,6 +296,21 @@ networkFindActiveConfigs(struct network_driver *driver) {
     cleanup:
         virNetworkObjUnlock(obj);
     }
+
+    /* remove inactive transient networks */
+    i = 0;
+    while (i < driver->networks.count) {
+        virNetworkObjPtr obj = driver->networks.objs[i];
+        virNetworkObjLock(obj);
+
+        if (!obj->persistent && !obj->active) {
+            networkRemoveInactive(driver, obj);
+            continue;
+        }
+
+        virNetworkObjUnlock(obj);
+        i++;
+    }
 }


@@ -415,6 +420,10 @@ networkStartup(bool privileged,
     /* if this fails now, it will be retried later with dnsmasqCapsRefresh() */
     driverState->dnsmasqCaps = dnsmasqCapsNewFromBinary(DNSMASQ);

+    if (virNetworkLoadAllState(&driverState->networks,
+                               NETWORK_STATE_DIR) < 0)
+        goto error;
+
     if (virNetworkLoadAllConfigs(&driverState->networks,
                                  driverState->networkConfigDir,
                                  driverState->networkAutostartDir) < 0)
@@ -479,6 +488,8 @@ networkReload(void) {
         return 0;

     networkDriverLock(driverState);
+    virNetworkLoadAllState(&driverState->networks,
+                           NETWORK_STATE_DIR);
     virNetworkLoadAllConfigs(&driverState->networks,
                              driverState->networkConfigDir,
                              driverState->networkAutostartDir);
-- 
1.8.2.1

--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]