bridge_driver.c 56.2 KB
Newer Older
1
/*
2
 * bridge_driver.c: core driver methods for managing network
3
 *
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
 * 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 <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>

46
#include "virterror_internal.h"
47
#include "datatypes.h"
48
#include "bridge_driver.h"
49 50 51 52 53
#include "network_conf.h"
#include "driver.h"
#include "event.h"
#include "buf.h"
#include "util.h"
54
#include "command.h"
55 56 57 58
#include "memory.h"
#include "uuid.h"
#include "iptables.h"
#include "bridge.h"
59
#include "logging.h"
60
#include "dnsmasq.h"
61
#include "util/network.h"
62
#include "configmake.h"
63

64 65
#define NETWORK_PID_DIR LOCALSTATEDIR "/run/libvirt/network"
#define NETWORK_STATE_DIR LOCALSTATEDIR "/lib/libvirt/network"
66

67
#define DNSMASQ_STATE_DIR LOCALSTATEDIR "/lib/libvirt/dnsmasq"
68

69 70
#define VIR_FROM_THIS VIR_FROM_NETWORK

71
#define networkReportError(code, ...)                                   \
72
    virReportErrorHelper(NULL, VIR_FROM_NETWORK, code, __FILE__,        \
73
                         __FUNCTION__, __LINE__, __VA_ARGS__)
74

75 76
/* Main driver state */
struct network_driver {
77
    virMutex lock;
78

79
    virNetworkObjList networks;
80 81 82 83 84 85 86 87

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

88 89 90

static void networkDriverLock(struct network_driver *driver)
{
91
    virMutexLock(&driver->lock);
92 93 94
}
static void networkDriverUnlock(struct network_driver *driver)
{
95
    virMutexUnlock(&driver->lock);
96 97
}

98 99
static int networkShutdown(void);

100 101
static int networkStartNetworkDaemon(struct network_driver *driver,
                                     virNetworkObjPtr network);
102

103 104
static int networkShutdownNetworkDaemon(struct network_driver *driver,
                                        virNetworkObjPtr network);
105

106 107
static void networkReloadIptablesRules(struct network_driver *driver);

108 109 110
static struct network_driver *driverState = NULL;


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

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

147
            /* Finally try and read dnsmasq pid if any */
148
            if ((VIR_SOCKET_HAS_ADDR(&obj->def->ipAddress) ||
149
                 obj->def->nranges) &&
150 151 152 153 154 155 156 157 158 159
                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;

160
                if (virAsprintf(&pidpath, "/proc/%d/exe", obj->dnsmasqPid) < 0) {
161
                    virReportOOMError();
162 163
                    goto cleanup;
                }
164 165 166 167 168 169 170
                if (virFileLinkPointsTo(pidpath, DNSMASQ) == 0)
                    obj->dnsmasqPid = -1;
                VIR_FREE(pidpath);
#endif
            }
        }

171
    cleanup:
172 173 174 175 176
        virNetworkObjUnlock(obj);
    }
}


177 178 179
static void
networkAutostartConfigs(struct network_driver *driver) {
    unsigned int i;
180

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

/**
 * networkStartup:
 *
 * Initialization function for the QEmu daemon
 */
static int
198
networkStartup(int privileged) {
199 200
    uid_t uid = geteuid();
    char *base = NULL;
201
    int err;
202 203

    if (VIR_ALLOC(driverState) < 0)
204
        goto error;
205

206 207 208 209
    if (virMutexInit(&driverState->lock) < 0) {
        VIR_FREE(driverState);
        goto error;
    }
210 211
    networkDriverLock(driverState);

212
    if (privileged) {
213
        if (virAsprintf(&driverState->logDir,
214
                        "%s/log/libvirt/qemu", LOCALSTATEDIR) == -1)
215 216
            goto out_of_memory;

217
        if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL)
218 219
            goto out_of_memory;
    } else {
220
        char *userdir = virGetUserDirectory(uid);
221 222 223

        if (!userdir)
            goto error;
224

225
        if (virAsprintf(&driverState->logDir,
226 227
                        "%s/.libvirt/qemu/log", userdir) == -1) {
            VIR_FREE(userdir);
228
            goto out_of_memory;
229
        }
230

231 232
        if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
            VIR_FREE(userdir);
233 234
            goto out_of_memory;
        }
235
        VIR_FREE(userdir);
236 237 238 239 240
    }

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

244 245
    if (virAsprintf(&driverState->networkAutostartDir, "%s/qemu/networks/autostart",
                    base) == -1)
246 247 248 249
        goto out_of_memory;

    VIR_FREE(base);

250
    if ((err = brInit(&driverState->brctl))) {
251
        virReportSystemError(err, "%s",
252 253 254 255 256
                             _("cannot initialize bridge support"));
        goto error;
    }

    if (!(driverState->iptables = iptablesContextNew())) {
257
        goto out_of_memory;
258 259 260
    }


261
    if (virNetworkLoadAllConfigs(&driverState->networks,
262
                                 driverState->networkConfigDir,
263 264 265
                                 driverState->networkAutostartDir) < 0)
        goto error;

266
    networkFindActiveConfigs(driverState);
267
    networkReloadIptablesRules(driverState);
268 269
    networkAutostartConfigs(driverState);

270 271
    networkDriverUnlock(driverState);

272 273
    return 0;

274
out_of_memory:
275
    virReportOOMError();
276 277

error:
278 279 280
    if (driverState)
        networkDriverUnlock(driverState);

281
    VIR_FREE(base);
282
    networkShutdown();
283 284 285 286 287 288 289 290 291 292 293
    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) {
294 295 296
    if (!driverState)
        return 0;

297
    networkDriverLock(driverState);
298
    virNetworkLoadAllConfigs(&driverState->networks,
299 300
                             driverState->networkConfigDir,
                             driverState->networkAutostartDir);
301
    networkReloadIptablesRules(driverState);
302
    networkAutostartConfigs(driverState);
303
    networkDriverUnlock(driverState);
304 305 306 307 308 309 310 311 312 313 314 315 316
    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) {
317
    unsigned int i;
318
    int active = 0;
319

320 321 322
    if (!driverState)
        return 0;

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

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

345 346
    networkDriverLock(driverState);

347
    /* free inactive networks */
348
    virNetworkObjListFree(&driverState->networks);
349 350 351 352 353 354 355 356 357 358

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

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

359
    networkDriverUnlock(driverState);
360
    virMutexDestroy(&driverState->lock);
361

362 363 364 365 366 367
    VIR_FREE(driverState);

    return 0;
}


