network_conf.c 28.8 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 26 27
 * 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>

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

36
#include "virterror_internal.h"
37
#include "datatypes.h"
38
#include "network_conf.h"
39
#include "network.h"
40 41 42 43 44
#include "memory.h"
#include "xml.h"
#include "uuid.h"
#include "util.h"
#include "buf.h"
45
#include "c-ctype.h"
46

47
#define MAX_BRIDGE_ID 256
48 49
#define VIR_FROM_THIS VIR_FROM_NETWORK

50 51 52 53 54 55
VIR_ENUM_DECL(virNetworkForward)

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

56
#define virNetworkReportError(code, ...)                                \
57
    virReportErrorHelper(NULL, 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 91 92 93 94 95 96 97 98 99 100 101 102 103

    return NULL;
}


void virNetworkDefFree(virNetworkDefPtr def)
{
    int i;

    if (!def)
        return;

    VIR_FREE(def->name);
    VIR_FREE(def->bridge);
    VIR_FREE(def->forwardDev);
    VIR_FREE(def->ipAddress);
    VIR_FREE(def->network);
    VIR_FREE(def->netmask);
104
    VIR_FREE(def->domain);
105 106 107 108 109 110 111

    for (i = 0 ; i < def->nranges && def->ranges ; i++) {
        VIR_FREE(def->ranges[i].start);
        VIR_FREE(def->ranges[i].end);
    }
    VIR_FREE(def->ranges);

112 113 114 115 116 117 118
    for (i = 0 ; i < def->nhosts && def->hosts ; i++) {
        VIR_FREE(def->hosts[i].mac);
        VIR_FREE(def->hosts[i].ip);
        VIR_FREE(def->hosts[i].name);
    }
    VIR_FREE(def->hosts);

119 120
    VIR_FREE(def->tftproot);
    VIR_FREE(def->bootfile);
121
    VIR_FREE(def->bootserver);
122

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

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

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

134 135
    virMutexDestroy(&net->lock);

136 137 138
    VIR_FREE(net);
}

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

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

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


static int
223
virNetworkDHCPRangeDefParseXML(virNetworkDefPtr def,
224 225 226 227 228 229
                               xmlNodePtr node) {

    xmlNodePtr cur;

    cur = node->children;
    while (cur != NULL) {
230 231
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "range")) {
232 233 234
            char *start, *end;
            virSocketAddr saddr, eaddr;
            int range;
235

236
            if (!(start = (char *) xmlGetProp(cur, BAD_CAST "start"))) {
237 238 239
                cur = cur->next;
                continue;
            }
240 241
            if (!(end = (char *) xmlGetProp(cur, BAD_CAST "end"))) {
                xmlFree(start);
242
                cur = cur->next;
243 244 245 246
                continue;
            }

            if (virSocketParseAddr(start, &saddr, 0) < 0) {
247
                virNetworkReportError(VIR_ERR_XML_ERROR,
248 249 250 251 252 253 254 255
                                      _("cannot parse dhcp start address '%s'"),
                                      start);
                xmlFree(start);
                xmlFree(end);
                cur = cur->next;
                continue;
            }
            if (virSocketParseAddr(end, &eaddr, 0) < 0) {
256
                virNetworkReportError(VIR_ERR_XML_ERROR,
257 258
                                      _("cannot parse dhcp end address '%s'"),
                                      end);
259
                xmlFree(start);
260 261 262 263 264 265 266
                xmlFree(end);
                cur = cur->next;
                continue;
            }

            range = virSocketGetRange(&saddr, &eaddr);
            if (range < 0) {
267
                virNetworkReportError(VIR_ERR_XML_ERROR,
268 269 270 271 272
                                      _("dhcp range '%s' to '%s' invalid"),
                                      start, end);
                xmlFree(start);
                xmlFree(end);
                cur = cur->next;
273 274
                continue;
            }
275

276 277 278
            if (VIR_REALLOC_N(def->ranges, def->nranges + 1) < 0) {
                xmlFree(start);
                xmlFree(end);
279
                virReportOOMError();
280 281 282 283
                return -1;
            }
            def->ranges[def->nranges].start = (char *)start;
            def->ranges[def->nranges].end = (char *)end;
284
            def->ranges[def->nranges].size = range;
285 286 287 288 289 290 291 292 293 294
            def->nranges++;
        } else if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "host")) {
            xmlChar *mac, *name, *ip;
            unsigned char addr[6];
            struct in_addr inaddress;

            mac = xmlGetProp(cur, BAD_CAST "mac");
            if ((mac != NULL) &&
                (virParseMacAddr((const char *) mac, &addr[0]) != 0)) {
295
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
296 297 298 299 300 301
                                      _("cannot parse MAC address '%s'"),
                                      mac);
                VIR_FREE(mac);
            }
            name = xmlGetProp(cur, BAD_CAST "name");
            if ((name != NULL) && (!c_isalpha(name[0]))) {
302
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
                                      _("cannot use name address '%s'"),
                                      name);
                VIR_FREE(name);
            }
            /*
             * You need at least one MAC address or one host name
             */
            if ((mac == NULL) && (name == NULL)) {
                VIR_FREE(mac);
                VIR_FREE(name);
                cur = cur->next;
                continue;
            }
            ip = xmlGetProp(cur, BAD_CAST "ip");
            if (inet_pton(AF_INET, (const char *) ip, &inaddress) <= 0) {
318
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
319 320 321 322 323 324 325 326 327 328 329 330
                                      _("cannot parse IP address '%s'"),
                                      ip);
                VIR_FREE(ip);
                VIR_FREE(mac);
                VIR_FREE(name);
                cur = cur->next;
                continue;
            }
            if (VIR_REALLOC_N(def->hosts, def->nhosts + 1) < 0) {
                VIR_FREE(ip);
                VIR_FREE(mac);
                VIR_FREE(name);
331
                virReportOOMError();
332 333 334 335 336 337
                return -1;
            }
            def->hosts[def->nhosts].mac = (char *)mac;
            def->hosts[def->nhosts].name = (char *)name;
            def->hosts[def->nhosts].ip = (char *)ip;
            def->nhosts++;
