You need to sign in or sign up before continuing.
network_conf.c 51.6 KB
Newer Older
1 2 3
/*
 * network_conf.c: network XML handling
 *
E
Eric Blake 已提交
4
 * Copyright (C) 2006-2011 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * 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>

26
#include <unistd.h>
27 28
#include <arpa/inet.h>
#include <sys/types.h>
A
Atsushi SAKAI 已提交
29
#include <sys/stat.h>
30
#include <fcntl.h>
31
#include <string.h>
32 33
#include <dirent.h>

34
#include "virterror_internal.h"
35
#include "datatypes.h"
36
#include "network_conf.h"
37 38
#include "netdev_vport_profile_conf.h"
#include "netdev_bandwidth_conf.h"
39 40 41 42 43
#include "memory.h"
#include "xml.h"
#include "uuid.h"
#include "util.h"
#include "buf.h"
44
#include "c-ctype.h"
E
Eric Blake 已提交
45
#include "virfile.h"
46

47
#define MAX_BRIDGE_ID 256
48 49
#define VIR_FROM_THIS VIR_FROM_NETWORK

50 51 52 53
VIR_ENUM_DECL(virNetworkForward)

VIR_ENUM_IMPL(virNetworkForward,
              VIR_NETWORK_FORWARD_LAST,
54
              "none", "nat", "route", "bridge", "private", "vepa", "passthrough" )
55

56
#define virNetworkReportError(code, ...)                                \
57
    virReportErrorHelper(VIR_FROM_NETWORK, code, __FILE__,              \
58
                         __FUNCTION__, __LINE__, __VA_ARGS__)
59

60
virNetworkObjPtr virNetworkFindByUUID(const virNetworkObjListPtr nets,
61 62
                                      const unsigned char *uuid)
{
63 64
    unsigned int i;

65 66
    for (i = 0 ; i < nets->count ; i++) {
        virNetworkObjLock(nets->objs[i]);
67 68
        if (!memcmp(nets->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
            return nets->objs[i];
69 70
        virNetworkObjUnlock(nets->objs[i]);
    }
71 72 73 74

    return NULL;
}

75
virNetworkObjPtr virNetworkFindByName(const virNetworkObjListPtr nets,
76 77
                                      const char *name)
{
78 79
    unsigned int i;

80 81
    for (i = 0 ; i < nets->count ; i++) {
        virNetworkObjLock(nets->objs[i]);
82 83
        if (STREQ(nets->objs[i]->def->name, name))
            return nets->objs[i];
84 85
        virNetworkObjUnlock(nets->objs[i]);
    }
86 87 88 89 90

    return NULL;
}


91 92 93 94 95
static void
virPortGroupDefClear(virPortGroupDefPtr def)
{
    VIR_FREE(def->name);
    VIR_FREE(def->virtPortProfile);
96
    virNetDevBandwidthFree(def->bandwidth);
97
    def->bandwidth = NULL;
98 99 100 101 102 103 104 105
}

static void
virNetworkForwardIfDefClear(virNetworkForwardIfDefPtr def)
{
    VIR_FREE(def->dev);
}

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
static void virNetworkIpDefClear(virNetworkIpDefPtr def)
{
    int ii;

    VIR_FREE(def->family);
    VIR_FREE(def->ranges);

    for (ii = 0 ; ii < def->nhosts && def->hosts ; ii++) {
        VIR_FREE(def->hosts[ii].mac);
        VIR_FREE(def->hosts[ii].name);
    }

    VIR_FREE(def->hosts);
    VIR_FREE(def->tftproot);
    VIR_FREE(def->bootfile);
}

123 124 125 126 127 128 129 130 131
static void virNetworkDNSDefFree(virNetworkDNSDefPtr def)
{
    if (def) {
        if (def->txtrecords) {
            while (def->ntxtrecords--) {
                VIR_FREE(def->txtrecords[def->ntxtrecords].name);
                VIR_FREE(def->txtrecords[def->ntxtrecords].value);
            }
        }
132
        VIR_FREE(def->txtrecords);
133 134 135 136 137 138 139
        if (def->nhosts) {
            while (def->nhosts--) {
                while (def->hosts[def->nhosts].nnames--)
                    VIR_FREE(def->hosts[def->nhosts].names[def->hosts[def->nhosts].nnames]);
                VIR_FREE(def->hosts[def->nhosts].names);
            }
        }
140
        VIR_FREE(def->hosts);
141 142 143 144
        VIR_FREE(def);
    }
}

145 146
void virNetworkDefFree(virNetworkDefPtr def)
{
147
    int ii;
148 149 150 151 152 153

    if (!def)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->bridge);
154
    VIR_FREE(def->domain);
155

156 157 158 159 160
    for (ii = 0 ; ii < def->nForwardIfs && def->forwardIfs ; ii++) {
        virNetworkForwardIfDefClear(&def->forwardIfs[ii]);
    }
    VIR_FREE(def->forwardIfs);

161 162
    for (ii = 0 ; ii < def->nips && def->ips ; ii++) {
        virNetworkIpDefClear(&def->ips[ii]);
163
    }
164
    VIR_FREE(def->ips);
165

166 167 168 169 170
    for (ii = 0; ii < def->nPortGroups && def->portGroups; ii++) {
        virPortGroupDefClear(&def->portGroups[ii]);
    }
    VIR_FREE(def->portGroups);

171 172
    virNetworkDNSDefFree(def->dns);

173 174
    VIR_FREE(def->virtPortProfile);

175
    virNetDevBandwidthFree(def->bandwidth);
176

177 178 179 180 181 182 183 184 185 186 187
    VIR_FREE(def);
}

void virNetworkObjFree(virNetworkObjPtr net)
{
    if (!net)
        return;

    virNetworkDefFree(net->def);
    virNetworkDefFree(net->newDef);

188 189
    virMutexDestroy(&net->lock);

190 191 192
    VIR_FREE(net);
}

193 194 195 196 197 198 199 200 201 202 203
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;
}

204
virNetworkObjPtr virNetworkAssignDef(virNetworkObjListPtr nets,
205 206 207 208
                                     const virNetworkDefPtr def)
{
    virNetworkObjPtr network;

209
    if ((network = virNetworkFindByName(nets, def->name))) {
D
Daniel P. Berrange 已提交
210
        if (!virNetworkObjIsActive(network)) {
211 212 213
            virNetworkDefFree(network->def);
            network->def = def;
        } else {
214
            virNetworkDefFree(network->newDef);
215 216 217 218 219 220 221
            network->newDef = def;
        }

        return network;
    }

    if (VIR_ALLOC(network) < 0) {
222
        virReportOOMError();
223 224
        return NULL;
    }
225
    if (virMutexInit(&network->lock) < 0) {
226
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
227 228 229 230
                              "%s", _("cannot initialize mutex"));
        VIR_FREE(network);
        return NULL;
    }
231
    virNetworkObjLock(network);
232 233
    network->def = def;

234
    if (VIR_REALLOC_N(nets->objs, nets->count + 1) < 0) {
235
        virReportOOMError();
236 237 238 239 240 241
        VIR_FREE(network);
        return NULL;
    }

    nets->objs[nets->count] = network;
    nets->count++;
242 243 244 245 246

    return network;

}

247
void virNetworkRemoveInactive(virNetworkObjListPtr nets,
248 249
                              const virNetworkObjPtr net)
{
250
    unsigned int i;
251

252
    virNetworkObjUnlock(net);
253
    for (i = 0 ; i < nets->count ; i++) {
254
        virNetworkObjLock(nets->objs[i]);
255
        if (nets->objs[i] == net) {
256
            virNetworkObjUnlock(nets->objs[i]);
257
            virNetworkObjFree(nets->objs[i]);
258

259 260 261
            if (i < (nets->count - 1))
                memmove(nets->objs + i, nets->objs + i + 1,
                        sizeof(*(nets->objs)) * (nets->count - (i + 1)));
262

263 264 265 266 267 268 269
            if (VIR_REALLOC_N(nets->objs, nets->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            nets->count--;

            break;
        }
270
        virNetworkObjUnlock(nets->objs[i]);
271
    }
272 273
}

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
/* return ips[index], or NULL if there aren't enough ips */
virNetworkIpDefPtr
virNetworkDefGetIpByIndex(const virNetworkDefPtr def,
                          int family, size_t n)
{
    int ii;

    if (!def->ips || n >= def->nips)
        return NULL;

    if (family == AF_UNSPEC) {
        return &def->ips[n];
    }

    /* find the nth ip of type "family" */
    for (ii = 0; ii < def->nips; ii++) {
290
        if (VIR_SOCKET_ADDR_IS_FAMILY(&def->ips[ii].address, family)
291 292 293 294 295 296 297 298
            && (n-- <= 0)) {
            return &def->ips[ii];
        }
    }
    /* failed to find enough of the right family */
    return NULL;
}

