bridge_driver.c 46.8 KB
Newer Older
1 2 3
/*
 * driver.c: core driver methods for managing qemu guests
 *
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 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 68 69
#define networkReportError(code, fmt...)                                \
    virReportErrorHelper(NULL, VIR_FROM_NETWORK, code, __FILE__,        \
                         __FUNCTION__, __LINE__, fmt)

70 71
/* Main driver state */
struct network_driver {
72
    virMutex lock;
73

74
    virNetworkObjList networks;
75 76 77 78 79 80 81 82

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

83 84 85

static void networkDriverLock(struct network_driver *driver)
{
86
    virMutexLock(&driver->lock);
87 88 89
}
static void networkDriverUnlock(struct network_driver *driver)
{
90
    virMutexUnlock(&driver->lock);
91 92
}

93 94
static int networkShutdown(void);

95 96
static int networkStartNetworkDaemon(struct network_driver *driver,
                                     virNetworkObjPtr network);
97

98 99
static int networkShutdownNetworkDaemon(struct network_driver *driver,
                                        virNetworkObjPtr network);
100

101 102
static void networkReloadIptablesRules(struct network_driver *driver);

103 104 105
static struct network_driver *driverState = NULL;


106 107 108 109 110 111 112 113 114 115 116
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);

117
        if ((config = virNetworkConfigFile(NETWORK_STATE_DIR,
118 119 120 121 122 123 124 125 126 127 128 129
                                           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 */
130
        tmp = virNetworkDefParseFile(config);
131 132 133 134 135 136 137 138 139 140 141
        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;

142 143 144
            /* Finally try and read dnsmasq pid if any */
            if ((obj->def->ipAddress ||
                 obj->def->nranges) &&
145 146 147 148 149 150 151 152 153 154
                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;

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

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


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

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

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

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

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

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

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

        if (!userdir)
            goto error;
219

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

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

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

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

    VIR_FREE(base);

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

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


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

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

265 266
    networkDriverUnlock(driverState);

267 268
    return 0;

269
out_of_memory:
270
    virReportOOMError();
271 272

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

276
    VIR_FREE(base);
277
    networkShutdown();
278 279 280 281 282 283 284 285 286 287 288
    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) {
289 290 291
    if (!driverState)
        return 0;

292
    networkDriverLock(driverState);
293
    virNetworkLoadAllConfigs(&driverState->networks,
294 295
                             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
    VIR_FREE(driverState);

    return 0;
}


static int
364
networkBuildDnsmasqArgv(virNetworkObjPtr network,
365 366
                        const char *pidfile,
                        const char ***argv) {
367
    int i, len, r;
368
    int nbleases = 0;
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
    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
     */
390 391 392 393 394 395

    len =
        1 + /* dnsmasq */
        1 + /* --strict-order */
        1 + /* --bind-interfaces */
        (network->def->domain?2:0) + /* --domain name */
396
        2 + /* --pid-file /var/run/libvirt/network/$NAME.pid */
397 398 399 400 401
        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 */
402 403
        /* --dhcp-lease-max=xxx if needed */
        (network->def->nranges ? 0 : 1) +
404 405
        /*  --dhcp-host 01:23:45:67:89:0a,hostname,10.0.0.3 */
        (2 * network->def->nhosts) +
406 407
        /* --enable-tftp --tftp-root /srv/tftp */
        (network->def->tftproot ? 3 : 0) +
408
        /* --dhcp-boot pxeboot.img[,,12.34.56.78] */
409
        (network->def->bootfile ? 2 : 0) +
410 411 412 413 414 415 416 417 418 419
        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)

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

423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
    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);
    }

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

443
    APPEND_ARG(*argv, i++, "--conf-file=");
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    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);
468 469 470 471 472 473
        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);
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
    }

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

494 495 496 497 498 499
    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) {
500 501 502 503 504
        snprintf(buf, sizeof(buf), "%s%s%s",
                 network->def->bootfile,
                 network->def->bootserver ? ",," : "",
                 network->def->bootserver ? network->def->bootserver : "");

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

509 510 511 512 513
#undef APPEND_ARG

    return 0;

 no_memory:
514
    if (*argv) {
515 516 517 518
        for (i = 0; (*argv)[i]; i++)
            VIR_FREE((*argv)[i]);
        VIR_FREE(*argv);
    }
519
    virReportOOMError();
520 521 522 523 524
    return -1;
}


