bridge_driver.c 146.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
    virNetworkDNSDefPtr dns = &network->def->dns;
G
Gene Czarcinski 已提交
744 745
    virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
    bool ipv6SLAAC;
746

747 748
    *configstr = NULL;

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

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

763 764
    /* create dnsmasq config file appropriate for this network */
    virBufferAsprintf(&configbuf,
765 766 767 768 769 770 771
                      "##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"
772
                      "strict-order\n",
773 774
                      network->def->name);

775 776 777 778 779 780 781 782
    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]);
        }
    }

783
    if (network->def->domain) {
784
        virBufferAsprintf(&configbuf,
785 786 787 788
                          "domain=%s\n"
                          "expand-hosts\n",
                          network->def->domain);
    }
789

790 791
    if (network->def->dns.forwardPlainNames
        == VIR_NETWORK_DNS_FORWARD_PLAIN_NAMES_NO) {
792 793 794 795
        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)
796
         */
797
        virBufferAddLit(&configbuf, "local=//\n");
798
    }
799

800
    if (pidfile)
801
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
802

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

806 807 808 809 810 811 812 813
    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.
         */
814
        virBufferAsprintf(&configbuf,
815 816 817
                          "bind-dynamic\n"
                          "interface=%s\n",
                          network->def->bridge);
818
    } else {
819
        virBufferAddLit(&configbuf, "bind-interfaces\n");
820 821 822 823 824 825 826 827
        /*
         * --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
         */
828 829 830
        for (i = 0;
             (tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
             i++) {
831 832 833 834
            char *ipaddr = virSocketAddrFormat(&tmpipdef->address);

            if (!ipaddr)
                goto cleanup;
835

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

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
846
                                 "The version of dnsmasq on this host (%d.%d) "
847 848 849 850
                                 "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 "
851 852 853 854 855 856
                                 "(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);
857 858
                goto cleanup;
            }
859
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
860 861 862
            VIR_FREE(ipaddr);
        }
    }
863

864 865
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
866
     * guaranteed to not work, and set no-resolv so that no dns
867 868 869
     * 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).
870
     */
871
    if (network->def->forward.type == VIR_NETWORK_FORWARD_NONE) {
872
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
873
                        "no-resolv\n");
874
    }
875

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

882
    for (i = 0; i < dns->nsrvs; i++) {
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
        /* service/protocol are required, and should have been validated
         * by the parser.
         */
        if (!dns->srvs[i].service) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing required 'service' "
                             "attribute in SRV record of network '%s'"),
                           network->def->name);
            goto cleanup;
        }
        if (!dns->srvs[i].protocol) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing required 'service' "
                             "attribute in SRV record of network '%s'"),
                           network->def->name);
            goto cleanup;
        }
        /* RFC2782 requires that service and protocol be preceded by
         * an underscore.
         */
        virBufferAsprintf(&configbuf, "srv-host=_%s._%s",
                          dns->srvs[i].service, dns->srvs[i].protocol);
905

906 907 908
        /* domain is optional - it defaults to the domain of this network */
        if (dns->srvs[i].domain)
            virBufferAsprintf(&configbuf, ".%s", dns->srvs[i].domain);
909

910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
        /* If target is empty or ".", that means "the service is
         * decidedly not available at this domain" (RFC2782). In that
         * case, any port, priority, or weight is irrelevant.
         */
        if (dns->srvs[i].target && STRNEQ(dns->srvs[i].target, ".")) {

            virBufferAsprintf(&configbuf, ",%s", dns->srvs[i].target);
            /* port, priority, and weight are optional, but are
             * identified by their position in the line. If an item is
             * unspecified, but something later in the line *is*
             * specified, we need to give the default value for the
             * unspecified item. (According to the dnsmasq manpage,
             * the default for port is 1).
             */
            if (dns->srvs[i].port ||
                dns->srvs[i].priority || dns->srvs[i].weight)
                virBufferAsprintf(&configbuf, ",%d",
                                  dns->srvs[i].port ? dns->srvs[i].port : 1);
            if (dns->srvs[i].priority || dns->srvs[i].weight)
                virBufferAsprintf(&configbuf, ",%d", dns->srvs[i].priority);
            if (dns->srvs[i].weight)
                virBufferAsprintf(&configbuf, ",%d", dns->srvs[i].weight);
932
        }
933
        virBufferAddLit(&configbuf, "\n");
934 935
    }

G
Gene Czarcinski 已提交
936
    /* Find the first dhcp for both IPv4 and IPv6 */
937 938 939
    for (i = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
         i++) {
G
Gene Czarcinski 已提交
940 941 942 943
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
944 945
                                   _("For IPv4, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
946 947 948 949 950 951 952 953 954 955 956
                    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,
957 958 959 960 961 962 963 964 965
                                   _("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 已提交
966 967 968 969
                    goto cleanup;
                }
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
970 971
                                   _("For IPv6, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
972 973 974 975 976 977 978 979 980 981 982 983 984
                    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 "
985 986 987 988
                 "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 已提交
989 990 991 992 993
    }

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
994
        for (r = 0; r < ipdef->nranges; r++) {
995
            char *saddr = virSocketAddrFormat(&ipdef->ranges[r].start);
996 997
            if (!saddr)
                goto cleanup;
998
            char *eaddr = virSocketAddrFormat(&ipdef->ranges[r].end);
999 1000 1001 1002
            if (!eaddr) {
                VIR_FREE(saddr);
                goto cleanup;
            }
1003
            virBufferAsprintf(&configbuf, "dhcp-range=%s,%s\n",
1004
                              saddr, eaddr);
1005
            VIR_FREE(saddr);
1006
            VIR_FREE(eaddr);
1007 1008
            nbleases += virSocketAddrGetRange(&ipdef->ranges[r].start,
                                              &ipdef->ranges[r].end);
1009
        }
1010

1011
        /*
1012 1013 1014 1015
         * 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)
1016 1017
         */
        if (!ipdef->nranges && ipdef->nhosts) {
1018
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
1019 1020
            if (!bridgeaddr)
                goto cleanup;
1021
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static\n", bridgeaddr);
1022 1023
            VIR_FREE(bridgeaddr);
        }
1024

G
Gene Czarcinski 已提交
1025 1026
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1027

G
Gene Czarcinski 已提交
1028 1029 1030
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts)
1031
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1032

G
Gene Czarcinski 已提交
1033
            if (ipdef->tftproot) {
1034 1035
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1036
            }
1037

G
Gene Czarcinski 已提交
1038 1039 1040
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1041

1042
                    if (!bootserver)
G
Gene Czarcinski 已提交
1043
                        goto cleanup;
1044
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1045
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1046 1047
                    VIR_FREE(bootserver);
                } else {
1048
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1049 1050 1051 1052 1053
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1054

G
Gene Czarcinski 已提交
1055 1056
    if (nbleases > 0) {
        char *leasefile = networkDnsmasqLeaseFileName(network->def->name);
1057
        if (!leasefile)
G
Gene Czarcinski 已提交
1058
            goto cleanup;
1059
        virBufferAsprintf(&configbuf, "dhcp-leasefile=%s\n", leasefile);
G
Gene Czarcinski 已提交
1060
        VIR_FREE(leasefile);
1061
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
G
Gene Czarcinski 已提交
1062
    }
1063

G
Gene Czarcinski 已提交
1064 1065
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1066
        goto cleanup;
G
Gene Czarcinski 已提交
1067 1068 1069 1070 1071 1072

    /* 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)
1073 1074
        virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n",
                          dctx->hostsfile->path);
G
Gene Czarcinski 已提交
1075

1076 1077
    /* Likewise, always create this file and put it on the
     * commandline, to allow for runtime additions.
G
Gene Czarcinski 已提交
1078
     */
1079
    virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
1080
                      dctx->addnhostsfile->path);
G
Gene Czarcinski 已提交
1081 1082 1083 1084

    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
        if (ipv6def)
1085
            virBufferAddLit(&configbuf, "enable-ra\n");
G
Gene Czarcinski 已提交
1086
        else {
1087 1088 1089
            for (i = 0;
                 (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
                 i++) {
G
Gene Czarcinski 已提交
1090 1091 1092 1093
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1094 1095
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1096 1097
                    VIR_FREE(bridgeaddr);
                }
1098
            }
1099
        }
1100 1101
    }

1102 1103 1104
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1105
    ret = 0;
G
Gene Czarcinski 已提交
1106

1107
 cleanup:
1108
    virBufferFreeAndReset(&configbuf);
1109
    return ret;
1110 1111
}

1112
/* build the dnsmasq command line */
1113 1114 1115
static int ATTRIBUTE_NONNULL(2)
networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
                                  virCommandPtr *cmdout,
1116 1117
                                  char *pidfile, dnsmasqContext *dctx,
                                  dnsmasqCapsPtr caps)
1118
{
1119
    virCommandPtr cmd = NULL;
G
Gene Czarcinski 已提交
1120
    int ret = -1;
1121 1122
    char *configfile = NULL;
    char *configstr = NULL;
1123 1124

    network->dnsmasqPid = -1;
1125

1126 1127 1128 1129 1130 1131
    if (networkDnsmasqConfContents(network, pidfile, &configstr, dctx, caps) < 0)
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1132
    if (!(configfile = networkDnsmasqConfigFileName(network->def->name)))
1133 1134 1135 1136 1137 1138 1139
        goto cleanup;

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

1143 1144
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(caps));
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1145
    *cmdout = cmd;
1146
    ret = 0;
1147
 cleanup:
1148 1149
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1150 1151 1152 1153
    return ret;
}

