bridge_driver.c 145.3 KB
Newer Older
1
/*
2
 * bridge_driver.c: core driver methods for managing network
3
 *
4
 * Copyright (C) 2006-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.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 <sys/wait.h>
#include <sys/ioctl.h>
43
#include <net/if.h>
44 45 46
#if HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
47

48
#include "virerror.h"
49
#include "datatypes.h"
50
#include "bridge_driver.h"
51
#include "bridge_driver_platform.h"
52
#include "network_conf.h"
53
#include "device_conf.h"
54
#include "driver.h"
55
#include "virbuffer.h"
56
#include "virpidfile.h"
57
#include "vircommand.h"
58
#include "viralloc.h"
59
#include "viruuid.h"
60
#include "viriptables.h"
61
#include "virlog.h"
62
#include "virdnsmasq.h"
63
#include "configmake.h"
64
#include "virnetdev.h"
65
#include "virpci.h"
66 67
#include "virnetdevbridge.h"
#include "virnetdevtap.h"
68
#include "virnetdevvportprofile.h"
69
#include "virdbus.h"
70
#include "virfile.h"
71
#include "virstring.h"
72
#include "viraccessapicheck.h"
73
#include "network_event.h"
74
#include "virhook.h"
75

76 77
#define VIR_FROM_THIS VIR_FROM_NETWORK

78 79
VIR_LOG_INIT("network.bridge_driver");

80
static void networkDriverLock(virNetworkDriverStatePtr driver)
81
{
82
    virMutexLock(&driver->lock);
83
}
84
static void networkDriverUnlock(virNetworkDriverStatePtr driver)
85
{
86
    virMutexUnlock(&driver->lock);
87 88
}

89
static int networkStateCleanup(void);
90

91
static int networkStartNetwork(virNetworkDriverStatePtr driver,
92 93
                               virNetworkObjPtr network);

94
static int networkShutdownNetwork(virNetworkDriverStatePtr driver,
95 96
                                  virNetworkObjPtr network);

97
static int networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
98
                                     virNetworkObjPtr network);
99

100
static int networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
R
Roman Bogorodskiy 已提交
101
                                         virNetworkObjPtr network);
102

103
static int networkStartNetworkExternal(virNetworkDriverStatePtr driver,
104 105
                                     virNetworkObjPtr network);

106
static int networkShutdownNetworkExternal(virNetworkDriverStatePtr driver,
107
                                        virNetworkObjPtr network);
108

109
static void networkReloadFirewallRules(virNetworkDriverStatePtr driver);
110
static void networkRefreshDaemons(virNetworkDriverStatePtr driver);
111

112 113 114 115 116
static int networkPlugBandwidth(virNetworkObjPtr net,
                                virDomainNetDefPtr iface);
static int networkUnplugBandwidth(virNetworkObjPtr net,
                                  virDomainNetDefPtr iface);

117 118 119
static void networkNetworkObjTaint(virNetworkObjPtr net,
                                   enum virNetworkTaintFlags taint);

120
static virNetworkDriverStatePtr driverState = NULL;
121

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
static virNetworkObjPtr
networkObjFromNetwork(virNetworkPtr net)
{
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
    virNetworkObjPtr network;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

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

    if (!network) {
        virUUIDFormat(net->uuid, uuidstr);
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching uuid '%s' (%s)"),
                       uuidstr, net->name);
    }

    return network;
}

143 144 145
static int
networkRunHook(virNetworkObjPtr network,
               virDomainDefPtr dom,
146
               virDomainNetDefPtr iface,
147 148 149 150 151 152 153 154 155
               int op,
               int sub_op)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *xml = NULL, *net_xml = NULL, *dom_xml = NULL;
    int hookret;
    int ret = -1;

    if (virHookPresent(VIR_HOOK_DRIVER_NETWORK)) {
156 157 158 159 160 161
        if (!network) {
            VIR_DEBUG("Not running hook as @network is NULL");
            ret = 0;
            goto cleanup;
        }

162 163
        virBufferAddLit(&buf, "<hookData>\n");
        virBufferAdjustIndent(&buf, 2);
164 165
        if (iface && virDomainNetDefFormat(&buf, iface, 0) < 0)
            goto cleanup;
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
        if (virNetworkDefFormatBuf(&buf, network->def, 0) < 0)
            goto cleanup;
        if (dom && virDomainDefFormatInternal(dom, 0, &buf) < 0)
            goto cleanup;

        virBufferAdjustIndent(&buf, -2);
        virBufferAddLit(&buf, "</hookData>");

        if (virBufferError(&buf) ||
            !(xml = virBufferContentAndReset(&buf)))
            goto cleanup;

        hookret = virHookCall(VIR_HOOK_DRIVER_NETWORK, network->def->name,
                              op, sub_op, NULL, xml, NULL);

        /*
         * If the script raised an error, pass it to the callee.
         */
        if (hookret < 0)
            goto cleanup;
186 187

        networkNetworkObjTaint(network, VIR_NETWORK_TAINT_HOOK);
188 189 190
    }

    ret = 0;
191
 cleanup:
192 193 194 195 196 197 198
    virBufferFreeAndReset(&buf);
    VIR_FREE(xml);
    VIR_FREE(net_xml);
    VIR_FREE(dom_xml);
    return ret;
}

199
static char *
200
networkDnsmasqLeaseFileNameDefault(const char *netname)
201 202 203
{
    char *leasefile;

204 205
    ignore_value(virAsprintf(&leasefile, "%s/%s.leases",
                             driverState->dnsmasqStateDir, netname));
206 207 208
    return leasefile;
}

209 210 211
networkDnsmasqLeaseFileNameFunc networkDnsmasqLeaseFileName =
    networkDnsmasqLeaseFileNameDefault;

212 213 214 215 216
static char *
networkDnsmasqConfigFileName(const char *netname)
{
    char *conffile;

217 218
    ignore_value(virAsprintf(&conffile, "%s/%s.conf",
                             driverState->dnsmasqStateDir, netname));
219 220 221
    return conffile;
}

222 223 224 225 226 227
static char *
networkRadvdPidfileBasename(const char *netname)
{
    /* this is simple but we want to be sure it's consistently done */
    char *pidfilebase;

228
    ignore_value(virAsprintf(&pidfilebase, "%s-radvd", netname));
229 230 231 232 233 234 235 236
    return pidfilebase;
}

static char *
networkRadvdConfigFileName(const char *netname)
{
    char *configfile;

237 238
    ignore_value(virAsprintf(&configfile, "%s/%s-radvd.conf",
                             driverState->radvdStateDir, netname));
239 240
    return configfile;
}
241

242 243
/* do needed cleanup steps and remove the network from the list */
static int
244
networkRemoveInactive(virNetworkDriverStatePtr driver,
245 246 247 248
                      virNetworkObjPtr net)
{
    char *leasefile = NULL;
    char *radvdconfigfile = NULL;
249
    char *configfile = NULL;
250
    char *radvdpidbase = NULL;
251
    char *statusfile = NULL;
252 253 254 255 256 257
    dnsmasqContext *dctx = NULL;
    virNetworkDefPtr def = virNetworkObjGetPersistentDef(net);

    int ret = -1;

    /* remove the (possibly) existing dnsmasq and radvd files */
258 259
    if (!(dctx = dnsmasqContextNew(def->name,
                                   driverState->dnsmasqStateDir))) {
260
        goto cleanup;
261
    }
262 263 264 265 266

    if (!(leasefile = networkDnsmasqLeaseFileName(def->name)))
        goto cleanup;

    if (!(radvdconfigfile = networkRadvdConfigFileName(def->name)))
267
        goto cleanup;
268 269

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
270
        goto cleanup;
271

272
    if (!(configfile = networkDnsmasqConfigFileName(def->name)))
273
        goto cleanup;
274

275 276
    if (!(statusfile
          = virNetworkConfigFile(driverState->stateDir, def->name)))
277
        goto cleanup;
278

279 280 281
    /* dnsmasq */
    dnsmasqDelete(dctx);
    unlink(leasefile);
282
    unlink(configfile);
283 284 285

    /* radvd */
    unlink(radvdconfigfile);
286
    virPidFileDelete(driverState->pidDir, radvdpidbase);
287

288 289 290
    /* remove status file */
    unlink(statusfile);

291 292 293 294 295
    /* remove the network definition */
    virNetworkRemoveInactive(&driver->networks, net);

    ret = 0;

296
 cleanup:
297
    VIR_FREE(leasefile);
298
    VIR_FREE(configfile);
299 300
    VIR_FREE(radvdconfigfile);
    VIR_FREE(radvdpidbase);
301
    VIR_FREE(statusfile);
302 303 304 305
    dnsmasqContextFree(dctx);
    return ret;
}

306 307 308
static char *
networkBridgeDummyNicName(const char *brname)
{
309
    static const char dummyNicSuffix[] = "-nic";
310 311
    char *nicname;

312 313 314 315 316 317 318
    if (strlen(brname) + sizeof(dummyNicSuffix) > IFNAMSIZ) {
        /* because the length of an ifname is limited to IFNAMSIZ-1
         * (usually 15), and we're adding 4 more characters, we must
         * truncate the original name to 11 to fit. In order to catch
         * a possible numeric ending (eg virbr0, virbr1, etc), we grab
         * the first 8 and last 3 characters of the string.
         */
319 320 321 322 323
        ignore_value(virAsprintf(&nicname, "%.*s%s%s",
                                 /* space for last 3 chars + "-nic" + NULL */
                                 (int)(IFNAMSIZ - (3 + sizeof(dummyNicSuffix))),
                                 brname, brname + strlen(brname) - 3,
                                 dummyNicSuffix));
324
    } else {
325
        ignore_value(virAsprintf(&nicname, "%s%s", brname, dummyNicSuffix));
326
    }
327 328 329
    return nicname;
}

330
static void
331
networkFindActiveConfigs(virNetworkDriverStatePtr driver)
332
{
333
    size_t i;
334

335
    for (i = 0; i < driver->networks.count; i++) {
336 337 338 339 340 341
        virNetworkObjPtr obj = driver->networks.objs[i];

        virNetworkObjLock(obj);

        /* If bridge exists, then mark it active */
        if (obj->def->bridge &&
H
Hu Tao 已提交
342
            virNetDevExists(obj->def->bridge) == 1) {
343 344
            obj->active = 1;

345 346
            /* Try and read dnsmasq/radvd pids if any */
            if (obj->def->ips && (obj->def->nips > 0)) {
347 348
                char *radvdpidbase;

349
                ignore_value(virPidFileReadIfAlive(driverState->pidDir, obj->def->name,
350 351
                                                   &obj->dnsmasqPid,
                                                   dnsmasqCapsGetBinaryPath(driver->dnsmasqCaps)));
352

353
                if (!(radvdpidbase = networkRadvdPidfileBasename(obj->def->name)))
354
                    goto cleanup;
355
                ignore_value(virPidFileReadIfAlive(driverState->pidDir, radvdpidbase,
356
                                                   &obj->radvdPid, RADVD));
357
                VIR_FREE(radvdpidbase);
358 359 360
            }
        }

361
    cleanup:
362 363
        virNetworkObjUnlock(obj);
    }
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378

    /* remove inactive transient networks */
    i = 0;
    while (i < driver->networks.count) {
        virNetworkObjPtr obj = driver->networks.objs[i];
        virNetworkObjLock(obj);

        if (!obj->persistent && !obj->active) {
            networkRemoveInactive(driver, obj);
            continue;
        }

        virNetworkObjUnlock(obj);
        i++;
    }
379 380 381
}


382
static void
383 384
networkAutostartConfigs(virNetworkDriverStatePtr driver)
{
385
    size_t i;
386

387
    for (i = 0; i < driver->networks.count; i++) {
388
        virNetworkObjLock(driver->networks.objs[i]);
389
        if (driver->networks.objs[i]->autostart &&
390 391
            !virNetworkObjIsActive(driver->networks.objs[i])) {
            if (networkStartNetwork(driver, driver->networks.objs[i]) < 0) {
392
            /* failed to start but already logged */
393
            }
394
        }
395
        virNetworkObjUnlock(driver->networks.objs[i]);
396 397 398
    }
}