368 369 370 371 372 373 374 375 376 377 378 379
static int
networkSaveDnsmasqHostsfile(virNetworkObjPtr network,
                            dnsmasqContext *dctx,
                            bool force)
{
    unsigned int i;

    if (! force && virFileExists(dctx->hostsfile->path))
        return 1;

    for (i = 0 ; i < network->def->nhosts ; i++) {
        virNetworkDHCPHostDefPtr host = &(network->def->hosts[i]);
380 381
        if ((host->mac) && VIR_SOCKET_HAS_ADDR(&host->ip))
            dnsmasqAddDhcpHost(dctx, host->mac, &host->ip, host->name);
382 383 384 385 386 387 388 389 390
    }

    if (dnsmasqSave(dctx) < 0)
        return 0;

    return 1;
}


391
static int
392
networkBuildDnsmasqArgv(virNetworkObjPtr network,
393
                        const char *pidfile,
394 395
                        virCommandPtr cmd) {
    int r, ret = -1;
396
    int nbleases = 0;
397
    char *bridgeaddr;
398

399 400
    if (!(bridgeaddr = virSocketFormatAddr(&network->def->ipAddress)))
        goto cleanup;
401
    /*
402
     * NB, be careful about syntax for dnsmasq options in long format.
403 404 405 406 407 408 409 410 411 412 413 414 415
     *
     * 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,
416 417
     * without reading the dnsmasq source :-( The manpage is not
     * very explicit on this.
418
     */
419 420 421 422 423

    /*
     * Needed to ensure dnsmasq uses same algorithm for processing
     * multiple namedriver entries in /etc/resolv.conf as GLibC.
     */
424
    virCommandAddArgList(cmd, "--strict-order", "--bind-interfaces", NULL);
425

426 427
    if (network->def->domain)
        virCommandAddArgList(cmd, "--domain", network->def->domain, NULL);
428

429
    virCommandAddArgPair(cmd, "--pid-file", pidfile);
430

431 432
    /* *no* conf file */
    virCommandAddArgList(cmd, "--conf-file=", "", NULL);
433 434 435 436 437 438 439

    /*
     * 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
     *
440 441
     * virCommandAddArg(cmd, "--interface");
     * virCommandAddArg(cmd, network->def->bridge);
442
     */
443 444 445 446
    virCommandAddArgList(cmd,
                         "--listen-address", bridgeaddr,
                         "--except-interface", "lo",
                         NULL);
447 448

    for (r = 0 ; r < network->def->nranges ; r++) {
449 450
        char *saddr = virSocketFormatAddr(&network->def->ranges[r].start);
        if (!saddr)
451
            goto cleanup;
452 453 454
        char *eaddr = virSocketFormatAddr(&network->def->ranges[r].end);
        if (!eaddr) {
            VIR_FREE(saddr);
455
            goto cleanup;
456
        }
457 458
        virCommandAddArg(cmd, "--dhcp-range");
        virCommandAddArgFormat(cmd, "%s,%s", saddr, eaddr);
459 460 461 462
        VIR_FREE(saddr);
        VIR_FREE(eaddr);
        nbleases += virSocketGetRange(&network->def->ranges[r].start,
                                      &network->def->ranges[r].end);
463 464
    }

465 466 467 468 469
    /*
     * For static-only DHCP, i.e. with no range but at least one host element,
     * we have to add a special --dhcp-range option to enable the service in
     * dnsmasq.
     */
470
    if (!network->def->nranges && network->def->nhosts) {
471 472
        virCommandAddArg(cmd, "--dhcp-range");
        virCommandAddArgFormat(cmd, "%s,static", bridgeaddr);
473 474
    }

475
    if (network->def->nranges > 0) {
476
        virCommandAddArgFormat(cmd, "--dhcp-lease-max=%d", nbleases);
477 478
    }

479 480
    if (network->def->nranges || network->def->nhosts)
        virCommandAddArg(cmd, "--dhcp-no-override");
481

482
    if (network->def->nhosts > 0) {
483 484 485 486 487 488
        dnsmasqContext *dctx = dnsmasqContextNew(network->def->name,
                                                 DNSMASQ_STATE_DIR);
        if (dctx == NULL) {
            virReportOOMError();
            goto cleanup;
        }
489 490

        if (networkSaveDnsmasqHostsfile(network, dctx, false)) {
491 492
            virCommandAddArgPair(cmd, "--dhcp-hostsfile",
                                 dctx->hostsfile->path);
493 494
        }
        dnsmasqContextFree(dctx);
495 496
    }

497
    if (network->def->tftproot) {
498 499 500
        virCommandAddArgList(cmd, "--enable-tftp",
                             "--tftp-root", network->def->tftproot,
                             NULL);
501 502
    }
    if (network->def->bootfile) {
503 504

        virCommandAddArg(cmd, "--dhcp-boot");
505
        if (VIR_SOCKET_HAS_ADDR(&network->def->bootserver)) {
506 507 508 509 510 511 512 513 514
            char *bootserver = virSocketFormatAddr(&network->def->bootserver);

            if (!bootserver)
                goto cleanup;
            virCommandAddArgFormat(cmd, "%s%s%s",
                               network->def->bootfile, ",,", bootserver);
            VIR_FREE(bootserver);
        } else {
            virCommandAddArg(cmd, network->def->bootfile);
515
        }
516 517
    }

518 519 520 521
    ret = 0;
cleanup:
    VIR_FREE(bridgeaddr);
    return ret;
522 523 524 525
}


