bridge_driver.c 170.1 KB
Newer Older
1
/*
2
 * bridge_driver.c: core driver methods for managing network
3
 *
4
 * Copyright (C) 2006-2015 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
#include <dirent.h>
45 46 47
#if HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
48

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

78
#define VIR_FROM_THIS VIR_FROM_NETWORK
79
#define MAX_BRIDGE_ID 256
80

81 82 83 84 85 86 87
/**
 * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX:
 *
 * Macro providing the upper limit on the size of leases file
 */
#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (32 * 1024 * 1024)

88 89
VIR_LOG_INIT("network.bridge_driver");

90
static virNetworkDriverStatePtr network_driver;
91

92 93 94 95 96 97 98 99
static virNetworkDriverStatePtr
networkGetDriver(void)
{
    /* Maybe one day we can store @network_driver in the
     * connection object, but until then, it's just a global
     * variable which is returned. */
    return network_driver;
}
100

101
static void networkDriverLock(virNetworkDriverStatePtr driver)
102
{
103
    virMutexLock(&driver->lock);
104
}
105
static void networkDriverUnlock(virNetworkDriverStatePtr driver)
106
{
107
    virMutexUnlock(&driver->lock);
108 109
}

110 111 112 113
static dnsmasqCapsPtr
networkGetDnsmasqCaps(virNetworkDriverStatePtr driver)
{
    dnsmasqCapsPtr ret;
114
    networkDriverLock(driver);
115
    ret = virObjectRef(driver->dnsmasqCaps);
116
    networkDriverUnlock(driver);
117 118 119 120 121 122 123 124 125 126 127
    return ret;
}

static int
networkDnsmasqCapsRefresh(virNetworkDriverStatePtr driver)
{
    dnsmasqCapsPtr caps;

    if (!(caps = dnsmasqCapsNewFromBinary(DNSMASQ)))
        return -1;

128
    networkDriverLock(driver);
129 130
    virObjectUnref(driver->dnsmasqCaps);
    driver->dnsmasqCaps = caps;
131
    networkDriverUnlock(driver);
132 133 134
    return 0;
}

135
static int networkStateCleanup(void);
136

137 138
static int networkStartNetwork(virNetworkDriverStatePtr driver,
                               virNetworkObjPtr network);
139

140 141
static int networkShutdownNetwork(virNetworkDriverStatePtr driver,
                                  virNetworkObjPtr network);
142

143 144
static int networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
                                      virNetworkObjPtr network);
145

146 147
static int networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
                                         virNetworkObjPtr network);
148

149
static int networkStartNetworkExternal(virNetworkObjPtr network);
150

151
static int networkShutdownNetworkExternal(virNetworkObjPtr network);
152

153 154
static void networkReloadFirewallRules(virNetworkDriverStatePtr driver);
static void networkRefreshDaemons(virNetworkDriverStatePtr driver);
155

156 157 158 159 160
static int networkPlugBandwidth(virNetworkObjPtr net,
                                virDomainNetDefPtr iface);
static int networkUnplugBandwidth(virNetworkObjPtr net,
                                  virDomainNetDefPtr iface);

161
static void networkNetworkObjTaint(virNetworkObjPtr net,
162
                                   virNetworkTaintFlags taint);
163

164 165 166
static virNetworkObjPtr
networkObjFromNetwork(virNetworkPtr net)
{
167
    virNetworkDriverStatePtr driver = networkGetDriver();
168 169 170
    virNetworkObjPtr network;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

171
    network = virNetworkObjFindByUUID(driver->networks, net->uuid);
172 173 174 175 176 177 178 179 180 181
    if (!network) {
        virUUIDFormat(net->uuid, uuidstr);
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching uuid '%s' (%s)"),
                       uuidstr, net->name);
    }

    return network;
}

182 183 184
static int
networkRunHook(virNetworkObjPtr network,
               virDomainDefPtr dom,
185
               virDomainNetDefPtr iface,
186 187 188 189 190 191 192 193 194
               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)) {
195 196 197 198 199 200
        if (!network) {
            VIR_DEBUG("Not running hook as @network is NULL");
            ret = 0;
            goto cleanup;
        }

201 202
        virBufferAddLit(&buf, "<hookData>\n");
        virBufferAdjustIndent(&buf, 2);
203 204
        if (iface && virDomainNetDefFormat(&buf, iface, 0) < 0)
            goto cleanup;
205 206 207 208 209 210 211 212
        if (virNetworkDefFormatBuf(&buf, network->def, 0) < 0)
            goto cleanup;
        if (dom && virDomainDefFormatInternal(dom, 0, &buf) < 0)
            goto cleanup;

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

213
        if (virBufferCheckError(&buf) < 0)
214 215
            goto cleanup;

216
        xml = virBufferContentAndReset(&buf);
217 218 219 220 221 222 223 224
        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;
225 226

        networkNetworkObjTaint(network, VIR_NETWORK_TAINT_HOOK);
227 228 229
    }

    ret = 0;
230
 cleanup:
231 232 233 234 235 236 237
    virBufferFreeAndReset(&buf);
    VIR_FREE(xml);
    VIR_FREE(net_xml);
    VIR_FREE(dom_xml);
    return ret;
}

238
static char *
239 240
networkDnsmasqLeaseFileNameDefault(virNetworkDriverStatePtr driver,
                                   const char *netname)
241 242 243
{
    char *leasefile;

244
    ignore_value(virAsprintf(&leasefile, "%s/%s.leases",
245
                             driver->dnsmasqStateDir, netname));
246 247 248
    return leasefile;
}

249
static char *
250 251
networkDnsmasqLeaseFileNameCustom(virNetworkDriverStatePtr driver,
                                  const char *bridge)
252 253 254 255
{
    char *leasefile;

    ignore_value(virAsprintf(&leasefile, "%s/%s.status",
256
                             driver->dnsmasqStateDir, bridge));
257 258 259
    return leasefile;
}

260
static char *
261 262
networkDnsmasqConfigFileName(virNetworkDriverStatePtr driver,
                             const char *netname)
263 264 265
{
    char *conffile;

266
    ignore_value(virAsprintf(&conffile, "%s/%s.conf",
267
                             driver->dnsmasqStateDir, netname));
268 269 270
    return conffile;
}

271 272 273 274 275 276
static char *
networkRadvdPidfileBasename(const char *netname)
{
    /* this is simple but we want to be sure it's consistently done */
    char *pidfilebase;

277
    ignore_value(virAsprintf(&pidfilebase, "%s-radvd", netname));
278 279 280 281
    return pidfilebase;
}

static char *
282 283
networkRadvdConfigFileName(virNetworkDriverStatePtr driver,
                           const char *netname)
284 285 286
{
    char *configfile;

287
    ignore_value(virAsprintf(&configfile, "%s/%s-radvd.conf",
288
                             driver->radvdStateDir, netname));
289 290
    return configfile;
}
291

292 293
/* do needed cleanup steps and remove the network from the list */
static int
294 295
networkRemoveInactive(virNetworkDriverStatePtr driver,
                      virNetworkObjPtr net)
296 297
{
    char *leasefile = NULL;
298
    char *customleasefile = NULL;
299
    char *radvdconfigfile = NULL;
300
    char *configfile = NULL;
301
    char *radvdpidbase = NULL;
302
    char *statusfile = NULL;
303 304 305 306 307 308
    dnsmasqContext *dctx = NULL;
    virNetworkDefPtr def = virNetworkObjGetPersistentDef(net);

    int ret = -1;

    /* remove the (possibly) existing dnsmasq and radvd files */
309
    if (!(dctx = dnsmasqContextNew(def->name,
310
                                   driver->dnsmasqStateDir))) {
311
        goto cleanup;
312
    }
313

314
    if (!(leasefile = networkDnsmasqLeaseFileNameDefault(driver, def->name)))
315 316
        goto cleanup;

317
    if (!(customleasefile = networkDnsmasqLeaseFileNameCustom(driver, def->bridge)))
318 319
        goto cleanup;

320
    if (!(radvdconfigfile = networkRadvdConfigFileName(driver, def->name)))
321
        goto cleanup;
322 323

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
324
        goto cleanup;
325

326
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
327
        goto cleanup;
328

329
    if (!(statusfile = virNetworkConfigFile(driver->stateDir, def->name)))
330
        goto cleanup;
331

332 333 334
    /* dnsmasq */
    dnsmasqDelete(dctx);
    unlink(leasefile);
335
    unlink(customleasefile);
336
    unlink(configfile);
337 338 339

    /* radvd */
    unlink(radvdconfigfile);
340
    virPidFileDelete(driver->pidDir, radvdpidbase);
341

342 343 344
    /* remove status file */
    unlink(statusfile);

345
    /* remove the network definition */
346
    virNetworkRemoveInactive(driver->networks, net);
347 348 349

    ret = 0;

350
 cleanup:
351
    VIR_FREE(leasefile);
352
    VIR_FREE(configfile);
353
    VIR_FREE(customleasefile);
354 355
    VIR_FREE(radvdconfigfile);
    VIR_FREE(radvdpidbase);
356
    VIR_FREE(statusfile);
357 358 359 360
    dnsmasqContextFree(dctx);
    return ret;
}

361 362 363
static char *
networkBridgeDummyNicName(const char *brname)
{
364
    static const char dummyNicSuffix[] = "-nic";
365 366
    char *nicname;

367 368 369 370 371 372 373
    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.
         */
374 375 376 377 378
        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));
379
    } else {
380
        ignore_value(virAsprintf(&nicname, "%s%s", brname, dummyNicSuffix));
381
    }
382 383 384
    return nicname;
}

385 386
static int
networkUpdateState(virNetworkObjPtr obj,
387
                   void *opaque)
388
{
389
    virNetworkDriverStatePtr driver = opaque;
390
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
391
    int ret = -1;
392

393
    virObjectLock(obj);
394
    if (!virNetworkObjIsActive(obj)) {
395 396
        ret = 0;
        goto cleanup;
397
    }
398

399 400 401 402 403 404 405 406
    switch (obj->def->forward.type) {
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
        /* If bridge doesn't exist, then mark it inactive */
        if (!(obj->def->bridge && virNetDevExists(obj->def->bridge) == 1))
            obj->active = 0;
        break;
407

408 409
    case VIR_NETWORK_FORWARD_BRIDGE:
        if (!(obj->def->bridge && virNetDevExists(obj->def->bridge) == 1)) {
410 411
                obj->active = 0;
            break;
412
        }
413 414 415 416 417 418 419 420 421
        /* intentionally drop through to common case for all
         * macvtap networks (forward='bridge' with no bridge
         * device defined is macvtap using its 'bridge' mode)
         */
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
        /* so far no extra checks */
        break;
422

423 424 425
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
426
    }
427

428 429 430
    /* Try and read dnsmasq/radvd pids of active networks */
    if (obj->active && obj->def->ips && (obj->def->nips > 0)) {
        char *radvdpidbase;
431

432 433 434
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           obj->def->name,
                                           &obj->dnsmasqPid,
435
                                           dnsmasqCapsGetBinaryPath(dnsmasq_caps)));
436 437 438
        radvdpidbase = networkRadvdPidfileBasename(obj->def->name);
        if (!radvdpidbase)
            goto cleanup;
439

440 441 442 443
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
                                           &obj->radvdPid, RADVD));
        VIR_FREE(radvdpidbase);
444
    }
445

446 447
    ret = 0;
 cleanup:
448
    virObjectUnlock(obj);
449
    virObjectUnref(dnsmasq_caps);
450 451
    return ret;
}
452

453

454 455
static int
networkAutostartConfig(virNetworkObjPtr net,
456
                       void *opaque)
457
{
458
    virNetworkDriverStatePtr driver = opaque;
459
    int ret = -1;
460

461
    virObjectLock(net);
462 463
    if (net->autostart &&
        !virNetworkObjIsActive(net) &&
464
        networkStartNetwork(driver, net) < 0)
465 466 467 468
        goto cleanup;

    ret = 0;
 cleanup:
469
    virObjectUnlock(net);
470
    return ret;
471 472
}

473 474 475
#if HAVE_FIREWALLD
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
476
                             DBusMessage *message, void *user_data)