338 339 340 341 342 343 344 345 346 347 348

        } else if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "bootp")) {
            xmlChar *file;

            if (!(file = xmlGetProp(cur, BAD_CAST "file"))) {
                cur = cur->next;
                continue;
            }

            def->bootfile = (char *)file;
349
            def->bootserver = (char *) xmlGetProp(cur, BAD_CAST "server");
350 351 352 353 354 355 356 357
        }

        cur = cur->next;
    }

    return 0;
}

358
static int
359
virNetworkIPParseXML(virNetworkDefPtr def,
360 361 362 363 364 365 366
                     xmlNodePtr node) {
    xmlNodePtr cur;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
367
            int result = virNetworkDHCPRangeDefParseXML(def, cur);
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
            if (result)
                return result;

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

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

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

        cur = cur->next;
    }
    return 0;
}

388
static virNetworkDefPtr
389
virNetworkDefParseXML(xmlXPathContextPtr ctxt)
390 391 392 393 394
{
    virNetworkDefPtr def;
    char *tmp;

    if (VIR_ALLOC(def) < 0) {
395
        virReportOOMError();
396 397 398 399
        return NULL;
    }

    /* Extract network name */
400
    def->name = virXPathString("string(./name[1])", ctxt);
401
    if (!def->name) {
402
        virNetworkReportError(VIR_ERR_NO_NAME, NULL);
403 404 405 406
        goto error;
    }

    /* Extract network uuid */
407
    tmp = virXPathString("string(./uuid[1])", ctxt);
408
    if (!tmp) {
409
        if (virUUIDGenerate(def->uuid)) {
410
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
411
                                  "%s", _("Failed to generate UUID"));
412 413 414 415 416
            goto error;
        }
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
            VIR_FREE(tmp);
417
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
418 419 420 421 422 423
                                  "%s", _("malformed uuid element"));
            goto error;
        }
        VIR_FREE(tmp);
    }

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

427
    /* Parse bridge information */
428 429
    def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt);
    tmp = virXPathString("string(./bridge[1]/@stp)", ctxt);
430 431 432
    def->stp = (tmp && STREQ(tmp, "off")) ? 0 : 1;
    VIR_FREE(tmp);

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

436 437
    def->ipAddress = virXPathString("string(./ip[1]/@address)", ctxt);
    def->netmask = virXPathString("string(./ip[1]/@netmask)", ctxt);
