network_conf.c 28.7 KB
Newer Older
1 2 3
/*
 * network_conf.c: network XML handling
 *
4
 * Copyright (C) 2006-2009 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 28 29
 * Copyright (C) 2006-2008 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */



#include <config.h>

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

36
#include "virterror_internal.h"
37
#include "datatypes.h"
38 39 40 41 42 43
#include "network_conf.h"
#include "memory.h"
#include "xml.h"
#include "uuid.h"
#include "util.h"
#include "buf.h"
44
#include "c-ctype.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(conn, code, fmt...)                            \
56
        virReportErrorHelper(conn, VIR_FROM_NETWORK, code, __FILE__,       \
57
                               __FUNCTION__, __LINE__, fmt)
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 90 91 92 93 94 95 96 97 98 99 100 101 102

    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);
103
    VIR_FREE(def->domain);
104 105 106 107 108 109 110

    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);

111 112 113 114 115 116 117
    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);

118 119 120
    VIR_FREE(def->tftproot);
    VIR_FREE(def->bootfile);

121 122 123 124 125 126 127 128 129 130 131
    VIR_FREE(def);
}

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

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

132 133
    virMutexDestroy(&net->lock);

134 135 136
    VIR_FREE(net);
}

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

148
virNetworkObjPtr virNetworkAssignDef(virConnectPtr conn,
149
                                     virNetworkObjListPtr nets,
150 151 152 153
                                     const virNetworkDefPtr def)
{
    virNetworkObjPtr network;

154
    if ((network = virNetworkFindByName(nets, def->name))) {
155 156 157 158 159 160 161 162 163 164 165 166 167
        if (!virNetworkIsActive(network)) {
            virNetworkDefFree(network->def);
            network->def = def;
        } else {
            if (network->newDef)
                virNetworkDefFree(network->newDef);
            network->newDef = def;
        }

        return network;
    }

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

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

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

    return network;

}

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

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

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

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

            break;
        }
216
        virNetworkObjUnlock(nets->objs[i]);
217
    }
218 219 220 221 222 223 224 225 226 227 228 229
}


static int
virNetworkDHCPRangeDefParseXML(virConnectPtr conn,
                               virNetworkDefPtr def,
                               xmlNodePtr node) {

    xmlNodePtr cur;

    cur = node->children;
    while (cur != NULL) {
230 231 232
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "range")) {
            xmlChar *start, *end;
233

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

244 245 246
            if (VIR_REALLOC_N(def->ranges, def->nranges + 1) < 0) {
                xmlFree(start);
                xmlFree(end);
247
                virReportOOMError(conn);
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
                return -1;
            }
            def->ranges[def->nranges].start = (char *)start;
            def->ranges[def->nranges].end = (char *)end;
            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)) {
                virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                      _("cannot parse MAC address '%s'"),
                                      mac);
                VIR_FREE(mac);
            }
            name = xmlGetProp(cur, BAD_CAST "name");
            if ((name != NULL) && (!c_isalpha(name[0]))) {
                virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                      _("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) {
                virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                      _("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);
298
                virReportOOMError(conn);
299 300 301 302 303 304
                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++;
305 306 307 308 309 310 311 312 313 314 315

        } 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;
316 317 318 319 320 321 322 323
        }

        cur = cur->next;
    }

    return 0;
}

324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
static int
virNetworkIPParseXML(virConnectPtr conn,
                     virNetworkDefPtr def,
                     xmlNodePtr node) {
    xmlNodePtr cur;

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE &&
            xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
            int result = virNetworkDHCPRangeDefParseXML(conn, def, cur);
            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;
}

