network_conf.c 35.2 KB
Newer Older
1 2 3
/*
 * network_conf.c: network XML handling
 *
4
 * Copyright (C) 2006-2010 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
#include "network.h"
38 39 40 41 42
#include "memory.h"
#include "xml.h"
#include "uuid.h"
#include "util.h"
#include "buf.h"
43
#include "c-ctype.h"
44
#include "files.h"
45

46
#define MAX_BRIDGE_ID 256
47 48
#define VIR_FROM_THIS VIR_FROM_NETWORK

49 50 51 52 53 54
VIR_ENUM_DECL(virNetworkForward)

VIR_ENUM_IMPL(virNetworkForward,
              VIR_NETWORK_FORWARD_LAST,
              "none", "nat", "route" )

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

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

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

    return NULL;
}

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

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

    return NULL;
}


90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
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);
}

107 108
void virNetworkDefFree(virNetworkDefPtr def)
{
109
    int ii;
110 111 112 113 114 115 116

    if (!def)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->bridge);
    VIR_FREE(def->forwardDev);
117
    VIR_FREE(def->domain);
118

119 120
    for (ii = 0 ; ii < def->nips && def->ips ; ii++) {
        virNetworkIpDefClear(&def->ips[ii]);
121
    }
122
    VIR_FREE(def->ips);
123

124 125 126 127 128 129 130 131 132 133 134
    VIR_FREE(def);
}

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

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

135 136
    virMutexDestroy(&net->lock);

137 138 139
    VIR_FREE(net);
}

140 141 142 143 144 145 146 147 148 149 150
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;
}

151
virNetworkObjPtr virNetworkAssignDef(virNetworkObjListPtr nets,
152 153 154 155
                                     const virNetworkDefPtr def)
{
    virNetworkObjPtr network;

156
    if ((network = virNetworkFindByName(nets, def->name))) {
D
Daniel P. Berrange 已提交
157
        if (!virNetworkObjIsActive(network)) {
158 159 160
            virNetworkDefFree(network->def);
            network->def = def;
        } else {
161
            virNetworkDefFree(network->newDef);
162 163 164 165 166 167 168
            network->newDef = def;
        }

        return network;
    }

    if (VIR_ALLOC(network) < 0) {
169
        virReportOOMError();
170 171
        return NULL;
    }
172
    if (virMutexInit(&network->lock) < 0) {
173
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
174 175 176 177
                              "%s", _("cannot initialize mutex"));
        VIR_FREE(network);
        return NULL;
    }
178
    virNetworkObjLock(network);
179 180
    network->def = def;

181
    if (VIR_REALLOC_N(nets->objs, nets->count + 1) < 0) {
182
        virReportOOMError();
183 184 185 186 187 188
        VIR_FREE(network);
        return NULL;
    }

    nets->objs[nets->count] = network;
    nets->count++;
189 190 191 192 193

    return network;

}

194
void virNetworkRemoveInactive(virNetworkObjListPtr nets,
195 196
                              const virNetworkObjPtr net)
{
197
    unsigned int i;
198

199
    virNetworkObjUnlock(net);
200
    for (i = 0 ; i < nets->count ; i++) {
201
        virNetworkObjLock(nets->objs[i]);
202
        if (nets->objs[i] == net) {
203
            virNetworkObjUnlock(nets->objs[i]);
204
            virNetworkObjFree(nets->objs[i]);
205

206 207 208
            if (i < (nets->count - 1))
                memmove(nets->objs + i, nets->objs + i + 1,
                        sizeof(*(nets->objs)) * (nets->count - (i + 1)));
209

210 211 212 213 214 215 216
            if (VIR_REALLOC_N(nets->objs, nets->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            nets->count--;

            break;
        }
217
        virNetworkObjUnlock(nets->objs[i]);
218
    }
219 220
}

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
/* 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++) {
        if (VIR_SOCKET_IS_FAMILY(&def->ips[ii].address, family)
            && (n-- <= 0)) {
            return &def->ips[ii];
        }
    }
    /* failed to find enough of the right family */
    return NULL;
}