static int
525
dhcpStartDhcpDaemon(virNetworkObjPtr network)
526 527
{
    const char **argv;
528 529 530 531
    char *pidfile;
    int ret = -1, i, err;

    network->dnsmasqPid = -1;
532 533

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

L
Laine Stump 已提交
539
    if ((err = virFileMakePath(NETWORK_PID_DIR)) != 0) {
540
        virReportSystemError(err,
541 542 543 544
                             _("cannot create directory %s"),
                             NETWORK_PID_DIR);
        return -1;
    }
L
Laine Stump 已提交
545
    if ((err = virFileMakePath(NETWORK_STATE_DIR)) != 0) {
546
        virReportSystemError(err,
547 548 549 550 551 552
                             _("cannot create directory %s"),
                             NETWORK_STATE_DIR);
        return -1;
    }

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

557
    argv = NULL;
558
    if (networkBuildDnsmasqArgv(network, pidfile, &argv) < 0) {
559
        VIR_FREE(pidfile);
560
        return -1;
561 562
    }

563
    if (virRun(argv, NULL) < 0)
564 565 566 567 568 569 570 571 572 573 574 575 576
        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;
577

578
    ret = 0;
579

580 581
cleanup:
    VIR_FREE(pidfile);
582 583 584 585 586 587 588 589
    for (i = 0; argv[i]; i++)
        VIR_FREE(argv[i]);
    VIR_FREE(argv);

    return ret;
}

static int
590 591
networkAddMasqueradingIptablesRules(struct network_driver *driver,
                                    virNetworkObjPtr network) {
592 593 594 595 596 597
    int err;
    /* allow forwarding packets from the bridge interface */
    if ((err = iptablesAddForwardAllowOut(driver->iptables,
                                          network->def->network,
                                          network->def->bridge,
                                          network->def->forwardDev))) {
598
        virReportSystemError(err,
599 600
                             _("failed to add iptables rule to allow forwarding from '%s'"),
                             network->def->bridge);
601 602 603 604 605 606 607 608
        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))) {
609
        virReportSystemError(err,
610 611
                             _("failed to add iptables rule to allow forwarding to '%s'"),
                             network->def->bridge);
612 613 614 615 616 617 618
        goto masqerr2;
    }

    /* enable masquerading */
    if ((err = iptablesAddForwardMasquerade(driver->iptables,
                                            network->def->network,
                                            network->def->forwardDev))) {
619
        virReportSystemError(err,
620 621
                             _("failed to add iptables rule to enable masquerading to '%s'\n"),
                             network->def->forwardDev ? network->def->forwardDev : NULL);
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
        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
642 643
networkAddRoutingIptablesRules(struct network_driver *driver,
                               virNetworkObjPtr network) {
644 645 646 647 648 649
    int err;
    /* allow routing packets from the bridge interface */
    if ((err = iptablesAddForwardAllowOut(driver->iptables,
                                          network->def->network,
                                          network->def->bridge,
                                          network->def->forwardDev))) {
650
        virReportSystemError(err,
651 652
                             _("failed to add iptables rule to allow routing from '%s'"),
                             network->def->bridge);
653 654 655 656 657 658 659 660
        goto routeerr1;
    }

    /* allow routing packets to the bridge interface */
    if ((err = iptablesAddForwardAllowIn(driver->iptables,
                                         network->def->network,
                                         network->def->bridge,
                                         network->def->forwardDev))) {
661
        virReportSystemError(err,
662 663
                             _("failed to add iptables rule to allow routing to '%s'"),
                             network->def->bridge);
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
        goto routeerr2;
    }

    return 1;


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

static int
680 681
networkAddIptablesRules(struct network_driver *driver,
                        virNetworkObjPtr network) {
682 683 684 685
    int err;

    /* allow DHCP requests through to dnsmasq */
    if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 67))) {
686
        virReportSystemError(err,
687 688
                             _("failed to add iptables rule to allow DHCP requests from '%s'"),
                             network->def->bridge);
689 690 691 692
        goto err1;
    }

    if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 67))) {
693
        virReportSystemError(err,
694 695
                             _("failed to add iptables rule to allow DHCP requests from '%s'"),
                             network->def->bridge);
696 697 698 699 700
        goto err2;
    }

    /* allow DNS requests through to dnsmasq */
    if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 53))) {
701
        virReportSystemError(err,
702 703
                             _("failed to add iptables rule to allow DNS requests from '%s'"),
                             network->def->bridge);
704 705 706 707
        goto err3;
    }

    if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 53))) {
708
        virReportSystemError(err,
709 710
                             _("failed to add iptables rule to allow DNS requests from '%s'"),
                             network->def->bridge);
711 712 713 714 715 716 717
        goto err4;
    }


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

    if ((err = iptablesAddForwardRejectOut(driver->iptables, network->def->bridge))) {
718
        virReportSystemError(err,
719 720
                             _("failed to add iptables rule to block outbound traffic from '%s'"),
                             network->def->bridge);
721 722 723 724
        goto err5;
    }

    if ((err = iptablesAddForwardRejectIn(driver->iptables, network->def->bridge))) {
725
        virReportSystemError(err,
726 727
                             _("failed to add iptables rule to block inbound traffic to '%s'"),
                             network->def->bridge);
728 729 730 731 732
        goto err6;
    }

    /* Allow traffic between guests on the same bridge */
    if ((err = iptablesAddForwardAllowCross(driver->iptables, network->def->bridge))) {
733
        virReportSystemError(err,
734 735
                             _("failed to add iptables rule to allow cross bridge traffic on '%s'"),
                             network->def->bridge);
736 737 738 739 740 741
        goto err7;
    }


    /* If masquerading is enabled, set up the rules*/
    if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT &&