355 356 357 358 359 360 361 362
static virNetworkDefPtr
virNetworkDefParseXML(virConnectPtr conn,
                      xmlXPathContextPtr ctxt)
{
    virNetworkDefPtr def;
    char *tmp;

    if (VIR_ALLOC(def) < 0) {
363
        virReportOOMError(conn);
364 365 366 367
        return NULL;
    }

    /* Extract network name */
368
    def->name = virXPathString(conn, "string(./name[1])", ctxt);
369 370 371 372 373 374
    if (!def->name) {
        virNetworkReportError(conn, VIR_ERR_NO_NAME, NULL);
        goto error;
    }

    /* Extract network uuid */
375
    tmp = virXPathString(conn, "string(./uuid[1])", ctxt);
376
    if (!tmp) {
377
        if (virUUIDGenerate(def->uuid)) {
378
            virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
379
                                  "%s", _("Failed to generate UUID"));
380 381 382 383 384 385 386 387 388 389 390 391
            goto error;
        }
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
            VIR_FREE(tmp);
            virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                  "%s", _("malformed uuid element"));
            goto error;
        }
        VIR_FREE(tmp);
    }

392 393 394
    /* Parse network domain information */
    def->domain = virXPathString(conn, "string(./domain[1]/@name)", ctxt);

395
    /* Parse bridge information */
396 397
    def->bridge = virXPathString(conn, "string(./bridge[1]/@name)", ctxt);
    tmp = virXPathString(conn, "string(./bridge[1]/@stp)", ctxt);
398 399 400
    def->stp = (tmp && STREQ(tmp, "off")) ? 0 : 1;
    VIR_FREE(tmp);

401
    if (virXPathULong(conn, "string(./bridge[1]/@delay)", ctxt, &def->delay) < 0)
402 403
        def->delay = 0;

404 405
    def->ipAddress = virXPathString(conn, "string(./ip[1]/@address)", ctxt);
    def->netmask = virXPathString(conn, "string(./ip[1]/@netmask)", ctxt);
406 407 408 409 410
    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;
411
        xmlNodePtr ip;
412

413
        if (inet_pton(AF_INET, def->ipAddress, &inaddress) <= 0) {
414 415 416 417 418
            virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                  _("cannot parse IP address '%s'"),
                                  def->ipAddress);
            goto error;
        }
419
        if (inet_pton(AF_INET, def->netmask, &innetmask) <= 0) {
420 421 422 423 424 425 426 427 428
            virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                  _("cannot parse netmask '%s'"),
                                  def->netmask);
            goto error;
        }

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

429
        if (virAsprintf(&def->network, "%s/%s", netaddr, def->netmask) < 0) {
430
            virReportOOMError(conn);
431 432 433
            goto error;
        }

434 435
        if ((ip = virXPathNode(conn, "./ip[1]", ctxt)) &&
            virNetworkIPParseXML(conn, def, ip) < 0)
436 437 438 439 440
            goto error;
    }


    /* IPv4 forwarding setup */
441
    if (virXPathBoolean(conn, "count(./forward) > 0", ctxt)) {
442 443 444 445 446 447 448
        if (!def->ipAddress ||
            !def->netmask) {
            virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                  "%s", _("Forwarding requested, but no IPv4 address/netmask provided"));
            goto error;
        }

449
        tmp = virXPathString(conn, "string(./forward[1]/@mode)", ctxt);
450 451 452 453 454 455 456 457 458 459 460 461 462
        if (tmp) {
            if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
                virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                      _("unknown forwarding type '%s'"), tmp);
                VIR_FREE(tmp);
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->forwardType = VIR_NETWORK_FORWARD_NAT;
        }


463
        def->forwardDev = virXPathString(conn, "string(./forward[1]/@dev)", ctxt);
464 465 466 467 468 469 470 471 472 473 474
    } else {
        def->forwardType = VIR_NETWORK_FORWARD_NONE;
    }

    return def;

 error:
    virNetworkDefFree(def);
    return NULL;
}

