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.
This commit is contained in:
Peter Krempa 2013-04-16 18:35:59 +02:00
parent f1a1ebf19d
commit 446dd66b7c
4 changed files with 171 additions and 99 deletions

View File

@ -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)

View File

@ -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);

View File

@ -454,6 +454,7 @@ virNetworkIpDefNetmask;
virNetworkIpDefPrefix;
virNetworkList;
virNetworkLoadAllConfigs;
virNetworkLoadAllState;
virNetworkObjAssignDef;
virNetworkObjFree;
virNetworkObjGetPersistentDef;
@ -465,7 +466,6 @@ virNetworkObjSetDefTransient;
virNetworkObjUnlock;
virNetworkObjUnsetDefTransient;
virNetworkObjUpdate;
virNetworkObjUpdateParseFile;
virNetworkRemoveInactive;
virNetworkSaveConfig;
virNetworkSaveStatus;

View File

@ -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);