438 439 440 441 442
    if (def->ipAddress &&
        def->netmask) {
        /* XXX someday we want IPv6 too, so inet_aton won't work there */
        struct in_addr inaddress, innetmask;
        char *netaddr;
443
        xmlNodePtr ip;
444

445
        if (inet_pton(AF_INET, def->ipAddress, &inaddress) <= 0) {
446
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
447 448 449 450
                                  _("cannot parse IP address '%s'"),
                                  def->ipAddress);
            goto error;
        }
451
        if (inet_pton(AF_INET, def->netmask, &innetmask) <= 0) {
452
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
453 454 455 456 457 458 459 460
                                  _("cannot parse netmask '%s'"),
                                  def->netmask);
            goto error;
        }

        inaddress.s_addr &= innetmask.s_addr;
        netaddr = inet_ntoa(inaddress);

461
        if (virAsprintf(&def->network, "%s/%s", netaddr, def->netmask) < 0) {
462
            virReportOOMError();
463 464 465
            goto error;
        }

466
        if ((ip = virXPathNode("./ip[1]", ctxt)) &&
467
            virNetworkIPParseXML(def, ip) < 0)
468 469 470 471 472
            goto error;
    }


    /* IPv4 forwarding setup */
473
    if (virXPathBoolean("count(./forward) > 0", ctxt)) {
474 475
        if (!def->ipAddress ||
            !def->netmask) {
476
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
477 478 479 480
                                  "%s", _("Forwarding requested, but no IPv4 address/netmask provided"));
            goto error;
        }

481
        tmp = virXPathString("string(./forward[1]/@mode)", ctxt);
482 483
        if (tmp) {
            if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
484
                virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
485 486 487 488 489 490 491 492 493 494
                                      _("unknown forwarding type '%s'"), tmp);
                VIR_FREE(tmp);
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->forwardType = VIR_NETWORK_FORWARD_NAT;
        }


495
        def->forwardDev = virXPathString("string(./forward[1]/@dev)", ctxt);
496 497 498 499 500 501 502 503 504 505 506
    } else {
        def->forwardType = VIR_NETWORK_FORWARD_NONE;
    }

    return def;

 error:
    virNetworkDefFree(def);
    return NULL;
}

507 508 509 510 511 512 513
/* Called from SAX on parsing errors in the XML. */
static void
catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;

    if (ctxt) {
514
        if (virGetLastError() == NULL &&
515 516
            ctxt->lastError.level == XML_ERR_FATAL &&
            ctxt->lastError.message != NULL) {
517 518 519 520
            virNetworkReportError(VIR_ERR_XML_DETAIL,
                                  _("at line %d: %s"),
                                  ctxt->lastError.line,
                                  ctxt->lastError.message);
521 522 523 524
        }
    }
}

525
virNetworkDefPtr virNetworkDefParseString(const char *xmlStr)
526
{
527 528
    xmlParserCtxtPtr pctxt;
    xmlDocPtr xml = NULL;
529
    xmlNodePtr root;
530
    virNetworkDefPtr def = NULL;
531

532 533 534 535 536 537 538 539 540 541
    /* Set up a parser context so we can catch the details of XML errors. */
    pctxt = xmlNewParserCtxt ();
    if (!pctxt || !pctxt->sax)
        goto cleanup;
    pctxt->sax->error = catchXMLError;

    xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr, "network.xml", NULL,
                          XML_PARSE_NOENT | XML_PARSE_NONET |
                          XML_PARSE_NOWARNING);
    if (!xml) {
542 543 544
        if (virGetLastError() == NULL)
            virNetworkReportError(VIR_ERR_XML_ERROR,
                                  "%s", _("failed to parse xml document"));
545
        goto cleanup;
546 547 548
    }

    if ((root = xmlDocGetRootElement(xml)) == NULL) {
549
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
550
                              "%s", _("missing root element"));
551
        goto cleanup;
552 553
    }

554
    def = virNetworkDefParseNode(xml, root);
555

556 557 558
cleanup:
    xmlFreeParserCtxt (pctxt);
    xmlFreeDoc (xml);
559 560 561
    return def;
}

