bridge_driver.c 180.8 KB
Newer Older
1
/*
2
 * bridge_driver.c: core driver methods for managing network
3
 *
4
 * Copyright (C) 2006-2016 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
 *
 * 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 <pwd.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
42
#include <net/if.h>
43
#include <dirent.h>
44 45 46
#if HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
47

48
#include "virerror.h"
49
#include "datatypes.h"
50
#include "bridge_driver.h"
51
#include "bridge_driver_platform.h"
52
#include "network_conf.h"
53
#include "device_conf.h"
54
#include "driver.h"
55
#include "virbuffer.h"
56
#include "virpidfile.h"
57
#include "vircommand.h"
58
#include "viralloc.h"
59
#include "viruuid.h"
60
#include "viriptables.h"
61
#include "virlog.h"
62
#include "virdnsmasq.h"
63
#include "configmake.h"
64
#include "virnetdev.h"
65
#include "virnetdevip.h"
66 67
#include "virnetdevbridge.h"
#include "virnetdevtap.h"
68
#include "virnetdevvportprofile.h"
69
#include "virpci.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
        if (iface && virDomainNetDefFormat(&buf, iface, NULL, 0) < 0)
204
            goto cleanup;
205 206
        if (virNetworkDefFormatBuf(&buf, network->def, 0) < 0)
            goto cleanup;
207
        if (dom && virDomainDefFormatInternal(dom, NULL, 0, &buf) < 0)
208 209 210 211 212
            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

M
Michal Privoznik 已提交
292 293 294 295 296 297 298 299 300 301 302
static char *
networkMacMgrFileName(virNetworkDriverStatePtr driver,
                      const char *bridge)
{
    char *filename;

    ignore_value(virAsprintf(&filename, "%s/%s.macs",
                             driver->dnsmasqStateDir, bridge));
    return filename;
}

303 304
/* do needed cleanup steps and remove the network from the list */
static int
305 306
networkRemoveInactive(virNetworkDriverStatePtr driver,
                      virNetworkObjPtr net)
307 308
{
    char *leasefile = NULL;
309
    char *customleasefile = NULL;
310
    char *radvdconfigfile = NULL;
311
    char *configfile = NULL;
312
    char *radvdpidbase = NULL;
313
    char *statusfile = NULL;
M
Michal Privoznik 已提交
314
    char *macMapFile = NULL;
315 316 317 318 319 320
    dnsmasqContext *dctx = NULL;
    virNetworkDefPtr def = virNetworkObjGetPersistentDef(net);

    int ret = -1;

    /* remove the (possibly) existing dnsmasq and radvd files */
321
    if (!(dctx = dnsmasqContextNew(def->name,
322
                                   driver->dnsmasqStateDir))) {
323
        goto cleanup;
324
    }
325

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

329
    if (!(customleasefile = networkDnsmasqLeaseFileNameCustom(driver, def->bridge)))
330 331
        goto cleanup;

332
    if (!(radvdconfigfile = networkRadvdConfigFileName(driver, def->name)))
333
        goto cleanup;
334 335

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
336
        goto cleanup;
337

338
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
339
        goto cleanup;
340

341
    if (!(statusfile = virNetworkConfigFile(driver->stateDir, def->name)))
342
        goto cleanup;
343

M
Michal Privoznik 已提交
344 345 346
    if (!(macMapFile = networkMacMgrFileName(driver, def->bridge)))
        goto cleanup;

347 348 349
    /* dnsmasq */
    dnsmasqDelete(dctx);
    unlink(leasefile);
350
    unlink(customleasefile);
351
    unlink(configfile);
352

M
Michal Privoznik 已提交
353 354 355
    /* MAC map manager */
    unlink(macMapFile);

356 357
    /* radvd */
    unlink(radvdconfigfile);
358
    virPidFileDelete(driver->pidDir, radvdpidbase);
359

360 361 362
    /* remove status file */
    unlink(statusfile);

363
    /* remove the network definition */
364
    virNetworkRemoveInactive(driver->networks, net);
365 366 367

    ret = 0;

368
 cleanup:
369
    VIR_FREE(leasefile);
370
    VIR_FREE(configfile);
371
    VIR_FREE(customleasefile);
372 373
    VIR_FREE(radvdconfigfile);
    VIR_FREE(radvdpidbase);
374
    VIR_FREE(statusfile);
M
Michal Privoznik 已提交
375
    VIR_FREE(macMapFile);
376 377 378 379
    dnsmasqContextFree(dctx);
    return ret;
}

M
Michal Privoznik 已提交
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
static int
networkMacMgrAdd(virNetworkDriverStatePtr driver,
                 virNetworkObjPtr network,
                 const char *domain,
                 const virMacAddr *mac)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    char *file = NULL;
    int ret = -1;

    if (!network->macmap)
        return 0;

    virMacAddrFormat(mac, macStr);

    if (!(file = networkMacMgrFileName(driver, network->def->bridge)))
        goto cleanup;

    if (virMacMapAdd(network->macmap, domain, macStr) < 0)
        goto cleanup;

    if (virMacMapWriteFile(network->macmap, file) < 0)
        goto cleanup;

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

static int
networkMacMgrDel(virNetworkDriverStatePtr driver,
                 virNetworkObjPtr network,
                 const char *domain,
                 const virMacAddr *mac)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    char *file = NULL;
    int ret = -1;

    if (!network->macmap)
        return 0;

    virMacAddrFormat(mac, macStr);

    if (!(file = networkMacMgrFileName(driver, network->def->bridge)))
        goto cleanup;

    if (virMacMapRemove(network->macmap, domain, macStr) < 0)
        goto cleanup;

    if (virMacMapWriteFile(network->macmap, file) < 0)
        goto cleanup;

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

440 441 442
static char *
networkBridgeDummyNicName(const char *brname)
{
443
    static const char dummyNicSuffix[] = "-nic";
444 445
    char *nicname;

446 447 448 449 450 451 452
    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.
         */
453 454 455 456 457
        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));
458
    } else {
459
        ignore_value(virAsprintf(&nicname, "%s%s", brname, dummyNicSuffix));
460
    }
461 462 463
    return nicname;
}

464 465
static int
networkUpdateState(virNetworkObjPtr obj,
466
                   void *opaque)
467
{
468
    virNetworkDriverStatePtr driver = opaque;
469
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
470
    int ret = -1;
471

472
    virObjectLock(obj);
473
    if (!virNetworkObjIsActive(obj)) {
474 475
        ret = 0;
        goto cleanup;
476
    }
477

478 479 480 481
    switch (obj->def->forward.type) {
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
482
    case VIR_NETWORK_FORWARD_OPEN:
483 484 485 486
        /* If bridge doesn't exist, then mark it inactive */
        if (!(obj->def->bridge && virNetDevExists(obj->def->bridge) == 1))
            obj->active = 0;
        break;
487

488
    case VIR_NETWORK_FORWARD_BRIDGE:
489 490
        if (obj->def->bridge) {
            if (virNetDevExists(obj->def->bridge) != 1)
491 492
                obj->active = 0;
            break;
493
        }
494 495 496 497 498 499 500 501 502
        /* 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;
503

504 505 506
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
507
    }
508

509 510 511
    /* Try and read dnsmasq/radvd pids of active networks */
    if (obj->active && obj->def->ips && (obj->def->nips > 0)) {
        char *radvdpidbase;
M
Michal Privoznik 已提交
512
        char *macMapFile;
513

514 515 516
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           obj->def->name,
                                           &obj->dnsmasqPid,
517
                                           dnsmasqCapsGetBinaryPath(dnsmasq_caps)));
M
Michal Privoznik 已提交
518

519 520 521
        radvdpidbase = networkRadvdPidfileBasename(obj->def->name);
        if (!radvdpidbase)
            goto cleanup;
522

523 524 525 526
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
                                           &obj->radvdPid, RADVD));
        VIR_FREE(radvdpidbase);
M
Michal Privoznik 已提交
527 528 529 530 531 532 533 534 535 536 537

        if (!(macMapFile = networkMacMgrFileName(driver, obj->def->bridge)))
            goto cleanup;

        if (virFileExists(macMapFile) &&
            !(obj->macmap = virMacMapNew(macMapFile))) {
            VIR_FREE(macMapFile);
            goto cleanup;
        }

        VIR_FREE(macMapFile);
538
    }
539

540 541
    ret = 0;
 cleanup:
542
    virObjectUnlock(obj);
543
    virObjectUnref(dnsmasq_caps);
544 545
    return ret;
}
546

547

548 549
static int
networkAutostartConfig(virNetworkObjPtr net,
550
                       void *opaque)
551
{
552
    virNetworkDriverStatePtr driver = opaque;
553
    int ret = -1;
554

555
    virObjectLock(net);
556 557
    if (net->autostart &&
        !virNetworkObjIsActive(net) &&
558
        networkStartNetwork(driver, net) < 0)
559 560 561 562
        goto cleanup;

    ret = 0;
 cleanup:
563
    virObjectUnlock(net);
564
    return ret;
565 566
}

567 568 569
#if HAVE_FIREWALLD
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
570
                             DBusMessage *message, void *user_data)
571
{
572 573
    virNetworkDriverStatePtr driver = user_data;

574 575 576 577 578 579
    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.");
580
        networkReloadFirewallRules(driver);
581 582 583 584 585 586
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

587
static int
588
networkMigrateStateFiles(virNetworkDriverStatePtr driver)
589 590 591 592 593 594 595 596 597 598 599 600 601
{
    /* 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;
602
    int direrr;
603 604 605
    struct dirent *entry;
    char *oldPath = NULL, *newPath = NULL;
    char *contents = NULL;
J
Ján Tomko 已提交
606
    int rc;
607

J
Ján Tomko 已提交
608 609
    if ((rc = virDirOpenIfExists(&dir, oldStateDir)) <= 0)
        return rc;
610 611 612 613 614 615 616

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

617
    while ((direrr = virDirRead(dir, &entry, oldStateDir)) > 0) {
618 619 620
        if (entry->d_type != DT_UNKNOWN &&
            entry->d_type != DT_REG)
            continue;
621 622 623

        if (virAsprintf(&oldPath, "%s/%s",
                        oldStateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
624
            goto cleanup;
625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641

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

642
        if (virFileReadAll(oldPath, 1024*1024, &contents) < 0)
J
Ján Tomko 已提交
643
            goto cleanup;
644 645 646

        if (virAsprintf(&newPath, "%s/%s",
                        driver->stateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
647
            goto cleanup;
648 649 650 651 652 653 654 655 656 657 658 659
        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);
    }
660
    if (direrr < 0)
J
Ján Tomko 已提交
661
        goto cleanup;
662 663 664

    ret = 0;
 cleanup:
J
Ján Tomko 已提交
665
    VIR_DIR_CLOSE(dir);
666 667 668 669 670 671
    VIR_FREE(oldPath);
    VIR_FREE(newPath);
    VIR_FREE(contents);
    return ret;
}

672
/**
673
 * networkStateInitialize:
674 675 676 677
 *
 * Initialization function for the QEmu daemon
 */
static int
678 679 680
networkStateInitialize(bool privileged,
                       virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
681
{
682 683 684
    int ret = -1;
    char *configdir = NULL;
    char *rundir = NULL;
685 686 687
#ifdef HAVE_FIREWALLD
    DBusConnection *sysbus = NULL;
#endif
688

689
    if (VIR_ALLOC(network_driver) < 0)
690
        goto error;
691

692 693
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
694 695
        goto error;
    }
696

697 698 699 700
    /* configuration/state paths are one of
     * ~/.config/libvirt/... (session/unprivileged)
     * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
     */
701
    if (privileged) {
702
        if (VIR_STRDUP(network_driver->networkConfigDir,
703
                       SYSCONFDIR "/libvirt/qemu/networks") < 0 ||
704
            VIR_STRDUP(network_driver->networkAutostartDir,
705
                       SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
706
            VIR_STRDUP(network_driver->stateDir,
707
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
708
            VIR_STRDUP(network_driver->pidDir,
709
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
710
            VIR_STRDUP(network_driver->dnsmasqStateDir,
711
                       LOCALSTATEDIR "/lib/libvirt/dnsmasq") < 0 ||
712
            VIR_STRDUP(network_driver->radvdStateDir,
713 714
                       LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
            goto error;
715 716 717 718 719

        /* migration from old to new location is only applicable for
         * privileged mode - unprivileged mode directories haven't
         * changed location.
         */
720
        if (networkMigrateStateFiles(network_driver) < 0)
721
            goto error;
722
    } else {
723 724 725
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
726
            goto error;
727

728
        if ((virAsprintf(&network_driver->networkConfigDir,
729
                         "%s/qemu/networks", configdir) < 0) ||
730
            (virAsprintf(&network_driver->networkAutostartDir,
731
                         "%s/qemu/networks/autostart", configdir) < 0) ||
732
            (virAsprintf(&network_driver->stateDir,
733
                         "%s/network/lib", rundir) < 0) ||
734
            (virAsprintf(&network_driver->pidDir,
735
                         "%s/network/run", rundir) < 0) ||
736
            (virAsprintf(&network_driver->dnsmasqStateDir,
737
                         "%s/dnsmasq/lib", rundir) < 0) ||
738
            (virAsprintf(&network_driver->radvdStateDir,
739
                         "%s/radvd/lib", rundir) < 0)) {
740
            goto error;
741
        }
742 743
    }

744
    if (virFileMakePath(network_driver->stateDir) < 0) {
745 746
        virReportSystemError(errno,
                             _("cannot create directory %s"),
747
                             network_driver->stateDir);
748 749 750
        goto error;
    }

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

754
    if (!(network_driver->networks = virNetworkObjListNew()))
755 756
        goto error;

757 758
    if (virNetworkLoadAllState(network_driver->networks,
                               network_driver->stateDir) < 0)
759 760
        goto error;

761 762 763
    if (virNetworkLoadAllConfigs(network_driver->networks,
                                 network_driver->networkConfigDir,
                                 network_driver->networkAutostartDir) < 0)
764 765
        goto error;

766 767 768 769
    /* 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). */
770
    virNetworkObjListForEach(network_driver->networks,
771
                             networkUpdateState,
772 773
                             network_driver);
    virNetworkObjListPrune(network_driver->networks,
774 775
                           VIR_CONNECT_LIST_NETWORKS_INACTIVE |
                           VIR_CONNECT_LIST_NETWORKS_TRANSIENT);
776 777
    networkReloadFirewallRules(network_driver);
    networkRefreshDaemons(network_driver);
778

779
    network_driver->networkEventState = virObjectEventStateNew();
780

781 782 783
#ifdef HAVE_FIREWALLD
    if (!(sysbus = virDBusGetSystemBus())) {
        VIR_WARN("DBus not available, disabling firewalld support "
784
                 "in bridge_network_driver: %s", virGetLastErrorMessage());
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
    } 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,
802
                                   network_driver, NULL);
803 804 805
    }
#endif

806
    ret = 0;
807
 cleanup:
808 809 810
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
811

812
 error:
813
    networkStateCleanup();
814
    goto cleanup;
815 816
}

817 818 819 820 821 822 823 824
/**
 * networkStateAutoStart:
 *
 * Function to AutoStart the bridge configs
 */
static void
networkStateAutoStart(void)
{
825
    if (!network_driver)
826 827
        return;

828
    virNetworkObjListForEach(network_driver->networks,
829
                             networkAutostartConfig,
830
                             network_driver);
831 832
}

833
/**
834
 * networkStateReload:
835 836 837 838 839
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
840 841
networkStateReload(void)
{
842
    if (!network_driver)
843 844
        return 0;

845 846 847 848 849 850 851 852
    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,
853
                             networkAutostartConfig,
854
                             network_driver);
855 856 857 858 859
    return 0;
}


/**
860
 * networkStateCleanup:
861 862 863 864
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
865 866
networkStateCleanup(void)
{
867
    if (!network_driver)
868 869
        return -1;

870
    virObjectUnref(network_driver->networkEventState);
871

872
    /* free inactive networks */
873
    virObjectUnref(network_driver->networks);
874

875 876 877 878 879 880
    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);
881

882
    virObjectUnref(network_driver->dnsmasqCaps);
883

884
    virMutexDestroy(&network_driver->lock);
885

886
    VIR_FREE(network_driver);
887 888 889 890 891

    return 0;
}


892 893 894 895 896 897 898
/* 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)
{
899 900
    size_t i;
    int ret = -1;
901 902 903 904 905 906 907
    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.
     */
908
    for (i = 0; i < 25; i++) {
909
        int signum = 0;
910
        if (i == 0) {
911
            signum = SIGTERM;
912
        } else if (i == 15) {
913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
            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);
948
 cleanup:
949 950 951
    return ret;
}

J
Ján Tomko 已提交
952 953 954
/* the following does not build a file, it builds a list
 * which is later saved into a file
 */
G
Gene Czarcinski 已提交
955

956
static int
G
Gene Czarcinski 已提交
957
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
958
                                 virNetworkIPDefPtr ipdef)
959
{
960
    size_t i;
G
Gene Czarcinski 已提交
961
    bool ipv6 = false;
962

G
Gene Czarcinski 已提交
963 964
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
965 966
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
967
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
968 969
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
970
                return -1;
971
    }
972

G
Gene Czarcinski 已提交
973 974 975 976 977 978 979
    return 0;
}

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

982 983
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
984
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
985
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
986
                for (j = 0; j < host->nnames; j++)
987 988
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
989 990
            }
        }
