bridge_driver.c 48.1 KB
Newer Older
1 2 3
/*
 * driver.c: core driver methods for managing qemu guests
 *
J
Jim Meyering 已提交
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
 * Copyright (C) 2006 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 <sys/types.h>
#include <sys/poll.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/ioctl.h>

47
#include "virterror_internal.h"
48
#include "datatypes.h"
49
#include "bridge_driver.h"
50 51 52 53 54 55 56 57 58
#include "network_conf.h"
#include "driver.h"
#include "event.h"
#include "buf.h"
#include "util.h"
#include "memory.h"
#include "uuid.h"
#include "iptables.h"
#include "bridge.h"
59
#include "logging.h"
60

61 62
#define NETWORK_PID_DIR LOCAL_STATE_DIR "/run/libvirt/network"
#define NETWORK_STATE_DIR LOCAL_STATE_DIR "/lib/libvirt/network"
63 64 65

#define VIR_FROM_THIS VIR_FROM_NETWORK

66 67
/* Main driver state */
struct network_driver {
68
    virMutex lock;
69

70
    virNetworkObjList networks;
71 72 73 74 75 76 77 78

    iptablesContext *iptables;
    brControl *brctl;
    char *networkConfigDir;
    char *networkAutostartDir;
    char *logDir;
};

79 80 81

static void networkDriverLock(struct network_driver *driver)
{
82
    virMutexLock(&driver->lock);
83 84 85
}
static void networkDriverUnlock(struct network_driver *driver)
{
86
    virMutexUnlock(&driver->lock);
87 88
}

89 90 91 92 93 94 95 96 97 98
static int networkShutdown(void);

static int networkStartNetworkDaemon(virConnectPtr conn,
                                   struct network_driver *driver,
                                   virNetworkObjPtr network);

static int networkShutdownNetworkDaemon(virConnectPtr conn,
                                      struct network_driver *driver,
                                      virNetworkObjPtr network);

99 100
static void networkReloadIptablesRules(struct network_driver *driver);

101 102 103
static struct network_driver *driverState = NULL;


104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
static void
networkFindActiveConfigs(struct network_driver *driver) {
    unsigned int i;

    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjPtr obj = driver->networks.objs[i];
        virNetworkDefPtr tmp;
        char *config;

        virNetworkObjLock(obj);

        if ((config = virNetworkConfigFile(NULL,
                                           NETWORK_STATE_DIR,
                                           obj->def->name)) == NULL) {
            virNetworkObjUnlock(obj);
            continue;
        }

        if (access(config, R_OK) < 0) {
            VIR_FREE(config);
            virNetworkObjUnlock(obj);
            continue;
        }

        /* Try and load the live config */
        tmp = virNetworkDefParseFile(NULL, config);
        VIR_FREE(config);
        if (tmp) {
            obj->newDef = obj->def;
            obj->def = tmp;
        }

        /* If bridge exists, then mark it active */
        if (obj->def->bridge &&
            brHasBridge(driver->brctl, obj->def->bridge) == 0) {
            obj->active = 1;

141 142 143
            /* Finally try and read dnsmasq pid if any */
            if ((obj->def->ipAddress ||
                 obj->def->nranges) &&
144 145 146 147 148 149 150 151 152 153
                virFileReadPid(NETWORK_PID_DIR, obj->def->name,
                               &obj->dnsmasqPid) == 0) {

                /* Check its still alive */
                if (kill(obj->dnsmasqPid, 0) != 0)
                    obj->dnsmasqPid = -1;

#ifdef __linux__
                char *pidpath;

154 155 156 157
                if (virAsprintf(&pidpath, "/proc/%d/exe", obj->dnsmasqPid) < 0) {
                    virReportOOMError(NULL);
                    goto cleanup;
                }
158 159 160 161 162 163 164
                if (virFileLinkPointsTo(pidpath, DNSMASQ) == 0)
                    obj->dnsmasqPid = -1;
                VIR_FREE(pidpath);
#endif
            }
        }

165
    cleanup:
166 167 168 169 170
        virNetworkObjUnlock(obj);
    }
}


171 172 173
static void
networkAutostartConfigs(struct network_driver *driver) {
    unsigned int i;
174

175
    for (i = 0 ; i < driver->networks.count ; i++) {
176
        virNetworkObjLock(driver->networks.objs[i]);
177
        if (driver->networks.objs[i]->autostart &&
D
Daniel P. Berrange 已提交
178
            !virNetworkObjIsActive(driver->networks.objs[i]) &&
179
            networkStartNetworkDaemon(NULL, driver, driver->networks.objs[i]) < 0) {
180
            /* failed to start but already logged */
181
        }
182
        virNetworkObjUnlock(driver->networks.objs[i]);
183 184 185 186 187 188 189 190 191
    }
}

/**
 * networkStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
192
networkStartup(int privileged) {
193 194
    uid_t uid = geteuid();
    char *base = NULL;
195
    int err;
196 197

    if (VIR_ALLOC(driverState) < 0)
198
        goto error;
199

200 201 202 203
    if (virMutexInit(&driverState->lock) < 0) {
        VIR_FREE(driverState);
        goto error;
    }
204 205
    networkDriverLock(driverState);

206
    if (privileged) {
207 208
        if (virAsprintf(&driverState->logDir,
                        "%s/log/libvirt/qemu", LOCAL_STATE_DIR) == -1)
209 210 211 212 213
            goto out_of_memory;

        if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
            goto out_of_memory;
    } else {
214 215 216 217
        char *userdir = virGetUserDirectory(NULL, uid);

        if (!userdir)
            goto error;
218

219
        if (virAsprintf(&driverState->logDir,
220 221
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
222
            goto out_of_memory;
223
        }
224

225 226
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
227 228
            goto out_of_memory;
        }
229
        VIR_FREE(userdir);
230 231 232 233 234
    }

    /* Configuration paths are either ~/.libvirt/qemu/... (session) or
     * /etc/libvirt/qemu/... (system).
     */
