bridge_driver.c 57.3 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
static int
networkSaveDnsmasqHostsfile(virNetworkObjPtr network,
                            dnsmasqContext *dctx,
                            bool force)
{
    unsigned int i;

    if (! force && virFileExists(dctx->hostsfile->path))
376
        return 0;
377 378 379

    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
    }

    if (dnsmasqSave(dctx) < 0)
385
        return -1;
386

387
    return 0;
388 389 390
}


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) < 0) {
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 591 592 593 594 595
    int prefix = virNetworkDefPrefix(network->def);

    if (prefix < 0) {
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid prefix or netmask for '%s'"),
                           network->def->bridge);
        goto masqerr1;
    }
596

597
    /* allow forwarding packets from the bridge interface */
598 599
    if (iptablesAddForwardAllowOut(driver->iptables,
                                   &network->def->ipAddress,
600
                                   prefix,
601 602 603 604 605
                                   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);
606 607 608 609
        goto masqerr1;
    }

    /* allow forwarding packets to the bridge interface if they are part of an existing connection */
610 611
    if (iptablesAddForwardAllowRelatedIn(driver->iptables,
                                         &network->def->ipAddress,
612
                                         prefix,
613 614 615 616 617
                                         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);
618 619 620
        goto masqerr2;
    }

621 622 623 624 625
    /*
     * Enable masquerading.
     *
     * We need to end up with 3 rules in the table in this order
     *
E
Eric Blake 已提交
626 627
     *  1. protocol=tcp with sport mapping restriction
     *  2. protocol=udp with sport mapping restriction
628 629 630
     *  3. generic any protocol
     *
     * The sport mappings are required, because default IPtables
E
Eric Blake 已提交
631
     * MASQUERADE maintain port numbers unchanged where possible.
632 633 634 635 636 637 638 639 640 641 642 643 644
     *
     * 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 */
645 646
    if (iptablesAddForwardMasquerade(driver->iptables,
                                     &network->def->ipAddress,
647
                                     prefix,
648 649 650 651 652
                                     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);
653 654 655
        goto masqerr3;
    }

656
    /* UDP with a source port restriction */
657 658
    if (iptablesAddForwardMasquerade(driver->iptables,
                                     &network->def->ipAddress,
659
                                     prefix,
660 661 662 663 664
                                     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);
665 666 667 668
        goto masqerr4;
    }

    /* TCP with a source port restriction */
669 670
    if (iptablesAddForwardMasquerade(driver->iptables,
                                     &network->def->ipAddress,
671
                                     prefix,
672 673 674 675 676
                                     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);
677 678 679
        goto masqerr5;
    }

680
    return 0;
681

682 683
 masqerr5:
    iptablesRemoveForwardMasquerade(driver->iptables,
684
                                    &network->def->ipAddress,
685
                                    prefix,
686 687 688 689
                                    network->def->forwardDev,
                                    "udp");
 masqerr4:
    iptablesRemoveForwardMasquerade(driver->iptables,
690
                                    &network->def->ipAddress,
691
                                    prefix,
692 693
                                    network->def->forwardDev,
                                    NULL);
694 695
 masqerr3:
    iptablesRemoveForwardAllowRelatedIn(driver->iptables,
696
                                        &network->def->ipAddress,
697
                                        prefix,
698 699
                                        network->def->bridge,
                                        network->def->forwardDev);
700 701
 masqerr2:
    iptablesRemoveForwardAllowOut(driver->iptables,
702
                                  &network->def->ipAddress,
703
                                  prefix,
704 705 706
                                  network->def->bridge,
                                  network->def->forwardDev);
 masqerr1:
707
    return -1;
708 709 710
}

static int
711 712
networkAddRoutingIptablesRules(struct network_driver *driver,
                               virNetworkObjPtr network) {
713 714 715 716 717 718 719 720
    int prefix = virNetworkDefPrefix(network->def);

    if (prefix < 0) {
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid prefix or netmask for '%s'"),
                           network->def->bridge);
        goto routeerr1;
    }