991 992
    }

993
    return 0;
994 995 996
}


997 998
int
networkDnsmasqConfContents(virNetworkObjPtr network,
999 1000 1001 1002
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
                           dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
1003
{
1004
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1005
    int r, ret = -1;
1006
    int nbleases = 0;
1007
    size_t i;
1008
    virNetworkDNSDefPtr dns = &network->def->dns;
1009
    bool wantDNS = dns->enable != VIR_TRISTATE_BOOL_NO;
1010
    virNetworkIPDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
G
Gene Czarcinski 已提交
1011
    bool ipv6SLAAC;
1012
    char *saddr = NULL, *eaddr = NULL;
1013

1014 1015
    *configstr = NULL;

1016
    /*
1017 1018 1019
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1020
     *
1021 1022
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1023
     */
1024 1025 1026 1027 1028 1029

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

1030 1031
    /* create dnsmasq config file appropriate for this network */
    virBufferAsprintf(&configbuf,
1032 1033 1034 1035 1036 1037 1038
                      "##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"
1039
                      "strict-order\n",
1040 1041
                      network->def->name);

1042 1043 1044 1045 1046 1047 1048
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

    if (wantDNS && network->def->dns.forwarders) {
1049 1050
        virBufferAddLit(&configbuf, "no-resolv\n");
        for (i = 0; i < network->def->dns.nfwds; i++) {
1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
            virNetworkDNSForwarderPtr fwd = &network->def->dns.forwarders[i];

            virBufferAddLit(&configbuf, "server=");
            if (fwd->domain)
                virBufferAsprintf(&configbuf, "/%s/", fwd->domain);
            if (VIR_SOCKET_ADDR_VALID(&fwd->addr)) {
                char *addr = virSocketAddrFormat(&fwd->addr);

                if (!addr)
                    goto cleanup;
                virBufferAsprintf(&configbuf, "%s\n", addr);
1062
                VIR_FREE(addr);
1063 1064 1065 1066
            } else {
                /* "don't forward requests for this domain" */
                virBufferAddLit(&configbuf, "#\n");
            }
1067 1068 1069
        }
    }

1070
    if (network->def->domain) {
1071 1072 1073 1074 1075
        if (network->def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
                              network->def->domain);
        }
1076
        virBufferAsprintf(&configbuf,
1077 1078 1079 1080
                          "domain=%s\n"
                          "expand-hosts\n",
                          network->def->domain);
    }
1081

1082
    if (wantDNS && network->def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1083 1084 1085 1086
        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)
1087
         */
1088
        virBufferAddLit(&configbuf, "local=//\n");
1089
    }
1090

1091
    if (pidfile)
1092
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1093

1094
    /* dnsmasq will *always* listen on localhost unless told otherwise */
P
Pavel Timofeev 已提交
1095
#ifdef __linux__
1096
    virBufferAddLit(&configbuf, "except-interface=lo\n");
P
Pavel Timofeev 已提交
1097 1098 1099 1100
#else
    /* BSD family OSes and Solaris call loopback interface as lo0 */
    virBufferAddLit(&configbuf, "except-interface=lo0\n");
#endif
1101

1102 1103 1104 1105 1106 1107 1108 1109
    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.
         */
1110
        virBufferAsprintf(&configbuf,
1111 1112 1113
                          "bind-dynamic\n"
                          "interface=%s\n",
                          network->def->bridge);
1114
    } else {
1115
        virBufferAddLit(&configbuf, "bind-interfaces\n");
1116 1117 1118 1119 1120 1121 1122 1123
        /*
         * --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
         */
1124
        for (i = 0;
1125
             (tmpipdef = virNetworkDefGetIPByIndex(network->def, AF_UNSPEC, i));
1126
             i++) {
1127 1128 1129 1130
            char *ipaddr = virSocketAddrFormat(&tmpipdef->address);

            if (!ipaddr)
                goto cleanup;
1131

1132
            /* also part of CVE 2012-3411 - if the host's version of
1133
             * dnsmasq doesn't have bind-dynamic, only allow listening on
1134 1135
             * private/local IP addresses (see RFC1918/RFC3484/RFC4193)
             */
1136 1137
            if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
                !virSocketAddrIsPrivate(&tmpipdef->address)) {
1138 1139 1140 1141
                unsigned long version = dnsmasqCapsGetVersion(caps);

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
1142
                                 "The version of dnsmasq on this host (%d.%d) "
1143 1144 1145 1146
                                 "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 "
1147 1148 1149 1150 1151 1152
                                 "(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);
1153
                VIR_FREE(ipaddr);
1154 1155
                goto cleanup;
            }
1156
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
1157 1158 1159
            VIR_FREE(ipaddr);
        }
    }
1160

1161 1162
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
1163
     * guaranteed to not work, and set no-resolv so that no dns
1164 1165 1166
     * 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).
1167 1168 1169
     * IPv6 RA always contains an implicit default route
     * via the sender's link-local address. The only thing we can do
     * is set the lifetime of this route to 0, i.e. disable it.
1170
     */
1171
    if (network->def->forward.type == VIR_NETWORK_FORWARD_NONE) {
1172
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
1173
                        "no-resolv\n");
1174 1175 1176 1177
        if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM)) {
            /* interface=* (any), interval=0 (default), lifetime=0 (seconds) */
            virBufferAddLit(&configbuf, "ra-param=*,0,0\n");
        }
1178
    }
1179

1180 1181 1182 1183 1184
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1185
        }
1186

1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209
        for (i = 0; i < dns->nsrvs; i++) {
            /* 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);
1210

1211 1212 1213 1214 1215 1216 1217
            /* domain is optional - it defaults to the domain of this network */
            if (dns->srvs[i].domain)
                virBufferAsprintf(&configbuf, ".%s", dns->srvs[i].domain);

            /* 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.
1218
             */
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238
            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);
            }
            virBufferAddLit(&configbuf, "\n");
1239
        }
1240 1241
    }

G
Gene Czarcinski 已提交
1242
    /* Find the first dhcp for both IPv4 and IPv6 */
1243
    for (i = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
1244
         (ipdef = virNetworkDefGetIPByIndex(network->def, AF_UNSPEC, i));
1245
         i++) {
G
Gene Czarcinski 已提交
1246 1247 1248 1249
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1250 1251
                                   _("For IPv4, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
                    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,
1263 1264 1265 1266 1267 1268 1269 1270 1271
                                   _("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 已提交
1272 1273 1274 1275
                    goto cleanup;
                }
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1276 1277
                                   _("For IPv6, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290
                    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 "
1291 1292 1293 1294
                 "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 已提交
1295 1296 1297 1298 1299
    }

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1300 1301
        int prefix;

1302
        prefix = virNetworkIPDefPrefix(ipdef);
1303 1304 1305 1306 1307 1308
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
                           network->def->bridge);
            goto cleanup;
        }
1309
        for (r = 0; r < ipdef->nranges; r++) {
1310 1311
            int thisRange;

1312 1313
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1314
                goto cleanup;
1315

1316
            virBufferAsprintf(&configbuf, "dhcp-range=%s,%s",
1317
                              saddr, eaddr);
1318
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1319
                virBufferAsprintf(&configbuf, ",%d", prefix);
1320 1321
            virBufferAddLit(&configbuf, "\n");

1322
            VIR_FREE(saddr);
1323
            VIR_FREE(eaddr);
1324
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1325 1326
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1327
                                              virNetworkIPDefPrefix(ipdef));
1328 1329 1330
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1331
        }
1332

1333
        /*
1334 1335 1336 1337
         * 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)
1338 1339
         */
        if (!ipdef->nranges && ipdef->nhosts) {
1340
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
1341 1342
            if (!bridgeaddr)
                goto cleanup;
1343 1344 1345
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static",
                              bridgeaddr);
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1346
                virBufferAsprintf(&configbuf, ",%d", prefix);
1347
            virBufferAddLit(&configbuf, "\n");
1348 1349
            VIR_FREE(bridgeaddr);
        }
1350

G
Gene Czarcinski 已提交
1351 1352
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1353

G
Gene Czarcinski 已提交
1354 1355
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
1356
            if (ipdef->nranges || ipdef->nhosts) {
1357
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1358 1359
                virBufferAddLit(&configbuf, "dhcp-authoritative\n");
            }
1360

G
Gene Czarcinski 已提交
1361
            if (ipdef->tftproot) {
1362 1363
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1364
            }
1365

G
Gene Czarcinski 已提交
1366 1367 1368
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1369

1370
                    if (!bootserver)
G
Gene Czarcinski 已提交
1371
                        goto cleanup;
1372
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1373
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1374 1375
                    VIR_FREE(bootserver);
                } else {
1376
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1377 1378 1379 1380 1381
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1382

1383
    if (nbleases > 0)
1384
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1385

G
Gene Czarcinski 已提交
1386 1387
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1388
        goto cleanup;
G
Gene Czarcinski 已提交
1389 1390 1391 1392 1393 1394

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

1398 1399
    /* Likewise, always create this file and put it on the
     * commandline, to allow for runtime additions.
G
Gene Czarcinski 已提交
1400
     */
1401 1402 1403 1404
    if (wantDNS) {
        virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
                          dctx->addnhostsfile->path);
    }