235
    if (virAsprintf(&driverState->networkConfigDir, "%s/qemu/networks", base) == -1)
236 237
        goto out_of_memory;

238 239
    if (virAsprintf(&driverState->networkAutostartDir, "%s/qemu/networks/autostart",
                    base) == -1)
240 241 242 243
        goto out_of_memory;

    VIR_FREE(base);

244 245 246 247 248 249 250
    if ((err = brInit(&driverState->brctl))) {
        virReportSystemError(NULL, err, "%s",
                             _("cannot initialize bridge support"));
        goto error;
    }

    if (!(driverState->iptables = iptablesContextNew())) {
251
        goto out_of_memory;
252 253 254
    }


255 256 257
    if (virNetworkLoadAllConfigs(NULL,
                                 &driverState->networks,
                                 driverState->networkConfigDir,
258 259 260
                                 driverState->networkAutostartDir) < 0)
        goto error;

261
    networkFindActiveConfigs(driverState);
262 263
    networkAutostartConfigs(driverState);

264 265
    networkDriverUnlock(driverState);

266 267
    return 0;

268
out_of_memory:
269
    virReportOOMError(NULL);
270 271

error:
272 273 274
    if (driverState)
        networkDriverUnlock(driverState);

275
    VIR_FREE(base);
276
    networkShutdown();
277 278 279 280 281 282 283 284 285 286 287
    return -1;
}

/**
 * networkReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
networkReload(void) {
288 289 290
    if (!driverState)
        return 0;

291
    networkDriverLock(driverState);
292 293 294 295
    virNetworkLoadAllConfigs(NULL,
                             &driverState->networks,
                             driverState->networkConfigDir,
                             driverState->networkAutostartDir);
296
    networkReloadIptablesRules(driverState);
297
    networkAutostartConfigs(driverState);
298
    networkDriverUnlock(driverState);
299 300 301 302 303 304 305 306 307 308 309 310 311
    return 0;
}

/**
 * networkActive:
 *
 * Checks if the QEmu daemon is active, i.e. has an active domain or
 * an active network
 *
 * Returns 1 if active, 0 otherwise
 */
static int
networkActive(void) {
312
    unsigned int i;
313
    int active = 0;
314

315 316 317
    if (!driverState)
        return 0;

318
    networkDriverLock(driverState);
319 320
    for (i = 0 ; i < driverState->networks.count ; i++) {
        virNetworkObjPtr net = driverState->networks.objs[i];
321
        virNetworkObjLock(net);
D
Daniel P. Berrange 已提交
322
        if (virNetworkObjIsActive(net))
323
            active = 1;
324
        virNetworkObjUnlock(net);
325
    }
326
    networkDriverUnlock(driverState);
327
    return active;
328 329 330 331 332 333 334 335 336 337 338 339
}

/**
 * networkShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
networkShutdown(void) {
    if (!driverState)
        return -1;

340 341
    networkDriverLock(driverState);

342
    /* free inactive networks */
343
    virNetworkObjListFree(&driverState->networks);
344 345 346 347 348 349 350 351 352 353

    VIR_FREE(driverState->logDir);
    VIR_FREE(driverState->networkConfigDir);
    VIR_FREE(driverState->networkAutostartDir);

    if (driverState->brctl)
        brShutdown(driverState->brctl);
    if (driverState->iptables)
        iptablesContextFree(driverState->iptables);

354
    networkDriverUnlock(driverState);
355
    virMutexDestroy(&driverState->lock);
356

357 358 359 360 361 362 363 364
    VIR_FREE(driverState);

    return 0;
}