L
Laine Stump 已提交
299 300 301
/* return number of 1 bits in netmask for the network's ipAddress,
 * or -1 on error
 */
302
int virNetworkIpDefPrefix(const virNetworkIpDefPtr def)
L
Laine Stump 已提交
303
{
304 305
    if (def->prefix > 0) {
        return def->prefix;
306 307 308
    } else if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
        return virSocketAddrGetNumNetmaskBits(&def->netmask);
    } else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
L
Laine Stump 已提交
309 310 311 312 313 314
        /* Return the natural prefix for the network's ip address.
         * On Linux we could use the IN_CLASSx() macros, but those
         * aren't guaranteed on all platforms, so we just deal with
         * the bits ourselves.
         */
        unsigned char octet
315
            = ntohl(def->address.data.inet4.sin_addr.s_addr) >> 24;
L
Laine Stump 已提交
316 317 318 319 320 321 322 323 324 325 326
        if ((octet & 0x80) == 0) {
            /* Class A network */
            return 8;
        } else if ((octet & 0xC0) == 0x80) {
            /* Class B network */
            return 16;
        } else if ((octet & 0xE0) == 0xC0) {
            /* Class C network */
            return 24;
        }
        return -1;
327
    } else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
328
        return 64;
L
Laine Stump 已提交
329 330 331 332 333 334 335 336
    }
    return -1;
}

/* Fill in a virSocketAddr with the proper netmask for this
 * definition, based on either the definition's netmask, or its
 * prefix. Return -1 on error (and set the netmask family to AF_UNSPEC)
 */
337 338
int virNetworkIpDefNetmask(const virNetworkIpDefPtr def,
                           virSocketAddrPtr netmask)
L
Laine Stump 已提交
339
{
340
    if (VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) {
L
Laine Stump 已提交
341 342 343 344
        *netmask = def->netmask;
        return 0;
    }

345
    return virSocketAddrPrefixToNetmask(virNetworkIpDefPrefix(def), netmask,
346
                                        VIR_SOCKET_ADDR_FAMILY(&def->address));
L
Laine Stump 已提交
347 348
}

349 350

static int
351 352
virNetworkDHCPRangeDefParseXML(const char *networkName,
                               virNetworkIpDefPtr def,
353 354
                               xmlNodePtr node)
{
355 356 357 358 359

    xmlNodePtr cur;

    cur = node->children;
    while (cur != NULL) {
360 361
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "range")) {
362 363 364
            char *start, *end;
            virSocketAddr saddr, eaddr;
            int range;
365

366
            if (!(start = virXMLPropString(cur, "start"))) {
367 368 369
                cur = cur->next;
                continue;
            }
370 371
            if (!(end = virXMLPropString(cur, "end"))) {
                VIR_FREE(start);
372
                cur = cur->next;
373 374 375
                continue;
            }

376
            if (virSocketAddrParse(&saddr, start, AF_UNSPEC) < 0) {
377 378
                VIR_FREE(start);
                VIR_FREE(end);
379
                return -1;
380
            }
381
            if (virSocketAddrParse(&eaddr, end, AF_UNSPEC) < 0) {
382 383
                VIR_FREE(start);
                VIR_FREE(end);
384
                return -1;
385 386
            }

387
            range = virSocketAddrGetRange(&saddr, &eaddr);
388
            if (range < 0) {
389
                virNetworkReportError(VIR_ERR_XML_ERROR,
390 391
                                      _("Invalid dhcp range '%s' to '%s' in network '%s'"),
                                      start, end, networkName);
392 393
                VIR_FREE(start);
                VIR_FREE(end);
394
                return -1;
395
            }
E
Eric Blake 已提交
396 397
            VIR_FREE(start);
            VIR_FREE(end);
398

399
            if (VIR_REALLOC_N(def->ranges, def->nranges + 1) < 0) {
400
                virReportOOMError();
401 402
                return -1;
            }
403 404
            def->ranges[def->nranges].start = saddr;
            def->ranges[def->nranges].end = eaddr;
405 406 407
            def->nranges++;
        } else if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "host")) {
408
            char *mac, *name, *ip;
409
            unsigned char addr[6];
410
            virSocketAddr inaddr;
411

412
            mac = virXMLPropString(cur, "mac");
413
            if ((mac != NULL) &&
414
                (virParseMacAddr(mac, &addr[0]) != 0)) {
415
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
416 417
                                      _("Cannot parse MAC address '%s' in network '%s'"),
                                      mac, networkName);
418 419
                VIR_FREE(mac);
            }
420
            name = virXMLPropString(cur, "name");
421
            if ((name != NULL) && (!c_isalpha(name[0]))) {
422
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
423 424
                                      _("Cannot use name address '%s' in network '%s'"),
                                      name, networkName);
425 426 427 428 429 430
                VIR_FREE(name);
            }
            /*
             * You need at least one MAC address or one host name
             */
            if ((mac == NULL) && (name == NULL)) {
431 432 433 434
                virNetworkReportError(VIR_ERR_XML_ERROR,
                                      _("Static host definition in network '%s' must have mac or name attribute"),
                                      networkName);
                return -1;
435
            }
436
            ip = virXMLPropString(cur, "ip");