G
Gene Czarcinski 已提交
1405 1406 1407

    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
1408
        if (ipv6def) {
1409
            virBufferAddLit(&configbuf, "enable-ra\n");
1410
        } else {
1411
            for (i = 0;
1412
                 (ipdef = virNetworkDefGetIPByIndex(network->def, AF_INET6, i));
1413
                 i++) {
G
Gene Czarcinski 已提交
1414 1415 1416 1417
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1418 1419
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1420 1421
                    VIR_FREE(bridgeaddr);
                }
1422
            }
1423
        }
1424 1425
    }

1426 1427 1428
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1429
    ret = 0;
G
Gene Czarcinski 已提交
1430

1431
 cleanup:
1432 1433
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1434
    virBufferFreeAndReset(&configbuf);
1435
    return ret;
1436 1437
}

1438
/* build the dnsmasq command line */
1439 1440 1441
static int ATTRIBUTE_NONNULL(3)
networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
                                  virNetworkObjPtr network,
1442
                                  virCommandPtr *cmdout,
1443 1444
                                  char *pidfile,
                                  dnsmasqContext *dctx)
1445
{
1446
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1447
    virCommandPtr cmd = NULL;
G
Gene Czarcinski 已提交
1448
    int ret = -1;
1449 1450
    char *configfile = NULL;
    char *configstr = NULL;
1451
    char *leaseshelper_path = NULL;
1452 1453

    network->dnsmasqPid = -1;
1454

1455
    if (networkDnsmasqConfContents(network, pidfile, &configstr,
1456
                                   dctx, dnsmasq_caps) < 0)
1457 1458 1459 1460 1461
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1462
    if (!(configfile = networkDnsmasqConfigFileName(driver, network->def->name)))
1463 1464 1465 1466 1467
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1468 1469
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1470 1471 1472
        goto cleanup;
    }

1473 1474
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1475
                                                  abs_topbuilddir "/src",
1476 1477 1478
                                                  LIBEXECDIR)))
        goto cleanup;

1479
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1480
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1481 1482
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1483
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1484
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", network->def->bridge);
1485

1486
    *cmdout = cmd;
1487
    ret = 0;
1488
 cleanup:
1489
    virObjectUnref(dnsmasq_caps);
1490 1491
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1492
    VIR_FREE(leaseshelper_path);
1493 1494 1495 1496
    return ret;
}

static int
1497 1498
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
                       virNetworkObjPtr network)
1499
{
1500 1501 1502
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1503 1504 1505
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
    int ret = -1;
1506
    dnsmasqContext *dctx = NULL;
1507

1508
    /* see if there are any IP addresses that need a dhcp server */
1509 1510 1511
    i = 0;
    while ((ipdef = virNetworkDefGetIPByIndex(network->def, AF_UNSPEC, i))) {
        i++;
1512 1513 1514 1515
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1516 1517 1518 1519 1520 1521
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1522
    if (!needDnsmasq && network->def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1523
        /* no DHCP services needed, and user disabled DNS service */
1524 1525 1526 1527
        ret = 0;
        goto cleanup;
    }

1528
    if (virFileMakePath(driver->pidDir) < 0) {
1529
        virReportSystemError(errno,
1530
                             _("cannot create directory %s"),
1531
                             driver->pidDir);
1532
        goto cleanup;
1533 1534
    }

1535
    if (!(pidfile = virPidFileBuildPath(driver->pidDir,
1536
                                        network->def->name)))
1537
        goto cleanup;
1538

1539
    if (virFileMakePath(driver->dnsmasqStateDir) < 0) {
1540
        virReportSystemError(errno,
1541
                             _("cannot create directory %s"),
1542
                             driver->dnsmasqStateDir);
1543 1544 1545
        goto cleanup;
    }

1546
    dctx = dnsmasqContextNew(network->def->name, driver->dnsmasqStateDir);
1547 1548 1549
    if (dctx == NULL)
        goto cleanup;

1550
    if (networkDnsmasqCapsRefresh(driver) < 0)
1551
        goto cleanup;
1552

1553
    ret = networkBuildDhcpDaemonCommandLine(driver, network, &cmd, pidfile, dctx);
1554 1555 1556 1557 1558
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1559
        goto cleanup;
1560

G
Guido Günther 已提交
1561
    ret = virCommandRun(cmd, NULL);
1562
    if (ret < 0)
1563 1564 1565
        goto cleanup;

    /*
1566 1567 1568 1569 1570
     * 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
1571 1572
     */

1573
    ret = virPidFileRead(driver->pidDir, network->def->name,
1574 1575
                         &network->dnsmasqPid);
    if (ret < 0)
1576
        goto cleanup;
1577

1578
    ret = 0;
1579
 cleanup:
1580
    VIR_FREE(pidfile);
1581
    virCommandFree(cmd);
1582
    dnsmasqContextFree(dctx);
1583 1584 1585
    return ret;
}

1586 1587
/* networkRefreshDhcpDaemon:
 *  Update dnsmasq config files, then send a SIGHUP so that it rereads
G
Gene Czarcinski 已提交
1588 1589
 *  them.   This only works for the dhcp-hostsfile and the
 *  addn-hosts file.
1590 1591 1592
 *
 *  Returns 0 on success, -1 on failure.
 */
1593
static int
1594 1595
networkRefreshDhcpDaemon(virNetworkDriverStatePtr driver,
                         virNetworkObjPtr network)
1596
{
1597 1598
    int ret = -1;
    size_t i;
1599
    virNetworkIPDefPtr ipdef, ipv4def, ipv6def;
1600
    dnsmasqContext *dctx = NULL;
1601

G
Gene Czarcinski 已提交
1602
    /* if no IP addresses specified, nothing to do */
1603
    if (!virNetworkDefGetIPByIndex(network->def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1604 1605
        return 0;

1606 1607
    /* if there's no running dnsmasq, just start it */
    if (network->dnsmasqPid <= 0 || (kill(network->dnsmasqPid, 0) < 0))
1608
        return networkStartDhcpDaemon(driver, network);
1609

G
Gene Czarcinski 已提交
1610
    VIR_INFO("Refreshing dnsmasq for network %s", network->def->bridge);
1611
    if (!(dctx = dnsmasqContextNew(network->def->name,
1612
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1613
        goto cleanup;
1614
    }
G
Gene Czarcinski 已提交
1615 1616 1617 1618 1619 1620

    /* 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;
1621
    for (i = 0;
1622
         (ipdef = virNetworkDefGetIPByIndex(network->def, AF_INET, i));
1623
         i++) {
G
Gene Czarcinski 已提交
1624 1625
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1626 1627
    }

G
Gene Czarcinski 已提交
1628
    ipv6def = NULL;
1629
    for (i = 0;
1630
         (ipdef = virNetworkDefGetIPByIndex(network->def, AF_INET6, i));
1631
         i++) {
G
Gene Czarcinski 已提交
1632 1633
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1634 1635
    }

G
Gene Czarcinski 已提交
1636
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1637
        goto cleanup;
G
Gene Czarcinski 已提交
1638 1639

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

G
Gene Czarcinski 已提交
1642
    if (networkBuildDnsmasqHostsList(dctx, &network->def->dns) < 0)
J
Ján Tomko 已提交
1643
        goto cleanup;
1644 1645

    if ((ret = dnsmasqSave(dctx)) < 0)
1646
        goto cleanup;
1647 1648

    ret = kill(network->dnsmasqPid, SIGHUP);
1649
 cleanup:
1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661
    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
1662 1663
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
                         virNetworkObjPtr network)
1664 1665 1666 1667 1668 1669
{
    /* if there is a running dnsmasq, kill it */
    if (network->dnsmasqPid > 0) {
        networkKillDaemon(network->dnsmasqPid, "dnsmasq",
                          network->def->name);
        network->dnsmasqPid = -1;
1670
    }
1671
    /* now start dnsmasq if it should be started */
1672
    return networkStartDhcpDaemon(driver, network);
1673 1674
}

G
Gene Czarcinski 已提交
1675 1676 1677 1678 1679 1680
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";

1681 1682 1683
static int
networkRadvdConfContents(virNetworkObjPtr network, char **configstr)
{
E
Eric Blake 已提交
1684
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1685 1686
    int ret = -1;
    size_t i;
1687
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1688
    bool v6present = false, dhcp6 = false;
1689 1690

    *configstr = NULL;
1691

G
Gene Czarcinski 已提交
1692
    /* Check if DHCPv6 is needed */
1693
    for (i = 0;
1694
         (ipdef = virNetworkDefGetIPByIndex(network->def, AF_INET6, i));
1695
         i++) {
G
Gene Czarcinski 已提交
1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708
        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;
    }

1709 1710 1711
    /* create radvd config file appropriate for this network;
     * IgnoreIfMissing allows radvd to start even when the bridge is down
     */
1712
    virBufferAsprintf(&configbuf, "interface %s\n"
1713 1714
                      "{\n"
                      "  AdvSendAdvert on;\n"
1715
                      "  IgnoreIfMissing on;\n"
G
Gene Czarcinski 已提交
1716 1717 1718 1719 1720
                      "  AdvManagedFlag %s;\n"
                      "%s",
                      network->def->bridge,
                      dhcp6 ? "on" : "off",
                      dhcp6 ? "\n" : radvd1);
1721 1722

    /* add a section for each IPv6 address in the config */
1723
    for (i = 0;
1724
         (ipdef = virNetworkDefGetIPByIndex(network->def, AF_INET6, i));
1725
         i++) {
1726 1727 1728
        int prefix;
        char *netaddr;

1729
        prefix = virNetworkIPDefPrefix(ipdef);
1730
        if (prefix < 0) {
1731 1732 1733
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
                           network->def->bridge);
1734 1735
            goto cleanup;
        }
1736
        if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
1737
            goto cleanup;
1738
        virBufferAsprintf(&configbuf,
1739
                          "  prefix %s/%d\n"
G
Gene Czarcinski 已提交
1740 1741 1742
                          "  {\n%s  };\n",
                          netaddr, prefix,
                          dhcp6 ? radvd2 : radvd3);
1743 1744 1745
        VIR_FREE(netaddr);
    }

1746
    virBufferAddLit(&configbuf, "};\n");
1747

1748
    if (virBufferCheckError(&configbuf) < 0)
1749
        goto cleanup;
1750

1751 1752
    *configstr = virBufferContentAndReset(&configbuf);

1753
    ret = 0;
1754
 cleanup:
1755 1756 1757 1758
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1759
/* write file and return its name (which must be freed by caller) */
1760
static int
1761 1762 1763
networkRadvdConfWrite(virNetworkDriverStatePtr driver,
                      virNetworkObjPtr network,
                      char **configFile)
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778
{
    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;
1779 1780 1781 1782
        goto cleanup;
    }

    /* construct the filename */
1783
    if (!(*configFile = networkRadvdConfigFileName(driver, network->def->name)))
1784 1785
        goto cleanup;
    /* write the file */
1786
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1787 1788
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1789 1790 1791 1792 1793
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1794
 cleanup:
1795 1796 1797 1798 1799 1800
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

static int
1801 1802
networkStartRadvd(virNetworkDriverStatePtr driver,
                  virNetworkObjPtr network)
1803
{
1804
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1805 1806 1807 1808 1809 1810 1811 1812
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

    network->radvdPid = -1;

G
Gene Czarcinski 已提交
1813
    /* Is dnsmasq handling RA? */
1814
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
1815 1816 1817 1818
        ret = 0;
        goto cleanup;
    }

1819
    if (!virNetworkDefGetIPByIndex(network->def, AF_INET6, 0)) {
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
        /* 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);
1830 1831 1832
        goto cleanup;
    }

1833
    if (virFileMakePath(driver->pidDir) < 0) {
1834 1835
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1836
                             driver->pidDir);
1837 1838
        goto cleanup;
    }
1839
    if (virFileMakePath(driver->radvdStateDir) < 0) {
1840 1841
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1842
                             driver->radvdStateDir);
1843 1844 1845 1846
        goto cleanup;
    }

    /* construct pidfile name */
1847
    if (!(radvdpidbase = networkRadvdPidfileBasename(network->def->name)))
1848
        goto cleanup;
1849
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
1850 1851
        goto cleanup;

1852
    if (networkRadvdConfWrite(driver, network, &configfile) < 0)
1853 1854
        goto cleanup;

1855 1856 1857 1858
    /* 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
1859
     * virPidFileRead() below will fail if we use them).
1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874
     * 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;

1875
    if (virPidFileRead(driver->pidDir, radvdpidbase, &network->radvdPid) < 0)
1876 1877 1878
        goto cleanup;

    ret = 0;
1879
 cleanup:
1880
    virObjectUnref(dnsmasq_caps);
1881 1882 1883 1884 1885 1886 1887
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

1888
static int
1889 1890
networkRefreshRadvd(virNetworkDriverStatePtr driver,
                    virNetworkObjPtr network)
1891
{
1892
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
1893 1894 1895
    char *radvdpidbase;

    /* Is dnsmasq handling RA? */
1896 1897
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
        virObjectUnref(dnsmasq_caps);
G
Gene Czarcinski 已提交
1898 1899 1900 1901 1902 1903 1904
        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)) {
1905
            virPidFileDelete(driver->pidDir, radvdpidbase);
G
Gene Czarcinski 已提交
1906 1907 1908 1909 1910
            VIR_FREE(radvdpidbase);
        }
        network->radvdPid = -1;
        return 0;
    }
1911
    virObjectUnref(dnsmasq_caps);
G
Gene Czarcinski 已提交
1912

1913 1914
    /* if there's no running radvd, just start it */
    if (network->radvdPid <= 0 || (kill(network->radvdPid, 0) < 0))
1915
        return networkStartRadvd(driver, network);
1916

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

1922
    if (networkRadvdConfWrite(driver, network, NULL) < 0)
1923 1924 1925 1926 1927
        return -1;

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

1928 1929
#if 0
/* currently unused, so it causes a build error unless we #if it out */
1930
static int
1931
networkRestartRadvd(virNetworkObjPtr network)
1932 1933 1934 1935 1936 1937 1938 1939 1940
{
    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 已提交
1941
        if ((networkKillDaemon(network->radvdPid, "radvd",
1942 1943 1944
                               network->def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))
             != NULL)) {
1945
            virPidFileDelete(driver->pidDir, radvdpidbase);
1946 1947 1948 1949 1950 1951 1952 1953 1954
            VIR_FREE(radvdpidbase);
        }
        network->radvdPid = -1;
    }
    /* now start radvd if it should be started */
    return networkStartRadvd(network);
}
#endif /* #if 0 */

1955 1956
static int
networkRefreshDaemonsHelper(virNetworkObjPtr net,
1957
                            void *opaque)
1958
{
1959
    virNetworkDriverStatePtr driver = opaque;
1960

1961
    virObjectLock(net);
1962 1963 1964
    if (virNetworkObjIsActive(net) &&
        ((net->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
         (net->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
1965 1966
         (net->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
         (net->def->forward.type == VIR_NETWORK_FORWARD_OPEN))) {
1967 1968 1969 1970 1971 1972
        /* 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.
         */
1973 1974
        networkRefreshDhcpDaemon(driver, net);
        networkRefreshRadvd(driver, net);
1975
    }
1976
    virObjectUnlock(net);
1977 1978 1979
    return 0;
}

1980 1981 1982 1983
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
1984
networkRefreshDaemons(virNetworkDriverStatePtr driver)
1985 1986
{
    VIR_INFO("Refreshing network daemons");
1987 1988
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
1989
                             driver);
1990
}
1991

1992 1993 1994 1995 1996
static int
networkReloadFirewallRulesHelper(virNetworkObjPtr net,
                                 void *opaque ATTRIBUTE_UNUSED)
{

1997
    virObjectLock(net);
1998 1999 2000 2001
    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))) {
2002 2003 2004 2005
        /* Only three of the L3 network types that are configured by
         * libvirt need to have iptables rules reloaded. The 4th L3
         * network type, forward='open', doesn't need this because it
         * has no iptables rules.
2006 2007 2008 2009
         */
        networkRemoveFirewallRules(net->def);
        if (networkAddFirewallRules(net->def) < 0) {
            /* failed to add but already logged */
2010 2011
        }
    }
2012
    virObjectUnlock(net);
2013
    return 0;
2014 2015
}