562
virNetworkDefPtr virNetworkDefParseFile(const char *filename)
563
{
564 565
    xmlParserCtxtPtr pctxt;
    xmlDocPtr xml = NULL;
566
    xmlNodePtr root;
567
    virNetworkDefPtr def = NULL;
568

569 570 571 572 573 574 575 576 577 578
    /* Set up a parser context so we can catch the details of XML errors. */
    pctxt = xmlNewParserCtxt ();
    if (!pctxt || !pctxt->sax)
        goto cleanup;
    pctxt->sax->error = catchXMLError;

    xml = xmlCtxtReadFile (pctxt, filename, NULL,
                           XML_PARSE_NOENT | XML_PARSE_NONET |
                           XML_PARSE_NOWARNING);
    if (!xml) {
579 580 581
        if (virGetLastError() == NULL)
            virNetworkReportError(VIR_ERR_XML_ERROR,
                                  "%s", _("failed to parse xml document"));
582
        goto cleanup;
583 584 585
    }

    if ((root = xmlDocGetRootElement(xml)) == NULL) {
586
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
587
                              "%s", _("missing root element"));
588
        goto cleanup;
589 590
    }

591
    def = virNetworkDefParseNode(xml, root);
592

593 594 595
cleanup:
    xmlFreeParserCtxt (pctxt);
    xmlFreeDoc (xml);
596 597 598 599
    return def;
}


600
virNetworkDefPtr virNetworkDefParseNode(xmlDocPtr xml,
601 602 603 604 605 606
                                        xmlNodePtr root)
{
    xmlXPathContextPtr ctxt = NULL;
    virNetworkDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "network")) {
607
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
608 609 610 611 612 613
                              "%s", _("incorrect root element"));
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
614
        virReportOOMError();
615 616 617 618
        goto cleanup;
    }

    ctxt->node = root;
619
    def = virNetworkDefParseXML(ctxt);
620 621 622 623 624 625

cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

626
char *virNetworkDefFormat(const virNetworkDefPtr def)
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 653 654
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    unsigned char *uuid;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

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

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

    if (def->forwardType != VIR_NETWORK_FORWARD_NONE) {
        const char *mode = virNetworkForwardTypeToString(def->forwardType);
        if (mode) {
            if (def->forwardDev) {
                virBufferEscapeString(&buf, "  <forward dev='%s'",
                                      def->forwardDev);
            } else {
                virBufferAddLit(&buf, "  <forward");
            }
            virBufferVSprintf(&buf, " mode='%s'/>\n", mode);
        }
    }

    virBufferAddLit(&buf, "  <bridge");
    if (def->bridge)
        virBufferEscapeString(&buf, " name='%s'", def->bridge);
655
    virBufferVSprintf(&buf, " stp='%s' delay='%ld' />\n",
656 657 658
                      def->stp ? "on" : "off",
                      def->delay);

659 660 661
    if (def->domain)
        virBufferVSprintf(&buf, "  <domain name='%s'/>\n", def->domain);

662 663 664 665 666 667 668 669 670 671 672
    if (def->ipAddress || def->netmask) {
        virBufferAddLit(&buf, "  <ip");

        if (def->ipAddress)
            virBufferVSprintf(&buf, " address='%s'", def->ipAddress);

        if (def->netmask)
            virBufferVSprintf(&buf, " netmask='%s'", def->netmask);

        virBufferAddLit(&buf, ">\n");

673 674 675 676
        if (def->tftproot) {
            virBufferEscapeString(&buf, "    <tftp root='%s' />\n",
                                  def->tftproot);
        }
677
        if ((def->nranges || def->nhosts)) {
678 679 680 681 682
            int i;
            virBufferAddLit(&buf, "    <dhcp>\n");
            for (i = 0 ; i < def->nranges ; i++)
                virBufferVSprintf(&buf, "      <range start='%s' end='%s' />\n",
                                  def->ranges[i].start, def->ranges[i].end);
683 684 685 686 687 688 689 690 691 692
            for (i = 0 ; i < def->nhosts ; i++) {
                virBufferAddLit(&buf, "      <host ");
                if (def->hosts[i].mac)
                    virBufferVSprintf(&buf, "mac='%s' ", def->hosts[i].mac);
                if (def->hosts[i].name)
                    virBufferVSprintf(&buf, "name='%s' ", def->hosts[i].name);
                if (def->hosts[i].ip)
                    virBufferVSprintf(&buf, "ip='%s' ", def->hosts[i].ip);
                virBufferAddLit(&buf, "/>\n");
            }
693
            if (def->bootfile) {
694
                virBufferEscapeString(&buf, "      <bootp file='%s' ",
695
                                      def->bootfile);
696 697 698 699 700
                if (def->bootserver) {
                    virBufferEscapeString(&buf, "server='%s' ",
                                          def->bootserver);
                }
                virBufferAddLit(&buf, "/>\n");
701 702
            }

703 704 705 706 707 708 709 710 711 712 713 714 715 716
            virBufferAddLit(&buf, "    </dhcp>\n");
        }

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

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

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

 no_memory:
717
    virReportOOMError();
718
    virBufferFreeAndReset(&buf);
719 720 721
    return NULL;
}