399 400 401
#if HAVE_FIREWALLD
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
402 403
                             DBusMessage *message, void *user_data)
{
404
    virNetworkDriverStatePtr _driverState = user_data;
405 406 407 408 409 410 411

    if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
                               "NameOwnerChanged") ||
        dbus_message_is_signal(message, "org.fedoraproject.FirewallD1",
                               "Reloaded"))
    {
        VIR_DEBUG("Reload in bridge_driver because of firewalld.");
412
        networkReloadFirewallRules(_driverState);
413 414 415 416 417 418
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

419
/**
420
 * networkStateInitialize:
421 422 423 424
 *
 * Initialization function for the QEmu daemon
 */
static int
425 426 427
networkStateInitialize(bool privileged,
                       virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
428
{
429 430 431
    int ret = -1;
    char *configdir = NULL;
    char *rundir = NULL;
432 433 434
#ifdef HAVE_FIREWALLD
    DBusConnection *sysbus = NULL;
#endif
435 436

    if (VIR_ALLOC(driverState) < 0)
437
        goto error;
438

439 440 441 442
    if (virMutexInit(&driverState->lock) < 0) {
        VIR_FREE(driverState);
        goto error;
    }
443 444
    networkDriverLock(driverState);

445 446 447 448 449 450 451 452 453
    /* configuration/state paths are one of
     * ~/.config/libvirt/... (session/unprivileged)
     * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
     *
     * NB: The qemu driver puts its domain state in /var/run, and I
     * think the network driver should have used /var/run too (instead
     * of /var/lib), but it's been this way for a long time, and we
     * probably shouldn't change it now.
     */
454
    if (privileged) {
455 456 457 458 459 460 461 462 463 464 465 466 467
        if (VIR_STRDUP(driverState->networkConfigDir,
                       SYSCONFDIR "/libvirt/qemu/networks") < 0 ||
            VIR_STRDUP(driverState->networkAutostartDir,
                       SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
            VIR_STRDUP(driverState->stateDir,
                       LOCALSTATEDIR "/lib/libvirt/network") < 0 ||
            VIR_STRDUP(driverState->pidDir,
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
            VIR_STRDUP(driverState->dnsmasqStateDir,
                       LOCALSTATEDIR "/lib/libvirt/dnsmasq") < 0 ||
            VIR_STRDUP(driverState->radvdStateDir,
                       LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
            goto error;
468
    } else {
469 470 471
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
472
            goto error;
473

474 475 476 477 478 479 480 481 482 483 484 485
        if ((virAsprintf(&driverState->networkConfigDir,
                         "%s/qemu/networks", configdir) < 0) ||
            (virAsprintf(&driverState->networkAutostartDir,
                         "%s/qemu/networks/autostart", configdir) < 0) ||
            (virAsprintf(&driverState->stateDir,
                         "%s/network/lib", rundir) < 0) ||
            (virAsprintf(&driverState->pidDir,
                         "%s/network/run", rundir) < 0) ||
            (virAsprintf(&driverState->dnsmasqStateDir,
                         "%s/dnsmasq/lib", rundir) < 0) ||
            (virAsprintf(&driverState->radvdStateDir,
                         "%s/radvd/lib", rundir) < 0)) {
486
            goto error;
487
        }
488 489
    }

490 491
    /* if this fails now, it will be retried later with dnsmasqCapsRefresh() */
    driverState->dnsmasqCaps = dnsmasqCapsNewFromBinary(DNSMASQ);
492

493
    if (virNetworkLoadAllState(&driverState->networks,
494
                               driverState->stateDir) < 0)
495 496
        goto error;

497
    if (virNetworkLoadAllConfigs(&driverState->networks,
498
                                 driverState->networkConfigDir,
499 500 501
                                 driverState->networkAutostartDir) < 0)
        goto error;

502
    networkFindActiveConfigs(driverState);
503
    networkReloadFirewallRules(driverState);
504
    networkRefreshDaemons(driverState);
505

506 507
    driverState->networkEventState = virObjectEventStateNew();

508 509
    networkDriverUnlock(driverState);

510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
#ifdef HAVE_FIREWALLD
    if (!(sysbus = virDBusGetSystemBus())) {
        virErrorPtr err = virGetLastError();
        VIR_WARN("DBus not available, disabling firewalld support "
                 "in bridge_driver: %s", err->message);
    } else {
        /* add matches for
         * NameOwnerChanged on org.freedesktop.DBus for firewalld start/stop
         * Reloaded on org.fedoraproject.FirewallD1 for firewalld reload
         */
        dbus_bus_add_match(sysbus,
                           "type='signal'"
                           ",interface='"DBUS_INTERFACE_DBUS"'"
                           ",member='NameOwnerChanged'"
                           ",arg0='org.fedoraproject.FirewallD1'",
                           NULL);
        dbus_bus_add_match(sysbus,
                           "type='signal'"
                           ",interface='org.fedoraproject.FirewallD1'"
                           ",member='Reloaded'",
                           NULL);
        dbus_connection_add_filter(sysbus, firewalld_dbus_filter_bridge,
                                   driverState, NULL);
    }
#endif

536
    ret = 0;
537
 cleanup:
538 539 540
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
541

542
 error:
543 544
    if (driverState)
        networkDriverUnlock(driverState);
545
    networkStateCleanup();
546
    goto cleanup;
547 548
}

549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
/**
 * networkStateAutoStart:
 *
 * Function to AutoStart the bridge configs
 */
static void
networkStateAutoStart(void)
{
    if (!driverState)
        return;

    networkDriverLock(driverState);
    networkAutostartConfigs(driverState);
    networkDriverUnlock(driverState);
}

565
/**
566
 * networkStateReload:
567 568 569 570 571
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
572 573
networkStateReload(void)
{
574 575 576
    if (!driverState)
        return 0;

577
    networkDriverLock(driverState);
578
    virNetworkLoadAllState(&driverState->networks,
579
                           driverState->stateDir);
580
    virNetworkLoadAllConfigs(&driverState->networks,
581 582
                             driverState->networkConfigDir,
                             driverState->networkAutostartDir);
583
    networkReloadFirewallRules(driverState);
584
    networkRefreshDaemons(driverState);
585
    networkAutostartConfigs(driverState);
586
    networkDriverUnlock(driverState);
587 588 589 590 591
    return 0;
}


/**
592
 * networkStateCleanup:
593 594 595 596
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
597 598
networkStateCleanup(void)
{
599 600 601
    if (!driverState)
        return -1;

602 603
    networkDriverLock(driverState);

604 605
    virObjectEventStateFree(driverState->networkEventState);

606
    /* free inactive networks */
607
    virNetworkObjListFree(&driverState->networks);
608 609 610

    VIR_FREE(driverState->networkConfigDir);
    VIR_FREE(driverState->networkAutostartDir);
611 612 613 614
    VIR_FREE(driverState->stateDir);
    VIR_FREE(driverState->pidDir);
    VIR_FREE(driverState->dnsmasqStateDir);
    VIR_FREE(driverState->radvdStateDir);
615

616 617
    virObjectUnref(driverState->dnsmasqCaps);

618
    networkDriverUnlock(driverState);
619
    virMutexDestroy(&driverState->lock);
620

621 622 623 624 625 626
    VIR_FREE(driverState);

    return 0;
}


627 628 629 630 631 632 633
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
networkKillDaemon(pid_t pid, const char *daemonName, const char *networkName)
{
634 635
    size_t i;
    int ret = -1;
636 637 638 639 640 641 642
    const char *signame = "TERM";

    /* send SIGTERM, then wait up to 3 seconds for the process to
     * disappear, send SIGKILL, then wait for up to another 2
     * seconds. If that fails, log a warning and continue, hoping
     * for the best.
     */
643
    for (i = 0; i < 25; i++) {
644
        int signum = 0;
645
        if (i == 0)
646
            signum = SIGTERM;
647
        else if (i == 15) {
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
            signum = SIGKILL;
            signame = "KILL";
        }
        if (kill(pid, signum) < 0) {
            if (errno == ESRCH) {
                ret = 0;
            } else {
                char ebuf[1024];
                VIR_WARN("Failed to terminate %s process %d "
                         "for network '%s' with SIG%s: %s",
                         daemonName, pid, networkName, signame,
                         virStrerror(errno, ebuf, sizeof(ebuf)));
            }
            goto cleanup;
        }
        /* NB: since networks have no reference count like
         * domains, there is no safe way to unlock the network
         * object temporarily, and so we can't follow the
         * procedure used by the qemu driver of 1) unlock driver
         * 2) sleep, 3) add ref to object 4) unlock object, 5)
         * re-lock driver, 6) re-lock object. We may need to add
         * that functionality eventually, but for now this
         * function is rarely used and, at worst, leaving the
         * network driver locked during this loop of sleeps will
         * have the effect of holding up any other thread trying
         * to make modifications to a network for up to 5 seconds;
         * since modifications to networks are much less common
         * than modifications to domains, this seems a reasonable
         * tradeoff in exchange for less code disruption.
         */
        usleep(20 * 1000);
    }
    VIR_WARN("Timed out waiting after SIG%s to %s process %d "
             "(network '%s')",
             signame, daemonName, pid, networkName);
683
 cleanup:
684 685 686
    return ret;
}

G
Gene Czarcinski 已提交
687 688 689 690
    /* the following does not build a file, it builds a list
     * which is later saved into a file
     */

691
static int
G
Gene Czarcinski 已提交
692 693
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
                                 virNetworkIpDefPtr ipdef)
694
{
695
    size_t i;
G
Gene Czarcinski 已提交
696
    bool ipv6 = false;
697

G
Gene Czarcinski 已提交
698 699
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
700 701
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
702
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
703 704
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
705
                return -1;
706
    }
707

G
Gene Czarcinski 已提交
708 709 710 711 712 713 714
    return 0;
}

static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
715
    size_t i, j;
G
Gene Czarcinski 已提交
716

717 718
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
719
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
720
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
721
                for (j = 0; j < host->nnames; j++)
722 723
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
724 725
            }
        }
726 727
    }

728
    return 0;
729 730 731
}


732 733
int
networkDnsmasqConfContents(virNetworkObjPtr network,
734 735 736 737
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
                           dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
738
{
739
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
740
    int r, ret = -1;
741
    int nbleases = 0;
742
    size_t i;
743 744 745 746
    char *record = NULL;
    char *recordPort = NULL;
    char *recordWeight = NULL;
    char *recordPriority = NULL;
747
    virNetworkDNSDefPtr dns = &network->def->dns;
G
Gene Czarcinski 已提交
748 749
    virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
    bool ipv6SLAAC;
750

751 752
    *configstr = NULL;

753
    /*
754 755 756
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
757
     *
758 759
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
760
     */
761 762 763 764 765 766

    /*
     * Needed to ensure dnsmasq uses same algorithm for processing
     * multiple namedriver entries in /etc/resolv.conf as GLibC.
     */

767 768
    /* create dnsmasq config file appropriate for this network */
    virBufferAsprintf(&configbuf,
769 770 771 772 773 774 775
                      "##WARNING:  THIS IS AN AUTO-GENERATED FILE. "
                      "CHANGES TO IT ARE LIKELY TO BE\n"
                      "##OVERWRITTEN AND LOST.  Changes to this "
                      "configuration should be made using:\n"
                      "##    virsh net-edit %s\n"
                      "## or other application using the libvirt API.\n"
                      "##\n## dnsmasq conf file created by libvirt\n"
776
                      "strict-order\n",
777 778
                      network->def->name);

779 780 781 782 783 784 785 786
    if (network->def->dns.forwarders) {
        virBufferAddLit(&configbuf, "no-resolv\n");
        for (i = 0; i < network->def->dns.nfwds; i++) {
            virBufferAsprintf(&configbuf, "server=%s\n",
                               network->def->dns.forwarders[i]);
        }
    }

787
    if (network->def->domain) {
788
        virBufferAsprintf(&configbuf,
789 790 791 792
                          "domain=%s\n"
                          "expand-hosts\n",
                          network->def->domain);
    }
793

794 795
    if (network->def->dns.forwardPlainNames
        == VIR_NETWORK_DNS_FORWARD_PLAIN_NAMES_NO) {
796 797 798 799
        virBufferAddLit(&configbuf, "domain-needed\n");
        /* need to specify local=// whether or not a domain is
         * specified, unless the config says we should forward "plain"
         * names (i.e. not fully qualified, no '.' characters)
800
         */
801
        virBufferAddLit(&configbuf, "local=//\n");
802
    }
803

804
    if (pidfile)
805
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
806

807 808 809
    /* dnsmasq will *always* listen on localhost unless told otherwise */
    virBufferAddLit(&configbuf, "except-interface=lo\n");

810 811 812 813 814 815 816 817
    if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_BIND_DYNAMIC)) {
        /* using --bind-dynamic with only --interface (no
         * --listen-address) prevents dnsmasq from responding to dns
         * queries that arrive on some interface other than our bridge
         * interface (in other words, requests originating somewhere
         * other than one of the virtual guests connected directly to
         * this network). This was added in response to CVE 2012-3411.
         */
818
        virBufferAsprintf(&configbuf,
819 820 821
                          "bind-dynamic\n"
                          "interface=%s\n",
                          network->def->bridge);
822
    } else {
823
        virBufferAddLit(&configbuf, "bind-interfaces\n");
824 825 826 827 828 829 830 831
        /*
         * --interface does not actually work with dnsmasq < 2.47,
         * due to DAD for ipv6 addresses on the interface.
         *
         * virCommandAddArgList(cmd, "--interface", network->def->bridge, NULL);
         *
         * So listen on all defined IPv[46] addresses
         */
832 833 834
        for (i = 0;
             (tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
             i++) {
835 836 837 838
            char *ipaddr = virSocketAddrFormat(&tmpipdef->address);

            if (!ipaddr)
                goto cleanup;
839

840
            /* also part of CVE 2012-3411 - if the host's version of
841
             * dnsmasq doesn't have bind-dynamic, only allow listening on
842 843
             * private/local IP addresses (see RFC1918/RFC3484/RFC4193)
             */
844 845
            if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
                !virSocketAddrIsPrivate(&tmpipdef->address)) {
846 847 848 849
                unsigned long version = dnsmasqCapsGetVersion(caps);

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
850
                                 "The version of dnsmasq on this host (%d.%d) "
851 852 853 854
                                 "doesn't support the bind-dynamic option or "
                                 "use SO_BINDTODEVICE on listening sockets, "
                                 "one of which is required for safe operation "
                                 "on a publicly routable subnet "
855 856 857 858 859 860
                                 "(see CVE-2012-3411). You must either "
                                 "upgrade dnsmasq, or use a private/local "
                                 "subnet range for this network "
                                 "(as described in RFC1918/RFC3484/RFC4193)."),
                               ipaddr, (int)version / 1000000,
                               (int)(version % 1000000) / 1000);
861 862
                goto cleanup;
            }
863
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
864 865 866
            VIR_FREE(ipaddr);
        }
    }
867

868 869
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
870
     * guaranteed to not work, and set no-resolv so that no dns
871 872 873
     * requests are forwarded on to the dns server listed in the
     * host's /etc/resolv.conf (since this could be used as a channel
     * to build a connection to the outside).
874
     */
875
    if (network->def->forward.type == VIR_NETWORK_FORWARD_NONE) {
876
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
877
                        "no-resolv\n");
878
    }
879

880
    for (i = 0; i < dns->ntxts; i++) {
881
        virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
882 883
                          dns->txts[i].name,
                          dns->txts[i].value);
884
    }
885

886 887 888 889
    for (i = 0; i < dns->nsrvs; i++) {
        if (dns->srvs[i].service && dns->srvs[i].protocol) {
            if (dns->srvs[i].port &&
                virAsprintf(&recordPort, "%d", dns->srvs[i].port) < 0)
890
                goto cleanup;
891 892
            if (dns->srvs[i].priority &&
                virAsprintf(&recordPriority, "%d", dns->srvs[i].priority) < 0)
893
                goto cleanup;
894 895
            if (dns->srvs[i].weight &&
                virAsprintf(&recordWeight, "%d", dns->srvs[i].weight) < 0)
896
                goto cleanup;
897

898
            if (virAsprintf(&record, "%s.%s.%s,%s,%s,%s,%s",
899 900 901 902
                            dns->srvs[i].service,
                            dns->srvs[i].protocol,
                            dns->srvs[i].domain ? dns->srvs[i].domain : "",
                            dns->srvs[i].target ? dns->srvs[i].target : "",
903 904
                            recordPort           ? recordPort           : "",
                            recordPriority       ? recordPriority       : "",
905
                            recordWeight         ? recordWeight         : "") < 0)
906 907
                goto cleanup;

908
            virBufferAsprintf(&configbuf, "srv-host=%s\n", record);
909 910 911 912
            VIR_FREE(record);
            VIR_FREE(recordPort);
            VIR_FREE(recordWeight);
            VIR_FREE(recordPriority);
913
        }
914 915
    }

G
Gene Czarcinski 已提交
916
    /* Find the first dhcp for both IPv4 and IPv6 */
917 918 919
    for (i = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
         i++) {
G
Gene Czarcinski 已提交
920 921 922 923
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
924 925
                                   _("For IPv4, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
926 927 928 929 930 931 932 933 934 935 936
                    goto cleanup;
                } else {
                    ipv4def = ipdef;
                }
            }
        }
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (!DNSMASQ_DHCPv6_SUPPORT(caps)) {
                    unsigned long version = dnsmasqCapsGetVersion(caps);
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
937 938 939 940 941 942 943 944 945
                                   _("The version of dnsmasq on this host "
                                     "(%d.%d) doesn't adequately support "
                                     "IPv6 dhcp range or dhcp host "
                                     "specification. Version %d.%d or later "
                                     "is required."),
                                   (int)version / 1000000,
                                   (int)(version % 1000000) / 1000,
                                   DNSMASQ_DHCPv6_MAJOR_REQD,
                                   DNSMASQ_DHCPv6_MINOR_REQD);
G
Gene Czarcinski 已提交
946 947 948 949
                    goto cleanup;
                }
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
950 951
                                   _("For IPv6, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
952 953 954 955 956 957 958 959 960 961 962 963 964
                    goto cleanup;
                } else {
                    ipv6def = ipdef;
                }
            } else {
                ipv6SLAAC = true;
            }
        }
    }

    if (ipv6def && ipv6SLAAC) {
        VIR_WARN("For IPv6, when DHCP is specified for one address, then "
                 "state-full Router Advertising will occur.  The additional "
965 966 967 968
                 "IPv6 addresses specified require manually configured guest "
                 "network to work properly since both state-full (DHCP) "
                 "and state-less (SLAAC) addressing are not supported "
                 "on the same network interface.");
G
Gene Czarcinski 已提交
969 970 971 972 973
    }

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
974
        for (r = 0; r < ipdef->nranges; r++) {
975
            char *saddr = virSocketAddrFormat(&ipdef->ranges[r].start);
976 977
            if (!saddr)
                goto cleanup;
978
            char *eaddr = virSocketAddrFormat(&ipdef->ranges[r].end);
979 980 981 982
            if (!eaddr) {
                VIR_FREE(saddr);
                goto cleanup;
            }
983
            virBufferAsprintf(&configbuf, "dhcp-range=%s,%s\n",
984
                              saddr, eaddr);
985
            VIR_FREE(saddr);
986
            VIR_FREE(eaddr);
987 988
            nbleases += virSocketAddrGetRange(&ipdef->ranges[r].start,
                                              &ipdef->ranges[r].end);
989
        }
990

991
        /*
992 993 994 995
         * 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. (this is for dhcp-hosts=
         * support)
996 997
         */
        if (!ipdef->nranges && ipdef->nhosts) {
998
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
999 1000
            if (!bridgeaddr)
                goto cleanup;
1001
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static\n", bridgeaddr);
1002 1003
            VIR_FREE(bridgeaddr);
        }
1004

G
Gene Czarcinski 已提交
1005 1006
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1007

G
Gene Czarcinski 已提交
1008 1009 1010
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts)
1011
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1012

G
Gene Czarcinski 已提交
1013
            if (ipdef->tftproot) {
1014 1015
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1016
            }
1017

G
Gene Czarcinski 已提交
1018 1019 1020
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1021

1022
                    if (!bootserver)
G
Gene Czarcinski 已提交
1023
                        goto cleanup;
