[libvirt] [PATCH 2/2] network: bridge_driver: don't lose transient networks on daemon restart

Peter Krempa pkrempa at redhat.com
Wed Apr 17 08:40:45 UTC 2013


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.
---
 src/conf/network_conf.c     | 220 +++++++++++++++++++++++++++++---------------
 src/conf/network_conf.h     |  10 +-
 src/libvirt_private.syms    |   2 +-
 src/network/bridge_driver.c |  51 ++++++----
 4 files changed, 184 insertions(+), 99 deletions(-)

diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 75584a0..009e90c 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,117 @@ cleanup:
     return ret;
 }

+virNetworkObjPtr
+virNetworkLoadState(virNetworkObjListPtr nets,
+                    const char *configDir,
+                    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(configDir, 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;
+    }
+
+    if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
+        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
+        def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
+        /* state configs should always have the bridge stored in the file */
+        if (!def->bridge || strstr(def->bridge, "%d")) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("network status XML does not contain valid bridge "
+                             "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;
+    /* no 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 +2648,40 @@ error:
     return NULL;
 }

+
+int
+virNetworkLoadAllState(virNetworkObjListPtr nets,
+                       const char *configDir)
+{
+    DIR *dir;
+    struct dirent *entry;
+
+    if (!(dir = opendir(configDir))) {
+        if (errno == ENOENT)
+            return 0;
+
+        virReportSystemError(errno, _("Failed to open dir '%s'"), configDir);
+        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, configDir, 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..7d4c40b 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 *configDir,
+                                     const char *name);
+
 int virNetworkLoadAllConfigs(virNetworkObjListPtr nets,
                              const char *configDir,
                              const char *autostartDir);

+int virNetworkLoadAllState(virNetworkObjListPtr nets,
+                           const char *configDir);
+
 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 bca6bd9..56af108 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -181,6 +181,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);

@@ -202,6 +203,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);
@@ -211,6 +215,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);

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

@@ -254,33 +262,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) {
@@ -307,6 +297,21 @@ networkFindActiveConfigs(struct network_driver *driver) {
     cleanup:
         virNetworkObjUnlock(obj);
     }
+
+redo:
+    /* remove inactive transient domains */
+    for (i = 0 ; i < driver->networks.count ; i++) {
+        virNetworkObjPtr obj = driver->networks.objs[i];
+
+        virNetworkObjLock(obj);
+
+        if (!obj->persistent && !obj->active) {
+            networkRemoveInactive(driver, obj);
+            goto redo;
+        }
+
+        virNetworkObjUnlock(obj);
+    }
 }


@@ -416,6 +421,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)
@@ -480,6 +489,8 @@ networkReload(void) {
         return 0;

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




More information about the libvir-list mailing list