From 446dd66b7c7641974d25423c4cb5c48e481a84e4 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Tue, 16 Apr 2013 18:35:59 +0200 Subject: [PATCH] network: bridge_driver: don't lose transient networks on daemon restart 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 | 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 75584a026d..18a7d575fd 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 1a86e3d562..163478c834 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 30fdcd72d8..f778e9cd38 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 6ea09faad8..27dd230ee7 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);