721

722
    /* allow routing packets from the bridge interface */
723 724
    if (iptablesAddForwardAllowOut(driver->iptables,
                                   &network->def->ipAddress,
725
                                   prefix,
726 727 728 729 730
                                   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);
731 732 733 734
        goto routeerr1;
    }

    /* allow routing packets to the bridge interface */
735 736
    if (iptablesAddForwardAllowIn(driver->iptables,
                                  &network->def->ipAddress,
737
                                  prefix,
738 739 740 741 742
                                  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);
743 744 745
        goto routeerr2;
    }

746
    return 0;
747 748 749 750


 routeerr2:
    iptablesRemoveForwardAllowOut(driver->iptables,
751
                                  &network->def->ipAddress,
752
                                  prefix,
753 754 755
                                  network->def->bridge,
                                  network->def->forwardDev);
 routeerr1:
756
    return -1;
757 758 759
}

static int
760 761
networkAddIptablesRules(struct network_driver *driver,
                        virNetworkObjPtr network) {
762 763

    /* allow DHCP requests through to dnsmasq */
764 765 766 767
    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);
768 769 770
        goto err1;
    }

771 772 773 774
    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);
775 776 777 778
        goto err2;
    }

    /* allow DNS requests through to dnsmasq */
779 780 781 782
    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);
783 784 785
        goto err3;
    }

786 787 788 789
    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);
790 791 792
        goto err4;
    }

793 794
    /* allow TFTP requests through to dnsmasq */
    if (network->def->tftproot &&
795 796 797 798
        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);
799 800 801
        goto err4tftp;
    }

802 803 804

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

805 806 807 808
    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);
809 810 811
        goto err5;
    }

812 813 814 815
    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);
816 817 818 819
        goto err6;
    }

    /* Allow traffic between guests on the same bridge */
820 821 822 823
    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);
824 825 826 827 828 829
        goto err7;
    }


    /* If masquerading is enabled, set up the rules*/
    if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT &&
830
        networkAddMasqueradingIptablesRules(driver, network) < 0)
831 832 833
        goto err8;
    /* else if routing is enabled, set up the rules*/
    else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE &&
834
             networkAddRoutingIptablesRules(driver, network) < 0)
835 836
        goto err8;

837 838 839 840 841 842
    /* 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).
     */

843 844
    if ((VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
         network->def->nranges) &&
845
        (iptablesAddOutputFixUdpChecksum(driver->iptables,
846
                                         network->def->bridge, 68) < 0)) {
847 848 849 850 851
        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.");
    }

852
    return 0;
853 854 855 856 857 858 859 860 861 862 863

 err8:
    iptablesRemoveForwardAllowCross(driver->iptables,
                                    network->def->bridge);
 err7:
    iptablesRemoveForwardRejectIn(driver->iptables,
                                  network->def->bridge);
 err6:
    iptablesRemoveForwardRejectOut(driver->iptables,
                                   network->def->bridge);
 err5:
864 865 866 867
    if (network->def->tftproot) {
        iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 69);
    }
 err4tftp:
868 869 870 871 872 873 874 875
    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:
876
    return -1;
877 878 879 880 881
}

static void
networkRemoveIptablesRules(struct network_driver *driver,
                         virNetworkObjPtr network) {
882 883
    if (VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
        network->def->nranges) {
884 885 886
        iptablesRemoveOutputFixUdpChecksum(driver->iptables,
                                           network->def->bridge, 68);
    }
887
    if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE) {
888 889 890 891 892 893 894 895 896
        int prefix = virNetworkDefPrefix(network->def);

        if (prefix < 0) {
            networkReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Invalid prefix or netmask for '%s'"),
                               network->def->bridge);
            goto error;
        }