static int
526
dhcpStartDhcpDaemon(virNetworkObjPtr network)
527
{
528 529 530
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
    int ret = -1, err;
531 532

    network->dnsmasqPid = -1;
533

534
    if (!VIR_SOCKET_IS_FAMILY(&network->def->ipAddress, AF_INET)) {
535
        networkReportError(VIR_ERR_INTERNAL_ERROR,
536
                           "%s", _("cannot start dhcp daemon without IPv4 address for server"));
537
        goto cleanup;
538 539
    }

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

    if (!(pidfile = virFilePid(NETWORK_PID_DIR, network->def->name))) {
554
        virReportOOMError();
555
        goto cleanup;
556 557
    }

558 559 560
    cmd = virCommandNew(DNSMASQ);
    if (networkBuildDnsmasqArgv(network, pidfile, cmd) < 0) {
        goto cleanup;
561 562
    }

563
    if (virCommandRun(cmd, NULL) < 0)
564 565 566
        goto cleanup;

    /*
567 568 569 570 571
     * 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 virCommandRun exits it has
     * waitpid'd and guaranteed the proess has started and written a
     * pid
572 573 574 575 576
     */

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

578 579 580
    ret = 0;
cleanup:
    VIR_FREE(pidfile);
581
    virCommandFree(cmd);
582 583 584 585
    return ret;
}

static int
586 587
networkAddMasqueradingIptablesRules(struct network_driver *driver,
                                    virNetworkObjPtr network) {
588 589 590
    int err;
    /* allow forwarding packets from the bridge interface */
    if ((err = iptablesAddForwardAllowOut(driver->iptables,
591 592
                                          &network->def->ipAddress,
                                          &network->def->netmask,
593 594
                                          network->def->bridge,
                                          network->def->forwardDev))) {
595
        virReportSystemError(err,
596 597
                             _("failed to add iptables rule to allow forwarding from '%s'"),
                             network->def->bridge);
598 599 600 601 602
        goto masqerr1;
    }

    /* allow forwarding packets to the bridge interface if they are part of an existing connection */
    if ((err = iptablesAddForwardAllowRelatedIn(driver->iptables,
603 604 605 606
                                                &network->def->ipAddress,
                                                &network->def->netmask,
                                                network->def->bridge,
                                                network->def->forwardDev))) {
607
        virReportSystemError(err,
608 609
                             _("failed to add iptables rule to allow forwarding to '%s'"),
                             network->def->bridge);
610 611 612
        goto masqerr2;
    }

613 614 615 616 617
    /*
     * Enable masquerading.
     *
     * We need to end up with 3 rules in the table in this order
     *
E
Eric Blake 已提交
618 619
     *  1. protocol=tcp with sport mapping restriction
     *  2. protocol=udp with sport mapping restriction
620 621 622
     *  3. generic any protocol
     *
     * The sport mappings are required, because default IPtables
E
Eric Blake 已提交
623
     * MASQUERADE maintain port numbers unchanged where possible.
624 625 626 627 628 629 630 631 632 633 634 635 636
     *
     * NFS can be configured to only "trust" port numbers < 1023.
     *
     * Guests using NAT thus need to be prevented from having port
     * numbers < 1023, otherwise they can bypass the NFS "security"
     * check on the source port number.
     *
     * Since we use '--insert' to add rules to the header of the
     * chain, we actually need to add them in the reverse of the
     * order just mentioned !
     */

    /* First the generic masquerade rule for other protocols */
637
    if ((err = iptablesAddForwardMasquerade(driver->iptables,
638 639
                                            &network->def->ipAddress,
                                            &network->def->netmask,
640 641
                                            network->def->forwardDev,
                                            NULL))) {
642
        virReportSystemError(err,
643
                             _("failed to add iptables rule to enable masquerading to '%s'"),
644
                             network->def->forwardDev ? network->def->forwardDev : NULL);
645 646 647
        goto masqerr3;
    }

648 649
    /* UDP with a source port restriction */
    if ((err = iptablesAddForwardMasquerade(driver->iptables,
650 651
                                            &network->def->ipAddress,
                                            &network->def->netmask,
652 653 654 655 656 657 658 659 660 661
                                            network->def->forwardDev,
                                            "udp"))) {
        virReportSystemError(err,
                             _("failed to add iptables rule to enable UDP masquerading to '%s'"),
                             network->def->forwardDev ? network->def->forwardDev : NULL);
        goto masqerr4;
    }

    /* TCP with a source port restriction */
    if ((err = iptablesAddForwardMasquerade(driver->iptables,
662 663
                                            &network->def->ipAddress,
                                            &network->def->netmask,
664 665 666 667 668 669 670 671
                                            network->def->forwardDev,
                                            "tcp"))) {
        virReportSystemError(err,
                             _("failed to add iptables rule to enable TCP masquerading to '%s'"),
                             network->def->forwardDev ? network->def->forwardDev : NULL);
        goto masqerr5;
    }

672 673
    return 1;

674 675
 masqerr5:
    iptablesRemoveForwardMasquerade(driver->iptables,
676 677
                                    &network->def->ipAddress,
                                    &network->def->netmask,
678 679 680 681
                                    network->def->forwardDev,
                                    "udp");
 masqerr4:
    iptablesRemoveForwardMasquerade(driver->iptables,
682 683
                                    &network->def->ipAddress,
                                    &network->def->netmask,
684 685
                                    network->def->forwardDev,
                                    NULL);
686 687
 masqerr3:
    iptablesRemoveForwardAllowRelatedIn(driver->iptables,
688 689 690 691
                                        &network->def->ipAddress,
                                        &network->def->netmask,
                                        network->def->bridge,
                                        network->def->forwardDev);
692 693
 masqerr2:
    iptablesRemoveForwardAllowOut(driver->iptables,
694 695
                                  &network->def->ipAddress,
                                  &network->def->netmask,
696 697 698 699 700 701 702
                                  network->def->bridge,
                                  network->def->forwardDev);
 masqerr1:
    return 0;
}

