We currently have two drivers which handle the networking XML containing
duplicated parsers and formatters for the XML, and very similar structs.
This patch introduces a new general purpose internal API for parsing and
formatting network XML, and representing it as a series of structs.
This code is derived from the current equivalent code in the QEMU driver
for networks.
The naming conventions I'm adopting in this patch follow those in the
storage driver:
- virNetworkPtr - the public opaque object in libvirt.h
- virNetworkObjPtr - the primary internal object for network state
- virNetworkDefPtr - the configuration data for a network
A virNetworkObjPtr contains a reference to one or two virNetworkDefPtr
objects - the current live config, and potentially a secondary inactive
config which will become live at the next restart.
The structs are defined in network_conf.h, along with a bunch of APIs for
dealing with them. These APIs are the same as similarly named ones from
the current qemu driver, but I'll go over them again for a reminder:
virNetworkObjPtr virNetworkFindByUUID(const virNetworkObjPtr nets,
const unsigned char *uuid);
virNetworkObjPtr virNetworkFindByName(const virNetworkObjPtr nets,
const char *name);
Allow lookup of a virNetworkObjPtr object based on its name or UUID, as
typically obtained from the public virNetworkPtr object.
The 'nets' parameter to both of thse is a linked list of networks which
are currently known to the driver using this API.
void virNetworkDefFree(virNetworkDefPtr def);
void virNetworkObjFree(virNetworkObjPtr net);
Convenience APIs to totally free the memory associated with these
objects.
virNetworkObjPtr virNetworkAssignDef(virConnectPtr conn,
virNetworkObjPtr *nets,
const virNetworkDefPtr def);
Given a virNetworkDefPtr object, it'll search for a pre-existing
virNetworkObjPtr object with matching config. If one is found, its
config will be updated, otherwise a new object will be allocated.
void virNetworkRemoveInactive(virNetworkObjPtr *nets,
const virNetworkObjPtr net);
Convenience for removing and free'ing a virNetworkObjPtr object in
the current list of active networks.
virNetworkDefPtr virNetworkDefParseString(virConnectPtr conn,
const char *xmlStr);
virNetworkDefPtr virNetworkDefParseFile(virConnectPtr conn,
const char *filename);
virNetworkDefPtr virNetworkDefParseNode(virConnectPtr conn,
xmlDocPtr xml,
xmlNodePtr root);
Based on DV's suggestion the parsing methods have changed slightly
so instead of only allowing a string to be parsed, we can directly
parse a file, or a XML node object.
char *virNetworkDefFormat(virConnectPtr conn,
const virNetworkDefPtr def);
Given a virNetworkDefPtr object, generate a XML document describing the
network.
For drivers which no other persistent storage native to their
virt type, there are helper methods for loading and saving the
XML configs to files. This is primarily for QEMU and LXC drivers
int virNetworkSaveConfig(virConnectPtr conn,
const char *configDir,
const char *autostartDir,
virNetworkObjPtr net);
virNetworkObjPtr virNetworkLoadConfig(virConnectPtr conn,
virNetworkObjPtr *nets,
const char *configDir,
const char *autostartDir,
const char *file);
int virNetworkLoadAllConfigs(virConnectPtr conn,
virNetworkObjPtr *nets,
const char *configDir,
const char *autostartDir);
int virNetworkDeleteConfig(virConnectPtr conn,
virNetworkObjPtr net);
As a mentioned earlier, the impl of these APIs is just copied from the QEMU
driver, but instead of using pre-declared char[PATH_MAX] fields, we allocate
memory for strings as required.
Other misc changes from last time - we introduce a VIR_FROM_NETWORK class
for reporting errors against
b/src/network_conf.c | 688 ++++++++++++++++++++++++++++++++++++++++++++
b/src/network_conf.h | 137 ++++++++
include/libvirt/virterror.h | 1
po/POTFILES.in | 1
src/Makefile.am | 1
src/virterror.c | 3
src/xml.c | 52 +++
src/xml.h | 3
8 files changed, 886 insertions(+)
Daniel
diff -r 097ed9d9ae46 include/libvirt/virterror.h
--- a/include/libvirt/virterror.h Mon Jul 07 12:06:49 2008 +0100
+++ b/include/libvirt/virterror.h Tue Jul 08 15:26:26 2008 +0100
@@ -56,6 +56,7 @@
VIR_FROM_STATS_LINUX, /* Error in the Linux Stats code */
VIR_FROM_LXC, /* Error from Linux Container driver */
VIR_FROM_STORAGE, /* Error from storage driver */
+ VIR_FROM_NETWORK, /* Error from network config */
} virErrorDomain;
diff -r 097ed9d9ae46 po/POTFILES.in
--- a/po/POTFILES.in Mon Jul 07 12:06:49 2008 +0100
+++ b/po/POTFILES.in Tue Jul 08 15:26:26 2008 +0100
@@ -9,6 +9,7 @@
src/lxc_conf.c
src/lxc_container.c
src/lxc_driver.c
+src/network_conf.c
src/openvz_conf.c
src/openvz_driver.c
src/proxy_internal.c
diff -r 097ed9d9ae46 src/Makefile.am
--- a/src/Makefile.am Mon Jul 07 12:06:49 2008 +0100
+++ b/src/Makefile.am Tue Jul 08 15:26:26 2008 +0100
@@ -52,6 +52,7 @@
driver.h \
proxy_internal.c proxy_internal.h \
conf.c conf.h \
+ network_conf.c network_conf.h \
xm_internal.c xm_internal.h \
remote_internal.c remote_internal.h \
bridge.c bridge.h \
diff -r 097ed9d9ae46 src/network_conf.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/network_conf.c Tue Jul 08 15:26:26 2008 +0100
@@ -0,0 +1,688 @@
+/*
+ * network_conf.c: network XML handling
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+
+
+#include <config.h>
+
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include "internal.h"
+
+#include "network_conf.h"
+#include "memory.h"
+#include "xml.h"
+#include "uuid.h"
+#include "util.h"
+#include "buf.h"
+
+VIR_ENUM_DECL(virNetworkForward)
+
+VIR_ENUM_IMPL(virNetworkForward,
+ VIR_NETWORK_FORWARD_LAST,
+ "none", "nat", "route" )
+
+static void virNetworkReportError(virConnectPtr conn,
+ int code, const char *fmt, ...)
+{
+ va_list args;
+ char errorMessage[1024];
+ const char *virerr;
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args);
+ va_end(args);
+ } else {
+ errorMessage[0] = '\0';
+ }
+
+ virerr = __virErrorMsg(code, (errorMessage[0] ? errorMessage : NULL));
+ __virRaiseError(conn, NULL, NULL, VIR_FROM_NETWORK, code, VIR_ERR_ERROR,
+ virerr, errorMessage, NULL, -1, -1, virerr, errorMessage);
+}
+
+
+virNetworkObjPtr virNetworkFindByUUID(const virNetworkObjPtr nets,
+ const unsigned char *uuid)
+{
+ virNetworkObjPtr net = nets;
+ while (net) {
+ if (!memcmp(net->def->uuid, uuid, VIR_UUID_BUFLEN))
+ return net;
+ net = net->next;
+ }
+
+ return NULL;
+}
+
+virNetworkObjPtr virNetworkFindByName(const virNetworkObjPtr nets,
+ const char *name)
+{
+ virNetworkObjPtr net = nets;
+ while (net) {
+ if (STREQ(net->def->name, name))
+ return net;
+ net = net->next;
+ }
+
+ return NULL;
+}
+
+
+void virNetworkDefFree(virNetworkDefPtr def)
+{
+ int i;
+
+ if (!def)
+ return;
+
+ VIR_FREE(def->name);
+ VIR_FREE(def->bridge);
+ VIR_FREE(def->forwardDev);
+ VIR_FREE(def->ipAddress);
+ VIR_FREE(def->network);
+ VIR_FREE(def->netmask);
+
+ for (i = 0 ; i < def->nranges && def->ranges ; i++) {
+ VIR_FREE(def->ranges[i].start);
+ VIR_FREE(def->ranges[i].end);
+ }
+ VIR_FREE(def->ranges);
+
+ VIR_FREE(def);
+}
+
+void virNetworkObjFree(virNetworkObjPtr net)
+{
+ if (!net)
+ return;
+
+ virNetworkDefFree(net->def);
+ virNetworkDefFree(net->newDef);
+
+ VIR_FREE(net->configFile);
+ VIR_FREE(net->autostartLink);
+
+ VIR_FREE(net);
+}
+
+virNetworkObjPtr virNetworkAssignDef(virConnectPtr conn,
+ virNetworkObjPtr *nets,
+ const virNetworkDefPtr def)
+{
+ virNetworkObjPtr network;
+
+ if ((network = virNetworkFindByName(*nets, def->name))) {
+ if (!virNetworkIsActive(network)) {
+ virNetworkDefFree(network->def);
+ network->def = def;
+ } else {
+ if (network->newDef)
+ virNetworkDefFree(network->newDef);
+ network->newDef = def;
+ }
+
+ return network;
+ }
+
+ if (VIR_ALLOC(network) < 0) {
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ network->def = def;
+ network->next = *nets;
+
+ *nets = network;
+
+ return network;
+
+}
+
+void virNetworkRemoveInactive(virNetworkObjPtr *nets,
+ const virNetworkObjPtr net)
+{
+ virNetworkObjPtr prev = NULL;
+ virNetworkObjPtr curr = *nets;
+
+ while (curr &&
+ curr != net) {
+ prev = curr;
+ curr = curr->next;
+ }
+
+ if (curr) {
+ if (prev)
+ prev->next = curr->next;
+ else
+ *nets = curr->next;
+ }
+
+ virNetworkObjFree(net);
+}
+
+
+static int
+virNetworkDHCPRangeDefParseXML(virConnectPtr conn,
+ virNetworkDefPtr def,
+ xmlNodePtr node) {
+
+ xmlNodePtr cur;
+
+ cur = node->children;
+ while (cur != NULL) {
+ xmlChar *start, *end;
+
+ if (cur->type != XML_ELEMENT_NODE ||
+ !xmlStrEqual(cur->name, BAD_CAST "range")) {
+ cur = cur->next;
+ continue;
+ }
+
+ if (!(start = xmlGetProp(cur, BAD_CAST "start"))) {
+ cur = cur->next;
+ continue;
+ }
+ if (!(end = xmlGetProp(cur, BAD_CAST "end"))) {
+ cur = cur->next;
+ xmlFree(start);
+ continue;
+ }
+
+ if (VIR_REALLOC_N(def->ranges, def->nranges + 1) < 0) {
+ xmlFree(start);
+ xmlFree(end);
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return -1;
+ }
+ def->ranges[def->nranges].start = (char *)start;
+ def->ranges[def->nranges].end = (char *)end;
+ def->nranges++;
+
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+static virNetworkDefPtr
+virNetworkDefParseXML(virConnectPtr conn,
+ xmlXPathContextPtr ctxt)
+{
+ virNetworkDefPtr def;
+ char *tmp;
+
+ if (VIR_ALLOC(def) < 0) {
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ /* Extract network name */
+ def->name = virXPathString("string(./name[1])", ctxt);
+ if (!def->name) {
+ virNetworkReportError(conn, VIR_ERR_NO_NAME, NULL);
+ goto error;
+ }
+
+ /* Extract network uuid */
+ tmp = virXPathString("string(./uuid[1])", ctxt);
+ if (!tmp) {
+ int err;
+ if ((err = virUUIDGenerate(def->uuid))) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Failed to generate UUID: %s"), strerror(err));
+ goto error;
+ }
+ } else {
+ if (virUUIDParse(tmp, def->uuid) < 0) {
+ VIR_FREE(tmp);
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed uuid
element"));
+ goto error;
+ }
+ VIR_FREE(tmp);
+ }
+
+ /* Parse bridge information */
+ def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt);
+ tmp = virXPathString("string(./bridge[1]/@stp)", ctxt);
+ def->stp = (tmp && STREQ(tmp, "off")) ? 0 : 1;
+ VIR_FREE(tmp);
+
+ if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay)
< 0)
+ def->delay = 0;
+
+ def->ipAddress = virXPathString("string(./ip[1]/@address)", ctxt);
+ def->netmask = virXPathString("string(./ip[1]/@netmask)", ctxt);
+ if (def->ipAddress &&
+ def->netmask) {
+ /* XXX someday we want IPv6 too, so inet_aton won't work there */
+ struct in_addr inaddress, innetmask;
+ char *netaddr;
+ xmlNodePtr dhcp;
+
+ if (!inet_aton(def->ipAddress, &inaddress)) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse IP address '%s'"),
+ def->ipAddress);
+ goto error;
+ }
+ if (!inet_aton(def->netmask, &innetmask)) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse netmask '%s'"),
+ def->netmask);
+ goto error;
+ }
+
+ inaddress.s_addr &= innetmask.s_addr;
+ netaddr = inet_ntoa(inaddress);
+
+ if (asprintf(&def->network, "%s/%s", netaddr, def->netmask)
< 0) {
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+
+ if ((dhcp = virXPathNode("./ip[1]/dhcp[1]", ctxt)) &&
+ virNetworkDHCPRangeDefParseXML(conn, def, dhcp) < 0)
+ goto error;
+ }
+
+
+ /* IPv4 forwarding setup */
+ if (virXPathBoolean("count(./forward) > 0", ctxt)) {
+ if (!def->ipAddress ||
+ !def->netmask) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Forwarding requested, but no
IPv4 address/netmask provided"));
+ goto error;
+ }
+
+ tmp = virXPathString("string(./forward[1]/@mode)", ctxt);
+ if (tmp) {
+ if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown forwarding type
'%s'"), tmp);
+ VIR_FREE(tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+ } else {
+ def->forwardType = VIR_NETWORK_FORWARD_NAT;
+ }
+
+
+ def->forwardDev = virXPathString("string(./forward[1]/@dev)",
ctxt);
+ } else {
+ def->forwardType = VIR_NETWORK_FORWARD_NONE;
+ }
+
+ return def;
+
+ error:
+ virNetworkDefFree(def);
+ return NULL;
+}
+
+virNetworkDefPtr virNetworkDefParseString(virConnectPtr conn,
+ const char *xmlStr)
+{
+ xmlDocPtr xml;
+ xmlNodePtr root;
+ virNetworkDefPtr def;
+
+ if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "network.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ virNetworkReportError(conn, VIR_ERR_XML_ERROR, NULL);
+ return NULL;
+ }
+
+ if ((root = xmlDocGetRootElement(xml)) == NULL) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing root element"));
+ xmlFreeDoc(xml);
+ return NULL;
+ }
+
+ def = virNetworkDefParseNode(conn, xml, root);
+
+ xmlFreeDoc(xml);
+ return def;
+}
+
+virNetworkDefPtr virNetworkDefParseFile(virConnectPtr conn,
+ const char *filename)
+{
+ xmlDocPtr xml;
+ xmlNodePtr root;
+ virNetworkDefPtr def;
+
+ if (!(xml = xmlReadFile(filename, NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ virNetworkReportError(conn, VIR_ERR_XML_ERROR, NULL);
+ return NULL;
+ }
+
+ if ((root = xmlDocGetRootElement(xml)) == NULL) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing root element"));
+ xmlFreeDoc(xml);
+ return NULL;
+ }
+
+ def = virNetworkDefParseNode(conn, xml, root);
+
+ xmlFreeDoc(xml);
+ return def;
+}
+
+
+virNetworkDefPtr virNetworkDefParseNode(virConnectPtr conn,
+ xmlDocPtr xml,
+ xmlNodePtr root)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ virNetworkDefPtr def = NULL;
+
+ if (!xmlStrEqual(root->name, BAD_CAST "network")) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("incorrect root element"));
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ def = virNetworkDefParseXML(conn, ctxt);
+
+cleanup:
+ xmlXPathFreeContext(ctxt);
+ return def;
+}
+
+char *virNetworkDefFormat(virConnectPtr conn,
+ const virNetworkDefPtr def)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ unsigned char *uuid;
+ char *tmp;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+
+ virBufferAddLit(&buf, "<network>\n");
+ virBufferEscapeString(&buf, " <name>%s</name>\n",
def->name);
+
+ uuid = def->uuid;
+ virUUIDFormat(uuid, uuidstr);
+ virBufferVSprintf(&buf, " <uuid>%s</uuid>\n", uuidstr);
+
+ if (def->forwardType != VIR_NETWORK_FORWARD_NONE) {
+ const char *mode = virNetworkForwardTypeToString(def->forwardType);
+ if (mode) {
+ if (def->forwardDev) {
+ virBufferEscapeString(&buf, " <forward
dev='%s'",
+ def->forwardDev);
+ } else {
+ virBufferAddLit(&buf, " <forward");
+ }
+ virBufferVSprintf(&buf, " mode='%s'/>\n", mode);
+ }
+ }
+
+ virBufferAddLit(&buf, " <bridge");
+ if (def->bridge)
+ virBufferEscapeString(&buf, " name='%s'", def->bridge);
+ virBufferVSprintf(&buf, " stp='%s' forwardDelay='%ld'
/>\n",
+ def->stp ? "on" : "off",
+ def->delay);
+
+ if (def->ipAddress || def->netmask) {
+ virBufferAddLit(&buf, " <ip");
+
+ if (def->ipAddress)
+ virBufferVSprintf(&buf, " address='%s'",
def->ipAddress);
+
+ if (def->netmask)
+ virBufferVSprintf(&buf, " netmask='%s'",
def->netmask);
+
+ virBufferAddLit(&buf, ">\n");
+
+ if (def->nranges) {
+ int i;
+ virBufferAddLit(&buf, " <dhcp>\n");
+ for (i = 0 ; i < def->nranges ; i++)
+ virBufferVSprintf(&buf, " <range start='%s'
end='%s' />\n",
+ def->ranges[i].start, def->ranges[i].end);
+ virBufferAddLit(&buf, " </dhcp>\n");
+ }
+
+ virBufferAddLit(&buf, " </ip>\n");
+ }
+
+ virBufferAddLit(&buf, "</network>\n");
+
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ return virBufferContentAndReset(&buf);
+
+ no_memory:
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ tmp = virBufferContentAndReset(&buf);
+ VIR_FREE(tmp);
+ return NULL;
+}
+
+int virNetworkSaveConfig(virConnectPtr conn,
+ const char *configDir,
+ const char *autostartDir,
+ virNetworkObjPtr net)
+{
+ char *xml;
+ int fd = -1, ret = -1;
+ int towrite;
+ int err;
+
+ if (!net->configFile &&
+ asprintf(&net->configFile, "%s/%s.xml",
+ configDir, net->def->name) < 0) {
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto cleanup;
+ }
+ if (!net->autostartLink &&
+ asprintf(&net->autostartLink, "%s/%s.xml",
+ autostartDir, net->def->name) < 0) {
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto cleanup;
+ }
+
+ if (!(xml = virNetworkDefFormat(conn,
+ net->newDef ? net->newDef : net->def)))
+ return -1;
+
+ if ((err = virFileMakePath(configDir))) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create config directory %s: %s"),
+ configDir, strerror(err));
+ goto cleanup;
+ }
+
+ if ((err = virFileMakePath(autostartDir))) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create autostart directory %s: %s"),
+ autostartDir, strerror(err));
+ goto cleanup;
+ }
+
+ if ((fd = open(net->configFile,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR )) < 0) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create config file %s: %s"),
+ net->configFile, strerror(errno));
+ goto cleanup;
+ }
+
+ towrite = strlen(xml);
+ if (safewrite(fd, xml, towrite) < 0) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot write config file %s: %s"),
+ net->configFile, strerror(errno));
+ goto cleanup;
+ }
+
+ if (close(fd) < 0) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot save config file %s: %s"),
+ net->configFile, strerror(errno));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FREE(xml);
+ close(fd);
+
+ return ret;
+}
+
+virNetworkObjPtr virNetworkLoadConfig(virConnectPtr conn,
+ virNetworkObjPtr *nets,
+ const char *configDir,
+ const char *autostartDir,
+ const char *file)
+{
+ char *configFile, *autostartLink;
+ virNetworkDefPtr def = NULL;
+ virNetworkObjPtr net;
+ int autostart;
+
+ if (asprintf(&configFile, "%s/%s",
+ configDir, file) < 0) {
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ if (asprintf(&autostartLink, "%s/%s",
+ autostartDir, file) < 0) {
+ virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+
+ if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
+ goto error;
+
+ if (!(def = virNetworkDefParseFile(conn, file)))
+ goto error;
+
+ if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Network config filename '%s'"
+ " does not match network name '%s'"),
+ configFile, def->name);
+ goto error;
+ }
+
+ if (!(net = virNetworkAssignDef(conn, nets, def)))
+ goto error;
+
+ net->configFile = configFile;
+ net->autostartLink = autostartLink;
+ net->autostart = autostart;
+
+ return net;
+
+error:
+ VIR_FREE(configFile);
+ VIR_FREE(autostartLink);
+ virNetworkDefFree(def);
+ return NULL;
+}
+
+int virNetworkLoadAllConfigs(virConnectPtr conn,
+ virNetworkObjPtr *nets,
+ const char *configDir,
+ const char *autostartDir)
+{
+ DIR *dir;
+ struct dirent *entry;
+
+ if (!(dir = opendir(configDir))) {
+ if (errno == ENOENT)
+ return 0;
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Failed to open dir '%s': %s"),
+ configDir, strerror(errno));
+ return -1;
+ }
+
+ while ((entry = readdir(dir))) {
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (!virFileHasSuffix(entry->d_name, ".xml"))
+ continue;
+
+ /* NB: ignoring errors, so one malformed config doesn't
+ kill the whole process */
+ virNetworkLoadConfig(conn,
+ nets,
+ configDir,
+ autostartDir,
+ entry->d_name);
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+int virNetworkDeleteConfig(virConnectPtr conn,
+ virNetworkObjPtr net)
+{
+ if (!net->configFile || !net->autostartLink) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("no config file for %s"),
net->def->name);
+ return -1;
+ }
+
+ /* Not fatal if this doesn't work */
+ unlink(net->autostartLink);
+
+ if (unlink(net->configFile) < 0) {
+ virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot remove config for %s"),
net->def->name);
+ return -1;
+ }
+
+ return 0;
+}
diff -r 097ed9d9ae46 src/network_conf.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/network_conf.h Tue Jul 08 15:26:26 2008 +0100
@@ -0,0 +1,137 @@
+/*
+ * network_conf.h: network XML handling
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#ifndef __NETWORK_CONF_H__
+#define __NETWORK_CONF_H__
+
+#include "internal.h"
+
+/* 2 possible types of forwarding */
+enum virNetworkForwardType {
+ VIR_NETWORK_FORWARD_NONE = 0,
+ VIR_NETWORK_FORWARD_NAT,
+ VIR_NETWORK_FORWARD_ROUTE,
+
+ VIR_NETWORK_FORWARD_LAST,
+};
+
+typedef struct _virNetworkDHCPRangeDef virNetworkDHCPRangeDef;
+typedef virNetworkDHCPRangeDef *virNetworkDHCPRangeDefPtr;
+struct _virNetworkDHCPRangeDef {
+ char *start;
+ char *end;
+};
+
+typedef struct _virNetworkDef virNetworkDef;
+typedef virNetworkDef *virNetworkDefPtr;
+struct _virNetworkDef {
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ char *name;
+
+ char *bridge; /* Name of bridge device */
+ int stp : 1; /* Spanning tree protocol */
+ unsigned long delay; /* Bridge forward delay (ms) */
+
+ int forwardType; /* One of virNetworkForwardType constants */
+ char *forwardDev; /* Destination device for forwarding */
+
+ char *ipAddress; /* Bridge IP address */
+ char *netmask;
+ char *network;
+
+ unsigned int nranges; /* Zero or more dhcp ranges */
+ virNetworkDHCPRangeDefPtr ranges;
+};
+
+typedef struct _virNetworkObj virNetworkObj;
+typedef virNetworkObj *virNetworkObjPtr;
+struct _virNetworkObj {
+ pid_t dnsmasqPid;
+ unsigned int active : 1;
+ unsigned int autostart : 1;
+ unsigned int persistent : 1;
+
+ char *configFile; /* Persistent config file path */
+ char *autostartLink; /* Symlink path for autostart */
+
+ virNetworkDefPtr def; /* The current definition */
+ virNetworkDefPtr newDef; /* New definition to activate at shutdown */
+
+ virNetworkObjPtr next;
+};
+
+static inline int
+virNetworkIsActive(const virNetworkObjPtr net)
+{
+ return net->active;
+}
+
+
+virNetworkObjPtr virNetworkFindByUUID(const virNetworkObjPtr nets,
+ const unsigned char *uuid);
+virNetworkObjPtr virNetworkFindByName(const virNetworkObjPtr nets,
+ const char *name);
+
+
+void virNetworkDefFree(virNetworkDefPtr def);
+void virNetworkObjFree(virNetworkObjPtr net);
+
+virNetworkObjPtr virNetworkAssignDef(virConnectPtr conn,
+ virNetworkObjPtr *nets,
+ const virNetworkDefPtr def);
+void virNetworkRemoveInactive(virNetworkObjPtr *nets,
+ const virNetworkObjPtr net);
+
+virNetworkDefPtr virNetworkDefParseString(virConnectPtr conn,
+ const char *xmlStr);
+virNetworkDefPtr virNetworkDefParseFile(virConnectPtr conn,
+ const char *filename);
+virNetworkDefPtr virNetworkDefParseNode(virConnectPtr conn,
+ xmlDocPtr xml,
+ xmlNodePtr root);
+
+char *virNetworkDefFormat(virConnectPtr conn,
+ const virNetworkDefPtr def);
+
+
+int virNetworkSaveConfig(virConnectPtr conn,
+ const char *configDir,
+ const char *autostartDir,
+ virNetworkObjPtr net);
+
+virNetworkObjPtr virNetworkLoadConfig(virConnectPtr conn,
+ virNetworkObjPtr *nets,
+ const char *configDir,
+ const char *autostartDir,
+ const char *file);
+
+int virNetworkLoadAllConfigs(virConnectPtr conn,
+ virNetworkObjPtr *nets,
+ const char *configDir,
+ const char *autostartDir);
+
+int virNetworkDeleteConfig(virConnectPtr conn,
+ virNetworkObjPtr net);
+
+#endif /* __NETWORK_CONF_H__ */
+
diff -r 097ed9d9ae46 src/virterror.c
--- a/src/virterror.c Mon Jul 07 12:06:49 2008 +0100
+++ b/src/virterror.c Tue Jul 08 15:26:26 2008 +0100
@@ -303,6 +303,9 @@
break;
case VIR_FROM_STORAGE:
dom = "Storage ";
+ break;
+ case VIR_FROM_NETWORK:
+ dom = "Network Config ";
break;
}
diff -r 097ed9d9ae46 src/xml.c
--- a/src/xml.c Mon Jul 07 12:06:49 2008 +0100
+++ b/src/xml.c Tue Jul 08 15:26:26 2008 +0100
@@ -500,6 +500,58 @@
}
/**
+ * virXPathULong:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathULong(const char *xpath, xmlXPathContextPtr ctxt, unsigned long *value)
+{
+ xmlXPathObjectPtr obj;
+ xmlNodePtr relnode;
+ int ret = 0;
+
+ if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+ virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid parameter to virXPathNumber()"), 0);
+ return (-1);
+ }
+ relnode = ctxt->node;
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+ (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+ char *conv = NULL;
+ long val;
+
+ val = strtoul((const char *) obj->stringval, &conv, 10);
+ if (conv == (const char *) obj->stringval) {
+ ret = -2;
+ } else {
+ *value = val;
+ }
+ } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
+ (!(isnan(obj->floatval)))) {
+ *value = (unsigned long) obj->floatval;
+ if (*value != obj->floatval) {
+ ret = -2;
+ }
+ } else {
+ ret = -1;
+ }
+
+ xmlXPathFreeObject(obj);
+ ctxt->node = relnode;
+ return (ret);
+}
+
+/**
* virXPathBoolean:
* @xpath: the XPath string to evaluate
* @ctxt: an XPath context
diff -r 097ed9d9ae46 src/xml.h
--- a/src/xml.h Mon Jul 07 12:06:49 2008 +0100
+++ b/src/xml.h Tue Jul 08 15:26:26 2008 +0100
@@ -26,6 +26,9 @@
int virXPathLong (const char *xpath,
xmlXPathContextPtr ctxt,
long *value);
+int virXPathULong (const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long *value);
xmlNodePtr virXPathNode (const char *xpath,
xmlXPathContextPtr ctxt);
int virXPathNodeSet (const char *xpath,
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|