722
int virNetworkSaveXML(const char *configDir,
723 724
                      virNetworkDefPtr def,
                      const char *xml)
725
{
726
    char *configFile = NULL;
727 728 729 730
    int fd = -1, ret = -1;
    size_t towrite;
    int err;

731
    if ((configFile = virNetworkConfigFile(configDir, def->name)) == NULL)
732 733 734
        goto cleanup;

    if ((err = virFileMakePath(configDir))) {
735
        virReportSystemError(err,
736 737
                             _("cannot create config directory '%s'"),
                             configDir);
738 739 740
        goto cleanup;
    }

741
    if ((fd = open(configFile,
742 743
                   O_WRONLY | O_CREAT | O_TRUNC,
                   S_IRUSR | S_IWUSR )) < 0) {
744
        virReportSystemError(errno,
745
                             _("cannot create config file '%s'"),
746
                             configFile);
747 748 749 750 751
        goto cleanup;
    }

    towrite = strlen(xml);
    if (safewrite(fd, xml, towrite) < 0) {
752
        virReportSystemError(errno,
753
                             _("cannot write config file '%s'"),
754
                             configFile);
755 756 757 758
        goto cleanup;
    }

    if (close(fd) < 0) {
759
        virReportSystemError(errno,
760
                             _("cannot save config file '%s'"),
761
                             configFile);
762 763 764 765 766 767 768 769 770
        goto cleanup;
    }

    ret = 0;

 cleanup:
    if (fd != -1)
        close(fd);

771 772 773 774 775
    VIR_FREE(configFile);

    return ret;
}

776
int virNetworkSaveConfig(const char *configDir,
777 778 779 780 781
                         virNetworkDefPtr def)
{
    int ret = -1;
    char *xml;

782
    if (!(xml = virNetworkDefFormat(def)))
783 784
        goto cleanup;

785
    if (virNetworkSaveXML(configDir, def, xml))
786 787 788 789 790
        goto cleanup;

    ret = 0;
cleanup:
    VIR_FREE(xml);
791 792 793
    return ret;
}

794

795
virNetworkObjPtr virNetworkLoadConfig(virNetworkObjListPtr nets,
796 797
                                      const char *configDir,
                                      const char *autostartDir,
798
                                      const char *name)
799 800 801 802 803 804
{
    char *configFile = NULL, *autostartLink = NULL;
    virNetworkDefPtr def = NULL;
    virNetworkObjPtr net;
    int autostart;

805
    if ((configFile = virNetworkConfigFile(configDir, name)) == NULL)
806
        goto error;
807
    if ((autostartLink = virNetworkConfigFile(autostartDir, name)) == NULL)
808 809 810 811 812
        goto error;

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

813
    if (!(def = virNetworkDefParseFile(configFile)))
814 815
        goto error;

816
    if (!STREQ(name, def->name)) {
817
        virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
818 819 820 821 822 823
                              _("Network config filename '%s'"
                                " does not match network name '%s'"),
                              configFile, def->name);
        goto error;
    }

824
    /* Generate a bridge if none is specified, but don't check for collisions
825 826
     * if a bridge is hardcoded, so the network is at least defined
     */
827
    if (virNetworkSetBridgeName(nets, def, 0))
828 829
        goto error;

830
    if (!(net = virNetworkAssignDef(nets, def)))
831 832 833
        goto error;

    net->autostart = autostart;
834
    net->persistent = 1;