static int
1154
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1155
                       virNetworkObjPtr network)
1156 1157 1158 1159
{
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
    int ret = -1;
1160
    dnsmasqContext *dctx = NULL;
1161

1162
    if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) {
G
Gene Czarcinski 已提交
1163
        /* no IP addresses, so we don't need to run */
1164 1165 1166 1167
        ret = 0;
        goto cleanup;
    }

1168
    if (virFileMakePath(driverState->pidDir) < 0) {
1169
        virReportSystemError(errno,
1170
                             _("cannot create directory %s"),
1171
                             driverState->pidDir);
1172
        goto cleanup;
1173
    }
1174
    if (virFileMakePath(driverState->stateDir) < 0) {
1175
        virReportSystemError(errno,
1176
                             _("cannot create directory %s"),
1177
                             driverState->stateDir);
1178
        goto cleanup;
1179 1180
    }

1181
    if (!(pidfile = virPidFileBuildPath(driverState->pidDir,
1182
                                        network->def->name)))
1183
        goto cleanup;
1184

1185
    if (virFileMakePath(driverState->dnsmasqStateDir) < 0) {
1186
        virReportSystemError(errno,
1187
                             _("cannot create directory %s"),
1188
                             driverState->dnsmasqStateDir);
1189 1190 1191
        goto cleanup;
    }

1192
    dctx = dnsmasqContextNew(network->def->name, driverState->dnsmasqStateDir);
1193 1194 1195
    if (dctx == NULL)
        goto cleanup;

1196 1197
    if (dnsmasqCapsRefresh(&driver->dnsmasqCaps, NULL) < 0)
        goto cleanup;
1198 1199 1200

    ret = networkBuildDhcpDaemonCommandLine(network, &cmd, pidfile,
                                            dctx, driver->dnsmasqCaps);
1201 1202 1203 1204 1205
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1206
        goto cleanup;
1207

G
Guido Günther 已提交
1208 1209
    ret = virCommandRun(cmd, NULL);
    if (ret < 0) {
1210
        goto cleanup;
G
Guido Günther 已提交
1211
    }
1212 1213

    /*
1214 1215 1216 1217 1218
     * 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
1219 1220
     */

1221
    ret = virPidFileRead(driverState->pidDir, network->def->name,
1222 1223
                         &network->dnsmasqPid);
    if (ret < 0)
1224
        goto cleanup;
1225

1226
    ret = 0;
1227
 cleanup:
1228
    VIR_FREE(pidfile);
1229
    virCommandFree(cmd);
1230
    dnsmasqContextFree(dctx);
1231 1232 1233
    return ret;
}

1234 1235
/* networkRefreshDhcpDaemon:
 *  Update dnsmasq config files, then send a SIGHUP so that it rereads
G
Gene Czarcinski 已提交
1236 1237
 *  them.   This only works for the dhcp-hostsfile and the
 *  addn-hosts file.
1238 1239 1240
 *
 *  Returns 0 on success, -1 on failure.
 */
1241
static int
1242
networkRefreshDhcpDaemon(virNetworkDriverStatePtr driver,
1243
                         virNetworkObjPtr network)
1244
{
1245 1246
    int ret = -1;
    size_t i;
G
Gene Czarcinski 已提交
1247
    virNetworkIpDefPtr ipdef, ipv4def, ipv6def;
1248
    dnsmasqContext *dctx = NULL;
1249

G
Gene Czarcinski 已提交
1250
    /* if no IP addresses specified, nothing to do */
1251
    if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1252 1253
        return 0;

1254 1255
    /* if there's no running dnsmasq, just start it */
    if (network->dnsmasqPid <= 0 || (kill(network->dnsmasqPid, 0) < 0))
1256
        return networkStartDhcpDaemon(driver, network);
1257

G
Gene Czarcinski 已提交
1258
    VIR_INFO("Refreshing dnsmasq for network %s", network->def->bridge);
1259 1260
    if (!(dctx = dnsmasqContextNew(network->def->name,
                                   driverState->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1261
        goto cleanup;
1262
    }
G
Gene Czarcinski 已提交
1263 1264 1265 1266 1267 1268

    /* 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;
1269 1270 1271
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
         i++) {
G
Gene Czarcinski 已提交
1272 1273
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1274 1275
    }

G
Gene Czarcinski 已提交
1276
    ipv6def = NULL;
1277 1278 1279
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
G
Gene Czarcinski 已提交
1280 1281
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1282 1283
    }

G
Gene Czarcinski 已提交
1284 1285 1286 1287 1288
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
           goto cleanup;

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

G
Gene Czarcinski 已提交
1290
    if (networkBuildDnsmasqHostsList(dctx, &network->def->dns) < 0)
1291 1292 1293
       goto cleanup;

    if ((ret = dnsmasqSave(dctx)) < 0)
1294
        goto cleanup;
1295 1296

    ret = kill(network->dnsmasqPid, SIGHUP);
1297
 cleanup:
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
    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
1310
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1311
                         virNetworkObjPtr network)
1312 1313 1314 1315 1316 1317
{
    /* if there is a running dnsmasq, kill it */
    if (network->dnsmasqPid > 0) {
        networkKillDaemon(network->dnsmasqPid, "dnsmasq",
                          network->def->name);
        network->dnsmasqPid = -1;
1318
    }
1319
    /* now start dnsmasq if it should be started */
1320
    return networkStartDhcpDaemon(driver, network);
1321 1322
}

G
Gene Czarcinski 已提交
1323 1324 1325 1326 1327 1328
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";

1329 1330 1331
static int
networkRadvdConfContents(virNetworkObjPtr network, char **configstr)
{
E
Eric Blake 已提交
1332
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1333 1334
    int ret = -1;
    size_t i;
1335
    virNetworkIpDefPtr ipdef;
G
Gene Czarcinski 已提交
1336
    bool v6present = false, dhcp6 = false;
1337 1338

    *configstr = NULL;
1339

G
Gene Czarcinski 已提交
1340
    /* Check if DHCPv6 is needed */
1341 1342 1343
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
G
Gene Czarcinski 已提交
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356
        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;
    }

1357 1358 1359
    /* create radvd config file appropriate for this network;
     * IgnoreIfMissing allows radvd to start even when the bridge is down
     */
1360
    virBufferAsprintf(&configbuf, "interface %s\n"
1361 1362
                      "{\n"
                      "  AdvSendAdvert on;\n"
1363
                      "  IgnoreIfMissing on;\n"
G
Gene Czarcinski 已提交
1364 1365 1366 1367 1368
                      "  AdvManagedFlag %s;\n"
                      "%s",
                      network->def->bridge,
                      dhcp6 ? "on" : "off",
                      dhcp6 ? "\n" : radvd1);
1369 1370

    /* add a section for each IPv6 address in the config */
1371 1372 1373
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
1374 1375 1376 1377 1378
        int prefix;
        char *netaddr;

        prefix = virNetworkIpDefPrefix(ipdef);
        if (prefix < 0) {
1379 1380 1381
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
                           network->def->bridge);
1382 1383
            goto cleanup;
        }
1384
        if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
1385
            goto cleanup;
1386
        virBufferAsprintf(&configbuf,
1387
                          "  prefix %s/%d\n"
G
Gene Czarcinski 已提交
1388 1389 1390
                          "  {\n%s  };\n",
                          netaddr, prefix,
                          dhcp6 ? radvd2 : radvd3);
1391 1392 1393
        VIR_FREE(netaddr);
    }

1394 1395 1396
    /* only create the string if we found at least one IPv6 address */
    if (v6present) {
        virBufferAddLit(&configbuf, "};\n");
1397

1398 1399 1400 1401 1402 1403 1404 1405
        if (virBufferError(&configbuf)) {
            virReportOOMError();
            goto cleanup;
        }
        if (!(*configstr = virBufferContentAndReset(&configbuf))) {
            virReportOOMError();
            goto cleanup;
        }
1406
    }
1407 1408

    ret = 0;
1409
 cleanup:
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
    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;
1432 1433 1434 1435
        goto cleanup;
    }

    /* construct the filename */
1436
    if (!(*configFile = networkRadvdConfigFileName(network->def->name)))
1437 1438
        goto cleanup;
    /* write the file */
1439
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1440 1441
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1442 1443 1444 1445 1446
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1447
 cleanup:
1448 1449 1450 1451 1452 1453
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

static int
1454
networkStartRadvd(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
G
Gene Czarcinski 已提交
1455
                        virNetworkObjPtr network)
1456 1457 1458 1459 1460 1461 1462 1463 1464
{
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

    network->radvdPid = -1;

G
Gene Czarcinski 已提交
1465
    /* Is dnsmasq handling RA? */
1466
   if (DNSMASQ_RA_SUPPORT(driver->dnsmasqCaps)) {
G
Gene Czarcinski 已提交
1467 1468 1469 1470
        ret = 0;
        goto cleanup;
    }

1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
    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);
1482 1483 1484
        goto cleanup;
    }

1485
    if (virFileMakePath(driverState->pidDir) < 0) {
1486 1487
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1488
                             driverState->pidDir);
1489 1490
        goto cleanup;
    }
1491
    if (virFileMakePath(driverState->radvdStateDir) < 0) {
1492 1493
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1494
                             driverState->radvdStateDir);
1495 1496 1497 1498
        goto cleanup;
    }

    /* construct pidfile name */
1499
    if (!(radvdpidbase = networkRadvdPidfileBasename(network->def->name)))
1500
        goto cleanup;
1501
    if (!(pidfile = virPidFileBuildPath(driverState->pidDir, radvdpidbase)))