static int
703 704
networkAddRoutingIptablesRules(struct network_driver *driver,
                               virNetworkObjPtr network) {
705 706 707
    int err;
    /* allow routing packets from the bridge interface */
    if ((err = iptablesAddForwardAllowOut(driver->iptables,
708 709
                                          &network->def->ipAddress,
                                          &network->def->netmask,
710 711
                                          network->def->bridge,
                                          network->def->forwardDev))) {
712
        virReportSystemError(err,
713 714
                             _("failed to add iptables rule to allow routing from '%s'"),
                             network->def->bridge);
715 716 717 718 719
        goto routeerr1;
    }

    /* allow routing packets to the bridge interface */
    if ((err = iptablesAddForwardAllowIn(driver->iptables,
720 721
                                         &network->def->ipAddress,
                                         &network->def->netmask,
722 723
                                         network->def->bridge,
                                         network->def->forwardDev))) {
724
        virReportSystemError(err,
725 726
                             _("failed to add iptables rule to allow routing to '%s'"),
                             network->def->bridge);
727 728 729 730 731 732 733 734
        goto routeerr2;
    }

    return 1;


 routeerr2:
    iptablesRemoveForwardAllowOut(driver->iptables,
735 736
                                  &network->def->ipAddress,
                                  &network->def->netmask,
737 738 739 740 741 742 743
                                  network->def->bridge,
                                  network->def->forwardDev);
 routeerr1:
    return 0;
}

static int
744 745
networkAddIptablesRules(struct network_driver *driver,
                        virNetworkObjPtr network) {
746 747 748 749
    int err;

    /* allow DHCP requests through to dnsmasq */
    if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 67))) {
750
        virReportSystemError(err,
751 752
                             _("failed to add iptables rule to allow DHCP requests from '%s'"),
                             network->def->bridge);
753 754 755 756
        goto err1;
    }

    if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 67))) {
757
        virReportSystemError(err,
758 759
                             _("failed to add iptables rule to allow DHCP requests from '%s'"),
                             network->def->bridge);
760 761 762 763 764
        goto err2;
    }

    /* allow DNS requests through to dnsmasq */
    if ((err = iptablesAddTcpInput(driver->iptables, network->def->bridge, 53))) {
765
        virReportSystemError(err,
766 767
                             _("failed to add iptables rule to allow DNS requests from '%s'"),
                             network->def->bridge);
768 769 770 771
        goto err3;
    }

    if ((err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 53))) {
772
        virReportSystemError(err,
773 774
                             _("failed to add iptables rule to allow DNS requests from '%s'"),
                             network->def->bridge);
775 776 777
        goto err4;
    }

778 779 780 781 782 783 784 785 786
    /* allow TFTP requests through to dnsmasq */
    if (network->def->tftproot &&
        (err = iptablesAddUdpInput(driver->iptables, network->def->bridge, 69))) {
        virReportSystemError(err,
                             _("failed to add iptables rule to allow TFTP requests from '%s'"),
                             network->def->bridge);
        goto err4tftp;
    }

787 788 789 790

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

    if ((err = iptablesAddForwardRejectOut(driver->iptables, network->def->bridge))) {
791
        virReportSystemError(err,
792 793
                             _("failed to add iptables rule to block outbound traffic from '%s'"),
                             network->def->bridge);
794 795 796 797
        goto err5;
    }

    if ((err = iptablesAddForwardRejectIn(driver->iptables, network->def->bridge))) {
798
        virReportSystemError(err,
799 800
                             _("failed to add iptables rule to block inbound traffic to '%s'"),
                             network->def->bridge);
801 802 803 804 805
        goto err6;
    }

    /* Allow traffic between guests on the same bridge */
    if ((err = iptablesAddForwardAllowCross(driver->iptables, network->def->bridge))) {
806
        virReportSystemError(err,
807 808
                             _("failed to add iptables rule to allow cross bridge traffic on '%s'"),
                             network->def->bridge);
809 810 811 812 813 814
        goto err7;
    }


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

822 823 824 825 826 827
    /* If we are doing local DHCP service on this network, attempt to
     * add a rule that will fixup the checksum of DHCP response
     * packets back to the guests (but report failure without
     * aborting, since not all iptables implementations support it).
     */

828 829
    if ((VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
         network->def->nranges) &&
830 831 832 833 834 835 836
        (iptablesAddOutputFixUdpChecksum(driver->iptables,
                                         network->def->bridge, 68) != 0)) {
        VIR_WARN("Could not add rule to fixup DHCP response checksums "
                 "on network '%s'.", network->def->name);
        VIR_WARN0("May need to update iptables package & kernel to support CHECKSUM rule.");
    }

837 838 839 840 841 842 843 844 845 846 847 848
    return 1;

 err8:
    iptablesRemoveForwardAllowCross(driver->iptables,
                                    network->def->bridge);
 err7:
    iptablesRemoveForwardRejectIn(driver->iptables,
                                  network->def->bridge);
 err6:
    iptablesRemoveForwardRejectOut(driver->iptables,
                                   network->def->bridge);
 err5:
849 850 851 852
    if (network->def->tftproot) {
        iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 69);
    }
 err4tftp:
853 854 855 856 857 858 859 860 861 862 863 864 865 866
    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) {
867 868
    if (VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
        network->def->nranges) {
869 870 871
        iptablesRemoveOutputFixUdpChecksum(driver->iptables,
                                           network->def->bridge, 68);
    }
872
    if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
873 874
        if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
            iptablesRemoveForwardMasquerade(driver->iptables,
875 876
                                            &network->def->ipAddress,
                                            &network->def->netmask,
877 878 879
                                            network->def->forwardDev,
                                            "tcp");
            iptablesRemoveForwardMasquerade(driver->iptables,
880 881
                                            &network->def->ipAddress,
                                            &network->def->netmask,
882 883 884
                                            network->def->forwardDev,
                                            "udp");
            iptablesRemoveForwardMasquerade(driver->iptables,
885 886
                                            &network->def->ipAddress,
                                            &network->def->netmask,
887 888
                                            network->def->forwardDev,
                                            NULL);
889
            iptablesRemoveForwardAllowRelatedIn(driver->iptables,
890 891
                                                &network->def->ipAddress,
                                                &network->def->netmask,
892 893
                                                network->def->bridge,
                                                network->def->forwardDev);
894
        } else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE)