742
        !networkAddMasqueradingIptablesRules(driver, network))
743 744 745
        goto err8;
    /* else if routing is enabled, set up the rules*/
    else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE &&
746
             !networkAddRoutingIptablesRules(driver, network))
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
        goto err8;

    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) {
776 777 778 779
        if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
            iptablesRemoveForwardMasquerade(driver->iptables,
                                                network->def->network,
                                                network->def->forwardDev);
780 781 782 783
            iptablesRemoveForwardAllowRelatedIn(driver->iptables,
                                                network->def->network,
                                                network->def->bridge,
                                                network->def->forwardDev);
784
        } else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE)
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
            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);
}

804 805 806 807 808 809 810 811 812 813 814 815
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]);
816
            if (!networkAddIptablesRules(driver, driver->networks.objs[i])) {
817 818 819 820 821 822 823 824
                /* failed to add but already logged */
            }
        }

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

825
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
826 827 828
static int
networkEnableIpForwarding(void)
{
M
Mark McLoughlin 已提交
829
    return virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n");
830 831
}

832 833
#define SYSCTL_PATH "/proc/sys"

834
static int networkDisableIPV6(virNetworkObjPtr network)
835 836 837 838 839
{
    char *field = NULL;
    int ret = -1;

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

844 845 846 847 848 849
    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;
    }

850
    if (virFileWriteStr(field, "1") < 0) {
851
        virReportSystemError(errno,
852 853 854 855 856 857
                             _("cannot enable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

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

    if (virFileWriteStr(field, "0") < 0) {
863
        virReportSystemError(errno,
864 865 866 867 868 869
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

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

    if (virFileWriteStr(field, "1") < 0) {
875
        virReportSystemError(errno,
876 877 878 879 880 881 882 883 884 885
                             _("cannot enable %s"), field);
        goto cleanup;
    }

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

886 887 888
static int networkStartNetworkDaemon(struct network_driver *driver,
                                     virNetworkObjPtr network)
{
889 890
    int err;

D
Daniel P. Berrange 已提交
891
    if (virNetworkObjIsActive(network)) {
892 893
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("network is already active"));
894 895 896
        return -1;
    }

897
    if ((err = brAddBridge(driver->brctl, network->def->bridge))) {
898
        virReportSystemError(err,
899 900
                             _("cannot create bridge '%s'"),
                             network->def->bridge);
901 902 903
        return -1;
    }

904
    if (networkDisableIPV6(network) < 0)
905 906
        goto err_delbr;

907 908 909 910 911 912 913 914
    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))) {
915
        virReportSystemError(err,
916 917
                             _("cannot set IP address on bridge '%s' to '%s'"),
                             network->def->bridge, network->def->ipAddress);
918 919 920 921 922
        goto err_delbr;
    }

    if (network->def->netmask &&
        (err = brSetInetNetmask(driver->brctl, network->def->bridge, network->def->netmask))) {
923
        virReportSystemError(err,
924 925
                             _("cannot set netmask on bridge '%s' to '%s'"),
                             network->def->bridge, network->def->netmask);
926 927 928
        goto err_delbr;
    }

929
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) {
930
        virReportSystemError(err,
931 932
                             _("failed to bring the bridge '%s' up"),
                             network->def->bridge);
933 934 935
        goto err_delbr;
    }

936
    if (!networkAddIptablesRules(driver, network))
937 938 939
        goto err_delbr1;

    if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE &&
940
        networkEnableIpForwarding() < 0) {
941
        virReportSystemError(errno, "%s",
942
                             _("failed to enable IP forwarding"));
943 944 945
        goto err_delbr2;
    }