1502 1503 1504 1505 1506
        goto cleanup;

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

1507 1508 1509 1510
    /* 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
1511
     * virPidFileRead() below will fail if we use them).
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
     * 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;

1527
    if (virPidFileRead(driverState->pidDir, radvdpidbase, &network->radvdPid) < 0)
1528 1529 1530
        goto cleanup;

    ret = 0;
1531
 cleanup:
1532 1533 1534 1535 1536 1537 1538
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

1539
static int
1540
networkRefreshRadvd(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
1541
                    virNetworkObjPtr network)
1542
{
G
Gene Czarcinski 已提交
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
    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)) {
1554
            virPidFileDelete(driverState->pidDir, radvdpidbase);
G
Gene Czarcinski 已提交
1555 1556 1557 1558 1559 1560
            VIR_FREE(radvdpidbase);
        }
        network->radvdPid = -1;
        return 0;
    }

1561 1562
    /* if there's no running radvd, just start it */
    if (network->radvdPid <= 0 || (kill(network->radvdPid, 0) < 0))
G
Gene Czarcinski 已提交
1563
        return networkStartRadvd(driver, network);
1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575

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

1576 1577
#if 0
/* currently unused, so it causes a build error unless we #if it out */
1578
static int
1579
networkRestartRadvd(virNetworkDriverStatePtr driver,
1580
                    virNetworkObjPtr network)
1581 1582 1583 1584 1585 1586 1587 1588 1589
{
    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 已提交
1590
        if ((networkKillDaemon(network->radvdPid, "radvd",
1591 1592 1593
                               network->def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
             != NULL)) {
1594
            virPidFileDelete(driverState->pidDir, radvdpidbase);
1595 1596 1597 1598 1599 1600 1601 1602 1603
            VIR_FREE(radvdpidbase);
        }
        network->radvdPid = -1;
    }
    /* now start radvd if it should be started */
    return networkStartRadvd(network);
}
#endif /* #if 0 */

1604 1605 1606 1607
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
1608
networkRefreshDaemons(virNetworkDriverStatePtr driver)
1609
{
1610
    size_t i;
1611 1612 1613

    VIR_INFO("Refreshing network daemons");

1614
    for (i = 0; i < driver->networks.count; i++) {
1615 1616 1617 1618
        virNetworkObjPtr network = driver->networks.objs[i];

        virNetworkObjLock(network);
        if (virNetworkObjIsActive(network) &&
1619 1620 1621
            ((network->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
             (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
             (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
1622 1623 1624 1625 1626 1627
            /* 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.
             */
1628 1629
            networkRefreshDhcpDaemon(driver, network);
            networkRefreshRadvd(driver, network);
1630 1631 1632 1633 1634
        }
        virNetworkObjUnlock(network);
    }
}

1635
static void
1636
networkReloadFirewallRules(virNetworkDriverStatePtr driver)
1637
{
1638
    size_t i;
1639

1640
    VIR_INFO("Reloading iptables rules");
1641

1642
    for (i = 0; i < driver->networks.count; i++) {
1643 1644 1645 1646
        virNetworkObjPtr network = driver->networks.objs[i];

        virNetworkObjLock(network);
        if (virNetworkObjIsActive(network) &&
1647 1648 1649
            ((network->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
             (network->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
             (network->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
1650 1651 1652
            /* Only the three L3 network types that are configured by libvirt
             * need to have iptables rules reloaded.
             */
1653 1654
            networkRemoveFirewallRules(network->def);
            if (networkAddFirewallRules(network->def) < 0) {
1655 1656
                /* failed to add but already logged */
            }
1657
        }
1658
        virNetworkObjUnlock(network);
1659 1660 1661
    }
}

1662
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
1663
static int
1664
networkEnableIpForwarding(bool enableIPv4, bool enableIPv6)
1665
{
1666
    int ret = 0;
1667 1668 1669 1670 1671 1672 1673 1674 1675
#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
1676 1677 1678 1679
    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);
1680
#endif
1681
    return ret;
1682 1683
}

1684 1685
#define SYSCTL_PATH "/proc/sys"

1686 1687
static int
networkSetIPv6Sysctls(virNetworkObjPtr network)
1688 1689 1690 1691
{
    char *field = NULL;
    int ret = -1;

1692 1693 1694 1695 1696
    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",
1697
                        network->def->bridge) < 0)
1698
            goto cleanup;
1699

1700 1701 1702 1703 1704 1705
        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;
        }
1706

1707 1708 1709 1710 1711 1712 1713
        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);
1714 1715
    }

1716 1717 1718 1719 1720 1721 1722 1723
    /* 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",
1724
                    network->def->bridge) < 0)
1725 1726
        goto cleanup;

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

1734 1735 1736 1737
    /* 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",
1738
                    network->def->bridge) < 0)
1739 1740
        goto cleanup;

1741
    if (virFileWriteStr(field, "0", 0) < 0) {
1742
        virReportSystemError(errno,
1743
                             _("cannot disable %s"), field);
1744 1745 1746 1747
        goto cleanup;
    }

    ret = 0;
1748
 cleanup:
1749 1750 1751 1752
    VIR_FREE(field);
    return ret;
}

1753
/* add an IP address to a bridge */
1754
static int
D
Daniel P. Berrange 已提交
1755
networkAddAddrToBridge(virNetworkObjPtr network,
1756
                       virNetworkIpDefPtr ipdef)
1757
{
1758 1759 1760
    int prefix = virNetworkIpDefPrefix(ipdef);

    if (prefix < 0) {
1761 1762 1763
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
                       network->def->bridge);
1764 1765 1766
        return -1;
    }

1767 1768
    if (virNetDevSetIPv4Address(network->def->bridge,
                                &ipdef->address, prefix) < 0)
1769 1770 1771 1772 1773
        return -1;

    return 0;
}

1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786
/* 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,
1787
                                    (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)
1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822
                                     ? "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;
}

1823
static int
1824
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
1825 1826
                          virNetworkObjPtr network)
{
1827
    size_t i;
1828
    bool v4present = false, v6present = false;
1829 1830
    virErrorPtr save_err = NULL;
    virNetworkIpDefPtr ipdef;
1831
    virNetworkRouteDefPtr routedef;
1832
    char *macTapIfName = NULL;
1833
    int tapfd = -1;
1834

1835
    /* Check to see if any network IP collides with an existing route */
1836
    if (networkCheckRouteCollision(network->def) < 0)
1837 1838
        return -1;

1839
    /* Create and configure the bridge device */
1840
    if (virNetDevBridgeCreate(network->def->bridge) < 0)
1841 1842
        return -1;

1843 1844 1845 1846 1847 1848 1849 1850
    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);
1851
        if (!macTapIfName)
1852
            goto err0;
1853
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
1854
        if (virNetDevTapCreateInBridgePort(network->def->bridge,
1855
                                           &macTapIfName, &network->def->mac,
1856
                                           NULL, &tapfd, 1, NULL, NULL,
1857 1858 1859
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
1860 1861 1862 1863 1864
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

1865
    /* Set bridge options */
1866 1867 1868 1869

    /* delay is configured in seconds, but virNetDevBridgeSetSTPDelay
     * expects milliseconds
     */
1870
    if (virNetDevBridgeSetSTPDelay(network->def->bridge,
1871
                                   network->def->delay * 1000) < 0)
1872
        goto err1;
1873

1874
    if (virNetDevBridgeSetSTP(network->def->bridge,
1875
                              network->def->stp ? true : false) < 0)
1876
        goto err1;
1877

1878 1879 1880 1881
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
    if (networkSetIPv6Sysctls(network) < 0)
1882
        goto err1;
1883

1884
    /* Add "once per network" rules */
1885
    if (networkAddFirewallRules(network->def) < 0)
1886 1887
        goto err1;

1888 1889 1890
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
         i++) {
1891
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
1892
            v4present = true;
1893
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1894
            v6present = true;
1895

1896
        /* Add the IP address/netmask to the bridge */
D
Daniel P. Berrange 已提交
1897
        if (networkAddAddrToBridge(network, ipdef) < 0) {
1898
            goto err2;
1899
        }
1900 1901
    }

1902
    /* Bring up the bridge interface */
1903
    if (virNetDevSetOnline(network->def->bridge, 1) < 0)
1904
        goto err2;
1905

1906 1907
    for (i = 0; i < network->def->nroutes; i++) {
        routedef = &network->def->routes[i];
1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918
        /* 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 */
            }
        }
    }

1919 1920
    /* If forward.type != NONE, turn on global IP forwarding */
    if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE &&
1921
        networkEnableIpForwarding(v4present, v6present) < 0) {
1922
        virReportSystemError(errno, "%s",
1923
                             _("failed to enable IP forwarding"));
1924
        goto err3;
1925 1926
    }

1927

1928
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
1929 1930
    if ((v4present || v6present) &&
        networkStartDhcpDaemon(driver, network) < 0)
1931
        goto err3;
1932

1933
    /* start radvd if there are any ipv6 addresses */
G
Gene Czarcinski 已提交
1934
    if (v6present && networkStartRadvd(driver, network) < 0)
1935 1936
        goto err4;