1024
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1025
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1026 1027
                    VIR_FREE(bootserver);
                } else {
1028
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1029 1030 1031 1032 1033
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1034

G
Gene Czarcinski 已提交
1035 1036
    if (nbleases > 0) {
        char *leasefile = networkDnsmasqLeaseFileName(network->def->name);
1037
        if (!leasefile)
G
Gene Czarcinski 已提交
1038
            goto cleanup;
1039
        virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n", leasefile);
G
Gene Czarcinski 已提交
1040
        VIR_FREE(leasefile);
1041
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
G
Gene Czarcinski 已提交
1042
    }
1043

G
Gene Czarcinski 已提交
1044 1045
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1046
        goto cleanup;
G
Gene Czarcinski 已提交
1047 1048 1049 1050 1051 1052

    /* Even if there are currently no static hosts, if we're
     * listening for DHCP, we should write a 0-length hosts
     * file to allow for runtime additions.
     */
    if (ipv4def || ipv6def)
1053 1054
        virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n",
                          dctx->hostsfile->path);
G
Gene Czarcinski 已提交
1055

1056 1057
    /* Likewise, always create this file and put it on the
     * commandline, to allow for runtime additions.
G
Gene Czarcinski 已提交
1058
     */
1059
    virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
1060
                      dctx->addnhostsfile->path);
G
Gene Czarcinski 已提交
1061 1062 1063 1064

    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
        if (ipv6def)
1065
            virBufferAddLit(&configbuf, "enable-ra\n");
G
Gene Czarcinski 已提交
1066
        else {
1067 1068 1069
            for (i = 0;
                 (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
                 i++) {
G
Gene Czarcinski 已提交
1070 1071 1072 1073
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1074 1075
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1076 1077
                    VIR_FREE(bridgeaddr);
                }
1078
            }
1079
        }
1080 1081
    }

1082 1083 1084
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1085
    ret = 0;
G
Gene Czarcinski 已提交
1086

1087
 cleanup:
1088
    virBufferFreeAndReset(&configbuf);
1089 1090 1091 1092
    VIR_FREE(record);
    VIR_FREE(recordPort);
    VIR_FREE(recordWeight);
    VIR_FREE(recordPriority);
1093
    return ret;
1094 1095
}

1096
/* build the dnsmasq command line */
1097 1098 1099
static int ATTRIBUTE_NONNULL(2)
networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
                                  virCommandPtr *cmdout,
1100 1101
                                  char *pidfile, dnsmasqContext *dctx,
                                  dnsmasqCapsPtr caps)
1102
{
1103
    virCommandPtr cmd = NULL;
G
Gene Czarcinski 已提交
1104
    int ret = -1;
1105 1106
    char *configfile = NULL;
    char *configstr = NULL;
1107 1108

    network->dnsmasqPid = -1;
1109

1110 1111 1112 1113 1114 1115
    if (networkDnsmasqConfContents(network, pidfile, &configstr, dctx, caps) < 0)
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1116
    if (!(configfile = networkDnsmasqConfigFileName(network->def->name)))
1117 1118 1119 1120 1121 1122 1123
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
                         _("couldn't write dnsmasq config file '%s'"),
                         configfile);
1124 1125 1126
        goto cleanup;
    }

1127 1128
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(caps));
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1129
    *cmdout = cmd;
1130
    ret = 0;
1131
 cleanup:
1132 1133
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1134 1135 1136 1137
    return ret;
}

static int
1138
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1139
                       virNetworkObjPtr network)
1140 1141 1142 1143
{
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
    int ret = -1;
1144
    dnsmasqContext *dctx = NULL;
1145

1146
    if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) {
G
Gene Czarcinski 已提交
1147
        /* no IP addresses, so we don't need to run */
1148 1149 1150 1151
        ret = 0;
        goto cleanup;
    }

1152
    if (virFileMakePath(driverState->pidDir) < 0) {
1153
        virReportSystemError(errno,
1154
                             _("cannot create directory %s"),
1155
                             driverState->pidDir);
1156
        goto cleanup;
1157
    }
1158
    if (virFileMakePath(driverState->stateDir) < 0) {
1159
        virReportSystemError(errno,
1160
                             _("cannot create directory %s"),
1161
                             driverState->stateDir);
1162
        goto cleanup;
1163 1164
    }

1165
    if (!(pidfile = virPidFileBuildPath(driverState->pidDir,
1166
                                        network->def->name)))
1167
        goto cleanup;
1168

1169
    if (virFileMakePath(driverState->dnsmasqStateDir) < 0) {
1170
        virReportSystemError(errno,
1171
                             _("cannot create directory %s"),
1172
                             driverState->dnsmasqStateDir);
1173 1174 1175
        goto cleanup;
    }

1176
    dctx = dnsmasqContextNew(network->def->name, driverState->dnsmasqStateDir);
1177 1178 1179
    if (dctx == NULL)
        goto cleanup;

1180 1181
    if (dnsmasqCapsRefresh(&driver->dnsmasqCaps, NULL) < 0)
        goto cleanup;
1182 1183 1184

    ret = networkBuildDhcpDaemonCommandLine(network, &cmd, pidfile,
                                            dctx, driver->dnsmasqCaps);
1185 1186 1187 1188 1189
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1190
        goto cleanup;
1191

G
Guido Günther 已提交
1192 1193
    ret = virCommandRun(cmd, NULL);
    if (ret < 0) {
1194
        goto cleanup;
G
Guido Günther 已提交
1195
    }
1196 1197

    /*
1198 1199 1200 1201 1202
     * 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
1203 1204
     */

1205
    ret = virPidFileRead(driverState->pidDir, network->def->name,
1206 1207
                         &network->dnsmasqPid);
    if (ret < 0)
1208
        goto cleanup;
1209

1210
    ret = 0;
1211
 cleanup:
1212
    VIR_FREE(pidfile);
1213
    virCommandFree(cmd);
1214
    dnsmasqContextFree(dctx);
1215 1216 1217
    return ret;
}

1218 1219
/* networkRefreshDhcpDaemon:
 *  Update dnsmasq config files, then send a SIGHUP so that it rereads
G
Gene Czarcinski 已提交
1220 1221
 *  them.   This only works for the dhcp-hostsfile and the
 *  addn-hosts file.
1222 1223 1224
 *
 *  Returns 0 on success, -1 on failure.
 */
1225
static int
1226
networkRefreshDhcpDaemon(virNetworkDriverStatePtr driver,
1227
                         virNetworkObjPtr network)
1228
{
1229 1230
    int ret = -1;
    size_t i;
G
Gene Czarcinski 已提交
1231
    virNetworkIpDefPtr ipdef, ipv4def, ipv6def;
1232
    dnsmasqContext *dctx = NULL;
1233

G
Gene Czarcinski 已提交
1234
    /* if no IP addresses specified, nothing to do */
1235
    if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1236 1237
        return 0;

1238 1239
    /* if there's no running dnsmasq, just start it */
    if (network->dnsmasqPid <= 0 || (kill(network->dnsmasqPid, 0) < 0))
1240
        return networkStartDhcpDaemon(driver, network);
1241

G
Gene Czarcinski 已提交
1242
    VIR_INFO("Refreshing dnsmasq for network %s", network->def->bridge);
1243 1244
    if (!(dctx = dnsmasqContextNew(network->def->name,
                                   driverState->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1245
        goto cleanup;
1246
    }
G
Gene Czarcinski 已提交
1247 1248 1249 1250 1251 1252

    /* Look for first IPv4 address that has dhcp defined.
     * We only support dhcp-host config on one IPv4 subnetwork
     * and on one IPv6 subnetwork.
     */
    ipv4def = NULL;
1253 1254 1255
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
         i++) {
G
Gene Czarcinski 已提交
1256 1257
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1258 1259
    }

G
Gene Czarcinski 已提交
1260
    ipv6def = NULL;
1261 1262 1263
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
G
Gene Czarcinski 已提交
1264 1265
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1266 1267
    }

G
Gene Czarcinski 已提交
1268 1269 1270 1271 1272
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
           goto cleanup;

    if (ipv6def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv6def) < 0))
           goto cleanup;
1273

G
Gene Czarcinski 已提交
1274
    if (networkBuildDnsmasqHostsList(dctx, &network->def->dns) < 0)
1275 1276 1277
       goto cleanup;

    if ((ret = dnsmasqSave(dctx)) < 0)
1278
        goto cleanup;
1279 1280

    ret = kill(network->dnsmasqPid, SIGHUP);
1281
 cleanup:
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
    dnsmasqContextFree(dctx);
    return ret;
}

/* networkRestartDhcpDaemon:
 *
 * kill and restart dnsmasq, in order to update any config that is on
 * the dnsmasq commandline (and any placed in separate config files).
 *
 *  Returns 0 on success, -1 on failure.
 */
static int
1294
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1295
                         virNetworkObjPtr network)
1296 1297 1298 1299 1300 1301
{
    /* if there is a running dnsmasq, kill it */
    if (network->dnsmasqPid > 0) {
        networkKillDaemon(network->dnsmasqPid, "dnsmasq",
                          network->def->name);
        network->dnsmasqPid = -1;
1302
    }
1303
    /* now start dnsmasq if it should be started */
1304
    return networkStartDhcpDaemon(driver, network);
1305 1306
}

G
Gene Czarcinski 已提交
1307 1308 1309 1310 1311 1312
static char radvd1[] = "  AdvOtherConfigFlag off;\n\n";
static char radvd2[] = "    AdvAutonomous off;\n";
static char radvd3[] = "    AdvOnLink on;\n"
                       "    AdvAutonomous on;\n"
                       "    AdvRouterAddr off;\n";

1313 1314 1315
static int
networkRadvdConfContents(virNetworkObjPtr network, char **configstr)
{
E
Eric Blake 已提交
1316
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1317 1318
    int ret = -1;
    size_t i;
1319
    virNetworkIpDefPtr ipdef;
G
Gene Czarcinski 已提交
1320
    bool v6present = false, dhcp6 = false;
1321 1322

    *configstr = NULL;
1323

G
Gene Czarcinski 已提交
1324
    /* Check if DHCPv6 is needed */
1325 1326 1327
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
G
Gene Czarcinski 已提交
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
        v6present = true;
        if (ipdef->nranges || ipdef->nhosts) {
            dhcp6 = true;
            break;
        }
    }

    /* If there are no IPv6 addresses, then we are done */
    if (!v6present) {
        ret = 0;
        goto cleanup;
    }

1341 1342 1343
    /* create radvd config file appropriate for this network;
     * IgnoreIfMissing allows radvd to start even when the bridge is down
     */
1344
    virBufferAsprintf(&configbuf, "interface %s\n"
1345 1346
                      "{\n"
                      "  AdvSendAdvert on;\n"
1347
                      "  IgnoreIfMissing on;\n"
G
Gene Czarcinski 已提交
1348 1349 1350 1351 1352
                      "  AdvManagedFlag %s;\n"
                      "%s",
                      network->def->bridge,
                      dhcp6 ? "on" : "off",
                      dhcp6 ? "\n" : radvd1);
1353 1354

    /* add a section for each IPv6 address in the config */
1355 1356 1357
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
1358 1359 1360 1361 1362
        int prefix;
        char *netaddr;

        prefix = virNetworkIpDefPrefix(ipdef);
        if (prefix < 0) {
1363 1364 1365
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
                           network->def->bridge);
1366 1367
            goto cleanup;
        }
1368
        if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
1369
            goto cleanup;
1370
        virBufferAsprintf(&configbuf,
1371
                          "  prefix %s/%d\n"
G
Gene Czarcinski 已提交
1372 1373 1374
                          "  {\n%s  };\n",
                          netaddr, prefix,
                          dhcp6 ? radvd2 : radvd3);
1375 1376 1377
        VIR_FREE(netaddr);
    }

1378 1379 1380
    /* only create the string if we found at least one IPv6 address */
    if (v6present) {
        virBufferAddLit(&configbuf, "};\n");
1381

1382 1383 1384 1385 1386 1387 1388 1389
        if (virBufferError(&configbuf)) {
            virReportOOMError();
            goto cleanup;
        }
        if (!(*configstr = virBufferContentAndReset(&configbuf))) {
            virReportOOMError();
            goto cleanup;
        }
1390
    }
1391 1392

    ret = 0;
1393
 cleanup:
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415
    virBufferFreeAndReset(&configbuf);
    return ret;
}

/* write file and return it's name (which must be freed by caller) */
static int
networkRadvdConfWrite(virNetworkObjPtr network, char **configFile)
{
    int ret = -1;
    char *configStr = NULL;
    char *myConfigFile = NULL;

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

    if (networkRadvdConfContents(network, &configStr) < 0)
        goto cleanup;

    if (!configStr) {
        ret = 0;
1416 1417 1418 1419
        goto cleanup;
    }

    /* construct the filename */
1420
    if (!(*configFile = networkRadvdConfigFileName(network->def->name)))
1421 1422
        goto cleanup;
    /* write the file */
1423
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1424 1425
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1426 1427 1428 1429 1430
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1431
 cleanup:
1432 1433 1434 1435 1436 1437
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

static int
1438
networkStartRadvd(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
G
Gene Czarcinski 已提交
1439
                        virNetworkObjPtr network)
1440 1441 1442 1443 1444 1445 1446 1447 1448
{
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

    network->radvdPid = -1;

G
Gene Czarcinski 已提交
1449
    /* Is dnsmasq handling RA? */
1450
   if (DNSMASQ_RA_SUPPORT(driver->dnsmasqCaps)) {
G
Gene Czarcinski 已提交
1451 1452 1453 1454
        ret = 0;
        goto cleanup;
    }

1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465
    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
        /* no IPv6 addresses, so we don't need to run radvd */
        ret = 0;
        goto cleanup;
    }

    if (!virFileIsExecutable(RADVD)) {
        virReportSystemError(errno,
                             _("Cannot find %s - "
                               "Possibly the package isn't installed"),
                             RADVD);
1466 1467 1468
        goto cleanup;
    }

1469
    if (virFileMakePath(driverState->pidDir) < 0) {
1470 1471
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1472
                             driverState->pidDir);
1473 1474
        goto cleanup;
    }
1475
    if (virFileMakePath(driverState->radvdStateDir) < 0) {
1476 1477
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1478
                             driverState->radvdStateDir);
1479 1480 1481 1482
        goto cleanup;
    }

    /* construct pidfile name */
1483
    if (!(radvdpidbase = networkRadvdPidfileBasename(network->def->name)))
1484
        goto cleanup;
1485
    if (!(pidfile = virPidFileBuildPath(driverState->pidDir, radvdpidbase)))
1486 1487 1488 1489 1490
        goto cleanup;

    if (networkRadvdConfWrite(network, &configfile) < 0)
        goto cleanup;

1491 1492 1493 1494
    /* prevent radvd from daemonizing itself with "--debug 1", and use
     * a dummy pidfile name - virCommand will create the pidfile we
     * want to use (this is necessary because radvd's internal
     * daemonization and pidfile creation causes a race, and the
1495
     * virPidFileRead() below will fail if we use them).
1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510
     * Unfortunately, it isn't possible to tell radvd to not create
     * its own pidfile, so we just let it do so, with a slightly
     * different name. Unused, but harmless.
     */
    cmd = virCommandNewArgList(RADVD, "--debug", "1",
                               "--config", configfile,
                               "--pidfile", NULL);
    virCommandAddArgFormat(cmd, "%s-bin", pidfile);

    virCommandSetPidFile(cmd, pidfile);
    virCommandDaemonize(cmd);

    if (virCommandRun(cmd, NULL) < 0)
        goto cleanup;

1511
    if (virPidFileRead(driverState->pidDir, radvdpidbase, &network->radvdPid) < 0)
1512 1513 1514
        goto cleanup;

    ret = 0;
1515
 cleanup:
1516 1517 1518 1519 1520 1521 1522
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

1523
static int
1524
networkRefreshRadvd(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
1525
                    virNetworkObjPtr network)