835

836 837 838
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);

839 840 841 842 843 844 845 846 847
    return net;

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

848
int virNetworkLoadAllConfigs(virNetworkObjListPtr nets,
849 850 851 852 853 854 855 856 857
                             const char *configDir,
                             const char *autostartDir)
{
    DIR *dir;
    struct dirent *entry;

    if (!(dir = opendir(configDir))) {
        if (errno == ENOENT)
            return 0;
858
        virReportSystemError(errno,
859 860
                             _("Failed to open dir '%s'"),
                             configDir);
861 862 863 864
        return -1;
    }

    while ((entry = readdir(dir))) {
865 866
        virNetworkObjPtr net;

867 868 869
        if (entry->d_name[0] == '.')
            continue;

870
        if (!virFileStripSuffix(entry->d_name, ".xml"))
871 872 873 874
            continue;

        /* NB: ignoring errors, so one malformed config doesn't
           kill the whole process */
875
        net = virNetworkLoadConfig(nets,
876 877 878 879 880
                                   configDir,
                                   autostartDir,
                                   entry->d_name);
        if (net)
            virNetworkObjUnlock(net);
881 882 883 884 885 886 887
    }

    closedir(dir);

    return 0;
}

888
int virNetworkDeleteConfig(const char *configDir,
889
                           const char *autostartDir,
890 891
                           virNetworkObjPtr net)
{
892 893
    char *configFile = NULL;
    char *autostartLink = NULL;
R
Ryota Ozaki 已提交
894
    int ret = -1;
895

896
    if ((configFile = virNetworkConfigFile(configDir, net->def->name)) == NULL)
897
        goto error;
898
    if ((autostartLink = virNetworkConfigFile(autostartDir, net->def->name)) == NULL)
899
        goto error;
900 901

    /* Not fatal if this doesn't work */
902
    unlink(autostartLink);
903

904
    if (unlink(configFile) < 0) {
905
        virReportSystemError(errno,
906
                             _("cannot remove config file '%s'"),
907 908
                             configFile);
        goto error;
909 910
    }

R
Ryota Ozaki 已提交
911
    ret = 0;
912 913 914 915

error:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
R
Ryota Ozaki 已提交
916
    return ret;
917 918
}

919
char *virNetworkConfigFile(const char *dir,
920 921 922 923 924
                           const char *name)
{
    char *ret = NULL;

    if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
925
        virReportOOMError();
926 927 928 929
        return NULL;
    }

    return ret;
930
}
D
Daniel P. Berrange 已提交
931

932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
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;
}

951
char *virNetworkAllocateBridge(const virNetworkObjListPtr nets,
952
                               const char *template)
953 954 955 956 957
{

    int id = 0;
    char *newname;

958 959 960
    if (!template)
        template = "virbr%d";

961 962 963
    do {
        char try[50];

964
        snprintf(try, sizeof(try), template, id);
965 966 967

        if (!virNetworkBridgeInUse(nets, try, NULL)) {
            if (!(newname = strdup(try))) {
968
                virReportOOMError();
969 970 971 972 973 974
                return NULL;
            }
            return newname;
        }

        id++;
975
    } while (id <= MAX_BRIDGE_ID);
976

977
    virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
978 979 980 981 982
                          _("Bridge generation exceeded max id %d"),
                          MAX_BRIDGE_ID);
    return NULL;
}

983
int virNetworkSetBridgeName(const virNetworkObjListPtr nets,
984 985
                            virNetworkDefPtr def,
                            int check_collision) {
986 987 988

    int ret = -1;

989
    if (def->bridge && !strstr(def->bridge, "%d")) {
990 991 992 993 994
        /* 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)) {
995 996 997
            virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
                                  _("bridge name '%s' already in use."),
                                  def->bridge);
998 999 1000 1001
            goto error;
        }
    } else {
        /* Allocate a bridge name */
1002
        if (!(def->bridge = virNetworkAllocateBridge(nets, def->bridge)))
1003 1004 1005 1006 1007 1008 1009
            goto error;
    }

    ret = 0;
error:
    return ret;
}
1010

1011 1012
void virNetworkObjLock(virNetworkObjPtr obj)
{
1013
    virMutexLock(&obj->lock);
1014 1015 1016 1017
}

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