1937 1938 1939 1940 1941 1942 1943 1944 1945
    /* 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);
    }

1946 1947
    if (virNetDevBandwidthSet(network->def->bridge,
                              network->def->bandwidth, true) < 0) {
1948 1949 1950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot set bandwidth limits on %s"),
                       network->def->bridge);
1951 1952 1953
        goto err5;
    }

1954
    VIR_FREE(macTapIfName);
1955 1956 1957

    return 0;

1958
 err5:
1959
    virNetDevBandwidthClear(network->def->bridge);
1960

1961 1962 1963 1964
 err4:
    if (!save_err)
        save_err = virSaveLastError();

1965 1966 1967 1968 1969
    if (network->dnsmasqPid > 0) {
        kill(network->dnsmasqPid, SIGTERM);
        network->dnsmasqPid = -1;
    }

1970 1971 1972
 err3:
    if (!save_err)
        save_err = virSaveLastError();
1973
    ignore_value(virNetDevSetOnline(network->def->bridge, 0));
1974

1975 1976 1977
 err2:
    if (!save_err)
        save_err = virSaveLastError();
1978
    networkRemoveFirewallRules(network->def);
1979 1980

 err1:
1981 1982 1983
    if (!save_err)
        save_err = virSaveLastError();

H
Hu Tao 已提交
1984
    if (macTapIfName) {
1985
        VIR_FORCE_CLOSE(tapfd);
H
Hu Tao 已提交
1986 1987 1988
        ignore_value(virNetDevTapDelete(macTapIfName));
        VIR_FREE(macTapIfName);
    }
1989 1990

 err0:
1991 1992
    if (!save_err)
        save_err = virSaveLastError();
1993
    ignore_value(virNetDevBridgeDelete(network->def->bridge));
1994

1995 1996 1997 1998
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
1999
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2000 2001 2002
    return -1;
}

2003
static int networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
R
Roman Bogorodskiy 已提交
2004
                                         virNetworkObjPtr network)
2005
{
2006
    virNetDevBandwidthClear(network->def->bridge);
2007

2008 2009 2010 2011 2012
    if (network->radvdPid > 0) {
        char *radvdpidbase;

        kill(network->radvdPid, SIGTERM);
        /* attempt to delete the pidfile we created */
2013
        if ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))) {
2014
            virPidFileDelete(driverState->pidDir, radvdpidbase);
2015 2016 2017 2018
            VIR_FREE(radvdpidbase);
        }
    }

2019 2020 2021
    if (network->dnsmasqPid > 0)
        kill(network->dnsmasqPid, SIGTERM);

2022
    if (network->def->mac_specified) {
2023
        char *macTapIfName = networkBridgeDummyNicName(network->def->bridge);
2024
        if (macTapIfName) {
2025
            ignore_value(virNetDevTapDelete(macTapIfName));
2026 2027 2028 2029
            VIR_FREE(macTapIfName);
        }
    }

2030
    ignore_value(virNetDevSetOnline(network->def->bridge, 0));
2031

2032
    networkRemoveFirewallRules(network->def);
2033

2034
    ignore_value(virNetDevBridgeDelete(network->def->bridge));
2035

2036
    /* See if its still alive and really really kill it */
2037
    if (network->dnsmasqPid > 0 &&
2038
        (kill(network->dnsmasqPid, 0) == 0))
2039 2040
        kill(network->dnsmasqPid, SIGKILL);
    network->dnsmasqPid = -1;
2041 2042 2043 2044 2045 2046

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

2047 2048 2049 2050
    return 0;
}

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

2062
static int networkShutdownNetworkExternal(virNetworkDriverStatePtr driver ATTRIBUTE_UNUSED,
2063 2064 2065
                                        virNetworkObjPtr network ATTRIBUTE_UNUSED)
{
    /* put anything here that needs to be done each time a network of
2066
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2067 2068 2069 2070 2071 2072 2073
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

static int
2074
networkStartNetwork(virNetworkDriverStatePtr driver,
2075 2076
                    virNetworkObjPtr network)
{
2077 2078 2079
    int ret = -1;

    VIR_DEBUG("driver=%p, network=%p", driver, network);
2080 2081

    if (virNetworkObjIsActive(network)) {
2082 2083
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2084
        return ret;
2085 2086
    }

2087 2088 2089
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2090
    if (virNetworkObjSetDefTransient(network, true) < 0)
2091
        goto cleanup;
2092

2093 2094
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2095
    if (networkRunHook(network, NULL, NULL,
2096 2097 2098 2099
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2100
    switch (network->def->forward.type) {
2101 2102 2103 2104

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2105 2106
        if (networkStartNetworkVirtual(driver, network) < 0)
            goto cleanup;
2107 2108 2109 2110 2111 2112
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2113
    case VIR_NETWORK_FORWARD_HOSTDEV:
2114 2115
        if (networkStartNetworkExternal(driver, network) < 0)
            goto cleanup;
2116 2117 2118
        break;
    }

2119
    /* finally we can call the 'started' hook script if any */
2120
    if (networkRunHook(network, NULL, NULL,
2121 2122 2123 2124
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2125 2126 2127
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2128 2129 2130
    VIR_DEBUG("Writing network status to disk");
    if (virNetworkSaveStatus(driverState->stateDir, network) < 0)
        goto cleanup;
2131 2132

    network->active = 1;
2133 2134
    VIR_INFO("Network '%s' started up", network->def->name);
    ret = 0;
2135

2136
 cleanup:
2137
    if (ret < 0) {
2138
        virNetworkObjUnsetDefTransient(network);
2139 2140 2141 2142 2143 2144 2145 2146 2147 2148
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
        networkShutdownNetwork(driver, network);
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2149
static int networkShutdownNetwork(virNetworkDriverStatePtr driver,
2150 2151 2152 2153 2154 2155 2156 2157 2158 2159
                                        virNetworkObjPtr network)
{
    int ret = 0;
    char *stateFile;

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

    if (!virNetworkObjIsActive(network))
        return 0;

2160 2161
    stateFile = virNetworkConfigFile(driverState->stateDir,
                                     network->def->name);
2162 2163 2164 2165 2166 2167
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2168
    switch (network->def->forward.type) {
2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179

    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:
2180
    case VIR_NETWORK_FORWARD_HOSTDEV:
2181 2182 2183 2184
        ret = networkShutdownNetworkExternal(driver, network);
        break;
    }

2185
    /* now that we know it's stopped call the hook if present */
2186
    networkRunHook(network, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2187 2188
                   VIR_HOOK_SUBOP_END);

2189
    network->active = 0;
2190
    virNetworkObjUnsetDefTransient(network);
2191
    return ret;
2192 2193 2194
}


2195
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
2196 2197
                                         const unsigned char *uuid)
{
2198
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2199 2200
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;
2201

2202
    networkDriverLock(driver);
2203
    network = virNetworkFindByUUID(&driver->networks, uuid);
2204
    networkDriverUnlock(driver);
2205
    if (!network) {
2206 2207
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
2208
        goto cleanup;
2209 2210
    }

2211 2212 2213
    if (virNetworkLookupByUUIDEnsureACL(conn, network->def) < 0)
        goto cleanup;

2214 2215
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2216
 cleanup:
2217 2218
    if (network)
        virNetworkObjUnlock(network);
2219
    return ret;
2220 2221
}

2222
static virNetworkPtr networkLookupByName(virConnectPtr conn,
2223 2224
                                         const char *name)
{
2225
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2226 2227 2228
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;

2229
    networkDriverLock(driver);
2230
    network = virNetworkFindByName(&driver->networks, name);
2231
    networkDriverUnlock(driver);
2232
    if (!network) {
2233 2234
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
2235
        goto cleanup;
2236 2237
    }

2238 2239 2240
    if (virNetworkLookupByNameEnsureACL(conn, network->def) < 0)
        goto cleanup;

2241 2242
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2243
 cleanup:
2244 2245
    if (network)
        virNetworkObjUnlock(network);
2246
    return ret;
2247 2248
}

2249 2250 2251
static virDrvOpenStatus networkOpen(virConnectPtr conn,
                                    virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                    unsigned int flags)
2252 2253 2254
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

2255 2256 2257 2258 2259 2260 2261
    if (!driverState)
        return VIR_DRV_OPEN_DECLINED;

    conn->networkPrivateData = driverState;
    return VIR_DRV_OPEN_SUCCESS;
}

2262 2263
static int networkClose(virConnectPtr conn)
{
2264 2265 2266 2267
    conn->networkPrivateData = NULL;
    return 0;
}

2268 2269
static int networkConnectNumOfNetworks(virConnectPtr conn)
{
2270 2271
    int nactive = 0;
    size_t i;
2272
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2273

2274 2275 2276
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

2277
    networkDriverLock(driver);
2278
    for (i = 0; i < driver->networks.count; i++) {
2279 2280 2281 2282
        virNetworkObjPtr obj = driver->networks.objs[i];
        virNetworkObjLock(obj);
        if (virConnectNumOfNetworksCheckACL(conn, obj->def) &&
            virNetworkObjIsActive(obj))
2283
            nactive++;
2284
        virNetworkObjUnlock(obj);
2285 2286
    }
    networkDriverUnlock(driver);
2287

2288 2289 2290
    return nactive;
}

2291
static int networkConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
2292
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2293 2294
    int got = 0;
    size_t i;
2295

2296 2297 2298
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

2299
    networkDriverLock(driver);
2300
    for (i = 0; i < driver->networks.count && got < nnames; i++) {
2301 2302 2303 2304 2305 2306
        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);
2307 2308 2309 2310
                goto cleanup;
            }
            got++;
        }
2311
        virNetworkObjUnlock(obj);
2312
    }
2313 2314
    networkDriverUnlock(driver);

2315 2316 2317
    return got;

 cleanup:
2318
    networkDriverUnlock(driver);
2319
    for (i = 0; i < got; i++)
2320 2321 2322 2323
        VIR_FREE(names[i]);
    return -1;
}