895
            iptablesRemoveForwardAllowIn(driver->iptables,
896 897
                                         &network->def->ipAddress,
                                         &network->def->netmask,
898 899 900 901
                                         network->def->bridge,
                                         network->def->forwardDev);

        iptablesRemoveForwardAllowOut(driver->iptables,
902 903
                                      &network->def->ipAddress,
                                      &network->def->netmask,
904 905 906 907 908 909
                                      network->def->bridge,
                                      network->def->forwardDev);
    }
    iptablesRemoveForwardAllowCross(driver->iptables, network->def->bridge);
    iptablesRemoveForwardRejectIn(driver->iptables, network->def->bridge);
    iptablesRemoveForwardRejectOut(driver->iptables, network->def->bridge);
910 911
    if (network->def->tftproot)
        iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 69);
912 913 914 915 916 917
    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);
}

918 919 920 921 922 923 924 925 926 927 928 929
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]);
930
            if (!networkAddIptablesRules(driver, driver->networks.objs[i])) {
931 932 933 934 935 936 937 938
                /* failed to add but already logged */
            }
        }

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

939
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
940 941 942
static int
networkEnableIpForwarding(void)
{
943
    return virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n", 0);
944 945
}

946 947
#define SYSCTL_PATH "/proc/sys"

948
static int networkDisableIPV6(virNetworkObjPtr network)
949 950 951 952 953
{
    char *field = NULL;
    int ret = -1;

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

958 959 960 961 962 963
    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;
    }

964
    if (virFileWriteStr(field, "1", 0) < 0) {
965
        virReportSystemError(errno,
966 967 968 969 970 971
                             _("cannot enable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

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

976
    if (virFileWriteStr(field, "0", 0) < 0) {
977
        virReportSystemError(errno,
978 979 980 981 982 983
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

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

988
    if (virFileWriteStr(field, "1", 0) < 0) {
989
        virReportSystemError(errno,
990 991 992 993 994 995 996 997 998 999
                             _("cannot enable %s"), field);
        goto cleanup;
    }

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

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
#define PROC_NET_ROUTE "/proc/net/route"

/* XXX: This function can be a lot more exhaustive, there are certainly
 *      other scenarios where we can ruin host network connectivity.
 * XXX: Using a proper library is preferred over parsing /proc
 */
static int networkCheckRouteCollision(virNetworkObjPtr network)
{
    int ret = -1, len;
    unsigned int net_dest;
    char *cur, *buf = NULL;
    enum {MAX_ROUTE_SIZE = 1024*64};

1013 1014
    if (!VIR_SOCKET_IS_FAMILY(&network->def->ipAddress, AF_INET) ||
        !VIR_SOCKET_IS_FAMILY(&network->def->netmask, AF_INET)) {
1015
        /* Only support collision check for IPv4 */
1016
        return 0;
1017 1018
    }

1019 1020
    net_dest = (network->def->ipAddress.data.inet4.sin_addr.s_addr &
                network->def->netmask.data.inet4.sin_addr.s_addr);
1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072

    /* Read whole routing table into memory */
    if ((len = virFileReadAll(PROC_NET_ROUTE, MAX_ROUTE_SIZE, &buf)) < 0)
        goto error;

    /* Dropping the last character shouldn't hurt */
    if (len > 0)
        buf[len-1] = '\0';

    VIR_DEBUG("%s output:\n%s", PROC_NET_ROUTE, buf);

    if (!STRPREFIX (buf, "Iface"))
        goto out;

    /* First line is just headings, skip it */
    cur = strchr(buf, '\n');
    if (cur)
        cur++;

    while (cur) {
        char iface[17], dest[128], mask[128];
        unsigned int addr_val, mask_val;
        int num;

        /* NUL-terminate the line, so sscanf doesn't go beyond a newline.  */
        char *nl = strchr(cur, '\n');
        if (nl) {
            *nl++ = '\0';
        }

        num = sscanf(cur, "%16s %127s %*s %*s %*s %*s %*s %127s",
                     iface, dest, mask);
        cur = nl;

        if (num != 3) {
            VIR_DEBUG("Failed to parse %s", PROC_NET_ROUTE);
            continue;
        }

        if (virStrToLong_ui(dest, NULL, 16, &addr_val) < 0) {
            VIR_DEBUG("Failed to convert network address %s to uint", dest);
            continue;
        }

        if (virStrToLong_ui(mask, NULL, 16, &mask_val) < 0) {
            VIR_DEBUG("Failed to convert network mask %s to uint", mask);
            continue;
        }

        addr_val &= mask_val;

        if ((net_dest == addr_val) &&
1073
            (network->def->netmask.data.inet4.sin_addr.s_addr == mask_val)) {
1074
            networkReportError(VIR_ERR_INTERNAL_ERROR,
1075 1076
                               _("Network is already in use by interface %s"),
                               iface);
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
            goto error;
        }
    }

out:
    ret = 0;
error:
    VIR_FREE(buf);
    return ret;
}

1088 1089 1090
static int networkStartNetworkDaemon(struct network_driver *driver,
                                     virNetworkObjPtr network)
{
1091
    int err;
1092
    virErrorPtr save_err;
1093

D
Daniel P. Berrange 已提交
1094
    if (virNetworkObjIsActive(network)) {
1095 1096
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("network is already active"));
1097 1098 1099
        return -1;
    }

1100 1101 1102 1103
    /* Check to see if network collides with an existing route */
    if (networkCheckRouteCollision(network) < 0)
        return -1;

1104
    if ((err = brAddBridge(driver->brctl, network->def->bridge))) {
1105
        virReportSystemError(err,
1106 1107
                             _("cannot create bridge '%s'"),
                             network->def->bridge);
1108 1109 1110
        return -1;
    }

1111
    if (networkDisableIPV6(network) < 0)
1112 1113
        goto err_delbr;

1114 1115 1116 1117 1118 1119
    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;

1120 1121 1122
    if (VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) &&
        (err = brSetInetAddress(driver->brctl, network->def->bridge,
                                &network->def->ipAddress))) {
1123
        virReportSystemError(err,
1124 1125
                             _("cannot set IP address on bridge '%s'"),
                             network->def->bridge);
1126 1127 1128
        goto err_delbr;
    }

1129 1130 1131
    if (VIR_SOCKET_HAS_ADDR(&network->def->netmask) &&
        (err = brSetInetNetmask(driver->brctl, network->def->bridge,
                                &network->def->netmask))) {
1132
        virReportSystemError(err,
1133 1134
                             _("cannot set netmask on bridge '%s'"),
                             network->def->bridge);
1135 1136 1137
        goto err_delbr;
    }

1138
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) {
1139
        virReportSystemError(err,
1140 1141
                             _("failed to bring the bridge '%s' up"),
                             network->def->bridge);
1142 1143 1144
        goto err_delbr;
    }

1145
    if (!networkAddIptablesRules(driver, network))
1146 1147 1148
        goto err_delbr1;

    if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE &&
1149
        networkEnableIpForwarding() < 0) {
1150
        virReportSystemError(errno, "%s",
1151
                             _("failed to enable IP forwarding"));
1152 1153 1154
        goto err_delbr2;
    }

1155
    if ((VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
1156
         network->def->nranges) &&
1157
        dhcpStartDhcpDaemon(network) < 0)
1158 1159
        goto err_delbr2;

1160 1161

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

1166 1167 1168 1169
    network->active = 1;

    return 0;

1170 1171 1172 1173 1174 1175
 err_kill:
    if (network->dnsmasqPid > 0) {
        kill(network->dnsmasqPid, SIGTERM);
        network->dnsmasqPid = -1;
    }

1176
 err_delbr2:
1177
    save_err = virSaveLastError();
1178
    networkRemoveIptablesRules(driver, network);
1179 1180 1181 1182
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
1183 1184

 err_delbr1:
1185
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
1186
        char ebuf[1024];
1187
        VIR_WARN("Failed to bring down bridge '%s' : %s",
1188
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1189 1190 1191 1192
    }

 err_delbr:
    if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
1193
        char ebuf[1024];
1194
        VIR_WARN("Failed to delete bridge '%s' : %s",
1195
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1196 1197 1198 1199 1200 1201
    }

    return -1;
}


1202 1203 1204
static int networkShutdownNetworkDaemon(struct network_driver *driver,
                                        virNetworkObjPtr network)
{
1205
    int err;
1206
    char *stateFile;
1207

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

D
Daniel P. Berrange 已提交
1210
    if (!virNetworkObjIsActive(network))
1211 1212
        return 0;

1213
    stateFile = virNetworkConfigFile(NETWORK_STATE_DIR, network->def->name);
1214 1215 1216 1217 1218 1219
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

1220 1221 1222 1223 1224
    if (network->dnsmasqPid > 0)
        kill(network->dnsmasqPid, SIGTERM);

    networkRemoveIptablesRules(driver, network);

1225
    char ebuf[1024];
1226
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
1227
        VIR_WARN("Failed to bring down bridge '%s' : %s",
1228
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1229 1230 1231
    }

    if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
1232
        VIR_WARN("Failed to delete bridge '%s' : %s",
1233
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1234 1235
    }

1236
    /* See if its still alive and really really kill it */
1237
    if (network->dnsmasqPid > 0 &&
1238
        (kill(network->dnsmasqPid, 0) == 0))
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
        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;
}


1254 1255 1256 1257 1258
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
                                         const unsigned char *uuid) {
    struct network_driver *driver = conn->networkPrivateData;
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;
1259

1260
    networkDriverLock(driver);
1261
    network = virNetworkFindByUUID(&driver->networks, uuid);
1262
    networkDriverUnlock(driver);
1263
    if (!network) {
1264 1265
        networkReportError(VIR_ERR_NO_NETWORK,
                           "%s", _("no network with matching uuid"));
1266
        goto cleanup;
1267 1268
    }

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

cleanup:
1272 1273
    if (network)
        virNetworkObjUnlock(network);
1274
    return ret;
1275 1276
}