L
Laine Stump 已提交
246 247 248
/* return number of 1 bits in netmask for the network's ipAddress,
 * or -1 on error
 */
249
int virNetworkIpDefPrefix(const virNetworkIpDefPtr def)
L
Laine Stump 已提交
250
{
251 252 253
    if (def->prefix > 0) {
        return def->prefix;
    } else if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
L
Laine Stump 已提交
254
        return virSocketGetNumNetmaskBits(&def->netmask);
255
    } else if (VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
L
Laine Stump 已提交
256 257 258 259 260 261
        /* 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
262
            = ntohl(def->address.data.inet4.sin_addr.s_addr) >> 24;
L
Laine Stump 已提交
263 264 265 266 267 268 269 270 271 272 273
        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;
274 275
    } else if (VIR_SOCKET_IS_FAMILY(&def->address, AF_INET6)) {
        return 64;
L
Laine Stump 已提交
276 277 278 279 280 281 282 283
    }
    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)
 */
284 285
int virNetworkIpDefNetmask(const virNetworkIpDefPtr def,
                           virSocketAddrPtr netmask)
L
Laine Stump 已提交
286 287 288 289 290 291
{
    if (VIR_SOCKET_IS_FAMILY(&def->netmask, AF_INET)) {
        *netmask = def->netmask;
        return 0;
    }

292 293
    return virSocketAddrPrefixToNetmask(virNetworkIpDefPrefix(def), netmask,
                                        VIR_SOCKET_FAMILY(&def->address));
L
Laine Stump 已提交
294 295
}

296 297

static int
298 299 300
virNetworkDHCPRangeDefParseXML(virNetworkIpDefPtr def,
                               xmlNodePtr node)
{
301 302 303 304 305

    xmlNodePtr cur;

    cur = node->children;
    while (cur != NULL) {
306 307
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "range")) {
308 309 310
            char *start, *end;
            virSocketAddr saddr, eaddr;
            int range;
311

312
            if (!(start = virXMLPropString(cur, "start"))) {
313 314 315
                cur = cur->next;
                continue;
            }
316 317
            if (!(end = virXMLPropString(cur, "end"))) {
                VIR_FREE(start);
318
                cur = cur->next;
319 320 321
                continue;
            }

322
            if (virSocketParseAddr(start, &saddr, AF_UNSPEC) < 0) {
323 324
                VIR_FREE(start);
                VIR_FREE(end);
325
                return -1;
326
            }
327
            if (virSocketParseAddr(end, &eaddr, AF_UNSPEC) < 0) {
328 329
                VIR_FREE(start);
                VIR_FREE(end);
330
                return -1;
331 332 333 334
            }

            range = virSocketGetRange(&saddr, &eaddr);
            if (range < 0) {
335
                virNetworkReportError(VIR_ERR_XML_ERROR,
336 337
                                      _("dhcp range '%s' to '%s' invalid"),
                                      start, end);
338 339
                VIR_FREE(start);
                VIR_FREE(end);
340
                return -1;
341
            }
E
Eric Blake 已提交
342 343
            VIR_FREE(start);
            VIR_FREE(end);
344

345
            if (VIR_REALLOC_N(def->ranges, def->nranges + 1) < 0) {
346
                virReportOOMError();
347 348
                return -1;
            }
349 350
            def->ranges[def->nranges].start = saddr;
            def->ranges[def->nranges].end = eaddr;
351 352 353
            def->nranges++;
        } else if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "host")) {
354
            char *mac, *name, *ip;
355
            unsigned char addr[6];
356
            virSocketAddr inaddr;
357

358
            mac = virXMLPropString(cur, "mac");
359
            if ((mac != NULL) &&
360
                (virParseMacAddr(mac, &addr[0]) != 0)) {
361
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
362 363 364 365
                                      _("cannot parse MAC address '%s'"),
                                      mac);
                VIR_FREE(mac);
            }