2324 2325
static int networkConnectNumOfDefinedNetworks(virConnectPtr conn)
{
2326 2327
    int ninactive = 0;
    size_t i;
2328
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2329

2330 2331 2332
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2333
    networkDriverLock(driver);
2334
    for (i = 0; i < driver->networks.count; i++) {
2335 2336 2337 2338
        virNetworkObjPtr obj = driver->networks.objs[i];
        virNetworkObjLock(obj);
        if (virConnectNumOfDefinedNetworksCheckACL(conn, obj->def) &&
            !virNetworkObjIsActive(obj))
2339
            ninactive++;
2340
        virNetworkObjUnlock(obj);
2341 2342
    }
    networkDriverUnlock(driver);
2343

2344 2345 2346
    return ninactive;
}

2347
static int networkConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
2348
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2349 2350
    int got = 0;
    size_t i;
2351

2352 2353 2354
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2355
    networkDriverLock(driver);
2356
    for (i = 0; i < driver->networks.count && got < nnames; i++) {
2357 2358 2359 2360 2361 2362
        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);
2363 2364 2365 2366
                goto cleanup;
            }
            got++;
        }
2367
        virNetworkObjUnlock(obj);
2368
    }
2369
    networkDriverUnlock(driver);
2370 2371 2372
    return got;

 cleanup:
2373
    networkDriverUnlock(driver);
2374
    for (i = 0; i < got; i++)
2375 2376 2377 2378
        VIR_FREE(names[i]);
    return -1;
}

2379
static int
2380 2381 2382
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
2383
{
2384
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2385 2386 2387 2388
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

2389 2390 2391
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

2392
    networkDriverLock(driver);
2393 2394 2395
    ret = virNetworkObjListExport(conn, driver->networks, nets,
                                  virConnectListAllNetworksCheckACL,
                                  flags);
2396 2397
    networkDriverUnlock(driver);

2398
 cleanup:
2399 2400
    return ret;
}
2401

2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416
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,
2417
                                       net, eventID, callback,
2418 2419 2420
                                       opaque, freecb, &ret) < 0)
        ret = -1;

2421
 cleanup:
2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
    return ret;
}

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

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

2435 2436 2437 2438 2439 2440
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;
2441

2442
 cleanup:
2443 2444 2445
    return ret;
}

2446 2447 2448 2449 2450
static int networkIsActive(virNetworkPtr net)
{
    virNetworkObjPtr obj;
    int ret = -1;

2451 2452
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
2453 2454 2455 2456

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

2457 2458
    ret = virNetworkObjIsActive(obj);

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

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

2470 2471
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
2472 2473 2474 2475

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

2476 2477
    ret = obj->persistent;

2478
 cleanup:
2479 2480 2481 2482 2483 2484
    if (obj)
        virNetworkObjUnlock(obj);
    return ret;
}


2485
static int
2486
networkValidate(virNetworkDriverStatePtr driver,
2487 2488
                virNetworkDefPtr def,
                bool check_active)
2489
{
2490
    size_t i;
2491 2492
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
2493
    virNetworkIpDefPtr ipdef;
G
Gene Czarcinski 已提交
2494
    bool ipv4def = false, ipv6def = false;
2495 2496 2497 2498 2499 2500 2501 2502

    /* 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
     */
2503 2504 2505
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
        def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
2506 2507 2508 2509 2510

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

        virNetworkSetBridgeMacAddr(def);
2511 2512
    } else {
        /* They are also the only types that currently support setting
2513 2514
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
2515
         */
2516 2517 2518 2519 2520 2521 2522 2523
        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;
        }
2524 2525 2526 2527 2528
        if (virNetworkDefGetIpByIndex(def, AF_UNSPEC, 0)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2529
                           virNetworkForwardTypeToString(def->forward.type));
2530 2531
            return -1;
        }
2532
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
2533 2534 2535 2536
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2537
                           virNetworkForwardTypeToString(def->forward.type));
2538 2539 2540 2541 2542 2543 2544
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2545
                           virNetworkForwardTypeToString(def->forward.type));
2546 2547
            return -1;
        }
2548 2549 2550 2551 2552 2553 2554 2555
        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;
        }
2556 2557
    }

G
Gene Czarcinski 已提交
2558 2559 2560
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
2561 2562 2563
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, i));
         i++) {
G
Gene Czarcinski 已提交
2564 2565 2566 2567 2568
        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 -- "
2569 2570
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587
                    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;
                }
2588 2589 2590
            }
        }
    }
2591 2592 2593 2594 2595 2596

    /* 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.
     */

2597
    vlanAllowed = ((def->forward.type == VIR_NETWORK_FORWARD_BRIDGE &&
2598
                   def->virtPortProfile &&
2599 2600 2601
                   def->virtPortProfile->virtPortType
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) ||
                   def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV);
2602 2603

    vlanUsed = def->vlan.nTags > 0;
2604 2605
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
2606 2607 2608 2609 2610
            /* 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.
             */
2611
            if (def->portGroups[i].virtPortProfile) {
2612
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
2613
                    def->portGroups[i].virtPortProfile->virtPortType
2614 2615 2616 2617 2618 2619 2620
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
2621
        }
2622
        if (def->portGroups[i].isDefault) {
2623 2624 2625 2626 2627
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
2628
                               def->name, defaultPortGroup->name,
2629
                               def->portGroups[i].name);
2630
                return -1;
2631
            }
2632
            defaultPortGroup = &def->portGroups[i];
2633
        }
2634
    }
2635 2636 2637 2638 2639 2640 2641
    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.
         */
2642 2643 2644 2645 2646 2647 2648 2649 2650
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
    return 0;
}

2651 2652
static virNetworkPtr networkCreateXML(virConnectPtr conn, const char *xml)
{
2653
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2654
    virNetworkDefPtr def;
2655
    virNetworkObjPtr network = NULL;
2656
    virNetworkPtr ret = NULL;
2657
    virObjectEventPtr event = NULL;
2658

2659 2660
    networkDriverLock(driver);

2661
    if (!(def = virNetworkDefParseString(xml)))
2662
        goto cleanup;
2663

2664 2665 2666
    if (virNetworkCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

2667
    if (networkValidate(driver, def, true) < 0)
2668 2669
       goto cleanup;

2670 2671 2672
    /* NB: even though this transient network hasn't yet been started,
     * we assign the def with live = true in anticipation that it will
     * be started momentarily.
2673
     */
2674
    if (!(network = virNetworkAssignDef(&driver->networks, def, true)))
2675 2676
        goto cleanup;
    def = NULL;
2677

2678
    if (networkStartNetwork(driver, network) < 0) {
2679 2680
        virNetworkRemoveInactive(&driver->networks,
                                 network);
2681
        network = NULL;
2682
        goto cleanup;
2683 2684
    }

2685 2686
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
2687 2688
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
2689

2690
    VIR_INFO("Creating network '%s'", network->def->name);
2691 2692
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2693
 cleanup:
2694
    virNetworkDefFree(def);
2695 2696
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
2697 2698 2699
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
2700
    return ret;
2701 2702
}

2703 2704
static virNetworkPtr networkDefineXML(virConnectPtr conn, const char *xml)
{
2705
    virNetworkDriverStatePtr driver = conn->networkPrivateData;
2706
    virNetworkDefPtr def = NULL;
2707
    bool freeDef = true;
2708
    virNetworkObjPtr network = NULL;
2709
    virNetworkPtr ret = NULL;
2710
    virObjectEventPtr event = NULL;
2711

2712 2713
    networkDriverLock(driver);

2714
    if (!(def = virNetworkDefParseString(xml)))
2715
        goto cleanup;
2716

2717 2718 2719
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

2720
    if (networkValidate(driver, def, false) < 0)
2721 2722
       goto cleanup;

2723 2724
    if (!(network = virNetworkAssignDef(&driver->networks, def, false)))
       goto cleanup;
2725

2726
    /* def was assigned to network object */
2727
    freeDef = false;
2728 2729

    if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
2730 2731 2732 2733 2734
        if (!virNetworkObjIsActive(network)) {
            virNetworkRemoveInactive(&driver->networks, network);
            network = NULL;
            goto cleanup;
        }
2735 2736 2737 2738 2739
        /* if network was active already, just undo new persistent
         * definition by making it transient.
         * XXX - this isn't necessarily the correct thing to do.
         */
        virNetworkObjAssignDef(network, NULL, false);
2740 2741 2742
        goto cleanup;
    }

2743
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
2744 2745
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
2746

2747 2748
    VIR_INFO("Defining network '%s'", def->name);
    ret = virGetNetwork(conn, def->name, def->uuid);
2749

2750
 cleanup:
2751 2752
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
2753 2754
    if (freeDef)
       virNetworkDefFree(def);
2755 2756 2757
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
2758
    return ret;
2759 2760
}