437
            if ((ip == NULL) ||
438
                (virSocketAddrParse(&inaddr, ip, AF_UNSPEC) < 0)) {
439 440 441
                virNetworkReportError(VIR_ERR_XML_ERROR,
                                      _("Missing IP address in static host definition for network '%s'"),
                                      networkName);
442 443 444
                VIR_FREE(ip);
                VIR_FREE(mac);
                VIR_FREE(name);
445
                return -1;
446
            }
E
Eric Blake 已提交
447
            VIR_FREE(ip);
448 449 450
            if (VIR_REALLOC_N(def->hosts, def->nhosts + 1) < 0) {
                VIR_FREE(mac);
                VIR_FREE(name);
451
                virReportOOMError();
452 453
                return -1;
            }
454 455
            def->hosts[def->nhosts].mac = mac;
            def->hosts[def->nhosts].name = name;
456
            def->hosts[def->nhosts].ip = inaddr;
457
            def->nhosts++;
458 459 460

        } else if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "bootp")) {
461 462
            char *file;
            char *server;
463
            virSocketAddr inaddr;
464
            memset(&inaddr, 0, sizeof(inaddr));
465

466
            if (!(file = virXMLPropString(cur, "file"))) {
467 468 469
                cur = cur->next;
                continue;
            }
470
            server = virXMLPropString(cur, "server");
471

472
            if (server &&
473
                virSocketAddrParse(&inaddr, server, AF_UNSPEC) < 0) {
E
Eric Blake 已提交
474 475
                VIR_FREE(file);
                VIR_FREE(server);
476
                return -1;
E
Eric Blake 已提交
477
            }
478

479
            def->bootfile = file;
480
            def->bootserver = inaddr;
E
Eric Blake 已提交
481
            VIR_FREE(server);
482 483 484 485 486 487 488 489
        }

        cur = cur->next;
    }

    return 0;
}

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
static int
virNetworkDNSHostsDefParseXML(virNetworkDNSDefPtr def,
                              xmlNodePtr node)
{
    xmlNodePtr cur;
    char *ip;
    virSocketAddr inaddr;
    int ret = -1;

    if (def->hosts == NULL) {
        if (VIR_ALLOC(def->hosts) < 0) {
            virReportOOMError();
            goto error;
        }
        def->nhosts = 0;
    }

    if (!(ip = virXMLPropString(node, "ip")) ||
508
        (virSocketAddrParse(&inaddr, ip, AF_UNSPEC) < 0)) {
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
        virNetworkReportError(VIR_ERR_XML_DETAIL,
                              _("Missing IP address in DNS host definition"));
        VIR_FREE(ip);
        goto error;
    }
    VIR_FREE(ip);

    if (VIR_REALLOC_N(def->hosts, def->nhosts + 1) < 0) {
        virReportOOMError();
        goto error;
    }

    def->hosts[def->nhosts].ip = inaddr;
    def->hosts[def->nhosts].nnames = 0;

    if (VIR_ALLOC(def->hosts[def->nhosts].names) < 0) {
        virReportOOMError();
        goto error;
    }

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "hostname")) {
              if (cur->children != NULL) {
                  if (VIR_REALLOC_N(def->hosts[def->nhosts].names, def->hosts[def->nhosts].nnames + 1) < 0) {
                      virReportOOMError();
                      goto error;
                  }

                  def->hosts[def->nhosts].names[def->hosts[def->nhosts].nnames] = strdup((char *)cur->children->content);
                  def->hosts[def->nhosts].nnames++;
              }
        }

        cur = cur->next;
    }

    def->nhosts++;

    ret = 0;

error:
    return ret;
}

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
static int
virNetworkDNSDefParseXML(virNetworkDNSDefPtr *dnsdef,
                         xmlNodePtr node)
{
    xmlNodePtr cur;
    int ret = -1;
    char *name = NULL;
    char *value = NULL;
    virNetworkDNSDefPtr def = NULL;

    if (VIR_ALLOC(def) < 0) {
        virReportOOMError();
        goto error;
    }

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "txt")) {
            if (!(name = virXMLPropString(cur, "name"))) {
                virNetworkReportError(VIR_ERR_XML_DETAIL,
                                      "%s", _("Missing required name attribute in dns txt record"));
                goto error;
            }
            if (!(value = virXMLPropString(cur, "value"))) {
                virNetworkReportError(VIR_ERR_XML_DETAIL,
                                      _("Missing required value attribute in dns txt record '%s'"), name);
                goto error;
            }

            if (strchr(name, ' ') != NULL) {
                virNetworkReportError(VIR_ERR_XML_DETAIL,
                                      _("spaces are not allowed in DNS TXT record names (name is '%s')"), name);
                goto error;
            }

            if (VIR_REALLOC_N(def->txtrecords, def->ntxtrecords + 1) < 0) {
                virReportOOMError();
                goto error;
            }

            def->txtrecords[def->ntxtrecords].name = name;
            def->txtrecords[def->ntxtrecords].value = value;
            def->ntxtrecords++;
            name = NULL;
            value = NULL;
601 602 603 604 605
        } else if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "host")) {
            ret = virNetworkDNSHostsDefParseXML(def, cur);
            if (ret < 0)
                goto error;
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
        }

        cur = cur->next;
    }

    ret = 0;
error:
    if (ret < 0) {
        VIR_FREE(name);
        VIR_FREE(value);
        virNetworkDNSDefFree(def);
    } else {
        *dnsdef = def;
    }
    return ret;
}

623
static int
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
virNetworkIPParseXML(const char *networkName,
                     virNetworkIpDefPtr def,
                     xmlNodePtr node,
                     xmlXPathContextPtr ctxt)
{
    /*
     * virNetworkIpDef object is already allocated as part of an array.
     * On failure clear it out, but don't free it.
     */

    xmlNodePtr cur, save;
    char *address = NULL, *netmask = NULL;
    unsigned long prefix;
    int result = -1;

    save = ctxt->node;
    ctxt->node = node;

    /* grab raw data from XML */
    def->family = virXPathString("string(./@family)", ctxt);
    address = virXPathString("string(./@address)", ctxt);
    if (virXPathULong("string(./@prefix)", ctxt, &prefix) < 0)
        def->prefix = 0;
    else
        def->prefix = prefix;

    netmask = virXPathString("string(./@netmask)", ctxt);

    if (address) {
653
        if (virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
654 655 656 657 658
            virNetworkReportError(VIR_ERR_XML_ERROR,
                                  _("Bad address '%s' in definition of network '%s'"),
                                  address, networkName);
            goto error;
        }
659

660
    }
661

662 663
    /* validate family vs. address */
    if (def->family == NULL) {
664 665
        if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) ||
              VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_UNSPEC))) {
666 667 668 669 670 671
            virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                  _("no family specified for non-IPv4 address address '%s' in network '%s'"),
                                  address, networkName);
            goto error;
        }
    } else if (STREQ(def->family, "ipv4")) {
672
        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
673 674 675 676 677 678
            virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                  _("family 'ipv4' specified for non-IPv4 address '%s' in network '%s'"),
                                  address, networkName);
            goto error;
        }
    } else if (STREQ(def->family, "ipv6")) {
679
        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
680 681 682 683 684 685 686 687 688 689 690
            virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                  _("family 'ipv6' specified for non-IPv6 address '%s' in network '%s'"),
                                  address, networkName);
            goto error;
        }
    } else {
        virNetworkReportError(VIR_ERR_XML_ERROR,
                              _("Unrecognized family '%s' in definition of network '%s'"),
                              def->family, networkName);
        goto error;
    }