475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
/* 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) {
        virConnectPtr conn = ctxt->_private;

        if (conn &&
            conn->err.code == VIR_ERR_NONE &&
            ctxt->lastError.level == XML_ERR_FATAL &&
            ctxt->lastError.message != NULL) {
            virNetworkReportError (conn, VIR_ERR_XML_DETAIL,
                                   _("at line %d: %s"),
                                   ctxt->lastError.line,
                                   ctxt->lastError.message);
        }
    }
}

496 497 498
virNetworkDefPtr virNetworkDefParseString(virConnectPtr conn,
                                          const char *xmlStr)
{
499 500
    xmlParserCtxtPtr pctxt;
    xmlDocPtr xml = NULL;
501
    xmlNodePtr root;
502
    virNetworkDefPtr def = NULL;
503

504 505 506 507 508 509 510 511 512 513 514 515 516 517
    /* 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;
    pctxt->_private = conn;

    if (conn) virResetError (&conn->err);
    xml = xmlCtxtReadDoc (pctxt, BAD_CAST xmlStr, "network.xml", NULL,
                          XML_PARSE_NOENT | XML_PARSE_NONET |
                          XML_PARSE_NOWARNING);
    if (!xml) {
        if (conn && conn->err.code == VIR_ERR_NONE)
              virNetworkReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
518
                                    "%s", _("failed to parse xml document"));
519
        goto cleanup;
520 521 522 523 524
    }

    if ((root = xmlDocGetRootElement(xml)) == NULL) {
        virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("missing root element"));
525
        goto cleanup;
526 527 528 529
    }

    def = virNetworkDefParseNode(conn, xml, root);

530 531 532
cleanup:
    xmlFreeParserCtxt (pctxt);
    xmlFreeDoc (xml);
533 534 535 536 537 538
    return def;
}

virNetworkDefPtr virNetworkDefParseFile(virConnectPtr conn,
                                        const char *filename)
{
539 540
    xmlParserCtxtPtr pctxt;
    xmlDocPtr xml = NULL;
541
    xmlNodePtr root;
542
    virNetworkDefPtr def = NULL;
543

544 545 546 547 548 549 550 551 552 553 554 555 556 557
    /* 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;
    pctxt->_private = conn;

    if (conn) virResetError (&conn->err);
    xml = xmlCtxtReadFile (pctxt, filename, NULL,
                           XML_PARSE_NOENT | XML_PARSE_NONET |
                           XML_PARSE_NOWARNING);
    if (!xml) {
        if (conn && conn->err.code == VIR_ERR_NONE)
              virNetworkReportError(conn, VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
558
                                    "%s", _("failed to parse xml document"));
559
        goto cleanup;
560 561 562 563 564
    }

    if ((root = xmlDocGetRootElement(xml)) == NULL) {
        virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("missing root element"));
565
        goto cleanup;
566 567 568 569
    }

    def = virNetworkDefParseNode(conn, xml, root);

570 571 572
cleanup:
    xmlFreeParserCtxt (pctxt);
    xmlFreeDoc (xml);
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591
    return def;
}


virNetworkDefPtr virNetworkDefParseNode(virConnectPtr conn,
                                        xmlDocPtr xml,
                                        xmlNodePtr root)
{
    xmlXPathContextPtr ctxt = NULL;
    virNetworkDefPtr def = NULL;

    if (!xmlStrEqual(root->name, BAD_CAST "network")) {
        virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              "%s", _("incorrect root element"));
        return NULL;
    }

    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
592
        virReportOOMError(conn);
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
        goto cleanup;
    }

    ctxt->node = root;
    def = virNetworkDefParseXML(conn, ctxt);

cleanup:
    xmlXPathFreeContext(ctxt);
    return def;
}

char *virNetworkDefFormat(virConnectPtr conn,
                          const virNetworkDefPtr def)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    unsigned char *uuid;
    char *tmp;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

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

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

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

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

639 640 641
    if (def->domain)
        virBufferVSprintf(&buf, "  <domain name='%s'/>\n", def->domain);

642 643 644 645 646 647 648 649 650 651 652
    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");

653 654 655 656
        if (def->tftproot) {
            virBufferEscapeString(&buf, "    <tftp root='%s' />\n",
                                  def->tftproot);
        }
657
        if ((def->nranges || def->nhosts)) {
658 659 660 661 662
            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);
663 664 665 666 667 668 669 670 671 672
            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");
            }
673 674 675 676 677
            if (def->bootfile) {
                virBufferEscapeString(&buf, "      <bootp file='%s' />\n",
                                      def->bootfile);
            }

678 679 680 681 682 683 684 685 686 687 688 689 690 691
            virBufferAddLit(&buf, "    </dhcp>\n");
        }

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

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

    if (virBufferError(&buf))
        goto no_memory;

    return virBufferContentAndReset(&buf);

 no_memory:
692
    virReportOOMError(conn);
693 694 695 696 697
    tmp = virBufferContentAndReset(&buf);
    VIR_FREE(tmp);
    return NULL;
}

698 699 700 701
int virNetworkSaveXML(virConnectPtr conn,
                      const char *configDir,
                      virNetworkDefPtr def,
                      const char *xml)
702
{
703
    char *configFile = NULL;
704 705 706 707
    int fd = -1, ret = -1;
    size_t towrite;
    int err;

708
    if ((configFile = virNetworkConfigFile(conn, configDir, def->name)) == NULL)
709 710 711
        goto cleanup;

    if ((err = virFileMakePath(configDir))) {
712 713 714
        virReportSystemError(conn, err,
                             _("cannot create config directory '%s'"),
                             configDir);
715 716 717
        goto cleanup;
    }

718
    if ((fd = open(configFile,
719 720
                   O_WRONLY | O_CREAT | O_TRUNC,
                   S_IRUSR | S_IWUSR )) < 0) {
721 722
        virReportSystemError(conn, errno,
                             _("cannot create config file '%s'"),
723
                             configFile);
724 725 726 727 728
        goto cleanup;
    }

    towrite = strlen(xml);
    if (safewrite(fd, xml, towrite) < 0) {
729 730
        virReportSystemError(conn, errno,
                             _("cannot write config file '%s'"),
731
                             configFile);
732 733 734 735
        goto cleanup;
    }

    if (close(fd) < 0) {
736 737
        virReportSystemError(conn, errno,
                             _("cannot save config file '%s'"),
738
                             configFile);
739 740 741 742 743 744 745 746 747
        goto cleanup;
    }

    ret = 0;

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

748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
    VIR_FREE(configFile);

    return ret;
}

int virNetworkSaveConfig(virConnectPtr conn,
                         const char *configDir,
                         virNetworkDefPtr def)
{
    int ret = -1;
    char *xml;

    if (!(xml = virNetworkDefFormat(conn, def)))
        goto cleanup;

    if (virNetworkSaveXML(conn, configDir, def, xml))
        goto cleanup;

    ret = 0;
cleanup:
    VIR_FREE(xml);
769 770 771
    return ret;
}

772

773
virNetworkObjPtr virNetworkLoadConfig(virConnectPtr conn,
774
                                      virNetworkObjListPtr nets,
775 776
                                      const char *configDir,
                                      const char *autostartDir,
777
                                      const char *name)
778 779 780 781 782 783
{
    char *configFile = NULL, *autostartLink = NULL;
    virNetworkDefPtr def = NULL;
    virNetworkObjPtr net;
    int autostart;

784
    if ((configFile = virNetworkConfigFile(conn, configDir, name)) == NULL)
785
        goto error;
786
    if ((autostartLink = virNetworkConfigFile(conn, autostartDir, name)) == NULL)
787 788 789 790 791
        goto error;

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

792
    if (!(def = virNetworkDefParseFile(conn, configFile)))
793 794
        goto error;

795
    if (!STREQ(name, def->name)) {
796 797 798 799 800 801 802
        virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                              _("Network config filename '%s'"
                                " does not match network name '%s'"),
                              configFile, def->name);
        goto error;
    }

803
    /* Generate a bridge if none is specified, but don't check for collisions
804 805
     * if a bridge is hardcoded, so the network is at least defined
     */