366
            name = virXMLPropString(cur, "name");
367
            if ((name != NULL) && (!c_isalpha(name[0]))) {
368
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
369 370 371 372 373 374 375 376 377 378 379 380 381
                                      _("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;
            }
382 383
            ip = virXMLPropString(cur, "ip");
            if (virSocketParseAddr(ip, &inaddr, AF_UNSPEC) < 0) {
384 385 386 387 388 389
                VIR_FREE(ip);
                VIR_FREE(mac);
                VIR_FREE(name);
                cur = cur->next;
                continue;
            }
E
Eric Blake 已提交
390
            VIR_FREE(ip);
391 392 393
            if (VIR_REALLOC_N(def->hosts, def->nhosts + 1) < 0) {
                VIR_FREE(mac);
                VIR_FREE(name);
394
                virReportOOMError();
395 396
                return -1;
            }
397 398
            def->hosts[def->nhosts].mac = mac;
            def->hosts[def->nhosts].name = name;
399
            def->hosts[def->nhosts].ip = inaddr;
400
            def->nhosts++;
401 402 403

        } else if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "bootp")) {
404 405
            char *file;
            char *server;
406
            virSocketAddr inaddr;
407
            memset(&inaddr, 0, sizeof(inaddr));
408

409
            if (!(file = virXMLPropString(cur, "file"))) {
410 411 412
                cur = cur->next;
                continue;
            }
413
            server = virXMLPropString(cur, "server");
414

415
            if (server &&
E
Eric Blake 已提交
416 417 418
                virSocketParseAddr(server, &inaddr, AF_UNSPEC) < 0) {
                VIR_FREE(file);
                VIR_FREE(server);
419
                return -1;
E
Eric Blake 已提交
420
            }
421

422
            def->bootfile = file;
423
            def->bootserver = inaddr;
E
Eric Blake 已提交
424
            VIR_FREE(server);
425 426 427 428 429 430 431 432
        }

        cur = cur->next;
    }

    return 0;
}

433
static int
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
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) {
        if (virSocketParseAddr(address, &def->address, AF_UNSPEC) < 0) {
            virNetworkReportError(VIR_ERR_XML_ERROR,
                                  _("Bad address '%s' in definition of network '%s'"),
                                  address, networkName);
            goto error;
        }
469

470
    }
471

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
    /* validate family vs. address */
    if (def->family == NULL) {
        if (!(VIR_SOCKET_IS_FAMILY(&def->address, AF_INET) ||
              VIR_SOCKET_IS_FAMILY(&def->address, AF_UNSPEC))) {
            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")) {
        if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
            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")) {
        if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET6)) {
            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;
    }
501

502 503 504 505 506 507 508 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 555 556 557
    /* 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;
        }

        if (!VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
            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;
        }

        if (virSocketParseAddr(netmask, &def->netmask, AF_UNSPEC) < 0)
            goto error;

        if (!VIR_SOCKET_IS_FAMILY(&def->netmask, AF_INET)) {
            virNetworkReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                  _("network '%s' has invalid netmask '%s' for address '%s' (both must be IPv4)"),
                                  networkName, netmask, address);
            goto error;
        }
    }

    if (VIR_SOCKET_IS_FAMILY(&def->address, AF_INET)) {
        /* parse IPv4-related info */
        cur = node->children;
        while (cur != NULL) {
            if (cur->type == XML_ELEMENT_NODE &&
                xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
                result = virNetworkDHCPRangeDefParseXML(def, cur);
                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;
558 559
            }

560
            cur = cur->next;
561
        }
562
    }
563

564 565 566 567 568
    result = 0;

error:
    if (result < 0) {
        virNetworkIpDefClear(def);
569
    }
570 571 572 573 574
    VIR_FREE(address);
    VIR_FREE(netmask);

    ctxt->node = save;
    return result;
575 576
}