691

692 693 694 695 696 697 698 699 700 701
    /* parse/validate netmask */
    if (netmask) {
        if (address == NULL) {
            /* netmask is meaningless without an address */
            virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                  _("netmask specified without address in network '%s'"),
                                  networkName);
            goto error;
        }

702
        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
703 704 705 706 707 708 709 710 711 712 713 714 715 716
            virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                  _("netmask not supported for address '%s' in network '%s' (IPv4 only)"),
                                  address, networkName);
            goto error;
        }

        if (def->prefix > 0) {
            /* can't have both netmask and prefix at the same time */
            virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                  _("network '%s' cannot have both prefix='%u' and a netmask"),
                                  networkName, def->prefix);
            goto error;
        }

717
        if (virSocketAddrParse(&def->netmask, netmask, AF_UNSPEC) < 0)
718 719
            goto error;

720
        if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) {
721 722 723 724 725 726 727
            virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                  _("network '%s' has invalid netmask '%s' for address '%s' (both must be IPv4)"),
                                  networkName, netmask, address);
            goto error;
        }
    }

728
    if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
729 730 731 732 733
        /* parse IPv4-related info */
        cur = node->children;
        while (cur != NULL) {
            if (cur->type == XML_ELEMENT_NODE &&
                xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
734
                result = virNetworkDHCPRangeDefParseXML(networkName, def, cur);
735 736 737 738 739 740 741 742 743 744 745 746 747
                if (result)
                    goto error;

            } else if (cur->type == XML_ELEMENT_NODE &&
                       xmlStrEqual(cur->name, BAD_CAST "tftp")) {
                char *root;

                if (!(root = virXMLPropString(cur, "root"))) {
                    cur = cur->next;
                    continue;
                }

                def->tftproot = (char *)root;
748 749
            }

750
            cur = cur->next;
751
        }
752
    }
753

754 755 756 757 758
    result = 0;

error:
    if (result < 0) {
        virNetworkIpDefClear(def);
759
    }
760 761 762 763 764
    VIR_FREE(address);
    VIR_FREE(netmask);

    ctxt->node = save;
    return result;
765 766
}

767 768 769 770 771 772 773 774 775 776 777 778
static int
virNetworkPortGroupParseXML(virPortGroupDefPtr def,
                            xmlNodePtr node,
                            xmlXPathContextPtr ctxt)
{
    /*
     * virPortGroupDef object is already allocated as part of an array.
     * On failure clear it out, but don't free it.
     */

    xmlNodePtr save;
    xmlNodePtr virtPortNode;
779
    xmlNodePtr bandwidth_node;
780 781 782 783 784 785 786 787 788 789 790 791 792 793
    char *isDefault = NULL;

    int result = -1;

    save = ctxt->node;
    ctxt->node = node;

    /* grab raw data from XML */
    def->name = virXPathString("string(./@name)", ctxt);
    isDefault = virXPathString("string(./@default)", ctxt);
    def->isDefault = isDefault && STRCASEEQ(isDefault, "yes");

    virtPortNode = virXPathNode("./virtualport", ctxt);
    if (virtPortNode &&
794
        (!(def->virtPortProfile = virNetDevVPortProfileParse(virtPortNode))))
795 796
        goto error;

797 798
    bandwidth_node = virXPathNode("./bandwidth", ctxt);
    if (bandwidth_node &&
799
        !(def->bandwidth = virNetDevBandwidthParse(bandwidth_node))) {
800 801 802
        goto error;
    }

803 804 805 806 807 808 809 810 811 812 813
    result = 0;
error:
    if (result < 0) {
        virPortGroupDefClear(def);
    }
    VIR_FREE(isDefault);

    ctxt->node = save;
    return result;
}

814
static virNetworkDefPtr
815
virNetworkDefParseXML(xmlXPathContextPtr ctxt)
816 817 818
{
    virNetworkDefPtr def;
    char *tmp;
819
    char *stp = NULL;
820
    xmlNodePtr *ipNodes = NULL;
821 822
    xmlNodePtr *portGroupNodes = NULL;
    xmlNodePtr *forwardIfNodes = NULL;
823
    xmlNodePtr dnsNode = NULL;
824 825 826 827 828
    xmlNodePtr virtPortNode = NULL;
    xmlNodePtr forwardNode = NULL;
    int nIps, nPortGroups, nForwardIfs;
    char *forwardDev = NULL;
    xmlNodePtr save = ctxt->node;
829
    xmlNodePtr bandwidthNode = NULL;
830 831

    if (VIR_ALLOC(def) < 0) {
832
        virReportOOMError();
833 834 835 836
        return NULL;
    }

    /* Extract network name */
837
    def->name = virXPathString("string(./name[1])", ctxt);
838
    if (!def->name) {
839
        virNetworkReportError(VIR_ERR_NO_NAME, NULL);
840 841 842 843
        goto error;
    }

    /* Extract network uuid */
844
    tmp = virXPathString("string(./uuid[1])", ctxt);
845
    if (!tmp) {
846
        if (virUUIDGenerate(def->uuid)) {
847
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
848
                                  "%s", _("Failed to generate UUID"));
849 850 851 852 853
            goto error;
        }
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
            VIR_FREE(tmp);
854
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
855 856 857 858 859 860
                                  "%s", _("malformed uuid element"));
            goto error;
        }
        VIR_FREE(tmp);
    }

861
    /* Parse network domain information */
862
    def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
863

864
    if ((bandwidthNode = virXPathNode("./bandwidth", ctxt)) != NULL &&
865
        (def->bandwidth = virNetDevBandwidthParse(bandwidthNode)) == NULL)
866 867
        goto error;

868
    /* Parse bridge information */
869
    def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt);
870
    stp = virXPathString("string(./bridge[1]/@stp)", ctxt);
871

872
    if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay) < 0)
873 874
        def->delay = 0;

875 876 877 878 879 880 881 882 883 884 885 886 887
    tmp = virXPathString("string(./mac[1]/@address)", ctxt);
    if (tmp) {
        if (virParseMacAddr(tmp, def->mac) < 0) {
            virNetworkReportError(VIR_ERR_XML_ERROR,
                                  _("Invalid bridge mac address '%s' in network '%s'"),
                                  tmp, def->name);
            VIR_FREE(tmp);
            goto error;
        }
        VIR_FREE(tmp);
        def->mac_specified = true;
    }

888 889 890 891 892 893
    dnsNode = virXPathNode("./dns", ctxt);
    if (dnsNode != NULL) {
        if (virNetworkDNSDefParseXML(&def->dns, dnsNode) < 0)
            goto error;
    }