946 947
    if ((network->def->ipAddress ||
         network->def->nranges) &&
948
        dhcpStartDhcpDaemon(network) < 0)
949 950
        goto err_delbr2;

951 952

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

957 958 959 960
    network->active = 1;

    return 0;

961 962 963 964 965 966
 err_kill:
    if (network->dnsmasqPid > 0) {
        kill(network->dnsmasqPid, SIGTERM);
        network->dnsmasqPid = -1;
    }

967 968 969 970
 err_delbr2:
    networkRemoveIptablesRules(driver, network);

 err_delbr1:
971
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
972
        char ebuf[1024];
973
        VIR_WARN(_("Failed to bring down bridge '%s' : %s"),
974
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
975 976 977 978
    }

 err_delbr:
    if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
979
        char ebuf[1024];
980
        VIR_WARN(_("Failed to delete bridge '%s' : %s"),
981
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
982 983 984 985 986 987
    }

    return -1;
}


988 989 990
static int networkShutdownNetworkDaemon(struct network_driver *driver,
                                        virNetworkObjPtr network)
{
991
    int err;
992
    char *stateFile;
993

994
    VIR_INFO(_("Shutting down network '%s'"), network->def->name);
995

D
Daniel P. Berrange 已提交
996
    if (!virNetworkObjIsActive(network))
997 998
        return 0;

999
    stateFile = virNetworkConfigFile(NETWORK_STATE_DIR, network->def->name);
1000 1001 1002 1003 1004 1005
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

1006 1007 1008 1009 1010
    if (network->dnsmasqPid > 0)
        kill(network->dnsmasqPid, SIGTERM);

    networkRemoveIptablesRules(driver, network);

1011
    char ebuf[1024];
1012
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
1013
        VIR_WARN(_("Failed to bring down bridge '%s' : %s"),
1014
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1015 1016 1017
    }

    if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
1018
        VIR_WARN(_("Failed to delete bridge '%s' : %s"),
1019
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1020 1021
    }

1022
    /* See if its still alive and really really kill it */
1023
    if (network->dnsmasqPid > 0 &&
1024
        (kill(network->dnsmasqPid, 0) == 0))
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
        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;
}


1040 1041 1042 1043 1044
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
                                         const unsigned char *uuid) {
    struct network_driver *driver = conn->networkPrivateData;
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;
1045

1046
    networkDriverLock(driver);
1047
    network = virNetworkFindByUUID(&driver->networks, uuid);
1048
    networkDriverUnlock(driver);
1049
    if (!network) {
1050 1051
        networkReportError(VIR_ERR_NO_NETWORK,
                           "%s", _("no network with matching uuid"));
1052
        goto cleanup;
1053 1054
    }

1055 1056 1057
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
1058 1059
    if (network)
        virNetworkObjUnlock(network);
1060
    return ret;
1061 1062
}

1063 1064 1065 1066 1067 1068
static virNetworkPtr networkLookupByName(virConnectPtr conn,
                                         const char *name) {
    struct network_driver *driver = conn->networkPrivateData;
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;

1069
    networkDriverLock(driver);
1070
    network = virNetworkFindByName(&driver->networks, name);
1071
    networkDriverUnlock(driver);
1072
    if (!network) {
1073 1074
        networkReportError(VIR_ERR_NO_NETWORK,
                           _("no network with matching name '%s'"), name);
1075
        goto cleanup;
1076 1077
    }

1078 1079 1080
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
1081 1082
    if (network)
        virNetworkObjUnlock(network);
1083
    return ret;
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101
}

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) {
1102
    int nactive = 0, i;
1103
    struct network_driver *driver = conn->networkPrivateData;
1104

1105 1106 1107
    networkDriverLock(driver);
    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1108
        if (virNetworkObjIsActive(driver->networks.objs[i]))
1109
            nactive++;
1110 1111 1112
        virNetworkObjUnlock(driver->networks.objs[i]);
    }
    networkDriverUnlock(driver);
