You need to sign in or sign up before continuing.
bridge_driver.c 56.1 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
    /* allow forwarding packets from the bridge interface */
590 591 592 593 594 595 596 597
    if (iptablesAddForwardAllowOut(driver->iptables,
                                   &network->def->ipAddress,
                                   &network->def->netmask,
                                   network->def->bridge,
                                   network->def->forwardDev) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to allow forwarding from '%s'"),
                           network->def->bridge);
598 599 600 601
        goto masqerr1;
    }

    /* allow forwarding packets to the bridge interface if they are part of an existing connection */
602 603 604 605 606 607 608 609
    if (iptablesAddForwardAllowRelatedIn(driver->iptables,
                                         &network->def->ipAddress,
                                         &network->def->netmask,
                                         network->def->bridge,
                                         network->def->forwardDev) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("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 638 639 640 641 642 643 644
    if (iptablesAddForwardMasquerade(driver->iptables,
                                     &network->def->ipAddress,
                                     &network->def->netmask,
                                     network->def->forwardDev,
                                     NULL) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to enable masquerading to '%s'"),
                           network->def->forwardDev ? network->def->forwardDev : NULL);
645 646 647
        goto masqerr3;
    }

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

    /* TCP with a source port restriction */
661 662 663 664 665 666 667 668
    if (iptablesAddForwardMasquerade(driver->iptables,
                                     &network->def->ipAddress,
                                     &network->def->netmask,
                                     network->def->forwardDev,
                                     "tcp") < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to enable TCP masquerading to '%s'"),
                           network->def->forwardDev ? network->def->forwardDev : NULL);
669 670 671
        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
    /* allow routing packets from the bridge interface */
707 708 709 710 711 712 713 714
    if (iptablesAddForwardAllowOut(driver->iptables,
                                   &network->def->ipAddress,
                                   &network->def->netmask,
                                   network->def->bridge,
                                   network->def->forwardDev) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to allow routing from '%s'"),
                           network->def->bridge);
715 716 717 718
        goto routeerr1;
    }

    /* allow routing packets to the bridge interface */
719 720 721 722 723 724 725 726
    if (iptablesAddForwardAllowIn(driver->iptables,
                                  &network->def->ipAddress,
                                  &network->def->netmask,
                                  network->def->bridge,
                                  network->def->forwardDev) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("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

    /* allow DHCP requests through to dnsmasq */
748 749 750 751
    if (iptablesAddTcpInput(driver->iptables, network->def->bridge, 67) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to allow DHCP requests from '%s'"),
                           network->def->bridge);
752 753 754
        goto err1;
    }

755 756 757 758
    if (iptablesAddUdpInput(driver->iptables, network->def->bridge, 67) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to allow DHCP requests from '%s'"),
                           network->def->bridge);
759 760 761 762
        goto err2;
    }

    /* allow DNS requests through to dnsmasq */
763 764 765 766
    if (iptablesAddTcpInput(driver->iptables, network->def->bridge, 53) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to allow DNS requests from '%s'"),
                           network->def->bridge);
767 768 769
        goto err3;
    }

770 771 772 773
    if (iptablesAddUdpInput(driver->iptables, network->def->bridge, 53) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to allow DNS requests from '%s'"),
                           network->def->bridge);
774 775 776
        goto err4;
    }

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

786 787 788

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

789 790 791 792
    if (iptablesAddForwardRejectOut(driver->iptables, network->def->bridge) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to block outbound traffic from '%s'"),
                           network->def->bridge);
793 794 795
        goto err5;
    }

796 797 798 799
    if (iptablesAddForwardRejectIn(driver->iptables, network->def->bridge) < 0) {
        networkReportError(VIR_ERR_SYSTEM_ERROR,
                           _("failed to add iptables rule to block inbound traffic to '%s'"),
                           network->def->bridge);
800 801 802 803
        goto err6;
    }

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


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

821 822 823 824 825 826
    /* 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).
     */

827 828
    if ((VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
         network->def->nranges) &&
829
        (iptablesAddOutputFixUdpChecksum(driver->iptables,
830
                                         network->def->bridge, 68) < 0)) {
831 832 833 834 835
        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.");
    }

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

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

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

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

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

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

945 946
#define SYSCTL_PATH "/proc/sys"

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

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

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

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

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

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

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

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

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

999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
#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};

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

1018 1019
    net_dest = (network->def->ipAddress.data.inet4.sin_addr.s_addr &
                network->def->netmask.data.inet4.sin_addr.s_addr);
1020 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

    /* 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) &&
1072
            (network->def->netmask.data.inet4.sin_addr.s_addr == mask_val)) {
1073
            networkReportError(VIR_ERR_INTERNAL_ERROR,
1074 1075
                               _("Network is already in use by interface %s"),
                               iface);
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
            goto error;
        }
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

1159 1160

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

1165 1166 1167 1168
    network->active = 1;

    return 0;

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

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

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

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

    return -1;
}


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

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

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

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

    unlink(stateFile);
    VIR_FREE(stateFile);

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

    networkRemoveIptablesRules(driver, network);

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

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

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


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

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

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

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

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

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

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

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

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

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

1327 1328 1329 1330
    return nactive;
}

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

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

1349 1350 1351
    return got;

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

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

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

1371 1372 1373 1374
    return ninactive;
}

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

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

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

1401 1402 1403

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

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

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

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

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

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


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

1451 1452
    networkDriverLock(driver);

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

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

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

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

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

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

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

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

1490 1491
    networkDriverLock(driver);

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

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

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

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

1506 1507
    network->persistent = 1;

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

1516 1517 1518 1519 1520 1521 1522 1523 1524
    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);
    }

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

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

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

1540 1541
    networkDriverLock(driver);

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

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

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

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

        dnsmasqDelete(dctx);
        dnsmasqContextFree(dctx);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1739 1740
    autostart = (autostart != 0);

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

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

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

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

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


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

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

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