1526
{
G
Gene Czarcinski 已提交
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537
    char *radvdpidbase;

    /* Is dnsmasq handling RA? */
    if (DNSMASQ_RA_SUPPORT(driver->dnsmasqCaps)) {
        if (network->radvdPid <= 0)
            return 0;
        /* radvd should not be running but in case it is */
        if ((networkKillDaemon(network->radvdPid, "radvd",
                               network->def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
             != NULL)) {
1538
            virPidFileDelete(driverState->pidDir, radvdpidbase);
G
Gene Czarcinski 已提交
1539 1540 1541 1542 1543 1544
            VIR_FREE(radvdpidbase);
        }
        network->radvdPid = -1;
        return 0;
    }

1545 1546
    /* if there's no running radvd, just start it */
    if (network->radvdPid <= 0 || (kill(network->radvdPid, 0) < 0))
G
Gene Czarcinski 已提交
1547
        return networkStartRadvd(driver, network);
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559

    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

    if (networkRadvdConfWrite(network, NULL) < 0)
        return -1;

    return kill(network->radvdPid, SIGHUP);
}

1560 1561
#if 0
/* currently unused, so it causes a build error unless we #if it out */
1562
static int
1563
networkRestartRadvd(virNetworkDriverStatePtr driver,
1564
                    virNetworkObjPtr network)
1565 1566 1567 1568 1569 1570 1571 1572 1573
{
    char *radvdpidbase;

    /* if there is a running radvd, kill it */
    if (network->radvdPid > 0) {
        /* essentially ignore errors from the following two functions,
         * since there's really no better recovery to be done than to
         * just push ahead (and that may be exactly what's needed).
         */
G
Gene Czarcinski 已提交
1574
        if ((networkKillDaemon(network->radvdPid, "radvd",
1575 1576 1577
                               network->def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
             != NULL)) {
1578
            virPidFileDelete(driverState->pidDir, radvdpidbase);
1579 1580 1581 1582 1583 1584 1585 1586 1587
            VIR_FREE(radvdpidbase);
        }
        network->radvdPid = -1;
    }
    /* now start radvd if it should be started */
    return networkStartRadvd(network);
}
#endif /* #if 0 */

1588 1589 1590 1591
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
1592
networkRefreshDaemons(virNetworkDriverStatePtr driver)
1593
{
1594
    size_t i;
1595 1596 1597

    VIR_INFO("Refreshing network daemons");

1598
    for (i = 0; i < driver->networks.count; i++) {
1599 1600 1601 1602
        virNetworkObjPtr network = driver->networks.objs[i];

        virNetworkObjLock(network);
        if (virNetworkObjIsActive(network) &&
1603 1604 1605
            ((network->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
             (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
             (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
1606 1607 1608 1609 1610 1611
            /* Only the three L3 network types that are configured by
             * libvirt will have a dnsmasq or radvd daemon associated
             * with them.  Here we send a SIGHUP to an existing
             * dnsmasq and/or radvd, or restart them if they've
             * disappeared.
             */
1612 1613
            networkRefreshDhcpDaemon(driver, network);
            networkRefreshRadvd(driver, network);
1614 1615 1616 1617 1618
        }
        virNetworkObjUnlock(network);
    }
}

1619
static void
1620
networkReloadFirewallRules(virNetworkDriverStatePtr driver)
1621
{
1622
    size_t i;
1623

1624
    VIR_INFO("Reloading iptables rules");
1625

1626
    for (i = 0; i < driver->networks.count; i++) {
1627 1628 1629 1630
        virNetworkObjPtr network = driver->networks.objs[i];

        virNetworkObjLock(network);
        if (virNetworkObjIsActive(network) &&
1631 1632 1633
            ((network->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
             (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
             (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
1634 1635 1636
            /* Only the three L3 network types that are configured by libvirt
             * need to have iptables rules reloaded.
             */
1637 1638
            networkRemoveFirewallRules(network);
            if (networkAddFirewallRules(network) < 0) {
1639 1640
                /* failed to add but already logged */
            }
1641
        }
1642
        virNetworkObjUnlock(network);
1643 1644 1645
    }
}

1646
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
1647
static int
1648
networkEnableIpForwarding(bool enableIPv4, bool enableIPv6)
1649
{
1650
    int ret = 0;
1651 1652 1653 1654 1655 1656 1657 1658 1659
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
                            &enabled, sizeof(enabled));
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
                            &enabled, sizeof(enabled));
#else
1660 1661 1662 1663
    if (enableIPv4)
        ret = virFileWriteStr("/proc/sys/net/ipv4/ip_forward", "1\n", 0);
    if (enableIPv6 && ret == 0)
        ret = virFileWriteStr("/proc/sys/net/ipv6/conf/all/forwarding", "1\n", 0);
1664
#endif
1665
    return ret;
1666 1667
}

1668 1669
#define SYSCTL_PATH "/proc/sys"

1670 1671
static int
networkSetIPv6Sysctls(virNetworkObjPtr network)
1672 1673 1674 1675
{
    char *field = NULL;
    int ret = -1;

1676 1677 1678 1679 1680
    if (!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0)) {
        /* Only set disable_ipv6 if there are no ipv6 addresses defined for
         * the network.
         */
        if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/disable_ipv6",
1681
                        network->def->bridge) < 0)
1682
            goto cleanup;
1683

1684 1685 1686 1687 1688 1689
        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;
        }
1690

1691 1692 1693 1694 1695 1696 1697
        if (virFileWriteStr(field, "1", 0) < 0) {
            virReportSystemError(errno,
                                 _("cannot write to %s to disable IPv6 on bridge %s"),
                                 field, network->def->bridge);
            goto cleanup;
        }
        VIR_FREE(field);
1698 1699
    }

1700 1701 1702 1703 1704 1705 1706 1707
    /* The rest of the ipv6 sysctl tunables should always be set,
     * whether or not we're using ipv6 on this bridge.
     */

    /* Prevent guests from hijacking the host network by sending out
     * their own router advertisements.
     */
    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/accept_ra",
1708
                    network->def->bridge) < 0)
1709 1710
        goto cleanup;

1711
    if (virFileWriteStr(field, "0", 0) < 0) {
1712
        virReportSystemError(errno,
1713 1714 1715 1716 1717
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

1718 1719 1720 1721
    /* All interfaces used as a gateway (which is what this is, by
     * definition), must always have autoconf=0.
     */
    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/autoconf",
1722
                    network->def->bridge) < 0)
1723 1724
        goto cleanup;

1725
    if (virFileWriteStr(field, "0", 0) < 0) {
1726
        virReportSystemError(errno,
1727
                             _("cannot disable %s"), field);
1728 1729 1730 1731
        goto cleanup;
    }

    ret = 0;
1732
 cleanup:
1733 1734 1735 1736
    VIR_FREE(field);
    return ret;
}

1737
/* add an IP address to a bridge */
1738
static int
D
Daniel P. Berrange 已提交
1739
networkAddAddrToBridge(virNetworkObjPtr network,
1740
                       virNetworkIpDefPtr ipdef)
1741
{
1742 1743 1744
    int prefix = virNetworkIpDefPrefix(ipdef);

    if (prefix < 0) {
1745 1746 1747
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
                       network->def->bridge);
1748 1749 1750
        return -1;
    }

1751 1752
    if (virNetDevSetIPv4Address(network->def->bridge,
                                &ipdef->address, prefix) < 0)
1753 1754 1755 1756 1757
        return -1;

    return 0;
}

1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770
/* add an IP (static) route to a bridge */
static int
networkAddRouteToBridge(virNetworkObjPtr network,
                        virNetworkRouteDefPtr routedef)
{
    int prefix = 0;
    unsigned int metric;
    virSocketAddrPtr addr = &routedef->address;
    virSocketAddrPtr mask = &routedef->netmask;
    virSocketAddr zero;

    /* this creates an all-0 address of the appropriate family */
    ignore_value(virSocketAddrParse(&zero,
1771
                                    (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806
                                     ? "0.0.0.0" : "::"),
                                    VIR_SOCKET_ADDR_FAMILY(addr)));

    if (virSocketAddrEqual(addr, &zero)) {
        if (routedef->has_prefix && routedef->prefix == 0)
            prefix = 0;
        else if ((VIR_SOCKET_ADDR_IS_FAMILY(mask, AF_INET) &&
                virSocketAddrEqual(mask, &zero)))
            prefix = 0;
        else
            prefix = virSocketAddrGetIpPrefix(addr, mask, routedef->prefix);
    } else {
        prefix = virSocketAddrGetIpPrefix(addr, mask, routedef->prefix);
    }

    if (prefix < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' has an invalid netmask "
                         "or IP address in route definition"),
                       network->def->name);
        return -1;
    }

    if (routedef->has_metric && routedef->metric > 0)
        metric = routedef->metric;
    else
        metric = 1;

    if (virNetDevAddRoute(network->def->bridge, &routedef->address,
                          prefix, &routedef->gateway, metric) < 0) {
        return -1;
    }
    return 0;
}

1807
static int
1808
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
1809 1810
                          virNetworkObjPtr network)
{
1811
    size_t i;
1812
    bool v4present = false, v6present = false;
1813 1814
    virErrorPtr save_err = NULL;
    virNetworkIpDefPtr ipdef;
1815
    virNetworkRouteDefPtr routedef;
1816
    char *macTapIfName = NULL;
1817
    int tapfd = -1;
1818

1819 1820
    /* Check to see if any network IP collides with an existing route */
    if (networkCheckRouteCollision(network) < 0)
1821 1822
        return -1;

1823
    /* Create and configure the bridge device */
1824
    if (virNetDevBridgeCreate(network->def->bridge) < 0)
1825 1826
        return -1;

1827 1828 1829 1830 1831 1832 1833 1834
    if (network->def->mac_specified) {
        /* To set a mac for the bridge, we need to define a dummy tap
         * device, set its mac, then attach it to the bridge. As long
         * as its mac address is lower than any other interface that
         * gets attached, the bridge will always maintain this mac
         * address.
         */
        macTapIfName = networkBridgeDummyNicName(network->def->bridge);
1835
        if (!macTapIfName)
1836
            goto err0;
1837
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
1838
        if (virNetDevTapCreateInBridgePort(network->def->bridge,
1839
                                           &macTapIfName, &network->def->mac,
1840
                                           NULL, &tapfd, 1, NULL, NULL,
1841 1842 1843
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
1844 1845 1846 1847 1848
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

1849
    /* Set bridge options */
1850 1851 1852 1853

    /* delay is configured in seconds, but virNetDevBridgeSetSTPDelay
     * expects milliseconds
     */
1854
    if (virNetDevBridgeSetSTPDelay(network->def->bridge,
1855
                                   network->def->delay * 1000) < 0)
1856
        goto err1;
1857

1858
    if (virNetDevBridgeSetSTP(network->def->bridge,
1859
                              network->def->stp ? true : false) < 0)
1860
        goto err1;
1861

1862 1863 1864 1865
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
    if (networkSetIPv6Sysctls(network) < 0)
1866
        goto err1;
1867

1868
    /* Add "once per network" rules */
1869
    if (networkAddFirewallRules(network) < 0)
1870 1871
        goto err1;

1872 1873 1874
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
         i++) {
1875
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
1876
            v4present = true;
1877
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1878
            v6present = true;
1879

1880
        /* Add the IP address/netmask to the bridge */
D
Daniel P. Berrange 已提交
1881
        if (networkAddAddrToBridge(network, ipdef) < 0) {
1882
            goto err2;
1883
        }
1884 1885
    }

1886
    /* Bring up the bridge interface */
1887
    if (virNetDevSetOnline(network->def->bridge, 1) < 0)
1888
        goto err2;
1889

1890 1891
    for (i = 0; i < network->def->nroutes; i++) {
        routedef = &network->def->routes[i];
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
        if (VIR_SOCKET_ADDR_VALID(&routedef->gateway)) {
            if (networkAddRouteToBridge(network, routedef) < 0) {
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

1903 1904
    /* If forward.type != NONE, turn on global IP forwarding */
    if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE &&
1905
        networkEnableIpForwarding(v4present, v6present) < 0) {
1906
        virReportSystemError(errno, "%s",
1907
                             _("failed to enable IP forwarding"));
1908
        goto err3;
1909 1910
    }

1911

1912
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
1913 1914
    if ((v4present || v6present) &&
        networkStartDhcpDaemon(driver, network) < 0)
1915
        goto err3;
1916

1917
    /* start radvd if there are any ipv6 addresses */
G
Gene Czarcinski 已提交
1918
    if (v6present && networkStartRadvd(driver, network) < 0)
1919 1920
        goto err4;

1921 1922 1923 1924 1925 1926 1927 1928 1929
    /* DAD has happened (dnsmasq waits for it), dnsmasq is now bound to the
     * bridge's IPv6 address, so we can now set the dummy tun down.
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
            goto err4;
        VIR_FORCE_CLOSE(tapfd);
    }

1930 1931
    if (virNetDevBandwidthSet(network->def->bridge,
                              network->def->bandwidth, true) < 0) {
1932 1933 1934
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot set bandwidth limits on %s"),
                       network->def->bridge);
1935 1936 1937
        goto err5;
    }

1938
    VIR_FREE(macTapIfName);
1939 1940 1941

    return 0;

1942
 err5:
1943
    virNetDevBandwidthClear(network->def->bridge);
1944

1945 1946 1947 1948
 err4:
    if (!save_err)
        save_err = virSaveLastError();

1949 1950 1951 1952 1953
    if (network->dnsmasqPid > 0) {
        kill(network->dnsmasqPid, SIGTERM);
        network->dnsmasqPid = -1;
    }

1954 1955 1956
 err3:
    if (!save_err)
        save_err = virSaveLastError();
1957
    ignore_value(virNetDevSetOnline(network->def->bridge, 0));
1958

1959 1960 1961
 err2:
    if (!save_err)
        save_err = virSaveLastError();
1962
    networkRemoveFirewallRules(network);
1963 1964

 err1:
1965 1966 1967
    if (!save_err)
        save_err = virSaveLastError();

H
Hu Tao 已提交
1968
    if (macTapIfName) {
1969
        VIR_FORCE_CLOSE(tapfd);
H
Hu Tao 已提交
1970 1971 1972
        ignore_value(virNetDevTapDelete(macTapIfName));
        VIR_FREE(macTapIfName);
    }
1973 1974

 err0:
1975 1976
    if (!save_err)
        save_err = virSaveLastError();
1977
    ignore_value(virNetDevBridgeDelete(network->def->bridge));
1978

1979 1980 1981 1982
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
1983
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
1984 1985 1986
    return -1;
}

1987
static int networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
R
Roman Bogorodskiy 已提交
1988
                                         virNetworkObjPtr network)
1989
{
1990
    virNetDevBandwidthClear(network->def->bridge);
1991

1992 1993 1994 1995 1996
    if (network->radvdPid > 0) {
        char *radvdpidbase;

        kill(network->radvdPid, SIGTERM);
        /* attempt to delete the pidfile we created */
1997
        if ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))) {
1998
            virPidFileDelete(driverState->pidDir, radvdpidbase);
1999 2000 2001 2002
            VIR_FREE(radvdpidbase);
        }
    }

2003 2004 2005
    if (network->dnsmasqPid > 0)
        kill(network->dnsmasqPid, SIGTERM);

2006
    if (network->def->mac_specified) {
2007
        char *macTapIfName = networkBridgeDummyNicName(network->def->bridge);
2008
        if (macTapIfName) {
2009
            ignore_value(virNetDevTapDelete(macTapIfName));
2010 2011 2012 2013
            VIR_FREE(macTapIfName);
        }
    }

2014
    ignore_value(virNetDevSetOnline(network->def->bridge, 0));
2015

2016
    networkRemoveFirewallRules(network);
2017

2018
    ignore_value(virNetDevBridgeDelete(network->def->bridge));
2019

2020
    /* See if its still alive and really really kill it */
2021
    if (network->dnsmasqPid > 0 &&
2022
        (kill(network->dnsmasqPid, 0) == 0))
2023 2024
        kill(network->dnsmasqPid, SIGKILL);
    network->dnsmasqPid = -1;
2025 2026 2027 2028 2029 2030

    if (network->radvdPid > 0 &&
        (kill(network->radvdPid, 0) == 0))
        kill(network->radvdPid, SIGKILL);
    network->radvdPid = -1;

2031 2032 2033 2034
    return 0;
}