897 898
        if (network->def->forwardType == VIR_NETWORK_FORWARD_NAT) {
            iptablesRemoveForwardMasquerade(driver->iptables,
899
                                            &network->def->ipAddress,
900
                                            prefix,
901 902 903
                                            network->def->forwardDev,
                                            "tcp");
            iptablesRemoveForwardMasquerade(driver->iptables,
904
                                            &network->def->ipAddress,
905
                                            prefix,
906 907 908
                                            network->def->forwardDev,
                                            "udp");
            iptablesRemoveForwardMasquerade(driver->iptables,
909
                                            &network->def->ipAddress,
910
                                            prefix,
911 912
                                            network->def->forwardDev,
                                            NULL);
913
            iptablesRemoveForwardAllowRelatedIn(driver->iptables,
914
                                                &network->def->ipAddress,
915
                                                prefix,
916 917
                                                network->def->bridge,
                                                network->def->forwardDev);
918
        } else if (network->def->forwardType == VIR_NETWORK_FORWARD_ROUTE)
919
            iptablesRemoveForwardAllowIn(driver->iptables,
920
                                         &network->def->ipAddress,
921
                                         prefix,
922 923 924 925
                                         network->def->bridge,
                                         network->def->forwardDev);

        iptablesRemoveForwardAllowOut(driver->iptables,
926
                                      &network->def->ipAddress,
927
                                      prefix,
928 929 930
                                      network->def->bridge,
                                      network->def->forwardDev);
    }
931
error:
932 933 934
    iptablesRemoveForwardAllowCross(driver->iptables, network->def->bridge);
    iptablesRemoveForwardRejectIn(driver->iptables, network->def->bridge);
    iptablesRemoveForwardRejectOut(driver->iptables, network->def->bridge);
935 936
    if (network->def->tftproot)
        iptablesRemoveUdpInput(driver->iptables, network->def->bridge, 69);
937 938 939 940 941 942
    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);
}

943 944 945 946 947 948 949 950 951 952 953 954
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]);
955
            if (networkAddIptablesRules(driver, driver->networks.objs[i]) < 0) {
956 957 958 959 960 961 962 963
                /* failed to add but already logged */
            }
        }

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

964
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
965 966 967
static int
networkEnableIpForwarding(void)
{
968
    return virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n", 0);
969 970
}

971 972
#define SYSCTL_PATH "/proc/sys"

973
static int networkDisableIPV6(virNetworkObjPtr network)
974 975 976 977 978
{
    char *field = NULL;
    int ret = -1;

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

983 984 985 986 987 988
    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;
    }

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

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

1001
    if (virFileWriteStr(field, "0", 0) < 0) {
1002
        virReportSystemError(errno,
1003 1004 1005 1006 1007 1008
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

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

1013
    if (virFileWriteStr(field, "1", 0) < 0) {
1014
        virReportSystemError(errno,
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
                             _("cannot enable %s"), field);
        goto cleanup;
    }

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

1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
#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;
1035
    virSocketAddr netmask;
1036 1037 1038
    char *cur, *buf = NULL;
    enum {MAX_ROUTE_SIZE = 1024*64};

1039
    if (!VIR_SOCKET_IS_FAMILY(&network->def->ipAddress, AF_INET)) {
1040
        /* Only support collision check for IPv4 */
1041
        return 0;
1042 1043
    }

1044 1045 1046 1047 1048 1049
    if (virNetworkDefNetmask(network->def, &netmask) < 0) {
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to get netmask of '%s'"),
                           network->def->bridge);
    }

1050
    net_dest = (network->def->ipAddress.data.inet4.sin_addr.s_addr &
1051
                netmask.data.inet4.sin_addr.s_addr);
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103

    /* 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) &&
1104
            (netmask.data.inet4.sin_addr.s_addr == mask_val)) {
1105
            networkReportError(VIR_ERR_INTERNAL_ERROR,
1106 1107
                               _("Network is already in use by interface %s"),
                               iface);
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
            goto error;
        }
    }

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

1119 1120 1121
static int networkStartNetworkDaemon(struct network_driver *driver,
                                     virNetworkObjPtr network)
{
1122
    int err;
1123
    virErrorPtr save_err;
1124

D
Daniel P. Berrange 已提交
1125
    if (virNetworkObjIsActive(network)) {
1126 1127
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("network is already active"));
1128 1129 1130
        return -1;
    }

1131 1132 1133 1134
    /* Check to see if network collides with an existing route */
    if (networkCheckRouteCollision(network) < 0)
        return -1;

1135
    if ((err = brAddBridge(driver->brctl, network->def->bridge))) {
1136
        virReportSystemError(err,
1137 1138
                             _("cannot create bridge '%s'"),
                             network->def->bridge);
1139 1140 1141
        return -1;
    }

1142
    if (networkDisableIPV6(network) < 0)
1143 1144
        goto err_delbr;

1145 1146 1147 1148 1149
    if ((err = brSetForwardDelay(driver->brctl, network->def->bridge,
                                 network->def->delay))) {
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot set forward delay on bridge '%s'"),
                           network->def->bridge);
1150 1151 1152
        goto err_delbr;
    }