static int
networkBuildDnsmasqArgv(virConnectPtr conn,
365 366 367
                        virNetworkObjPtr network,
                        const char *pidfile,
                        const char ***argv) {
368
    int i, len, r;
369
    int nbleases = 0;
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
    char *pidfileArg;
    char buf[1024];

    /*
     * NB, be careful about syntax for dnsmasq options in long format
     *
     * If the flag has a mandatory argument, it can be given using
     * either syntax:
     *
     *     --foo bar
     *     --foo=bar
     *
     * If the flag has a optional argument, it *must* be given using
     * the syntax:
     *
     *     --foo=bar
     *
     * It is hard to determine whether a flag is optional or not,
     * without reading the dnsmasq source :-( The manpages is not
     * very explicit on this
     */
391 392 393 394 395 396

    len =
        1 + /* dnsmasq */
        1 + /* --strict-order */
        1 + /* --bind-interfaces */
        (network->def->domain?2:0) + /* --domain name */
397
        2 + /* --pid-file /var/run/libvirt/network/$NAME.pid */
398 399 400 401 402
        2 + /* --conf-file "" */
        /*2 + *//* --interface virbr0 */
        2 + /* --except-interface lo */
        2 + /* --listen-address 10.0.0.1 */
        (2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
403 404
        /* --dhcp-lease-max=xxx if needed */
        (network->def->nranges ? 0 : 1) +
405 406
        /*  --dhcp-host 01:23:45:67:89:0a,hostname,10.0.0.3 */
        (2 * network->def->nhosts) +
407 408
        /* --enable-tftp --tftp-root /srv/tftp */
        (network->def->tftproot ? 3 : 0) +
409
        /* --dhcp-boot pxeboot.img[,,12.34.56.78] */
410
        (network->def->bootfile ? 2 : 0) +
411 412 413 414 415 416 417 418 419 420
        1;  /* NULL */

    if (VIR_ALLOC_N(*argv, len) < 0)
        goto no_memory;

#define APPEND_ARG(v, n, s) do {     \
        if (!((v)[(n)] = strdup(s))) \
            goto no_memory;          \
    } while (0)

421 422 423
#define APPEND_ARG_LIT(v, n, s) \
        (v)[(n)] = s

424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
    i = 0;

    APPEND_ARG(*argv, i++, DNSMASQ);

    /*
     * Needed to ensure dnsmasq uses same algorithm for processing
     * multiple namedriver entries in /etc/resolv.conf as GLibC.
     */
    APPEND_ARG(*argv, i++, "--strict-order");
    APPEND_ARG(*argv, i++, "--bind-interfaces");

    if (network->def->domain) {
       APPEND_ARG(*argv, i++, "--domain");
       APPEND_ARG(*argv, i++, network->def->domain);
    }

440 441 442
    if (virAsprintf(&pidfileArg, "--pid-file=%s", pidfile) < 0)
        goto no_memory;
    APPEND_ARG_LIT(*argv, i++, pidfileArg);
443

444
    APPEND_ARG(*argv, i++, "--conf-file=");
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
    APPEND_ARG(*argv, i++, "");

    /*
     * XXX does not actually work, due to some kind of
     * race condition setting up ipv6 addresses on the
     * interface. A sleep(10) makes it work, but that's
     * clearly not practical
     *
     * APPEND_ARG(*argv, i++, "--interface");
     * APPEND_ARG(*argv, i++, network->def->bridge);
     */
    APPEND_ARG(*argv, i++, "--listen-address");
    APPEND_ARG(*argv, i++, network->def->ipAddress);

    APPEND_ARG(*argv, i++, "--except-interface");
    APPEND_ARG(*argv, i++, "lo");

    for (r = 0 ; r < network->def->nranges ; r++) {
        snprintf(buf, sizeof(buf), "%s,%s",
                 network->def->ranges[r].start,
                 network->def->ranges[r].end);

        APPEND_ARG(*argv, i++, "--dhcp-range");
        APPEND_ARG(*argv, i++, buf);
469 470 471 472 473 474
        nbleases += network->def->ranges[r].size;
    }

    if (network->def->nranges > 0) {
        snprintf(buf, sizeof(buf), "--dhcp-lease-max=%d", nbleases);
        APPEND_ARG(*argv, i++, buf);
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
    }

    for (r = 0 ; r < network->def->nhosts ; r++) {
        virNetworkDHCPHostDefPtr host = &(network->def->hosts[r]);
        if ((host->mac) && (host->name)) {
            snprintf(buf, sizeof(buf), "%s,%s,%s",
                     host->mac, host->name, host->ip);
        } else if (host->mac) {
            snprintf(buf, sizeof(buf), "%s,%s",
                     host->mac, host->ip);
        } else if (host->name) {
            snprintf(buf, sizeof(buf), "%s,%s",
                     host->name, host->ip);
        } else
            continue;

        APPEND_ARG(*argv, i++, "--dhcp-host");
        APPEND_ARG(*argv, i++, buf);
    }

495 496 497 498 499 500
    if (network->def->tftproot) {
        APPEND_ARG(*argv, i++, "--enable-tftp");
        APPEND_ARG(*argv, i++, "--tftp-root");
        APPEND_ARG(*argv, i++, network->def->tftproot);
    }
    if (network->def->bootfile) {
501 502 503 504 505
        snprintf(buf, sizeof(buf), "%s%s%s",
                 network->def->bootfile,
                 network->def->bootserver ? ",," : "",
                 network->def->bootserver ? network->def->bootserver : "");

506
        APPEND_ARG(*argv, i++, "--dhcp-boot");
507
        APPEND_ARG(*argv, i++, buf);
508 509
    }

510 511 512 513 514 515 516 517 518 519
#undef APPEND_ARG

    return 0;

 no_memory:
    if (argv) {
        for (i = 0; (*argv)[i]; i++)
            VIR_FREE((*argv)[i]);
        VIR_FREE(*argv);
    }
520
    virReportOOMError(conn);
521 522 523 524 525 526 527 528 529
    return -1;
}


static int
dhcpStartDhcpDaemon(virConnectPtr conn,
                    virNetworkObjPtr network)
{
    const char **argv;
530 531 532 533
    char *pidfile;
    int ret = -1, i, err;

    network->dnsmasqPid = -1;
534 535 536 537 538 539 540

    if (network->def->ipAddress == NULL) {
        networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot start dhcp daemon without IP address for server"));
        return -1;
    }

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
    if ((err = virFileMakePath(NETWORK_PID_DIR)) < 0) {
        virReportSystemError(conn, err,
                             _("cannot create directory %s"),
                             NETWORK_PID_DIR);
        return -1;
    }
    if ((err = virFileMakePath(NETWORK_STATE_DIR)) < 0) {
        virReportSystemError(conn, err,
                             _("cannot create directory %s"),
                             NETWORK_STATE_DIR);
        return -1;
    }

    if (!(pidfile = virFilePid(NETWORK_PID_DIR, network->def->name))) {
        virReportOOMError(conn);
        return -1;
    }

559
    argv = NULL;
560 561
    if (networkBuildDnsmasqArgv(conn, network, pidfile, &argv) < 0) {
        VIR_FREE(pidfile);
562
        return -1;
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
    }

    if (virRun(conn, argv, NULL) < 0)
        goto cleanup;

    /*
     * There really is no race here - when dnsmasq daemonizes,
     * its leader process stays around until its child has
     * actually written its pidfile. So by time virRun exits
     * it has waitpid'd and guaranteed the proess has started
     * and written a pid
     */

    if (virFileReadPid(NETWORK_PID_DIR, network->def->name,
                       &network->dnsmasqPid) < 0)
        goto cleanup;
579

580
    ret = 0;
581

582 583
cleanup:
    VIR_FREE(pidfile);
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
    for (i = 0; argv[i]; i++)
        VIR_FREE(argv[i]);
    VIR_FREE(argv);

    return ret;
}

