From 747fad6654e0bda921adc51639a1481f498318d4 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 11 Jul 2008 10:48:34 +0000 Subject: [PATCH] Generic APIs for network XML configuration --- ChangeLog | 10 + include/libvirt/virterror.h | 1 + po/POTFILES.in | 1 + src/Makefile.am | 1 + src/network_conf.c | 694 ++++++++++++++++++++++++++++++++++++ src/network_conf.h | 137 +++++++ src/virterror.c | 3 + src/xml.c | 52 +++ src/xml.h | 3 + 9 files changed, 902 insertions(+) create mode 100644 src/network_conf.c create mode 100644 src/network_conf.h diff --git a/ChangeLog b/ChangeLog index c7199615fa..a7ce09f283 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Fri Jul 11 11:35:59 BST 2008 Daniel P. Berrange + + 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 * src/qemu_conf.c: Fix booting off CDROM devices diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index c575f9d048..72878aedc2 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -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; diff --git a/po/POTFILES.in b/po/POTFILES.in index f5adbbaf3f..c5e48d9bf1 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index a0957e2ef2..9e8d9c8432 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 0000000000..6e7155e44a --- /dev/null +++ b/src/network_conf.c @@ -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 + */ + + + +#include + +#include +#include +#include +#include +#include + +#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, "\n"); + virBufferEscapeString(&buf, " %s\n", def->name); + + uuid = def->uuid; + virUUIDFormat(uuid, uuidstr); + virBufferVSprintf(&buf, " %s\n", uuidstr); + + if (def->forwardType != VIR_NETWORK_FORWARD_NONE) { + const char *mode = virNetworkForwardTypeToString(def->forwardType); + if (mode) { + if (def->forwardDev) { + virBufferEscapeString(&buf, " forwardDev); + } else { + virBufferAddLit(&buf, " \n", mode); + } + } + + virBufferAddLit(&buf, " 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, " 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, " \n"); + for (i = 0 ; i < def->nranges ; i++) + virBufferVSprintf(&buf, " \n", + def->ranges[i].start, def->ranges[i].end); + virBufferAddLit(&buf, " \n"); + } + + virBufferAddLit(&buf, " \n"); + } + + virBufferAddLit(&buf, "\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 index 0000000000..4434390c24 --- /dev/null +++ b/src/network_conf.h @@ -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 + */ + +#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__ */ + diff --git a/src/virterror.c b/src/virterror.c index 1f45eedbdd..b1d2b39394 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -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)) { diff --git a/src/xml.c b/src/xml.c index 446f88c4b9..3a6f9da307 100644 --- 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 diff --git a/src/xml.h b/src/xml.h index 679325755f..4b7b6deb20 100644 --- 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,