1153 1154
    if ((err = brSetEnableSTP(driver->brctl, network->def->bridge,
                              network->def->stp ? 1 : 0))) {
1155
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1156 1157
                           _("cannot set STP '%s' on bridge '%s'"),
                           network->def->stp ? "on" : "off", network->def->bridge);
1158 1159 1160
        goto err_delbr;
    }

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
    if (VIR_SOCKET_HAS_ADDR(&network->def->ipAddress)) {
        int prefix = virNetworkDefPrefix(network->def);

        if (prefix < 0) {
            networkReportError(VIR_ERR_INTERNAL_ERROR,
                               _("bridge '%s' has an invalid netmask or IP address"),
                               network->def->bridge);
            goto err_delbr;
        }

        if ((err = brAddInetAddress(driver->brctl, network->def->bridge,
                                    &network->def->ipAddress, prefix))) {
            networkReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot set IP address on bridge '%s'"),
                               network->def->bridge);
            goto err_delbr;
        }
1178 1179
    }

1180
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 1))) {
1181
        virReportSystemError(err,
1182 1183
                             _("failed to bring the bridge '%s' up"),
                             network->def->bridge);
1184 1185 1186
        goto err_delbr;
    }

1187
    if (networkAddIptablesRules(driver, network) < 0)
1188 1189 1190
        goto err_delbr1;

    if (network->def->forwardType != VIR_NETWORK_FORWARD_NONE &&
1191
        networkEnableIpForwarding() < 0) {
1192
        virReportSystemError(errno, "%s",
1193
                             _("failed to enable IP forwarding"));
1194 1195 1196
        goto err_delbr2;
    }

1197
    if ((VIR_SOCKET_HAS_ADDR(&network->def->ipAddress) ||
1198
         network->def->nranges) &&
1199
        dhcpStartDhcpDaemon(network) < 0)
1200 1201
        goto err_delbr2;

1202 1203

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

1208 1209 1210 1211
    network->active = 1;

    return 0;

1212 1213 1214 1215 1216 1217
 err_kill:
    if (network->dnsmasqPid > 0) {
        kill(network->dnsmasqPid, SIGTERM);
        network->dnsmasqPid = -1;
    }

1218
 err_delbr2:
1219
    save_err = virSaveLastError();
1220
    networkRemoveIptablesRules(driver, network);
1221 1222 1223 1224
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
1225 1226

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

 err_delbr:
    if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
1235
        char ebuf[1024];
1236
        VIR_WARN("Failed to delete bridge '%s' : %s",
1237
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1238 1239 1240 1241 1242 1243
    }

    return -1;
}