static int
networkAddMasqueradingIptablesRules(virConnectPtr conn,
                      struct network_driver *driver,
                      virNetworkObjPtr network) {
    int err;
    /* allow forwarding packets from the bridge interface */
    if ((err = iptablesAddForwardAllowOut(driver->iptables,
                                          network->def->network,
                                          network->def->bridge,
                                          network->def->forwardDev))) {
601 602 603
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow forwarding from '%s'"),
                             network->def->bridge);
604 605 606 607 608 609 610 611
        goto masqerr1;
    }

    /* allow forwarding packets to the bridge interface if they are part of an existing connection */
    if ((err = iptablesAddForwardAllowRelatedIn(driver->iptables,
                                         network->def->network,
                                         network->def->bridge,
                                         network->def->forwardDev))) {
612 613 614
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow forwarding to '%s'"),
                             network->def->bridge);
615 616 617 618 619 620 621
        goto masqerr2;
    }

    /* enable masquerading */
    if ((err = iptablesAddForwardMasquerade(driver->iptables,
                                            network->def->network,
                                            network->def->forwardDev))) {
622 623 624
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to enable masquerading to '%s'\n"),
                             network->def->forwardDev ? network->def->forwardDev : NULL);
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
        goto masqerr3;
    }

    return 1;

 masqerr3:
    iptablesRemoveForwardAllowRelatedIn(driver->iptables,
                                 network->def->network,
                                 network->def->bridge,
                                 network->def->forwardDev);
 masqerr2:
    iptablesRemoveForwardAllowOut(driver->iptables,
                                  network->def->network,
                                  network->def->bridge,
                                  network->def->forwardDev);
 masqerr1:
    return 0;
}

static int
networkAddRoutingIptablesRules(virConnectPtr conn,
                      struct network_driver *driver,
                      virNetworkObjPtr network) {
    int err;
    /* allow routing packets from the bridge interface */
    if ((err = iptablesAddForwardAllowOut(driver->iptables,
                                          network->def->network,
                                          network->def->bridge,
                                          network->def->forwardDev))) {
654 655 656
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow routing from '%s'"),
                             network->def->bridge);
657 658 659 660 661 662 663 664
        goto routeerr1;
    }

    /* allow routing packets to the bridge interface */
    if ((err = iptablesAddForwardAllowIn(driver->iptables,
                                         network->def->network,
                                         network->def->bridge,
                                         network->def->forwardDev))) {
665 666 667
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow routing to '%s'"),
                             network->def->bridge);
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
        goto routeerr2;
    }

    return 1;


 routeerr2:
    iptablesRemoveForwardAllowOut(driver->iptables,
                                  network->def->network,
                                  network->def->bridge,
                                  network->def->forwardDev);
 routeerr1:
    return 0;
}

static int
networkAddIptablesRules(virConnectPtr conn,
                      struct network_driver *driver,
                      virNetworkObjPtr network) {
    int err;

    /* allow DHCP requests through to dnsmasq */
    if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 67))) {
691 692 693
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow DHCP requests from '%s'"),
                             network->def->bridge);
694 695 696 697
        goto err1;
    }

    if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 67))) {
698 699 700
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow DHCP requests from '%s'"),
                             network->def->bridge);
701 702 703 704 705
        goto err2;
    }

    /* allow DNS requests through to dnsmasq */
    if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 53))) {
706 707 708
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow DNS requests from '%s'"),
                             network->def->bridge);
709 710 711 712
        goto err3;
    }

    if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 53))) {
713 714 715
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow DNS requests from '%s'"),
                             network->def->bridge);
716 717 718 719 720 721 722
        goto err4;
    }


    /* Catch all rules to block forwarding to/from bridges */

    if ((err = iptablesAddForwardRejectOut(driver->iptables, network->def->bridge))) {
723 724 725
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to block outbound traffic from '%s'"),
                             network->def->bridge);
726 727 728 729
        goto err5;
    }

    if ((err = iptablesAddForwardRejectIn(driver->iptables, network->def->bridge))) {
730 731 732
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to block inbound traffic to '%s'"),
                             network->def->bridge);
733 734 735 736 737
        goto err6;
    }

    /* Allow traffic between guests on the same bridge */
    if ((err = iptablesAddForwardAllowCross(driver->iptables, network->def->bridge))) {
738 739 740
        virReportSystemError(conn, err,
                             _("failed to add iptables rule to allow cross bridge traffic on '%s'"),
                             network->def->bridge);
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
        goto err7;
    }


    /* If masquerading is enabled, set up the rules*/
    if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT &&
        !networkAddMasqueradingIptablesRules(conn, driver, network))
        goto err8;
    /* else if routing is enabled, set up the rules*/
    else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE &&
             !networkAddRoutingIptablesRules(conn, driver, network))
        goto err8;

    iptablesSaveRules(driver->iptables);

    return 1;

 err8:
    iptablesRemoveForwardAllowCross(driver->iptables,
                                    network->def->bridge);
 err7:
    iptablesRemoveForwardRejectIn(driver->iptables,
                                  network->def->bridge);
 err6:
    iptablesRemoveForwardRejectOut(driver->iptables,
                                   network->def->bridge);
 err5:
    iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53);
 err4:
    iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53);
 err3:
    iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 67);
 err2:
    iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 67);
 err1:
    return 0;
}

static void
networkRemoveIptablesRules(struct network_driver *driver,
                         virNetworkObjPtr network) {
    if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
783 784 785 786
        if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
            iptablesRemoveForwardMasquerade(driver->iptables,
                                                network->def->network,
                                                network->def->forwardDev);
787 788 789 790
            iptablesRemoveForwardAllowRelatedIn(driver->iptables,
                                                network->def->network,
                                                network->def->bridge,
                                                network->def->forwardDev);
791
        } else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE)
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
            iptablesRemoveForwardAllowIn(driver->iptables,
                                         network->def->network,
                                         network->def->bridge,
                                         network->def->forwardDev);

        iptablesRemoveForwardAllowOut(driver->iptables,
                                      network->def->network,
                                      network->def->bridge,
                                      network->def->forwardDev);
    }
    iptablesRemoveForwardAllowCross(driver->iptables, network->def->bridge);
    iptablesRemoveForwardRejectIn(driver->iptables, network->def->bridge);
    iptablesRemoveForwardRejectOut(driver->iptables, network->def->bridge);
    iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 53);
    iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 53);
    iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 67);
    iptablesRemoveTcpInput(driver->iptables, network->def->bridge, 67);
    iptablesSaveRules(driver->iptables);
}