477
{
478 479
    virNetworkDriverStatePtr driver = user_data;

480 481 482 483 484 485
    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.");
486
        networkReloadFirewallRules(driver);
487 488 489 490 491 492
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

493
static int
494
networkMigrateStateFiles(virNetworkDriverStatePtr driver)
495 496 497 498 499 500 501 502 503 504 505 506 507
{
    /* Due to a change in location of network state xml beginning in
     * libvirt 1.2.4 (from /var/lib/libvirt/network to
     * /var/run/libvirt/network), we must check for state files in two
     * locations. Anything found in the old location must be written
     * to the new location, then erased from the old location. (Note
     * that we read/write the file rather than calling rename()
     * because the old and new state directories are likely in
     * different filesystems).
     */
    int ret = -1;
    const char *oldStateDir = LOCALSTATEDIR "/lib/libvirt/network";
    DIR *dir;
508
    int direrr;
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
    struct dirent *entry;
    char *oldPath = NULL, *newPath = NULL;
    char *contents = NULL;

    if (!(dir = opendir(oldStateDir))) {
        if (errno == ENOENT)
            return 0;

        virReportSystemError(errno, _("failed to open directory '%s'"),
                             oldStateDir);
        return -1;
    }

    if (virFileMakePath(driver->stateDir) < 0) {
        virReportSystemError(errno, _("cannot create directory %s"),
                             driver->stateDir);
        goto cleanup;
    }

528
    while ((direrr = virDirRead(dir, &entry, oldStateDir)) > 0) {
529 530 531
        if (entry->d_type != DT_UNKNOWN &&
            entry->d_type != DT_REG)
            continue;
532

533
        if (STREQ(entry->d_name, ".") ||
534 535 536 537 538
            STREQ(entry->d_name, ".."))
            continue;

        if (virAsprintf(&oldPath, "%s/%s",
                        oldStateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
539
            goto cleanup;
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556

        if (entry->d_type == DT_UNKNOWN) {
            struct stat st;

            if (lstat(oldPath, &st) < 0) {
                virReportSystemError(errno,
                                     _("failed to stat network status file '%s'"),
                                     oldPath);
                goto cleanup;
            }

            if (!S_ISREG(st.st_mode)) {
                VIR_FREE(oldPath);
                continue;
            }
        }

557
        if (virFileReadAll(oldPath, 1024*1024, &contents) < 0)
J
Ján Tomko 已提交
558
            goto cleanup;
559 560 561

        if (virAsprintf(&newPath, "%s/%s",
                        driver->stateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
562
            goto cleanup;
563 564 565 566 567 568 569 570 571 572 573 574
        if (virFileWriteStr(newPath, contents, S_IRUSR | S_IWUSR) < 0) {
            virReportSystemError(errno,
                                 _("failed to write network status file '%s'"),
                                 newPath);
            goto cleanup;
        }

        unlink(oldPath);
        VIR_FREE(oldPath);
        VIR_FREE(newPath);
        VIR_FREE(contents);
    }
575
    if (direrr < 0)
J
Ján Tomko 已提交
576
        goto cleanup;
577 578 579 580 581 582 583 584 585 586

    ret = 0;
 cleanup:
    closedir(dir);
    VIR_FREE(oldPath);
    VIR_FREE(newPath);
    VIR_FREE(contents);
    return ret;
}

587
/**
588
 * networkStateInitialize:
589 590 591 592
 *
 * Initialization function for the QEmu daemon
 */
static int
593 594 595
networkStateInitialize(bool privileged,
                       virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
596
{
597 598 599
    int ret = -1;
    char *configdir = NULL;
    char *rundir = NULL;
600 601 602
#ifdef HAVE_FIREWALLD
    DBusConnection *sysbus = NULL;
#endif
603

604
    if (VIR_ALLOC(network_driver) < 0)
605
        goto error;
606

607 608
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
609 610
        goto error;
    }
611

612 613 614 615
    /* configuration/state paths are one of
     * ~/.config/libvirt/... (session/unprivileged)
     * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
     */
616
    if (privileged) {
617
        if (VIR_STRDUP(network_driver->networkConfigDir,
618
                       SYSCONFDIR "/libvirt/qemu/networks") < 0 ||
619
            VIR_STRDUP(network_driver->networkAutostartDir,
620
                       SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
621
            VIR_STRDUP(network_driver->stateDir,
622
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
623
            VIR_STRDUP(network_driver->pidDir,
624
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
625
            VIR_STRDUP(network_driver->dnsmasqStateDir,
626
                       LOCALSTATEDIR "/lib/libvirt/dnsmasq") < 0 ||
627
            VIR_STRDUP(network_driver->radvdStateDir,
628 629
                       LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
            goto error;
630 631 632 633 634

        /* migration from old to new location is only applicable for
         * privileged mode - unprivileged mode directories haven't
         * changed location.
         */
635
        if (networkMigrateStateFiles(network_driver) < 0)
636
            goto error;
637
    } else {
638 639 640
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
641
            goto error;
642

643
        if ((virAsprintf(&network_driver->networkConfigDir,
644
                         "%s/qemu/networks", configdir) < 0) ||
645
            (virAsprintf(&network_driver->networkAutostartDir,
646
                         "%s/qemu/networks/autostart", configdir) < 0) ||
647
            (virAsprintf(&network_driver->stateDir,
648
                         "%s/network/lib", rundir) < 0) ||
649
            (virAsprintf(&network_driver->pidDir,
650
                         "%s/network/run", rundir) < 0) ||
651
            (virAsprintf(&network_driver->dnsmasqStateDir,
652
                         "%s/dnsmasq/lib", rundir) < 0) ||
653
            (virAsprintf(&network_driver->radvdStateDir,
654
                         "%s/radvd/lib", rundir) < 0)) {
655
            goto error;
656
        }
657 658
    }

659
    if (virFileMakePath(network_driver->stateDir) < 0) {
660 661
        virReportSystemError(errno,
                             _("cannot create directory %s"),
662
                             network_driver->stateDir);
663 664 665
        goto error;
    }

666
    /* if this fails now, it will be retried later with dnsmasqCapsRefresh() */
667
    network_driver->dnsmasqCaps = dnsmasqCapsNewFromBinary(DNSMASQ);
668

669
    if (!(network_driver->networks = virNetworkObjListNew()))
670 671
        goto error;

672 673
    if (virNetworkLoadAllState(network_driver->networks,
                               network_driver->stateDir) < 0)
674 675
        goto error;

676 677 678
    if (virNetworkLoadAllConfigs(network_driver->networks,
                                 network_driver->networkConfigDir,
                                 network_driver->networkAutostartDir) < 0)
679 680
        goto error;

681 682 683 684
    /* Update the internal status of all allegedly active
     * networks according to external conditions on the host
     * (i.e. anything that isn't stored directly in each
     * network's state file). */
685
    virNetworkObjListForEach(network_driver->networks,
686
                             networkUpdateState,
687 688
                             network_driver);
    virNetworkObjListPrune(network_driver->networks,
689 690
                           VIR_CONNECT_LIST_NETWORKS_INACTIVE |
                           VIR_CONNECT_LIST_NETWORKS_TRANSIENT);
691 692
    networkReloadFirewallRules(network_driver);
    networkRefreshDaemons(network_driver);
693

694
    network_driver->networkEventState = virObjectEventStateNew();
695

696 697 698 699
#ifdef HAVE_FIREWALLD
    if (!(sysbus = virDBusGetSystemBus())) {
        virErrorPtr err = virGetLastError();
        VIR_WARN("DBus not available, disabling firewalld support "
700
                 "in bridge_network_driver: %s", err->message);
701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
    } 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,
718
                                   network_driver, NULL);
719 720 721
    }
#endif

722
    ret = 0;
723
 cleanup:
724 725 726
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
727

728
 error:
729 730
    if (network_driver)
        networkDriverUnlock(network_driver);
731
    networkStateCleanup();
732
    goto cleanup;
733 734
}

735 736 737 738 739 740 741 742
/**
 * networkStateAutoStart:
 *
 * Function to AutoStart the bridge configs
 */
static void
networkStateAutoStart(void)
{
743
    if (!network_driver)
744 745
        return;

746
    virNetworkObjListForEach(network_driver->networks,
747
                             networkAutostartConfig,
748
                             network_driver);
749 750
}

751
/**
752
 * networkStateReload:
753 754 755 756 757
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
758 759
networkStateReload(void)
{
760
    if (!network_driver)
761 762
        return 0;

763 764 765 766 767 768 769 770
    virNetworkLoadAllState(network_driver->networks,
                           network_driver->stateDir);
    virNetworkLoadAllConfigs(network_driver->networks,
                             network_driver->networkConfigDir,
                             network_driver->networkAutostartDir);
    networkReloadFirewallRules(network_driver);
    networkRefreshDaemons(network_driver);
    virNetworkObjListForEach(network_driver->networks,
771 772
                             networkAutostartConfig,
                             NULL);
773 774 775 776 777
    return 0;
}


/**
778
 * networkStateCleanup:
779 780 781 782
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
783 784
networkStateCleanup(void)
{
785
    if (!network_driver)
786 787
        return -1;

788
    virObjectEventStateFree(network_driver->networkEventState);
789

790
    /* free inactive networks */
791
    virObjectUnref(network_driver->networks);
792

793 794 795 796 797 798
    VIR_FREE(network_driver->networkConfigDir);
    VIR_FREE(network_driver->networkAutostartDir);
    VIR_FREE(network_driver->stateDir);
    VIR_FREE(network_driver->pidDir);
    VIR_FREE(network_driver->dnsmasqStateDir);
    VIR_FREE(network_driver->radvdStateDir);
799

800
    virObjectUnref(network_driver->dnsmasqCaps);
801

802
    virMutexDestroy(&network_driver->lock);
803

804
    VIR_FREE(network_driver);
805 806 807 808 809

    return 0;
}


810 811 812 813 814 815 816
/* 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)
{
817 818
    size_t i;
    int ret = -1;
819 820 821 822 823 824 825
    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.
     */
826
    for (i = 0; i < 25; i++) {
827
        int signum = 0;
828
        if (i == 0) {
829
            signum = SIGTERM;
830
        } else if (i == 15) {
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
            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);
866
 cleanup:
867 868 869
    return ret;
}

J
Ján Tomko 已提交
870 871 872
/* the following does not build a file, it builds a list
 * which is later saved into a file
 */
G
Gene Czarcinski 已提交
873

874
static int
G
Gene Czarcinski 已提交
875 876
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
                                 virNetworkIpDefPtr ipdef)
877
{
878
    size_t i;
G
Gene Czarcinski 已提交
879
    bool ipv6 = false;
880

G
Gene Czarcinski 已提交
881 882
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
883 884
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
885
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
886 887
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
888
                return -1;
889
    }
890

G
Gene Czarcinski 已提交
891 892 893 894 895 896 897
    return 0;
}

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

900 901
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
902
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
903
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
904
                for (j = 0; j < host->nnames; j++)
905 906
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
907 908
            }
        }
909 910
    }

911
    return 0;
912 913 914
}


915 916
int
networkDnsmasqConfContents(virNetworkObjPtr network,
917 918 919 920
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
                           dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
921
{
922
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
923
    int r, ret = -1;
924
    int nbleases = 0;
925
    size_t i;
926
    virNetworkDNSDefPtr dns = &network->def->dns;
G
Gene Czarcinski 已提交
927 928
    virNetworkIpDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
    bool ipv6SLAAC;
929
    char *saddr = NULL, *eaddr = NULL;
930

931 932
    *configstr = NULL;

933
    /*
934 935 936
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
937
     *
938 939
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
940
     */
941 942 943 944 945 946

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

947 948
    /* create dnsmasq config file appropriate for this network */
    virBufferAsprintf(&configbuf,
949 950 951 952 953 954 955
                      "##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"
956
                      "strict-order\n",
957 958
                      network->def->name);

959 960 961 962
    if (network->def->dns.forwarders) {
        virBufferAddLit(&configbuf, "no-resolv\n");
        for (i = 0; i < network->def->dns.nfwds; i++) {
            virBufferAsprintf(&configbuf, "server=%s\n",
J
Ján Tomko 已提交
963
                              network->def->dns.forwarders[i]);
964 965 966
        }
    }

967
    if (network->def->domain) {
968 969 970 971 972
        if (network->def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
                              network->def->domain);
        }
973
        virBufferAsprintf(&configbuf,
974 975 976 977
                          "domain=%s\n"
                          "expand-hosts\n",
                          network->def->domain);
    }
978

J
Ján Tomko 已提交
979
    if (network->def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
980 981 982 983
        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)
984
         */
985
        virBufferAddLit(&configbuf, "local=//\n");
986
    }
987

988
    if (pidfile)
989
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
990

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

994 995 996 997 998 999 1000 1001
    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.
         */
1002
        virBufferAsprintf(&configbuf,
1003 1004 1005
                          "bind-dynamic\n"
                          "interface=%s\n",
                          network->def->bridge);
1006
    } else {
1007
        virBufferAddLit(&configbuf, "bind-interfaces\n");
1008 1009 1010 1011 1012 1013 1014 1015
        /*
         * --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
         */
1016 1017 1018
        for (i = 0;
             (tmpipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
             i++) {
1019 1020 1021 1022
            char *ipaddr = virSocketAddrFormat(&tmpipdef->address);

            if (!ipaddr)
                goto cleanup;
1023

1024
            /* also part of CVE 2012-3411 - if the host's version of
1025
             * dnsmasq doesn't have bind-dynamic, only allow listening on
1026 1027
             * private/local IP addresses (see RFC1918/RFC3484/RFC4193)
             */
1028 1029
            if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
                !virSocketAddrIsPrivate(&tmpipdef->address)) {
1030 1031 1032 1033
                unsigned long version = dnsmasqCapsGetVersion(caps);

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
1034
                                 "The version of dnsmasq on this host (%d.%d) "
1035 1036 1037 1038
                                 "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 "
1039 1040 1041 1042 1043 1044
                                 "(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);
1045
                VIR_FREE(ipaddr);
1046 1047
                goto cleanup;
            }
1048
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
1049 1050 1051
            VIR_FREE(ipaddr);
        }
    }
1052

1053 1054
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
1055
     * guaranteed to not work, and set no-resolv so that no dns
1056 1057 1058
     * 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).
1059
     */
1060
    if (network->def->forward.type == VIR_NETWORK_FORWARD_NONE) {
1061
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
1062
                        "no-resolv\n");
1063
    }
1064

1065
    for (i = 0; i < dns->ntxts; i++) {
1066
        virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
1067 1068
                          dns->txts[i].name,
                          dns->txts[i].value);
1069
    }
1070

1071
    for (i = 0; i < dns->nsrvs; i++) {
1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
        /* 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);
1094

1095 1096 1097
        /* domain is optional - it defaults to the domain of this network */
        if (dns->srvs[i].domain)
            virBufferAsprintf(&configbuf, ".%s", dns->srvs[i].domain);
1098

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
        /* 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);
1121
        }
1122
        virBufferAddLit(&configbuf, "\n");
1123 1124
    }

G
Gene Czarcinski 已提交
1125
    /* Find the first dhcp for both IPv4 and IPv6 */
1126 1127 1128
    for (i = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
         i++) {
G
Gene Czarcinski 已提交
1129 1130 1131 1132
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1133 1134
                                   _("For IPv4, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
                    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,
1146 1147 1148 1149 1150 1151 1152 1153 1154
                                   _("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 已提交
1155 1156 1157 1158
                    goto cleanup;
                }
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1159 1160
                                   _("For IPv6, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
                    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 "
1174 1175 1176 1177
                 "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 已提交
1178 1179 1180 1181 1182
    }

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1183
        for (r = 0; r < ipdef->nranges; r++) {
1184 1185
            int thisRange;

1186 1187
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1188
                goto cleanup;
1189

1190
            virBufferAsprintf(&configbuf, "dhcp-range=%s,%s\n",
1191
                              saddr, eaddr);
1192
            VIR_FREE(saddr);
1193
            VIR_FREE(eaddr);
1194
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1195 1196 1197
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
                                              virNetworkIpDefPrefix(ipdef));
1198 1199 1200
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1201
        }
1202

1203
        /*
1204 1205 1206 1207
         * 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)
1208 1209
         */
        if (!ipdef->nranges && ipdef->nhosts) {
1210
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
1211 1212
            if (!bridgeaddr)
                goto cleanup;
1213
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static\n", bridgeaddr);
1214 1215
            VIR_FREE(bridgeaddr);
        }
1216

G
Gene Czarcinski 已提交
1217 1218
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1219

G
Gene Czarcinski 已提交
1220 1221 1222
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts)
1223
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1224

G
Gene Czarcinski 已提交
1225
            if (ipdef->tftproot) {
1226 1227
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1228
            }
1229

G
Gene Czarcinski 已提交
1230 1231 1232
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1233

1234
                    if (!bootserver)
G
Gene Czarcinski 已提交
1235
                        goto cleanup;
1236
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1237
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1238 1239
                    VIR_FREE(bootserver);
                } else {
1240
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1241 1242 1243 1244 1245
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1246

1247
    if (nbleases > 0)
1248
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1249

G
Gene Czarcinski 已提交
1250 1251
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1252
        goto cleanup;
G
Gene Czarcinski 已提交
1253 1254 1255 1256 1257 1258

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

1262 1263
    /* Likewise, always create this file and put it on the
     * commandline, to allow for runtime additions.
G
Gene Czarcinski 已提交
1264
     */
1265
    virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
1266
                      dctx->addnhostsfile->path);