1277 1278 1279 1280 1281 1282
static virNetworkPtr networkLookupByName(virConnectPtr conn,
                                         const char *name) {
    struct network_driver *driver = conn->networkPrivateData;
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;

1283
    networkDriverLock(driver);
1284
    network = virNetworkFindByName(&driver->networks, name);
1285
    networkDriverUnlock(driver);
1286
    if (!network) {
1287 1288
        networkReportError(VIR_ERR_NO_NETWORK,
                           _("no network with matching name '%s'"), name);
1289
        goto cleanup;
1290 1291
    }

1292 1293 1294
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
1295 1296
    if (network)
        virNetworkObjUnlock(network);
1297
    return ret;
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
}

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) {
1316
    int nactive = 0, i;
1317
    struct network_driver *driver = conn->networkPrivateData;
1318

1319 1320 1321
    networkDriverLock(driver);
    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1322
        if (virNetworkObjIsActive(driver->networks.objs[i]))
1323
            nactive++;
1324 1325 1326
        virNetworkObjUnlock(driver->networks.objs[i]);
    }
    networkDriverUnlock(driver);
1327

1328 1329 1330 1331
    return nactive;
}

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

1335
    networkDriverLock(driver);
1336
    for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
1337
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1338
        if (virNetworkObjIsActive(driver->networks.objs[i])) {
1339
            if (!(names[got] = strdup(driver->networks.objs[i]->def->name))) {
1340
                virNetworkObjUnlock(driver->networks.objs[i]);
1341
                virReportOOMError();
1342 1343 1344 1345
                goto cleanup;
            }
            got++;
        }
1346
        virNetworkObjUnlock(driver->networks.objs[i]);
1347
    }
1348 1349
    networkDriverUnlock(driver);

1350 1351 1352
    return got;

 cleanup:
1353
    networkDriverUnlock(driver);
1354 1355 1356 1357 1358 1359
    for (i = 0 ; i < got ; i++)
        VIR_FREE(names[i]);
    return -1;
}

static int networkNumDefinedNetworks(virConnectPtr conn) {
1360
    int ninactive = 0, i;
1361
    struct network_driver *driver = conn->networkPrivateData;
1362

1363 1364 1365
    networkDriverLock(driver);
    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1366
        if (!virNetworkObjIsActive(driver->networks.objs[i]))
1367
            ninactive++;
1368 1369 1370
        virNetworkObjUnlock(driver->networks.objs[i]);
    }
    networkDriverUnlock(driver);