577
static virNetworkDefPtr
578
virNetworkDefParseXML(xmlXPathContextPtr ctxt)
579 580 581
{
    virNetworkDefPtr def;
    char *tmp;
582 583
    xmlNodePtr *ipNodes = NULL;
    int nIps;
584 585

    if (VIR_ALLOC(def) < 0) {
586
        virReportOOMError();
587 588 589 590
        return NULL;
    }

    /* Extract network name */
591
    def->name = virXPathString("string(./name[1])", ctxt);
592
    if (!def->name) {
593
        virNetworkReportError(VIR_ERR_NO_NAME, NULL);
594 595 596 597
        goto error;
    }

    /* Extract network uuid */
598
    tmp = virXPathString("string(./uuid[1])", ctxt);
599
    if (!tmp) {
600
        if (virUUIDGenerate(def->uuid)) {
601
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
602
                                  "%s", _("Failed to generate UUID"));
603 604 605 606 607
            goto error;
        }
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
            VIR_FREE(tmp);
608
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
609 610 611 612 613 614
                                  "%s", _("malformed uuid element"));
            goto error;
        }
        VIR_FREE(tmp);
    }

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

618
    /* Parse bridge information */
619 620
    def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt);
    tmp = virXPathString("string(./bridge[1]/@stp)", ctxt);
621 622 623
    def->stp = (tmp && STREQ(tmp, "off")) ? 0 : 1;
    VIR_FREE(tmp);

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

627 628 629
    nIps = virXPathNodeSet("./ip", ctxt, &ipNodes);
    if (nIps > 0) {
        int ii;
630

631 632 633
        /* allocate array to hold all the addrs */
        if (VIR_ALLOC_N(def->ips, nIps) < 0) {
            virReportOOMError();
634 635
            goto error;
        }
636 637 638 639 640 641 642
        /* 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++;
643
        }
644
    }
645

646 647
    /* IPv4 forwarding setup */
    if (virXPathBoolean("count(./forward) > 0", ctxt)) {
648 649 650 651 652
        if (def->nips == 0) {
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
                                  "%s", _("Forwarding requested, but no IP address provided"));
            goto error;
        }
653
        tmp = virXPathString("string(./forward[1]/@mode)", ctxt);
654 655
        if (tmp) {
            if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
656
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
657 658 659 660 661 662 663 664 665 666
                                      _("unknown forwarding type '%s'"), tmp);
                VIR_FREE(tmp);
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->forwardType = VIR_NETWORK_FORWARD_NAT;
        }


667
        def->forwardDev = virXPathString("string(./forward[1]/@dev)", ctxt);
668 669 670 671 672 673 674 675 676 677 678
    } else {
        def->forwardType = VIR_NETWORK_FORWARD_NONE;
    }

    return def;

 error:
    virNetworkDefFree(def);
    return NULL;
}

J
Jiri Denemark 已提交
679 680 681
static virNetworkDefPtr
virNetworkDefParse(const char *xmlStr,
                   const char *filename)
682
{
J
Jiri Denemark 已提交
683
    xmlDocPtr xml;
684
    virNetworkDefPtr def = NULL;
685

J
Jiri Denemark 已提交
686 687 688
    if ((xml = virXMLParse(filename, xmlStr, "network.xml"))) {
        def = virNetworkDefParseNode(xml, xmlDocGetRootElement(xml));
        xmlFreeDoc(xml);
689 690 691 692 693
    }

    return def;
}

J
Jiri Denemark 已提交
694
virNetworkDefPtr virNetworkDefParseString(const char *xmlStr)
695
{
J
Jiri Denemark 已提交
696 697
    return virNetworkDefParse(xmlStr, NULL);
}
698

J
Jiri Denemark 已提交
699 700 701
virNetworkDefPtr virNetworkDefParseFile(const char *filename)
{
    return virNetworkDefParse(NULL, filename);
702 703 704
}