806
    if (virNetworkSetBridgeName(conn, nets, def, 0))
807 808
        goto error;

809 810 811 812
    if (!(net = virNetworkAssignDef(conn, nets, def)))
        goto error;

    net->autostart = autostart;
813
    net->persistent = 1;
814

815 816 817
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);

818 819 820 821 822 823 824 825 826 827
    return net;

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

int virNetworkLoadAllConfigs(virConnectPtr conn,
828
                             virNetworkObjListPtr nets,
829 830 831 832 833 834 835 836 837
                             const char *configDir,
                             const char *autostartDir)
{
    DIR *dir;
    struct dirent *entry;

    if (!(dir = opendir(configDir))) {
        if (errno == ENOENT)
            return 0;
838 839 840
        virReportSystemError(conn, errno,
                             _("Failed to open dir '%s'"),
                             configDir);
841 842 843 844
        return -1;
    }

    while ((entry = readdir(dir))) {
845 846
        virNetworkObjPtr net;

847 848 849
        if (entry->d_name[0] == '.')
            continue;

850
        if (!virFileStripSuffix(entry->d_name, ".xml"))
851 852 853 854
            continue;

        /* NB: ignoring errors, so one malformed config doesn't
           kill the whole process */
855 856 857 858 859 860 861
        net = virNetworkLoadConfig(conn,
                                   nets,
                                   configDir,
                                   autostartDir,
                                   entry->d_name);
        if (net)
            virNetworkObjUnlock(net);
862 863 864 865 866 867 868 869
    }

    closedir(dir);

    return 0;
}