812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
static void
networkReloadIptablesRules(struct network_driver *driver)
{
    unsigned int i;

    VIR_INFO0(_("Reloading iptables rules"));

    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjLock(driver->networks.objs[i]);

        if (virNetworkObjIsActive(driver->networks.objs[i])) {
            networkRemoveIptablesRules(driver, driver->networks.objs[i]);
            if (!networkAddIptablesRules(NULL, driver, driver->networks.objs[i])) {
                /* failed to add but already logged */
            }
        }

        virNetworkObjUnlock(driver->networks.objs[i]);
    }
}

833
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
834 835 836
static int
networkEnableIpForwarding(void)
{
M
Mark McLoughlin 已提交
837
    return virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n");
838 839
}

840 841 842 843 844 845 846 847 848 849 850 851 852
#define SYSCTL_PATH "/proc/sys"

static int networkDisableIPV6(virConnectPtr conn,
                              virNetworkObjPtr network)
{
    char *field = NULL;
    int ret = -1;

    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/disable_ipv6", network->def->bridge) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }

853 854 855 856 857 858
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        VIR_DEBUG("ipv6 appears to already be disabled on %s", network->def->bridge);
        ret = 0;
        goto cleanup;
    }

859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
    if (virFileWriteStr(field, "1") < 0) {
        virReportSystemError(conn, errno,
                             _("cannot enable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/accept_ra", network->def->bridge) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }

    if (virFileWriteStr(field, "0") < 0) {
        virReportSystemError(conn, errno,
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/autoconf", network->def->bridge) < 0) {
        virReportOOMError(conn);
        goto cleanup;
    }

    if (virFileWriteStr(field, "1") < 0) {
        virReportSystemError(conn, errno,
                             _("cannot enable %s"), field);
        goto cleanup;
    }

    ret = 0;
cleanup:
    VIR_FREE(field);
    return ret;
}

895 896 897 898 899
static int networkStartNetworkDaemon(virConnectPtr conn,
                                   struct network_driver *driver,
                                   virNetworkObjPtr network) {
    int err;

D
Daniel P. Berrange 已提交
900
    if (virNetworkObjIsActive(network)) {
901 902 903 904 905
        networkReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("network is already active"));
        return -1;
    }

906
    if ((err = brAddBridge(driver->brctl, network->def->bridge))) {
907 908 909
        virReportSystemError(conn, err,
                             _("cannot create bridge '%s'"),
                             network->def->bridge);
910 911 912
        return -1;
    }

913 914 915
    if (networkDisableIPV6(conn, network) < 0)
        goto err_delbr;

916 917 918 919 920 921 922 923
    if (brSetForwardDelay(driver->brctl, network->def->bridge, network->def->delay) < 0)
        goto err_delbr;

    if (brSetEnableSTP(driver->brctl, network->def->bridge, network->def->stp ? 1 : 0) < 0)
        goto err_delbr;

    if (network->def->ipAddress &&
        (err = brSetInetAddress(driver->brctl, network->def->bridge, network->def->ipAddress))) {
924 925 926
        virReportSystemError(conn, err,
                             _("cannot set IP address on bridge '%s' to '%s'"),
                             network->def->bridge, network->def->ipAddress);
927 928 929 930 931
        goto err_delbr;
    }

    if (network->def->netmask &&
        (err = brSetInetNetmask(driver->brctl, network->def->bridge, network->def->netmask))) {
932 933 934
        virReportSystemError(conn, err,
                             _("cannot set netmask on bridge '%s' to '%s'"),
                             network->def->bridge, network->def->netmask);
935 936 937
        goto err_delbr;
    }

938
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) {
939 940 941
        virReportSystemError(conn, err,
                             _("failed to bring the bridge '%s' up"),
                             network->def->bridge);
942 943 944 945 946 947 948
        goto err_delbr;
    }

    if (!networkAddIptablesRules(conn, driver, network))
        goto err_delbr1;

    if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE &&
949
        networkEnableIpForwarding() < 0) {
950 951
        virReportSystemError(conn, errno, "%s",
                             _("failed to enable IP forwarding"));
952 953 954
        goto err_delbr2;
    }

955 956
    if ((network->def->ipAddress ||
         network->def->nranges) &&
957 958 959
        dhcpStartDhcpDaemon(conn, network) < 0)
        goto err_delbr2;

960 961 962 963 964 965

    /* Persist the live configuration now we have bridge info  */
    if (virNetworkSaveConfig(conn, NETWORK_STATE_DIR, network->def) < 0) {
        goto err_kill;
    }

966 967 968 969
    network->active = 1;

    return 0;

970 971 972 973 974 975
 err_kill:
    if (network->dnsmasqPid > 0) {
        kill(network->dnsmasqPid, SIGTERM);
        network->dnsmasqPid = -1;
    }

976 977 978 979
 err_delbr2:
    networkRemoveIptablesRules(driver, network);

 err_delbr1:
980
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
981
        char ebuf[1024];
982
        VIR_WARN(_("Failed to bring down bridge '%s' : %s\n"),
983
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
984 985 986 987
    }

 err_delbr:
    if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
988
        char ebuf[1024];
989
        VIR_WARN(_("Failed to delete bridge '%s' : %s\n"),
990
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
991 992 993 994 995 996
    }

    return -1;
}