1371

1372 1373 1374 1375
    return ninactive;
}

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

1379
    networkDriverLock(driver);
1380
    for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
1381
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1382
        if (!virNetworkObjIsActive(driver->networks.objs[i])) {
1383
            if (!(names[got] = strdup(driver->networks.objs[i]->def->name))) {
1384
                virNetworkObjUnlock(driver->networks.objs[i]);
1385
                virReportOOMError();
1386 1387 1388 1389
                goto cleanup;
            }
            got++;
        }
1390
        virNetworkObjUnlock(driver->networks.objs[i]);
1391
    }
1392
    networkDriverUnlock(driver);
1393 1394 1395
    return got;

 cleanup:
1396
    networkDriverUnlock(driver);
1397 1398 1399 1400 1401
    for (i = 0 ; i < got ; i++)
        VIR_FREE(names[i]);
    return -1;
}

1402 1403 1404

static int networkIsActive(virNetworkPtr net)
{
1405
    struct network_driver *driver = net->conn->networkPrivateData;
1406 1407 1408 1409 1410 1411 1412
    virNetworkObjPtr obj;
    int ret = -1;

    networkDriverLock(driver);
    obj = virNetworkFindByUUID(&driver->networks, net->uuid);
    networkDriverUnlock(driver);
    if (!obj) {
1413
        networkReportError(VIR_ERR_NO_NETWORK, NULL);
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
        goto cleanup;
    }
    ret = virNetworkObjIsActive(obj);

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

static int networkIsPersistent(virNetworkPtr net)
{
1426
    struct network_driver *driver = net->conn->networkPrivateData;
1427 1428 1429 1430 1431 1432 1433
    virNetworkObjPtr obj;
    int ret = -1;

    networkDriverLock(driver);
    obj = virNetworkFindByUUID(&driver->networks, net->uuid);
    networkDriverUnlock(driver);
    if (!obj) {
1434
        networkReportError(VIR_ERR_NO_NETWORK, NULL);
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
        goto cleanup;
    }
    ret = obj->persistent;

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


1446
static virNetworkPtr networkCreate(virConnectPtr conn, const char *xml) {
1447
    struct network_driver *driver = conn->networkPrivateData;
1448
    virNetworkDefPtr def;
1449
    virNetworkObjPtr network = NULL;
1450
    virNetworkPtr ret = NULL;
1451

1452 1453
    networkDriverLock(driver);

1454
    if (!(def = virNetworkDefParseString(xml)))
1455
        goto cleanup;
1456

1457 1458 1459
    if (virNetworkObjIsDuplicate(&driver->networks, def, 1) < 0)
        goto cleanup;

1460
    if (virNetworkSetBridgeName(&driver->networks, def, 1))
1461 1462
        goto cleanup;

1463
    if (!(network = virNetworkAssignDef(&driver->networks,
1464 1465 1466
                                        def)))
        goto cleanup;
    def = NULL;
1467

1468
    if (networkStartNetworkDaemon(driver, network) < 0) {
1469 1470
        virNetworkRemoveInactive(&driver->networks,
                                 network);
1471
        network = NULL;
1472
        goto cleanup;
1473 1474
    }

1475 1476 1477 1478
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
    virNetworkDefFree(def);
1479 1480 1481
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1482
    return ret;
1483 1484 1485
}

static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
1486
    struct network_driver *driver = conn->networkPrivateData;
1487
    virNetworkDefPtr def;
1488
    virNetworkObjPtr network = NULL;
1489
    virNetworkPtr ret = NULL;
1490

1491 1492
    networkDriverLock(driver);

1493
    if (!(def = virNetworkDefParseString(xml)))
1494
        goto cleanup;
1495

E
Eric Blake 已提交
1496
    if (virNetworkObjIsDuplicate(&driver->networks, def, 0) < 0)
1497 1498
        goto cleanup;

1499
    if (virNetworkSetBridgeName(&driver->networks, def, 1))
1500 1501
        goto cleanup;

1502
    if (!(network = virNetworkAssignDef(&driver->networks,
1503 1504 1505
                                        def)))
        goto cleanup;
    def = NULL;
1506

1507 1508
    network->persistent = 1;

1509
    if (virNetworkSaveConfig(driver->networkConfigDir,
1510
                             network->newDef ? network->newDef : network->def) < 0) {
1511 1512
        virNetworkRemoveInactive(&driver->networks,
                                 network);
1513
        network = NULL;
1514
        goto cleanup;
1515 1516
    }

1517 1518 1519 1520 1521 1522 1523 1524 1525
    if (network->def->nhosts > 0) {
        dnsmasqContext *dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR);
        if (dctx == NULL)
            goto cleanup;

        networkSaveDnsmasqHostsfile(network, dctx, true);
        dnsmasqContextFree(dctx);
    }

1526 1527 1528 1529
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
    virNetworkDefFree(def);
1530 1531 1532
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1533
    return ret;
1534 1535 1536
}

static int networkUndefine(virNetworkPtr net) {
1537
    struct network_driver *driver = net->conn->networkPrivateData;
1538
    virNetworkObjPtr network = NULL;
1539
    int ret = -1;
1540

1541 1542
    networkDriverLock(driver);

1543
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1544
    if (!network) {
1545
        networkReportError(VIR_ERR_INVALID_NETWORK,
1546 1547
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1548 1549
    }

D
Daniel P. Berrange 已提交
1550
    if (virNetworkObjIsActive(network)) {
1551
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1552 1553
                           "%s", _("network is still active"));
        goto cleanup;
1554 1555
    }

1556
    if (virNetworkDeleteConfig(driver->networkConfigDir,
1557 1558
                               driver->networkAutostartDir,
                               network) < 0)
1559
        goto cleanup;
1560

1561 1562 1563 1564 1565 1566 1567 1568 1569
    if (network->def->nhosts > 0) {
        dnsmasqContext *dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR);
        if (dctx == NULL)
            goto cleanup;

        dnsmasqDelete(dctx);
        dnsmasqContextFree(dctx);
    }