894 895
    virtPortNode = virXPathNode("./virtualport", ctxt);
    if (virtPortNode &&
896
        (!(def->virtPortProfile = virNetDevVPortProfileParse(virtPortNode))))
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
        goto error;

    nPortGroups = virXPathNodeSet("./portgroup", ctxt, &portGroupNodes);
    if (nPortGroups < 0)
        goto error;

    if (nPortGroups > 0) {
        int ii;

        /* allocate array to hold all the portgroups */
        if (VIR_ALLOC_N(def->portGroups, nPortGroups) < 0) {
            virReportOOMError();
            goto error;
        }
        /* parse each portgroup */
        for (ii = 0; ii < nPortGroups; ii++) {
            int ret = virNetworkPortGroupParseXML(&def->portGroups[ii],
                                                  portGroupNodes[ii], ctxt);
            if (ret < 0)
                goto error;
            def->nPortGroups++;
        }
    }
    VIR_FREE(portGroupNodes);

922
    nIps = virXPathNodeSet("./ip", ctxt, &ipNodes);
923 924 925
    if (nIps < 0)
        goto error;

926 927
    if (nIps > 0) {
        int ii;
928

929 930 931
        /* allocate array to hold all the addrs */
        if (VIR_ALLOC_N(def->ips, nIps) < 0) {
            virReportOOMError();
932 933
            goto error;
        }
934 935 936 937 938 939 940
        /* parse each addr */
        for (ii = 0; ii < nIps; ii++) {
            int ret = virNetworkIPParseXML(def->name, &def->ips[ii],
                                           ipNodes[ii], ctxt);
            if (ret < 0)
                goto error;
            def->nips++;
941
        }
942
    }
E
Eric Blake 已提交
943
    VIR_FREE(ipNodes);
944

945 946 947 948 949 950 951
    forwardNode = virXPathNode("./forward", ctxt);
    if (!forwardNode) {
        def->forwardType = VIR_NETWORK_FORWARD_NONE;
        def->stp = (stp && STREQ(stp, "off")) ? 0 : 1;
    } else {
        ctxt->node = forwardNode;
        tmp = virXPathString("string(./@mode)", ctxt);
952 953
        if (tmp) {
            if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
954
                virNetworkReportError(VIR_ERR_XML_ERROR,
955 956 957 958 959 960 961 962 963
                                      _("unknown forwarding type '%s'"), tmp);
                VIR_FREE(tmp);
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->forwardType = VIR_NETWORK_FORWARD_NAT;
        }

964
        forwardDev = virXPathString("string(./@dev)", ctxt);
965

966 967 968 969 970 971 972
        /* all of these modes can use a pool of physical interfaces */
        nForwardIfs = virXPathNodeSet("./interface", ctxt, &forwardIfNodes);
        if (nForwardIfs < 0)
            goto error;

        if ((nForwardIfs > 0) || forwardDev) {
            int ii;
973

974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
            /* allocate array to hold all the portgroups */
            if (VIR_ALLOC_N(def->forwardIfs, MAX(nForwardIfs, 1)) < 0) {
                virReportOOMError();
                goto error;
            }

            if (forwardDev) {
                def->forwardIfs[0].usageCount = 0;
                def->forwardIfs[0].dev = forwardDev;
                forwardDev = NULL;
                def->nForwardIfs++;
            }

            /* parse each forwardIf */
            for (ii = 0; ii < nForwardIfs; ii++) {
                forwardDev = virXMLPropString(forwardIfNodes[ii], "dev");
                if (!forwardDev) {
                    virNetworkReportError(VIR_ERR_XML_ERROR,
                                          _("Missing required dev attribute in network '%s' forward interface element"),
                                          def->name);
                    goto error;
                }

                if ((ii == 0) && (def->nForwardIfs == 1)) {
                    /* both forwardDev and an interface element are present.
                     * If they don't match, it's an error. */
                    if (STRNEQ(forwardDev, def->forwardIfs[0].dev)) {
                        virNetworkReportError(VIR_ERR_XML_ERROR,
                                              _("forward dev '%s' must match first interface element dev '%s' in network '%s'"),
                                              def->forwardIfs[0].dev,
                                              forwardDev, def->name);
                        goto error;
                    }
                    VIR_FREE(forwardDev);
                    continue;
                }

                def->forwardIfs[ii].dev = forwardDev;
                forwardDev = NULL;
                def->forwardIfs[ii].usageCount = 0;
                def->nForwardIfs++;
            }
        }
        VIR_FREE(forwardIfNodes);

        switch (def->forwardType) {
        case VIR_NETWORK_FORWARD_ROUTE:
        case VIR_NETWORK_FORWARD_NAT:
            /* It's pointless to specify L3 forwarding without specifying
             * the network we're on.
             */
            if (def->nips == 0) {
                virNetworkReportError(VIR_ERR_XML_ERROR,
                                      _("%s forwarding requested, but no IP address provided for network '%s'"),
                                      virNetworkForwardTypeToString(def->forwardType),
                                      def->name);
                goto error;
            }
            if (def->nForwardIfs > 1) {
                virNetworkReportError(VIR_ERR_XML_ERROR,
                                      _("multiple forwarding interfaces specified for network '%s', only one is supported"),
                                      def->name);
                goto error;
            }
            def->stp = (stp && STREQ(stp, "off")) ? 0 : 1;
            break;
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
            if (def->bridge) {
                virNetworkReportError(VIR_ERR_XML_ERROR,
                                      _("bridge name not allowed in %s mode (network '%s'"),
                                      virNetworkForwardTypeToString(def->forwardType),
                                      def->name);
                goto error;
            }
            /* fall through to next case */
        case VIR_NETWORK_FORWARD_BRIDGE:
            if (def->delay || stp) {
                virNetworkReportError(VIR_ERR_XML_ERROR,
                                      _("bridge delay/stp options only allowed in route, nat, and isolated mode, not in %s (network '%s')"),
                                      virNetworkForwardTypeToString(def->forwardType),
                                      def->name);
                goto error;
            }
            break;
        }
    }
    VIR_FREE(stp);
    ctxt->node = save;
1064 1065 1066
    return def;

 error:
1067
    VIR_FREE(stp);
1068
    virNetworkDefFree(def);
E
Eric Blake 已提交
1069
    VIR_FREE(ipNodes);
1070 1071 1072 1073
    VIR_FREE(portGroupNodes);
    VIR_FREE(forwardIfNodes);
    VIR_FREE(forwardDev);
    ctxt->node = save;
1074 1075 1076
    return NULL;
}

J
Jiri Denemark 已提交
1077 1078 1079
static virNetworkDefPtr
virNetworkDefParse(const char *xmlStr,
                   const char *filename)
1080
{
J
Jiri Denemark 已提交
1081
    xmlDocPtr xml;
1082
    virNetworkDefPtr def = NULL;
1083

1084
    if ((xml = virXMLParse(filename, xmlStr, _("(network_definition)")))) {
J
Jiri Denemark 已提交
1085 1086
        def = virNetworkDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
1087 1088 1089 1090 1091
    }

    return def;
}

