mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-07 12:17:18 +00:00
Generic APIs for network XML configuration
This commit is contained in:
parent
69582431a0
commit
747fad6654
10
ChangeLog
10
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>
|
Fri Jul 11 10:55:59 BST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
* src/qemu_conf.c: Fix booting off CDROM devices
|
* src/qemu_conf.c: Fix booting off CDROM devices
|
||||||
|
@ -56,6 +56,7 @@ typedef enum {
|
|||||||
VIR_FROM_STATS_LINUX, /* Error in the Linux Stats code */
|
VIR_FROM_STATS_LINUX, /* Error in the Linux Stats code */
|
||||||
VIR_FROM_LXC, /* Error from Linux Container driver */
|
VIR_FROM_LXC, /* Error from Linux Container driver */
|
||||||
VIR_FROM_STORAGE, /* Error from storage driver */
|
VIR_FROM_STORAGE, /* Error from storage driver */
|
||||||
|
VIR_FROM_NETWORK, /* Error from network config */
|
||||||
} virErrorDomain;
|
} virErrorDomain;
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ src/libvirt.c
|
|||||||
src/lxc_conf.c
|
src/lxc_conf.c
|
||||||
src/lxc_container.c
|
src/lxc_container.c
|
||||||
src/lxc_driver.c
|
src/lxc_driver.c
|
||||||
|
src/network_conf.c
|
||||||
src/openvz_conf.c
|
src/openvz_conf.c
|
||||||
src/openvz_driver.c
|
src/openvz_driver.c
|
||||||
src/proxy_internal.c
|
src/proxy_internal.c
|
||||||
|
@ -52,6 +52,7 @@ CLIENT_SOURCES = \
|
|||||||
driver.h \
|
driver.h \
|
||||||
proxy_internal.c proxy_internal.h \
|
proxy_internal.c proxy_internal.h \
|
||||||
conf.c conf.h \
|
conf.c conf.h \
|
||||||
|
network_conf.c network_conf.h \
|
||||||
xm_internal.c xm_internal.h \
|
xm_internal.c xm_internal.h \
|
||||||
remote_internal.c remote_internal.h \
|
remote_internal.c remote_internal.h \
|
||||||
bridge.c bridge.h \
|
bridge.c bridge.h \
|
||||||
|
694
src/network_conf.c
Normal file
694
src/network_conf.c
Normal file
@ -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;
|
||||||
|
}
|
137
src/network_conf.h
Normal file
137
src/network_conf.h
Normal file
@ -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__ */
|
||||||
|
|
@ -304,6 +304,9 @@ virDefaultErrorFunc(virErrorPtr err)
|
|||||||
case VIR_FROM_STORAGE:
|
case VIR_FROM_STORAGE:
|
||||||
dom = "Storage ";
|
dom = "Storage ";
|
||||||
break;
|
break;
|
||||||
|
case VIR_FROM_NETWORK:
|
||||||
|
dom = "Network Config ";
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
|
if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
|
||||||
|
52
src/xml.c
52
src/xml.c
@ -499,6 +499,58 @@ virXPathLong(const char *xpath, xmlXPathContextPtr ctxt, long *value)
|
|||||||
return (ret);
|
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:
|
* virXPathBoolean:
|
||||||
* @xpath: the XPath string to evaluate
|
* @xpath: the XPath string to evaluate
|
||||||
|
@ -26,6 +26,9 @@ int virXPathNumber (const char *xpath,
|
|||||||
int virXPathLong (const char *xpath,
|
int virXPathLong (const char *xpath,
|
||||||
xmlXPathContextPtr ctxt,
|
xmlXPathContextPtr ctxt,
|
||||||
long *value);
|
long *value);
|
||||||
|
int virXPathULong (const char *xpath,
|
||||||
|
xmlXPathContextPtr ctxt,
|
||||||
|
unsigned long *value);
|
||||||
xmlNodePtr virXPathNode (const char *xpath,
|
xmlNodePtr virXPathNode (const char *xpath,
|
||||||
xmlXPathContextPtr ctxt);
|
xmlXPathContextPtr ctxt);
|
||||||
int virXPathNodeSet (const char *xpath,
|
int virXPathNodeSet (const char *xpath,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user