1244 1245 1246
static int networkShutdownNetworkDaemon(struct network_driver *driver,
                                        virNetworkObjPtr network)
{
1247
    int err;
1248
    char *stateFile;
1249

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

D
Daniel P. Berrange 已提交
1252
    if (!virNetworkObjIsActive(network))
1253 1254
        return 0;

1255
    stateFile = virNetworkConfigFile(NETWORK_STATE_DIR, network->def->name);
1256 1257 1258 1259 1260 1261
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

1262 1263 1264 1265 1266
    if (network->dnsmasqPid > 0)
        kill(network->dnsmasqPid, SIGTERM);

    networkRemoveIptablesRules(driver, network);

1267
    char ebuf[1024];
1268
    if ((err = brSetInterfaceUp(driver->brctl, network->def->bridge, 0))) {
1269
        VIR_WARN("Failed to bring down bridge '%s' : %s",
1270
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1271 1272 1273
    }

    if ((err = brDeleteBridge(driver->brctl, network->def->bridge))) {
1274
        VIR_WARN("Failed to delete bridge '%s' : %s",
1275
                 network->def->bridge, virStrerror(err, ebuf, sizeof ebuf));
1276 1277
    }

1278
    /* See if its still alive and really really kill it */
1279
    if (network->dnsmasqPid > 0 &&
1280
        (kill(network->dnsmasqPid, 0) == 0))
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295
        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;
}


1296 1297 1298 1299 1300
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
                                         const unsigned char *uuid) {
    struct network_driver *driver = conn->networkPrivateData;
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;
1301

1302
    networkDriverLock(driver);
1303
    network = virNetworkFindByUUID(&driver->networks, uuid);
1304
    networkDriverUnlock(driver);
1305
    if (!network) {
1306 1307
        networkReportError(VIR_ERR_NO_NETWORK,
                           "%s", _("no network with matching uuid"));
1308
        goto cleanup;
1309 1310
    }

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

cleanup:
1314 1315
    if (network)
        virNetworkObjUnlock(network);
1316
    return ret;
1317 1318
}

1319 1320 1321 1322 1323 1324
static virNetworkPtr networkLookupByName(virConnectPtr conn,
                                         const char *name) {
    struct network_driver *driver = conn->networkPrivateData;
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;

1325
    networkDriverLock(driver);
1326
    network = virNetworkFindByName(&driver->networks, name);
1327
    networkDriverUnlock(driver);
1328
    if (!network) {
1329 1330
        networkReportError(VIR_ERR_NO_NETWORK,
                           _("no network with matching name '%s'"), name);
1331
        goto cleanup;
1332 1333
    }

1334 1335 1336
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
1337 1338
    if (network)
        virNetworkObjUnlock(network);
1339
    return ret;
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
}

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) {
1358
    int nactive = 0, i;
1359
    struct network_driver *driver = conn->networkPrivateData;
1360

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

1370 1371 1372 1373
    return nactive;
}

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

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

1392 1393 1394
    return got;

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

static int networkNumDefinedNetworks(virConnectPtr conn) {
1402
    int ninactive = 0, i;
1403
    struct network_driver *driver = conn->networkPrivateData;
1404

1405 1406 1407
    networkDriverLock(driver);
    for (i = 0 ; i < driver->networks.count ; i++) {
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1408
        if (!virNetworkObjIsActive(driver->networks.objs[i]))
1409
            ninactive++;
1410 1411 1412
        virNetworkObjUnlock(driver->networks.objs[i]);
    }
    networkDriverUnlock(driver);
1413

1414 1415 1416 1417
    return ninactive;
}

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

1421
    networkDriverLock(driver);