G
Gene Czarcinski 已提交
1267 1268 1269

    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
1270
        if (ipv6def) {
1271
            virBufferAddLit(&configbuf, "enable-ra\n");
1272
        } else {
1273 1274 1275
            for (i = 0;
                 (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
                 i++) {
G
Gene Czarcinski 已提交
1276 1277 1278 1279
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1280 1281
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1282 1283
                    VIR_FREE(bridgeaddr);
                }
1284
            }
1285
        }
1286 1287
    }

1288 1289 1290
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1291
    ret = 0;
G
Gene Czarcinski 已提交
1292

1293
 cleanup:
1294 1295
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1296
    virBufferFreeAndReset(&configbuf);
1297
    return ret;
1298 1299
}

1300
/* build the dnsmasq command line */
1301 1302 1303
static int ATTRIBUTE_NONNULL(3)
networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
                                  virNetworkObjPtr network,
1304
                                  virCommandPtr *cmdout,
1305 1306
                                  char *pidfile,
                                  dnsmasqContext *dctx)
1307
{
1308
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1309
    virCommandPtr cmd = NULL;
G
Gene Czarcinski 已提交
1310
    int ret = -1;
1311 1312
    char *configfile = NULL;
    char *configstr = NULL;
1313
    char *leaseshelper_path = NULL;
1314 1315

    network->dnsmasqPid = -1;
1316

1317
    if (networkDnsmasqConfContents(network, pidfile, &configstr,
1318
                                   dctx, dnsmasq_caps) < 0)
1319 1320 1321 1322 1323
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1324
    if (!(configfile = networkDnsmasqConfigFileName(driver, network->def->name)))
1325 1326 1327 1328 1329
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1330 1331
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1332 1333 1334
        goto cleanup;
    }

1335 1336
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1337
                                                  abs_topbuilddir "/src",
1338 1339 1340
                                                  LIBEXECDIR)))
        goto cleanup;

1341
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1342
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1343 1344
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1345
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1346
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", network->def->bridge);
1347

1348
    *cmdout = cmd;
1349
    ret = 0;
1350
 cleanup:
1351
    virObjectUnref(dnsmasq_caps);
1352 1353
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1354
    VIR_FREE(leaseshelper_path);
1355 1356 1357 1358
    return ret;
}

static int
1359 1360
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
                       virNetworkObjPtr network)
1361 1362 1363 1364
{
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
    int ret = -1;
1365
    dnsmasqContext *dctx = NULL;
1366

1367
    if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0)) {
G
Gene Czarcinski 已提交
1368
        /* no IP addresses, so we don't need to run */
1369 1370 1371 1372
        ret = 0;
        goto cleanup;
    }

1373
    if (virFileMakePath(driver->pidDir) < 0) {
1374
        virReportSystemError(errno,
1375
                             _("cannot create directory %s"),
1376
                             driver->pidDir);
1377
        goto cleanup;
1378 1379
    }

1380
    if (!(pidfile = virPidFileBuildPath(driver->pidDir,
1381
                                        network->def->name)))
1382
        goto cleanup;
1383

1384
    if (virFileMakePath(driver->dnsmasqStateDir) < 0) {
1385
        virReportSystemError(errno,
1386
                             _("cannot create directory %s"),
1387
                             driver->dnsmasqStateDir);
1388 1389 1390
        goto cleanup;
    }

1391
    dctx = dnsmasqContextNew(network->def->name, driver->dnsmasqStateDir);
1392 1393 1394
    if (dctx == NULL)
        goto cleanup;

1395
    if (networkDnsmasqCapsRefresh(driver) < 0)
1396
        goto cleanup;
1397

1398
    ret = networkBuildDhcpDaemonCommandLine(driver, network, &cmd, pidfile, dctx);
1399 1400 1401 1402 1403
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1404
        goto cleanup;
1405

G
Guido Günther 已提交
1406
    ret = virCommandRun(cmd, NULL);
1407
    if (ret < 0)
1408 1409 1410
        goto cleanup;

    /*
1411 1412 1413 1414 1415
     * 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
1416 1417
     */

1418
    ret = virPidFileRead(driver->pidDir, network->def->name,
1419 1420
                         &network->dnsmasqPid);
    if (ret < 0)
1421
        goto cleanup;
1422

1423
    ret = 0;
1424
 cleanup:
1425
    VIR_FREE(pidfile);
1426
    virCommandFree(cmd);
1427
    dnsmasqContextFree(dctx);
1428 1429 1430
    return ret;
}

1431 1432
/* networkRefreshDhcpDaemon:
 *  Update dnsmasq config files, then send a SIGHUP so that it rereads
G
Gene Czarcinski 已提交
1433 1434
 *  them.   This only works for the dhcp-hostsfile and the
 *  addn-hosts file.
1435 1436 1437
 *
 *  Returns 0 on success, -1 on failure.
 */
1438
static int
1439 1440
networkRefreshDhcpDaemon(virNetworkDriverStatePtr driver,
                         virNetworkObjPtr network)
1441
{
1442 1443
    int ret = -1;
    size_t i;
G
Gene Czarcinski 已提交
1444
    virNetworkIpDefPtr ipdef, ipv4def, ipv6def;
1445
    dnsmasqContext *dctx = NULL;
1446

G
Gene Czarcinski 已提交
1447
    /* if no IP addresses specified, nothing to do */
1448
    if (!virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1449 1450
        return 0;

1451 1452
    /* if there's no running dnsmasq, just start it */
    if (network->dnsmasqPid <= 0 || (kill(network->dnsmasqPid, 0) < 0))
1453
        return networkStartDhcpDaemon(driver, network);
1454

G
Gene Czarcinski 已提交
1455
    VIR_INFO("Refreshing dnsmasq for network %s", network->def->bridge);
1456
    if (!(dctx = dnsmasqContextNew(network->def->name,
1457
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1458
        goto cleanup;
1459
    }
G
Gene Czarcinski 已提交
1460 1461 1462 1463 1464 1465

    /* 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;
1466 1467 1468
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
         i++) {
G
Gene Czarcinski 已提交
1469 1470
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1471 1472
    }

G
Gene Czarcinski 已提交
1473
    ipv6def = NULL;
1474 1475 1476
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
G
Gene Czarcinski 已提交
1477 1478
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1479 1480
    }

G
Gene Czarcinski 已提交
1481
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1482
        goto cleanup;
G
Gene Czarcinski 已提交
1483 1484

    if (ipv6def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv6def) < 0))
J
Ján Tomko 已提交
1485
        goto cleanup;
1486

G
Gene Czarcinski 已提交
1487
    if (networkBuildDnsmasqHostsList(dctx, &network->def->dns) < 0)
J
Ján Tomko 已提交
1488
        goto cleanup;
1489 1490

    if ((ret = dnsmasqSave(dctx)) < 0)
1491
        goto cleanup;
1492 1493

    ret = kill(network->dnsmasqPid, SIGHUP);
1494
 cleanup:
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
    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
1507 1508
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
                         virNetworkObjPtr network)
1509 1510 1511 1512 1513 1514
{
    /* if there is a running dnsmasq, kill it */
    if (network->dnsmasqPid > 0) {
        networkKillDaemon(network->dnsmasqPid, "dnsmasq",
                          network->def->name);
        network->dnsmasqPid = -1;
1515
    }
1516
    /* now start dnsmasq if it should be started */
1517
    return networkStartDhcpDaemon(driver, network);
1518 1519
}

G
Gene Czarcinski 已提交
1520 1521 1522 1523 1524 1525
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";

1526 1527 1528
static int
networkRadvdConfContents(virNetworkObjPtr network, char **configstr)
{
E
Eric Blake 已提交
1529
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1530 1531
    int ret = -1;
    size_t i;
1532
    virNetworkIpDefPtr ipdef;
G
Gene Czarcinski 已提交
1533
    bool v6present = false, dhcp6 = false;
1534 1535

    *configstr = NULL;
1536

G
Gene Czarcinski 已提交
1537
    /* Check if DHCPv6 is needed */
1538 1539 1540
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
G
Gene Czarcinski 已提交
1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
        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;
    }

1554 1555 1556
    /* create radvd config file appropriate for this network;
     * IgnoreIfMissing allows radvd to start even when the bridge is down
     */
1557
    virBufferAsprintf(&configbuf, "interface %s\n"
1558 1559
                      "{\n"
                      "  AdvSendAdvert on;\n"
1560
                      "  IgnoreIfMissing on;\n"
G
Gene Czarcinski 已提交
1561 1562 1563 1564 1565
                      "  AdvManagedFlag %s;\n"
                      "%s",
                      network->def->bridge,
                      dhcp6 ? "on" : "off",
                      dhcp6 ? "\n" : radvd1);
1566 1567

    /* add a section for each IPv6 address in the config */
1568 1569 1570
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET6, i));
         i++) {
1571 1572 1573 1574 1575
        int prefix;
        char *netaddr;

        prefix = virNetworkIpDefPrefix(ipdef);
        if (prefix < 0) {
1576 1577 1578
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
                           network->def->bridge);
1579 1580
            goto cleanup;
        }
1581
        if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
1582
            goto cleanup;
1583
        virBufferAsprintf(&configbuf,
1584
                          "  prefix %s/%d\n"
G
Gene Czarcinski 已提交
1585 1586 1587
                          "  {\n%s  };\n",
                          netaddr, prefix,
                          dhcp6 ? radvd2 : radvd3);
1588 1589 1590
        VIR_FREE(netaddr);
    }

1591
    virBufferAddLit(&configbuf, "};\n");
1592

1593
    if (virBufferCheckError(&configbuf) < 0)
1594
        goto cleanup;
1595

1596 1597
    *configstr = virBufferContentAndReset(&configbuf);

1598
    ret = 0;
1599
 cleanup:
1600 1601 1602 1603
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1604
/* write file and return its name (which must be freed by caller) */
1605
static int
1606 1607 1608
networkRadvdConfWrite(virNetworkDriverStatePtr driver,
                      virNetworkObjPtr network,
                      char **configFile)
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623
{
    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;
1624 1625 1626 1627
        goto cleanup;
    }

    /* construct the filename */
1628
    if (!(*configFile = networkRadvdConfigFileName(driver, network->def->name)))
1629 1630
        goto cleanup;
    /* write the file */
1631
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1632 1633
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1634 1635 1636 1637 1638
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1639
 cleanup:
1640 1641 1642 1643 1644 1645
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

static int
1646 1647
networkStartRadvd(virNetworkDriverStatePtr driver,
                  virNetworkObjPtr network)
1648
{
1649
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1650 1651 1652 1653 1654 1655 1656 1657
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

    network->radvdPid = -1;

G
Gene Czarcinski 已提交
1658
    /* Is dnsmasq handling RA? */
1659
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
1660 1661 1662 1663
        ret = 0;
        goto cleanup;
    }

1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674
    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);
1675 1676 1677
        goto cleanup;
    }

1678
    if (virFileMakePath(driver->pidDir) < 0) {
1679 1680
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1681
                             driver->pidDir);
1682 1683
        goto cleanup;
    }
1684
    if (virFileMakePath(driver->radvdStateDir) < 0) {
1685 1686
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1687
                             driver->radvdStateDir);
1688 1689 1690 1691
        goto cleanup;
    }

    /* construct pidfile name */
1692
    if (!(radvdpidbase = networkRadvdPidfileBasename(network->def->name)))
1693
        goto cleanup;
1694
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
1695 1696
        goto cleanup;

1697
    if (networkRadvdConfWrite(driver, network, &configfile) < 0)
1698 1699
        goto cleanup;

1700 1701 1702 1703
    /* 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
1704
     * virPidFileRead() below will fail if we use them).
1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719
     * 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;

1720
    if (virPidFileRead(driver->pidDir, radvdpidbase, &network->radvdPid) < 0)
1721 1722 1723
        goto cleanup;

    ret = 0;
1724
 cleanup:
1725
    virObjectUnref(dnsmasq_caps);
1726 1727 1728 1729 1730 1731 1732
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

1733
static int
1734 1735
networkRefreshRadvd(virNetworkDriverStatePtr driver,
                    virNetworkObjPtr network)
1736
{
1737
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
1738 1739 1740
    char *radvdpidbase;

    /* Is dnsmasq handling RA? */
1741 1742
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
        virObjectUnref(dnsmasq_caps);
G
Gene Czarcinski 已提交
1743 1744 1745 1746 1747 1748 1749
        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)) {
1750
            virPidFileDelete(driver->pidDir, radvdpidbase);
G
Gene Czarcinski 已提交
1751 1752 1753 1754 1755
            VIR_FREE(radvdpidbase);
        }
        network->radvdPid = -1;
        return 0;
    }
1756
    virObjectUnref(dnsmasq_caps);
G
Gene Czarcinski 已提交
1757

1758 1759
    /* if there's no running radvd, just start it */
    if (network->radvdPid <= 0 || (kill(network->radvdPid, 0) < 0))
1760
        return networkStartRadvd(driver, network);
1761 1762 1763 1764 1765 1766

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

1767
    if (networkRadvdConfWrite(driver, network, NULL) < 0)
1768 1769 1770 1771 1772
        return -1;

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

1773 1774
#if 0
/* currently unused, so it causes a build error unless we #if it out */
1775
static int
1776
networkRestartRadvd(virNetworkObjPtr network)
1777 1778 1779 1780 1781 1782 1783 1784 1785
{
    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 已提交
1786
        if ((networkKillDaemon(network->radvdPid, "radvd",
1787 1788 1789
                               network->def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
             != NULL)) {
1790
            virPidFileDelete(driver->pidDir, radvdpidbase);
1791 1792 1793 1794 1795 1796 1797 1798 1799
            VIR_FREE(radvdpidbase);
        }
        network->radvdPid = -1;
    }
    /* now start radvd if it should be started */
    return networkStartRadvd(network);
}
#endif /* #if 0 */

1800 1801
static int
networkRefreshDaemonsHelper(virNetworkObjPtr net,
1802
                            void *opaque)