static int
2035
networkStartNetworkExternal(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
2036 2037 2038
                            virNetworkObjPtr network ATTRIBUTE_UNUSED)
{
    /* put anything here that needs to be done each time a network of
2039
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2040 2041 2042 2043 2044 2045
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2046
static int networkShutdownNetworkExternal(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
2047 2048 2049
                                        virNetworkObjPtr network ATTRIBUTE_UNUSED)
{
    /* put anything here that needs to be done each time a network of
2050
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2051 2052 2053 2054 2055 2056 2057
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

static int
2058
networkStartNetwork(virNetworkDriverStatePtr driver,
2059 2060
                    virNetworkObjPtr network)
{
2061 2062 2063
    int ret = -1;

    VIR_DEBUG("driver=%p, network=%p", driver, network);
2064 2065

    if (virNetworkObjIsActive(network)) {
2066 2067
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2068
        return ret;
2069 2070
    }

2071 2072 2073
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2074
    if (virNetworkObjSetDefTransient(network, true) < 0)
2075
        goto cleanup;
2076

2077 2078
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2079
    if (networkRunHook(network, NULL, NULL,
2080 2081 2082 2083
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2084
    switch (network->def->forward.type) {
2085 2086 2087 2088

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2089 2090
        if (networkStartNetworkVirtual(driver, network) < 0)
            goto cleanup;
2091 2092 2093 2094 2095 2096
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2097
    case VIR_NETWORK_FORWARD_HOSTDEV:
2098 2099
        if (networkStartNetworkExternal(driver, network) < 0)
            goto cleanup;
2100 2101 2102
        break;
    }

2103
    /* finally we can call the 'started' hook script if any */
2104
    if (networkRunHook(network, NULL, NULL,
2105 2106 2107 2108
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2109 2110 2111
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2112 2113 2114
    VIR_DEBUG("Writing network status to disk");
    if (virNetworkSaveStatus(driverState->stateDir, network) < 0)
        goto cleanup;
2115 2116

    network->active = 1;
2117 2118
    VIR_INFO("Network '%s' started up", network->def->name);
    ret = 0;
2119

2120
 cleanup:
2121
    if (ret < 0) {
2122
        virNetworkObjUnsetDefTransient(network);
2123 2124 2125 2126 2127 2128 2129 2130 2131 2132
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
        networkShutdownNetwork(driver, network);
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2133
static int networkShutdownNetwork(virNetworkDriverStatePtr driver,
2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
                                        virNetworkObjPtr network)
{
    int ret = 0;
    char *stateFile;

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

    if (!virNetworkObjIsActive(network))
        return 0;

2144 2145
    stateFile = virNetworkConfigFile(driverState->stateDir,
                                     network->def->name);
2146 2147 2148 2149 2150 2151
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2152
    switch (network->def->forward.type) {
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
        ret = networkShutdownNetworkVirtual(driver, network);
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2164
    case VIR_NETWORK_FORWARD_HOSTDEV:
2165 2166 2167 2168
        ret = networkShutdownNetworkExternal(driver, network);
        break;
    }

2169
    /* now that we know it's stopped call the hook if present */
2170
    networkRunHook(network, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2171 2172
                   VIR_HOOK_SUBOP_END);

2173
    network->active = 0;
2174
    virNetworkObjUnsetDefTransient(network);
2175
    return ret;
2176 2177 2178
}


2179
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
2180 2181
                                         const unsigned char *uuid)
{
2182
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2183 2184
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;
2185

2186
    networkDriverLock(driver);
2187
    network = virNetworkFindByUUID(&driver->networks, uuid);
2188
    networkDriverUnlock(driver);
2189
    if (!network) {
2190 2191
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
2192
        goto cleanup;
2193 2194
    }

2195 2196 2197
    if (virNetworkLookupByUUIDEnsureACL(conn, network->def) < 0)
        goto cleanup;

2198 2199
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2200
 cleanup:
2201 2202
    if (network)
        virNetworkObjUnlock(network);
2203
    return ret;
2204 2205
}

2206
static virNetworkPtr networkLookupByName(virConnectPtr conn,
2207 2208
                                         const char *name)
{
2209
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2210 2211 2212
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;

2213
    networkDriverLock(driver);
2214
    network = virNetworkFindByName(&driver->networks, name);
2215
    networkDriverUnlock(driver);
2216
    if (!network) {
2217 2218
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
2219
        goto cleanup;
2220 2221
    }

2222 2223 2224
    if (virNetworkLookupByNameEnsureACL(conn, network->def) < 0)
        goto cleanup;

2225 2226
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2227
 cleanup:
2228 2229
    if (network)
        virNetworkObjUnlock(network);
2230
    return ret;
2231 2232
}

2233 2234 2235
static virDrvOpenStatus networkOpen(virConnectPtr conn,
                                    virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                    unsigned int flags)
2236 2237 2238
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

2239 2240 2241 2242 2243 2244 2245
    if (!driverState)
        return VIR_DRV_OPEN_DECLINED;

    conn->networkPrivateData = driverState;
    return VIR_DRV_OPEN_SUCCESS;
}

2246 2247
static int networkClose(virConnectPtr conn)
{
2248 2249 2250 2251
    conn->networkPrivateData = NULL;
    return 0;
}

2252 2253
static int networkConnectNumOfNetworks(virConnectPtr conn)
{
2254 2255
    int nactive = 0;
    size_t i;
2256
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2257

2258 2259 2260
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

2261
    networkDriverLock(driver);
2262
    for (i = 0; i < driver->networks.count; i++) {
2263 2264 2265 2266
        virNetworkObjPtr obj = driver->networks.objs[i];
        virNetworkObjLock(obj);
        if (virConnectNumOfNetworksCheckACL(conn, obj->def) &&
            virNetworkObjIsActive(obj))
2267
            nactive++;
2268
        virNetworkObjUnlock(obj);
2269 2270
    }
    networkDriverUnlock(driver);
2271

2272 2273 2274
    return nactive;
}

2275
static int networkConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
2276
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2277 2278
    int got = 0;
    size_t i;
2279

2280 2281 2282
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

2283
    networkDriverLock(driver);
2284
    for (i = 0; i < driver->networks.count && got < nnames; i++) {
2285 2286 2287 2288 2289 2290
        virNetworkObjPtr obj = driver->networks.objs[i];
        virNetworkObjLock(obj);
        if (virConnectListNetworksCheckACL(conn, obj->def) &&
            virNetworkObjIsActive(obj)) {
            if (VIR_STRDUP(names[got], obj->def->name) < 0) {
                virNetworkObjUnlock(obj);
2291 2292 2293 2294
                goto cleanup;
            }
            got++;
        }
2295
        virNetworkObjUnlock(obj);
2296
    }
2297 2298
    networkDriverUnlock(driver);

2299 2300 2301
    return got;

 cleanup:
2302
    networkDriverUnlock(driver);
2303
    for (i = 0; i < got; i++)
2304 2305 2306 2307
        VIR_FREE(names[i]);
    return -1;
}

2308 2309
static int networkConnectNumOfDefinedNetworks(virConnectPtr conn)
{
2310 2311
    int ninactive = 0;
    size_t i;
2312
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2313

2314 2315 2316
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2317
    networkDriverLock(driver);
2318
    for (i = 0; i < driver->networks.count; i++) {
2319 2320 2321 2322
        virNetworkObjPtr obj = driver->networks.objs[i];
        virNetworkObjLock(obj);
        if (virConnectNumOfDefinedNetworksCheckACL(conn, obj->def) &&
            !virNetworkObjIsActive(obj))
2323
            ninactive++;
2324
        virNetworkObjUnlock(obj);
2325 2326
    }
    networkDriverUnlock(driver);
2327

2328 2329 2330
    return ninactive;
}

2331
static int networkConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
2332
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2333 2334
    int got = 0;
    size_t i;
2335

2336 2337 2338
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2339
    networkDriverLock(driver);
2340
    for (i = 0; i < driver->networks.count && got < nnames; i++) {
2341 2342 2343 2344 2345 2346
        virNetworkObjPtr obj = driver->networks.objs[i];
        virNetworkObjLock(obj);
        if (virConnectListDefinedNetworksCheckACL(conn, obj->def) &&
            !virNetworkObjIsActive(obj)) {
            if (VIR_STRDUP(names[got], obj->def->name) < 0) {
                virNetworkObjUnlock(obj);
2347 2348 2349 2350
                goto cleanup;
            }
            got++;
        }
2351
        virNetworkObjUnlock(obj);
2352
    }
2353
    networkDriverUnlock(driver);
2354 2355 2356
    return got;

 cleanup:
2357
    networkDriverUnlock(driver);
2358
    for (i = 0; i < got; i++)
2359 2360 2361 2362
        VIR_FREE(names[i]);
    return -1;
}

2363
static int
2364 2365 2366
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
2367
{
2368
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2369 2370 2371 2372
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

2373 2374 2375
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

2376
    networkDriverLock(driver);
2377 2378 2379
    ret = virNetworkObjListExport(conn, driver->networks, nets,
                                  virConnectListAllNetworksCheckACL,
                                  flags);
2380 2381
    networkDriverUnlock(driver);

2382
 cleanup:
2383 2384
    return ret;
}
2385

2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
    int ret = -1;

    if (virConnectNetworkEventRegisterAnyEnsureACL(conn) < 0)
        goto cleanup;

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
2401
                                       net, eventID, callback,
2402 2403 2404
                                       opaque, freecb, &ret) < 0)
        ret = -1;

2405
 cleanup:
2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418
    return ret;
}

static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
    int ret = -1;

    if (virConnectNetworkEventDeregisterAnyEnsureACL(conn) < 0)
        goto cleanup;

2419 2420 2421 2422 2423 2424
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;
2425

2426
 cleanup:
2427 2428 2429
    return ret;
}

2430 2431 2432 2433 2434
static int networkIsActive(virNetworkPtr net)
{
    virNetworkObjPtr obj;
    int ret = -1;

2435 2436
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
2437 2438 2439 2440

    if (virNetworkIsActiveEnsureACL(net->conn, obj->def) < 0)
        goto cleanup;

2441 2442
    ret = virNetworkObjIsActive(obj);

2443
 cleanup:
2444 2445 2446 2447 2448 2449 2450 2451 2452 2453
    if (obj)
        virNetworkObjUnlock(obj);
    return ret;
}

static int networkIsPersistent(virNetworkPtr net)
{
    virNetworkObjPtr obj;
    int ret = -1;

2454 2455
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
2456 2457 2458 2459

    if (virNetworkIsPersistentEnsureACL(net->conn, obj->def) < 0)
        goto cleanup;

2460 2461
    ret = obj->persistent;

2462
 cleanup:
2463 2464 2465 2466 2467 2468
    if (obj)
        virNetworkObjUnlock(obj);
    return ret;
}


2469
static int
2470
networkValidate(virNetworkDriverStatePtr driver,
2471 2472
                virNetworkDefPtr def,
                bool check_active)
2473
{
2474
    size_t i;
2475 2476
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
2477
    virNetworkIpDefPtr ipdef;
G
Gene Czarcinski 已提交
2478
    bool ipv4def = false, ipv6def = false;
2479 2480 2481 2482 2483 2484 2485 2486

    /* check for duplicate networks */
    if (virNetworkObjIsDuplicate(&driver->networks, def, check_active) < 0)
        return -1;

    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
2487 2488 2489
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
        def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
2490 2491 2492 2493 2494

        if (virNetworkSetBridgeName(&driver->networks, def, 1))
            return -1;

        virNetworkSetBridgeMacAddr(def);
2495 2496
    } else {
        /* They are also the only types that currently support setting
2497 2498
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
2499
         */
2500 2501 2502 2503 2504 2505 2506 2507
        if (def->mac_specified) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <mac> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
                           virNetworkForwardTypeToString(def->forward.type));
            return -1;
        }
2508 2509 2510 2511 2512
        if (virNetworkDefGetIpByIndex(def, AF_UNSPEC, 0)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2513
                           virNetworkForwardTypeToString(def->forward.type));
2514 2515
            return -1;
        }
2516
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
2517 2518 2519 2520
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2521
                           virNetworkForwardTypeToString(def->forward.type));
2522 2523 2524 2525 2526 2527 2528
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2529
                           virNetworkForwardTypeToString(def->forward.type));
2530 2531
            return -1;
        }
2532 2533 2534 2535 2536 2537 2538 2539
        if (def->bandwidth) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported network-wide <bandwidth> element "
                             "in network %s with forward mode='%s'"),
                           def->name,
                           virNetworkForwardTypeToString(def->forward.type));
            return -1;
        }
2540 2541
    }

G
Gene Czarcinski 已提交
2542 2543 2544
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
2545 2546 2547
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, i));
         i++) {
G
Gene Czarcinski 已提交
2548 2549 2550 2551 2552
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Multiple IPv4 dhcp sections found -- "
2553 2554
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571
                    return -1;
                } else {
                    ipv4def = true;
                }
            }
        }
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Multiple IPv6 dhcp sections found -- "
                                 "dhcp is supported only for a "
                                 "single IPv6 address on each network"));
                    return -1;
                } else {
                    ipv6def = true;
                }
2572 2573 2574
            }
        }
    }
2575 2576 2577 2578 2579 2580

    /* The only type of networks that currently support transparent
     * vlan configuration are those using hostdev sr-iov devices from
     * a pool, and those using an Open vSwitch bridge.
     */

2581
    vlanAllowed = ((def->forward.type == VIR_NETWORK_FORWARD_BRIDGE &&
2582
                   def->virtPortProfile &&
2583 2584 2585
                   def->virtPortProfile->virtPortType
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) ||
                   def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV);
2586 2587

    vlanUsed = def->vlan.nTags > 0;
2588 2589
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
2590 2591 2592 2593 2594
            /* anyone using this portgroup will get a vlan tag. Verify
             * that they will also be using an openvswitch connection,
             * as that is the only type of network that currently
             * supports a vlan tag.
             */
2595
            if (def->portGroups[i].virtPortProfile) {
2596
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
2597
                    def->portGroups[i].virtPortProfile->virtPortType
2598 2599 2600 2601 2602 2603 2604
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
2605
        }
2606
        if (def->portGroups[i].isDefault) {
2607 2608 2609 2610 2611
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
2612
                               def->name, defaultPortGroup->name,
2613
                               def->portGroups[i].name);
2614
                return -1;
2615
            }
2616
            defaultPortGroup = &def->portGroups[i];
2617
        }
2618
    }
2619 2620 2621 2622 2623 2624 2625
    if (badVlanUse ||
        (vlanUsed && !vlanAllowed && !defaultPortGroup)) {
        /* NB: if defaultPortGroup is set, we don't directly look at
         * vlanUsed && !vlanAllowed, because the network will never be
         * used without having a portgroup added in, so all necessary
         * checks were done in the loop above.
         */
2626 2627 2628 2629 2630 2631 2632 2633 2634
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
    return 0;
}

2635 2636
static virNetworkPtr networkCreateXML(virConnectPtr conn, const char *xml)
{
2637
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2638
    virNetworkDefPtr def;
2639
    virNetworkObjPtr network = NULL;
2640
    virNetworkPtr ret = NULL;
2641
    virObjectEventPtr event = NULL;
2642

2643 2644
    networkDriverLock(driver);

2645
    if (!(def = virNetworkDefParseString(xml)))
2646
        goto cleanup;
2647

2648 2649 2650
    if (virNetworkCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

2651
    if (networkValidate(driver, def, true) < 0)
2652 2653
       goto cleanup;

2654 2655 2656 2657
    /* NB: "live" is false because this transient network hasn't yet
     * been started
     */
    if (!(network = virNetworkAssignDef(&driver->networks, def, false)))
2658 2659
        goto cleanup;
    def = NULL;
2660

2661
    if (networkStartNetwork(driver, network) < 0) {
2662 2663
        virNetworkRemoveInactive(&driver->networks,
                                 network);
2664
        network = NULL;
2665
        goto cleanup;
2666 2667
    }

2668 2669
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
2670 2671
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
2672

2673
    VIR_INFO("Creating network '%s'", network->def->name);
2674 2675
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2676
 cleanup:
2677
    virNetworkDefFree(def);
2678 2679
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
2680 2681 2682
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
2683
    return ret;
2684 2685
}

2686 2687
static virNetworkPtr networkDefineXML(virConnectPtr conn, const char *xml)
{
2688
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2689
    virNetworkDefPtr def = NULL;
2690
    bool freeDef = true;
2691
    virNetworkObjPtr network = NULL;
2692
    virNetworkPtr ret = NULL;
2693
    virObjectEventPtr event = NULL;
2694

2695 2696
    networkDriverLock(driver);

2697
    if (!(def = virNetworkDefParseString(xml)))
2698
        goto cleanup;
2699

2700 2701 2702
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

2703
    if (networkValidate(driver, def, false) < 0)
2704 2705
       goto cleanup;

2706 2707 2708 2709 2710 2711 2712 2713
    if ((network = virNetworkFindByName(&driver->networks, def->name))) {
        network->persistent = 1;
        if (virNetworkObjAssignDef(network, def, false) < 0)
            goto cleanup;
    } else {
        if (!(network = virNetworkAssignDef(&driver->networks, def, false)))
            goto cleanup;
    }
2714

2715 2716 2717
    /* define makes the network persistent - always */
    network->persistent = 1;

2718 2719
    /* def was asigned */
    freeDef = false;
2720 2721

    if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
2722 2723 2724 2725 2726 2727 2728 2729
        if (!virNetworkObjIsActive(network)) {
            virNetworkRemoveInactive(&driver->networks, network);
            network = NULL;
            goto cleanup;
        }
        network->persistent = 0;
        virNetworkDefFree(network->newDef);
        network->newDef = NULL;
2730 2731 2732
        goto cleanup;
    }

2733
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
2734 2735
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
2736

2737 2738
    VIR_INFO("Defining network '%s'", def->name);
    ret = virGetNetwork(conn, def->name, def->uuid);
2739

2740
 cleanup:
2741 2742
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
2743 2744
    if (freeDef)
       virNetworkDefFree(def);
2745 2746 2747
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
2748
    return ret;
2749 2750
}