997 998 999
static int networkShutdownNetworkDaemon(virConnectPtr conn,
                                        struct network_driver *driver,
                                        virNetworkObjPtr network) {
1000
    int err;
1001
    char *stateFile;
1002

1003
    VIR_INFO(_("Shutting down network '%s'\n"), network->def->name);
1004

D
Daniel P. Berrange 已提交
1005
    if (!virNetworkObjIsActive(network))
1006 1007
        return 0;

1008 1009 1010 1011 1012 1013 1014
    stateFile = virNetworkConfigFile(conn, NETWORK_STATE_DIR, network->def->name);
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

1015 1016 1017 1018 1019
    if (network->dnsmasqPid > 0)
        kill(network->dnsmasqPid, SIGTERM);

    networkRemoveIptablesRules(driver, network);

1020
    char ebuf[1024];
1021
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
1022
        VIR_WARN(_("Failed to bring down bridge '%s' : %s\n"),
1023
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1024 1025 1026
    }

    if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
1027
        VIR_WARN(_("Failed to delete bridge '%s' : %s\n"),
1028
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1029 1030
    }

1031
    /* See if its still alive and really really kill it */
1032
    if (network->dnsmasqPid > 0 &&
1033
        (kill(network->dnsmasqPid, 0) == 0))
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
        kill(network->dnsmasqPid, SIGKILL);

    network->dnsmasqPid = -1;
    network->active = 0;

    if (network->newDef) {
        virNetworkDefFree(network->def);
        network->def = network->newDef;
        network->newDef = NULL;
    }

    return 0;
}


1049 1050 1051 1052 1053
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
                                         const unsigned char *uuid) {
    struct network_driver *driver = conn->networkPrivateData;
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;
1054

1055
    networkDriverLock(driver);
1056
    network = virNetworkFindByUUID(&driver->networks, uuid);
1057
    networkDriverUnlock(driver);
1058 1059 1060
    if (!network) {
        networkReportError(conn, NULL, NULL, VIR_ERR_NO_NETWORK,
                         "%s", _("no network with matching uuid"));
1061
        goto cleanup;
1062 1063
    }

1064 1065 1066
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
1067 1068
    if (network)
        virNetworkObjUnlock(network);
1069
    return ret;
1070 1071
}

1072 1073 1074 1075 1076 1077
static virNetworkPtr networkLookupByName(virConnectPtr conn,
                                         const char *name) {
    struct network_driver *driver = conn->networkPrivateData;
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;

1078
    networkDriverLock(driver);
1079
    network = virNetworkFindByName(&driver->networks, name);
1080
    networkDriverUnlock(driver);
1081 1082
    if (!network) {
        networkReportError(conn, NULL, NULL, VIR_ERR_NO_NETWORK,
1083
                         _("no network with matching name '%s'"), name);
1084
        goto cleanup;
1085 1086
    }

1087 1088 1089
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
1090 1091
    if (network)
        virNetworkObjUnlock(network);
1092
    return ret;
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
}

static virDrvOpenStatus networkOpenNetwork(virConnectPtr conn,
                                           virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                           int flags ATTRIBUTE_UNUSED) {
    if (!driverState)
        return VIR_DRV_OPEN_DECLINED;

    conn->networkPrivateData = driverState;
    return VIR_DRV_OPEN_SUCCESS;
}

static int networkCloseNetwork(virConnectPtr conn) {
    conn->networkPrivateData = NULL;
    return 0;
}

static int networkNumNetworks(virConnectPtr conn) {
1111
    int nactive = 0, i;
1112
    struct network_driver *driver = conn->networkPrivateData;
1113

1114 1115 1116
    networkDriverLock(driver);
    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1117
        if (virNetworkObjIsActive(driver->networks.objs[i]))
1118
            nactive++;
1119 1120 1121
        virNetworkObjUnlock(driver->networks.objs[i]);
    }
    networkDriverUnlock(driver);
1122

1123 1124 1125 1126
    return nactive;
}

static int networkListNetworks(virConnectPtr conn, char **const names, int nnames) {
1127
    struct network_driver *driver = conn->networkPrivateData;
1128
    int got = 0, i;
1129

1130
    networkDriverLock(driver);
1131
    for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
1132
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1133
        if (virNetworkObjIsActive(driver->networks.objs[i])) {
1134
            if (!(names[got] = strdup(driver->networks.objs[i]->def->name))) {
1135
                virNetworkObjUnlock(driver->networks.objs[i]);
1136
                virReportOOMError(conn);
1137 1138 1139 1140
                goto cleanup;
            }
            got++;
        }
1141
        virNetworkObjUnlock(driver->networks.objs[i]);
1142
    }
1143 1144
    networkDriverUnlock(driver);

1145 1146 1147
    return got;

 cleanup:
1148
    networkDriverUnlock(driver);
1149 1150 1151 1152 1153 1154
    for (i = 0 ; i < got ; i++)
        VIR_FREE(names[i]);
    return -1;
}

static int networkNumDefinedNetworks(virConnectPtr conn) {
1155
    int ninactive = 0, i;
1156
    struct network_driver *driver = conn->networkPrivateData;
1157

1158 1159 1160
    networkDriverLock(driver);
    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1161
        if (!virNetworkObjIsActive(driver->networks.objs[i]))
1162
            ninactive++;
1163 1164 1165
        virNetworkObjUnlock(driver->networks.objs[i]);
    }
    networkDriverUnlock(driver);
1166

1167 1168 1169 1170
    return ninactive;
}

static int networkListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
1171
    struct network_driver *driver = conn->networkPrivateData;
1172
    int got = 0, i;
1173

1174
    networkDriverLock(driver);
1175
    for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
1176
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1177
        if (!virNetworkObjIsActive(driver->networks.objs[i])) {
1178
            if (!(names[got] = strdup(driver->networks.objs[i]->def->name))) {
1179
                virNetworkObjUnlock(driver->networks.objs[i]);
1180
                virReportOOMError(conn);
1181 1182 1183 1184
                goto cleanup;
            }
            got++;
        }
1185
        virNetworkObjUnlock(driver->networks.objs[i]);