2016
static void
2017
networkReloadFirewallRules(virNetworkDriverStatePtr driver)
2018
{
2019
    VIR_INFO("Reloading iptables rules");
2020 2021 2022
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2023 2024
}

2025
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
2026
static int
2027
networkEnableIPForwarding(bool enableIPv4, bool enableIPv6)
2028
{
2029
    int ret = 0;
2030 2031 2032 2033
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
2034
                           &enabled, sizeof(enabled));
2035 2036
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
2037
                           &enabled, sizeof(enabled));
2038
#else
2039 2040 2041 2042
    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);
2043
#endif
2044
    return ret;
2045 2046
}

2047 2048
#define SYSCTL_PATH "/proc/sys"

2049 2050
static int
networkSetIPv6Sysctls(virNetworkObjPtr network)
2051 2052 2053
{
    char *field = NULL;
    int ret = -1;
2054
    bool enableIPv6 =  !!virNetworkDefGetIPByIndex(network->def, AF_INET6, 0);
2055

2056 2057 2058 2059 2060 2061 2062
    /* 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;
2063

2064 2065
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2066 2067
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
                      network->def->bridge);
2068 2069 2070
        ret = 0;
        goto cleanup;
    }
2071

2072 2073 2074 2075 2076
    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;
2077
    }
2078
    VIR_FREE(field);
2079

2080 2081
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2082 2083 2084 2085 2086 2087
     */

    /* 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",
2088
                    network->def->bridge) < 0)
2089 2090
        goto cleanup;

2091
    if (virFileWriteStr(field, "0", 0) < 0) {
2092
        virReportSystemError(errno,
2093 2094 2095 2096 2097
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

2098 2099 2100 2101
    /* 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",
2102
                    network->def->bridge) < 0)
2103 2104
        goto cleanup;

2105
    if (virFileWriteStr(field, "0", 0) < 0) {
2106
        virReportSystemError(errno,
2107
                             _("cannot disable %s"), field);
2108 2109 2110 2111
        goto cleanup;
    }

    ret = 0;
2112
 cleanup:
2113 2114 2115 2116
    VIR_FREE(field);
    return ret;
}

2117
/* add an IP address to a bridge */
2118
static int
D
Daniel P. Berrange 已提交
2119
networkAddAddrToBridge(virNetworkObjPtr network,
2120
                       virNetworkIPDefPtr ipdef)
2121
{
2122
    int prefix = virNetworkIPDefPrefix(ipdef);
2123 2124

    if (prefix < 0) {
2125 2126 2127
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
                       network->def->bridge);
2128 2129 2130
        return -1;
    }

2131 2132
    if (virNetDevIPAddrAdd(network->def->bridge,
                           &ipdef->address, NULL, prefix) < 0)
2133 2134 2135 2136 2137
        return -1;

    return 0;
}

2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160

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


2161 2162 2163
/* add an IP (static) route to a bridge */
static int
networkAddRouteToBridge(virNetworkObjPtr network,
2164
                        virNetDevIPRoutePtr routedef)
2165
{
2166 2167 2168 2169
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2170 2171 2172 2173 2174 2175 2176 2177 2178

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

2179 2180
    if (virNetDevIPRouteAdd(network->def->bridge, addr,
                            prefix, gateway, metric) < 0) {
2181 2182 2183 2184 2185
        return -1;
    }
    return 0;
}

2186 2187 2188
static int
networkWaitDadFinish(virNetworkObjPtr network)
{
2189
    virNetworkIPDefPtr ipdef;
2190 2191 2192 2193 2194 2195
    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);

2196
    while ((ipdef = virNetworkDefGetIPByIndex(network->def,
2197 2198 2199 2200 2201 2202
                                              AF_INET6, naddrs))) {
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2203
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2204 2205 2206 2207 2208 2209 2210 2211

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

2212
static int
2213 2214
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
                           virNetworkObjPtr network)
2215
{
2216
    size_t i;
2217
    bool v4present = false, v6present = false;
2218
    virErrorPtr save_err = NULL;
2219
    virNetworkIPDefPtr ipdef;
2220
    virNetDevIPRoutePtr routedef;
2221
    char *macTapIfName = NULL;
M
Michal Privoznik 已提交
2222
    char *macMapFile = NULL;
2223
    int tapfd = -1;
2224

2225
    /* Check to see if any network IP collides with an existing route */
2226
    if (networkCheckRouteCollision(network->def) < 0)
2227 2228
        return -1;

2229
    /* Create and configure the bridge device */
2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243
    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;
    }
2244
    if (virNetDevBridgeCreate(network->def->bridge) < 0)
2245 2246
        return -1;

2247 2248 2249 2250 2251 2252 2253 2254
    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);
2255
        if (!macTapIfName)
2256
            goto err0;
2257
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2258
        if (virNetDevTapCreateInBridgePort(network->def->bridge,
2259
                                           &macTapIfName, &network->def->mac,
2260
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2261 2262 2263
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2264 2265 2266 2267 2268
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

M
Michal Privoznik 已提交
2269 2270 2271 2272
    if (!(macMapFile = networkMacMgrFileName(driver, network->def->bridge)) ||
        !(network->macmap = virMacMapNew(macMapFile)))
        goto err1;

2273
    /* Set bridge options */
2274 2275 2276 2277

    /* delay is configured in seconds, but virNetDevBridgeSetSTPDelay
     * expects milliseconds
     */
2278
    if (virNetDevBridgeSetSTPDelay(network->def->bridge,
2279
                                   network->def->delay * 1000) < 0)
2280
        goto err1;
2281

2282
    if (virNetDevBridgeSetSTP(network->def->bridge,
2283
                              network->def->stp ? true : false) < 0)
2284
        goto err1;
2285

2286 2287 2288 2289
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
    if (networkSetIPv6Sysctls(network) < 0)
2290
        goto err1;
2291

2292
    /* Add "once per network" rules */
2293 2294
    if (network->def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(network->def) < 0)
2295 2296
        goto err1;

2297
    for (i = 0;
2298
         (ipdef = virNetworkDefGetIPByIndex(network->def, AF_UNSPEC, i));
2299
         i++) {
2300
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2301
            v4present = true;
2302
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2303
            v6present = true;
2304

2305
        /* Add the IP address/netmask to the bridge */
2306
        if (networkAddAddrToBridge(network, ipdef) < 0)
2307
            goto err2;
2308 2309
    }

2310 2311 2312
    if (networkStartHandleMACTableManagerMode(network, macTapIfName) < 0)
        goto err2;

2313
    /* Bring up the bridge interface */
2314
    if (virNetDevSetOnline(network->def->bridge, 1) < 0)
2315
        goto err2;
2316

2317
    for (i = 0; i < network->def->nroutes; i++) {
2318 2319 2320
        virSocketAddrPtr gateway = NULL;

        routedef = network->def->routes[i];
2321
        gateway = virNetDevIPRouteGetGateway(routedef);
2322

2323 2324 2325
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2326
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2327 2328 2329 2330 2331 2332 2333
            if (networkAddRouteToBridge(network, routedef) < 0) {
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2334 2335
    /* If forward.type != NONE, turn on global IP forwarding */
    if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE &&
2336
        networkEnableIPForwarding(v4present, v6present) < 0) {
2337
        virReportSystemError(errno, "%s",
2338
                             _("failed to enable IP forwarding"));
2339
        goto err3;
2340 2341
    }

2342

2343
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2344
    if ((v4present || v6present) &&
2345
        networkStartDhcpDaemon(driver, network) < 0)
2346
        goto err3;
2347

2348
    /* start radvd if there are any ipv6 addresses */
2349
    if (v6present && networkStartRadvd(driver, network) < 0)
2350 2351
        goto err4;

2352 2353 2354 2355 2356 2357 2358 2359
    /* 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.
2360 2361 2362 2363 2364 2365 2366
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
            goto err4;
        VIR_FORCE_CLOSE(tapfd);
    }

2367
    if (virNetDevBandwidthSet(network->def->bridge,
2368
                              network->def->bandwidth, true) < 0)
2369 2370
        goto err5;

2371
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2372
    VIR_FREE(macMapFile);
2373 2374 2375

    return 0;

2376
 err5:
2377 2378
    if (network->def->bandwidth)
       virNetDevBandwidthClear(network->def->bridge);
2379

2380 2381 2382 2383
 err4:
    if (!save_err)
        save_err = virSaveLastError();

2384 2385 2386 2387 2388
    if (network->dnsmasqPid > 0) {
        kill(network->dnsmasqPid, SIGTERM);
        network->dnsmasqPid = -1;
    }

2389 2390 2391
 err3:
    if (!save_err)
        save_err = virSaveLastError();
2392
    ignore_value(virNetDevSetOnline(network->def->bridge, 0));
2393

2394 2395 2396
 err2:
    if (!save_err)
        save_err = virSaveLastError();
2397 2398
    if (network->def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(network->def);
2399 2400

 err1:
2401 2402 2403
    if (!save_err)
        save_err = virSaveLastError();

H
Hu Tao 已提交
2404
    if (macTapIfName) {
2405
        VIR_FORCE_CLOSE(tapfd);
2406
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2407 2408
        VIR_FREE(macTapIfName);
    }
M
Michal Privoznik 已提交
2409
    VIR_FREE(macMapFile);
2410 2411

 err0:
2412 2413
    if (!save_err)
        save_err = virSaveLastError();
2414
    ignore_value(virNetDevBridgeDelete(network->def->bridge));
2415

2416 2417 2418 2419
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
2420
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2421 2422 2423
    return -1;
}

2424 2425 2426
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
                              virNetworkObjPtr network)
2427
{
2428 2429
    if (network->def->bandwidth)
        virNetDevBandwidthClear(network->def->bridge);
2430

M
Michal Privoznik 已提交
2431 2432
    virObjectUnref(network->macmap);

2433 2434 2435 2436 2437
    if (network->radvdPid > 0) {
        char *radvdpidbase;

        kill(network->radvdPid, SIGTERM);
        /* attempt to delete the pidfile we created */
2438
        if ((radvdpidbase = networkRadvdPidfileBasename(network->def->name))) {
2439
            virPidFileDelete(driver->pidDir, radvdpidbase);
2440 2441 2442 2443
            VIR_FREE(radvdpidbase);
        }
    }

2444 2445 2446
    if (network->dnsmasqPid > 0)
        kill(network->dnsmasqPid, SIGTERM);

2447
    if (network->def->mac_specified) {
2448
        char *macTapIfName = networkBridgeDummyNicName(network->def->bridge);
2449
        if (macTapIfName) {
2450
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2451 2452 2453 2454
            VIR_FREE(macTapIfName);
        }
    }

2455
    ignore_value(virNetDevSetOnline(network->def->bridge, 0));
2456

2457 2458
    if (network->def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(network->def);
2459

2460
    ignore_value(virNetDevBridgeDelete(network->def->bridge));
2461

2462
    /* See if its still alive and really really kill it */
2463
    if (network->dnsmasqPid > 0 &&
2464
        (kill(network->dnsmasqPid, 0) == 0))
2465 2466
        kill(network->dnsmasqPid, SIGKILL);
    network->dnsmasqPid = -1;
2467 2468 2469 2470 2471 2472

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

2473 2474 2475
    return 0;
}

2476

2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497
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;
}


2498 2499 2500 2501 2502 2503 2504 2505 2506
/* 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;
2507
    unsigned int maxVirtFns = 0;
2508 2509 2510 2511 2512 2513
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2514 2515 2516
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2517 2518
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564
        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:
2565
        case VIR_NETWORK_FORWARD_OPEN:
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605
        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;
}


2606
static int
2607
networkStartNetworkExternal(virNetworkObjPtr network)
2608 2609
{
    /* put anything here that needs to be done each time a network of
2610
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2611 2612 2613
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2614
    return networkCreateInterfacePool(network->def);
2615 2616
}

2617
static int networkShutdownNetworkExternal(virNetworkObjPtr network ATTRIBUTE_UNUSED)
2618 2619
{
    /* put anything here that needs to be done each time a network of
2620
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2621 2622 2623 2624 2625 2626 2627
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

static int
2628 2629
networkStartNetwork(virNetworkDriverStatePtr driver,
                    virNetworkObjPtr network)
2630
{
2631 2632 2633
    int ret = -1;

    VIR_DEBUG("driver=%p, network=%p", driver, network);
2634 2635

    if (virNetworkObjIsActive(network)) {
2636 2637
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2638
        return ret;
2639 2640
    }

2641 2642 2643
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2644
    if (virNetworkObjSetDefTransient(network, true) < 0)
2645
        goto cleanup;
2646

2647 2648
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2649
    if (networkRunHook(network, NULL, NULL,
2650 2651 2652 2653
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2654
    switch (network->def->forward.type) {
2655 2656 2657 2658

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2659
    case VIR_NETWORK_FORWARD_OPEN:
2660
        if (networkStartNetworkVirtual(driver, network) < 0)
2661
            goto cleanup;
2662 2663 2664
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2665 2666 2667 2668 2669 2670 2671 2672 2673
        if (network->def->bridge) {
            if (networkStartNetworkBridge(network) < 0)
                goto cleanup;
            break;
        }
        /* intentionally fall through to the macvtap/direct case for
         * VIR_NETWORK_FORWARD_BRIDGE with no bridge device defined
         * (since that is macvtap bridge mode).
         */
2674 2675 2676
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2677
    case VIR_NETWORK_FORWARD_HOSTDEV:
2678
        if (networkStartNetworkExternal(network) < 0)
2679
            goto cleanup;
2680 2681 2682
        break;
    }