2751
static int
2752 2753
networkUndefine(virNetworkPtr net)
{
2754
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
2755
    virNetworkObjPtr network;
2756
    int ret = -1;
2757
    bool active = false;
2758
    virObjectEventPtr event = NULL;
2759

2760 2761
    networkDriverLock(driver);

2762
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
2763
    if (!network) {
2764 2765
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
2766
        goto cleanup;
2767 2768
    }

2769 2770 2771
    if (virNetworkUndefineEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

2772 2773
    if (virNetworkObjIsActive(network))
        active = true;
2774

2775
    if (virNetworkDeleteConfig(driver->networkConfigDir,
2776 2777
                               driver->networkAutostartDir,
                               network) < 0)
2778
        goto cleanup;
2779

2780 2781
    /* make the network transient */
    network->persistent = 0;
2782
    network->autostart = 0;
2783 2784 2785
    virNetworkDefFree(network->newDef);
    network->newDef = NULL;

2786 2787
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
2788 2789
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
2790

2791
    VIR_INFO("Undefining network '%s'", network->def->name);
2792 2793 2794 2795 2796
    if (!active) {
        if (networkRemoveInactive(driver, network) < 0) {
            network = NULL;
            goto cleanup;
        }
2797
        network = NULL;
2798 2799
    }

2800
    ret = 0;
2801

2802
 cleanup:
2803 2804
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
2805 2806 2807
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
2808
    return ret;
2809 2810
}

2811 2812 2813 2814 2815 2816 2817 2818
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
2819
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
2820
    virNetworkObjPtr network = NULL;
2821 2822
    int isActive, ret = -1;
    size_t i;
2823 2824
    virNetworkIpDefPtr ipdef;
    bool oldDhcpActive = false;
2825
    bool needFirewallRefresh = false;
2826

2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

    networkDriverLock(driver);

    network = virNetworkFindByUUID(&driver->networks, net->uuid);
    if (!network) {
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
        goto cleanup;
    }

2841 2842 2843
    if (virNetworkUpdateEnsureACL(net->conn, network->def, flags) < 0)
        goto cleanup;

2844
    /* see if we are listening for dhcp pre-modification */
2845 2846 2847
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
         i++) {
2848 2849 2850 2851 2852 2853
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

2854 2855 2856 2857
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
    */
    isActive = virNetworkObjIsActive(network);
2858 2859
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
2860 2861 2862 2863 2864 2865 2866
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
        if (network->def->forward.type == VIR_NETWORK_FORWARD_NONE ||
            network->def->forward.type == VIR_NETWORK_FORWARD_NAT ||
            network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
            switch (section) {
            case VIR_NETWORK_SECTION_FORWARD:
            case VIR_NETWORK_SECTION_FORWARD_INTERFACE:
            case VIR_NETWORK_SECTION_IP:
            case VIR_NETWORK_SECTION_IP_DHCP_RANGE:
            case VIR_NETWORK_SECTION_IP_DHCP_HOST:
                /* these could affect the firewall rules, so remove the
                 * old rules (and remember to load new ones after the
                 * update).
                 */
                networkRemoveFirewallRules(network);
                needFirewallRefresh = true;
                break;
            default:
                break;
            }
        }
    }

2893
    /* update the network config in memory/on disk */
2894 2895 2896 2897 2898 2899 2900
    if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0) {
        if (needFirewallRefresh)
            ignore_value(networkAddFirewallRules(network));
        goto cleanup;
    }

    if (needFirewallRefresh && networkAddFirewallRules(network) < 0)
2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
                                 virNetworkObjGetPersistentDef(network)) < 0) {
            goto cleanup;
        }
    }

    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* rewrite dnsmasq host files, restart dnsmasq, update iptables
         * rules, etc, according to which section was modified. Note that
         * some sections require multiple actions, so a single switch
         * statement is inadequate.
         */
        if (section == VIR_NETWORK_SECTION_BRIDGE ||
            section == VIR_NETWORK_SECTION_DOMAIN ||
            section == VIR_NETWORK_SECTION_IP ||
            section == VIR_NETWORK_SECTION_IP_DHCP_RANGE) {
            /* these sections all change things on the dnsmasq commandline,
             * so we need to kill and restart dnsmasq.
             */
2924
            if (networkRestartDhcpDaemon(driver, network) < 0)
2925 2926
                goto cleanup;

2927 2928 2929 2930 2931 2932 2933 2934
        } else if (section == VIR_NETWORK_SECTION_IP_DHCP_HOST) {
            /* if we previously weren't listening for dhcp and now we
             * are (or vice-versa) then we need to do a restart,
             * otherwise we just need to do a refresh (redo the config
             * files and send SIGHUP)
             */
            bool newDhcpActive = false;

2935 2936 2937
            for (i = 0;
                 (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
                 i++) {
2938 2939 2940 2941 2942 2943 2944
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
2945 2946
                 networkRestartDhcpDaemon(driver, network) < 0) ||
                networkRefreshDhcpDaemon(driver, network) < 0) {
2947 2948 2949 2950
                goto cleanup;
            }

        } else if (section == VIR_NETWORK_SECTION_DNS_HOST ||
2951 2952 2953 2954 2955 2956
                   section == VIR_NETWORK_SECTION_DNS_TXT ||
                   section == VIR_NETWORK_SECTION_DNS_SRV) {
            /* these sections only change things in config files, so we
             * can just update the config files and send SIGHUP to
             * dnsmasq.
             */
2957
            if (networkRefreshDhcpDaemon(driver, network) < 0)
2958 2959 2960 2961 2962 2963 2964 2965
                goto cleanup;

        }

        if (section == VIR_NETWORK_SECTION_IP) {
            /* only a change in IP addresses will affect radvd, and all of radvd's
             * config is stored in the conf file which will be re-read with a SIGHUP.
             */
2966
            if (networkRefreshRadvd(driver, network) < 0)
2967 2968 2969 2970
                goto cleanup;
        }

        /* save current network state to disk */
2971 2972
        if ((ret = virNetworkSaveStatus(driverState->stateDir,
                                        network)) < 0) {
2973
            goto cleanup;
2974
        }
2975 2976
    }
    ret = 0;
2977
 cleanup:
2978 2979 2980 2981 2982 2983
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
    return ret;
}

2984 2985
static int networkCreate(virNetworkPtr net)
{
2986
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
2987 2988
    virNetworkObjPtr network;
    int ret = -1;
2989
    virObjectEventPtr event = NULL;
2990

2991
    networkDriverLock(driver);
2992
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
2993

2994
    if (!network) {
2995 2996
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
2997
        goto cleanup;
2998 2999
    }

3000 3001 3002
    if (virNetworkCreateEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3003
    ret = networkStartNetwork(driver, network);
3004

3005 3006
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3007 3008
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3009

3010
 cleanup:
3011 3012
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3013 3014
    if (network)
        virNetworkObjUnlock(network);
3015
    networkDriverUnlock(driver);
3016
    return ret;
3017 3018
}

3019 3020
static int networkDestroy(virNetworkPtr net)
{
3021
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
3022 3023
    virNetworkObjPtr network;
    int ret = -1;
3024
    virObjectEventPtr event = NULL;
3025

3026
    networkDriverLock(driver);
3027
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
3028

3029
    if (!network) {
3030 3031
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
3032
        goto cleanup;
3033 3034
    }

3035 3036 3037
    if (virNetworkDestroyEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3038
    if (!virNetworkObjIsActive(network)) {
3039 3040
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is not active"));
3041 3042 3043
        goto cleanup;
    }

3044 3045 3046
    if ((ret = networkShutdownNetwork(driver, network)) < 0)
        goto cleanup;

3047 3048
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3049 3050
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
3051

3052
    if (!network->persistent) {
3053 3054 3055 3056 3057
        if (networkRemoveInactive(driver, network) < 0) {
            network = NULL;
            ret = -1;
            goto cleanup;
        }
3058 3059
        network = NULL;
    }
3060

3061
 cleanup:
3062 3063
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3064 3065
    if (network)
        virNetworkObjUnlock(network);
3066
    networkDriverUnlock(driver);
3067 3068 3069
    return ret;
}

3070
static char *networkGetXMLDesc(virNetworkPtr net,
3071
                               unsigned int flags)
3072
{
3073
    virNetworkObjPtr network;
3074
    virNetworkDefPtr def;
3075
    char *ret = NULL;
3076

3077
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
3078

3079 3080
    if (!(network = networkObjFromNetwork(net)))
        return ret;
3081

3082 3083 3084
    if (virNetworkGetXMLDescEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3085 3086 3087 3088 3089 3090
    if ((flags & VIR_NETWORK_XML_INACTIVE) && network->newDef)
        def = network->newDef;
    else
        def = network->def;

    ret = virNetworkDefFormat(def, flags);
3091

3092
 cleanup:
3093 3094
    if (network)
        virNetworkObjUnlock(network);
3095
    return ret;
3096 3097 3098
}

static char *networkGetBridgeName(virNetworkPtr net) {
3099 3100 3101
    virNetworkObjPtr network;
    char *bridge = NULL;

3102 3103
    if (!(network = networkObjFromNetwork(net)))
        return bridge;
3104

3105 3106 3107
    if (virNetworkGetBridgeNameEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3108
    if (!(network->def->bridge)) {
3109 3110 3111
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
                       network->def->name);
3112 3113 3114
        goto cleanup;
    }

3115
    ignore_value(VIR_STRDUP(bridge, network->def->bridge));
3116

3117
 cleanup:
3118 3119
    if (network)
        virNetworkObjUnlock(network);
3120 3121 3122 3123
    return bridge;
}

static int networkGetAutostart(virNetworkPtr net,
3124 3125
                             int *autostart)
{
3126 3127
    virNetworkObjPtr network;
    int ret = -1;
3128

3129 3130
    if (!(network = networkObjFromNetwork(net)))
        return ret;
3131

3132 3133 3134
    if (virNetworkGetAutostartEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3135
    *autostart = network->autostart;
3136
    ret = 0;
3137

3138
 cleanup:
3139 3140
    if (network)
        virNetworkObjUnlock(network);
3141
    return ret;
3142 3143 3144
}

static int networkSetAutostart(virNetworkPtr net,
3145 3146
                               int autostart)
{
3147
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
3148
    virNetworkObjPtr network;
3149
    char *configFile = NULL, *autostartLink = NULL;
3150
    int ret = -1;
3151

3152
    networkDriverLock(driver);
3153
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
3154

3155
    if (!network) {
3156 3157
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
3158
        goto cleanup;
3159 3160
    }

3161 3162 3163
    if (virNetworkSetAutostartEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3164
    if (!network->persistent) {
3165 3166
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
3167 3168 3169
        goto cleanup;
    }

3170 3171
    autostart = (autostart != 0);

3172
    if (network->autostart != autostart) {
3173
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir, network->def->name)) == NULL)
3174
            goto cleanup;
3175
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, network->def->name)) == NULL)
3176 3177
            goto cleanup;

3178
        if (autostart) {
3179
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
3180
                virReportSystemError(errno,
3181 3182
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
3183 3184
                goto cleanup;
            }
3185

3186
            if (symlink(configFile, autostartLink) < 0) {
3187
                virReportSystemError(errno,
3188
                                     _("Failed to create symlink '%s' to '%s'"),
3189
                                     autostartLink, configFile);
3190 3191 3192
                goto cleanup;
            }
        } else {
3193
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
3194
                virReportSystemError(errno,
3195
                                     _("Failed to delete symlink '%s'"),
3196
                                     autostartLink);
3197 3198
                goto cleanup;
            }
3199 3200
        }

3201
        network->autostart = autostart;
3202
    }
3203
    ret = 0;
3204

3205
 cleanup:
3206 3207
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
3208 3209
    if (network)
        virNetworkObjUnlock(network);
3210
    networkDriverUnlock(driver);
3211
    return ret;
3212 3213 3214 3215 3216
}


static virNetworkDriver networkDriver = {
    "Network",
3217 3218 3219 3220 3221 3222 3223
    .networkOpen = networkOpen, /* 0.2.0 */
    .networkClose = networkClose, /* 0.2.0 */
    .connectNumOfNetworks = networkConnectNumOfNetworks, /* 0.2.0 */
    .connectListNetworks = networkConnectListNetworks, /* 0.2.0 */
    .connectNumOfDefinedNetworks = networkConnectNumOfDefinedNetworks, /* 0.2.0 */
    .connectListDefinedNetworks = networkConnectListDefinedNetworks, /* 0.2.0 */
    .connectListAllNetworks = networkConnectListAllNetworks, /* 0.10.2 */
3224 3225
    .connectNetworkEventRegisterAny = networkConnectNetworkEventRegisterAny, /* 1.2.1 */
    .connectNetworkEventDeregisterAny = networkConnectNetworkEventDeregisterAny, /* 1.2.1 */
3226 3227
    .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
    .networkLookupByName = networkLookupByName, /* 0.2.0 */
3228 3229
    .networkCreateXML = networkCreateXML, /* 0.2.0 */
    .networkDefineXML = networkDefineXML, /* 0.2.0 */
3230
    .networkUndefine = networkUndefine, /* 0.2.0 */
3231
    .networkUpdate = networkUpdate, /* 0.10.2 */
3232
    .networkCreate = networkCreate, /* 0.2.0 */
3233 3234 3235 3236 3237 3238 3239
    .networkDestroy = networkDestroy, /* 0.2.0 */
    .networkGetXMLDesc = networkGetXMLDesc, /* 0.2.0 */
    .networkGetBridgeName = networkGetBridgeName, /* 0.2.0 */
    .networkGetAutostart = networkGetAutostart, /* 0.2.1 */
    .networkSetAutostart = networkSetAutostart, /* 0.2.1 */
    .networkIsActive = networkIsActive, /* 0.7.3 */
    .networkIsPersistent = networkIsPersistent, /* 0.7.3 */
3240 3241 3242
};

static virStateDriver networkStateDriver = {
3243
    .name = "Network",
3244
    .stateInitialize  = networkStateInitialize,
3245
    .stateAutoStart  = networkStateAutoStart,
3246 3247
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
3248 3249
};

3250 3251
int networkRegister(void)
{
3252 3253
    if (virRegisterNetworkDriver(&networkDriver) < 0)
        return -1;
3254 3255
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
3256 3257
    return 0;
}
3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268

/********************************************************/

/* Private API to deal with logical switch capabilities.
 * These functions are exported so that other parts of libvirt can
 * call them, but are not part of the public API and not in the
 * driver's function table. If we ever have more than one network
 * driver, we will need to present these functions via a second
 * "backend" function table.
 */

3269 3270 3271 3272 3273 3274
/* networkCreateInterfacePool:
 * @netdef: the original NetDef from the network
 *
 * Creates an implicit interface pool of VF's when a PF dev is given
 */
static int
3275 3276
networkCreateInterfacePool(virNetworkDefPtr netdef)
{
3277
    size_t num_virt_fns = 0;
3278
    char **vfname = NULL;
3279
    virPCIDeviceAddressPtr *virt_fns;
3280 3281
    int ret = -1;
    size_t i;
3282

3283
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev,
3284
                                      &vfname, &virt_fns, &num_virt_fns)) < 0) {
3285 3286
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get Virtual functions on %s"),
3287
                       netdef->forward.pfs->dev);