1422
    for (i = 0 ; i < driver->networks.count && got < nnames ; i++) {
1423
        virNetworkObjLock(driver->networks.objs[i]);
D
Daniel P. Berrange 已提交
1424
        if (!virNetworkObjIsActive(driver->networks.objs[i])) {
1425
            if (!(names[got] = strdup(driver->networks.objs[i]->def->name))) {
1426
                virNetworkObjUnlock(driver->networks.objs[i]);
1427
                virReportOOMError();
1428 1429 1430 1431
                goto cleanup;
            }
            got++;
        }
1432
        virNetworkObjUnlock(driver->networks.objs[i]);
1433
    }
1434
    networkDriverUnlock(driver);
1435 1436 1437
    return got;

 cleanup:
1438
    networkDriverUnlock(driver);
1439 1440 1441 1442 1443
    for (i = 0 ; i < got ; i++)
        VIR_FREE(names[i]);
    return -1;
}

1444 1445 1446

static int networkIsActive(virNetworkPtr net)
{
1447
    struct network_driver *driver = net->conn->networkPrivateData;
1448 1449 1450 1451 1452 1453 1454
    virNetworkObjPtr obj;
    int ret = -1;

    networkDriverLock(driver);
    obj = virNetworkFindByUUID(&driver->networks, net->uuid);
    networkDriverUnlock(driver);
    if (!obj) {
1455
        networkReportError(VIR_ERR_NO_NETWORK, NULL);
1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467
        goto cleanup;
    }
    ret = virNetworkObjIsActive(obj);

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

static int networkIsPersistent(virNetworkPtr net)
{
1468
    struct network_driver *driver = net->conn->networkPrivateData;
1469 1470 1471 1472 1473 1474 1475
    virNetworkObjPtr obj;
    int ret = -1;

    networkDriverLock(driver);
    obj = virNetworkFindByUUID(&driver->networks, net->uuid);
    networkDriverUnlock(driver);
    if (!obj) {
1476
        networkReportError(VIR_ERR_NO_NETWORK, NULL);
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
        goto cleanup;
    }
    ret = obj->persistent;

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


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

1494 1495
    networkDriverLock(driver);

1496
    if (!(def = virNetworkDefParseString(xml)))
1497
        goto cleanup;
1498

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

1502
    if (virNetworkSetBridgeName(&driver->networks, def, 1))
1503 1504
        goto cleanup;

1505
    if (!(network = virNetworkAssignDef(&driver->networks,
1506 1507 1508
                                        def)))
        goto cleanup;
    def = NULL;
1509

1510
    if (networkStartNetworkDaemon(driver, network) < 0) {
1511 1512
        virNetworkRemoveInactive(&driver->networks,
                                 network);
1513
        network = NULL;
1514
        goto cleanup;
1515 1516
    }

1517 1518 1519 1520
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
    virNetworkDefFree(def);
1521 1522 1523
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1524
    return ret;
1525 1526 1527
}

static virNetworkPtr networkDefine(virConnectPtr conn, const char *xml) {
1528
    struct network_driver *driver = conn->networkPrivateData;
1529
    virNetworkDefPtr def;
1530
    virNetworkObjPtr network = NULL;
1531
    virNetworkPtr ret = NULL;
1532

1533 1534
    networkDriverLock(driver);

1535
    if (!(def = virNetworkDefParseString(xml)))
1536
        goto cleanup;
1537

E
Eric Blake 已提交
1538
    if (virNetworkObjIsDuplicate(&driver->networks, def, 0) < 0)
1539 1540
        goto cleanup;

1541
    if (virNetworkSetBridgeName(&driver->networks, def, 1))
1542 1543
        goto cleanup;

1544
    if (!(network = virNetworkAssignDef(&driver->networks,
1545 1546 1547
                                        def)))
        goto cleanup;
    def = NULL;
1548

1549 1550
    network->persistent = 1;

1551
    if (virNetworkSaveConfig(driver->networkConfigDir,
1552
                             network->newDef ? network->newDef : network->def) < 0) {
1553 1554
        virNetworkRemoveInactive(&driver->networks,
                                 network);
1555
        network = NULL;
1556
        goto cleanup;
1557 1558
    }

1559 1560 1561 1562 1563 1564 1565 1566 1567
    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);
    }

