Like we keep domain status file to keep some internal data
during daemon restart, now it is needed for network as well.
Because network has now class_id attribute which is hidden
from users and thus not part of network XML.
---
daemon/libvirtd.c | 3 +
src/conf/network_conf.c | 219 ++++++++++++++++++++++++++++++++++++-------
src/conf/network_conf.h | 7 ++
src/libvirt_private.syms | 2 +
src/network/bridge_driver.c | 33 +++++--
5 files changed, 222 insertions(+), 42 deletions(-)
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index b1b542b..aa0dccb 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -1607,6 +1607,9 @@ int main(int argc, char **argv) {
0, "shutdown", NULL);
cleanup:
+ /* Notify drivers we are about to quit,
+ * so they can save their stuff */
+ virStateCleanup();
virNetServerProgramFree(remoteProgram);
virNetServerProgramFree(qemuProgram);
virNetServerClose(srv);
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 019cdc7..9073b08 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1282,6 +1282,99 @@ cleanup:
}
static int
+virNetworkObjParseXML(virNetworkObjPtr obj,
+ xmlDocPtr xml ATTRIBUTE_UNUSED,
+ xmlXPathContextPtr ctxt)
+{
+ int ret = -1;
+ xmlNodePtr config;
+ char *class_id = NULL;
+
+ if ((config = virXPathNode("./network", ctxt))) {
+ xmlNodePtr oldnode;
+ virNetworkDefPtr tmp_def;
+
+ oldnode = ctxt->node;
+ ctxt->node = config;
+ tmp_def = virNetworkDefParseXML(ctxt);
+ ctxt->node = oldnode;
+
+ if (tmp_def) {
+ obj->newDef = obj->def;
+ obj->def = tmp_def;
+ } else {
+ goto cleanup;
+ }
+ }
+
+ if ((class_id=virXPathString("string(./class_id[1]/@next)", ctxt))) {
+ if (virStrToLong_ui(class_id, NULL, 10, &obj->class_id) < 0) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("Malformed class_id attribute: %s"),
+ class_id);
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(class_id);
+ return ret;
+}
+
+static int
+virNetworkObjParseNode(virNetworkObjPtr obj,
+ xmlDocPtr xml,
+ xmlNodePtr root)
+{
+ int ret = -1;
+ xmlXPathContextPtr ctxt = NULL;
+
+ if (!xmlStrEqual(root->name, BAD_CAST "networkstatus")) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("unexpected root element <%s>, "
+ "expecting <networkstatus>"),
+ root->name);
+ return -1;
+ }
+
+ if (!(ctxt = xmlXPathNewContext(xml))) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ ret = virNetworkObjParseXML(obj, xml, ctxt);
+
+cleanup:
+ xmlXPathFreeContext(ctxt);
+ return ret;
+}
+
+static int
+virNetworkObjParseFile(virNetworkObjPtr obj,
+ const char *filename)
+{
+ int ret = -1;
+ xmlDocPtr xml;
+
+ if ((xml = virXMLParseFile(filename))) {
+ ret = virNetworkObjParseNode(obj, xml, xmlDocGetRootElement(xml));
+ xmlFreeDoc(xml);
+ }
+
+ return ret;
+}
+
+int
+virNetworkObjUpdateStatus(virNetworkObjPtr net,
+ const char *filename)
+{
+ return virNetworkObjParseFile(net, filename);
+}
+
+static int
virNetworkDNSDefFormat(virBufferPtr buf,
virNetworkDNSDefPtr def)
{
@@ -1449,19 +1542,21 @@ virPortGroupDefFormat(virBufferPtr buf,
return 0;
}
-char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags)
+static int
+virNetworkDefFormatInternal(virBufferPtr buf,
+ const virNetworkDefPtr def,
+ unsigned int flags)
{
- virBuffer buf = VIR_BUFFER_INITIALIZER;
unsigned char *uuid;
char uuidstr[VIR_UUID_STRING_BUFLEN];
int ii;
- virBufferAddLit(&buf, "<network>\n");
- virBufferEscapeString(&buf, " <name>%s</name>\n",
def->name);
+ virBufferAddLit(buf, "<network>\n");
+ virBufferEscapeString(buf, " <name>%s</name>\n",
def->name);
uuid = def->uuid;
virUUIDFormat(uuid, uuidstr);
- virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", uuidstr);
+ virBufferAsprintf(buf, " <uuid>%s</uuid>\n", uuidstr);
if (def->forwardType != VIR_NETWORK_FORWARD_NONE) {
const char *dev = NULL;
@@ -1475,86 +1570,97 @@ char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int
flags)
def->forwardType, def->name);
goto error;
}
- virBufferAddLit(&buf, " <forward");
- virBufferEscapeString(&buf, " dev='%s'", dev);
- virBufferAsprintf(&buf, " mode='%s'%s>\n", mode,
+ virBufferAddLit(buf, " <forward");
+ virBufferEscapeString(buf, " dev='%s'", dev);
+ virBufferAsprintf(buf, " mode='%s'%s>\n", mode,
(def->nForwardIfs || def->nForwardPfs) ? "" :
"/");
/* For now, hard-coded to at most 1 forwardPfs */
if (def->nForwardPfs)
- virBufferEscapeString(&buf, " <pf
dev='%s'/>\n",
+ virBufferEscapeString(buf, " <pf dev='%s'/>\n",
def->forwardPfs[0].dev);
if (def->nForwardIfs &&
(!def->nForwardPfs || !(flags & VIR_NETWORK_XML_INACTIVE))) {
for (ii = 0; ii < def->nForwardIfs; ii++) {
- virBufferEscapeString(&buf, " <interface
dev='%s'/>\n",
+ virBufferEscapeString(buf, " <interface
dev='%s'/>\n",
def->forwardIfs[ii].dev);
}
}
if (def->nForwardPfs || def->nForwardIfs)
- virBufferAddLit(&buf, " </forward>\n");
+ virBufferAddLit(buf, " </forward>\n");
}
if (def->forwardType == VIR_NETWORK_FORWARD_NONE ||
def->forwardType == VIR_NETWORK_FORWARD_NAT ||
def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
- virBufferAddLit(&buf, " <bridge");
+ virBufferAddLit(buf, " <bridge");
if (def->bridge)
- virBufferEscapeString(&buf, " name='%s'",
def->bridge);
- virBufferAsprintf(&buf, " stp='%s' delay='%ld'
/>\n",
+ virBufferEscapeString(buf, " name='%s'", def->bridge);
+ virBufferAsprintf(buf, " stp='%s' delay='%ld'
/>\n",
def->stp ? "on" : "off",
def->delay);
} else if (def->forwardType == VIR_NETWORK_FORWARD_BRIDGE &&
def->bridge) {
- virBufferEscapeString(&buf, " <bridge name='%s'
/>\n", def->bridge);
+ virBufferEscapeString(buf, " <bridge name='%s' />\n",
def->bridge);
}
if (def->mac_specified) {
char macaddr[VIR_MAC_STRING_BUFLEN];
virFormatMacAddr(def->mac, macaddr);
- virBufferAsprintf(&buf, " <mac address='%s'/>\n",
macaddr);
+ virBufferAsprintf(buf, " <mac address='%s'/>\n",
macaddr);
}
if (def->domain)
- virBufferAsprintf(&buf, " <domain name='%s'/>\n",
def->domain);
+ virBufferAsprintf(buf, " <domain name='%s'/>\n",
def->domain);
- if (virNetworkDNSDefFormat(&buf, def->dns) < 0)
+ if (virNetworkDNSDefFormat(buf, def->dns) < 0)
goto error;
- virBufferAdjustIndent(&buf, 2);
- if (virNetDevBandwidthFormat(def->bandwidth, &buf) < 0)
+ virBufferAdjustIndent(buf, 2);
+ if (virNetDevBandwidthFormat(def->bandwidth, buf) < 0)
goto error;
- virBufferAdjustIndent(&buf, -2);
+ virBufferAdjustIndent(buf, -2);
for (ii = 0; ii < def->nips; ii++) {
- if (virNetworkIpDefFormat(&buf, &def->ips[ii]) < 0)
+ if (virNetworkIpDefFormat(buf, &def->ips[ii]) < 0)
goto error;
}
- virBufferAdjustIndent(&buf, 2);
- if (virNetDevVPortProfileFormat(def->virtPortProfile, &buf) < 0)
+ virBufferAdjustIndent(buf, 2);
+ if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
goto error;
- virBufferAdjustIndent(&buf, -2);
+ virBufferAdjustIndent(buf, -2);
for (ii = 0; ii < def->nPortGroups; ii++)
- if (virPortGroupDefFormat(&buf, &def->portGroups[ii]) < 0)
+ if (virPortGroupDefFormat(buf, &def->portGroups[ii]) < 0)
goto error;
- virBufferAddLit(&buf, "</network>\n");
+ virBufferAddLit(buf, "</network>\n");
- if (virBufferError(&buf))
+ if (virBufferError(buf))
goto no_memory;
- return virBufferContentAndReset(&buf);
+ return 0;
- no_memory:
+no_memory:
virReportOOMError();
- error:
- virBufferFreeAndReset(&buf);
- return NULL;
+error:
+ return -1;
+}
+
+char *virNetworkDefFormat(const virNetworkDefPtr def, unsigned int flags)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (virNetworkDefFormatInternal(&buf, def, flags) < 0) {
+ virBufferFreeAndReset(&buf);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
}
virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net,
@@ -1573,6 +1679,34 @@ virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net,
return NULL;
}
+static char *
+virNetworkObjFormat(virNetworkObjPtr obj)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAddLit(&buf, "<networkstatus>\n");
+ if (obj->class_id)
+ virBufferAsprintf(&buf, " <class_id next='%u'/>\n",
obj->class_id);
+
+ virBufferAdjustIndent(&buf, 2);
+ if (virNetworkDefFormatInternal(&buf, obj->def, 0) < 0)
+ goto error;
+ virBufferAdjustIndent(&buf, -2);
+
+ virBufferAddLit(&buf, "</networkstatus>\n");
+
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ return virBufferContentAndReset(&buf);
+
+no_memory:
+ virReportOOMError();
+error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
int virNetworkSaveXML(const char *configDir,
virNetworkDefPtr def,
const char *xml)
@@ -1597,6 +1731,24 @@ int virNetworkSaveXML(const char *configDir,
return ret;
}
+int virNetworkSaveObj(const char *configDir,
+ virNetworkObjPtr net)
+{
+ int ret = -1;
+ char *xml;
+
+ if (!(xml = virNetworkObjFormat(net)))
+ goto cleanup;
+
+ if (virNetworkSaveXML(configDir, net->def, xml))
+ goto cleanup;
+
+ ret = 0;
+cleanup:
+ VIR_FREE(xml);
+ return ret;
+}
+
int virNetworkSaveConfig(const char *configDir,
virNetworkDefPtr def)
{
@@ -1615,7 +1767,6 @@ cleanup:
return ret;
}
-
virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
const char *configDir,
const char *autostartDir,
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index dcbf84d..1161acf 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -255,11 +255,18 @@ int virNetworkSaveXML(const char *configDir,
int virNetworkSaveConfig(const char *configDir,
virNetworkDefPtr def);
+int virNetworkSaveObj(const char *configDir,
+ virNetworkObjPtr net);
+
virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
const char *configDir,
const char *autostartDir,
const char *file);
+int virNetworkObjUpdateStatus(virNetworkObjPtr net,
+ const char *filename)
+ ATTRIBUTE_NONNULL(1);
+
int virNetworkLoadAllConfigs(virNetworkObjListPtr nets,
const char *configDir,
const char *autostartDir);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ca4beb1..bd74050 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -759,8 +759,10 @@ virNetworkObjIsDuplicate;
virNetworkObjListFree;
virNetworkObjLock;
virNetworkObjUnlock;
+virNetworkObjUpdateStatus;
virNetworkRemoveInactive;
virNetworkSaveConfig;
+virNetworkSaveObj;
virNetworkSetBridgeMacAddr;
virNetworkSetBridgeName;
virPortGroupFindByName;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 4cea7c2..2f3da60 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -184,7 +184,6 @@ networkFindActiveConfigs(struct network_driver *driver) {
for (i = 0 ; i < driver->networks.count ; i++) {
virNetworkObjPtr obj = driver->networks.objs[i];
- virNetworkDefPtr tmp;
char *config;
virNetworkObjLock(obj);
@@ -201,13 +200,12 @@ networkFindActiveConfigs(struct network_driver *driver) {
continue;
}
- /* Try and load the live config */
- tmp = virNetworkDefParseFile(config);
- VIR_FREE(config);
- if (tmp) {
- obj->newDef = obj->def;
- obj->def = tmp;
+ /* Try to update the live config */
+ if (virNetworkObjUpdateStatus(obj, config) < 0) {
+ VIR_WARN("Unable to update config on '%s' network",
+ obj->def->name);
}
+ VIR_FREE(config);
/* If bridge exists, then mark it active */
if (obj->def->bridge &&
@@ -396,11 +394,25 @@ networkActive(void) {
*/
static int
networkShutdown(void) {
+ unsigned int i;
+
if (!driverState)
return -1;
networkDriverLock(driverState);
+ for (i = 0; i < driverState->networks.count; i++) {
+ virNetworkObjPtr obj = driverState->networks.objs[i];
+
+ if (!virNetworkObjIsActive(obj))
+ continue;
+
+ if (virNetworkSaveObj(NETWORK_STATE_DIR, obj) < 0) {
+ VIR_WARN("Unable to save network '%s'",
+ obj->def->name);
+ }
+ }
+
/* free inactive networks */
virNetworkObjListFree(&driverState->networks);
@@ -1990,7 +2002,7 @@ networkStartNetwork(struct network_driver *driver,
/* Persist the live configuration now that anything autogenerated
* is setup.
*/
- if ((ret = virNetworkSaveConfig(NETWORK_STATE_DIR, network->def)) < 0) {
+ if ((ret = virNetworkSaveObj(NETWORK_STATE_DIR, network)) < 0) {
goto error;
}
@@ -3299,6 +3311,11 @@ networkNotifyPlug(virNetworkPtr net,
network->class_id++;
}
+ if (virNetworkSaveObj(NETWORK_STATE_DIR, network) < 0) {
+ VIR_WARN("Unable to save network '%s'",
+ network->def->name);
+ }
+
ret = 0;
cleanup:
--
1.7.3.4