2761
static int
2762 2763
networkUndefine(virNetworkPtr net)
{
2764
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
2765
    virNetworkObjPtr network;
2766
    int ret = -1;
2767
    bool active = false;
2768
    virObjectEventPtr event = NULL;
2769

2770 2771
    networkDriverLock(driver);

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

2779 2780 2781
    if (virNetworkUndefineEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

2782 2783
    if (virNetworkObjIsActive(network))
        active = true;
2784

2785
    /* remove autostart link */
2786
    if (virNetworkDeleteConfig(driver->networkConfigDir,
2787 2788
                               driver->networkAutostartDir,
                               network) < 0)
2789
        goto cleanup;
2790
    network->autostart = 0;
2791

2792 2793
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
2794 2795
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
2796

2797
    VIR_INFO("Undefining network '%s'", network->def->name);
2798 2799 2800 2801 2802
    if (!active) {
        if (networkRemoveInactive(driver, network) < 0) {
            network = NULL;
            goto cleanup;
        }
2803
        network = NULL;
2804 2805 2806 2807 2808 2809
    } else {

        /* if the network still exists, it was active, and we need to make
         * it transient (by deleting the persistent def)
         */
        virNetworkObjAssignDef(network, NULL, false);
2810 2811
    }

2812
    ret = 0;
2813

2814
 cleanup:
2815 2816
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
2817 2818 2819
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
2820
    return ret;
2821 2822
}

2823 2824 2825 2826 2827 2828 2829 2830
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
2831
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
2832
    virNetworkObjPtr network = NULL;
2833 2834
    int isActive, ret = -1;
    size_t i;
2835 2836
    virNetworkIpDefPtr ipdef;
    bool oldDhcpActive = false;
2837
    bool needFirewallRefresh = false;
2838

2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852

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

2853 2854 2855
    if (virNetworkUpdateEnsureACL(net->conn, network->def, flags) < 0)
        goto cleanup;

2856
    /* see if we are listening for dhcp pre-modification */
2857 2858 2859
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
         i++) {
2860 2861 2862 2863 2864 2865
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

2866 2867 2868 2869
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
    */
    isActive = virNetworkObjIsActive(network);
2870 2871
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
2872 2873 2874 2875 2876 2877 2878
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895
    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).
                 */
2896
                networkRemoveFirewallRules(network->def);
2897 2898 2899 2900 2901 2902 2903 2904
                needFirewallRefresh = true;
                break;
            default:
                break;
            }
        }
    }

2905
    /* update the network config in memory/on disk */
2906 2907
    if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0) {
        if (needFirewallRefresh)
2908
            ignore_value(networkAddFirewallRules(network->def));
2909 2910 2911
        goto cleanup;
    }

2912
    if (needFirewallRefresh && networkAddFirewallRules(network->def) < 0)
2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935
        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.
             */
2936
            if (networkRestartDhcpDaemon(driver, network) < 0)
2937 2938
                goto cleanup;

2939 2940 2941 2942 2943 2944 2945 2946
        } 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;

2947 2948 2949
            for (i = 0;
                 (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
                 i++) {
2950 2951 2952 2953 2954 2955 2956
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
2957 2958
                 networkRestartDhcpDaemon(driver, network) < 0) ||
                networkRefreshDhcpDaemon(driver, network) < 0) {
2959 2960 2961 2962
                goto cleanup;
            }

        } else if (section == VIR_NETWORK_SECTION_DNS_HOST ||
2963 2964 2965 2966 2967 2968
                   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.
             */
2969
            if (networkRefreshDhcpDaemon(driver, network) < 0)
2970 2971 2972 2973 2974 2975 2976 2977
                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.
             */
2978
            if (networkRefreshRadvd(driver, network) < 0)
2979 2980 2981 2982
                goto cleanup;
        }

        /* save current network state to disk */
2983 2984
        if ((ret = virNetworkSaveStatus(driverState->stateDir,
                                        network)) < 0) {
2985
            goto cleanup;
2986
        }
2987 2988
    }
    ret = 0;
2989
 cleanup:
2990 2991 2992 2993 2994 2995
    if (network)
        virNetworkObjUnlock(network);
    networkDriverUnlock(driver);
    return ret;
}

2996 2997
static int networkCreate(virNetworkPtr net)
{
2998
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
2999 3000
    virNetworkObjPtr network;
    int ret = -1;
3001
    virObjectEventPtr event = NULL;
3002

3003
    networkDriverLock(driver);
3004
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
3005

3006
    if (!network) {
3007 3008
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
3009
        goto cleanup;
3010 3011
    }

3012 3013 3014
    if (virNetworkCreateEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3015
    ret = networkStartNetwork(driver, network);
3016

3017 3018
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3019 3020
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3021

3022
 cleanup:
3023 3024
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3025 3026
    if (network)
        virNetworkObjUnlock(network);
3027
    networkDriverUnlock(driver);
3028
    return ret;
3029 3030
}

3031 3032
static int networkDestroy(virNetworkPtr net)
{
3033
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
3034 3035
    virNetworkObjPtr network;
    int ret = -1;
3036
    virObjectEventPtr event = NULL;
3037

3038
    networkDriverLock(driver);
3039
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
3040

3041
    if (!network) {
3042 3043
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
3044
        goto cleanup;
3045 3046
    }

3047 3048 3049
    if (virNetworkDestroyEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3050
    if (!virNetworkObjIsActive(network)) {
3051 3052
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is not active"));
3053 3054 3055
        goto cleanup;
    }

3056 3057 3058
    if ((ret = networkShutdownNetwork(driver, network)) < 0)
        goto cleanup;

3059 3060
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3061 3062
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
3063

3064
    if (!network->persistent) {
3065 3066 3067 3068 3069
        if (networkRemoveInactive(driver, network) < 0) {
            network = NULL;
            ret = -1;
            goto cleanup;
        }
3070 3071
        network = NULL;
    }
3072

3073
 cleanup:
3074 3075
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3076 3077
    if (network)
        virNetworkObjUnlock(network);
3078
    networkDriverUnlock(driver);
3079 3080 3081
    return ret;
}

3082
static char *networkGetXMLDesc(virNetworkPtr net,
3083
                               unsigned int flags)
3084
{
3085
    virNetworkObjPtr network;
3086
    virNetworkDefPtr def;
3087
    char *ret = NULL;
3088

3089
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
3090

3091 3092
    if (!(network = networkObjFromNetwork(net)))
        return ret;
3093

3094 3095 3096
    if (virNetworkGetXMLDescEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3097 3098 3099 3100 3101 3102
    if ((flags & VIR_NETWORK_XML_INACTIVE) && network->newDef)
        def = network->newDef;
    else
        def = network->def;

    ret = virNetworkDefFormat(def, flags);
3103

3104
 cleanup:
3105 3106
    if (network)
        virNetworkObjUnlock(network);
3107
    return ret;
3108 3109 3110
}

static char *networkGetBridgeName(virNetworkPtr net) {
3111 3112 3113
    virNetworkObjPtr network;
    char *bridge = NULL;

3114 3115
    if (!(network = networkObjFromNetwork(net)))
        return bridge;
3116

3117 3118 3119
    if (virNetworkGetBridgeNameEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3120
    if (!(network->def->bridge)) {
3121 3122 3123
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
                       network->def->name);
3124 3125 3126
        goto cleanup;
    }

3127
    ignore_value(VIR_STRDUP(bridge, network->def->bridge));
3128

3129
 cleanup:
3130 3131
    if (network)
        virNetworkObjUnlock(network);
3132 3133 3134 3135
    return bridge;
}

static int networkGetAutostart(virNetworkPtr net,
3136 3137
                             int *autostart)
{
3138 3139
    virNetworkObjPtr network;
    int ret = -1;
3140

3141 3142
    if (!(network = networkObjFromNetwork(net)))
        return ret;
3143

3144 3145 3146
    if (virNetworkGetAutostartEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3147
    *autostart = network->autostart;
3148
    ret = 0;
3149

3150
 cleanup:
3151 3152
    if (network)
        virNetworkObjUnlock(network);
3153
    return ret;
3154 3155 3156
}

static int networkSetAutostart(virNetworkPtr net,
3157 3158
                               int autostart)
{
3159
    virNetworkDriverStatePtr driver = net->conn->networkPrivateData;
3160
    virNetworkObjPtr network;
3161
    char *configFile = NULL, *autostartLink = NULL;
3162
    int ret = -1;
3163

3164
    networkDriverLock(driver);
3165
    network = virNetworkFindByUUID(&driver->networks, net->uuid);
3166

3167
    if (!network) {
3168 3169
        virReportError(VIR_ERR_NO_NETWORK,
                       "%s", _("no network with matching uuid"));
3170
        goto cleanup;
3171 3172
    }

3173 3174 3175
    if (virNetworkSetAutostartEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3176
    if (!network->persistent) {
3177 3178
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
3179 3180 3181
        goto cleanup;
    }

3182 3183
    autostart = (autostart != 0);

3184
    if (network->autostart != autostart) {
3185
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir, network->def->name)) == NULL)
3186
            goto cleanup;
3187
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, network->def->name)) == NULL)
3188 3189
            goto cleanup;

3190
        if (autostart) {
3191
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
3192
                virReportSystemError(errno,
3193 3194
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
3195 3196
                goto cleanup;
            }
3197

3198
            if (symlink(configFile, autostartLink) < 0) {
3199
                virReportSystemError(errno,
3200
                                     _("Failed to create symlink '%s' to '%s'"),
3201
                                     autostartLink, configFile);
3202 3203 3204
                goto cleanup;
            }
        } else {
3205
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
3206
                virReportSystemError(errno,
3207
                                     _("Failed to delete symlink '%s'"),
3208
                                     autostartLink);
3209 3210
                goto cleanup;
            }
3211 3212
        }

3213
        network->autostart = autostart;
3214
    }
3215
    ret = 0;
3216

3217
 cleanup:
3218 3219
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
3220 3221
    if (network)
        virNetworkObjUnlock(network);
3222
    networkDriverUnlock(driver);
3223
    return ret;
3224 3225 3226 3227 3228
}