3288 3289 3290 3291 3292 3293
        goto finish;
    }

    if (num_virt_fns == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No Vf's present on SRIOV PF %s"),
3294
                       netdef->forward.pfs->dev);
3295 3296 3297
       goto finish;
    }

3298
    if (VIR_ALLOC_N(netdef->forward.ifs, num_virt_fns) < 0)
3299 3300
        goto finish;

3301
    netdef->forward.nifs = num_virt_fns;
3302

3303
    for (i = 0; i < netdef->forward.nifs; i++) {
3304 3305 3306 3307
        if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) ||
            (netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) ||
            (netdef->forward.type == VIR_NETWORK_FORWARD_VEPA) ||
            (netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH)) {
3308 3309 3310
            netdef->forward.ifs[i].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
            if (vfname[i]) {
                if (VIR_STRDUP(netdef->forward.ifs[i].device.dev, vfname[i]) < 0)
3311
                    goto finish;
3312
            } else {
3313
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3314
                               _("Direct mode types require interface names"));
3315 3316
                goto finish;
            }
3317
        }
3318
        else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
3319
            /* VF's are always PCI devices */
3320 3321 3322 3323 3324
            netdef->forward.ifs[i].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI;
            netdef->forward.ifs[i].device.pci.domain = virt_fns[i]->domain;
            netdef->forward.ifs[i].device.pci.bus = virt_fns[i]->bus;
            netdef->forward.ifs[i].device.pci.slot = virt_fns[i]->slot;
            netdef->forward.ifs[i].device.pci.function = virt_fns[i]->function;
3325
        }
3326 3327 3328
    }

    ret = 0;
3329
 finish:
3330 3331 3332
    for (i = 0; i < num_virt_fns; i++) {
        VIR_FREE(vfname[i]);
        VIR_FREE(virt_fns[i]);
3333
    }
3334
    VIR_FREE(vfname);
3335
    VIR_FREE(virt_fns);
3336 3337 3338
    return ret;
}

3339
/* networkAllocateActualDevice:
3340
 * @dom: domain definition that @iface belongs to
3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351
 * @iface: the original NetDef from the domain
 *
 * Looks up the network reference by iface, allocates a physical
 * device from that network (if appropriate), and returns with the
 * virDomainActualNetDef filled in accordingly. If there are no
 * changes to be made in the netdef, then just leave the actualdef
 * empty.
 *
 * Returns 0 on success, -1 on failure.
 */
int
3352 3353
networkAllocateActualDevice(virDomainDefPtr dom,
                            virDomainNetDefPtr iface)
3354
{
3355
    virNetworkDriverStatePtr driver = driverState;
3356 3357 3358
    enum virDomainNetType actualType = iface->type;
    virNetworkObjPtr network = NULL;
    virNetworkDefPtr netdef = NULL;
3359
    virNetDevBandwidthPtr bandwidth = NULL;
3360 3361 3362
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
3363
    virNetworkForwardIfDefPtr dev = NULL;
3364
    size_t i;
3365 3366 3367
    int ret = -1;

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
3368
        goto validate;
3369 3370 3371 3372 3373 3374 3375 3376

    virDomainActualNetDefFree(iface->data.network.actual);
    iface->data.network.actual = NULL;

    networkDriverLock(driver);
    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
    networkDriverUnlock(driver);
    if (!network) {
3377 3378 3379
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
3380
        goto error;
3381 3382
    }
    netdef = network->def;
3383

3384 3385 3386
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

3387 3388 3389 3390 3391 3392 3393 3394 3395 3396
    /* portgroup can be present for any type of network, in particular
     * for bandwidth information, so we need to check for that and
     * fill it in appropriately for all forward types.
    */
    portgroup = virPortGroupFindByName(netdef, iface->data.network.portgroup);

    /* If there is already interface-specific bandwidth, just use that
     * (already in NetDef). Otherwise, if there is bandwidth info in
     * the portgroup, fill that into the ActualDef.
     */
3397 3398 3399 3400 3401 3402

    if (iface->bandwidth)
        bandwidth = iface->bandwidth;
    else if (portgroup && portgroup->bandwidth)
        bandwidth = portgroup->bandwidth;

3403 3404
    if (bandwidth && virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
                                            bandwidth) < 0)
3405
        goto error;
3406

3407 3408 3409 3410 3411 3412 3413 3414
    /* copy appropriate vlan info to actualNet */
    if (iface->vlan.nTags > 0)
        vlan = &iface->vlan;
    else if (portgroup && portgroup->vlan.nTags > 0)
        vlan = &portgroup->vlan;
    else if (netdef->vlan.nTags > 0)
        vlan = &netdef->vlan;

3415 3416
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
3417

3418 3419 3420
    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE)) {
3421 3422 3423 3424
        /* for these forward types, the actual net type really *is*
         *NETWORK; we just keep the info from the portgroup in
         * iface->data.network.actual
        */
3425
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
3426 3427 3428 3429

        if (networkPlugBandwidth(network, iface) < 0)
            goto error;

3430
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
3431
               netdef->bridge) {
3432 3433 3434 3435 3436

        /* <forward type='bridge'/> <bridge name='xxx'/>
         * is VIR_DOMAIN_NET_TYPE_BRIDGE
         */

3437
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
3438 3439
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
3440
            goto error;
3441

3442 3443 3444 3445 3446 3447 3448 3449
        /* merge virtualports from interface, network, and portgroup to
         * arrive at actual virtualport to use
         */
        if (virNetDevVPortProfileMerge3(&iface->data.network.actual->virtPortProfile,
                                        iface->virtPortProfile,
                                        netdef->virtPortProfile,
                                        portgroup
                                        ? portgroup->virtPortProfile : NULL) < 0) {
3450
            goto error;
3451 3452 3453 3454 3455 3456 3457 3458 3459 3460
        }
        virtport = iface->data.network.actual->virtPortProfile;
        if (virtport) {
            /* only type='openvswitch' is allowed for bridges */
            if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses a bridge device"),
                               virNetDevVPortTypeToString(virtport->virtPortType),
                               netdef->name);
3461
                goto error;
3462 3463 3464
            }
        }

3465
    } else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
3466

3467 3468
        virDomainHostdevSubsysPciBackendType backend;

3469
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
3470
        if (netdef->forward.npfs > 0 && netdef->forward.nifs <= 0 &&
3471 3472 3473 3474 3475
            networkCreateInterfacePool(netdef) < 0) {
            goto error;
        }

        /* pick first dev with 0 connections */
3476 3477 3478
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492
                break;
            }
        }
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' requires exclusive access "
                             "to interfaces, but none are available"),
                           netdef->name);
            goto error;
        }
        iface->data.network.actual->data.hostdev.def.parent.type = VIR_DOMAIN_DEVICE_NET;
        iface->data.network.actual->data.hostdev.def.parent.data.net = iface;
        iface->data.network.actual->data.hostdev.def.info = &iface->info;
        iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
3493
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
3494
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
3495
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
3496

3497 3498 3499
        switch (netdef->forward.driverName)
        {
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
3500
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
3501 3502
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
3503
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
3504 3505
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
3506
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
            break;
        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unrecognized driver name value %d "
                             " in network '%s'"),
                           netdef->forward.driverName, netdef->name);
            goto error;
        }
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.backend
            = backend;

3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542
        /* merge virtualports from interface, network, and portgroup to
         * arrive at actual virtualport to use
         */
        if (virNetDevVPortProfileMerge3(&iface->data.network.actual->virtPortProfile,
                                        iface->virtPortProfile,
                                        netdef->virtPortProfile,
                                        portgroup
                                        ? portgroup->virtPortProfile : NULL) < 0) {
            goto error;
        }
        virtport = iface->data.network.actual->virtPortProfile;
        if (virtport) {
            /* make sure type is supported for hostdev connections */
            if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses an SR-IOV Virtual Function "
                                 "via PCI passthrough"),
                               virNetDevVPortTypeToString(virtport->virtPortType),
                               netdef->name);
                goto error;
            }
        }

3543 3544 3545 3546
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) ||
               (netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) ||
               (netdef->forward.type == VIR_NETWORK_FORWARD_VEPA) ||
               (netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH)) {
3547 3548 3549 3550 3551 3552

        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
3553
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
3554
        switch (netdef->forward.type) {
3555
        case VIR_NETWORK_FORWARD_BRIDGE:
3556
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
3557 3558
            break;
        case VIR_NETWORK_FORWARD_PRIVATE:
3559
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
3560 3561
            break;
        case VIR_NETWORK_FORWARD_VEPA:
3562
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
3563 3564
            break;
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
3565
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PASSTHRU;
3566 3567 3568
            break;
        }

3569 3570 3571 3572 3573 3574 3575 3576
        /* merge virtualports from interface, network, and portgroup to
         * arrive at actual virtualport to use
         */
        if (virNetDevVPortProfileMerge3(&iface->data.network.actual->virtPortProfile,
                                        iface->virtPortProfile,
                                        netdef->virtPortProfile,
                                        portgroup
                                        ? portgroup->virtPortProfile : NULL) < 0) {
3577
            goto error;
3578
        }
3579
        virtport = iface->data.network.actual->virtPortProfile;
3580
        if (virtport) {
3581 3582 3583 3584 3585 3586 3587 3588
            /* make sure type is supported for macvtap connections */
            if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses a macvtap device"),
                               virNetDevVPortTypeToString(virtport->virtPortType),
                               netdef->name);
3589
                goto error;
3590 3591
            }
        }
3592

3593 3594 3595
        /* If there is only a single device, just return it (caller will detect
         * any error if exclusive use is required but could not be acquired).
         */
3596
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
3597 3598 3599 3600
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
3601
            goto error;
3602 3603 3604
        } else {
            /* pick an interface from the pool */

3605
            if (netdef->forward.npfs > 0 && netdef->forward.nifs == 0 &&
3606 3607 3608 3609
                networkCreateInterfacePool(netdef) < 0) {
                goto error;
            }

3610 3611 3612 3613 3614
            /* PASSTHROUGH mode, and PRIVATE Mode + 802.1Qbh both
             * require exclusive access to a device, so current
             * connections count must be 0.  Other modes can share, so
             * just search for the one with the lowest number of
             * connections.
3615
             */
3616 3617
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
3618 3619 3620
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
3621

3622
                /* pick first dev with 0 connections */
3623 3624 3625
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
3626 3627 3628 3629 3630
                        break;
                    }
                }
            } else {
                /* pick least used dev */
3631
                dev = &netdef->forward.ifs[0];
3632 3633 3634
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
3635 3636 3637 3638
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
3639 3640 3641 3642
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
3643
                goto error;
3644
            }
3645 3646
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
3647
                goto error;
3648 3649 3650
        }
    }

3651
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
3652
        goto error;
3653

3654
 validate:
3655 3656 3657 3658 3659
    /* make sure that everything now specified for the device is
     * actually supported on this type of network. NB: network,
     * netdev, and iface->data.network.actual may all be NULL.
     */

3660
    if (virDomainNetGetActualVlan(iface)) {
3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689
        /* vlan configuration via libvirt is only supported for
         * PCI Passthrough SR-IOV devices and openvswitch bridges.
         * otherwise log an error and fail
         */
        if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
              (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE &&
               virtport && virtport->virtPortType
               == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
            if (netdef) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("an interface connecting to network '%s' "
                                 "is requesting a vlan tag, but that is not "
                                 "supported for this type of network"),
                               netdef->name);
            } else {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("an interface of type '%s' "
                                 "is requesting a vlan tag, but that is not "
                                 "supported for this type of connection"),
                               virDomainNetTypeToString(iface->type));
            }
            goto error;
        }
    }

    if (netdef) {
        netdef->connections++;
        VIR_DEBUG("Using network %s, %d connections",
                  netdef->name, netdef->connections);
3690

3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709
        if (dev) {
            /* mark the allocation */
            dev->connections++;
            if (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV) {
                VIR_DEBUG("Using physical device %s, %d connections",
                          dev->device.dev, dev->connections);
            } else {
                VIR_DEBUG("Using physical device %04x:%02x:%02x.%x, connections %d",
                          dev->device.pci.domain, dev->device.pci.bus,
                          dev->device.pci.slot, dev->device.pci.function,
                          dev->connections);
            }
        }

        /* finally we can call the 'plugged' hook script if any */
        if (networkRunHook(network, dom, iface,
                           VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
                           VIR_HOOK_SUBOP_BEGIN) < 0) {
            /* adjust for failure */
3710
            netdef->connections--;
3711 3712 3713 3714
            if (dev)
                dev->connections--;
            goto error;
        }
3715 3716
    }

3717
    ret = 0;
3718

3719
 cleanup:
3720 3721
    if (network)
        virNetworkObjUnlock(network);
3722 3723
    return ret;

3724
 error:
3725
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
3726 3727 3728
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
3729
    goto cleanup;
3730 3731 3732
}

/* networkNotifyActualDevice:
3733
 * @dom: domain definition that @iface belongs to
3734 3735 3736 3737 3738 3739 3740 3741 3742 3743
 * @iface:  the domain's NetDef with an "actual" device already filled in.
 *
 * Called to notify the network driver when libvirtd is restarted and
 * finds an already running domain. If appropriate it will force an
 * allocation of the actual->direct.linkdev to get everything back in
 * order.
 *
 * Returns 0 on success, -1 on failure.
 */
int
3744 3745
networkNotifyActualDevice(virDomainDefPtr dom,
                          virDomainNetDefPtr iface)
3746
{
3747
    virNetworkDriverStatePtr driver = driverState;
3748
    enum virDomainNetType actualType = virDomainNetGetActualType(iface);
3749 3750
    virNetworkObjPtr network;
    virNetworkDefPtr netdef;
3751
    virNetworkForwardIfDefPtr dev = NULL;
3752 3753
    size_t i;
    int ret = -1;
3754 3755 3756 3757 3758 3759 3760 3761

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
       return 0;

    networkDriverLock(driver);
    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
    networkDriverUnlock(driver);
    if (!network) {
3762 3763 3764
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
3765 3766 3767 3768 3769
        goto error;
    }
    netdef = network->def;

    if (!iface->data.network.actual ||
3770 3771
        (actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
3772 3773
        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
        goto success;
3774 3775
    }

3776
    if (netdef->forward.npfs > 0 && netdef->forward.nifs == 0 &&
3777
        networkCreateInterfacePool(netdef) < 0) {
3778
        goto error;
3779
    }
3780
    if (netdef->forward.nifs == 0) {
3781
        virReportError(VIR_ERR_INTERNAL_ERROR,
3782 3783
                       _("network '%s' uses a direct or hostdev mode, "
                         "but has no forward dev and no interface pool"),
3784
                       netdef->name);
3785
        goto error;
3786
    }
3787

3788 3789
    if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
        const char *actualDev;
3790

3791 3792 3793 3794 3795 3796 3797 3798 3799
        actualDev = virDomainNetGetActualDirectDev(iface);
        if (!actualDev) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("the interface uses a direct mode, "
                             "but has no source dev"));
            goto error;
        }

        /* find the matching interface and increment its connections */
3800 3801
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
3802
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
3803 3804
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
3805 3806 3807 3808 3809
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
3810
            virReportError(VIR_ERR_INTERNAL_ERROR,
3811 3812
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
3813
                           netdef->name, actualDev);
3814
            goto error;
3815 3816
        }

3817
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
3818 3819
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
3820
         */
3821
        if ((dev->connections > 0) &&
3822 3823
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
3824 3825
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
3826
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
3827
            virReportError(VIR_ERR_INTERNAL_ERROR,
3828 3829
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
3830
                           netdef->name, actualDev);
3831
            goto error;
3832
        }
3833

3834
        /* we are now assured of success, so mark the allocation */
3835
        dev->connections++;
3836
        VIR_DEBUG("Using physical device %s, connections %d",
3837
                  dev->device.dev, dev->connections);
3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850

    }  else /* if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) */ {
        virDomainHostdevDefPtr hostdev;

        hostdev = virDomainNetGetActualHostdev(iface);
        if (!hostdev) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("the interface uses a hostdev mode, "
                             "but has no hostdev"));
            goto error;
        }

        /* find the matching interface and increment its connections */