1186
    }
1187
    networkDriverUnlock(driver);
1188 1189 1190
    return got;

 cleanup:
1191
    networkDriverUnlock(driver);
1192 1193 1194 1195 1196
    for (i = 0 ; i < got ; i++)
        VIR_FREE(names[i]);
    return -1;
}

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 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240

static int networkIsActive(virNetworkPtr net)
{
    struct network_driver *driver = net->conn->privateData;
    virNetworkObjPtr obj;
    int ret = -1;

    networkDriverLock(driver);
    obj = virNetworkFindByUUID(&driver->networks, net->uuid);
    networkDriverUnlock(driver);
    if (!obj) {
        networkReportError(net->conn, NULL, NULL, VIR_ERR_NO_NETWORK, NULL);
        goto cleanup;
    }
    ret = virNetworkObjIsActive(obj);

cleanup:
    if (obj)
        virNetworkObjUnlock(obj);
    return ret;
}

static int networkIsPersistent(virNetworkPtr net)
{
    struct network_driver *driver = net->conn->privateData;
    virNetworkObjPtr obj;
    int ret = -1;

    networkDriverLock(driver);
    obj = virNetworkFindByUUID(&driver->networks, net->uuid);
    networkDriverUnlock(driver);
    if (!obj) {
        networkReportError(net->conn, NULL, NULL, VIR_ERR_NO_NETWORK, NULL);
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
        virNetworkObjUnlock(obj);
    return ret;
}


1241
static virNetworkPtr networkCreate(virConnectPtr conn, const char *xml) {
1242
    struct network_driver *driver = conn->networkPrivateData;
1243
    virNetworkDefPtr def;
1244
    virNetworkObjPtr network = NULL;
1245
    virNetworkPtr ret = NULL;
1246

1247 1248
    networkDriverLock(driver);

1249
    if (!(def = virNetworkDefParseString(conn, xml)))
1250
        goto cleanup;
1251

1252
    if (virNetworkSetBridgeName(conn, &driver->networks, def, 1))
1253 1254
        goto cleanup;

1255 1256
    if (!(network = virNetworkAssignDef(conn,
                                        &driver->networks,
1257 1258 1259
                                        def)))
        goto cleanup;
    def = NULL;
1260 1261 1262 1263

    if (networkStartNetworkDaemon(conn, driver, network) < 0) {
        virNetworkRemoveInactive(&driver->networks,
                                 network);
1264
        network = NULL;
1265
        goto cleanup;
1266 1267
    }

1268 1269 1270 1271
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
    virNetworkDefFree(def);
1272 1273 1274
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1275
    return ret;
1276 1277 1278
}

static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
1279
    struct network_driver *driver = conn->networkPrivateData;
1280
    virNetworkDefPtr def;
1281
    virNetworkObjPtr network = NULL;
1282
    virNetworkPtr ret = NULL;
1283

1284 1285
    networkDriverLock(driver);

1286
    if (!(def = virNetworkDefParseString(conn, xml)))
1287
        goto cleanup;
1288

1289
    if (virNetworkSetBridgeName(conn, &driver->networks, def, 1))
1290 1291
        goto cleanup;

1292 1293
    if (!(network = virNetworkAssignDef(conn,
                                        &driver->networks,
1294 1295 1296
                                        def)))
        goto cleanup;
    def = NULL;
1297

1298 1299
    network->persistent = 1;

1300 1301
    if (virNetworkSaveConfig(conn,
                             driver->networkConfigDir,
1302
                             network->newDef ? network->newDef : network->def) < 0) {
1303 1304
        virNetworkRemoveInactive(&driver->networks,
                                 network);
1305
        network = NULL;
1306
        goto cleanup;
1307 1308
    }

1309 1310 1311 1312
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
    virNetworkDefFree(def);
1313 1314 1315
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1316
    return ret;
1317 1318 1319
}

static int networkUndefine(virNetworkPtr net) {
1320
    struct network_driver *driver = net->conn->networkPrivateData;
1321
    virNetworkObjPtr network = NULL;
1322
    int ret = -1;
1323

1324 1325
    networkDriverLock(driver);

1326
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1327
    if (!network) {
1328
        networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
1329 1330
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1331 1332
    }

D
Daniel P. Berrange 已提交
1333
    if (virNetworkObjIsActive(network)) {
1334
        networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
1335 1336
                           "%s", _("network is still active"));
        goto cleanup;
1337 1338
    }

1339 1340 1341 1342
    if (virNetworkDeleteConfig(net->conn,
                               driver->networkConfigDir,
                               driver->networkAutostartDir,
                               network) < 0)
1343
        goto cleanup;
1344 1345 1346

    virNetworkRemoveInactive(&driver->networks,
                             network);
1347
    network = NULL;
1348
    ret = 0;
1349

1350
cleanup:
1351 1352 1353
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1354
    return ret;
1355 1356 1357
}

static int networkStart(virNetworkPtr net) {
1358 1359 1360
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1361

1362
    networkDriverLock(driver);
1363
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1364

1365 1366
    if (!network) {
        networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
1367 1368
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1369 1370
    }

1371 1372 1373
    ret = networkStartNetworkDaemon(net->conn, driver, network);

cleanup:
1374 1375
    if (network)
        virNetworkObjUnlock(network);
1376
    networkDriverUnlock(driver);
1377
    return ret;
1378 1379 1380
}

static int networkDestroy(virNetworkPtr net) {
1381 1382 1383
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1384

1385
    networkDriverLock(driver);
1386
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1387

1388 1389
    if (!network) {
        networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
1390 1391
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1392 1393
    }

D
Daniel P. Berrange 已提交
1394
    if (!virNetworkObjIsActive(network)) {
1395 1396 1397 1398 1399
        networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
                           "%s", _("network is not active"));
        goto cleanup;
    }

1400
    ret = networkShutdownNetworkDaemon(net->conn, driver, network);