1803
{
1804
    virNetworkDriverStatePtr driver = opaque;
1805

1806
    virObjectLock(net);
1807 1808 1809 1810 1811 1812 1813 1814 1815 1816
    if (virNetworkObjIsActive(net) &&
        ((net->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
         (net->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
         (net->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
        /* 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.
         */
1817 1818
        networkRefreshDhcpDaemon(driver, net);
        networkRefreshRadvd(driver, net);
1819
    }
1820
    virObjectUnlock(net);
1821 1822 1823
    return 0;
}

1824 1825 1826 1827
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
1828
networkRefreshDaemons(virNetworkDriverStatePtr driver)
1829 1830
{
    VIR_INFO("Refreshing network daemons");
1831 1832
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
1833
                             driver);
1834
}
1835

1836 1837 1838 1839 1840
static int
networkReloadFirewallRulesHelper(virNetworkObjPtr net,
                                 void *opaque ATTRIBUTE_UNUSED)
{

1841
    virObjectLock(net);
1842 1843 1844 1845 1846 1847 1848 1849 1850 1851
    if (virNetworkObjIsActive(net) &&
        ((net->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
         (net->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
         (net->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
        /* Only the three L3 network types that are configured by libvirt
         * need to have iptables rules reloaded.
         */
        networkRemoveFirewallRules(net->def);
        if (networkAddFirewallRules(net->def) < 0) {
            /* failed to add but already logged */
1852 1853
        }
    }
1854
    virObjectUnlock(net);
1855
    return 0;
1856 1857
}

1858
static void
1859
networkReloadFirewallRules(virNetworkDriverStatePtr driver)
1860
{
1861
    VIR_INFO("Reloading iptables rules");
1862 1863 1864
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
1865 1866
}

1867
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
1868
static int
1869
networkEnableIpForwarding(bool enableIPv4, bool enableIPv6)
1870
{
1871
    int ret = 0;
1872 1873 1874 1875
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
1876
                           &enabled, sizeof(enabled));
1877 1878
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
1879
                           &enabled, sizeof(enabled));
1880
#else
1881 1882 1883 1884
    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);
1885
#endif
1886
    return ret;
1887 1888
}

1889 1890
#define SYSCTL_PATH "/proc/sys"

1891 1892
static int
networkSetIPv6Sysctls(virNetworkObjPtr network)
1893 1894 1895
{
    char *field = NULL;
    int ret = -1;
1896
    bool enableIPv6 =  !!virNetworkDefGetIpByIndex(network->def, AF_INET6, 0);
1897

1898 1899 1900 1901 1902 1903 1904
    /* set disable_ipv6 if there are no ipv6 addresses defined for the
     * network. But also unset it if there *are* ipv6 addresses, as we
     * can't be sure of its default value.
     */
    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/disable_ipv6",
                    network->def->bridge) < 0)
       goto cleanup;
1905

1906 1907
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
1908 1909
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
                      network->def->bridge);
1910 1911 1912
        ret = 0;
        goto cleanup;
    }
1913

1914 1915 1916 1917 1918
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
                               "on bridge %s"), field, network->def->bridge);
        goto cleanup;
1919
    }
1920
    VIR_FREE(field);
1921

1922 1923
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
1924 1925 1926 1927 1928 1929
     */

    /* 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",
1930
                    network->def->bridge) < 0)
1931 1932
        goto cleanup;

1933
    if (virFileWriteStr(field, "0", 0) < 0) {
1934
        virReportSystemError(errno,
1935 1936 1937 1938 1939
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

1940 1941 1942 1943
    /* 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",
1944
                    network->def->bridge) < 0)
1945 1946
        goto cleanup;

1947
    if (virFileWriteStr(field, "0", 0) < 0) {
1948
        virReportSystemError(errno,
1949
                             _("cannot disable %s"), field);
1950 1951 1952 1953
        goto cleanup;
    }

    ret = 0;
1954
 cleanup:
1955 1956 1957 1958
    VIR_FREE(field);
    return ret;
}

1959
/* add an IP address to a bridge */
1960
static int
D
Daniel P. Berrange 已提交
1961
networkAddAddrToBridge(virNetworkObjPtr network,
1962
                       virNetworkIpDefPtr ipdef)
1963
{
1964 1965 1966
    int prefix = virNetworkIpDefPrefix(ipdef);

    if (prefix < 0) {
1967 1968 1969
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
                       network->def->bridge);
1970 1971 1972
        return -1;
    }

1973 1974
    if (virNetDevSetIPAddress(network->def->bridge,
                              &ipdef->address, prefix) < 0)
1975 1976 1977 1978 1979
        return -1;

    return 0;
}

1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002

static int
networkStartHandleMACTableManagerMode(virNetworkObjPtr network,
                                      const char *macTapIfName)
{
    const char *brname = network->def->bridge;

    if (brname &&
        network->def->macTableManager
        == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
        if (virNetDevBridgeSetVlanFiltering(brname, true) < 0)
            return -1;
        if (macTapIfName) {
            if (virNetDevBridgePortSetLearning(brname, macTapIfName, false) < 0)
                return -1;
            if (virNetDevBridgePortSetUnicastFlood(brname, macTapIfName, false) < 0)
                return -1;
        }
    }
    return 0;
}


2003 2004 2005 2006 2007
/* add an IP (static) route to a bridge */
static int
networkAddRouteToBridge(virNetworkObjPtr network,
                        virNetworkRouteDefPtr routedef)
{
2008 2009 2010 2011
    int prefix = virNetworkRouteDefGetPrefix(routedef);
    unsigned int metric = virNetworkRouteDefGetMetric(routedef);
    virSocketAddrPtr addr = virNetworkRouteDefGetAddress(routedef);
    virSocketAddrPtr gateway = virNetworkRouteDefGetGateway(routedef);
2012 2013 2014 2015 2016 2017 2018 2019 2020

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

2021 2022
    if (virNetDevAddRoute(network->def->bridge, addr,
                          prefix, gateway, metric) < 0) {
2023 2024 2025 2026 2027
        return -1;
    }
    return 0;
}

2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053
static int
networkWaitDadFinish(virNetworkObjPtr network)
{
    virNetworkIpDefPtr ipdef;
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

    VIR_DEBUG("Begin waiting for IPv6 DAD on network %s", network->def->name);

    while ((ipdef = virNetworkDefGetIpByIndex(network->def,
                                              AF_INET6, naddrs))) {
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

    ret = (naddrs == 0) ? 0 : virNetDevWaitDadFinish(addrs, naddrs);

 cleanup:
    VIR_FREE(addrs);
    VIR_DEBUG("Finished waiting for IPv6 DAD on network %s with status %d",
              network->def->name, ret);
    return ret;
}

2054
static int
2055 2056
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
                           virNetworkObjPtr network)
2057
{
2058
    size_t i;
2059
    bool v4present = false, v6present = false;
2060 2061
    virErrorPtr save_err = NULL;
    virNetworkIpDefPtr ipdef;
2062
    virNetworkRouteDefPtr routedef;
2063
    char *macTapIfName = NULL;
2064
    int tapfd = -1;
2065

2066
    /* Check to see if any network IP collides with an existing route */
2067
    if (networkCheckRouteCollision(network->def) < 0)
2068 2069
        return -1;

2070
    /* Create and configure the bridge device */
2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084
    if (!network->def->bridge) {
        /* bridge name can only be empty if the config files were
         * edited directly. Otherwise networkValidate() (called after
         * parsing the XML from networkCreateXML() and
         * networkDefine()) guarantees we will have a valid bridge
         * name before this point. Since hand editing of the config
         * files is explicitly prohibited we can, with clear
         * conscience, log an error and fail at this point.
         */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' has no bridge name defined"),
                       network->def->name);
        return -1;
    }
2085
    if (virNetDevBridgeCreate(network->def->bridge) < 0)
2086 2087
        return -1;

2088 2089 2090 2091 2092 2093 2094 2095
    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);
2096
        if (!macTapIfName)
2097
            goto err0;
2098
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2099
        if (virNetDevTapCreateInBridgePort(network->def->bridge,
2100
                                           &macTapIfName, &network->def->mac,
2101
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2102 2103 2104
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2105 2106 2107 2108 2109
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

2110
    /* Set bridge options */
2111 2112 2113 2114

    /* delay is configured in seconds, but virNetDevBridgeSetSTPDelay
     * expects milliseconds
     */
2115
    if (virNetDevBridgeSetSTPDelay(network->def->bridge,
2116
                                   network->def->delay * 1000) < 0)
2117
        goto err1;
2118

2119
    if (virNetDevBridgeSetSTP(network->def->bridge,
2120
                              network->def->stp ? true : false) < 0)
2121
        goto err1;
2122

2123 2124 2125 2126
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
    if (networkSetIPv6Sysctls(network) < 0)
2127
        goto err1;
2128

2129
    /* Add "once per network" rules */
2130
    if (networkAddFirewallRules(network->def) < 0)
2131 2132
        goto err1;

2133 2134 2135
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, i));
         i++) {
2136
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2137
            v4present = true;
2138
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2139
            v6present = true;
2140

2141
        /* Add the IP address/netmask to the bridge */
2142
        if (networkAddAddrToBridge(network, ipdef) < 0)
2143
            goto err2;
2144 2145
    }

2146 2147 2148
    if (networkStartHandleMACTableManagerMode(network, macTapIfName) < 0)
        goto err2;

2149
    /* Bring up the bridge interface */
2150
    if (virNetDevSetOnline(network->def->bridge, 1) < 0)
2151
        goto err2;
2152

2153
    for (i = 0; i < network->def->nroutes; i++) {
2154 2155 2156 2157 2158
        virSocketAddrPtr gateway = NULL;

        routedef = network->def->routes[i];
        gateway = virNetworkRouteDefGetGateway(routedef);

2159 2160 2161
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2162
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2163 2164 2165 2166 2167 2168 2169
            if (networkAddRouteToBridge(network, routedef) < 0) {
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2170 2171
    /* If forward.type != NONE, turn on global IP forwarding */
    if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE &&
2172
        networkEnableIpForwarding(v4present, v6present) < 0) {
2173
        virReportSystemError(errno, "%s",
2174
                             _("failed to enable IP forwarding"));
2175
        goto err3;
2176 2177
    }

2178

2179
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2180
    if ((v4present || v6present) &&
2181
        networkStartDhcpDaemon(driver, network) < 0)
2182
        goto err3;
2183

2184
    /* start radvd if there are any ipv6 addresses */
2185
    if (v6present && networkStartRadvd(driver, network) < 0)
2186 2187
        goto err4;

2188 2189 2190 2191 2192 2193 2194 2195
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
    if (v6present && networkWaitDadFinish(network) < 0)
        goto err4;

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2196 2197 2198 2199 2200 2201 2202
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
            goto err4;
        VIR_FORCE_CLOSE(tapfd);
    }

2203
    if (virNetDevBandwidthSet(network->def->bridge,
2204
                              network->def->bandwidth, true) < 0)
2205 2206
        goto err5;

2207
    VIR_FREE(macTapIfName);
2208 2209 2210

    return 0;

2211
 err5:
2212 2213
    if (network->def->bandwidth)
       virNetDevBandwidthClear(network->def->bridge);
2214

2215 2216 2217 2218
 err4:
    if (!save_err)
        save_err = virSaveLastError();

2219 2220 2221 2222 2223
    if (network->dnsmasqPid > 0) {
        kill(network->dnsmasqPid, SIGTERM);
        network->dnsmasqPid = -1;
    }

2224 2225 2226
 err3:
    if (!save_err)
        save_err = virSaveLastError();
2227
    ignore_value(virNetDevSetOnline(network->def->bridge, 0));
2228

2229 2230 2231
 err2:
    if (!save_err)
        save_err = virSaveLastError();
2232
    networkRemoveFirewallRules(network->def);
2233 2234

 err1:
2235 2236 2237
    if (!save_err)
        save_err = virSaveLastError();

H
Hu Tao 已提交
2238
    if (macTapIfName) {
2239
        VIR_FORCE_CLOSE(tapfd);
2240
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2241 2242
        VIR_FREE(macTapIfName);
    }
2243 2244

 err0:
2245 2246
    if (!save_err)
        save_err = virSaveLastError();
2247
    ignore_value(virNetDevBridgeDelete(network->def->bridge));
2248

2249 2250 2251 2252
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
2253
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2254 2255 2256
    return -1;
}

2257 2258 2259
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
                              virNetworkObjPtr network)
2260
{
2261 2262
    if (network->def->bandwidth)
        virNetDevBandwidthClear(network->def->bridge);
2263

2264 2265 2266 2267 2268
    if (network->radvdPid > 0) {
        char *radvdpidbase;

        kill(network->radvdPid, SIGTERM);
        /* attempt to delete the pidfile we created */
2269
        if ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))) {
2270
            virPidFileDelete(driver->pidDir, radvdpidbase);
2271 2272 2273 2274
            VIR_FREE(radvdpidbase);
        }
    }

2275 2276 2277
    if (network->dnsmasqPid > 0)
        kill(network->dnsmasqPid, SIGTERM);

2278
    if (network->def->mac_specified) {
2279
        char *macTapIfName = networkBridgeDummyNicName(network->def->bridge);
2280
        if (macTapIfName) {
2281
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2282 2283 2284 2285
            VIR_FREE(macTapIfName);
        }
    }

2286
    ignore_value(virNetDevSetOnline(network->def->bridge, 0));
2287

2288
    networkRemoveFirewallRules(network->def);
2289

2290
    ignore_value(virNetDevBridgeDelete(network->def->bridge));
2291

2292
    /* See if its still alive and really really kill it */
2293
    if (network->dnsmasqPid > 0 &&
2294
        (kill(network->dnsmasqPid, 0) == 0))
2295 2296
        kill(network->dnsmasqPid, SIGKILL);
    network->dnsmasqPid = -1;
2297 2298 2299 2300 2301 2302

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

2303 2304 2305
    return 0;
}

2306

2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327
static int
networkStartNetworkBridge(virNetworkObjPtr network)
{
    /* put anything here that needs to be done each time a network of
     * type BRIDGE, is started. On failure, undo anything you've done,
     * and return -1. On success return 0.
     */
    return networkStartHandleMACTableManagerMode(network, NULL);
}

static int
networkShutdownNetworkBridge(virNetworkObjPtr network ATTRIBUTE_UNUSED)
{
    /* put anything here that needs to be done each time a network of
     * type BRIDGE is shutdown. On failure, undo anything you've done,
     * and return -1. On success return 0.
     */
    return 0;
}


2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342
/* networkCreateInterfacePool:
 * @netdef: the original NetDef from the network
 *
 * Creates an implicit interface pool of VF's when a PF dev is given
 */