static virNetworkDriver networkDriver = {
    "Network",
3229 3230 3231 3232 3233 3234 3235
    .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 */
3236 3237
    .connectNetworkEventRegisterAny = networkConnectNetworkEventRegisterAny, /* 1.2.1 */
    .connectNetworkEventDeregisterAny = networkConnectNetworkEventDeregisterAny, /* 1.2.1 */
3238 3239
    .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
    .networkLookupByName = networkLookupByName, /* 0.2.0 */
3240 3241
    .networkCreateXML = networkCreateXML, /* 0.2.0 */
    .networkDefineXML = networkDefineXML, /* 0.2.0 */
3242
    .networkUndefine = networkUndefine, /* 0.2.0 */
3243
    .networkUpdate = networkUpdate, /* 0.10.2 */
3244
    .networkCreate = networkCreate, /* 0.2.0 */
3245 3246 3247 3248 3249 3250 3251
    .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 */
3252 3253 3254
};

static virStateDriver networkStateDriver = {
3255
    .name = "Network",
3256
    .stateInitialize  = networkStateInitialize,
3257
    .stateAutoStart  = networkStateAutoStart,
3258 3259
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
3260 3261
};

3262 3263
int networkRegister(void)
{
3264 3265
    if (virRegisterNetworkDriver(&networkDriver) < 0)
        return -1;
3266 3267
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
3268 3269
    return 0;
}
3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280

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

/* 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.
 */

3281 3282 3283 3284 3285 3286
/* networkCreateInterfacePool:
 * @netdef: the original NetDef from the network
 *
 * Creates an implicit interface pool of VF's when a PF dev is given
 */
static int
3287 3288
networkCreateInterfacePool(virNetworkDefPtr netdef)
{
3289
    size_t num_virt_fns = 0;
3290
    char **vfname = NULL;
3291
    virPCIDeviceAddressPtr *virt_fns;
3292 3293
    int ret = -1;
    size_t i;
3294

3295
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev,
3296
                                      &vfname, &virt_fns, &num_virt_fns)) < 0) {
3297 3298
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get Virtual functions on %s"),
3299
                       netdef->forward.pfs->dev);
3300 3301 3302 3303 3304 3305
        goto finish;
    }

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

3310
    if (VIR_ALLOC_N(netdef->forward.ifs, num_virt_fns) < 0)
3311 3312
        goto finish;

3313
    netdef->forward.nifs = num_virt_fns;
3314

3315
    for (i = 0; i < netdef->forward.nifs; i++) {
3316 3317 3318 3319
        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)) {
3320 3321 3322
            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)
3323
                    goto finish;
3324
            } else {
3325
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3326
                               _("Direct mode types require interface names"));
3327 3328
                goto finish;
            }
3329
        }
3330
        else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
3331
            /* VF's are always PCI devices */
3332 3333 3334 3335 3336
            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;
3337
        }
3338 3339 3340
    }

    ret = 0;
3341
 finish:
3342 3343 3344
    for (i = 0; i < num_virt_fns; i++) {
        VIR_FREE(vfname[i]);
        VIR_FREE(virt_fns[i]);
3345
    }
3346
    VIR_FREE(vfname);
3347
    VIR_FREE(virt_fns);
3348 3349 3350
    return ret;
}

3351
/* networkAllocateActualDevice:
3352
 * @dom: domain definition that @iface belongs to
3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363
 * @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
3364 3365
networkAllocateActualDevice(virDomainDefPtr dom,
                            virDomainNetDefPtr iface)
3366
{
3367
    virNetworkDriverStatePtr driver = driverState;
3368 3369 3370
    enum virDomainNetType actualType = iface->type;
    virNetworkObjPtr network = NULL;
    virNetworkDefPtr netdef = NULL;
3371
    virNetDevBandwidthPtr bandwidth = NULL;
3372 3373 3374
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
3375
    virNetworkForwardIfDefPtr dev = NULL;
3376
    size_t i;
3377 3378 3379
    int ret = -1;

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
3380
        goto validate;
3381 3382 3383 3384 3385 3386 3387 3388

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

    networkDriverLock(driver);
    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
    networkDriverUnlock(driver);
    if (!network) {
3389 3390 3391
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
3392
        goto error;
3393 3394
    }
    netdef = network->def;
3395

3396 3397 3398
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

3399 3400 3401 3402 3403 3404 3405 3406 3407 3408
    /* 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.
     */
3409 3410 3411 3412 3413 3414

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

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

3419 3420 3421 3422 3423 3424 3425 3426
    /* 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;

3427 3428
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
3429

3430 3431 3432
    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE)) {
3433 3434 3435 3436
        /* for these forward types, the actual net type really *is*
         *NETWORK; we just keep the info from the portgroup in
         * iface->data.network.actual
        */
3437
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
3438 3439 3440 3441

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

3442
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
3443
               netdef->bridge) {
3444 3445 3446 3447 3448

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

3449
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
3450 3451
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
3452
            goto error;
3453

3454 3455 3456 3457 3458 3459 3460 3461
        /* 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) {
3462
            goto error;
3463 3464 3465 3466 3467 3468 3469 3470 3471 3472
        }
        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);
3473
                goto error;
3474 3475 3476
            }
        }

3477
    } else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
3478

3479
        virDomainHostdevSubsysPCIBackendType backend;
3480

3481
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
3482
        if (netdef->forward.npfs > 0 && netdef->forward.nifs <= 0 &&
3483 3484 3485 3486 3487
            networkCreateInterfacePool(netdef) < 0) {
            goto error;
        }

        /* pick first dev with 0 connections */
3488 3489 3490
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504
                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;
3505
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
3506
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
3507
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
3508

3509 3510 3511
        switch (netdef->forward.driverName)
        {
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
3512
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
3513 3514
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
3515
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
3516 3517
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
3518
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529
            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;

3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554
        /* 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;
            }
        }

3555 3556 3557 3558
    } 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)) {
3559 3560 3561 3562 3563 3564

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

        /* Set type=direct and appropriate <source mode='xxx'/> */
3565
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
3566
        switch (netdef->forward.type) {
3567
        case VIR_NETWORK_FORWARD_BRIDGE:
3568
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
3569 3570
            break;
        case VIR_NETWORK_FORWARD_PRIVATE:
3571
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
3572 3573
            break;
        case VIR_NETWORK_FORWARD_VEPA:
3574
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
3575 3576
            break;
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
3577
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PASSTHRU;
3578 3579 3580
            break;
        }

3581 3582 3583 3584 3585 3586 3587 3588
        /* 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) {
3589
            goto error;
3590
        }
3591
        virtport = iface->data.network.actual->virtPortProfile;
3592
        if (virtport) {
3593 3594 3595 3596 3597 3598 3599 3600
            /* 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);
3601
                goto error;
3602 3603
            }
        }
3604

3605 3606 3607
        /* 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).
         */
3608
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
3609 3610 3611 3612
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
3613
            goto error;
3614 3615 3616
        } else {
            /* pick an interface from the pool */

3617
            if (netdef->forward.npfs > 0 && netdef->forward.nifs == 0 &&
3618 3619 3620 3621
                networkCreateInterfacePool(netdef) < 0) {
                goto error;
            }

3622 3623 3624 3625 3626
            /* 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.
3627
             */
3628 3629
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
3630 3631 3632
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
3633

3634
                /* pick first dev with 0 connections */
3635 3636 3637
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
3638 3639 3640 3641 3642
                        break;
                    }
                }
            } else {
                /* pick least used dev */
3643
                dev = &netdef->forward.ifs[0];
3644 3645 3646
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
3647 3648 3649 3650
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
3651 3652 3653 3654
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
3655
                goto error;
3656
            }
3657 3658
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
3659
                goto error;
3660 3661 3662
        }
    }

3663
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
3664
        goto error;
3665

3666
 validate:
3667 3668 3669 3670 3671
    /* 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.
     */

3672
    if (virDomainNetGetActualVlan(iface)) {
3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701
        /* 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);
3702

3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721
        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 */
3722
            netdef->connections--;
3723 3724 3725 3726
            if (dev)
                dev->connections--;
            goto error;
        }
3727 3728
    }

3729
    ret = 0;
3730

3731
 cleanup:
3732 3733
    if (network)
        virNetworkObjUnlock(network);
3734 3735
    return ret;

3736
 error:
3737
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
3738 3739 3740
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
3741
    goto cleanup;
3742 3743 3744
}

/* networkNotifyActualDevice:
3745
 * @dom: domain definition that @iface belongs to
3746 3747 3748 3749 3750 3751 3752 3753 3754 3755
 * @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
3756 3757
networkNotifyActualDevice(virDomainDefPtr dom,
                          virDomainNetDefPtr iface)
3758
{
3759
    virNetworkDriverStatePtr driver = driverState;
3760
    enum virDomainNetType actualType = virDomainNetGetActualType(iface);
3761 3762
    virNetworkObjPtr network;
    virNetworkDefPtr netdef;
3763
    virNetworkForwardIfDefPtr dev = NULL;
3764 3765
    size_t i;
    int ret = -1;
3766 3767 3768 3769 3770 3771 3772 3773

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

    networkDriverLock(driver);
    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
    networkDriverUnlock(driver);
    if (!network) {
3774 3775 3776
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
3777 3778 3779 3780 3781
        goto error;
    }
    netdef = network->def;

    if (!iface->data.network.actual ||
3782 3783
        (actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
3784 3785
        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
        goto success;
3786 3787
    }

3788
    if (netdef->forward.npfs > 0 && netdef->forward.nifs == 0 &&
3789
        networkCreateInterfacePool(netdef) < 0) {
3790
        goto error;
3791
    }
3792
    if (netdef->forward.nifs == 0) {
3793
        virReportError(VIR_ERR_INTERNAL_ERROR,
3794 3795
                       _("network '%s' uses a direct or hostdev mode, "
                         "but has no forward dev and no interface pool"),
3796
                       netdef->name);
3797
        goto error;
3798
    }
3799

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

3803 3804 3805 3806 3807 3808 3809 3810 3811
        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 */
