]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Generic APIs for network XML configuration
authorDaniel P. Berrange <berrange@redhat.com>
Fri, 11 Jul 2008 10:48:34 +0000 (10:48 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 11 Jul 2008 10:48:34 +0000 (10:48 +0000)
ChangeLog
include/libvirt/virterror.h
po/POTFILES.in
src/Makefile.am
src/network_conf.c [new file with mode: 0644]
src/network_conf.h [new file with mode: 0644]
src/virterror.c
src/xml.c
src/xml.h

index c7199615faef5d33d585dd06a62a64a218133f18..a7ce09f283203e87ea41c26a9f7252bc6e5f3d06 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+Fri Jul 11 11:35:59 BST 2008 Daniel P. Berrange <berrange@redhat.com>
+
+       Generic APIs for network XML configuration
+       * include/libvirt/virterror.h, src/virterror.c: Added new
+       scope VIR_FROM_NETWORK
+       * src/Makefile.am, po/POTFILES.in: Added network_conf.{c,h}
+       * src/xml.c, src/xml.h: Added virXPathULong function
+       * src/network_conf.c, src/network_conf.h: Added generic
+       APIs for network XML configuration
+
 Fri Jul 11 10:55:59 BST 2008 Daniel P. Berrange <berrange@redhat.com>
 
        * src/qemu_conf.c: Fix booting off CDROM devices
index c575f9d048b26f42d9e4e0527c0f750e27a1dcd5..72878aedc2215c403cfa0ba59e7da346d48188d8 100644 (file)
@@ -56,6 +56,7 @@ typedef enum {
     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;
 
 
index f5adbbaf3f641d8059996f75684f4c2127a55d8a..c5e48d9bf173d1b6a3313d72e1bf6a8d6904f16f 100644 (file)
@@ -9,6 +9,7 @@ src/libvirt.c
 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
index a0957e2ef295dd9234cb4d2e937c10ae52ddd189..9e8d9c84323febf53da3f1821ea04ad50cb66199 100644 (file)
@@ -52,6 +52,7 @@ CLIENT_SOURCES =                                              \
                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 --git a/src/network_conf.c b/src/network_conf.c
new file mode 100644 (file)
index 0000000..6e7155e
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * 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@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"));
+        return NULL;
+    }
+
+    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;
+    size_t towrite;
+    int err;
+
+    if (!net->configFile &&
+        asprintf(&net->configFile, "%s/%s.xml",
+                 configDir, net->def->name) < 0) {
+        net->configFile = NULL;
+        virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+        goto cleanup;
+    }
+    if (!net->autostartLink &&
+        asprintf(&net->autostartLink, "%s/%s.xml",
+                 autostartDir, net->def->name) < 0) {
+        net->autostartLink = NULL;
+        virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+        goto cleanup;
+    }
+
+    if (!(xml = virNetworkDefFormat(conn,
+                                    net->newDef ? net->newDef : net->def)))
+        goto cleanup;
+
+    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);
+    if (fd != -1)
+        close(fd);
+
+    return ret;
+}
+
+virNetworkObjPtr virNetworkLoadConfig(virConnectPtr conn,
+                                      virNetworkObjPtr *nets,
+                                      const char *configDir,
+                                      const char *autostartDir,
+                                      const char *file)
+{
+    char *configFile = NULL, *autostartLink = NULL;
+    virNetworkDefPtr def = NULL;
+    virNetworkObjPtr net;
+    int autostart;
+
+    if (asprintf(&configFile, "%s/%s",
+                 configDir, file) < 0) {
+        configFile = NULL;
+        virNetworkReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+        goto error;
+    }
+    if (asprintf(&autostartLink, "%s/%s",
+                 autostartDir, file) < 0) {
+        autostartLink = NULL;
+        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: %s"),
+                              net->def->name, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/src/network_conf.h b/src/network_conf.h
new file mode 100644 (file)
index 0000000..4434390
--- /dev/null
@@ -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@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 */
+    unsigned long delay;   /* Bridge forward delay (ms) */
+    int stp : 1; /* Spanning tree protocol */
+
+    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__ */
+
index 1f45eedbdd755f32cbef423d37239b2f3d633b90..b1d2b3939451dff835bc9e30eb00f128aab246fa 100644 (file)
@@ -304,6 +304,9 @@ virDefaultErrorFunc(virErrorPtr err)
         case VIR_FROM_STORAGE:
             dom = "Storage ";
             break;
+        case VIR_FROM_NETWORK:
+            dom = "Network Config ";
+            break;
 
     }
     if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
index 446f88c4b921b506a523697fd5e3e2eba576285d..3a6f9da30705f80edc1fbf47fa40933e7dffe78e 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -499,6 +499,58 @@ virXPathLong(const char *xpath, xmlXPathContextPtr ctxt, long *value)
     return (ret);
 }
 
+/**
+ * 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
index 679325755fb4ac653ef0b492f10b30d2f2d97632..4b7b6deb208d3a5271fc6368c950fffd41cbfab1 100644 (file)
--- a/src/xml.h
+++ b/src/xml.h
@@ -26,6 +26,9 @@ int           virXPathNumber  (const char *xpath,
 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,