2683
    /* finally we can call the 'started' hook script if any */
2684
    if (networkRunHook(network, NULL, NULL,
2685 2686 2687 2688
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2689 2690 2691
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2692
    VIR_DEBUG("Writing network status to disk");
2693
    if (virNetworkSaveStatus(driver->stateDir, network) < 0)
2694
        goto cleanup;
2695 2696

    network->active = 1;
2697 2698
    VIR_INFO("Network '%s' started up", network->def->name);
    ret = 0;
2699

2700
 cleanup:
2701
    if (ret < 0) {
2702
        virNetworkObjUnsetDefTransient(network);
2703 2704
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
2705
        networkShutdownNetwork(driver, network);
2706 2707 2708 2709 2710 2711 2712
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2713 2714 2715
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
                       virNetworkObjPtr network)
2716 2717 2718 2719 2720 2721 2722 2723 2724
{
    int ret = 0;
    char *stateFile;

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

    if (!virNetworkObjIsActive(network))
        return 0;

2725
    stateFile = virNetworkConfigFile(driver->stateDir,
2726
                                     network->def->name);
2727 2728 2729 2730 2731 2732
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2733
    switch (network->def->forward.type) {
2734 2735 2736 2737

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2738
    case VIR_NETWORK_FORWARD_OPEN:
2739
        ret = networkShutdownNetworkVirtual(driver, network);
2740 2741 2742
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2743 2744 2745 2746 2747 2748 2749 2750
        if (network->def->bridge) {
            ret = networkShutdownNetworkBridge(network);
            break;
        }
        /* intentionally fall through to the macvtap/direct case for
         * VIR_NETWORK_FORWARD_BRIDGE with no bridge device defined
         * (since that is macvtap bridge mode).
         */
2751 2752 2753
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2754
    case VIR_NETWORK_FORWARD_HOSTDEV:
2755
        ret = networkShutdownNetworkExternal(network);
2756 2757 2758
        break;
    }

2759
    /* now that we know it's stopped call the hook if present */
2760
    networkRunHook(network, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2761 2762
                   VIR_HOOK_SUBOP_END);

2763
    network->active = 0;
2764
    virNetworkObjUnsetDefTransient(network);
2765
    return ret;
2766 2767 2768
}


2769
static virNetworkPtr networkLookupByUUID(virConnectPtr conn,
2770 2771
                                         const unsigned char *uuid)
{
2772
    virNetworkDriverStatePtr driver = networkGetDriver();
2773 2774
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;
2775

2776
    network = virNetworkObjFindByUUID(driver->networks, uuid);
2777
    if (!network) {
2778 2779
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
2780
        virReportError(VIR_ERR_NO_NETWORK,
2781 2782
                       _("no network with matching uuid '%s'"),
                       uuidstr);
2783
        goto cleanup;
2784 2785
    }

2786 2787 2788
    if (virNetworkLookupByUUIDEnsureACL(conn, network->def) < 0)
        goto cleanup;

2789 2790
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2791
 cleanup:
2792
    virNetworkObjEndAPI(&network);
2793
    return ret;
2794 2795
}

2796
static virNetworkPtr networkLookupByName(virConnectPtr conn,
2797 2798
                                         const char *name)
{
2799
    virNetworkDriverStatePtr driver = networkGetDriver();
2800 2801 2802
    virNetworkObjPtr network;
    virNetworkPtr ret = NULL;

2803
    network = virNetworkObjFindByName(driver->networks, name);
2804
    if (!network) {
2805 2806
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
2807
        goto cleanup;
2808 2809
    }

2810 2811 2812
    if (virNetworkLookupByNameEnsureACL(conn, network->def) < 0)
        goto cleanup;

2813 2814
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

2815
 cleanup:
2816
    virNetworkObjEndAPI(&network);
2817
    return ret;
2818 2819
}

2820 2821
static int networkConnectNumOfNetworks(virConnectPtr conn)
{
2822
    virNetworkDriverStatePtr driver = networkGetDriver();
2823
    int nactive;
2824

2825 2826 2827
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

2828 2829 2830 2831
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
2832

2833 2834 2835
    return nactive;
}

2836 2837 2838 2839 2840
static int networkConnectListNetworks(virConnectPtr conn,
                                      char **const names,
                                      int nnames)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
2841
    int got = 0;
2842

2843 2844 2845
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

2846 2847 2848 2849
    got = virNetworkObjListGetNames(driver->networks,
                                    true, names, nnames,
                                    virConnectListNetworksCheckACL,
                                    conn);
2850

2851 2852 2853
    return got;
}

2854 2855
static int networkConnectNumOfDefinedNetworks(virConnectPtr conn)
{
2856
    virNetworkDriverStatePtr driver = networkGetDriver();
2857
    int ninactive = 0;
2858

2859 2860 2861
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2862 2863 2864 2865
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
2866

2867 2868 2869
    return ninactive;
}

2870 2871 2872
static int networkConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
2873
    int got = 0;
2874

2875 2876 2877
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2878 2879 2880 2881
    got = virNetworkObjListGetNames(driver->networks,
                                    false, names, nnames,
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
2882 2883 2884
    return got;
}

2885
static int
2886 2887 2888
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
2889
{
2890
    virNetworkDriverStatePtr driver = networkGetDriver();
2891 2892 2893 2894
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

2895 2896 2897
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

2898
    ret = virNetworkObjListExport(conn, driver->networks, nets,
2899 2900
                                  virConnectListAllNetworksCheckACL,
                                  flags);
2901

2902
 cleanup:
2903 2904
    return ret;
}
2905

2906 2907 2908 2909 2910 2911 2912 2913
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
2914
    virNetworkDriverStatePtr driver = networkGetDriver();
2915 2916 2917 2918 2919 2920
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
2921
                                       net, eventID, callback,
2922 2923 2924
                                       opaque, freecb, &ret) < 0)
        ret = -1;

2925
 cleanup:
2926 2927 2928 2929 2930 2931 2932
    return ret;
}

static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
2933
    virNetworkDriverStatePtr driver = networkGetDriver();
2934 2935 2936 2937 2938
    int ret = -1;

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

2939 2940 2941 2942 2943 2944
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;
2945

2946
 cleanup:
2947 2948 2949
    return ret;
}

2950 2951 2952 2953 2954
static int networkIsActive(virNetworkPtr net)
{
    virNetworkObjPtr obj;
    int ret = -1;

2955 2956
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
2957 2958 2959 2960

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

2961 2962
    ret = virNetworkObjIsActive(obj);

2963
 cleanup:
2964
    virNetworkObjEndAPI(&obj);
2965 2966 2967 2968 2969 2970 2971 2972
    return ret;
}

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

2973 2974
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
2975 2976 2977 2978

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

2979 2980
    ret = obj->persistent;

2981
 cleanup:
2982
    virNetworkObjEndAPI(&obj);
2983 2984 2985 2986
    return ret;
}


2987 2988
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
2989 2990 2991
 * 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.
2992 2993 2994 2995 2996 2997 2998 2999
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{

    int ret = -1, id = 0;
    char *newname = NULL;
3000 3001 3002 3003 3004
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3005
        p && p[1] == 'd')
3006
        templ = def->bridge;
3007 3008 3009 3010

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3011 3012 3013 3014 3015 3016 3017
        /* 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)) {
3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069
            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;
}


3070
static int
3071
networkValidate(virNetworkDriverStatePtr driver,
3072
                virNetworkDefPtr def)
3073
{
3074
    size_t i, j;
3075 3076
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3077
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3078
    bool ipv4def = false, ipv6def = false;
3079
    bool bandwidthAllowed = true;
3080
    bool usesInterface = false, usesAddress = false;
3081

3082 3083 3084
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3085 3086 3087
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3088 3089
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
3090 3091
        def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
        def->forward.type == VIR_NETWORK_FORWARD_OPEN) {
3092

3093 3094 3095 3096
        /* 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)
3097 3098 3099
            return -1;

        virNetworkSetBridgeMacAddr(def);
3100 3101
    } else {
        /* They are also the only types that currently support setting
3102 3103
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
3104
         */
3105 3106 3107 3108 3109 3110 3111 3112
        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;
        }
3113
        if (virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0)) {
3114 3115 3116 3117
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3118
                           virNetworkForwardTypeToString(def->forward.type));
3119 3120
            return -1;
        }
3121
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
3122 3123 3124 3125
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3126
                           virNetworkForwardTypeToString(def->forward.type));
3127 3128 3129 3130 3131 3132 3133
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3134
                           virNetworkForwardTypeToString(def->forward.type));
3135 3136
            return -1;
        }
3137 3138 3139 3140 3141 3142 3143 3144
        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;
        }
3145
        bandwidthAllowed = false;
3146 3147
    }

3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181
    /* 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 已提交
3182 3183 3184
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
3185
    for (i = 0;
3186
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
3187
         i++) {
G
Gene Czarcinski 已提交
3188 3189 3190 3191 3192
        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 -- "
3193 3194
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211
                    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;
                }
3212 3213 3214
            }
        }
    }
3215 3216 3217 3218 3219 3220

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

3221 3222 3223
    vlanAllowed = (def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV ||
                   def->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH ||
                   (def->forward.type == VIR_NETWORK_FORWARD_BRIDGE &&
J
Ján Tomko 已提交
3224 3225
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3226
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3227 3228

    vlanUsed = def->vlan.nTags > 0;
3229 3230
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
3231 3232 3233 3234 3235
            /* 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.
             */
3236
            if (def->portGroups[i].virtPortProfile) {
3237
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
3238
                    def->portGroups[i].virtPortProfile->virtPortType
3239 3240 3241 3242 3243 3244 3245
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
3246
        }
3247
        if (def->portGroups[i].isDefault) {
3248 3249 3250 3251 3252
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
3253
                               def->name, defaultPortGroup->name,
3254
                               def->portGroups[i].name);
3255
                return -1;
3256
            }
3257
            defaultPortGroup = &def->portGroups[i];