int virNetworkDeleteConfig(virConnectPtr conn,
870 871
                           const char *configDir,
                           const char *autostartDir,
872 873
                           virNetworkObjPtr net)
{
874 875
    char *configFile = NULL;
    char *autostartLink = NULL;
R
Ryota Ozaki 已提交
876
    int ret = -1;
877 878 879 880 881

    if ((configFile = virNetworkConfigFile(conn, configDir, net->def->name)) == NULL)
        goto error;
    if ((autostartLink = virNetworkConfigFile(conn, autostartDir, net->def->name)) == NULL)
        goto error;
882 883

    /* Not fatal if this doesn't work */
884
    unlink(autostartLink);
885

886
    if (unlink(configFile) < 0) {
887 888
        virReportSystemError(conn, errno,
                             _("cannot remove config file '%s'"),
889 890
                             configFile);
        goto error;
891 892
    }

R
Ryota Ozaki 已提交
893
    ret = 0;
894 895 896 897

error:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
R
Ryota Ozaki 已提交
898
    return ret;
899 900 901 902 903 904 905 906 907
}

char *virNetworkConfigFile(virConnectPtr conn,
                           const char *dir,
                           const char *name)
{
    char *ret = NULL;

    if (virAsprintf(&ret, "%s/%s.xml", dir, name) < 0) {
908
        virReportOOMError(conn);
909 910 911 912
        return NULL;
    }

    return ret;
913
}
D
Daniel P. Berrange 已提交
914

915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
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;
}

char *virNetworkAllocateBridge(virConnectPtr conn,
935 936
                               const virNetworkObjListPtr nets,
                               const char *template)
937 938 939 940 941
{

    int id = 0;
    char *newname;

942 943 944
    if (!template)
        template = "virbr%d";

945 946 947
    do {
        char try[50];

948
        snprintf(try, sizeof(try), template, id);
949 950 951 952 953 954 955 956 957 958

        if (!virNetworkBridgeInUse(nets, try, NULL)) {
            if (!(newname = strdup(try))) {
                virReportOOMError(conn);
                return NULL;
            }
            return newname;
        }

        id++;
959
    } while (id <= MAX_BRIDGE_ID);
960 961 962 963 964 965 966 967 968

    virNetworkReportError(conn, VIR_ERR_INTERNAL_ERROR,
                          _("Bridge generation exceeded max id %d"),
                          MAX_BRIDGE_ID);
    return NULL;
}

int virNetworkSetBridgeName(virConnectPtr conn,
                            const virNetworkObjListPtr nets,
969 970
                            virNetworkDefPtr def,
                            int check_collision) {
971 972 973

    int ret = -1;

974
    if (def->bridge && !strstr(def->bridge, "%d")) {
975 976 977 978 979
        /* 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)) {
980 981 982 983 984 985 986
            networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                               _("bridge name '%s' already in use."),
                               def->bridge);
            goto error;
        }
    } else {
        /* Allocate a bridge name */
987
        if (!(def->bridge = virNetworkAllocateBridge(conn, nets, def->bridge)))
988 989 990 991 992 993 994
            goto error;
    }

    ret = 0;
error:
    return ret;
}
995

996 997
void virNetworkObjLock(virNetworkObjPtr obj)
{
998
    virMutexLock(&obj->lock);
999 1000 1001 1002
}

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