static int
networkCreateInterfacePool(virNetworkDefPtr netdef)
{
    size_t numVirtFns = 0;
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2343 2344 2345
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev,
                                      &vfNames, &virtFns, &numVirtFns)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get Virtual functions on %s"),
                       netdef->forward.pfs->dev);
        goto cleanup;
    }

    if (VIR_ALLOC_N(netdef->forward.ifs, numVirtFns) < 0)
        goto cleanup;

    for (i = 0; i < numVirtFns; i++) {
        virPCIDeviceAddressPtr thisVirtFn = virtFns[i];
        const char *thisName = vfNames[i];
        virNetworkForwardIfDefPtr thisIf
            = &netdef->forward.ifs[netdef->forward.nifs];

        switch (netdef->forward.type) {
        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
            if (thisName) {
                if (VIR_STRDUP(thisIf->device.dev, thisName) < 0)
                    goto cleanup;
                thisIf->type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
                netdef->forward.nifs++;
            } else {
                VIR_WARN("VF %zu of SRIOV PF %s couldn't be added to the "
                         "interface pool because it isn't bound "
                         "to a network driver - possibly in use elsewhere",
                         i, netdef->forward.pfs->dev);
            }
            break;

        case VIR_NETWORK_FORWARD_HOSTDEV:
            /* VF's are always PCI devices */
            thisIf->type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI;
            thisIf->device.pci.domain = thisVirtFn->domain;
            thisIf->device.pci.bus = thisVirtFn->bus;
            thisIf->device.pci.slot = thisVirtFn->slot;
            thisIf->device.pci.function = thisVirtFn->function;
            netdef->forward.nifs++;
            break;

        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
        case VIR_NETWORK_FORWARD_LAST:
            /* by definition these will never be encountered here */
            break;
        }
    }

    if (netdef->forward.nifs == 0) {
        /* If we don't get at least one interface in the pool, declare
         * failure
         */
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No usable Vf's present on SRIOV PF %s"),
                       netdef->forward.pfs->dev);
        goto cleanup;
    }

    ret = 0;
 cleanup:
    if (ret < 0) {
        /* free all the entries made before error */
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV)
                VIR_FREE(netdef->forward.ifs[i].device.dev);
        }
        netdef->forward.nifs = 0;
    }
    if (netdef->forward.nifs == 0)
        VIR_FREE(netdef->forward.ifs);

    for (i = 0; i < numVirtFns; i++) {
        VIR_FREE(vfNames[i]);
        VIR_FREE(virtFns[i]);
    }
    VIR_FREE(vfNames);
    VIR_FREE(virtFns);
    return ret;
}


2434
static int
2435
networkStartNetworkExternal(virNetworkObjPtr network)
2436 2437
{
    /* put anything here that needs to be done each time a network of
2438
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2439 2440 2441
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2442
    return networkCreateInterfacePool(network->def);
2443 2444
}

2445
static int networkShutdownNetworkExternal(virNetworkObjPtr network ATTRIBUTE_UNUSED)
2446 2447
{
    /* put anything here that needs to be done each time a network of
2448
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2449 2450 2451 2452 2453 2454 2455
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

static int
2456 2457
networkStartNetwork(virNetworkDriverStatePtr driver,
                    virNetworkObjPtr network)
2458
{
2459 2460 2461
    int ret = -1;

    VIR_DEBUG("driver=%p, network=%p", driver, network);
2462 2463

    if (virNetworkObjIsActive(network)) {
2464 2465
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2466
        return ret;
2467 2468
    }

2469 2470 2471
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2472
    if (virNetworkObjSetDefTransient(network, true) < 0)
2473
        goto cleanup;
2474

2475 2476
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2477
    if (networkRunHook(network, NULL, NULL,
2478 2479 2480 2481
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2482
    switch (network->def->forward.type) {
2483 2484 2485 2486

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2487
        if (networkStartNetworkVirtual(driver, network) < 0)
2488
            goto cleanup;
2489 2490 2491
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2492 2493 2494 2495
       if (networkStartNetworkBridge(network) < 0)
          goto cleanup;
       break;

2496 2497 2498
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2499
    case VIR_NETWORK_FORWARD_HOSTDEV:
2500
        if (networkStartNetworkExternal(network) < 0)
2501
            goto cleanup;
2502 2503 2504
        break;
    }

2505
    /* finally we can call the 'started' hook script if any */
2506
    if (networkRunHook(network, NULL, NULL,
2507 2508 2509 2510
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2511 2512 2513
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2514
    VIR_DEBUG("Writing network status to disk");
2515
    if (virNetworkSaveStatus(driver->stateDir, network) < 0)
2516
        goto cleanup;
2517 2518

    network->active = 1;
2519 2520
    VIR_INFO("Network '%s' started up", network->def->name);
    ret = 0;
2521

2522
 cleanup:
2523
    if (ret < 0) {
2524
        virNetworkObjUnsetDefTransient(network);
2525 2526
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
2527
        networkShutdownNetwork(driver, network);
2528 2529 2530 2531 2532 2533 2534
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2535 2536 2537
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
                       virNetworkObjPtr network)
2538 2539 2540 2541 2542 2543 2544 2545 2546
{
    int ret = 0;
    char *stateFile;

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

    if (!virNetworkObjIsActive(network))
        return 0;

2547
    stateFile = virNetworkConfigFile(driver->stateDir,
2548
                                     network->def->name);
2549 2550 2551 2552 2553 2554
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2555
    switch (network->def->forward.type) {
2556 2557 2558 2559

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2560
        ret = networkShutdownNetworkVirtual(driver, network);
2561 2562 2563
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2564 2565 2566
        ret = networkShutdownNetworkBridge(network);
        break;

2567 2568 2569
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2570
    case VIR_NETWORK_FORWARD_HOSTDEV:
2571
        ret = networkShutdownNetworkExternal(network);
2572 2573 2574
        break;
    }

2575
    /* now that we know it's stopped call the hook if present */
2576
    networkRunHook(network, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2577 2578
                   VIR_HOOK_SUBOP_END);

2579
    network->active = 0;
2580
    virNetworkObjUnsetDefTransient(network);
2581
    return ret;
2582 2583 2584
}


2585
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
2586 2587
                                         const unsigned char *uuid)
{
2588
    virNetworkDriverStatePtr driver = networkGetDriver();
2589 2590
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;
2591

2592
    network = virNetworkObjFindByUUID(driver->networks, uuid);
2593
    if (!network) {
2594 2595
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
2596
        virReportError(VIR_ERR_NO_NETWORK,
2597 2598
                       _("no network with matching uuid '%s'"),
                       uuidstr);
2599
        goto cleanup;
2600 2601
    }

2602 2603 2604
    if (virNetworkLookupByUUIDEnsureACL(conn, network->def) < 0)
        goto cleanup;

2605 2606
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2607
 cleanup:
2608
    virNetworkObjEndAPI(&network);
2609
    return ret;
2610 2611
}

2612
static virNetworkPtr networkLookupByName(virConnectPtr conn,
2613 2614
                                         const char *name)
{
2615
    virNetworkDriverStatePtr driver = networkGetDriver();
2616 2617 2618
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;

2619
    network = virNetworkObjFindByName(driver->networks, name);
2620
    if (!network) {
2621 2622
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
2623
        goto cleanup;
2624 2625
    }

2626 2627 2628
    if (virNetworkLookupByNameEnsureACL(conn, network->def) < 0)
        goto cleanup;

2629 2630
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2631
 cleanup:
2632
    virNetworkObjEndAPI(&network);
2633
    return ret;
2634 2635
}

2636 2637
static int networkConnectNumOfNetworks(virConnectPtr conn)
{
2638
    virNetworkDriverStatePtr driver = networkGetDriver();
2639
    int nactive;
2640

2641 2642 2643
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

2644 2645 2646 2647
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
2648

2649 2650 2651
    return nactive;
}

2652 2653 2654 2655 2656
static int networkConnectListNetworks(virConnectPtr conn,
                                      char **const names,
                                      int nnames)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
2657
    int got = 0;
2658

2659 2660 2661
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

2662 2663 2664 2665
    got = virNetworkObjListGetNames(driver->networks,
                                    true, names, nnames,
                                    virConnectListNetworksCheckACL,
                                    conn);
2666

2667 2668 2669
    return got;
}

2670 2671
static int networkConnectNumOfDefinedNetworks(virConnectPtr conn)
{
2672
    virNetworkDriverStatePtr driver = networkGetDriver();
2673
    int ninactive = 0;
2674

2675 2676 2677
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2678 2679 2680 2681
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
2682

2683 2684 2685
    return ninactive;
}

2686 2687 2688
static int networkConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
2689
    int got = 0;
2690

2691 2692 2693
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2694 2695 2696 2697
    got = virNetworkObjListGetNames(driver->networks,
                                    false, names, nnames,
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
2698 2699 2700
    return got;
}

2701
static int
2702 2703 2704
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
2705
{
2706
    virNetworkDriverStatePtr driver = networkGetDriver();
2707 2708 2709 2710
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

2711 2712 2713
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

2714
    ret = virNetworkObjListExport(conn, driver->networks, nets,
2715 2716
                                  virConnectListAllNetworksCheckACL,
                                  flags);
2717

2718
 cleanup:
2719 2720
    return ret;
}
2721

2722 2723 2724 2725 2726 2727 2728 2729
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
2730
    virNetworkDriverStatePtr driver = networkGetDriver();
2731 2732 2733 2734 2735 2736
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
2737
                                       net, eventID, callback,
2738 2739 2740
                                       opaque, freecb, &ret) < 0)
        ret = -1;

2741
 cleanup:
2742 2743 2744 2745 2746 2747 2748
    return ret;
}

static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
2749
    virNetworkDriverStatePtr driver = networkGetDriver();
2750 2751 2752 2753 2754
    int ret = -1;

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

2755 2756 2757 2758 2759 2760
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;
2761

2762
 cleanup:
2763 2764 2765
    return ret;
}

2766 2767 2768 2769 2770
static int networkIsActive(virNetworkPtr net)
{
    virNetworkObjPtr obj;
    int ret = -1;

2771 2772
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
2773 2774 2775 2776

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

2777 2778
    ret = virNetworkObjIsActive(obj);

2779
 cleanup:
2780
    virNetworkObjEndAPI(&obj);
2781 2782 2783 2784 2785 2786 2787 2788
    return ret;
}

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

2789 2790
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
2791 2792 2793 2794

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

2795 2796
    ret = obj->persistent;

2797
 cleanup:
2798
    virNetworkObjEndAPI(&obj);
2799 2800 2801 2802
    return ret;
}


2803 2804
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
2805 2806 2807
 * unused by the currently configured libvirt networks, as well as by
 * the host system itself (possibly created by someone/something other
 * than libvirt). Set this network's name to that new name.
2808 2809 2810 2811 2812 2813 2814 2815
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{

    int ret = -1, id = 0;
    char *newname = NULL;
2816 2817 2818 2819 2820
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
2821
        p && p[1] == 'd')
2822
        templ = def->bridge;
2823 2824 2825 2826

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
2827 2828 2829 2830 2831 2832 2833
        /* check if this name is used in another libvirt network or
         * there is an existing device with that name. ignore errors
         * from virNetDevExists(), just in case it isn't implemented
         * on this platform (probably impossible).
         */
        if (!(virNetworkBridgeInUse(nets, newname, def->name) ||
              virNetDevExists(newname) == 1)) {
2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885
            VIR_FREE(def->bridge); /*could contain template */
            def->bridge = newname;
            ret = 0;
            goto cleanup;
        }
        VIR_FREE(newname);
    } while (++id <= MAX_BRIDGE_ID);

    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Bridge generation exceeded max id %d"),
                   MAX_BRIDGE_ID);
    ret = 0;
 cleanup:
    if (ret < 0)
        VIR_FREE(newname);
    return ret;
}



/*
 * networkValidateBridgeName() - if no bridge name is set, or if the
 * bridge name contains a %d (indicating that this is a template for
 * the actual name) try to set an appropriate bridge name.  If a
 * bridge name *is* set, make sure it doesn't conflict with any other
 * network's bridge name.
 */
static int
networkBridgeNameValidate(virNetworkObjListPtr nets,
                          virNetworkDefPtr def)
{
    int ret = -1;

    if (def->bridge && !strstr(def->bridge, "%d")) {
        if (virNetworkBridgeInUse(nets, def->bridge, def->name)) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge name '%s' already in use."),
                           def->bridge);
            goto cleanup;
        }
    } else {
        /* Allocate a bridge name */
        if (networkFindUnusedBridgeName(nets, def) < 0)
            goto cleanup;
    }

    ret = 0;
 cleanup:
    return ret;
}


2886
static int
2887
networkValidate(virNetworkDriverStatePtr driver,
2888
                virNetworkDefPtr def)
2889
{
2890
    size_t i, j;
2891 2892
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
2893
    virNetworkIpDefPtr ipdef;
G
Gene Czarcinski 已提交
2894
    bool ipv4def = false, ipv6def = false;
2895
    bool bandwidthAllowed = true;
2896
    bool usesInterface = false, usesAddress = false;
2897 2898 2899 2900

    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
2901 2902 2903
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
        def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
2904

2905 2906 2907 2908
        /* if no bridge name was given in the config, find a name
         * unused by any other libvirt networks and assign it.
         */
        if (networkBridgeNameValidate(driver->networks, def) < 0)
2909 2910 2911
            return -1;

        virNetworkSetBridgeMacAddr(def);
2912 2913
    } else {
        /* They are also the only types that currently support setting
2914 2915
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
2916
         */
2917 2918 2919 2920 2921 2922 2923 2924
        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;
        }
2925 2926 2927 2928 2929
        if (virNetworkDefGetIpByIndex(def, AF_UNSPEC, 0)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2930
                           virNetworkForwardTypeToString(def->forward.type));
2931 2932
            return -1;
        }
2933
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
2934 2935 2936 2937
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2938
                           virNetworkForwardTypeToString(def->forward.type));
2939 2940 2941 2942 2943 2944 2945
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
2946
                           virNetworkForwardTypeToString(def->forward.type));
2947 2948
            return -1;
        }
2949 2950 2951 2952 2953 2954 2955 2956
        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;
        }
2957
        bandwidthAllowed = false;
2958 2959
    }

2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993
    /* we support configs with a single PF defined:
     *   <pf dev='eth0'/>
     * or with a list of netdev names:
     *   <interface dev='eth9'/>
     * OR a list of PCI addresses
     *   <address type='pci' domain='0' bus='4' slot='0' function='1'/>
     * but not any combination of those.
     *
     * Since <interface> and <address> are for some strange reason
     * stored in the same array, we need to cycle through it and check
     * the type of each.
     */
    for (i = 0; i < def->forward.nifs; i++) {
        switch ((virNetworkForwardHostdevDeviceType)
                def->forward.ifs[i].type) {
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
            break;
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI:
            usesAddress = true;
            break;
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NONE:
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST:
            break;
        }
    }
    if ((def->forward.npfs > 0) + usesInterface + usesAddress > 1) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<address>, <interface>, and <pf> elements of "
                         "<forward> in network %s are mutually exclusive"),
                       def->name);
        return -1;
    }

G
Gene Czarcinski 已提交
2994 2995 2996
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
2997 2998 2999
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, i));
         i++) {
G
Gene Czarcinski 已提交
3000 3001 3002 3003 3004
        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 -- "
3005 3006
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023
                    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;
                }
3024 3025 3026
            }
        }
    }
3027 3028 3029 3030 3031 3032

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

3033
    vlanAllowed = ((def->forward.type == VIR_NETWORK_FORWARD_BRIDGE &&
J
Ján Tomko 已提交
3034 3035
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3036 3037
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) ||
                   def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV);
3038 3039

    vlanUsed = def->vlan.nTags > 0;