1568 1569 1570 1571
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

cleanup:
    virNetworkDefFree(def);
1572 1573 1574
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1575
    return ret;
1576 1577 1578
}

static int networkUndefine(virNetworkPtr net) {
1579
    struct network_driver *driver = net->conn->networkPrivateData;
1580
    virNetworkObjPtr network = NULL;
1581
    int ret = -1;
1582

1583 1584
    networkDriverLock(driver);

1585
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1586
    if (!network) {
1587
        networkReportError(VIR_ERR_INVALID_NETWORK,
1588 1589
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1590 1591
    }

D
Daniel P. Berrange 已提交
1592
    if (virNetworkObjIsActive(network)) {
1593
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1594 1595
                           "%s", _("network is still active"));
        goto cleanup;
1596 1597
    }

1598
    if (virNetworkDeleteConfig(driver->networkConfigDir,
1599 1600
                               driver->networkAutostartDir,
                               network) < 0)
1601
        goto cleanup;
1602

1603 1604 1605 1606 1607 1608 1609 1610 1611
    if (network->def->nhosts > 0) {
        dnsmasqContext *dctx = dnsmasqContextNew(network->def->name, DNSMASQ_STATE_DIR);
        if (dctx == NULL)
            goto cleanup;

        dnsmasqDelete(dctx);
        dnsmasqContextFree(dctx);
    }

1612 1613
    virNetworkRemoveInactive(&driver->networks,
                             network);
1614
    network = NULL;
1615
    ret = 0;
1616

1617
cleanup:
1618 1619 1620
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
1621
    return ret;
1622 1623 1624
}