705
virNetworkDefPtr virNetworkDefParseNode(xmlDocPtr xml,
706 707 708 709 710 711
                                        xmlNodePtr root)
{
    xmlXPathContextPtr ctxt = NULL;
    virNetworkDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "network")) {
712
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
713 714 715 716 717 718
                              "%s", _("incorrect root element"));
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
719
        virReportOOMError();
720 721 722 723
        goto cleanup;
    }

    ctxt->node = root;
724
    def = virNetworkDefParseXML(ctxt);
725 726 727 728 729 730

cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
static int
virNetworkIpDefFormat(virBufferPtr buf,
                      const virNetworkIpDefPtr def)
{
    int result = -1;

    virBufferAddLit(buf, "  <ip");

    if (def->family) {
        virBufferVSprintf(buf, " family='%s'", def->family);
    }
    if (VIR_SOCKET_HAS_ADDR(&def->address)) {
        char *addr = virSocketFormatAddr(&def->address);
        if (!addr)
            goto error;
        virBufferVSprintf(buf, " address='%s'", addr);
        VIR_FREE(addr);
    }
    if (VIR_SOCKET_HAS_ADDR(&def->netmask)) {
        char *addr = virSocketFormatAddr(&def->netmask);
        if (!addr)
            goto error;
        virBufferVSprintf(buf, " netmask='%s'", addr);
        VIR_FREE(addr);
    }
    if (def->prefix > 0) {
        virBufferVSprintf(buf," prefix='%u'", def->prefix);
    }
    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++) {
            char *saddr = virSocketFormatAddr(&def->ranges[ii].start);
            if (!saddr)
                goto error;
            char *eaddr = virSocketFormatAddr(&def->ranges[ii].end);
            if (!eaddr) {
                VIR_FREE(saddr);
                goto error;
            }
            virBufferVSprintf(buf, "      <range start='%s' end='%s' />\n",
                              saddr, eaddr);
            VIR_FREE(saddr);
            VIR_FREE(eaddr);
        }
        for (ii = 0 ; ii < def->nhosts ; ii++) {
            virBufferAddLit(buf, "      <host ");
            if (def->hosts[ii].mac)
                virBufferVSprintf(buf, "mac='%s' ", def->hosts[ii].mac);
            if (def->hosts[ii].name)
                virBufferVSprintf(buf, "name='%s' ", def->hosts[ii].name);
            if (VIR_SOCKET_HAS_ADDR(&def->hosts[ii].ip)) {
                char *ipaddr = virSocketFormatAddr(&def->hosts[ii].ip);
                if (!ipaddr)
                    goto error;
                virBufferVSprintf(buf, "ip='%s' ", ipaddr);
                VIR_FREE(ipaddr);
            }
            virBufferAddLit(buf, "/>\n");
        }
        if (def->bootfile) {
            virBufferEscapeString(buf, "      <bootp file='%s' ",
                                  def->bootfile);
            if (VIR_SOCKET_HAS_ADDR(&def->bootserver)) {
                char *ipaddr = virSocketFormatAddr(&def->bootserver);
                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;
}

820
char *virNetworkDefFormat(const virNetworkDefPtr def)
821 822 823 824
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
825
    int ii;
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849

    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);
850
    virBufferVSprintf(&buf, " stp='%s' delay='%ld' />\n",
851 852 853
                      def->stp ? "on" : "off",
                      def->delay);

854 855 856
    if (def->domain)
        virBufferVSprintf(&buf, "  <domain name='%s'/>\n", def->domain);

857 858 859
    for (ii = 0; ii < def->nips; ii++) {
        if (virNetworkIpDefFormat(&buf, &def->ips[ii]) < 0)
            goto error;
860 861 862 863 864 865 866 867 868 869
    }

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

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

 no_memory:
870
    virReportOOMError();
871
  error:
872
    virBufferFreeAndReset(&buf);
873 874 875
    return NULL;
}