3812 3813
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
3814
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
3815 3816
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
3817 3818 3819 3820 3821
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
3822
            virReportError(VIR_ERR_INTERNAL_ERROR,
3823 3824
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
3825
                           netdef->name, actualDev);
3826
            goto error;
3827 3828
        }

3829
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
3830 3831
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
3832
         */
3833
        if ((dev->connections > 0) &&
3834 3835
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
3836 3837
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
3838
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
3839
            virReportError(VIR_ERR_INTERNAL_ERROR,
3840 3841
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
3842
                           netdef->name, actualDev);
3843
            goto error;
3844
        }
3845

3846
        /* we are now assured of success, so mark the allocation */
3847
        dev->connections++;
3848
        VIR_DEBUG("Using physical device %s, connections %d",
3849
                  dev->device.dev, dev->connections);
3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862

    }  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 */
3863 3864
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
3865
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
3866
                virDevicePCIAddressEqual(&hostdev->source.subsys.u.pci.addr,
3867 3868
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
3869 3870 3871 3872 3873 3874 3875 3876 3877
                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,
3878 3879 3880 3881
                           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);
3882 3883 3884 3885 3886 3887 3888 3889
                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) &&
3890
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906
            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);
3907 3908
    }

3909
 success:
3910 3911 3912
    netdef->connections++;
    VIR_DEBUG("Using network %s, %d connections",
              netdef->name, netdef->connections);
3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923

    /* 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;
    }

3924
    ret = 0;
3925
 cleanup:
3926 3927 3928
    if (network)
        virNetworkObjUnlock(network);
    return ret;
3929

3930
 error:
3931
    goto cleanup;
3932 3933 3934 3935
}


/* networkReleaseActualDevice:
3936
 * @dom: domain definition that @iface belongs to
3937 3938 3939 3940 3941 3942 3943 3944 3945 3946
 * @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
3947 3948
networkReleaseActualDevice(virDomainDefPtr dom,
                           virDomainNetDefPtr iface)
3949
{
3950
    virNetworkDriverStatePtr driver = driverState;
3951
    enum virDomainNetType actualType = virDomainNetGetActualType(iface);
3952
    virNetworkObjPtr network;
3953
    virNetworkDefPtr netdef;
3954
    virNetworkForwardIfDefPtr dev = NULL;
3955 3956
    size_t i;
    int ret = -1;
3957 3958 3959 3960 3961 3962 3963 3964

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

    networkDriverLock(driver);
    network = virNetworkFindByName(&driver->networks, iface->data.network.name);
    networkDriverUnlock(driver);
    if (!network) {
3965 3966 3967
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
3968 3969 3970 3971
        goto error;
    }
    netdef = network->def;

3972 3973
    if (iface->data.network.actual &&
        (netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
3974 3975 3976 3977 3978
         netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) &&
        networkUnplugBandwidth(network, iface) < 0)
        goto error;

3979 3980 3981
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
3982 3983
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
3984 3985
    }

3986
    if (netdef->forward.nifs == 0) {
3987
        virReportError(VIR_ERR_INTERNAL_ERROR,
3988
                       _("network '%s' uses a direct/hostdev mode, but "
3989 3990
                         "has no forward dev and no interface pool"),
                       netdef->name);
3991
        goto error;
3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003
    }

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

4005 4006
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4007
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4008 4009
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4010 4011 4012
                break;
            }
        }
4013

4014
        if (!dev) {
4015
            virReportError(VIR_ERR_INTERNAL_ERROR,
4016 4017
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4018
                           netdef->name, actualDev);
4019
            goto error;
4020 4021
        }

4022
        dev->connections--;
4023
        VIR_DEBUG("Releasing physical device %s, connections %d",
4024
                  dev->device.dev, dev->connections);
4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035

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

4036 4037
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4038
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4039
                virDevicePCIAddressEqual(&hostdev->source.subsys.u.pci.addr,
4040 4041
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4042 4043 4044 4045 4046 4047 4048 4049 4050
                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,
4051 4052 4053 4054
                           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);
4055 4056 4057 4058 4059 4060 4061 4062 4063
                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);
   }
4064

4065
 success:
4066
    if (iface->data.network.actual) {
4067
        netdef->connections--;
4068 4069
        VIR_DEBUG("Releasing network %s, %d connections",
                  netdef->name, netdef->connections);
4070

4071 4072 4073 4074
        /* finally we can call the 'unplugged' hook script if any */
        networkRunHook(network, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
                       VIR_HOOK_SUBOP_BEGIN);
    }
4075
    ret = 0;
4076
 cleanup:
4077 4078
    if (network)
        virNetworkObjUnlock(network);
4079 4080 4081 4082
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4083
    return ret;
4084

4085
 error:
4086
    goto cleanup;
4087
}
4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111

/*
 * 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;
4112
    virNetworkDriverStatePtr driver = driverState;
4113
    virNetworkObjPtr network;
4114 4115 4116 4117
    virNetworkDefPtr netdef;
    virNetworkIpDefPtr ipdef;
    virSocketAddr addr;
    virSocketAddrPtr addrptr = NULL;
4118
    char *dev_name = NULL;
4119 4120 4121 4122 4123 4124

    *netaddr = NULL;
    networkDriverLock(driver);
    network = virNetworkFindByName(&driver->networks, netname);
    networkDriverUnlock(driver);
    if (!network) {
4125 4126 4127
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       netname);
4128
        goto error;
4129 4130 4131
    }
    netdef = network->def;

4132
    switch (netdef->forward.type) {
4133 4134 4135 4136 4137 4138
    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) {
4139 4140 4141
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have an IPv4 address"),
                           netdef->name);
4142 4143 4144 4145 4146 4147
            break;
        }
        addrptr = &ipdef->address;
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
4148
        if ((dev_name = netdef->bridge))
4149 4150 4151 4152 4153 4154 4155 4156
            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:
4157 4158
        if ((netdef->forward.nifs > 0) && netdef->forward.ifs)
            dev_name = netdef->forward.ifs[0].device.dev;
4159

4160
        if (!dev_name) {
4161 4162 4163
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' has no associated interface or bridge"),
                           netdef->name);
4164 4165 4166 4167
        }
        break;
    }

4168
    if (dev_name) {
4169
        if (virNetDevGetIPv4Address(dev_name, &addr) < 0)
4170
            goto error;
4171
        addrptr = &addr;
4172 4173
    }

4174 4175 4176
    if (!(addrptr &&
          (*netaddr = virSocketAddrFormat(addrptr)))) {
        goto error;
4177 4178
    }

4179
    ret = 0;
4180
 cleanup:
4181 4182 4183
    if (network)
        virNetworkObjUnlock(network);
    return ret;
4184

4185
 error:
4186
    goto cleanup;
4187
}
4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205

/**
 * 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;
4206
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
4207 4208 4209 4210
    unsigned long long tmp_floor_sum = net->floor_sum;
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221
    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;
    }

4222
    if (!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor ||
4223 4224
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
4225
        return 1;
4226
    }
4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257

    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;

4258
 cleanup:
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 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295
    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];
4296
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324

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

4325 4326
    plug_ret = virNetDevBandwidthPlug(net->def->bridge, net->def->bandwidth,
                                      &iface->mac, ifaceBand, class_id);
4327 4328 4329 4330 4331 4332 4333 4334
    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 */
4335
    net->floor_sum += ifaceBand->in->floor;
4336
    /* update status file */
4337
    if (virNetworkSaveStatus(driverState->stateDir, net) < 0) {
4338
        ignore_value(virBitmapClearBit(net->class_id, class_id));
4339
        net->floor_sum -= ifaceBand->in->floor;
4340 4341 4342 4343
        iface->data.network.actual->class_id = 0;
        ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
        goto cleanup;
    }
4344 4345 4346 4347 4348 4349 4350 4351 4352
    /* 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;

4353
 cleanup:
4354 4355 4356 4357 4358 4359 4360 4361 4362
    return ret;
}

static int
networkUnplugBandwidth(virNetworkObjPtr net,
                       virDomainNetDefPtr iface)
{
    int ret = 0;
    unsigned long long new_rate;
4363
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
4364 4365 4366

    if (iface->data.network.actual &&
        iface->data.network.actual->class_id) {
4367 4368 4369 4370 4371
        if (!net->def->bandwidth || !net->def->bandwidth->in) {
            VIR_WARN("Network %s has no bandwidth but unplug requested",
                     net->def->name);
            goto cleanup;
        }
4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382
        /* 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 */
4383
        net->floor_sum -= ifaceBand->in->floor;
4384 4385 4386 4387
        /* return class ID */
        ignore_value(virBitmapClearBit(net->class_id,
                                       iface->data.network.actual->class_id));
        /* update status file */
4388
        if (virNetworkSaveStatus(driverState->stateDir, net) < 0) {
4389
            net->floor_sum += ifaceBand->in->floor;
4390 4391 4392 4393
            ignore_value(virBitmapSetBit(net->class_id,
                                         iface->data.network.actual->class_id));
            goto cleanup;
        }
4394 4395 4396 4397 4398 4399 4400 4401 4402 4403
        /* 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;
    }

4404
 cleanup:
4405 4406
    return ret;
}
4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421

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