J
Jiri Denemark 已提交
1092
virNetworkDefPtr virNetworkDefParseString(const char *xmlStr)
1093
{
J
Jiri Denemark 已提交
1094 1095
    return virNetworkDefParse(xmlStr, NULL);
}
1096

J
Jiri Denemark 已提交
1097 1098 1099
virNetworkDefPtr virNetworkDefParseFile(const char *filename)
{
    return virNetworkDefParse(NULL, filename);
1100 1101 1102
}


1103
virNetworkDefPtr virNetworkDefParseNode(xmlDocPtr xml,
1104 1105 1106 1107 1108 1109
                                        xmlNodePtr root)
{
    xmlXPathContextPtr ctxt = NULL;
    virNetworkDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "network")) {
1110
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
1111 1112 1113 1114 1115 1116
                              "%s", _("incorrect root element"));
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
1117
        virReportOOMError();
1118 1119 1120 1121
        goto cleanup;
    }

    ctxt->node = root;
1122
    def = virNetworkDefParseXML(ctxt);
1123 1124 1125 1126 1127 1128

cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
static int
virNetworkDNSDefFormat(virBufferPtr buf,
                       virNetworkDNSDefPtr def)
{
    int result = 0;
    int i;

    if (def == NULL)
        goto out;

    virBufferAddLit(buf, "  <dns>\n");

    for (i = 0 ; i < def->ntxtrecords ; i++) {
        virBufferAsprintf(buf, "    <txt name='%s' value='%s' />\n",
                              def->txtrecords[i].name,
                              def->txtrecords[i].value);
    }

1147 1148 1149 1150
    if (def->nhosts) {
        int ii, j;

        for (ii = 0 ; ii < def->nhosts; ii++) {
1151
            char *ip = virSocketAddrFormat(&def->hosts[ii].ip);
1152 1153 1154 1155 1156 1157 1158 1159

            virBufferAsprintf(buf, "    <host ip='%s'>\n", ip);

            for (j = 0; j < def->hosts[ii].nnames; j++)
                virBufferAsprintf(buf, "      <hostname>%s</hostname>\n",
                                               def->hosts[ii].names[j]);

            virBufferAsprintf(buf, "    </host>\n");
1160
            VIR_FREE(ip);
1161 1162 1163
        }
    }

1164 1165 1166 1167 1168
    virBufferAddLit(buf, "  </dns>\n");
out:
    return result;
}

1169 1170 1171 1172 1173 1174 1175 1176 1177
static int
virNetworkIpDefFormat(virBufferPtr buf,
                      const virNetworkIpDefPtr def)
{
    int result = -1;

    virBufferAddLit(buf, "  <ip");

    if (def->family) {
1178
        virBufferAsprintf(buf, " family='%s'", def->family);
1179
    }
1180 1181
    if (VIR_SOCKET_ADDR_VALID(&def->address)) {
        char *addr = virSocketAddrFormat(&def->address);
1182 1183
        if (!addr)
            goto error;
1184
        virBufferAsprintf(buf, " address='%s'", addr);
1185 1186
        VIR_FREE(addr);
    }
1187 1188
    if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
        char *addr = virSocketAddrFormat(&def->netmask);
1189 1190
        if (!addr)
            goto error;
1191
        virBufferAsprintf(buf, " netmask='%s'", addr);
1192 1193 1194
        VIR_FREE(addr);
    }
    if (def->prefix > 0) {
1195
        virBufferAsprintf(buf," prefix='%u'", def->prefix);
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206
    }
    virBufferAddLit(buf, ">\n");

    if (def->tftproot) {
        virBufferEscapeString(buf, "    <tftp root='%s' />\n",
                              def->tftproot);
    }
    if ((def->nranges || def->nhosts)) {
        int ii;
        virBufferAddLit(buf, "    <dhcp>\n");
        for (ii = 0 ; ii < def->nranges ; ii++) {
1207
            char *saddr = virSocketAddrFormat(&def->ranges[ii].start);
1208 1209
            if (!saddr)
                goto error;
1210
            char *eaddr = virSocketAddrFormat(&def->ranges[ii].end);
1211 1212 1213 1214
            if (!eaddr) {
                VIR_FREE(saddr);
                goto error;
            }
1215
            virBufferAsprintf(buf, "      <range start='%s' end='%s' />\n",
1216 1217 1218 1219 1220 1221 1222
                              saddr, eaddr);
            VIR_FREE(saddr);
            VIR_FREE(eaddr);
        }
        for (ii = 0 ; ii < def->nhosts ; ii++) {
            virBufferAddLit(buf, "      <host ");
            if (def->hosts[ii].mac)
1223
                virBufferAsprintf(buf, "mac='%s' ", def->hosts[ii].mac);
1224
            if (def->hosts[ii].name)
1225
                virBufferAsprintf(buf, "name='%s' ", def->hosts[ii].name);
1226 1227
            if (VIR_SOCKET_ADDR_VALID(&def->hosts[ii].ip)) {
                char *ipaddr = virSocketAddrFormat(&def->hosts[ii].ip);
1228 1229
                if (!ipaddr)
                    goto error;
1230
                virBufferAsprintf(buf, "ip='%s' ", ipaddr);
1231 1232 1233 1234 1235 1236 1237
                VIR_FREE(ipaddr);
            }
            virBufferAddLit(buf, "/>\n");
        }
        if (def->bootfile) {
            virBufferEscapeString(buf, "      <bootp file='%s' ",
                                  def->bootfile);
1238 1239
            if (VIR_SOCKET_ADDR_VALID(&def->bootserver)) {
                char *ipaddr = virSocketAddrFormat(&def->bootserver);
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
                if (!ipaddr)
                    goto error;
                virBufferEscapeString(buf, "server='%s' ", ipaddr);
                VIR_FREE(ipaddr);
            }
            virBufferAddLit(buf, "/>\n");
        }

        virBufferAddLit(buf, "    </dhcp>\n");
    }

    virBufferAddLit(buf, "  </ip>\n");

    result = 0;
error:
    return result;
}

1258
static int
1259 1260 1261 1262 1263 1264 1265 1266
virPortGroupDefFormat(virBufferPtr buf,
                      const virPortGroupDefPtr def)
{
    virBufferAsprintf(buf, "  <portgroup name='%s'", def->name);
    if (def->isDefault) {
        virBufferAddLit(buf, " default='yes'");
    }
    virBufferAddLit(buf, ">\n");
1267
    virBufferAdjustIndent(buf, 4);
1268 1269
    if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
        return -1;
1270
    virNetDevBandwidthFormat(def->bandwidth, buf);
1271
    virBufferAdjustIndent(buf, -4);
1272
    virBufferAddLit(buf, "  </portgroup>\n");
1273
    return 0;
1274 1275
}

1276
char *virNetworkDefFormat(const virNetworkDefPtr def)
1277 1278 1279 1280
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
1281
    int ii;
1282 1283 1284 1285 1286 1287

    virBufferAddLit(&buf, "<network>\n");
    virBufferEscapeString(&buf, "  <name>%s</name>\n", def->name);

    uuid = def->uuid;
    virUUIDFormat(uuid, uuidstr);