1570 1571
    virNetworkRemoveInactive(&driver->networks,
                             network);
1572
    network = NULL;
1573
    ret = 0;
1574

1575
cleanup:
1576 1577 1578
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1579
    return ret;
1580 1581 1582
}

static int networkStart(virNetworkPtr net) {
1583 1584 1585
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1586

1587
    networkDriverLock(driver);
1588
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1589

1590
    if (!network) {
1591
        networkReportError(VIR_ERR_INVALID_NETWORK,
1592 1593
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1594 1595
    }

1596
    ret = networkStartNetworkDaemon(driver, network);
1597 1598

cleanup:
1599 1600
    if (network)
        virNetworkObjUnlock(network);
1601
    networkDriverUnlock(driver);
1602
    return ret;
1603 1604 1605
}

static int networkDestroy(virNetworkPtr net) {
1606 1607 1608
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1609

1610
    networkDriverLock(driver);
1611
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1612

1613
    if (!network) {
1614
        networkReportError(VIR_ERR_INVALID_NETWORK,
1615 1616
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1617 1618
    }

D
Daniel P. Berrange 已提交
1619
    if (!virNetworkObjIsActive(network)) {
1620
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1621 1622 1623 1624
                           "%s", _("network is not active"));
        goto cleanup;
    }

1625
    ret = networkShutdownNetworkDaemon(driver, network);
1626
    if (!network->persistent) {
1627 1628 1629 1630
        virNetworkRemoveInactive(&driver->networks,
                                 network);
        network = NULL;
    }
1631

1632
cleanup:
1633 1634
    if (network)
        virNetworkObjUnlock(network);
1635
    networkDriverUnlock(driver);
1636 1637 1638 1639
    return ret;
}

static char *networkDumpXML(virNetworkPtr net, int flags ATTRIBUTE_UNUSED) {
1640 1641 1642
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char *ret = NULL;
1643

1644
    networkDriverLock(driver);
1645
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1646 1647
    networkDriverUnlock(driver);

1648
    if (!network) {
1649
        networkReportError(VIR_ERR_INVALID_NETWORK,
1650 1651
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1652 1653
    }

1654
    ret = virNetworkDefFormat(network->def);
1655 1656

cleanup:
1657 1658
    if (network)
        virNetworkObjUnlock(network);
1659
    return ret;
1660 1661 1662
}

static char *networkGetBridgeName(virNetworkPtr net) {
1663 1664 1665 1666
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char *bridge = NULL;

1667
    networkDriverLock(driver);
1668
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1669 1670
    networkDriverUnlock(driver);

1671
    if (!network) {
1672
        networkReportError(VIR_ERR_INVALID_NETWORK,
1673 1674
                           "%s", _("no network with matching id"));
        goto cleanup;
1675 1676
    }

1677
    if (!(network->def->bridge)) {
1678
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1679 1680 1681 1682 1683
                           _("network '%s' does not have a bridge name."),
                           network->def->name);
        goto cleanup;
    }

1684
    bridge = strdup(network->def->bridge);
1685
    if (!bridge)
1686
        virReportOOMError();
1687 1688

cleanup:
1689 1690
    if (network)
        virNetworkObjUnlock(network);
1691 1692 1693 1694 1695
    return bridge;
}

static int networkGetAutostart(virNetworkPtr net,
                             int *autostart) {
1696 1697 1698
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1699

1700
    networkDriverLock(driver);
1701
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1702
    networkDriverUnlock(driver);
1703
    if (!network) {
1704 1705
        networkReportError(VIR_ERR_INVALID_NETWORK,
                           "%s", _("no network with matching uuid"));
1706
        goto cleanup;
1707 1708 1709
    }

    *autostart = network->autostart;
1710
    ret = 0;
1711

1712
cleanup:
1713 1714
    if (network)
        virNetworkObjUnlock(network);
1715
    return ret;
1716 1717 1718
}

static int networkSetAutostart(virNetworkPtr net,
1719
                               int autostart) {
1720 1721
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
1722
    char *configFile = NULL, *autostartLink = NULL;
1723
    int ret = -1;
1724

1725
    networkDriverLock(driver);
1726
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1727

1728
    if (!network) {
1729 1730
        networkReportError(VIR_ERR_INVALID_NETWORK,
                           "%s", _("no network with matching uuid"));
1731
        goto cleanup;
1732 1733
    }

1734
    if (!network->persistent) {
1735 1736
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot set autostart for transient network"));
1737 1738 1739
        goto cleanup;
    }

1740 1741
    autostart = (autostart != 0);

1742
    if (network->autostart != autostart) {
1743
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir, network->def->name)) == NULL)
1744
            goto cleanup;
1745
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, network->def->name)) == NULL)
1746 1747
            goto cleanup;

1748
        if (autostart) {
1749
            if (virFileMakePath(driver->networkAutostartDir)) {
1750
                virReportSystemError(errno,
1751 1752
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
1753 1754
                goto cleanup;
            }
1755

1756
            if (symlink(configFile, autostartLink) < 0) {
1757
                virReportSystemError(errno,
1758
                                     _("Failed to create symlink '%s' to '%s'"),
1759
                                     autostartLink, configFile);
1760 1761 1762
                goto cleanup;
            }
        } else {
1763
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1764
                virReportSystemError(errno,
1765
                                     _("Failed to delete symlink '%s'"),
1766
                                     autostartLink);
1767 1768
                goto cleanup;
            }
1769 1770
        }

1771
        network->autostart = autostart;
1772
    }
1773
    ret = 0;
1774

1775
cleanup:
1776 1777
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
1778 1779
    if (network)
        virNetworkObjUnlock(network);
1780
    networkDriverUnlock(driver);
1781
    return ret;
1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
}


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 */
1804 1805
    networkIsActive,
    networkIsPersistent,
1806 1807 1808
};

static virStateDriver networkStateDriver = {
1809
    "Network",
1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820
    networkStartup,
    networkShutdown,
    networkReload,
    networkActive,
};

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