3040 3041
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
3042 3043 3044 3045 3046
            /* 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.
             */
3047
            if (def->portGroups[i].virtPortProfile) {
3048
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
3049
                    def->portGroups[i].virtPortProfile->virtPortType
3050 3051 3052 3053 3054 3055 3056
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
3057
        }
3058
        if (def->portGroups[i].isDefault) {
3059 3060 3061 3062 3063
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
3064
                               def->name, defaultPortGroup->name,
3065
                               def->portGroups[i].name);
3066
                return -1;
3067
            }
3068
            defaultPortGroup = &def->portGroups[i];
3069
        }
3070 3071 3072 3073 3074 3075 3076 3077 3078
        for (j = i + 1; j < def->nPortGroups; j++) {
            if (STREQ(def->portGroups[i].name, def->portGroups[j].name)) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("multiple <portgroup> elements with the "
                                 "same name (%s) in network '%s'"),
                               def->portGroups[i].name, def->name);
                return -1;
            }
        }
3079 3080 3081 3082 3083 3084 3085 3086
        if (def->portGroups[i].bandwidth && !bandwidthAllowed) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <bandwidth> element in network '%s' "
                             "in portgroup '%s' with forward mode='%s'"),
                           def->name, def->portGroups[i].name,
                           virNetworkForwardTypeToString(def->forward.type));
            return -1;
        }
3087
    }
3088 3089 3090 3091 3092 3093 3094
    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.
         */
3095 3096 3097 3098 3099 3100 3101 3102 3103
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
    return 0;
}

3104 3105
static virNetworkPtr networkCreateXML(virConnectPtr conn, const char *xml)
{
3106
    virNetworkDriverStatePtr driver = networkGetDriver();
3107
    virNetworkDefPtr def;
3108
    virNetworkObjPtr network = NULL;
3109
    virNetworkPtr ret = NULL;
3110
    virObjectEventPtr event = NULL;
3111

3112
    if (!(def = virNetworkDefParseString(xml)))
3113
        goto cleanup;
3114

3115 3116 3117
    if (virNetworkCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3118
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3119
        goto cleanup;
3120

3121 3122 3123
    /* 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.
3124
     */
3125 3126 3127
    if (!(network = virNetworkAssignDef(driver->networks, def,
                                        VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                        VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3128 3129
        goto cleanup;
    def = NULL;
3130

3131
    if (networkStartNetwork(driver, network) < 0) {
3132
        virNetworkRemoveInactive(driver->networks,
3133
                                 network);
3134
        goto cleanup;
3135 3136
    }

3137 3138
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3139 3140
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3141

3142
    VIR_INFO("Creating network '%s'", network->def->name);
3143 3144
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

3145
 cleanup:
3146
    virNetworkDefFree(def);
3147 3148
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3149
    virNetworkObjEndAPI(&network);
3150
    return ret;
3151 3152
}

3153 3154
static virNetworkPtr networkDefineXML(virConnectPtr conn, const char *xml)
{
3155
    virNetworkDriverStatePtr driver = networkGetDriver();
3156
    virNetworkDefPtr def = NULL;
3157
    bool freeDef = true;
3158
    virNetworkObjPtr network = NULL;
3159
    virNetworkPtr ret = NULL;
3160
    virObjectEventPtr event = NULL;
3161

3162
    if (!(def = virNetworkDefParseString(xml)))
3163
        goto cleanup;
3164

3165 3166 3167
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3168
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3169
        goto cleanup;
3170

3171
    if (!(network = virNetworkAssignDef(driver->networks, def, 0)))
J
Ján Tomko 已提交
3172
        goto cleanup;
3173

3174
    /* def was assigned to network object */
3175
    freeDef = false;
3176 3177

    if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
3178
        if (!virNetworkObjIsActive(network)) {
3179
            virNetworkRemoveInactive(driver->networks, network);
3180 3181
            goto cleanup;
        }
3182 3183 3184 3185 3186
        /* 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);
3187 3188 3189
        goto cleanup;
    }

3190
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3191 3192
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3193

3194 3195
    VIR_INFO("Defining network '%s'", def->name);
    ret = virGetNetwork(conn, def->name, def->uuid);
3196

3197
 cleanup:
3198 3199
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3200
    if (freeDef)
J
Ján Tomko 已提交
3201
        virNetworkDefFree(def);
3202
    virNetworkObjEndAPI(&network);
3203
    return ret;
3204 3205
}

3206
static int
3207 3208
networkUndefine(virNetworkPtr net)
{
3209
    virNetworkDriverStatePtr driver = networkGetDriver();
3210
    virNetworkObjPtr network;
3211
    int ret = -1;
3212
    bool active = false;
3213
    virObjectEventPtr event = NULL;
3214

3215
    if (!(network = networkObjFromNetwork(net)))
3216
        goto cleanup;
3217

3218 3219 3220
    if (virNetworkUndefineEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3221 3222
    if (virNetworkObjIsActive(network))
        active = true;
3223

3224
    /* remove autostart link */
3225
    if (virNetworkDeleteConfig(driver->networkConfigDir,
3226 3227
                               driver->networkAutostartDir,
                               network) < 0)
3228
        goto cleanup;
3229

3230 3231
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3232 3233
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3234

3235
    VIR_INFO("Undefining network '%s'", network->def->name);
3236
    if (!active) {
3237
        if (networkRemoveInactive(driver, network) < 0)
3238
            goto cleanup;
3239 3240 3241 3242 3243 3244
    } 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);
3245 3246
    }

3247
    ret = 0;
3248

3249
 cleanup:
3250 3251
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3252
    virNetworkObjEndAPI(&network);
3253
    return ret;
3254 3255
}

3256 3257 3258 3259 3260 3261 3262 3263
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3264
    virNetworkDriverStatePtr driver = networkGetDriver();
3265
    virNetworkObjPtr network = NULL;
3266 3267
    int isActive, ret = -1;
    size_t i;
3268 3269
    virNetworkIpDefPtr ipdef;
    bool oldDhcpActive = false;
3270
    bool needFirewallRefresh = false;
3271

3272 3273 3274 3275 3276

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3277
    if (!(network = networkObjFromNetwork(net)))
3278 3279
        goto cleanup;

3280 3281 3282
    if (virNetworkUpdateEnsureACL(net->conn, network->def, flags) < 0)
        goto cleanup;

3283
    /* see if we are listening for dhcp pre-modification */
3284 3285 3286
    for (i = 0;
         (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
         i++) {
3287 3288 3289 3290 3291 3292
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3293 3294
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3295
     */
3296
    isActive = virNetworkObjIsActive(network);
3297 3298
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3299 3300 3301 3302 3303 3304 3305
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322
    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).
                 */
3323
                networkRemoveFirewallRules(network->def);
3324 3325 3326 3327 3328 3329 3330 3331
                needFirewallRefresh = true;
                break;
            default:
                break;
            }
        }
    }

3332
    /* update the network config in memory/on disk */
3333 3334
    if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0) {
        if (needFirewallRefresh)
3335
            ignore_value(networkAddFirewallRules(network->def));
3336 3337 3338
        goto cleanup;
    }

3339
    if (needFirewallRefresh && networkAddFirewallRules(network->def) < 0)
3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362
        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.
             */
3363
            if (networkRestartDhcpDaemon(driver, network) < 0)
3364 3365
                goto cleanup;

3366 3367 3368 3369 3370 3371 3372 3373
        } 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;

3374 3375 3376
            for (i = 0;
                 (ipdef = virNetworkDefGetIpByIndex(network->def, AF_INET, i));
                 i++) {
3377 3378 3379 3380 3381 3382 3383
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3384 3385
                 networkRestartDhcpDaemon(driver, network) < 0) ||
                networkRefreshDhcpDaemon(driver, network) < 0) {
3386 3387 3388 3389
                goto cleanup;
            }

        } else if (section == VIR_NETWORK_SECTION_DNS_HOST ||
3390 3391 3392 3393 3394 3395
                   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.
             */
3396
            if (networkRefreshDhcpDaemon(driver, network) < 0)
3397 3398 3399 3400 3401 3402 3403 3404
                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.
             */
3405
            if (networkRefreshRadvd(driver, network) < 0)
3406 3407 3408 3409
                goto cleanup;
        }

        /* save current network state to disk */
3410
        if ((ret = virNetworkSaveStatus(driver->stateDir,
3411
                                        network)) < 0) {
3412
            goto cleanup;
3413
        }
3414 3415
    }
    ret = 0;
3416
 cleanup:
3417
    virNetworkObjEndAPI(&network);
3418 3419 3420
    return ret;
}

3421 3422
static int networkCreate(virNetworkPtr net)
{
3423
    virNetworkDriverStatePtr driver = networkGetDriver();
3424 3425
    virNetworkObjPtr network;
    int ret = -1;
3426
    virObjectEventPtr event = NULL;
3427

3428
    if (!(network = networkObjFromNetwork(net)))
3429
        goto cleanup;
3430

3431 3432 3433
    if (virNetworkCreateEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3434
    if ((ret = networkStartNetwork(driver, network)) < 0)
3435
        goto cleanup;
3436

3437 3438
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3439 3440
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3441

3442
 cleanup:
3443 3444
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3445
    virNetworkObjEndAPI(&network);
3446
    return ret;
3447 3448
}

3449 3450
static int networkDestroy(virNetworkPtr net)
{
3451
    virNetworkDriverStatePtr driver = networkGetDriver();
3452 3453
    virNetworkObjPtr network;
    int ret = -1;
3454
    virObjectEventPtr event = NULL;
3455

3456
    if (!(network = networkObjFromNetwork(net)))
3457
        goto cleanup;
3458

3459 3460 3461
    if (virNetworkDestroyEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3462
    if (!virNetworkObjIsActive(network)) {
3463
        virReportError(VIR_ERR_OPERATION_INVALID,
3464 3465
                       _("network '%s' is not active"),
                       network->def->name);
3466 3467 3468
        goto cleanup;
    }

3469
    if ((ret = networkShutdownNetwork(driver, network)) < 0)
3470 3471
        goto cleanup;

3472 3473
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3474 3475
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
3476

3477
    if (!network->persistent &&
3478
        networkRemoveInactive(driver, network) < 0) {
3479 3480
        ret = -1;
        goto cleanup;
3481
    }
3482

3483
 cleanup:
3484 3485
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3486
    virNetworkObjEndAPI(&network);
3487 3488 3489
    return ret;
}

3490
static char *networkGetXMLDesc(virNetworkPtr net,
3491
                               unsigned int flags)
3492
{
3493
    virNetworkObjPtr network;
3494
    virNetworkDefPtr def;
3495
    char *ret = NULL;
3496

3497
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
3498

3499 3500
    if (!(network = networkObjFromNetwork(net)))
        return ret;
3501

3502 3503 3504
    if (virNetworkGetXMLDescEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3505 3506 3507 3508 3509 3510
    if ((flags & VIR_NETWORK_XML_INACTIVE) && network->newDef)
        def = network->newDef;
    else
        def = network->def;

    ret = virNetworkDefFormat(def, flags);
3511

3512
 cleanup:
3513
    virNetworkObjEndAPI(&network);
3514
    return ret;
3515 3516 3517
}

static char *networkGetBridgeName(virNetworkPtr net) {
3518 3519 3520
    virNetworkObjPtr network;
    char *bridge = NULL;

3521 3522
    if (!(network = networkObjFromNetwork(net)))
        return bridge;
3523

3524 3525 3526
    if (virNetworkGetBridgeNameEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3527
    if (!(network->def->bridge)) {
3528 3529 3530
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
                       network->def->name);
3531 3532 3533
        goto cleanup;
    }

3534
    ignore_value(VIR_STRDUP(bridge, network->def->bridge));
3535

3536
 cleanup:
3537
    virNetworkObjEndAPI(&network);
3538 3539 3540 3541
    return bridge;
}

static int networkGetAutostart(virNetworkPtr net,
J
Ján Tomko 已提交
3542
                               int *autostart)
3543
{
3544 3545
    virNetworkObjPtr network;
    int ret = -1;
3546

3547 3548
    if (!(network = networkObjFromNetwork(net)))
        return ret;
3549

3550 3551 3552
    if (virNetworkGetAutostartEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3553
    *autostart = network->autostart;
3554
    ret = 0;
3555

3556
 cleanup:
3557
    virNetworkObjEndAPI(&network);
3558
    return ret;
3559 3560 3561
}

static int networkSetAutostart(virNetworkPtr net,
3562 3563
                               int autostart)
{
3564
    virNetworkDriverStatePtr driver = networkGetDriver();
3565
    virNetworkObjPtr network;
3566
    char *configFile = NULL, *autostartLink = NULL;
3567
    int ret = -1;
3568

3569

3570
    if (!(network = networkObjFromNetwork(net)))
3571
        goto cleanup;
3572

3573 3574 3575
    if (virNetworkSetAutostartEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3576
    if (!network->persistent) {
3577 3578
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
3579 3580 3581
        goto cleanup;
    }

3582 3583
    autostart = (autostart != 0);

3584
    if (network->autostart != autostart) {
3585
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir, network->def->name)) == NULL)
3586
            goto cleanup;
3587
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, network->def->name)) == NULL)
3588 3589
            goto cleanup;

3590
        if (autostart) {
3591
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
3592
                virReportSystemError(errno,
3593 3594
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
3595 3596
                goto cleanup;
            }
3597

3598
            if (symlink(configFile, autostartLink) < 0) {
3599
                virReportSystemError(errno,
3600
                                     _("Failed to create symlink '%s' to '%s'"),
3601
                                     autostartLink, configFile);
3602 3603 3604
                goto cleanup;
            }
        } else {
3605
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
3606
                virReportSystemError(errno,
3607
                                     _("Failed to delete symlink '%s'"),
3608
                                     autostartLink);
3609 3610
                goto cleanup;
            }
3611 3612
        }

3613
        network->autostart = autostart;
3614
    }
3615
    ret = 0;
3616

3617
 cleanup:
3618 3619
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
3620
    virNetworkObjEndAPI(&network);
3621
    return ret;
3622 3623
}