1288
    virBufferAsprintf(&buf, "  <uuid>%s</uuid>\n", uuidstr);
1289 1290

    if (def->forwardType != VIR_NETWORK_FORWARD_NONE) {
1291
        const char *dev = virNetworkDefForwardIf(def, 0);
1292
        const char *mode = virNetworkForwardTypeToString(def->forwardType);
1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311

        if (!mode) {
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
                                  _("Unknown forward type %d in network '%s'"),
                                  def->forwardType, def->name);
            goto error;
        }
        virBufferAddLit(&buf, "  <forward");
        if (dev)
            virBufferEscapeString(&buf, " dev='%s'", dev);
        virBufferAsprintf(&buf, " mode='%s'%s>\n", mode,
                          def->nForwardIfs ? "" : "/");

        if (def->nForwardIfs) {
            for (ii = 0; ii < def->nForwardIfs; ii++) {
                if (def->forwardIfs[ii].dev) {
                    virBufferEscapeString(&buf, "    <interface dev='%s'/>\n",
                                          def->forwardIfs[ii].dev);
                }
1312
            }
1313
            virBufferAddLit(&buf, "  </forward>\n");
1314 1315 1316
        }
    }

1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
    if (def->forwardType == VIR_NETWORK_FORWARD_NONE ||
         def->forwardType == VIR_NETWORK_FORWARD_NAT ||
         def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {

        virBufferAddLit(&buf, "  <bridge");
        if (def->bridge)
            virBufferEscapeString(&buf, " name='%s'", def->bridge);
        virBufferAsprintf(&buf, " stp='%s' delay='%ld' />\n",
                          def->stp ? "on" : "off",
                          def->delay);
    } else if (def->forwardType == VIR_NETWORK_FORWARD_BRIDGE &&
               def->bridge) {
       virBufferEscapeString(&buf, "  <bridge name='%s' />\n", def->bridge);
    }


1333 1334 1335
    if (def->mac_specified) {
        char macaddr[VIR_MAC_STRING_BUFLEN];
        virFormatMacAddr(def->mac, macaddr);
1336
        virBufferAsprintf(&buf, "  <mac address='%s'/>\n", macaddr);
1337
    }
1338

1339
    if (def->domain)
1340
        virBufferAsprintf(&buf, "  <domain name='%s'/>\n", def->domain);
1341

1342 1343 1344
    if (virNetworkDNSDefFormat(&buf, def->dns) < 0)
        goto error;

1345
    virBufferAdjustIndent(&buf, 2);
1346
    if (virNetDevBandwidthFormat(def->bandwidth, &buf) < 0)
1347
        goto error;
1348
    virBufferAdjustIndent(&buf, -2);
1349

1350 1351 1352
    for (ii = 0; ii < def->nips; ii++) {
        if (virNetworkIpDefFormat(&buf, &def->ips[ii]) < 0)
            goto error;
1353 1354
    }

1355
    virBufferAdjustIndent(&buf, 2);
1356 1357
    if (virNetDevVPortProfileFormat(def->virtPortProfile, &buf) < 0)
        goto error;
1358
    virBufferAdjustIndent(&buf, -2);
1359 1360

    for (ii = 0; ii < def->nPortGroups; ii++)
1361 1362
        if (virPortGroupDefFormat(&buf, &def->portGroups[ii]) < 0)
            goto error;
1363

1364 1365 1366 1367 1368 1369 1370 1371
    virBufferAddLit(&buf, "</network>\n");

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

 no_memory:
1372
    virReportOOMError();
1373
  error:
1374
    virBufferFreeAndReset(&buf);
1375 1376 1377
    return NULL;
}

1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net,
                                          const char *portgroup)
{
    int ii;
    for (ii = 0; ii < net->nPortGroups; ii++) {
        if (portgroup) {
            if (STREQ(portgroup, net->portGroups[ii].name))
                return &net->portGroups[ii];
        } else {
            if (net->portGroups[ii].isDefault)
                return &net->portGroups[ii];
        }
    }
    return NULL;
}

1394
int virNetworkSaveXML(const char *configDir,
1395 1396
                      virNetworkDefPtr def,
                      const char *xml)
1397
{
1398
    char *configFile = NULL;
1399
    int ret = -1;
1400

1401
    if ((configFile = virNetworkConfigFile(configDir, def->name)) == NULL)
1402 1403
        goto cleanup;

1404 1405
    if (virFileMakePath(configDir) < 0) {
        virReportSystemError(errno,
1406 1407
                             _("cannot create config directory '%s'"),
                             configDir);
1408 1409 1410
        goto cleanup;
    }

1411
    ret = virXMLSaveFile(configFile, def->name, "net-edit", xml);
1412 1413

 cleanup:
1414 1415 1416 1417
    VIR_FREE(configFile);
    return ret;
}

1418
int virNetworkSaveConfig(const char *configDir,
1419 1420 1421 1422 1423
                         virNetworkDefPtr def)
{
    int ret = -1;
    char *xml;

1424
    if (!(xml = virNetworkDefFormat(def)))
1425 1426
        goto cleanup;

1427
    if (virNetworkSaveXML(configDir, def, xml))
1428 1429 1430 1431 1432
        goto cleanup;

    ret = 0;
cleanup:
    VIR_FREE(xml);
1433 1434 1435
    return ret;
}

1436

1437
virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
1438 1439
                                      const char *configDir,
                                      const char *autostartDir,
1440
                                      const char *name)
1441 1442 1443 1444 1445 1446
{
    char *configFile = NULL, *autostartLink = NULL;
    virNetworkDefPtr def = NULL;
    virNetworkObjPtr net;
    int autostart;

1447
    if ((configFile = virNetworkConfigFile(configDir, name)) == NULL)
1448
        goto error;
1449
    if ((autostartLink = virNetworkConfigFile(autostartDir, name)) == NULL)
1450 1451 1452 1453 1454
        goto error;

    if ((autostart = virFileLinkPointsTo(autostartLink, configFile)) < 0)
        goto error;

1455
    if (!(def = virNetworkDefParseFile(configFile)))
1456 1457
        goto error;

1458
    if (!STREQ(name, def->name)) {
1459
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
1460 1461 1462 1463 1464 1465
                              _("Network config filename '%s'"
                                " does not match network name '%s'"),
                              configFile, def->name);
        goto error;
    }

1466 1467 1468 1469 1470 1471 1472 1473 1474 1475
    if (def->forwardType == VIR_NETWORK_FORWARD_NONE ||
        def->forwardType == VIR_NETWORK_FORWARD_NAT ||
        def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {

        /* Generate a bridge if none is specified, but don't check for collisions
         * if a bridge is hardcoded, so the network is at least defined.
         */
        if (virNetworkSetBridgeName(nets, def, 0))
            goto error;
    }
1476

1477
    if (!(net = virNetworkAssignDef(nets, def)))
1478 1479 1480
        goto error;

    net->autostart = autostart;
1481
    net->persistent = 1;
1482

1483 1484 1485
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);