3258
        }
3259 3260 3261 3262 3263 3264 3265 3266 3267
        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;
            }
        }
3268 3269 3270 3271 3272 3273 3274 3275
        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;
        }
3276
    }
3277 3278 3279 3280 3281 3282 3283
    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.
         */
3284 3285 3286 3287 3288 3289
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303

    if (def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
        for (i = 0; i < def->nPortGroups; i++) {
            if (def->portGroups[i].bandwidth) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported <bandwidth> element "
                                 "in <portgroup name='%s'> of "
                                 "network '%s' with forward mode='%s'"),
                               def->portGroups[i].name, def->name,
                               virNetworkForwardTypeToString(def->forward.type));
                return -1;
            }
        }
    }
3304 3305 3306
    return 0;
}

3307 3308
static virNetworkPtr networkCreateXML(virConnectPtr conn, const char *xml)
{
3309
    virNetworkDriverStatePtr driver = networkGetDriver();
3310
    virNetworkDefPtr def;
3311
    virNetworkObjPtr network = NULL;
3312
    virNetworkPtr ret = NULL;
3313
    virObjectEventPtr event = NULL;
3314

3315
    if (!(def = virNetworkDefParseString(xml)))
3316
        goto cleanup;
3317

3318 3319 3320
    if (virNetworkCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3321
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3322
        goto cleanup;
3323

3324 3325 3326
    /* 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.
3327
     */
3328 3329 3330
    if (!(network = virNetworkAssignDef(driver->networks, def,
                                        VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                        VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3331 3332
        goto cleanup;
    def = NULL;
3333

3334
    if (networkStartNetwork(driver, network) < 0) {
3335
        virNetworkRemoveInactive(driver->networks,
3336
                                 network);
3337
        goto cleanup;
3338 3339
    }

3340 3341
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3342 3343
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3344

3345
    VIR_INFO("Creating network '%s'", network->def->name);
3346 3347
    ret = virGetNetwork(conn, network->def->name, network->def->uuid);

3348
 cleanup:
3349
    virNetworkDefFree(def);
3350 3351
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3352
    virNetworkObjEndAPI(&network);
3353
    return ret;
3354 3355
}

3356 3357
static virNetworkPtr networkDefineXML(virConnectPtr conn, const char *xml)
{
3358
    virNetworkDriverStatePtr driver = networkGetDriver();
3359
    virNetworkDefPtr def = NULL;
3360
    bool freeDef = true;
3361
    virNetworkObjPtr network = NULL;
3362
    virNetworkPtr ret = NULL;
3363
    virObjectEventPtr event = NULL;
3364

3365
    if (!(def = virNetworkDefParseString(xml)))
3366
        goto cleanup;
3367

3368 3369 3370
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3371
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3372
        goto cleanup;
3373

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

3377
    /* def was assigned to network object */
3378
    freeDef = false;
3379 3380

    if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
3381
        if (!virNetworkObjIsActive(network)) {
3382
            virNetworkRemoveInactive(driver->networks, network);
3383 3384
            goto cleanup;
        }
3385 3386 3387 3388 3389
        /* 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);
3390 3391 3392
        goto cleanup;
    }

3393
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3394 3395
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3396

3397 3398
    VIR_INFO("Defining network '%s'", def->name);
    ret = virGetNetwork(conn, def->name, def->uuid);
3399

3400
 cleanup:
3401 3402
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3403
    if (freeDef)
J
Ján Tomko 已提交
3404
        virNetworkDefFree(def);
3405
    virNetworkObjEndAPI(&network);
3406
    return ret;
3407 3408
}

3409
static int
3410 3411
networkUndefine(virNetworkPtr net)
{
3412
    virNetworkDriverStatePtr driver = networkGetDriver();
3413
    virNetworkObjPtr network;
3414
    int ret = -1;
3415
    bool active = false;
3416
    virObjectEventPtr event = NULL;
3417

3418
    if (!(network = networkObjFromNetwork(net)))
3419
        goto cleanup;
3420

3421 3422 3423
    if (virNetworkUndefineEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3424 3425
    if (virNetworkObjIsActive(network))
        active = true;
3426

3427 3428 3429 3430 3431 3432
    if (!network->persistent) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3433
    /* remove autostart link */
3434
    if (virNetworkDeleteConfig(driver->networkConfigDir,
3435 3436
                               driver->networkAutostartDir,
                               network) < 0)
3437
        goto cleanup;
3438

3439 3440
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3441 3442
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3443

3444
    VIR_INFO("Undefining network '%s'", network->def->name);
3445
    if (!active) {
3446
        if (networkRemoveInactive(driver, network) < 0)
3447
            goto cleanup;
3448 3449 3450 3451 3452 3453
    } 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);
3454 3455
    }

3456
    ret = 0;
3457

3458
 cleanup:
3459 3460
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3461
    virNetworkObjEndAPI(&network);
3462
    return ret;
3463 3464
}

3465 3466 3467 3468 3469 3470 3471 3472
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3473
    virNetworkDriverStatePtr driver = networkGetDriver();
3474
    virNetworkObjPtr network = NULL;
3475 3476
    int isActive, ret = -1;
    size_t i;
3477
    virNetworkIPDefPtr ipdef;
3478
    bool oldDhcpActive = false;
3479
    bool needFirewallRefresh = false;
3480

3481 3482 3483 3484 3485

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3486
    if (!(network = networkObjFromNetwork(net)))
3487 3488
        goto cleanup;

3489 3490 3491
    if (virNetworkUpdateEnsureACL(net->conn, network->def, flags) < 0)
        goto cleanup;

3492
    /* see if we are listening for dhcp pre-modification */
3493
    for (i = 0;
3494
         (ipdef = virNetworkDefGetIPByIndex(network->def, AF_INET, i));
3495
         i++) {
3496 3497 3498 3499 3500 3501
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3502 3503
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3504
     */
3505
    isActive = virNetworkObjIsActive(network);
3506 3507
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3508 3509 3510 3511 3512 3513 3514
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531
    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).
                 */
3532 3533 3534 3535
                if (network->def->forward.type != VIR_NETWORK_FORWARD_OPEN) {
                    networkRemoveFirewallRules(network->def);
                    needFirewallRefresh = true;
                }
3536 3537 3538 3539 3540 3541 3542
                break;
            default:
                break;
            }
        }
    }

3543
    /* update the network config in memory/on disk */
3544 3545
    if (virNetworkObjUpdate(network, command, section, parentIndex, xml, flags) < 0) {
        if (needFirewallRefresh)
3546
            ignore_value(networkAddFirewallRules(network->def));
3547 3548 3549
        goto cleanup;
    }

3550
    if (needFirewallRefresh && networkAddFirewallRules(network->def) < 0)
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569
        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 ||
3570 3571 3572 3573 3574 3575 3576 3577
            section == VIR_NETWORK_SECTION_IP_DHCP_RANGE ||
            section == VIR_NETWORK_SECTION_DNS_TXT ||
            section == VIR_NETWORK_SECTION_DNS_SRV) {
            /* these sections all change things on the dnsmasq
             * commandline (i.e. in the .conf file), so we need to
             * kill and restart dnsmasq, because dnsmasq sets its uid
             * to "nobody" after it starts, and is unable to re-read
             * the conf file (owned by root, mode 600)
3578
             */
3579
            if (networkRestartDhcpDaemon(driver, network) < 0)
3580 3581
                goto cleanup;

3582 3583 3584 3585 3586 3587 3588 3589
        } 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;

3590
            for (i = 0;
3591
                 (ipdef = virNetworkDefGetIPByIndex(network->def, AF_INET, i));
3592
                 i++) {
3593 3594 3595 3596 3597 3598 3599
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3600 3601
                 networkRestartDhcpDaemon(driver, network) < 0) ||
                networkRefreshDhcpDaemon(driver, network) < 0) {
3602 3603 3604
                goto cleanup;
            }

3605 3606 3607 3608
        } else if (section == VIR_NETWORK_SECTION_DNS_HOST) {
            /* this section only changes data in an external file
             * (not the .conf file) so we can just update the config
             * files and send SIGHUP to dnsmasq.
3609
             */
3610
            if (networkRefreshDhcpDaemon(driver, network) < 0)
3611 3612 3613 3614 3615 3616 3617 3618
                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.
             */
3619
            if (networkRefreshRadvd(driver, network) < 0)
3620 3621 3622 3623
                goto cleanup;
        }

        /* save current network state to disk */
3624
        if ((ret = virNetworkSaveStatus(driver->stateDir,
3625
                                        network)) < 0) {
3626
            goto cleanup;
3627
        }
3628
    }
3629 3630 3631 3632 3633 3634

    /* call the 'updated' network hook script */
    if (networkRunHook(network, NULL, NULL, VIR_HOOK_NETWORK_OP_UPDATED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

3635
    ret = 0;
3636
 cleanup:
3637
    virNetworkObjEndAPI(&network);
3638 3639 3640
    return ret;
}

3641 3642
static int networkCreate(virNetworkPtr net)
{
3643
    virNetworkDriverStatePtr driver = networkGetDriver();
3644 3645
    virNetworkObjPtr network;
    int ret = -1;
3646
    virObjectEventPtr event = NULL;
3647

3648
    if (!(network = networkObjFromNetwork(net)))
3649
        goto cleanup;
3650

3651 3652 3653
    if (virNetworkCreateEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3654
    if ((ret = networkStartNetwork(driver, network)) < 0)
3655
        goto cleanup;
3656

3657 3658
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3659 3660
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3661

3662
 cleanup:
3663 3664
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3665
    virNetworkObjEndAPI(&network);
3666
    return ret;
3667 3668
}

3669 3670
static int networkDestroy(virNetworkPtr net)
{
3671
    virNetworkDriverStatePtr driver = networkGetDriver();
3672 3673
    virNetworkObjPtr network;
    int ret = -1;
3674
    virObjectEventPtr event = NULL;
3675

3676
    if (!(network = networkObjFromNetwork(net)))
3677
        goto cleanup;
3678

3679 3680 3681
    if (virNetworkDestroyEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
3682
    if (!virNetworkObjIsActive(network)) {
3683
        virReportError(VIR_ERR_OPERATION_INVALID,
3684 3685
                       _("network '%s' is not active"),
                       network->def->name);
3686 3687 3688
        goto cleanup;
    }

3689
    if ((ret = networkShutdownNetwork(driver, network)) < 0)
3690 3691
        goto cleanup;

3692 3693
    event = virNetworkEventLifecycleNew(network->def->name,
                                        network->def->uuid,
3694 3695
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
3696

3697
    if (!network->persistent &&
3698
        networkRemoveInactive(driver, network) < 0) {
3699 3700
        ret = -1;
        goto cleanup;
3701
    }
3702

3703
 cleanup:
3704 3705
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3706
    virNetworkObjEndAPI(&network);
3707 3708 3709
    return ret;
}

3710
static char *networkGetXMLDesc(virNetworkPtr net,
3711
                               unsigned int flags)
3712
{
3713
    virNetworkObjPtr network;
3714
    virNetworkDefPtr def;
3715
    char *ret = NULL;
3716

3717
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
3718

3719 3720
    if (!(network = networkObjFromNetwork(net)))
        return ret;
3721

3722 3723 3724
    if (virNetworkGetXMLDescEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3725 3726 3727 3728 3729 3730
    if ((flags & VIR_NETWORK_XML_INACTIVE) && network->newDef)
        def = network->newDef;
    else
        def = network->def;

    ret = virNetworkDefFormat(def, flags);
3731

3732
 cleanup:
3733
    virNetworkObjEndAPI(&network);
3734
    return ret;
3735 3736 3737
}

static char *networkGetBridgeName(virNetworkPtr net) {
3738 3739 3740
    virNetworkObjPtr network;
    char *bridge = NULL;

3741 3742
    if (!(network = networkObjFromNetwork(net)))
        return bridge;
3743

3744 3745 3746
    if (virNetworkGetBridgeNameEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3747
    if (!(network->def->bridge)) {
3748 3749 3750
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
                       network->def->name);
3751 3752 3753
        goto cleanup;
    }

3754
    ignore_value(VIR_STRDUP(bridge, network->def->bridge));
3755

3756
 cleanup:
3757
    virNetworkObjEndAPI(&network);
3758 3759 3760 3761
    return bridge;
}

static int networkGetAutostart(virNetworkPtr net,
J
Ján Tomko 已提交
3762
                               int *autostart)
3763
{
3764 3765
    virNetworkObjPtr network;
    int ret = -1;
3766

3767 3768
    if (!(network = networkObjFromNetwork(net)))
        return ret;
3769

3770 3771 3772
    if (virNetworkGetAutostartEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3773
    *autostart = network->autostart;
3774
    ret = 0;
3775

3776
 cleanup:
3777
    virNetworkObjEndAPI(&network);
3778
    return ret;
3779 3780 3781
}

static int networkSetAutostart(virNetworkPtr net,
3782 3783
                               int autostart)
{
3784
    virNetworkDriverStatePtr driver = networkGetDriver();
3785
    virNetworkObjPtr network;
3786
    char *configFile = NULL, *autostartLink = NULL;
3787
    int ret = -1;
3788

3789

3790
    if (!(network = networkObjFromNetwork(net)))
3791
        goto cleanup;
3792

3793 3794 3795
    if (virNetworkSetAutostartEnsureACL(net->conn, network->def) < 0)
        goto cleanup;

3796
    if (!network->persistent) {
3797 3798
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
3799 3800 3801
        goto cleanup;
    }

3802 3803
    autostart = (autostart != 0);

3804
    if (network->autostart != autostart) {
3805
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir, network->def->name)) == NULL)
3806
            goto cleanup;
3807
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, network->def->name)) == NULL)
3808 3809
            goto cleanup;

3810
        if (autostart) {
3811
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
3812
                virReportSystemError(errno,
3813 3814
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
3815 3816
                goto cleanup;
            }
3817

3818
            if (symlink(configFile, autostartLink) < 0) {
3819
                virReportSystemError(errno,
3820
                                     _("Failed to create symlink '%s' to '%s'"),
3821
                                     autostartLink, configFile);
3822 3823 3824
                goto cleanup;
            }
        } else {
3825
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
3826
                virReportSystemError(errno,
3827
                                     _("Failed to delete symlink '%s'"),
3828
                                     autostartLink);
3829 3830
                goto cleanup;
            }
3831 3832
        }

3833
        network->autostart = autostart;
3834
    }