876
int virNetworkSaveXML(const char *configDir,
877 878
                      virNetworkDefPtr def,
                      const char *xml)
879
{
880
    char *configFile = NULL;
881 882 883 884
    int fd = -1, ret = -1;
    size_t towrite;
    int err;

885
    if ((configFile = virNetworkConfigFile(configDir, def->name)) == NULL)
886 887 888
        goto cleanup;

    if ((err = virFileMakePath(configDir))) {
889
        virReportSystemError(err,
890 891
                             _("cannot create config directory '%s'"),
                             configDir);
892 893 894
        goto cleanup;
    }

895
    if ((fd = open(configFile,
896 897
                   O_WRONLY | O_CREAT | O_TRUNC,
                   S_IRUSR | S_IWUSR )) < 0) {
898
        virReportSystemError(errno,
899
                             _("cannot create config file '%s'"),
900
                             configFile);
901 902 903 904 905
        goto cleanup;
    }

    towrite = strlen(xml);
    if (safewrite(fd, xml, towrite) < 0) {
906
        virReportSystemError(errno,
907
                             _("cannot write config file '%s'"),
908
                             configFile);
909 910 911
        goto cleanup;
    }

912
    if (VIR_CLOSE(fd) < 0) {
913
        virReportSystemError(errno,
914
                             _("cannot save config file '%s'"),
915
                             configFile);
916 917 918 919 920 921
        goto cleanup;
    }

    ret = 0;

 cleanup:
922
    VIR_FORCE_CLOSE(fd);
923

924 925 926 927 928
    VIR_FREE(configFile);

    return ret;
}

929
int virNetworkSaveConfig(const char *configDir,
930 931 932 933 934
                         virNetworkDefPtr def)
{
    int ret = -1;
    char *xml;

935
    if (!(xml = virNetworkDefFormat(def)))
936 937
        goto cleanup;

938
    if (virNetworkSaveXML(configDir, def, xml))
939 940 941 942 943
        goto cleanup;

    ret = 0;
cleanup:
    VIR_FREE(xml);
944 945 946
    return ret;
}

947

948
virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
949 950
                                      const char *configDir,
                                      const char *autostartDir,
951
                                      const char *name)
952 953 954 955 956 957
{
    char *configFile = NULL, *autostartLink = NULL;
    virNetworkDefPtr def = NULL;
    virNetworkObjPtr net;
    int autostart;

958
    if ((configFile = virNetworkConfigFile(configDir, name)) == NULL)
959
        goto error;
960
    if ((autostartLink = virNetworkConfigFile(autostartDir, name)) == NULL)
961 962 963 964 965
        goto error;

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

966
    if (!(def = virNetworkDefParseFile(configFile)))
967 968
        goto error;

969
    if (!STREQ(name, def->name)) {
970
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
971 972 973 974 975 976
                              _("Network config filename '%s'"
                                " does not match network name '%s'"),
                              configFile, def->name);
        goto error;
    }

977
    /* Generate a bridge if none is specified, but don't check for collisions
978 979
     * if a bridge is hardcoded, so the network is at least defined
     */
980
    if (virNetworkSetBridgeName(nets, def, 0))
981 982
        goto error;

983
    if (!(net = virNetworkAssignDef(nets, def)))
984 985 986
        goto error;

    net->autostart = autostart;
987
    net->persistent = 1;
988

989 990 991
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);

992 993 994 995 996 997 998 999 1000
    return net;

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