3624
static int
3625 3626 3627 3628
networkGetDHCPLeases(virNetworkPtr network,
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
3629
{
3630
    virNetworkDriverStatePtr driver = networkGetDriver();
3631 3632 3633
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
3634
    ssize_t size = 0;
3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648
    int custom_lease_file_len = 0;
    bool need_results = !!leases;
    long long currtime = 0;
    long long expirytime_tmp = -1;
    bool ipv6 = false;
    char *lease_entries = NULL;
    char *custom_lease_file = NULL;
    const char *ip_tmp = NULL;
    const char *mac_tmp = NULL;
    virJSONValuePtr lease_tmp = NULL;
    virJSONValuePtr leases_array = NULL;
    virNetworkIpDefPtr ipdef_tmp = NULL;
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
3649 3650 3651 3652 3653 3654 3655 3656 3657
    virNetworkObjPtr obj;

    virCheckFlags(0, -1);

    if (!(obj = networkObjFromNetwork(network)))
        return -1;

    if (virNetworkGetDHCPLeasesEnsureACL(network->conn, obj->def) < 0)
        goto cleanup;
3658 3659

    /* Retrieve custom leases file location */
3660
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, obj->def->bridge);
3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703

    /* Read entire contents */
    if ((custom_lease_file_len = virFileReadAll(custom_lease_file,
                                                VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX,
                                                &lease_entries)) < 0) {
        /* Even though src/network/leaseshelper.c guarantees the existence of
         * leases file (even if no leases are present), and the control reaches
         * here, instead of reporting error, return 0 leases */
        rv = 0;
        goto error;
    }

    if (custom_lease_file_len) {
        if (!(leases_array = virJSONValueFromString(lease_entries))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("invalid json in file: %s"), custom_lease_file);
            goto error;
        }

        if ((size = virJSONValueArraySize(leases_array)) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("couldn't fetch array of leases"));
            goto error;
        }
    }

    currtime = (long long) time(NULL);

    for (i = 0; i < size; i++) {
        if (!(lease_tmp = virJSONValueArrayGet(leases_array, i))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to parse json"));
            goto error;
        }

        if (!(mac_tmp = virJSONValueObjectGetString(lease_tmp, "mac-address"))) {
            /* leaseshelper program guarantees that lease will be stored only if
             * mac-address is known otherwise not */
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("found lease without mac-address"));
            goto error;
        }

3704
        if (mac && virMacAddrCompare(mac, mac_tmp))
3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754
            continue;

        if (virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime_tmp) < 0) {
            /* A lease cannot be present without expiry-time */
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("found lease without expiry-time"));
            goto error;
        }

        /* Do not report expired lease */
        if (expirytime_tmp < currtime)
            continue;

        if (need_results) {
            if (VIR_ALLOC(lease) < 0)
                goto error;

            lease->expirytime = expirytime_tmp;

            if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address"))) {
                /* A lease without ip-address makes no sense */
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("found lease without ip-address"));
                goto error;
            }

            /* Unlike IPv4, IPv6 uses ':' instead of '.' as separator */
            ipv6 = strchr(ip_tmp, ':') ? true : false;
            lease->type = ipv6 ? VIR_IP_ADDR_TYPE_IPV6 : VIR_IP_ADDR_TYPE_IPV4;

            /* Obtain prefix */
            for (j = 0; j < obj->def->nips; j++) {
                ipdef_tmp = &obj->def->ips[j];

                if (ipv6 && VIR_SOCKET_ADDR_IS_FAMILY(&ipdef_tmp->address,
                                                      AF_INET6)) {
                    lease->prefix = ipdef_tmp->prefix;
                    break;
                }
                if (!ipv6 && VIR_SOCKET_ADDR_IS_FAMILY(&ipdef_tmp->address,
                                                      AF_INET)) {
                    lease->prefix = virSocketAddrGetIpPrefix(&ipdef_tmp->address,
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
3755
                (VIR_STRDUP(lease->iface, obj->def->bridge) < 0))
3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787
                goto error;

            /* Fields that can be NULL */
            if ((VIR_STRDUP(lease->iaid,
                            virJSONValueObjectGetString(lease_tmp, "iaid")) < 0) ||
                (VIR_STRDUP(lease->clientid,
                            virJSONValueObjectGetString(lease_tmp, "client-id")) < 0) ||
                (VIR_STRDUP(lease->hostname,
                            virJSONValueObjectGetString(lease_tmp, "hostname")) < 0))
                goto error;

            if (VIR_INSERT_ELEMENT(leases_ret, nleases, nleases, lease) < 0)
                goto error;

        } else {
            nleases++;
        }

        VIR_FREE(lease);
    }

    if (leases_ret) {
        /* NULL terminated array */
        ignore_value(VIR_REALLOC_N(leases_ret, nleases + 1));
        *leases = leases_ret;
        leases_ret = NULL;
    }

    rv = nleases;

 cleanup:
    VIR_FREE(lease);
3788
    VIR_FREE(lease_entries);
3789 3790
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
3791

3792
    virNetworkObjEndAPI(&obj);
3793

3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804
    return rv;

 error:
    if (leases_ret) {
        for (i = 0; i < nleases; i++)
            virNetworkDHCPLeaseFree(leases_ret[i]);
        VIR_FREE(leases_ret);
    }
    goto cleanup;
}

3805 3806

static virNetworkDriver networkDriver = {
3807
    .name = "bridge",
3808 3809 3810 3811 3812
    .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 */
3813 3814
    .connectNetworkEventRegisterAny = networkConnectNetworkEventRegisterAny, /* 1.2.1 */
    .connectNetworkEventDeregisterAny = networkConnectNetworkEventDeregisterAny, /* 1.2.1 */
3815 3816
    .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
    .networkLookupByName = networkLookupByName, /* 0.2.0 */
3817 3818
    .networkCreateXML = networkCreateXML, /* 0.2.0 */
    .networkDefineXML = networkDefineXML, /* 0.2.0 */
3819
    .networkUndefine = networkUndefine, /* 0.2.0 */
3820
    .networkUpdate = networkUpdate, /* 0.10.2 */
3821
    .networkCreate = networkCreate, /* 0.2.0 */
3822 3823 3824 3825 3826 3827 3828
    .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 */
3829
    .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.2.6 */
3830 3831 3832
};

static virStateDriver networkStateDriver = {
3833
    .name = "bridge",
3834
    .stateInitialize  = networkStateInitialize,
3835
    .stateAutoStart  = networkStateAutoStart,
3836 3837
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
3838 3839
};

3840 3841
int networkRegister(void)
{
3842
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
3843
        return -1;
3844 3845
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
3846 3847
    return 0;
}
3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859

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

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

/* networkAllocateActualDevice:
3860
 * @dom: domain definition that @iface belongs to
3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871
 * @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
3872 3873
networkAllocateActualDevice(virDomainDefPtr dom,
                            virDomainNetDefPtr iface)
3874
{
3875
    virNetworkDriverStatePtr driver = networkGetDriver();
3876
    virDomainNetType actualType = iface->type;
3877 3878
    virNetworkObjPtr network = NULL;
    virNetworkDefPtr netdef = NULL;
3879
    virNetDevBandwidthPtr bandwidth = NULL;
3880 3881 3882
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
3883
    virNetworkForwardIfDefPtr dev = NULL;
3884
    size_t i;
3885 3886 3887
    int ret = -1;

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
3888
        goto validate;
3889 3890 3891 3892

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

3893
    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
3894
    if (!network) {
3895 3896 3897
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
3898
        goto error;
3899 3900
    }
    netdef = network->def;
3901

3902 3903 3904 3905 3906 3907 3908
    if (!virNetworkObjIsActive(network)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

3909 3910 3911
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

3912 3913 3914
    /* 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.
J
Ján Tomko 已提交
3915
     */
3916 3917 3918 3919 3920 3921
    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.
     */
3922 3923 3924 3925 3926 3927

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

3928 3929
    if (bandwidth && virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
                                            bandwidth) < 0)
3930
        goto error;
3931

3932 3933 3934 3935 3936 3937 3938 3939
    /* 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;

3940 3941
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
3942

3943 3944 3945 3946 3947 3948 3949 3950 3951 3952
    if (iface->trustGuestRxFilters)
       iface->data.network.actual->trustGuestRxFilters
          = iface->trustGuestRxFilters;
    else if (portgroup && portgroup->trustGuestRxFilters)
       iface->data.network.actual->trustGuestRxFilters
          = portgroup->trustGuestRxFilters;
    else if (netdef->trustGuestRxFilters)
       iface->data.network.actual->trustGuestRxFilters
          = netdef->trustGuestRxFilters;

3953 3954 3955
    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE)) {
3956
        /* for these forward types, the actual net type really *is*
3957
         * NETWORK; we just keep the info from the portgroup in
3958
         * iface->data.network.actual
J
Ján Tomko 已提交
3959
         */
3960
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
3961

3962
        /* we also store the bridge device and macTableManager settings
3963 3964 3965 3966 3967 3968 3969
         * in iface->data.network.actual->data.bridge for later use
         * after the domain's tap device is created (to attach to the
         * bridge and set flood/learning mode on the tap device)
         */
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
            goto error;
3970 3971
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
3972

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

3976
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
3977
               netdef->bridge) {
3978 3979 3980 3981 3982

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

3983
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
3984 3985
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
3986
            goto error;
3987 3988
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
3989

3990 3991 3992 3993 3994 3995 3996 3997
        /* 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) {
3998
            goto error;
3999 4000 4001 4002 4003 4004 4005 4006 4007 4008
        }
        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);
4009
                goto error;
4010 4011 4012
            }
        }

4013
    } else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4014

4015
        virDomainHostdevSubsysPCIBackendType backend;
4016

4017
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
4018
        if (networkCreateInterfacePool(netdef) < 0)
4019 4020 4021
            goto error;

        /* pick first dev with 0 connections */
4022 4023 4024
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038
                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;
4039
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
4040
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
4041
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
4042

E
Eric Blake 已提交
4043
        switch (netdef->forward.driverName) {
4044
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
4045
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4046 4047
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
4048
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
4049 4050
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
4051
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062
            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;

4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087
        /* 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;
            }
        }

4088 4089 4090 4091
    } 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)) {
4092 4093 4094 4095 4096 4097

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

        /* Set type=direct and appropriate <source mode='xxx'/> */
4098
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
4099
        switch (netdef->forward.type) {
4100
        case VIR_NETWORK_FORWARD_BRIDGE:
4101
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
4102 4103
            break;
        case VIR_NETWORK_FORWARD_PRIVATE:
4104
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
4105 4106
            break;
        case VIR_NETWORK_FORWARD_VEPA:
4107
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
4108 4109
            break;
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
4110
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PASSTHRU;
4111 4112 4113
            break;
        }

4114 4115 4116 4117 4118 4119 4120 4121
        /* 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) {
4122
            goto error;
4123
        }
4124
        virtport = iface->data.network.actual->virtPortProfile;
4125
        if (virtport) {
4126 4127 4128 4129 4130 4131 4132 4133
            /* 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);
4134
                goto error;
4135 4136
            }
        }
4137

4138 4139 4140
        /* 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).
         */
4141
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4142 4143 4144 4145
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4146
            goto error;
4147 4148 4149
        } else {
            /* pick an interface from the pool */

4150
            if (networkCreateInterfacePool(netdef) < 0)
4151 4152
                goto error;

4153 4154 4155 4156 4157
            /* 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.
4158
             */
4159 4160
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4161 4162 4163
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4164

4165
                /* pick first dev with 0 connections */
4166 4167 4168
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4169 4170 4171 4172 4173
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4174
                dev = &netdef->forward.ifs[0];
4175 4176 4177
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4178 4179 4180 4181
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4182 4183 4184 4185
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4186
                goto error;
4187
            }
4188 4189
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
4190
                goto error;
4191 4192 4193
        }
    }

4194
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
4195
        goto error;
4196

4197
 validate:
4198 4199 4200 4201 4202
    /* 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.
     */

4203
    if (virDomainNetGetActualVlan(iface)) {
4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232
        /* 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);
4233

4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252
        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 */
4253
            netdef->connections--;
4254 4255 4256 4257
            if (dev)
                dev->connections--;
            goto error;
        }
4258 4259
    }

4260
    ret = 0;
4261

4262
 cleanup:
4263
    virNetworkObjEndAPI(&network);
4264 4265
    return ret;

4266
 error:
4267
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4268 4269 4270
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4271
    goto cleanup;
4272 4273 4274
}

/* networkNotifyActualDevice:
4275
 * @dom: domain definition that @iface belongs to
4276 4277 4278 4279 4280 4281 4282 4283 4284 4285
 * @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
4286 4287
networkNotifyActualDevice(virDomainDefPtr dom,
                          virDomainNetDefPtr iface)
4288
{
4289
    virNetworkDriverStatePtr driver = networkGetDriver();
4290
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4291 4292
    virNetworkObjPtr network;
    virNetworkDefPtr netdef;
4293
    virNetworkForwardIfDefPtr dev = NULL;
4294 4295
    size_t i;
    int ret = -1;
4296 4297

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
J
Ján Tomko 已提交
4298
        return 0;
4299

4300
    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
4301
    if (!network) {
4302 4303 4304
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4305 4306 4307 4308
        goto error;
    }
    netdef = network->def;

4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319
    /* if we're restarting libvirtd after an upgrade from a version
     * that didn't save bridge name in actualNetDef for
     * actualType==network, we need to copy it in so that it will be
     * available in all cases
     */
    if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK &&
        !iface->data.network.actual->data.bridge.brname &&
        (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                    netdef->bridge) < 0))
            goto error;

4320
    if (!iface->data.network.actual ||
4321 4322
        (actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
4323 4324
        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
        goto success;
4325 4326
    }

4327
    if (networkCreateInterfacePool(netdef) < 0)
4328
        goto error;
4329

4330
    if (netdef->forward.nifs == 0) {
4331
        virReportError(VIR_ERR_INTERNAL_ERROR,
4332 4333
                       _("network '%s' uses a direct or hostdev mode, "
                         "but has no forward dev and no interface pool"),
4334
                       netdef->name);
4335
        goto error;
4336
    }
4337

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

4341 4342 4343 4344 4345 4346 4347 4348 4349
        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 */
4350 4351
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4352
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4353 4354
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4355 4356 4357 4358 4359
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4360
            virReportError(VIR_ERR_INTERNAL_ERROR,
4361 4362
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4363
                           netdef->name, actualDev);
4364
            goto error;
4365 4366
        }

4367
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4368 4369
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4370
         */
4371
        if ((dev->connections > 0) &&
4372 4373
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4374 4375
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
4376
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4377
            virReportError(VIR_ERR_INTERNAL_ERROR,
4378 4379
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
4380
                           netdef->name, actualDev);
4381
            goto error;
4382
        }
4383

4384
        /* we are now assured of success, so mark the allocation */
4385
        dev->connections++;
4386
        VIR_DEBUG("Using physical device %s, connections %d",
4387
                  dev->device.dev, dev->connections);
4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400

    }  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 */
4401 4402
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4403
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4404
                virDevicePCIAddressEqual(&hostdev->source.subsys.u.pci.addr,
4405 4406
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4407 4408 4409 4410 4411 4412 4413 4414 4415
                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,
4416 4417 4418 4419
                           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);
J
Ján Tomko 已提交
4420
            goto error;