1113

1114 1115 1116 1117
    return nactive;
}

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

1121
    networkDriverLock(driver);
1122
    for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
1123
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1124
        if (virNetworkObjIsActive(driver->networks.objs[i])) {
1125
            if (!(names[got] = strdup(driver->networks.objs[i]->def->name))) {
1126
                virNetworkObjUnlock(driver->networks.objs[i]);
1127
                virReportOOMError();
1128 1129 1130 1131
                goto cleanup;
            }
            got++;
        }
1132
        virNetworkObjUnlock(driver->networks.objs[i]);
1133
    }
1134 1135
    networkDriverUnlock(driver);

1136 1137 1138
    return got;

 cleanup:
1139
    networkDriverUnlock(driver);
1140 1141 1142 1143 1144 1145
    for (i = 0 ; i < got ; i++)
        VIR_FREE(names[i]);
    return -1;
}

static int networkNumDefinedNetworks(virConnectPtr conn) {
1146
    int ninactive = 0, i;
1147
    struct network_driver *driver = conn->networkPrivateData;
1148

1149 1150 1151
    networkDriverLock(driver);
    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1152
        if (!virNetworkObjIsActive(driver->networks.objs[i]))
1153
            ninactive++;
1154 1155 1156
        virNetworkObjUnlock(driver->networks.objs[i]);
    }
    networkDriverUnlock(driver);
1157

1158 1159 1160 1161
    return ninactive;
}

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

1165
    networkDriverLock(driver);
1166
    for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
1167
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1168
        if (!virNetworkObjIsActive(driver->networks.objs[i])) {
1169
            if (!(names[got] = strdup(driver->networks.objs[i]->def->name))) {
1170
                virNetworkObjUnlock(driver->networks.objs[i]);
1171
                virReportOOMError();
1172 1173 1174 1175
                goto cleanup;
            }
            got++;
        }
1176
        virNetworkObjUnlock(driver->networks.objs[i]);
1177
    }
1178
    networkDriverUnlock(driver);
1179 1180 1181
    return got;

 cleanup:
1182
    networkDriverUnlock(driver);
1183 1184 1185 1186 1187
    for (i = 0 ; i < got ; i++)
        VIR_FREE(names[i]);
    return -1;
}

1188 1189 1190