1401
    if (!network->persistent) {
1402 1403 1404 1405
        virNetworkRemoveInactive(&driver->networks,
                                 network);
        network = NULL;
    }
1406

1407
cleanup:
1408 1409
    if (network)
        virNetworkObjUnlock(network);
1410
    networkDriverUnlock(driver);
1411 1412 1413 1414
    return ret;
}

static char *networkDumpXML(virNetworkPtr net, int flags ATTRIBUTE_UNUSED) {
1415 1416 1417
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char *ret = NULL;
1418

1419
    networkDriverLock(driver);
1420
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1421 1422
    networkDriverUnlock(driver);

1423 1424
    if (!network) {
        networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
1425 1426
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1427 1428
    }

1429 1430 1431
    ret = virNetworkDefFormat(net->conn, network->def);

cleanup:
1432 1433
    if (network)
        virNetworkObjUnlock(network);
1434
    return ret;
1435 1436 1437
}

static char *networkGetBridgeName(virNetworkPtr net) {
1438 1439 1440 1441
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char *bridge = NULL;

1442
    networkDriverLock(driver);
1443
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1444 1445
    networkDriverUnlock(driver);

1446 1447
    if (!network) {
        networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
1448 1449
                           "%s", _("no network with matching id"));
        goto cleanup;
1450 1451
    }

1452 1453 1454 1455 1456 1457 1458
    if (!(network->def->bridge)) {
        networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' does not have a bridge name."),
                           network->def->name);
        goto cleanup;
    }

1459
    bridge = strdup(network->def->bridge);
1460
    if (!bridge)
1461
        virReportOOMError(net->conn);
1462 1463

cleanup:
1464 1465
    if (network)
        virNetworkObjUnlock(network);
1466 1467 1468 1469 1470
    return bridge;
}

static int networkGetAutostart(virNetworkPtr net,
                             int *autostart) {
1471 1472 1473
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1474

1475
    networkDriverLock(driver);
1476
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1477
    networkDriverUnlock(driver);
1478 1479 1480
    if (!network) {
        networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
                         "%s", _("no network with matching uuid"));
1481
        goto cleanup;
1482 1483 1484
    }

    *autostart = network->autostart;
1485
    ret = 0;
1486

1487
cleanup:
1488 1489
    if (network)
        virNetworkObjUnlock(network);
1490
    return ret;
1491 1492 1493
}

static int networkSetAutostart(virNetworkPtr net,
1494
                               int autostart) {
1495 1496
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
1497
    char *configFile = NULL, *autostartLink = NULL;
1498
    int ret = -1;
1499

1500
    networkDriverLock(driver);
1501
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1502

1503 1504 1505
    if (!network) {
        networkReportError(net->conn, NULL, net, VIR_ERR_INVALID_NETWORK,
                         "%s", _("no network with matching uuid"));
1506
        goto cleanup;
1507 1508
    }

1509 1510 1511 1512 1513 1514
    if (!network->persistent) {
        networkReportError(net->conn, NULL, net, VIR_ERR_INTERNAL_ERROR,
                         "%s", _("cannot set autostart for transient network"));
        goto cleanup;
    }

1515 1516
    autostart = (autostart != 0);

1517
    if (network->autostart != autostart) {
1518 1519 1520 1521 1522
        if ((configFile = virNetworkConfigFile(net->conn, driver->networkConfigDir, network->def->name)) == NULL)
            goto cleanup;
        if ((autostartLink = virNetworkConfigFile(net->conn, driver->networkAutostartDir, network->def->name)) == NULL)
            goto cleanup;

1523
        if (autostart) {
1524
            if (virFileMakePath(driver->networkAutostartDir)) {
1525 1526 1527
                virReportSystemError(net->conn, errno,
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
1528 1529
                goto cleanup;
            }
1530

1531
            if (symlink(configFile, autostartLink) < 0) {
1532 1533
                virReportSystemError(net->conn, errno,
                                     _("Failed to create symlink '%s' to '%s'"),
1534
                                     autostartLink, configFile);
1535 1536 1537
                goto cleanup;
            }
        } else {
1538
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1539 1540
                virReportSystemError(net->conn, errno,
                                     _("Failed to delete symlink '%s'"),
1541
                                     autostartLink);
1542 1543
                goto cleanup;
            }
1544 1545
        }

1546
        network->autostart = autostart;
1547
    }
1548
    ret = 0;
1549

1550
cleanup:
1551 1552
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
1553 1554
    if (network)
        virNetworkObjUnlock(network);
1555
    networkDriverUnlock(driver);
1556
    return ret;
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
}


static virNetworkDriver networkDriver = {
    "Network",
    networkOpenNetwork, /* open */
    networkCloseNetwork, /* close */
    networkNumNetworks, /* numOfNetworks */
    networkListNetworks, /* listNetworks */
    networkNumDefinedNetworks, /* numOfDefinedNetworks */
    networkListDefinedNetworks, /* listDefinedNetworks */
    networkLookupByUUID, /* networkLookupByUUID */
    networkLookupByName, /* networkLookupByName */
    networkCreate, /* networkCreateXML */
    networkDefine, /* networkDefineXML */
    networkUndefine, /* networkUndefine */
    networkStart, /* networkCreate */
    networkDestroy, /* networkDestroy */
    networkDumpXML, /* networkDumpXML */
    networkGetBridgeName, /* networkGetBridgeName */
    networkGetAutostart, /* networkGetAutostart */
    networkSetAutostart, /* networkSetAutostart */
1579 1580
    networkIsActive,
    networkIsPersistent,
1581 1582 1583
};

static virStateDriver networkStateDriver = {
1584
    "Network",
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
    networkStartup,
    networkShutdown,
    networkReload,
    networkActive,
};

int networkRegister(void) {
    virRegisterNetworkDriver(&networkDriver);
    virRegisterStateDriver(&networkStateDriver);
    return 0;
}