1486 1487 1488 1489 1490 1491 1492 1493 1494
    return net;

error:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    virNetworkDefFree(def);
    return NULL;
}

1495
int virNetworkLoadAllConfigs(virNetworkObjListPtr nets,
1496 1497 1498 1499 1500 1501 1502 1503 1504
                             const char *configDir,
                             const char *autostartDir)
{
    DIR *dir;
    struct dirent *entry;

    if (!(dir = opendir(configDir))) {
        if (errno == ENOENT)
            return 0;
1505
        virReportSystemError(errno,
1506 1507
                             _("Failed to open dir '%s'"),
                             configDir);
1508 1509 1510 1511
        return -1;
    }

    while ((entry = readdir(dir))) {
1512 1513
        virNetworkObjPtr net;

1514 1515 1516
        if (entry->d_name[0] == '.')
            continue;

1517
        if (!virFileStripSuffix(entry->d_name, ".xml"))
1518 1519 1520 1521
            continue;

        /* NB: ignoring errors, so one malformed config doesn't
           kill the whole process */
1522
        net = virNetworkLoadConfig(nets,
1523 1524 1525 1526 1527
                                   configDir,
                                   autostartDir,
                                   entry->d_name);
        if (net)
            virNetworkObjUnlock(net);
1528 1529 1530 1531 1532 1533 1534
    }

    closedir(dir);

    return 0;
}

1535
int virNetworkDeleteConfig(const char *configDir,
1536
                           const char *autostartDir,
1537 1538
                           virNetworkObjPtr net)
{
1539 1540
    char *configFile = NULL;
    char *autostartLink = NULL;
R
Ryota Ozaki 已提交
1541
    int ret = -1;
1542

1543
    if ((configFile = virNetworkConfigFile(configDir, net->def->name)) == NULL)
1544
        goto error;
1545
    if ((autostartLink = virNetworkConfigFile(autostartDir, net->def->name)) == NULL)
1546
        goto error;
1547 1548

    /* Not fatal if this doesn't work */
1549
    unlink(autostartLink);
1550

1551
    if (unlink(configFile) < 0) {
1552
        virReportSystemError(errno,
1553
                             _("cannot remove config file '%s'"),
1554 1555
                             configFile);
        goto error;
1556 1557
    }

R
Ryota Ozaki 已提交
1558
    ret = 0;
1559 1560 1561 1562

error:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
R
Ryota Ozaki 已提交
1563
    return ret;
1564 1565
}

1566
char *virNetworkConfigFile(const char *dir,
1567 1568 1569 1570 1571
                           const char *name)
{
    char *ret = NULL;

    if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
1572
        virReportOOMError();
1573 1574 1575 1576
        return NULL;
    }

    return ret;
1577
}
D
Daniel P. Berrange 已提交
1578

1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597
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;
}

1598
char *virNetworkAllocateBridge(const virNetworkObjListPtr nets,
1599
                               const char *template)
1600 1601 1602 1603 1604
{

    int id = 0;
    char *newname;

1605 1606 1607
    if (!template)
        template = "virbr%d";

1608
    do {
1609 1610 1611 1612 1613
        if (virAsprintf(&newname, template, id) < 0) {
            virReportOOMError();
            return NULL;
        }
        if (!virNetworkBridgeInUse(nets, newname, NULL)) {
1614 1615
            return newname;
        }
1616
        VIR_FREE(newname);
1617 1618

        id++;
1619
    } while (id <= MAX_BRIDGE_ID);
1620

1621
    virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
1622 1623 1624 1625 1626
                          _("Bridge generation exceeded max id %d"),
                          MAX_BRIDGE_ID);
    return NULL;
}

1627
int virNetworkSetBridgeName(const virNetworkObjListPtr nets,
1628 1629
                            virNetworkDefPtr def,
                            int check_collision) {
1630 1631 1632

    int ret = -1;

1633
    if (def->bridge && !strstr(def->bridge, "%d")) {
1634 1635 1636 1637 1638
        /* 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)) {
1639 1640 1641
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
                                  _("bridge name '%s' already in use."),
                                  def->bridge);
1642 1643 1644 1645
            goto error;
        }
    } else {
        /* Allocate a bridge name */
1646
        if (!(def->bridge = virNetworkAllocateBridge(nets, def->bridge)))
1647 1648 1649 1650 1651 1652 1653
            goto error;
    }

    ret = 0;
error:
    return ret;
}
1654

1655

1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
void virNetworkSetBridgeMacAddr(virNetworkDefPtr def)
{
    if (!def->mac_specified) {
        /* if the bridge doesn't have a mac address explicitly defined,
         * autogenerate a random one.
         */
        virGenerateMacAddr((unsigned char[]){ 0x52, 0x54, 0 },
                           def->mac);
        def->mac_specified = true;
    }
}

1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
/*
 * virNetworkObjIsDuplicate:
 * @doms : virNetworkObjListPtr to search
 * @def  : virNetworkDefPtr definition of network to lookup
 * @check_active: If true, ensure that network is not active
 *
 * Returns: -1 on error
 *          0 if network is new
 *          1 if network is a duplicate
 */
int
virNetworkObjIsDuplicate(virNetworkObjListPtr doms,
                         virNetworkDefPtr def,
                         unsigned int check_active)
{
    int ret = -1;
    int dupVM = 0;
    virNetworkObjPtr vm = NULL;

    /* See if a VM with matching UUID already exists */
    vm = virNetworkFindByUUID(doms, def->uuid);
    if (vm) {
        /* UUID matches, but if names don't match, refuse it */
        if (STRNEQ(vm->def->name, def->name)) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
            virNetworkReportError(VIR_ERR_OPERATION_FAILED,
                                  _("network '%s' is already defined with uuid %s"),
                                  vm->def->name, uuidstr);
            goto cleanup;
        }

        if (check_active) {
            /* UUID & name match, but if VM is already active, refuse it */
            if (virNetworkObjIsActive(vm)) {
                virNetworkReportError(VIR_ERR_OPERATION_INVALID,
                                      _("network is already active as '%s'"),
                                      vm->def->name);
                goto cleanup;
            }
        }

        dupVM = 1;
    } else {
        /* UUID does not match, but if a name matches, refuse it */
        vm = virNetworkFindByName(doms, def->name);
        if (vm) {
            char uuidstr[VIR_UUID_STRING_BUFLEN];
            virUUIDFormat(vm->def->uuid, uuidstr);
            virNetworkReportError(VIR_ERR_OPERATION_FAILED,
                                  _("network '%s' already exists with uuid %s"),
                                  def->name, uuidstr);
            goto cleanup;
        }
    }

    ret = dupVM;
cleanup:
    if (vm)
        virNetworkObjUnlock(vm);
    return ret;
}


1732 1733
void virNetworkObjLock(virNetworkObjPtr obj)
{
1734
    virMutexLock(&obj->lock);
1735 1736 1737 1738
}

void virNetworkObjUnlock(virNetworkObjPtr obj)
{
1739
    virMutexUnlock(&obj->lock);
D
Daniel P. Berrange 已提交
1740
}