static int networkStart(virNetworkPtr net) {
1625 1626 1627
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1628

1629
    networkDriverLock(driver);
1630
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1631

1632
    if (!network) {
1633
        networkReportError(VIR_ERR_INVALID_NETWORK,
1634 1635
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1636 1637
    }

1638
    ret = networkStartNetworkDaemon(driver, network);
1639 1640

cleanup:
1641 1642
    if (network)
        virNetworkObjUnlock(network);
1643
    networkDriverUnlock(driver);
1644
    return ret;
1645 1646 1647
}

static int networkDestroy(virNetworkPtr net) {
1648 1649 1650
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1651

1652
    networkDriverLock(driver);
1653
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1654

1655
    if (!network) {
1656
        networkReportError(VIR_ERR_INVALID_NETWORK,
1657 1658
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1659 1660
    }

D
Daniel P. Berrange 已提交
1661
    if (!virNetworkObjIsActive(network)) {
1662
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1663 1664 1665 1666
                           "%s", _("network is not active"));
        goto cleanup;
    }

1667
    ret = networkShutdownNetworkDaemon(driver, network);
1668
    if (!network->persistent) {
1669 1670 1671 1672
        virNetworkRemoveInactive(&driver->networks,
                                 network);
        network = NULL;
    }
1673

1674
cleanup:
1675 1676
    if (network)
        virNetworkObjUnlock(network);
1677
    networkDriverUnlock(driver);
1678 1679 1680 1681
    return ret;
}

static char *networkDumpXML(virNetworkPtr net, int flags ATTRIBUTE_UNUSED) {
1682 1683 1684
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char *ret = NULL;
1685

1686
    networkDriverLock(driver);
1687
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1688 1689
    networkDriverUnlock(driver);

1690
    if (!network) {
1691
        networkReportError(VIR_ERR_INVALID_NETWORK,
1692 1693
                           "%s", _("no network with matching uuid"));
        goto cleanup;
1694 1695
    }

1696
    ret = virNetworkDefFormat(network->def);
1697 1698

cleanup:
1699 1700
    if (network)
        virNetworkObjUnlock(network);
1701
    return ret;
1702 1703 1704
}

static char *networkGetBridgeName(virNetworkPtr net) {
1705 1706 1707 1708
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char *bridge = NULL;

1709
    networkDriverLock(driver);
1710
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1711 1712
    networkDriverUnlock(driver);

1713
    if (!network) {
1714
        networkReportError(VIR_ERR_INVALID_NETWORK,
1715 1716
                           "%s", _("no network with matching id"));
        goto cleanup;
1717 1718
    }

1719
    if (!(network->def->bridge)) {
1720
        networkReportError(VIR_ERR_INTERNAL_ERROR,
1721 1722 1723 1724 1725
                           _("network '%s' does not have a bridge name."),
                           network->def->name);
        goto cleanup;
    }

1726
    bridge = strdup(network->def->bridge);
1727
    if (!bridge)
1728
        virReportOOMError();
1729 1730

cleanup:
1731 1732
    if (network)
        virNetworkObjUnlock(network);
1733 1734 1735 1736 1737
    return bridge;
}

static int networkGetAutostart(virNetworkPtr net,
                             int *autostart) {
1738 1739 1740
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    int ret = -1;
1741

1742
    networkDriverLock(driver);
1743
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1744
    networkDriverUnlock(driver);
1745
    if (!network) {
1746 1747
        networkReportError(VIR_ERR_INVALID_NETWORK,
                           "%s", _("no network with matching uuid"));
1748
        goto cleanup;
1749 1750 1751
    }

    *autostart = network->autostart;
1752
    ret = 0;
1753

1754
cleanup:
1755 1756
    if (network)
        virNetworkObjUnlock(network);
1757
    return ret;
1758 1759 1760
}

static int networkSetAutostart(virNetworkPtr net,
1761
                               int autostart) {
1762 1763
    struct network_driver *driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
1764
    char *configFile = NULL, *autostartLink = NULL;
1765
    int ret = -1;
1766

1767
    networkDriverLock(driver);
1768
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
1769

1770
    if (!network) {
1771 1772
        networkReportError(VIR_ERR_INVALID_NETWORK,
                           "%s", _("no network with matching uuid"));
1773
        goto cleanup;
1774 1775
    }

1776
    if (!network->persistent) {
1777 1778
        networkReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("cannot set autostart for transient network"));
1779 1780 1781
        goto cleanup;
    }

1782 1783
    autostart = (autostart != 0);

1784
    if (network->autostart != autostart) {
1785
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir, network->def->name)) == NULL)
1786
            goto cleanup;
1787
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, network->def->name)) == NULL)
1788 1789
            goto cleanup;

1790
        if (autostart) {
1791
            if (virFileMakePath(driver->networkAutostartDir)) {
1792
                virReportSystemError(errno,
1793 1794
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
1795 1796
                goto cleanup;
            }
1797

1798
            if (symlink(configFile, autostartLink) < 0) {
1799
                virReportSystemError(errno,
1800
                                     _("Failed to create symlink '%s' to '%s'"),
1801
                                     autostartLink, configFile);
1802 1803 1804
                goto cleanup;
            }
        } else {
1805
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
1806
                virReportSystemError(errno,
1807
                                     _("Failed to delete symlink '%s'"),
1808
                                     autostartLink);
1809 1810
                goto cleanup;
            }
1811 1812
        }

1813
        network->autostart = autostart;
1814
    }
1815
    ret = 0;
1816

1817
cleanup:
1818 1819
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
1820 1821
    if (network)
        virNetworkObjUnlock(network);
1822
    networkDriverUnlock(driver);
1823
    return ret;
1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845
}


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 */
1846 1847
    networkIsActive,
    networkIsPersistent,
1848 1849 1850
};

static virStateDriver networkStateDriver = {
1851
    "Network",
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
    networkStartup,
    networkShutdown,
    networkReload,
    networkActive,
};

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