4421 4422 4423 4424 4425 4426 4427
        }

        /* 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) &&
4428
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444
            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);
4445 4446
    }

4447
 success:
4448 4449 4450
    netdef->connections++;
    VIR_DEBUG("Using network %s, %d connections",
              netdef->name, netdef->connections);
4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461

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

4462
    ret = 0;
4463
 cleanup:
4464
    virNetworkObjEndAPI(&network);
4465
    return ret;
4466

4467
 error:
4468
    goto cleanup;
4469 4470 4471 4472
}


/* networkReleaseActualDevice:
4473
 * @dom: domain definition that @iface belongs to
4474 4475 4476 4477 4478 4479 4480 4481 4482 4483
 * @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
4484 4485
networkReleaseActualDevice(virDomainDefPtr dom,
                           virDomainNetDefPtr iface)
4486
{
4487
    virNetworkDriverStatePtr driver = networkGetDriver();
4488
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4489
    virNetworkObjPtr network;
4490
    virNetworkDefPtr netdef;
4491
    virNetworkForwardIfDefPtr dev = NULL;
4492 4493
    size_t i;
    int ret = -1;
4494 4495

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
J
Ján Tomko 已提交
4496
        return 0;
4497

4498
    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
4499
    if (!network) {
4500 4501 4502
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4503 4504 4505 4506
        goto error;
    }
    netdef = network->def;

4507 4508
    if (iface->data.network.actual &&
        (netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
4509 4510 4511 4512 4513
         netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) &&
        networkUnplugBandwidth(network, iface) < 0)
        goto error;

4514 4515 4516
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
4517 4518
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
4519 4520
    }

4521
    if (netdef->forward.nifs == 0) {
4522
        virReportError(VIR_ERR_INTERNAL_ERROR,
4523
                       _("network '%s' uses a direct/hostdev mode, but "
4524 4525
                         "has no forward dev and no interface pool"),
                       netdef->name);
4526
        goto error;
4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538
    }

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

4540 4541
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4542
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4543 4544
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4545 4546 4547
                break;
            }
        }
4548

4549
        if (!dev) {
4550
            virReportError(VIR_ERR_INTERNAL_ERROR,
4551 4552
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4553
                           netdef->name, actualDev);
4554
            goto error;
4555 4556
        }

4557
        dev->connections--;
4558
        VIR_DEBUG("Releasing physical device %s, connections %d",
4559
                  dev->device.dev, dev->connections);
4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570

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

4571 4572
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4573
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4574
                virDevicePCIAddressEqual(&hostdev->source.subsys.u.pci.addr,
4575 4576
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4577 4578 4579 4580 4581 4582 4583 4584 4585
                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,
4586 4587 4588 4589
                           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);
J
Ján Tomko 已提交
4590
            goto error;
4591 4592 4593 4594 4595 4596 4597
        }

        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);
J
Ján Tomko 已提交
4598
    }
4599

4600
 success:
4601
    if (iface->data.network.actual) {
4602
        netdef->connections--;
4603 4604
        VIR_DEBUG("Releasing network %s, %d connections",
                  netdef->name, netdef->connections);
4605

4606 4607 4608 4609
        /* finally we can call the 'unplugged' hook script if any */
        networkRunHook(network, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
                       VIR_HOOK_SUBOP_BEGIN);
    }
4610
    ret = 0;
4611
 cleanup:
4612
    virNetworkObjEndAPI(&network);
4613 4614 4615 4616
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4617
    return ret;
4618

4619
 error:
4620
    goto cleanup;
4621
}
4622 4623 4624 4625 4626 4627

/*
 * networkGetNetworkAddress:
 * @netname: the name of a network
 * @netaddr: string representation of IP address for that network.
 *
4628
 * Attempt to return an IP address associated with the named
4629 4630 4631 4632
 * 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.
 *
4633
 * Note: This function returns the first IP address it finds. It might
4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644
 * 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)
{
4645
    virNetworkDriverStatePtr driver = networkGetDriver();
4646
    int ret = -1;
4647
    virNetworkObjPtr network;
4648 4649 4650 4651
    virNetworkDefPtr netdef;
    virNetworkIpDefPtr ipdef;
    virSocketAddr addr;
    virSocketAddrPtr addrptr = NULL;
4652
    char *dev_name = NULL;
4653 4654

    *netaddr = NULL;
4655
    network = virNetworkObjFindByName(driver->networks, netname);
4656
    if (!network) {
4657 4658 4659
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       netname);
4660
        goto cleanup;
4661 4662 4663
    }
    netdef = network->def;

4664
    switch (netdef->forward.type) {
4665 4666 4667
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
4668
        ipdef = virNetworkDefGetIpByIndex(netdef, AF_UNSPEC, 0);
4669
        if (!ipdef) {
4670
            virReportError(VIR_ERR_INTERNAL_ERROR,
4671
                           _("network '%s' doesn't have an IP address"),
4672
                           netdef->name);
4673
            goto cleanup;
4674 4675 4676 4677 4678
        }
        addrptr = &ipdef->address;
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
4679
        if ((dev_name = netdef->bridge))
4680 4681 4682 4683 4684 4685 4686 4687
            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:
4688 4689
        if ((netdef->forward.nifs > 0) && netdef->forward.ifs)
            dev_name = netdef->forward.ifs[0].device.dev;
4690

4691
        if (!dev_name) {
4692 4693 4694
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' has no associated interface or bridge"),
                           netdef->name);
4695
            goto cleanup;
4696 4697 4698 4699
        }
        break;
    }

4700
    if (dev_name) {
4701
        if (virNetDevGetIPAddress(dev_name, &addr) < 0)
4702
            goto cleanup;
4703
        addrptr = &addr;
4704 4705
    }

4706 4707
    if (!(addrptr &&
          (*netaddr = virSocketAddrFormat(addrptr)))) {
4708
        goto cleanup;
4709 4710
    }

4711
    ret = 0;
4712
 cleanup:
4713
    virNetworkObjEndAPI(&network);
4714 4715
    return ret;
}
4716 4717 4718 4719

/**
 * networkCheckBandwidth:
 * @net: network QoS
4720
 * @ifaceBand: interface QoS (may be NULL if no QoS)
4721
 * @oldBandwidth: new interface QoS (may be NULL if no QoS)
4722
 * @ifaceMac: interface MAC (used in error messages for identification)
4723 4724
 * @new_rate: new rate for non guaranteed class
 *
4725 4726 4727 4728 4729 4730 4731 4732
 * Function checks if @ifaceBand can be satisfied on @net. However, sometimes it
 * may happen that the interface that @ifaceBand corresponds to is already
 * plugged into the @net and the bandwidth is to be updated. In that case we
 * need to check if new bandwidth can be satisfied. If that's the case
 * @ifaceBand should point to new bandwidth settings and @oldBandwidth to
 * current ones. If you want to suppress this functionality just pass
 * @oldBandwidth == NULL.
 *
4733 4734 4735 4736 4737 4738
 * 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,
4739
                      virNetDevBandwidthPtr ifaceBand,
4740
                      virNetDevBandwidthPtr oldBandwidth,
4741
                      virMacAddr ifaceMac,
4742 4743 4744 4745 4746 4747 4748 4749
                      unsigned long long *new_rate)
{
    int ret = -1;
    virNetDevBandwidthPtr netBand = net->def->bandwidth;
    unsigned long long tmp_floor_sum = net->floor_sum;
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

4750
    virMacAddrFormat(&ifaceMac, ifmac);
4751 4752 4753 4754 4755 4756 4757 4758 4759 4760

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

4761 4762
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor)) ||
4763 4764
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
4765
        return 1;
4766
    }
4767 4768

    tmp_new_rate = netBand->in->average;
4769 4770 4771 4772
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797

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

4798 4799
    if (new_rate)
        *new_rate = tmp_new_rate;
4800 4801
    ret = 0;

4802
 cleanup:
4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818
    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)
{
4819
    ssize_t ret = 0;
4820

4821
    ret = virBitmapNextClearBit(net->class_id, -1);
4822

4823
    if (ret < 0 || virBitmapSetBit(net->class_id, ret) < 0)
4824 4825 4826 4827 4828
        return -1;

    return ret;
}

4829

4830
static int
4831 4832 4833 4834
networkPlugBandwidthImpl(virNetworkObjPtr net,
                         virDomainNetDefPtr iface,
                         virNetDevBandwidthPtr ifaceBand,
                         unsigned long long new_rate)
4835
{
4836
    virNetworkDriverStatePtr driver = networkGetDriver();
4837
    ssize_t class_id = 0;
4838 4839
    int plug_ret;
    int ret = -1;
4840 4841 4842 4843 4844 4845 4846 4847

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

4848 4849
    plug_ret = virNetDevBandwidthPlug(net->def->bridge, net->def->bandwidth,
                                      &iface->mac, ifaceBand, class_id);
4850 4851 4852 4853 4854 4855 4856 4857
    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 */
4858
    net->floor_sum += ifaceBand->in->floor;
4859
    /* update status file */
4860
    if (virNetworkSaveStatus(driver->stateDir, net) < 0) {
4861
        ignore_value(virBitmapClearBit(net->class_id, class_id));
4862
        net->floor_sum -= ifaceBand->in->floor;
4863 4864 4865 4866
        iface->data.network.actual->class_id = 0;
        ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
        goto cleanup;
    }
4867 4868
    /* update rate for non guaranteed NICs */
    new_rate -= net->floor_sum;
4869
    if (virNetDevBandwidthUpdateRate(net->def->bridge, 2,
4870 4871 4872 4873 4874
                                     net->def->bandwidth, new_rate) < 0)
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
                 net->def->bridge);

    ret = 0;
4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914
 cleanup:
    return ret;
}


static int
networkPlugBandwidth(virNetworkObjPtr net,
                     virDomainNetDefPtr iface)
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);

    if ((plug_ret = networkCheckBandwidth(net, ifaceBand, NULL,
                                          iface->mac, &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;
    }

    if (networkPlugBandwidthImpl(net, iface, ifaceBand, new_rate) < 0)
        goto cleanup;

    ret = 0;
4915

4916
 cleanup:
4917 4918 4919 4920 4921 4922 4923
    return ret;
}

static int
networkUnplugBandwidth(virNetworkObjPtr net,
                       virDomainNetDefPtr iface)
{
4924
    virNetworkDriverStatePtr driver = networkGetDriver();
4925 4926
    int ret = 0;
    unsigned long long new_rate;
4927
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
4928 4929 4930

    if (iface->data.network.actual &&
        iface->data.network.actual->class_id) {
4931 4932 4933 4934 4935
        if (!net->def->bandwidth || !net->def->bandwidth->in) {
            VIR_WARN("Network %s has no bandwidth but unplug requested",
                     net->def->name);
            goto cleanup;
        }
4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946
        /* 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 */
4947
        net->floor_sum -= ifaceBand->in->floor;
4948 4949 4950 4951
        /* return class ID */
        ignore_value(virBitmapClearBit(net->class_id,
                                       iface->data.network.actual->class_id));
        /* update status file */
4952
        if (virNetworkSaveStatus(driver->stateDir, net) < 0) {
4953
            net->floor_sum += ifaceBand->in->floor;
4954 4955 4956 4957
            ignore_value(virBitmapSetBit(net->class_id,
                                         iface->data.network.actual->class_id));
            goto cleanup;
        }
4958 4959
        /* update rate for non guaranteed NICs */
        new_rate -= net->floor_sum;
4960
        if (virNetDevBandwidthUpdateRate(net->def->bridge, 2,
4961 4962 4963 4964 4965 4966 4967
                                         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;
    }

4968
 cleanup:
4969 4970
    return ret;
}
4971 4972 4973

static void
networkNetworkObjTaint(virNetworkObjPtr net,
4974
                       virNetworkTaintFlags taint)
4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985
{
    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));
    }
}
4986 4987 4988 4989 4990 4991


static bool
networkBandwidthGenericChecks(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
4992
    virNetDevBandwidthPtr ifaceBand;
4993 4994 4995 4996 4997 4998 4999 5000
    unsigned long long old_floor, new_floor;

    if (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_NETWORK) {
        /* This is not an interface that's plugged into a network.
         * We don't care. Thus from our POV bandwidth change is allowed. */
        return false;
    }

5001
    ifaceBand = virDomainNetGetActualBandwidth(iface);
5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041
    old_floor = new_floor = 0;

    if (ifaceBand && ifaceBand->in)
        old_floor = ifaceBand->in->floor;
    if (newBandwidth && newBandwidth->in)
        new_floor = newBandwidth->in->floor;

    return new_floor != old_floor;
}


bool
networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
    virNetworkObjPtr network = NULL;
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    bool ret = false;

    if (!networkBandwidthGenericChecks(iface, newBandwidth))
        return true;

    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!network) {
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return false;
    }

    if (networkCheckBandwidth(network, newBandwidth, ifaceBand, iface->mac, NULL) < 0)
        goto cleanup;

    ret = true;

 cleanup:
    virNetworkObjEndAPI(&network);
    return ret;
}
5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079


int
networkBandwidthUpdate(virDomainNetDefPtr iface,
                       virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
    virNetworkObjPtr network = NULL;
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    unsigned long long new_rate = 0;
    int plug_ret;
    int ret = -1;

    if (!networkBandwidthGenericChecks(iface, newBandwidth))
        return 0;

    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!network) {
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return ret;
    }

    if ((plug_ret = networkCheckBandwidth(network, newBandwidth, ifaceBand,
                                          iface->mac, &new_rate)) < 0) {
        /* helper reported error */
        goto cleanup;
    }

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

    /* Okay, there are three possible scenarios: */

5080 5081
    if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
        newBandwidth && newBandwidth->in && newBandwidth->in->floor) {
5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123
        /* Either we just need to update @floor .. */

        if (virNetDevBandwidthUpdateRate(network->def->bridge,
                                         iface->data.network.actual->class_id,
                                         network->def->bandwidth,
                                         newBandwidth->in->floor) < 0)
            goto cleanup;

        network->floor_sum -= ifaceBand->in->floor;
        network->floor_sum += newBandwidth->in->floor;
        new_rate -= network->floor_sum;

        if (virNetDevBandwidthUpdateRate(network->def->bridge, 2,
                                         network->def->bandwidth, new_rate) < 0 ||
            virNetworkSaveStatus(driver->stateDir, network) < 0) {
            /* Ouch, rollback */
            network->floor_sum -= newBandwidth->in->floor;
            network->floor_sum += ifaceBand->in->floor;

            ignore_value(virNetDevBandwidthUpdateRate(network->def->bridge,
                                                      iface->data.network.actual->class_id,
                                                      network->def->bandwidth,
                                                      ifaceBand->in->floor));
            goto cleanup;
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

        if (networkPlugBandwidthImpl(network, iface, newBandwidth, new_rate) < 0)
            goto cleanup;
    } else {
        /* .. or unplug old. */

        if (networkUnplugBandwidth(network, iface) < 0)
            goto cleanup;
    }

    ret = 0;
 cleanup:
    virNetworkObjEndAPI(&network);
    return ret;
}