1001
int virNetworkLoadAllConfigs(virNetworkObjListPtr nets,
1002 1003 1004 1005 1006 1007 1008 1009 1010
                             const char *configDir,
                             const char *autostartDir)
{
    DIR *dir;
    struct dirent *entry;

    if (!(dir = opendir(configDir))) {
        if (errno == ENOENT)
            return 0;
1011
        virReportSystemError(errno,
1012 1013
                             _("Failed to open dir '%s'"),
                             configDir);
1014 1015 1016 1017
        return -1;
    }

    while ((entry = readdir(dir))) {
1018 1019
        virNetworkObjPtr net;

1020 1021 1022
        if (entry->d_name[0] == '.')
            continue;

1023
        if (!virFileStripSuffix(entry->d_name, ".xml"))
1024 1025 1026 1027
            continue;

        /* NB: ignoring errors, so one malformed config doesn't
           kill the whole process */
1028
        net = virNetworkLoadConfig(nets,
1029 1030 1031 1032 1033
                                   configDir,
                                   autostartDir,
                                   entry->d_name);
        if (net)
            virNetworkObjUnlock(net);
1034 1035 1036 1037 1038 1039 1040
    }

    closedir(dir);

    return 0;
}

1041
int virNetworkDeleteConfig(const char *configDir,
1042
                           const char *autostartDir,
1043 1044
                           virNetworkObjPtr net)
{
1045 1046
    char *configFile = NULL;
    char *autostartLink = NULL;
R
Ryota Ozaki 已提交
1047
    int ret = -1;
1048

1049
    if ((configFile = virNetworkConfigFile(configDir, net->def->name)) == NULL)
1050
        goto error;
1051
    if ((autostartLink = virNetworkConfigFile(autostartDir, net->def->name)) == NULL)
1052
        goto error;
1053 1054

    /* Not fatal if this doesn't work */
1055
    unlink(autostartLink);
1056

1057
    if (unlink(configFile) < 0) {
1058
        virReportSystemError(errno,
1059
                             _("cannot remove config file '%s'"),
1060 1061
                             configFile);
        goto error;
1062 1063
    }

R
Ryota Ozaki 已提交
1064
    ret = 0;
1065 1066 1067 1068

error:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
R
Ryota Ozaki 已提交
1069
    return ret;
1070 1071
}

1072
char *virNetworkConfigFile(const char *dir,
1073 1074 1075 1076 1077
                           const char *name)
{
    char *ret = NULL;

    if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
1078
        virReportOOMError();
1079 1080 1081 1082
        return NULL;
    }

    return ret;
1083
}
D
Daniel P. Berrange 已提交
1084

1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
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;
}

1104
char *virNetworkAllocateBridge(const virNetworkObjListPtr nets,
1105
                               const char *template)
1106 1107 1108 1109 1110
{

    int id = 0;
    char *newname;

1111 1112 1113
    if (!template)
        template = "virbr%d";

1114
    do {
1115 1116 1117 1118 1119
        if (virAsprintf(&newname, template, id) < 0) {
            virReportOOMError();
            return NULL;
        }
        if (!virNetworkBridgeInUse(nets, newname, NULL)) {
1120 1121
            return newname;
        }
1122
        VIR_FREE(newname);
1123 1124

        id++;
1125
    } while (id <= MAX_BRIDGE_ID);
1126

1127
    virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
1128 1129 1130 1131 1132
                          _("Bridge generation exceeded max id %d"),
                          MAX_BRIDGE_ID);
    return NULL;
}

1133
int virNetworkSetBridgeName(const virNetworkObjListPtr nets,
1134 1135
                            virNetworkDefPtr def,
                            int check_collision) {
1136 1137 1138

    int ret = -1;

1139
    if (def->bridge && !strstr(def->bridge, "%d")) {
1140 1141 1142 1143 1144
        /* 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)) {
1145 1146 1147
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
                                  _("bridge name '%s' already in use."),
                                  def->bridge);
1148 1149 1150 1151
            goto error;
        }
    } else {
        /* Allocate a bridge name */
1152
        if (!(def->bridge = virNetworkAllocateBridge(nets, def->bridge)))
1153 1154 1155 1156 1157 1158 1159
            goto error;
    }

    ret = 0;
error:
    return ret;
}
1160

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225

/*
 * 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;
}


1226 1227
void virNetworkObjLock(virNetworkObjPtr obj)
{
1228
    virMutexLock(&obj->lock);
1229 1230 1231 1232
}

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