2008-07-11 10:48:34 +00:00
|
|
|
/*
|
|
|
|
* network_conf.c: network XML handling
|
|
|
|
*
|
2009-09-04 17:15:51 +00:00
|
|
|
* Copyright (C) 2006-2009 Red Hat, Inc.
|
2008-07-11 10:48:34 +00:00
|
|
|
* 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>
|
|
|
|
|
2009-12-22 02:06:57 +00:00
|
|
|
#include <unistd.h>
|
2008-07-11 10:48:34 +00:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/types.h>
|
2008-08-12 08:25:48 +00:00
|
|
|
#include <sys/stat.h>
|
2008-07-11 10:48:34 +00:00
|
|
|
#include <fcntl.h>
|
2008-10-28 17:45:41 +00:00
|
|
|
#include <string.h>
|
2008-07-11 10:48:34 +00:00
|
|
|
#include <dirent.h>
|
|
|
|
|
2008-11-04 22:30:33 +00:00
|
|
|
#include "virterror_internal.h"
|
2008-11-04 23:22:06 +00:00
|
|
|
#include "datatypes.h"
|
2008-07-11 10:48:34 +00:00
|
|
|
#include "network_conf.h"
|
2009-11-06 16:50:54 +00:00
|
|
|
#include "network.h"
|
2008-07-11 10:48:34 +00:00
|
|
|
#include "memory.h"
|
|
|
|
#include "xml.h"
|
|
|
|
#include "uuid.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "buf.h"
|
2008-08-20 12:50:29 +00:00
|
|
|
#include "c-ctype.h"
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2009-03-02 17:37:03 +00:00
|
|
|
#define MAX_BRIDGE_ID 256
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NETWORK
|
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
VIR_ENUM_DECL(virNetworkForward)
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virNetworkForward,
|
|
|
|
VIR_NETWORK_FORWARD_LAST,
|
|
|
|
"none", "nat", "route" )
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
#define virNetworkReportError(code, fmt...) \
|
|
|
|
virReportErrorHelper(NULL, VIR_FROM_NETWORK, code, __FILE__, \
|
|
|
|
__FUNCTION__, __LINE__, fmt)
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
virNetworkObjPtr virNetworkFindByUUID(const virNetworkObjListPtr nets,
|
2008-07-11 10:48:34 +00:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2008-10-10 14:50:26 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
2008-12-04 22:00:14 +00:00
|
|
|
for (i = 0 ; i < nets->count ; i++) {
|
|
|
|
virNetworkObjLock(nets->objs[i]);
|
2008-10-10 14:50:26 +00:00
|
|
|
if (!memcmp(nets->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
|
|
|
|
return nets->objs[i];
|
2008-12-04 22:00:14 +00:00
|
|
|
virNetworkObjUnlock(nets->objs[i]);
|
|
|
|
}
|
2008-07-11 10:48:34 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
virNetworkObjPtr virNetworkFindByName(const virNetworkObjListPtr nets,
|
2008-07-11 10:48:34 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
2008-10-10 14:50:26 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
2008-12-04 22:00:14 +00:00
|
|
|
for (i = 0 ; i < nets->count ; i++) {
|
|
|
|
virNetworkObjLock(nets->objs[i]);
|
2008-10-10 14:50:26 +00:00
|
|
|
if (STREQ(nets->objs[i]->def->name, name))
|
|
|
|
return nets->objs[i];
|
2008-12-04 22:00:14 +00:00
|
|
|
virNetworkObjUnlock(nets->objs[i]);
|
|
|
|
}
|
2008-07-11 10:48:34 +00:00
|
|
|
|
|
|
|
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);
|
2008-09-08 12:45:29 +00:00
|
|
|
VIR_FREE(def->domain);
|
2008-07-11 10:48:34 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2008-08-20 12:50:29 +00:00
|
|
|
for (i = 0 ; i < def->nhosts && def->hosts ; i++) {
|
|
|
|
VIR_FREE(def->hosts[i].mac);
|
|
|
|
VIR_FREE(def->hosts[i].ip);
|
|
|
|
VIR_FREE(def->hosts[i].name);
|
|
|
|
}
|
|
|
|
VIR_FREE(def->hosts);
|
|
|
|
|
2009-09-21 20:50:25 +00:00
|
|
|
VIR_FREE(def->tftproot);
|
|
|
|
VIR_FREE(def->bootfile);
|
2009-10-28 14:57:49 +00:00
|
|
|
VIR_FREE(def->bootserver);
|
2009-09-21 20:50:25 +00:00
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
VIR_FREE(def);
|
|
|
|
}
|
|
|
|
|
|
|
|
void virNetworkObjFree(virNetworkObjPtr net)
|
|
|
|
{
|
|
|
|
if (!net)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virNetworkDefFree(net->def);
|
|
|
|
virNetworkDefFree(net->newDef);
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexDestroy(&net->lock);
|
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
VIR_FREE(net);
|
|
|
|
}
|
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
void virNetworkObjListFree(virNetworkObjListPtr nets)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0 ; i < nets->count ; i++)
|
|
|
|
virNetworkObjFree(nets->objs[i]);
|
|
|
|
|
|
|
|
VIR_FREE(nets->objs);
|
|
|
|
nets->count = 0;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkObjPtr virNetworkAssignDef(virNetworkObjListPtr nets,
|
2008-07-11 10:48:34 +00:00
|
|
|
const virNetworkDefPtr def)
|
|
|
|
{
|
|
|
|
virNetworkObjPtr network;
|
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
if ((network = virNetworkFindByName(nets, def->name))) {
|
Rename internal APis
Rename virDomainIsActive to virDomainObjIsActive, and
virInterfaceIsActive to virInterfaceObjIsActive and finally
virNetworkIsActive to virNetworkObjIsActive.
* src/conf/domain_conf.c, src/conf/domain_conf.h,
src/conf/interface_conf.h, src/conf/network_conf.c,
src/conf/network_conf.h, src/lxc/lxc_driver.c,
src/network/bridge_driver.c, src/opennebula/one_driver.c,
src/openvz/openvz_driver.c, src/qemu/qemu_driver.c,
src/test/test_driver.c, src/uml/uml_driver.c: Update for
renamed APIs.
2009-10-20 14:51:03 +00:00
|
|
|
if (!virNetworkObjIsActive(network)) {
|
2008-07-11 10:48:34 +00:00
|
|
|
virNetworkDefFree(network->def);
|
|
|
|
network->def = def;
|
|
|
|
} else {
|
|
|
|
if (network->newDef)
|
|
|
|
virNetworkDefFree(network->newDef);
|
|
|
|
network->newDef = def;
|
|
|
|
}
|
|
|
|
|
|
|
|
return network;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(network) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-07-11 10:48:34 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virMutexInit(&network->lock) < 0) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-15 19:56:05 +00:00
|
|
|
"%s", _("cannot initialize mutex"));
|
|
|
|
VIR_FREE(network);
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-12-04 22:00:14 +00:00
|
|
|
virNetworkObjLock(network);
|
2008-07-11 10:48:34 +00:00
|
|
|
network->def = def;
|
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
if (VIR_REALLOC_N(nets->objs, nets->count + 1) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-10-10 14:50:26 +00:00
|
|
|
VIR_FREE(network);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
nets->objs[nets->count] = network;
|
|
|
|
nets->count++;
|
2008-07-11 10:48:34 +00:00
|
|
|
|
|
|
|
return network;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
void virNetworkRemoveInactive(virNetworkObjListPtr nets,
|
2008-07-11 10:48:34 +00:00
|
|
|
const virNetworkObjPtr net)
|
|
|
|
{
|
2008-10-10 14:50:26 +00:00
|
|
|
unsigned int i;
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-12-04 22:00:14 +00:00
|
|
|
virNetworkObjUnlock(net);
|
2008-10-10 14:50:26 +00:00
|
|
|
for (i = 0 ; i < nets->count ; i++) {
|
2008-12-04 22:00:14 +00:00
|
|
|
virNetworkObjLock(nets->objs[i]);
|
2008-10-10 14:50:26 +00:00
|
|
|
if (nets->objs[i] == net) {
|
2008-12-04 22:00:14 +00:00
|
|
|
virNetworkObjUnlock(nets->objs[i]);
|
2008-10-10 14:50:26 +00:00
|
|
|
virNetworkObjFree(nets->objs[i]);
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
if (i < (nets->count - 1))
|
|
|
|
memmove(nets->objs + i, nets->objs + i + 1,
|
|
|
|
sizeof(*(nets->objs)) * (nets->count - (i + 1)));
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-10-10 14:50:26 +00:00
|
|
|
if (VIR_REALLOC_N(nets->objs, nets->count - 1) < 0) {
|
|
|
|
; /* Failure to reduce memory allocation isn't fatal */
|
|
|
|
}
|
|
|
|
nets->count--;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2008-12-04 22:00:14 +00:00
|
|
|
virNetworkObjUnlock(nets->objs[i]);
|
2008-10-10 14:50:26 +00:00
|
|
|
}
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkDHCPRangeDefParseXML(virNetworkDefPtr def,
|
2008-07-11 10:48:34 +00:00
|
|
|
xmlNodePtr node) {
|
|
|
|
|
|
|
|
xmlNodePtr cur;
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
2008-08-20 12:50:29 +00:00
|
|
|
if (cur->type == XML_ELEMENT_NODE &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "range")) {
|
2009-11-06 16:50:54 +00:00
|
|
|
char *start, *end;
|
|
|
|
virSocketAddr saddr, eaddr;
|
|
|
|
int range;
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2009-11-06 16:50:54 +00:00
|
|
|
if (!(start = (char *) xmlGetProp(cur, BAD_CAST "start"))) {
|
2008-08-20 12:50:29 +00:00
|
|
|
cur = cur->next;
|
|
|
|
continue;
|
|
|
|
}
|
2009-11-06 16:50:54 +00:00
|
|
|
if (!(end = (char *) xmlGetProp(cur, BAD_CAST "end"))) {
|
|
|
|
xmlFree(start);
|
2008-08-20 12:50:29 +00:00
|
|
|
cur = cur->next;
|
2009-11-06 16:50:54 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virSocketParseAddr(start, &saddr, 0) < 0) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_XML_ERROR,
|
2009-11-06 16:50:54 +00:00
|
|
|
_("cannot parse dhcp start address '%s'"),
|
|
|
|
start);
|
|
|
|
xmlFree(start);
|
|
|
|
xmlFree(end);
|
|
|
|
cur = cur->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (virSocketParseAddr(end, &eaddr, 0) < 0) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_XML_ERROR,
|
2009-11-06 16:50:54 +00:00
|
|
|
_("cannot parse dhcp end address '%s'"),
|
|
|
|
end);
|
2008-08-20 12:50:29 +00:00
|
|
|
xmlFree(start);
|
2009-11-06 16:50:54 +00:00
|
|
|
xmlFree(end);
|
|
|
|
cur = cur->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
range = virSocketGetRange(&saddr, &eaddr);
|
|
|
|
if (range < 0) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_XML_ERROR,
|
2009-11-06 16:50:54 +00:00
|
|
|
_("dhcp range '%s' to '%s' invalid"),
|
|
|
|
start, end);
|
|
|
|
xmlFree(start);
|
|
|
|
xmlFree(end);
|
|
|
|
cur = cur->next;
|
2008-08-20 12:50:29 +00:00
|
|
|
continue;
|
|
|
|
}
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-08-20 12:50:29 +00:00
|
|
|
if (VIR_REALLOC_N(def->ranges, def->nranges + 1) < 0) {
|
|
|
|
xmlFree(start);
|
|
|
|
xmlFree(end);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-08-20 12:50:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
def->ranges[def->nranges].start = (char *)start;
|
|
|
|
def->ranges[def->nranges].end = (char *)end;
|
2009-11-06 16:50:54 +00:00
|
|
|
def->ranges[def->nranges].size = range;
|
2008-08-20 12:50:29 +00:00
|
|
|
def->nranges++;
|
|
|
|
} else if (cur->type == XML_ELEMENT_NODE &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "host")) {
|
|
|
|
xmlChar *mac, *name, *ip;
|
|
|
|
unsigned char addr[6];
|
|
|
|
struct in_addr inaddress;
|
|
|
|
|
|
|
|
mac = xmlGetProp(cur, BAD_CAST "mac");
|
|
|
|
if ((mac != NULL) &&
|
|
|
|
(virParseMacAddr((const char *) mac, &addr[0]) != 0)) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-20 12:50:29 +00:00
|
|
|
_("cannot parse MAC address '%s'"),
|
|
|
|
mac);
|
|
|
|
VIR_FREE(mac);
|
|
|
|
}
|
|
|
|
name = xmlGetProp(cur, BAD_CAST "name");
|
|
|
|
if ((name != NULL) && (!c_isalpha(name[0]))) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-20 12:50:29 +00:00
|
|
|
_("cannot use name address '%s'"),
|
|
|
|
name);
|
|
|
|
VIR_FREE(name);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* You need at least one MAC address or one host name
|
|
|
|
*/
|
|
|
|
if ((mac == NULL) && (name == NULL)) {
|
|
|
|
VIR_FREE(mac);
|
|
|
|
VIR_FREE(name);
|
|
|
|
cur = cur->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ip = xmlGetProp(cur, BAD_CAST "ip");
|
|
|
|
if (inet_pton(AF_INET, (const char *) ip, &inaddress) <= 0) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-08-20 12:50:29 +00:00
|
|
|
_("cannot parse IP address '%s'"),
|
|
|
|
ip);
|
|
|
|
VIR_FREE(ip);
|
|
|
|
VIR_FREE(mac);
|
|
|
|
VIR_FREE(name);
|
|
|
|
cur = cur->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (VIR_REALLOC_N(def->hosts, def->nhosts + 1) < 0) {
|
|
|
|
VIR_FREE(ip);
|
|
|
|
VIR_FREE(mac);
|
|
|
|
VIR_FREE(name);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-08-20 12:50:29 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
def->hosts[def->nhosts].mac = (char *)mac;
|
|
|
|
def->hosts[def->nhosts].name = (char *)name;
|
|
|
|
def->hosts[def->nhosts].ip = (char *)ip;
|
|
|
|
def->nhosts++;
|
2009-09-21 20:50:25 +00:00
|
|
|
|
|
|
|
} else if (cur->type == XML_ELEMENT_NODE &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "bootp")) {
|
|
|
|
xmlChar *file;
|
|
|
|
|
|
|
|
if (!(file = xmlGetProp(cur, BAD_CAST "file"))) {
|
|
|
|
cur = cur->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->bootfile = (char *)file;
|
2009-10-28 14:57:49 +00:00
|
|
|
def->bootserver = (char *) xmlGetProp(cur, BAD_CAST "server");
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-21 20:50:25 +00:00
|
|
|
static int
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkIPParseXML(virNetworkDefPtr def,
|
2009-09-21 20:50:25 +00:00
|
|
|
xmlNodePtr node) {
|
|
|
|
xmlNodePtr cur;
|
|
|
|
|
|
|
|
cur = node->children;
|
|
|
|
while (cur != NULL) {
|
|
|
|
if (cur->type == XML_ELEMENT_NODE &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
|
2010-02-10 10:22:52 +00:00
|
|
|
int result = virNetworkDHCPRangeDefParseXML(def, cur);
|
2009-09-21 20:50:25 +00:00
|
|
|
if (result)
|
|
|
|
return result;
|
|
|
|
|
|
|
|
} else if (cur->type == XML_ELEMENT_NODE &&
|
|
|
|
xmlStrEqual(cur->name, BAD_CAST "tftp")) {
|
|
|
|
xmlChar *root;
|
|
|
|
|
|
|
|
if (!(root = xmlGetProp(cur, BAD_CAST "root"))) {
|
|
|
|
cur = cur->next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
def->tftproot = (char *)root;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = cur->next;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
static virNetworkDefPtr
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkDefParseXML(xmlXPathContextPtr ctxt)
|
2008-07-11 10:48:34 +00:00
|
|
|
{
|
|
|
|
virNetworkDefPtr def;
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-07-11 10:48:34 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract network name */
|
2010-02-04 21:52:34 +00:00
|
|
|
def->name = virXPathString("string(./name[1])", ctxt);
|
2008-07-11 10:48:34 +00:00
|
|
|
if (!def->name) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_NO_NAME, NULL);
|
2008-07-11 10:48:34 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract network uuid */
|
2010-02-04 21:52:34 +00:00
|
|
|
tmp = virXPathString("string(./uuid[1])", ctxt);
|
2008-07-11 10:48:34 +00:00
|
|
|
if (!tmp) {
|
2009-09-04 17:15:51 +00:00
|
|
|
if (virUUIDGenerate(def->uuid)) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-01-20 17:13:33 +00:00
|
|
|
"%s", _("Failed to generate UUID"));
|
2008-07-11 10:48:34 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virUUIDParse(tmp, def->uuid) < 0) {
|
|
|
|
VIR_FREE(tmp);
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
"%s", _("malformed uuid element"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
}
|
|
|
|
|
2008-09-08 12:45:29 +00:00
|
|
|
/* Parse network domain information */
|
2010-02-04 21:52:34 +00:00
|
|
|
def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
|
2008-09-08 12:45:29 +00:00
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
/* Parse bridge information */
|
2010-02-04 21:52:34 +00:00
|
|
|
def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt);
|
|
|
|
tmp = virXPathString("string(./bridge[1]/@stp)", ctxt);
|
2008-07-11 10:48:34 +00:00
|
|
|
def->stp = (tmp && STREQ(tmp, "off")) ? 0 : 1;
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay) < 0)
|
2008-07-11 10:48:34 +00:00
|
|
|
def->delay = 0;
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
def->ipAddress = virXPathString("string(./ip[1]/@address)", ctxt);
|
|
|
|
def->netmask = virXPathString("string(./ip[1]/@netmask)", ctxt);
|
2008-07-11 10:48:34 +00:00
|
|
|
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;
|
2009-09-21 20:50:25 +00:00
|
|
|
xmlNodePtr ip;
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-08-06 12:08:49 +00:00
|
|
|
if (inet_pton(AF_INET, def->ipAddress, &inaddress) <= 0) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
_("cannot parse IP address '%s'"),
|
|
|
|
def->ipAddress);
|
|
|
|
goto error;
|
|
|
|
}
|
2008-08-06 12:08:49 +00:00
|
|
|
if (inet_pton(AF_INET, def->netmask, &innetmask) <= 0) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
_("cannot parse netmask '%s'"),
|
|
|
|
def->netmask);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
inaddress.s_addr &= innetmask.s_addr;
|
|
|
|
netaddr = inet_ntoa(inaddress);
|
|
|
|
|
2008-12-23 13:03:29 +00:00
|
|
|
if (virAsprintf(&def->network, "%s/%s", netaddr, def->netmask) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-07-11 10:48:34 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
if ((ip = virXPathNode("./ip[1]", ctxt)) &&
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkIPParseXML(def, ip) < 0)
|
2008-07-11 10:48:34 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* IPv4 forwarding setup */
|
2010-02-04 21:52:34 +00:00
|
|
|
if (virXPathBoolean("count(./forward) > 0", ctxt)) {
|
2008-07-11 10:48:34 +00:00
|
|
|
if (!def->ipAddress ||
|
|
|
|
!def->netmask) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
"%s", _("Forwarding requested, but no IPv4 address/netmask provided"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
tmp = virXPathString("string(./forward[1]/@mode)", ctxt);
|
2008-07-11 10:48:34 +00:00
|
|
|
if (tmp) {
|
|
|
|
if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
_("unknown forwarding type '%s'"), tmp);
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
} else {
|
|
|
|
def->forwardType = VIR_NETWORK_FORWARD_NAT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
def->forwardDev = virXPathString("string(./forward[1]/@dev)", ctxt);
|
2008-07-11 10:48:34 +00:00
|
|
|
} else {
|
|
|
|
def->forwardType = VIR_NETWORK_FORWARD_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return def;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virNetworkDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
/* Called from SAX on parsing errors in the XML. */
|
|
|
|
static void
|
|
|
|
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
|
|
|
|
{
|
|
|
|
xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
|
|
|
|
|
|
|
|
if (ctxt) {
|
2010-02-10 10:22:52 +00:00
|
|
|
if (virGetLastError() == NULL &&
|
2008-08-01 09:39:44 +00:00
|
|
|
ctxt->lastError.level == XML_ERR_FATAL &&
|
|
|
|
ctxt->lastError.message != NULL) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_XML_DETAIL,
|
|
|
|
_("at line %d: %s"),
|
|
|
|
ctxt->lastError.line,
|
|
|
|
ctxt->lastError.message);
|
2008-08-01 09:39:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkDefPtr virNetworkDefParseString(const char *xmlStr)
|
2008-07-11 10:48:34 +00:00
|
|
|
{
|
2008-08-01 09:39:44 +00:00
|
|
|
xmlParserCtxtPtr pctxt;
|
|
|
|
xmlDocPtr xml = NULL;
|
2008-07-11 10:48:34 +00:00
|
|
|
xmlNodePtr root;
|
2008-08-01 09:39:44 +00:00
|
|
|
virNetworkDefPtr def = NULL;
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
/* Set up a parser context so we can catch the details of XML errors. */
|
|
|
|
pctxt = xmlNewParserCtxt ();
|
|
|
|
if (!pctxt || !pctxt->sax)
|
|
|
|
goto cleanup;
|
|
|
|
pctxt->sax->error = catchXMLError;
|
|
|
|
|
|
|
|
xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr, "network.xml", NULL,
|
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOWARNING);
|
|
|
|
if (!xml) {
|
2010-02-10 10:22:52 +00:00
|
|
|
if (virGetLastError() == NULL)
|
|
|
|
virNetworkReportError(VIR_ERR_XML_ERROR,
|
|
|
|
"%s", _("failed to parse xml document"));
|
2008-08-01 09:39:44 +00:00
|
|
|
goto cleanup;
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((root = xmlDocGetRootElement(xml)) == NULL) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
"%s", _("missing root element"));
|
2008-08-01 09:39:44 +00:00
|
|
|
goto cleanup;
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
def = virNetworkDefParseNode(xml, root);
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
cleanup:
|
|
|
|
xmlFreeParserCtxt (pctxt);
|
|
|
|
xmlFreeDoc (xml);
|
2008-07-11 10:48:34 +00:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkDefPtr virNetworkDefParseFile(const char *filename)
|
2008-07-11 10:48:34 +00:00
|
|
|
{
|
2008-08-01 09:39:44 +00:00
|
|
|
xmlParserCtxtPtr pctxt;
|
|
|
|
xmlDocPtr xml = NULL;
|
2008-07-11 10:48:34 +00:00
|
|
|
xmlNodePtr root;
|
2008-08-01 09:39:44 +00:00
|
|
|
virNetworkDefPtr def = NULL;
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
/* Set up a parser context so we can catch the details of XML errors. */
|
|
|
|
pctxt = xmlNewParserCtxt ();
|
|
|
|
if (!pctxt || !pctxt->sax)
|
|
|
|
goto cleanup;
|
|
|
|
pctxt->sax->error = catchXMLError;
|
|
|
|
|
|
|
|
xml = xmlCtxtReadFile (pctxt, filename, NULL,
|
|
|
|
XML_PARSE_NOENT | XML_PARSE_NONET |
|
|
|
|
XML_PARSE_NOWARNING);
|
|
|
|
if (!xml) {
|
2010-02-10 10:22:52 +00:00
|
|
|
if (virGetLastError() == NULL)
|
|
|
|
virNetworkReportError(VIR_ERR_XML_ERROR,
|
|
|
|
"%s", _("failed to parse xml document"));
|
2008-08-01 09:39:44 +00:00
|
|
|
goto cleanup;
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((root = xmlDocGetRootElement(xml)) == NULL) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
"%s", _("missing root element"));
|
2008-08-01 09:39:44 +00:00
|
|
|
goto cleanup;
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
def = virNetworkDefParseNode(xml, root);
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2008-08-01 09:39:44 +00:00
|
|
|
cleanup:
|
|
|
|
xmlFreeParserCtxt (pctxt);
|
|
|
|
xmlFreeDoc (xml);
|
2008-07-11 10:48:34 +00:00
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkDefPtr virNetworkDefParseNode(xmlDocPtr xml,
|
2008-07-11 10:48:34 +00:00
|
|
|
xmlNodePtr root)
|
|
|
|
{
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
virNetworkDefPtr def = NULL;
|
|
|
|
|
|
|
|
if (!xmlStrEqual(root->name, BAD_CAST "network")) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
"%s", _("incorrect root element"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-07-11 10:48:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
2010-02-10 10:22:52 +00:00
|
|
|
def = virNetworkDefParseXML(ctxt);
|
2008-07-11 10:48:34 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
char *virNetworkDefFormat(const virNetworkDefPtr def)
|
2008-07-11 10:48:34 +00:00
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
unsigned char *uuid;
|
|
|
|
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);
|
2009-10-13 15:31:27 +00:00
|
|
|
virBufferVSprintf(&buf, " stp='%s' delay='%ld' />\n",
|
2008-07-11 10:48:34 +00:00
|
|
|
def->stp ? "on" : "off",
|
|
|
|
def->delay);
|
|
|
|
|
2009-07-02 14:02:18 +00:00
|
|
|
if (def->domain)
|
|
|
|
virBufferVSprintf(&buf, " <domain name='%s'/>\n", def->domain);
|
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
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");
|
|
|
|
|
2009-09-21 20:50:25 +00:00
|
|
|
if (def->tftproot) {
|
|
|
|
virBufferEscapeString(&buf, " <tftp root='%s' />\n",
|
|
|
|
def->tftproot);
|
|
|
|
}
|
2008-08-20 12:50:29 +00:00
|
|
|
if ((def->nranges || def->nhosts)) {
|
2008-07-11 10:48:34 +00:00
|
|
|
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);
|
2008-08-20 12:50:29 +00:00
|
|
|
for (i = 0 ; i < def->nhosts ; i++) {
|
|
|
|
virBufferAddLit(&buf, " <host ");
|
|
|
|
if (def->hosts[i].mac)
|
|
|
|
virBufferVSprintf(&buf, "mac='%s' ", def->hosts[i].mac);
|
|
|
|
if (def->hosts[i].name)
|
|
|
|
virBufferVSprintf(&buf, "name='%s' ", def->hosts[i].name);
|
|
|
|
if (def->hosts[i].ip)
|
|
|
|
virBufferVSprintf(&buf, "ip='%s' ", def->hosts[i].ip);
|
|
|
|
virBufferAddLit(&buf, "/>\n");
|
|
|
|
}
|
2009-09-21 20:50:25 +00:00
|
|
|
if (def->bootfile) {
|
2009-10-28 14:57:49 +00:00
|
|
|
virBufferEscapeString(&buf, " <bootp file='%s' ",
|
2009-09-21 20:50:25 +00:00
|
|
|
def->bootfile);
|
2009-10-28 14:57:49 +00:00
|
|
|
if (def->bootserver) {
|
|
|
|
virBufferEscapeString(&buf, "server='%s' ",
|
|
|
|
def->bootserver);
|
|
|
|
}
|
|
|
|
virBufferAddLit(&buf, "/>\n");
|
2009-09-21 20:50:25 +00:00
|
|
|
}
|
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
virBufferAddLit(&buf, " </dhcp>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, " </ip>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "</network>\n");
|
|
|
|
|
|
|
|
if (virBufferError(&buf))
|
|
|
|
goto no_memory;
|
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-12-09 23:00:50 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2008-07-11 10:48:34 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
int virNetworkSaveXML(const char *configDir,
|
2009-01-20 22:36:10 +00:00
|
|
|
virNetworkDefPtr def,
|
|
|
|
const char *xml)
|
2008-07-11 10:48:34 +00:00
|
|
|
{
|
2009-01-20 22:36:10 +00:00
|
|
|
char *configFile = NULL;
|
2008-07-11 10:48:34 +00:00
|
|
|
int fd = -1, ret = -1;
|
|
|
|
size_t towrite;
|
|
|
|
int err;
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if ((configFile = virNetworkConfigFile(configDir, def->name)) == NULL)
|
2008-07-11 10:48:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((err = virFileMakePath(configDir))) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(err,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot create config directory '%s'"),
|
|
|
|
configDir);
|
2008-07-11 10:48:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
if ((fd = open(configFile,
|
2008-07-11 10:48:34 +00:00
|
|
|
O_WRONLY | O_CREAT | O_TRUNC,
|
|
|
|
S_IRUSR | S_IWUSR )) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot create config file '%s'"),
|
2009-01-20 22:36:10 +00:00
|
|
|
configFile);
|
2008-07-11 10:48:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
towrite = strlen(xml);
|
|
|
|
if (safewrite(fd, xml, towrite) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot write config file '%s'"),
|
2009-01-20 22:36:10 +00:00
|
|
|
configFile);
|
2008-07-11 10:48:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (close(fd) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot save config file '%s'"),
|
2009-01-20 22:36:10 +00:00
|
|
|
configFile);
|
2008-07-11 10:48:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (fd != -1)
|
|
|
|
close(fd);
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
VIR_FREE(configFile);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
int virNetworkSaveConfig(const char *configDir,
|
2009-01-20 22:36:10 +00:00
|
|
|
virNetworkDefPtr def)
|
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
char *xml;
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if (!(xml = virNetworkDefFormat(def)))
|
2009-01-20 22:36:10 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if (virNetworkSaveXML(configDir, def, xml))
|
2009-01-20 22:36:10 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
2008-07-11 10:48:34 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
|
2008-07-11 10:48:34 +00:00
|
|
|
const char *configDir,
|
|
|
|
const char *autostartDir,
|
2009-01-20 22:36:10 +00:00
|
|
|
const char *name)
|
2008-07-11 10:48:34 +00:00
|
|
|
{
|
|
|
|
char *configFile = NULL, *autostartLink = NULL;
|
|
|
|
virNetworkDefPtr def = NULL;
|
|
|
|
virNetworkObjPtr net;
|
|
|
|
int autostart;
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if ((configFile = virNetworkConfigFile(configDir, name)) == NULL)
|
2008-07-11 10:48:34 +00:00
|
|
|
goto error;
|
2010-02-10 10:22:52 +00:00
|
|
|
if ((autostartLink = virNetworkConfigFile(autostartDir, name)) == NULL)
|
2008-07-11 10:48:34 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if (!(def = virNetworkDefParseFile(configFile)))
|
2008-07-11 10:48:34 +00:00
|
|
|
goto error;
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
if (!STREQ(name, def->name)) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2008-07-11 10:48:34 +00:00
|
|
|
_("Network config filename '%s'"
|
|
|
|
" does not match network name '%s'"),
|
|
|
|
configFile, def->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2009-05-29 14:18:57 +00:00
|
|
|
/* Generate a bridge if none is specified, but don't check for collisions
|
2009-03-02 17:37:03 +00:00
|
|
|
* if a bridge is hardcoded, so the network is at least defined
|
|
|
|
*/
|
2010-02-10 10:22:52 +00:00
|
|
|
if (virNetworkSetBridgeName(nets, def, 0))
|
2009-03-02 17:37:03 +00:00
|
|
|
goto error;
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if (!(net = virNetworkAssignDef(nets, def)))
|
2008-07-11 10:48:34 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
net->autostart = autostart;
|
2009-03-02 17:29:44 +00:00
|
|
|
net->persistent = 1;
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
return net;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
|
|
|
virNetworkDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
int virNetworkLoadAllConfigs(virNetworkObjListPtr nets,
|
2008-07-11 10:48:34 +00:00
|
|
|
const char *configDir,
|
|
|
|
const char *autostartDir)
|
|
|
|
{
|
|
|
|
DIR *dir;
|
|
|
|
struct dirent *entry;
|
|
|
|
|
|
|
|
if (!(dir = opendir(configDir))) {
|
|
|
|
if (errno == ENOENT)
|
|
|
|
return 0;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("Failed to open dir '%s'"),
|
|
|
|
configDir);
|
2008-07-11 10:48:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((entry = readdir(dir))) {
|
2008-12-04 22:00:14 +00:00
|
|
|
virNetworkObjPtr net;
|
|
|
|
|
2008-07-11 10:48:34 +00:00
|
|
|
if (entry->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
if (!virFileStripSuffix(entry->d_name, ".xml"))
|
2008-07-11 10:48:34 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* NB: ignoring errors, so one malformed config doesn't
|
|
|
|
kill the whole process */
|
2010-02-10 10:22:52 +00:00
|
|
|
net = virNetworkLoadConfig(nets,
|
2008-12-04 22:00:14 +00:00
|
|
|
configDir,
|
|
|
|
autostartDir,
|
|
|
|
entry->d_name);
|
|
|
|
if (net)
|
|
|
|
virNetworkObjUnlock(net);
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
int virNetworkDeleteConfig(const char *configDir,
|
2009-01-20 22:36:10 +00:00
|
|
|
const char *autostartDir,
|
2008-07-11 10:48:34 +00:00
|
|
|
virNetworkObjPtr net)
|
|
|
|
{
|
2009-01-20 22:36:10 +00:00
|
|
|
char *configFile = NULL;
|
|
|
|
char *autostartLink = NULL;
|
2009-09-04 13:56:32 +00:00
|
|
|
int ret = -1;
|
2009-01-20 22:36:10 +00:00
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
if ((configFile = virNetworkConfigFile(configDir, net->def->name)) == NULL)
|
2009-01-20 22:36:10 +00:00
|
|
|
goto error;
|
2010-02-10 10:22:52 +00:00
|
|
|
if ((autostartLink = virNetworkConfigFile(autostartDir, net->def->name)) == NULL)
|
2009-01-20 22:36:10 +00:00
|
|
|
goto error;
|
2008-07-11 10:48:34 +00:00
|
|
|
|
|
|
|
/* Not fatal if this doesn't work */
|
2009-01-20 22:36:10 +00:00
|
|
|
unlink(autostartLink);
|
2008-07-11 10:48:34 +00:00
|
|
|
|
2009-01-20 22:36:10 +00:00
|
|
|
if (unlink(configFile) < 0) {
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno,
|
2009-01-20 17:13:33 +00:00
|
|
|
_("cannot remove config file '%s'"),
|
2009-01-20 22:36:10 +00:00
|
|
|
configFile);
|
|
|
|
goto error;
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
|
|
|
|
2009-09-04 13:56:32 +00:00
|
|
|
ret = 0;
|
2009-01-20 22:36:10 +00:00
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(configFile);
|
|
|
|
VIR_FREE(autostartLink);
|
2009-09-04 13:56:32 +00:00
|
|
|
return ret;
|
2009-01-20 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
char *virNetworkConfigFile(const char *dir,
|
2009-01-20 22:36:10 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-01-20 22:36:10 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2008-07-11 10:48:34 +00:00
|
|
|
}
|
2008-12-04 20:53:20 +00:00
|
|
|
|
2009-03-02 17:37:03 +00:00
|
|
|
int virNetworkBridgeInUse(const virNetworkObjListPtr nets,
|
|
|
|
const char *bridge,
|
|
|
|
const char *skipname)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
unsigned int ret = 0;
|
|
|
|
|
|
|
|
for (i = 0 ; i < nets->count ; i++) {
|
|
|
|
virNetworkObjLock(nets->objs[i]);
|
|
|
|
if (nets->objs[i]->def->bridge &&
|
|
|
|
STREQ(nets->objs[i]->def->bridge, bridge) &&
|
|
|
|
!(skipname && STREQ(nets->objs[i]->def->name, skipname)))
|
|
|
|
ret = 1;
|
|
|
|
virNetworkObjUnlock(nets->objs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
char *virNetworkAllocateBridge(const virNetworkObjListPtr nets,
|
2009-04-21 19:00:06 +00:00
|
|
|
const char *template)
|
2009-03-02 17:37:03 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
int id = 0;
|
|
|
|
char *newname;
|
|
|
|
|
2009-04-21 19:00:06 +00:00
|
|
|
if (!template)
|
|
|
|
template = "virbr%d";
|
|
|
|
|
2009-03-02 17:37:03 +00:00
|
|
|
do {
|
|
|
|
char try[50];
|
|
|
|
|
2009-04-21 19:00:06 +00:00
|
|
|
snprintf(try, sizeof(try), template, id);
|
2009-03-02 17:37:03 +00:00
|
|
|
|
|
|
|
if (!virNetworkBridgeInUse(nets, try, NULL)) {
|
|
|
|
if (!(newname = strdup(try))) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-03-02 17:37:03 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return newname;
|
|
|
|
}
|
|
|
|
|
|
|
|
id++;
|
2009-03-02 17:56:50 +00:00
|
|
|
} while (id <= MAX_BRIDGE_ID);
|
2009-03-02 17:37:03 +00:00
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
2009-03-02 17:37:03 +00:00
|
|
|
_("Bridge generation exceeded max id %d"),
|
|
|
|
MAX_BRIDGE_ID);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-10 10:22:52 +00:00
|
|
|
int virNetworkSetBridgeName(const virNetworkObjListPtr nets,
|
2009-05-29 14:18:57 +00:00
|
|
|
virNetworkDefPtr def,
|
|
|
|
int check_collision) {
|
2009-03-02 17:37:03 +00:00
|
|
|
|
|
|
|
int ret = -1;
|
|
|
|
|
2009-04-21 19:00:06 +00:00
|
|
|
if (def->bridge && !strstr(def->bridge, "%d")) {
|
2009-05-29 14:18:57 +00:00
|
|
|
/* We may want to skip collision detection in this case (ex. when
|
|
|
|
* loading configs at daemon startup, so the network is at least
|
|
|
|
* defined. */
|
|
|
|
if (check_collision &&
|
|
|
|
virNetworkBridgeInUse(nets, def->bridge, def->name)) {
|
2010-02-10 10:22:52 +00:00
|
|
|
virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("bridge name '%s' already in use."),
|
|
|
|
def->bridge);
|
2009-03-02 17:37:03 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Allocate a bridge name */
|
2010-02-10 10:22:52 +00:00
|
|
|
if (!(def->bridge = virNetworkAllocateBridge(nets, def->bridge)))
|
2009-03-02 17:37:03 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
error:
|
|
|
|
return ret;
|
|
|
|
}
|
2009-01-20 22:36:10 +00:00
|
|
|
|
2008-12-04 22:00:14 +00:00
|
|
|
void virNetworkObjLock(virNetworkObjPtr obj)
|
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&obj->lock);
|
2008-12-04 22:00:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void virNetworkObjUnlock(virNetworkObjPtr obj)
|
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&obj->lock);
|
2008-12-04 20:53:20 +00:00
|
|
|
}
|