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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list