static int networkIsActive(virNetworkPtr net)
{
1191
    struct network_driver *driver = net->conn->networkPrivateData;
1192 1193 1194 1195 1196 1197 1198
    virNetworkObjPtr obj;
    int ret = -1;

    networkDriverLock(driver);
    obj = virNetworkFindByUUID(&driver->networks, net->uuid);
    networkDriverUnlock(driver);
    if (!obj) {
1199
        networkReportError(VIR_ERR_NO_NETWORK, NULL);
1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
        goto cleanup;
    }
    ret = virNetworkObjIsActive(obj);

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

static int networkIsPersistent(virNetworkPtr net)
{
1212
    struct network_driver *driver = net->conn->networkPrivateData;
1213 1214 1215 1216 1217 1218 1219
    virNetworkObjPtr obj;
    int ret = -1;

    networkDriverLock(driver);
    obj = virNetworkFindByUUID(&driver->networks, net->uuid);
    networkDriverUnlock(driver);
    if (!obj) {
1220
        networkReportError(VIR_ERR_NO_NETWORK, NULL);
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
        goto cleanup;
    }
    ret = obj->persistent;

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


1232
static virNetworkPtr networkCreate(virConnectPtr conn, const char *xml) {
1233
    struct network_driver *driver = conn->networkPrivateData;
1234
    virNetworkDefPtr def;
1235
    virNetworkObjPtr network = NULL;
1236
    virNetworkPtr ret = NULL;
1237

1238 1239
    networkDriverLock(driver);

1240
    if (!(def = virNetworkDefParseString(xml)))
1241
        goto cleanup;
1242

1243
    if (virNetworkSetBridgeName(&driver->networks, def, 1))
1244 1245
        goto cleanup;

1246
    if (!(network = virNetworkAssignDef(&driver->networks,
1247 1248 1249
                                        def)))
        goto cleanup;
    def = NULL;
1250

1251
    if (networkStartNetworkDaemon(driver, network) < 0) {
1252 1253
        virNetworkRemoveInactive(&driver->networks,
                                 network);
1254
        network = NULL;
1255
        goto cleanup;
1256 1257
    }

1258 1259 1260 1261
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
    virNetworkDefFree(def);
1262 1263 1264
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1265
    return ret;
1266 1267 1268
}

static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
1269
    struct network_driver *driver = conn->networkPrivateData;
1270
    virNetworkDefPtr def;
1271
    virNetworkObjPtr network = NULL;
1272
    virNetworkPtr ret = NULL;
1273

1274 1275
    networkDriverLock(driver);

1276
    if (!(def = virNetworkDefParseString(xml)))
1277
        goto cleanup;
1278

1279
    if (virNetworkSetBridgeName(&driver->networks, def, 1))
1280 1281
        goto cleanup;

1282
    if (!(network = virNetworkAssignDef(&driver->networks,
1283 1284 1285
                                        def)))
        goto cleanup;
    def = NULL;
1286

1287 1288
    network->persistent = 1;

1289
    if (virNetworkSaveConfig(driver->networkConfigDir,
1290
                             network->newDef ? network->newDef : network->def) < 0) {
1291 1292
        virNetworkRemoveInactive(&driver->networks,
                                 network);
1293
        network = NULL;
1294
        goto cleanup;
1295 1296
    }

1297 1298 1299 1300
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
    virNetworkDefFree(def);
1301 1302 1303
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1304
    return ret;
1305 1306 1307
}

static int networkUndefine(virNetworkPtr net) {
1308
    struct network_driver *driver = net->conn->networkPrivateData;
1309
    virNetworkObjPtr network = NULL;
1310
    int ret = -1;
1311

1312 1313
    networkDriverLock(driver);

1314
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1315
    if (!network) {
1316
        networkReportError(VIR_ERR_INVALID_NETWORK,
1317 1318
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1319 1320
    }

D
Daniel P. Berrange 已提交
1321
    if (virNetworkObjIsActive(network)) {
1322
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1323 1324
                           "%s", _("network is still active"));
        goto cleanup;
1325 1326
    }

1327
    if (virNetworkDeleteConfig(driver->networkConfigDir,
1328 1329
                               driver->networkAutostartDir,
                               network) < 0)
1330
        goto cleanup;
1331 1332 1333

    virNetworkRemoveInactive(&driver->networks,
                             network);
1334
    network = NULL;
1335
    ret = 0;
1336

1337
cleanup:
1338 1339 1340
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1341
    return ret;
1342 1343 1344
}

static int networkStart(virNetworkPtr net) {
1345 1346 1347
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1348

1349
    networkDriverLock(driver);
1350
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1351

1352
    if (!network) {
1353
        networkReportError(VIR_ERR_INVALID_NETWORK,
1354 1355
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1356 1357
    }

1358
    ret = networkStartNetworkDaemon(driver, network);
1359 1360

cleanup:
1361 1362
    if (network)
        virNetworkObjUnlock(network);
1363
    networkDriverUnlock(driver);
1364
    return ret;
1365 1366 1367
}

static int networkDestroy(virNetworkPtr net) {
1368 1369 1370
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1371

1372
    networkDriverLock(driver);
1373
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1374

1375
    if (!network) {
1376
        networkReportError(VIR_ERR_INVALID_NETWORK,
1377 1378
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1379 1380
    }

D
Daniel P. Berrange 已提交
1381
    if (!virNetworkObjIsActive(network)) {
1382
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1383 1384 1385 1386
                           "%s", _("network is not active"));
        goto cleanup;
    }

1387
    ret = networkShutdownNetworkDaemon(driver, network);
1388
    if (!network->persistent) {
1389 1390 1391 1392
        virNetworkRemoveInactive(&driver->networks,
                                 network);
        network = NULL;
    }
1393

1394
cleanup:
1395 1396
    if (network)
        virNetworkObjUnlock(network);
1397
    networkDriverUnlock(driver);
1398 1399 1400 1401
    return ret;
}

static char *networkDumpXML(virNetworkPtr net, int flags ATTRIBUTE_UNUSED) {
1402 1403 1404
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char *ret = NULL;
1405

1406
    networkDriverLock(driver);
1407
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1408 1409
    networkDriverUnlock(driver);

1410
    if (!network) {
1411
        networkReportError(VIR_ERR_INVALID_NETWORK,
1412 1413
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1414 1415
    }

1416
    ret = virNetworkDefFormat(network->def);
1417 1418

cleanup:
1419 1420
    if (network)
        virNetworkObjUnlock(network);
1421
    return ret;
1422 1423 1424
}

static char *networkGetBridgeName(virNetworkPtr net) {
1425 1426 1427 1428
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char *bridge = NULL;

1429
    networkDriverLock(driver);
1430
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1431 1432
    networkDriverUnlock(driver);

1433
    if (!network) {
1434
        networkReportError(VIR_ERR_INVALID_NETWORK,
1435 1436
                           "%s", _("no network with matching id"));
        goto cleanup;
1437 1438
    }

1439
    if (!(network->def->bridge)) {
1440
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1441 1442 1443 1444 1445
                           _("network '%s' does not have a bridge name."),
                           network->def->name);
        goto cleanup;
    }

1446
    bridge = strdup(network->def->bridge);
1447
    if (!bridge)
1448
        virReportOOMError();
1449 1450

cleanup:
1451 1452
    if (network)
        virNetworkObjUnlock(network);
1453 1454 1455 1456 1457
    return bridge;
}

static int networkGetAutostart(virNetworkPtr net,
                             int *autostart) {
1458 1459 1460
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1461

1462
    networkDriverLock(driver);
1463
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1464
    networkDriverUnlock(driver);
1465
    if (!network) {
1466 1467
        networkReportError(VIR_ERR_INVALID_NETWORK,
                           "%s", _("no network with matching uuid"));
1468
        goto cleanup;
1469 1470 1471
    }

    *autostart = network->autostart;
1472
    ret = 0;
1473

1474
cleanup:
1475 1476
    if (network)
        virNetworkObjUnlock(network);
1477
    return ret;
1478 1479 1480
}

static int networkSetAutostart(virNetworkPtr net,
1481
                               int autostart) {
1482 1483
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
1484
    char *configFile = NULL, *autostartLink = NULL;
1485
    int ret = -1;
1486

1487
    networkDriverLock(driver);
1488
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1489

1490
    if (!network) {
1491 1492
        networkReportError(VIR_ERR_INVALID_NETWORK,
                           "%s", _("no network with matching uuid"));
1493
        goto cleanup;
1494 1495
    }

1496
    if (!network->persistent) {
1497 1498
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot set autostart for transient network"));
1499 1500 1501
        goto cleanup;
    }

1502 1503
    autostart = (autostart != 0);

1504
    if (network->autostart != autostart) {
1505
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir, network->def->name)) == NULL)
1506
            goto cleanup;
1507
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, network->def->name)) == NULL)
1508 1509
            goto cleanup;

1510
        if (autostart) {
1511
            if (virFileMakePath(driver->networkAutostartDir)) {
1512
                virReportSystemError(errno,
1513 1514
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
1515 1516
                goto cleanup;
            }
1517

1518
            if (symlink(configFile, autostartLink) < 0) {
1519
                virReportSystemError(errno,
1520
                                     _("Failed to create symlink '%s' to '%s'"),
1521
                                     autostartLink, configFile);
1522 1523 1524
                goto cleanup;
            }
        } else {
1525
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1526
                virReportSystemError(errno,
1527
                                     _("Failed to delete symlink '%s'"),
1528
                                     autostartLink);
1529 1530
                goto cleanup;
            }
1531 1532
        }

1533
        network->autostart = autostart;
1534
    }
1535
    ret = 0;
1536

1537
cleanup:
1538 1539
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
1540 1541
    if (network)
        virNetworkObjUnlock(network);
1542
    networkDriverUnlock(driver);
1543
    return ret;
1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
}


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 */
1566 1567
    networkIsActive,
    networkIsPersistent,
1568 1569 1570
};

static virStateDriver networkStateDriver = {
1571
    "Network",
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582
    networkStartup,
    networkShutdown,
    networkReload,
    networkActive,
};

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