3835
    ret = 0;
3836

3837
 cleanup:
3838 3839
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
3840
    virNetworkObjEndAPI(&network);
3841
    return ret;
3842 3843
}

3844
static int
3845 3846 3847 3848
networkGetDHCPLeases(virNetworkPtr network,
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
3849
{
3850
    virNetworkDriverStatePtr driver = networkGetDriver();
3851 3852 3853
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
3854
    ssize_t size = 0;
3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865
    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;
3866
    virNetworkIPDefPtr ipdef_tmp = NULL;
3867 3868
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
3869
    virNetworkObjPtr obj;
3870
    virMacAddr mac_addr;
3871 3872 3873

    virCheckFlags(0, -1);

3874 3875 3876 3877 3878 3879
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

3880 3881 3882 3883 3884
    if (!(obj = networkObjFromNetwork(network)))
        return -1;

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

    /* Retrieve custom leases file location */
3887
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, obj->def->bridge);
3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930

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

3931
        if (mac && virMacAddrCompare(mac, mac_tmp))
3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972
            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)) {
3973
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
3974 3975 3976 3977 3978 3979 3980 3981
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
3982
                (VIR_STRDUP(lease->iface, obj->def->bridge) < 0))
3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014
                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);
4015
    VIR_FREE(lease_entries);
4016 4017
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4018

4019
    virNetworkObjEndAPI(&obj);
4020

4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031
    return rv;

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

4032 4033

static virNetworkDriver networkDriver = {
4034
    .name = "bridge",
4035 4036 4037 4038 4039
    .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 */
4040 4041
    .connectNetworkEventRegisterAny = networkConnectNetworkEventRegisterAny, /* 1.2.1 */
    .connectNetworkEventDeregisterAny = networkConnectNetworkEventDeregisterAny, /* 1.2.1 */
4042 4043
    .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
    .networkLookupByName = networkLookupByName, /* 0.2.0 */
4044 4045
    .networkCreateXML = networkCreateXML, /* 0.2.0 */
    .networkDefineXML = networkDefineXML, /* 0.2.0 */
4046
    .networkUndefine = networkUndefine, /* 0.2.0 */
4047
    .networkUpdate = networkUpdate, /* 0.10.2 */
4048
    .networkCreate = networkCreate, /* 0.2.0 */
4049 4050 4051 4052 4053 4054 4055
    .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 */
4056
    .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.2.6 */
4057 4058 4059
};

static virStateDriver networkStateDriver = {
4060
    .name = "bridge",
4061
    .stateInitialize  = networkStateInitialize,
4062
    .stateAutoStart  = networkStateAutoStart,
4063 4064
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
4065 4066
};

4067 4068
int networkRegister(void)
{
4069
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
4070
        return -1;
4071 4072
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
4073 4074
    return 0;
}
4075 4076 4077

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

4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112
/* A unified function to log network connections and disconnections */

static void
networkLogAllocation(virNetworkDefPtr netdef,
                     virDomainNetType actualType,
                     virNetworkForwardIfDefPtr dev,
                     virDomainNetDefPtr iface,
                     bool inUse)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    const char *verb = inUse ? "using" : "releasing";

    if (!dev) {
        VIR_INFO("MAC %s %s network %s (%d connections)",
                 virMacAddrFormat(&iface->mac, macStr), verb,
                 netdef->name, netdef->connections);
    } else {
        if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
            VIR_INFO("MAC %s %s network %s (%d connections) "
                     "physical device %04x:%02x:%02x.%x (%d connections)",
                     virMacAddrFormat(&iface->mac, macStr), verb,
                     netdef->name, netdef->connections,
                     dev->device.pci.domain, dev->device.pci.bus,
                     dev->device.pci.slot, dev->device.pci.function,
                     dev->connections);
        } else {
            VIR_INFO("MAC %s %s network %s (%d connections) "
                     "physical device %s (%d connections)",
                     virMacAddrFormat(&iface->mac, macStr), verb,
                     netdef->name, netdef->connections,
                     dev->device.dev, dev->connections);
        }
    }
}

4113 4114 4115 4116 4117 4118 4119 4120 4121
/* 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:
4122
 * @dom: domain definition that @iface belongs to
4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133
 * @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
4134 4135
networkAllocateActualDevice(virDomainDefPtr dom,
                            virDomainNetDefPtr iface)
4136
{
4137
    virNetworkDriverStatePtr driver = networkGetDriver();
4138
    virDomainNetType actualType = iface->type;
4139 4140
    virNetworkObjPtr network = NULL;
    virNetworkDefPtr netdef = NULL;
4141
    virNetDevBandwidthPtr bandwidth = NULL;
4142 4143 4144
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
4145
    virNetworkForwardIfDefPtr dev = NULL;
4146
    size_t i;
4147 4148 4149
    int ret = -1;

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4150
        goto validate;
4151 4152 4153 4154

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

4155
    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
4156
    if (!network) {
4157 4158 4159
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4160
        goto error;
4161 4162
    }
    netdef = network->def;
4163

4164 4165 4166 4167 4168 4169 4170
    if (!virNetworkObjIsActive(network)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4171 4172 4173
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

4174 4175 4176
    /* 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 已提交
4177
     */
4178 4179 4180 4181 4182 4183
    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.
     */
4184 4185 4186 4187 4188 4189

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

4190 4191
    if (bandwidth && virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
                                            bandwidth) < 0)
4192
        goto error;
4193

4194 4195 4196 4197 4198 4199 4200 4201
    /* 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;

4202 4203
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
4204

4205 4206 4207 4208 4209 4210 4211 4212 4213 4214
    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;

4215 4216
    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
4217 4218
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
4219
        /* for these forward types, the actual net type really *is*
4220
         * NETWORK; we just keep the info from the portgroup in
4221
         * iface->data.network.actual
J
Ján Tomko 已提交
4222
         */
4223
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
4224

4225
        /* we also store the bridge device and macTableManager settings
4226 4227 4228 4229 4230 4231 4232
         * 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;
4233 4234
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4235

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

4239
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
4240
               netdef->bridge) {
4241 4242 4243 4244 4245

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

4246
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
4247 4248
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
4249
            goto error;
4250 4251
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4252

4253 4254 4255 4256 4257 4258 4259 4260
        /* 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) {
4261
            goto error;
4262 4263 4264 4265 4266 4267 4268 4269 4270 4271
        }
        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);
4272
                goto error;
4273 4274 4275
            }
        }

4276
    } else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4277

4278
        virDomainHostdevSubsysPCIBackendType backend;
4279

4280
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
4281
        if (networkCreateInterfacePool(netdef) < 0)
4282 4283 4284
            goto error;

        /* pick first dev with 0 connections */
4285 4286 4287
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301
                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;
4302
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
4303
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
4304
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
4305

E
Eric Blake 已提交
4306
        switch (netdef->forward.driverName) {
4307
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
4308
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4309 4310
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
4311
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
4312 4313
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
4314
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325
            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;

4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350
        /* 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;
            }
        }

4351 4352 4353 4354
    } 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)) {
4355 4356 4357 4358 4359 4360

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

        /* Set type=direct and appropriate <source mode='xxx'/> */
4361
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
4362
        switch (netdef->forward.type) {
4363
        case VIR_NETWORK_FORWARD_BRIDGE:
4364
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
4365 4366
            break;
        case VIR_NETWORK_FORWARD_PRIVATE:
4367
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
4368 4369
            break;
        case VIR_NETWORK_FORWARD_VEPA:
4370
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
4371 4372
            break;
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
4373
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PASSTHRU;
4374 4375 4376
            break;
        }

4377 4378 4379 4380 4381 4382 4383 4384
        /* 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) {
4385
            goto error;
4386
        }
4387
        virtport = iface->data.network.actual->virtPortProfile;
4388
        if (virtport) {
4389 4390 4391 4392 4393 4394 4395 4396
            /* 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);
4397
                goto error;
4398 4399
            }
        }
4400

4401 4402 4403
        /* 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).
         */
4404
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4405 4406 4407 4408
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4409
            goto error;
4410 4411 4412
        } else {
            /* pick an interface from the pool */

4413
            if (networkCreateInterfacePool(netdef) < 0)
4414 4415
                goto error;

4416 4417 4418 4419 4420
            /* 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.
4421
             */
4422 4423
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4424 4425 4426
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4427

4428
                /* pick first dev with 0 connections */
4429 4430 4431
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4432 4433 4434 4435 4436
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4437
                dev = &netdef->forward.ifs[0];
4438 4439 4440
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4441 4442 4443 4444
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4445 4446 4447 4448
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4449
                goto error;
4450
            }
4451 4452
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
4453
                goto error;
4454 4455 4456
        }
    }

M
Michal Privoznik 已提交
4457 4458 4459
    if (networkMacMgrAdd(driver, network, dom->name, &iface->mac) < 0)
        goto error;

4460
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
4461
        goto error;
4462

4463
 validate:
4464 4465 4466 4467 4468
    /* 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.
     */

4469
    if (virDomainNetGetActualVlan(iface)) {
4470 4471 4472 4473
        /* vlan configuration via libvirt is only supported for PCI
         * Passthrough SR-IOV devices (hostdev or macvtap passthru
         * mode) and openvswitch bridges. Otherwise log an error and
         * fail
4474 4475
         */
        if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
4476 4477 4478
              (actualType == VIR_DOMAIN_NET_TYPE_DIRECT &&
               virDomainNetGetActualDirectMode(iface)
               == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) ||
4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497
              (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;
        }
    }
4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508
    if (virDomainNetGetActualBandwidth(iface)) {
        /* bandwidth configuration via libvirt is not supported for
         * hostdev network devices
         */
        if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("bandwidth settings are not supported "
                             "for hostdev interfaces"));
            goto error;
        }
    }
4509 4510 4511

    if (netdef) {
        netdef->connections++;
4512
        if (dev)
4513 4514 4515 4516 4517 4518
            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 */
4519
            netdef->connections--;
4520 4521 4522 4523
            if (dev)
                dev->connections--;
            goto error;
        }
4524
        networkLogAllocation(netdef, actualType, dev, iface, true);
4525 4526
    }

4527
    ret = 0;
4528

4529
 cleanup:
4530
    virNetworkObjEndAPI(&network);
4531 4532
    return ret;

4533
 error:
4534
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4535 4536 4537
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4538
    goto cleanup;
4539 4540 4541
}

/* networkNotifyActualDevice:
4542
 * @dom: domain definition that @iface belongs to
4543 4544 4545 4546 4547 4548 4549 4550 4551 4552
 * @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
4553 4554
networkNotifyActualDevice(virDomainDefPtr dom,
                          virDomainNetDefPtr iface)
4555
{
4556
    virNetworkDriverStatePtr driver = networkGetDriver();
4557
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4558 4559
    virNetworkObjPtr network;
    virNetworkDefPtr netdef;
4560
    virNetworkForwardIfDefPtr dev = NULL;
4561 4562
    size_t i;
    int ret = -1;
4563 4564

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

4567
    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
4568
    if (!network) {
4569 4570 4571
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4572 4573 4574 4575
        goto error;
    }
    netdef = network->def;

4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586
    /* 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;

4587
    if (!iface->data.network.actual ||
4588 4589
        (actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
4590 4591
        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
        goto success;
4592 4593
    }

4594
    if (networkCreateInterfacePool(netdef) < 0)
4595
        goto error;
4596

4597
    if (netdef->forward.nifs == 0) {
4598
        virReportError(VIR_ERR_INTERNAL_ERROR,
4599 4600
                       _("network '%s' uses a direct or hostdev mode, "
                         "but has no forward dev and no interface pool"),
4601
                       netdef->name);
4602
        goto error;
4603
    }
4604

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

4608 4609 4610 4611 4612 4613 4614 4615 4616
        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 */
4617 4618
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4619
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4620 4621
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4622 4623 4624 4625 4626
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4627
            virReportError(VIR_ERR_INTERNAL_ERROR,
4628 4629
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4630
                           netdef->name, actualDev);
4631
            goto error;
4632 4633
        }

4634
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4635 4636
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4637
         */