3851 3852
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
3853
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
3854
                virDevicePCIAddressEqual(&hostdev->source.subsys.u.pci.addr,
3855 3856
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
3857 3858 3859 3860 3861 3862 3863 3864 3865
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have "
                             "PCI device %04x:%02x:%02x.%x in use by domain"),
                           netdef->name,
3866 3867 3868 3869
                           hostdev->source.subsys.u.pci.addr.domain,
                           hostdev->source.subsys.u.pci.addr.bus,
                           hostdev->source.subsys.u.pci.addr.slot,
                           hostdev->source.subsys.u.pci.addr.function);
3870 3871 3872 3873 3874 3875 3876 3877
                goto error;
        }

        /* PASSTHROUGH mode, PRIVATE Mode + 802.1Qbh, and hostdev (PCI
         * passthrough) all require exclusive access to a device, so
         * current connections count must be 0 in those cases.
         */
        if ((dev->connections > 0) &&
3878
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' claims the PCI device at "
                             "domain=%d bus=%d slot=%d function=%d "
                             "is already in use by a different domain"),
                           netdef->name,
                           dev->device.pci.domain, dev->device.pci.bus,
                           dev->device.pci.slot, dev->device.pci.function);
            goto error;
        }

        /* we are now assured of success, so mark the allocation */
        dev->connections++;
        VIR_DEBUG("Using physical device %04x:%02x:%02x.%x, connections %d",
                  dev->device.pci.domain, dev->device.pci.bus,
                  dev->device.pci.slot, dev->device.pci.function,
                  dev->connections);
3895 3896
    }

3897
 success:
3898 3899 3900
    netdef->connections++;
    VIR_DEBUG("Using network %s, %d connections",
              netdef->name, netdef->connections);
3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911

    /* finally we can call the 'plugged' hook script if any */
    if (networkRunHook(network, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
        goto error;
    }

3912
    ret = 0;
3913
 cleanup:
3914 3915 3916
    if (network)
        virNetworkObjUnlock(network);
    return ret;
3917

3918
 error:
3919
    goto cleanup;
3920 3921 3922 3923
}


/* networkReleaseActualDevice:
3924
 * @dom: domain definition that @iface belongs to
3925 3926 3927 3928 3929 3930 3931 3932 3933 3934
 * @iface:  a domain's NetDef (interface definition)
 *
 * Given a domain <interface> element that previously had its <actual>
 * element filled in (and possibly a physical device allocated to it),
 * free up the physical device for use by someone else, and free the
 * virDomainActualNetDef.
 *
 * Returns 0 on success, -1 on failure.
 */
int
3935 3936
networkReleaseActualDevice(virDomainDefPtr dom,
                           virDomainNetDefPtr iface)
3937
{
3938
    virNetworkDriverStatePtr driver = driverState;
3939
    enum virDomainNetType actualType = virDomainNetGetActualType(iface);
3940
    virNetworkObjPtr network;
3941
    virNetworkDefPtr netdef;
3942
    virNetworkForwardIfDefPtr dev = NULL;
3943 3944
    size_t i;
    int ret = -1;
3945 3946 3947 3948 3949 3950 3951 3952

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
       return 0;

    networkDriverLock(driver);
    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
    networkDriverUnlock(driver);
    if (!network) {
3953 3954 3955
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
3956 3957 3958 3959
        goto error;
    }
    netdef = network->def;

3960 3961
    if (iface->data.network.actual &&
        (netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
3962 3963 3964 3965 3966
         netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) &&
        networkUnplugBandwidth(network, iface) < 0)
        goto error;

3967 3968 3969
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
3970 3971
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
3972 3973
    }

3974
    if (netdef->forward.nifs == 0) {
3975
        virReportError(VIR_ERR_INTERNAL_ERROR,
3976
                       _("network '%s' uses a direct/hostdev mode, but "
3977 3978
                         "has no forward dev and no interface pool"),
                       netdef->name);
3979
        goto error;
3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991
    }

    if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
        const char *actualDev;

        actualDev = virDomainNetGetActualDirectDev(iface);
        if (!actualDev) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("the interface uses a direct mode, "
                             "but has no source dev"));
            goto error;
        }
3992

3993 3994
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
3995
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
3996 3997
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
3998 3999 4000
                break;
            }
        }
4001

4002
        if (!dev) {
4003
            virReportError(VIR_ERR_INTERNAL_ERROR,
4004 4005
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4006
                           netdef->name, actualDev);
4007
            goto error;
4008 4009
        }

4010
        dev->connections--;
4011
        VIR_DEBUG("Releasing physical device %s, connections %d",
4012
                  dev->device.dev, dev->connections);
4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023

    } else /* if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) */ {
        virDomainHostdevDefPtr hostdev;

        hostdev = virDomainNetGetActualHostdev(iface);
        if (!hostdev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("the interface uses a hostdev mode, but has no hostdev"));
            goto error;
        }

4024 4025
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4026
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4027
                virDevicePCIAddressEqual(&hostdev->source.subsys.u.pci.addr,
4028 4029
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4030 4031 4032 4033 4034 4035 4036 4037 4038
                break;
            }
        }

        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have "
                             "PCI device %04x:%02x:%02x.%x in use by domain"),
                           netdef->name,
4039 4040 4041 4042
                           hostdev->source.subsys.u.pci.addr.domain,
                           hostdev->source.subsys.u.pci.addr.bus,
                           hostdev->source.subsys.u.pci.addr.slot,
                           hostdev->source.subsys.u.pci.addr.function);
4043 4044 4045 4046 4047 4048 4049 4050 4051
                goto error;
        }

        dev->connections--;
        VIR_DEBUG("Releasing physical device %04x:%02x:%02x.%x, connections %d",
                  dev->device.pci.domain, dev->device.pci.bus,
                  dev->device.pci.slot, dev->device.pci.function,
                  dev->connections);
   }
4052

4053
 success:
4054
    if (iface->data.network.actual) {
4055
        netdef->connections--;
4056 4057
        VIR_DEBUG("Releasing network %s, %d connections",
                  netdef->name, netdef->connections);
4058

4059 4060 4061 4062
        /* finally we can call the 'unplugged' hook script if any */
        networkRunHook(network, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
                       VIR_HOOK_SUBOP_BEGIN);
    }
4063
    ret = 0;
4064
 cleanup:
4065 4066
    if (network)
        virNetworkObjUnlock(network);
4067 4068 4069 4070
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4071
    return ret;
4072

4073
 error:
4074
    goto cleanup;
4075
}
4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099

/*
 * networkGetNetworkAddress:
 * @netname: the name of a network
 * @netaddr: string representation of IP address for that network.
 *
 * Attempt to return an IP (v4) address associated with the named
 * network. If a libvirt virtual network, that will be provided in the
 * configuration. For host bridge and direct (macvtap) networks, we
 * must do an ioctl to learn the address.
 *
 * Note: This function returns the 1st IPv4 address it finds. It might
 * be useful if it was more flexible, but the current use (getting a
 * listen address for qemu's vnc/spice graphics server) can only use a
 * single address anyway.
 *
 * Returns 0 on success, and puts a string (which must be free'd by
 * the caller) into *netaddr. Returns -1 on failure or -2 if
 * completely unsupported.
 */
int
networkGetNetworkAddress(const char *netname, char **netaddr)
{
    int ret = -1;
4100
    virNetworkDriverStatePtr driver = driverState;
4101
    virNetworkObjPtr network;
4102 4103 4104 4105
    virNetworkDefPtr netdef;
    virNetworkIpDefPtr ipdef;
    virSocketAddr addr;
    virSocketAddrPtr addrptr = NULL;
4106
    char *dev_name = NULL;
4107 4108 4109 4110 4111 4112

    *netaddr = NULL;
    networkDriverLock(driver);
    network = virNetworkFindByName(&driver->networks, netname);
    networkDriverUnlock(driver);
    if (!network) {
4113 4114 4115
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       netname);
4116
        goto error;
4117 4118 4119
    }
    netdef = network->def;

4120
    switch (netdef->forward.type) {
4121 4122 4123 4124 4125 4126
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
        /* if there's an ipv4def, get it's address */
        ipdef = virNetworkDefGetIpByIndex(netdef, AF_INET, 0);
        if (!ipdef) {
4127 4128 4129
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have an IPv4 address"),
                           netdef->name);
4130 4131 4132 4133 4134 4135
            break;
        }
        addrptr = &ipdef->address;
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
4136
        if ((dev_name = netdef->bridge))
4137 4138 4139 4140 4141 4142 4143 4144
            break;
        /*
         * fall through if netdef->bridge wasn't set, since this is
         * also a direct-mode interface.
         */
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
4145 4146
        if ((netdef->forward.nifs > 0) && netdef->forward.ifs)
            dev_name = netdef->forward.ifs[0].device.dev;
4147

4148
        if (!dev_name) {
4149 4150 4151
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' has no associated interface or bridge"),
                           netdef->name);
4152 4153 4154 4155
        }
        break;
    }

4156
    if (dev_name) {
4157
        if (virNetDevGetIPv4Address(dev_name, &addr) < 0)
4158
            goto error;
4159
        addrptr = &addr;
4160 4161
    }

4162 4163 4164
    if (!(addrptr &&
          (*netaddr = virSocketAddrFormat(addrptr)))) {
        goto error;
4165 4166
    }

4167
    ret = 0;
4168
 cleanup:
4169 4170 4171
    if (network)
        virNetworkObjUnlock(network);
    return ret;
4172

4173
 error:
4174
    goto cleanup;
4175
}
4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193

/**
 * networkCheckBandwidth:
 * @net: network QoS
 * @iface: interface QoS
 * @new_rate: new rate for non guaranteed class
 *
 * Returns: -1 if plugging would overcommit network QoS
 *           0 if plugging is safe (@new_rate updated)
 *           1 if no QoS is set (@new_rate untouched)
 */
static int
networkCheckBandwidth(virNetworkObjPtr net,
                      virDomainNetDefPtr iface,
                      unsigned long long *new_rate)
{
    int ret = -1;
    virNetDevBandwidthPtr netBand = net->def->bandwidth;
4194
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
4195 4196 4197 4198
    unsigned long long tmp_floor_sum = net->floor_sum;
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209
    virMacAddrFormat(&iface->mac, ifmac);

    if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
        !(netBand && netBand->in)) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("Invalid use of 'floor' on interface with MAC "
                         "address %s - network '%s' has no inbound QoS set"),
                       ifmac, net->def->name);
        return -1;
    }

4210
    if (!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor ||
4211 4212
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
4213
        return 1;
4214
    }
4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245

    tmp_new_rate = netBand->in->average;
    tmp_floor_sum += ifaceBand->in->floor;

    /* check against peak */
    if (netBand->in->peak) {
        tmp_new_rate = netBand->in->peak;
        if (tmp_floor_sum > netBand->in->peak) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("Cannot plug '%s' interface into '%s' because it "
                             "would overcommit 'peak' on network '%s'"),
                           ifmac,
                           net->def->bridge,
                           net->def->name);
            goto cleanup;
        }
    } else if (tmp_floor_sum > netBand->in->average) {
        /* tmp_floor_sum can be between 'average' and 'peak' iff 'peak' is set.
         * Otherwise, tmp_floor_sum must be below 'average'. */
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Cannot plug '%s' interface into '%s' because it "
                         "would overcommit 'average' on network '%s'"),
                       ifmac,
                       net->def->bridge,
                       net->def->name);
        goto cleanup;
    }

    *new_rate = tmp_new_rate;
    ret = 0;

4246
 cleanup:
4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283
    return ret;
}

/**
 * networkNextClassID:
 * @net: network object
 *
 * Find next free class ID. @net is supposed
 * to be locked already. If there is a free ID,
 * it is marked as used and returned.
 *
 * Returns next free class ID or -1 if none is available.
 */
static ssize_t
networkNextClassID(virNetworkObjPtr net)
{
    size_t ret = 0;
    bool is_set = false;

    while (virBitmapGetBit(net->class_id, ret, &is_set) == 0 && is_set)
        ret++;

    if (is_set || virBitmapSetBit(net->class_id, ret) < 0)
        return -1;

    return ret;
}

static int
networkPlugBandwidth(virNetworkObjPtr net,
                     virDomainNetDefPtr iface)
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    ssize_t class_id = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];
4284
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312

    if ((plug_ret = networkCheckBandwidth(net, iface, &new_rate)) < 0) {
        /* helper reported error */
        goto cleanup;
    }

    if (plug_ret > 0) {
        /* no QoS needs to be set; claim success */
        ret = 0;
        goto cleanup;
    }

    virMacAddrFormat(&iface->mac, ifmac);
    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK ||
        !iface->data.network.actual) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot set bandwidth on interface '%s' of type %d"),
                       ifmac, iface->type);
        goto cleanup;
    }

    /* generate new class_id */
    if ((class_id = networkNextClassID(net)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate next class ID"));
        goto cleanup;
    }

4313 4314
    plug_ret = virNetDevBandwidthPlug(net->def->bridge, net->def->bandwidth,
                                      &iface->mac, ifaceBand, class_id);
4315 4316 4317 4318 4319 4320 4321 4322
    if (plug_ret < 0) {
        ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
        goto cleanup;
    }

    /* QoS was set, generate new class ID */
    iface->data.network.actual->class_id = class_id;
    /* update sum of 'floor'-s of attached NICs */
4323
    net->floor_sum += ifaceBand->in->floor;
4324
    /* update status file */
4325
    if (virNetworkSaveStatus(driverState->stateDir, net) < 0) {
4326
        ignore_value(virBitmapClearBit(net->class_id, class_id));
4327
        net->floor_sum -= ifaceBand->in->floor;
4328 4329 4330 4331
        iface->data.network.actual->class_id = 0;
        ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
        goto cleanup;
    }
4332 4333 4334 4335 4336 4337 4338 4339 4340
    /* update rate for non guaranteed NICs */
    new_rate -= net->floor_sum;
    if (virNetDevBandwidthUpdateRate(net->def->bridge, "1:2",
                                     net->def->bandwidth, new_rate) < 0)
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
                 net->def->bridge);

    ret = 0;

4341
 cleanup:
4342 4343 4344 4345 4346 4347 4348 4349 4350
    return ret;
}

static int
networkUnplugBandwidth(virNetworkObjPtr net,
                       virDomainNetDefPtr iface)
{
    int ret = 0;
    unsigned long long new_rate;
4351
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
4352 4353 4354

    if (iface->data.network.actual &&
        iface->data.network.actual->class_id) {
4355 4356 4357 4358 4359
        if (!net->def->bandwidth || !net->def->bandwidth->in) {
            VIR_WARN("Network %s has no bandwidth but unplug requested",
                     net->def->name);
            goto cleanup;
        }
4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370
        /* we must remove class from bridge */
        new_rate = net->def->bandwidth->in->average;

        if (net->def->bandwidth->in->peak > 0)
            new_rate = net->def->bandwidth->in->peak;

        ret = virNetDevBandwidthUnplug(net->def->bridge,
                                       iface->data.network.actual->class_id);
        if (ret < 0)
            goto cleanup;
        /* update sum of 'floor'-s of attached NICs */
4371
        net->floor_sum -= ifaceBand->in->floor;
4372 4373 4374 4375
        /* return class ID */
        ignore_value(virBitmapClearBit(net->class_id,
                                       iface->data.network.actual->class_id));
        /* update status file */
4376
        if (virNetworkSaveStatus(driverState->stateDir, net) < 0) {
4377
            net->floor_sum += ifaceBand->in->floor;
4378 4379 4380 4381
            ignore_value(virBitmapSetBit(net->class_id,
                                         iface->data.network.actual->class_id));
            goto cleanup;
        }
4382 4383 4384 4385 4386 4387 4388 4389 4390 4391
        /* update rate for non guaranteed NICs */
        new_rate -= net->floor_sum;
        if (virNetDevBandwidthUpdateRate(net->def->bridge, "1:2",
                                         net->def->bandwidth, new_rate) < 0)
            VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
                     net->def->bridge);
        /* no class is associated any longer */
        iface->data.network.actual->class_id = 0;
    }

4392
 cleanup:
4393 4394
    return ret;
}
4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409

static void
networkNetworkObjTaint(virNetworkObjPtr net,
                       enum virNetworkTaintFlags taint)
{
    if (virNetworkObjTaint(net, taint)) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(net->def->uuid, uuidstr);

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
                 net->def->name,
                 uuidstr,
                 virNetworkTaintTypeToString(taint));
    }
}