4638
        if ((dev->connections > 0) &&
4639 4640
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4641 4642
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
4643
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4644
            virReportError(VIR_ERR_INTERNAL_ERROR,
4645 4646
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
4647
                           netdef->name, actualDev);
4648
            goto error;
4649
        }
4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661
    }  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 */
4662 4663
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4664
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4665
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
4666 4667
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4668 4669 4670 4671 4672 4673 4674 4675 4676
                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,
4677 4678 4679 4680
                           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 已提交
4681
            goto error;
4682 4683 4684 4685 4686 4687 4688
        }

        /* 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) &&
4689
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4690 4691 4692 4693 4694 4695 4696 4697 4698
            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;
        }
4699 4700
    }

4701
 success:
4702
    netdef->connections++;
4703 4704
    if (dev)
        dev->connections++;
4705 4706 4707 4708 4709 4710 4711 4712 4713
    /* 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;
    }
4714
    networkLogAllocation(netdef, actualType, dev, iface, true);
4715

4716
    ret = 0;
4717
 cleanup:
4718
    virNetworkObjEndAPI(&network);
4719
    return ret;
4720

4721
 error:
4722
    goto cleanup;
4723 4724 4725
}


4726

4727
/* networkReleaseActualDevice:
4728
 * @dom: domain definition that @iface belongs to
4729 4730 4731 4732 4733 4734 4735 4736 4737 4738
 * @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
4739 4740
networkReleaseActualDevice(virDomainDefPtr dom,
                           virDomainNetDefPtr iface)
4741
{
4742
    virNetworkDriverStatePtr driver = networkGetDriver();
4743
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4744
    virNetworkObjPtr network;
4745
    virNetworkDefPtr netdef;
4746
    virNetworkForwardIfDefPtr dev = NULL;
4747 4748
    size_t i;
    int ret = -1;
4749 4750

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

4753
    network = virNetworkObjFindByName(driver->networks, iface->data.network.name);
4754
    if (!network) {
4755 4756 4757
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4758 4759 4760 4761
        goto error;
    }
    netdef = network->def;

4762 4763
    if (iface->data.network.actual &&
        (netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
4764
         netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
4765 4766
         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
         netdef->forward.type == VIR_NETWORK_FORWARD_OPEN) &&
4767 4768 4769
        networkUnplugBandwidth(network, iface) < 0)
        goto error;

4770 4771 4772
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
4773 4774
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
4775 4776
    }

4777
    if (netdef->forward.nifs == 0) {
4778
        virReportError(VIR_ERR_INTERNAL_ERROR,
4779
                       _("network '%s' uses a direct/hostdev mode, but "
4780 4781
                         "has no forward dev and no interface pool"),
                       netdef->name);
4782
        goto error;
4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794
    }

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

4796 4797
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4798
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4799 4800
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4801 4802 4803
                break;
            }
        }
4804

4805
        if (!dev) {
4806
            virReportError(VIR_ERR_INTERNAL_ERROR,
4807 4808
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4809
                           netdef->name, actualDev);
4810
            goto error;
4811
        }
4812 4813 4814 4815 4816 4817 4818 4819 4820 4821
    } 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;
        }

4822 4823
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4824
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4825
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
4826 4827
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4828 4829 4830 4831 4832 4833 4834 4835 4836
                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,
4837 4838 4839 4840
                           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 已提交
4841
            goto error;
4842
        }
J
Ján Tomko 已提交
4843
    }
4844

4845
 success:
M
Michal Privoznik 已提交
4846 4847
    networkMacMgrDel(driver, network, dom->name, &iface->mac);

4848
    if (iface->data.network.actual) {
4849
        netdef->connections--;
4850 4851
        if (dev)
            dev->connections--;
4852 4853 4854
        /* finally we can call the 'unplugged' hook script if any */
        networkRunHook(network, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
                       VIR_HOOK_SUBOP_BEGIN);
4855
        networkLogAllocation(netdef, actualType, dev, iface, false);
4856
    }
4857
    ret = 0;
4858
 cleanup:
4859
    virNetworkObjEndAPI(&network);
4860 4861 4862 4863
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4864
    return ret;
4865

4866
 error:
4867
    goto cleanup;
4868
}
4869 4870 4871 4872 4873 4874

/*
 * networkGetNetworkAddress:
 * @netname: the name of a network
 * @netaddr: string representation of IP address for that network.
 *
4875
 * Attempt to return an IP address associated with the named
4876 4877 4878 4879
 * 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.
 *
4880
 * Note: This function returns the first IP address it finds. It might
4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891
 * 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)
{
4892
    virNetworkDriverStatePtr driver = networkGetDriver();
4893
    int ret = -1;
4894
    virNetworkObjPtr network;
4895
    virNetworkDefPtr netdef;
4896
    virNetworkIPDefPtr ipdef;
4897 4898
    virSocketAddr addr;
    virSocketAddrPtr addrptr = NULL;
4899
    char *dev_name = NULL;
4900 4901

    *netaddr = NULL;
4902
    network = virNetworkObjFindByName(driver->networks, netname);
4903
    if (!network) {
4904 4905 4906
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       netname);
4907
        goto cleanup;
4908 4909 4910
    }
    netdef = network->def;

4911
    switch (netdef->forward.type) {
4912 4913 4914
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
4915
    case VIR_NETWORK_FORWARD_OPEN:
4916
        ipdef = virNetworkDefGetIPByIndex(netdef, AF_UNSPEC, 0);
4917
        if (!ipdef) {
4918
            virReportError(VIR_ERR_INTERNAL_ERROR,
4919
                           _("network '%s' doesn't have an IP address"),
4920
                           netdef->name);
4921
            goto cleanup;
4922 4923 4924 4925 4926
        }
        addrptr = &ipdef->address;
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
4927
        if ((dev_name = netdef->bridge))
4928 4929
            break;
        /*
4930 4931
         * fall through if netdef->bridge wasn't set, since that is
         * macvtap bridge mode network.
4932 4933 4934 4935
         */
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
4936 4937
        if ((netdef->forward.nifs > 0) && netdef->forward.ifs)
            dev_name = netdef->forward.ifs[0].device.dev;
4938

4939
        if (!dev_name) {
4940 4941 4942
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' has no associated interface or bridge"),
                           netdef->name);
4943
            goto cleanup;
4944 4945 4946 4947
        }
        break;
    }

4948
    if (dev_name) {
4949
        if (virNetDevIPAddrGet(dev_name, &addr) < 0)
4950
            goto cleanup;
4951
        addrptr = &addr;
4952 4953
    }

4954 4955
    if (!(addrptr &&
          (*netaddr = virSocketAddrFormat(addrptr)))) {
4956
        goto cleanup;
4957 4958
    }

4959
    ret = 0;
4960
 cleanup:
4961
    virNetworkObjEndAPI(&network);
4962 4963
    return ret;
}
4964

4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998
/* networkGetActualType:
 * @dom: domain definition that @iface belongs to
 * @iface: the original NetDef from the domain
 *
 * Looks up the network reference by iface, and returns the actual
 * type of the connection without allocating any resources.
 *
 * Returns 0 on success, -1 on failure.
 */
int
networkGetActualType(virDomainNetDefPtr iface)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
    virNetworkObjPtr network = NULL;
    virNetworkDefPtr netdef = NULL;
    int ret = -1;

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

    if (iface->data.network.actual)
        return iface->data.network.actual->type;

    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 -1;
    }
    netdef = network->def;

    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
4999 5000
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
5001 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
        /* for these forward types, the actual net type really *is*
         * NETWORK; we just keep the info from the portgroup in
         * iface->data.network.actual
         */
        ret = VIR_DOMAIN_NET_TYPE_NETWORK;

    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
               netdef->bridge) {

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

        ret = VIR_DOMAIN_NET_TYPE_BRIDGE;

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

        ret = VIR_DOMAIN_NET_TYPE_HOSTDEV;

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

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

        ret = VIR_DOMAIN_NET_TYPE_DIRECT;

    }

    virNetworkObjEndAPI(&network);
    return ret;
}


5038 5039 5040
/**
 * networkCheckBandwidth:
 * @net: network QoS
5041
 * @ifaceBand: interface QoS (may be NULL if no QoS)
5042
 * @oldBandwidth: new interface QoS (may be NULL if no QoS)
5043
 * @ifaceMac: interface MAC (used in error messages for identification)
5044 5045
 * @new_rate: new rate for non guaranteed class
 *
5046 5047 5048 5049 5050 5051 5052 5053
 * 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.
 *
5054 5055 5056 5057 5058 5059
 * 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,
5060
                      virNetDevBandwidthPtr ifaceBand,
5061
                      virNetDevBandwidthPtr oldBandwidth,
5062
                      virMacAddr ifaceMac,
5063 5064 5065 5066 5067 5068 5069 5070
                      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];

5071
    virMacAddrFormat(&ifaceMac, ifmac);
5072 5073 5074 5075 5076 5077 5078 5079 5080 5081

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

5082 5083
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor)) ||
5084 5085
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
5086
        return 1;
5087
    }
5088 5089

    tmp_new_rate = netBand->in->average;
5090 5091 5092 5093
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
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

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

5119 5120
    if (new_rate)
        *new_rate = tmp_new_rate;
5121 5122
    ret = 0;

5123
 cleanup:
5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139
    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)
{
5140
    ssize_t ret = 0;
5141

5142
    ret = virBitmapNextClearBit(net->class_id, -1);
5143

5144
    if (ret < 0 || virBitmapSetBit(net->class_id, ret) < 0)
5145 5146 5147 5148 5149
        return -1;

    return ret;
}

5150

5151
static int
5152 5153 5154 5155
networkPlugBandwidthImpl(virNetworkObjPtr net,
                         virDomainNetDefPtr iface,
                         virNetDevBandwidthPtr ifaceBand,
                         unsigned long long new_rate)
5156
{
5157
    virNetworkDriverStatePtr driver = networkGetDriver();
5158
    ssize_t class_id = 0;
5159 5160
    int plug_ret;
    int ret = -1;
5161 5162 5163 5164 5165 5166 5167 5168

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

5169 5170
    plug_ret = virNetDevBandwidthPlug(net->def->bridge, net->def->bandwidth,
                                      &iface->mac, ifaceBand, class_id);
5171 5172 5173 5174 5175 5176 5177 5178
    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 */
5179
    net->floor_sum += ifaceBand->in->floor;
5180
    /* update status file */
5181
    if (virNetworkSaveStatus(driver->stateDir, net) < 0) {
5182
        ignore_value(virBitmapClearBit(net->class_id, class_id));
5183
        net->floor_sum -= ifaceBand->in->floor;
5184 5185 5186 5187
        iface->data.network.actual->class_id = 0;
        ignore_value(virNetDevBandwidthUnplug(net->def->bridge, class_id));
        goto cleanup;
    }
5188 5189
    /* update rate for non guaranteed NICs */
    new_rate -= net->floor_sum;
5190
    if (virNetDevBandwidthUpdateRate(net->def->bridge, 2,
5191 5192 5193 5194 5195
                                     net->def->bandwidth, new_rate) < 0)
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
                 net->def->bridge);

    ret = 0;
5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235
 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;
5236

5237
 cleanup:
5238 5239 5240 5241 5242 5243 5244
    return ret;
}

static int
networkUnplugBandwidth(virNetworkObjPtr net,
                       virDomainNetDefPtr iface)
{
5245
    virNetworkDriverStatePtr driver = networkGetDriver();
5246 5247
    int ret = 0;
    unsigned long long new_rate;
5248
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
5249 5250 5251

    if (iface->data.network.actual &&
        iface->data.network.actual->class_id) {
5252 5253 5254 5255 5256
        if (!net->def->bandwidth || !net->def->bandwidth->in) {
            VIR_WARN("Network %s has no bandwidth but unplug requested",
                     net->def->name);
            goto cleanup;
        }
5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267
        /* 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 */
5268
        net->floor_sum -= ifaceBand->in->floor;
5269 5270 5271 5272
        /* return class ID */
        ignore_value(virBitmapClearBit(net->class_id,
                                       iface->data.network.actual->class_id));
        /* update status file */
5273
        if (virNetworkSaveStatus(driver->stateDir, net) < 0) {
5274
            net->floor_sum += ifaceBand->in->floor;
5275 5276 5277 5278
            ignore_value(virBitmapSetBit(net->class_id,
                                         iface->data.network.actual->class_id));
            goto cleanup;
        }
5279 5280
        /* update rate for non guaranteed NICs */
        new_rate -= net->floor_sum;
5281
        if (virNetDevBandwidthUpdateRate(net->def->bridge, 2,
5282 5283 5284 5285 5286 5287 5288
                                         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;
    }

5289
 cleanup:
5290 5291
    return ret;
}
5292 5293 5294

static void
networkNetworkObjTaint(virNetworkObjPtr net,
5295
                       virNetworkTaintFlags taint)
5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306
{
    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));
    }
}
5307 5308 5309 5310 5311 5312


static bool
networkBandwidthGenericChecks(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
5313
    virNetDevBandwidthPtr ifaceBand;
5314 5315 5316 5317 5318 5319 5320 5321
    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;
    }

5322
    ifaceBand = virDomainNetGetActualBandwidth(iface);
5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362
    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;
}
5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400


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

5401 5402
    if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
        newBandwidth && newBandwidth->in && newBandwidth->in->floor) {
5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444
        /* 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;
}