bridge_driver.c 190.6 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
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <stdarg.h>
#include <unistd.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>
35
#include <net/if.h>
36
#ifdef HAVE_SYSCTLBYNAME
37 38
# include <sys/sysctl.h>
#endif
39

40
#include "virerror.h"
41
#include "datatypes.h"
42
#include "bridge_driver.h"
43
#include "bridge_driver_platform.h"
44
#include "device_conf.h"
45
#include "driver.h"
46
#include "virbuffer.h"
47
#include "virpidfile.h"
48
#include "vircommand.h"
49
#include "viralloc.h"
50
#include "viruuid.h"
51
#include "viriptables.h"
52
#include "virlog.h"
53
#include "virdnsmasq.h"
54
#include "configmake.h"
55
#include "virnetlink.h"
56
#include "virnetdev.h"
57
#include "virnetdevip.h"
58
#include "virnetdevbridge.h"
59
#include "virnetdevopenvswitch.h"
60
#include "virnetdevtap.h"
61
#include "virnetdevvportprofile.h"
62
#include "virpci.h"
63
#include "virdbus.h"
64
#include "virfile.h"
65
#include "virstring.h"
66
#include "viraccessapicheck.h"
67
#include "network_event.h"
68
#include "virhook.h"
69
#include "virjson.h"
70
#include "virnetworkportdef.h"
71

72
#define VIR_FROM_THIS VIR_FROM_NETWORK
73
#define MAX_BRIDGE_ID 256
74

75 76 77 78 79 80 81
/**
 * 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)

82 83
#define SYSCTL_PATH "/proc/sys"

84 85
VIR_LOG_INIT("network.bridge_driver");

86
static virNetworkDriverStatePtr network_driver;
87

88

89 90 91 92 93 94 95 96
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;
}
97

98 99 100

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


static void
networkDriverUnlock(virNetworkDriverStatePtr driver)
108
{
109
    virMutexUnlock(&driver->lock);
110 111
}

112

113 114 115 116
static dnsmasqCapsPtr
networkGetDnsmasqCaps(virNetworkDriverStatePtr driver)
{
    dnsmasqCapsPtr ret;
117
    networkDriverLock(driver);
118
    ret = virObjectRef(driver->dnsmasqCaps);
119
    networkDriverUnlock(driver);
120 121 122
    return ret;
}

123

124 125 126 127 128 129 130 131
static int
networkDnsmasqCapsRefresh(virNetworkDriverStatePtr driver)
{
    dnsmasqCapsPtr caps;

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

132
    networkDriverLock(driver);
133 134
    virObjectUnref(driver->dnsmasqCaps);
    driver->dnsmasqCaps = caps;
135
    networkDriverUnlock(driver);
136 137 138
    return 0;
}

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231

static void
networkDnsmasqDefNamespaceFree(void *nsdata)
{
    networkDnsmasqXmlNsDefPtr def = nsdata;
    if (!def)
        return;

    virStringListFreeCount(def->options, def->noptions);

    VIR_FREE(def);
}


static int
networkDnsmasqDefNamespaceParseOptions(networkDnsmasqXmlNsDefPtr nsdef,
                                       xmlXPathContextPtr ctxt)
{
    VIR_AUTOFREE(xmlNodePtr *) nodes = NULL;
    ssize_t nnodes;
    size_t i;

    if ((nnodes = virXPathNodeSet("./dnsmasq:options/dnsmasq:option",
                                  ctxt, &nodes)) < 0)
        return -1;

    if (nnodes == 0)
        return 0;

    if (VIR_ALLOC_N(nsdef->options, nnodes) < 0)
        return -1;

    for (i = 0; i < nnodes; i++) {
        if (!(nsdef->options[nsdef->noptions++] = virXMLPropString(nodes[i], "value"))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No dnsmasq options value specified"));
            return -1;
        }
    }

    return 0;
}


static int
networkDnsmasqDefNamespaceParse(xmlXPathContextPtr ctxt,
                                void **data)
{
    networkDnsmasqXmlNsDefPtr nsdata = NULL;
    int ret = -1;

    if (VIR_ALLOC(nsdata) < 0)
        return -1;

    if (networkDnsmasqDefNamespaceParseOptions(nsdata, ctxt))
        goto cleanup;

    if (nsdata->noptions > 0)
        VIR_STEAL_PTR(*data, nsdata);

    ret = 0;

 cleanup:
    networkDnsmasqDefNamespaceFree(nsdata);
    return ret;
}


static int
networkDnsmasqDefNamespaceFormatXML(virBufferPtr buf,
                                    void *nsdata)
{
    networkDnsmasqXmlNsDefPtr def = nsdata;
    size_t i;

    if (!def->noptions)
        return 0;

    virBufferAddLit(buf, "<dnsmasq:options>\n");
    virBufferAdjustIndent(buf, 2);

    for (i = 0; i < def->noptions; i++) {
        virBufferEscapeString(buf, "<dnsmasq:option value='%s'/>\n",
                              def->options[i]);
    }

    virBufferAdjustIndent(buf, -2);
    virBufferAddLit(buf, "</dnsmasq:options>\n");

    return 0;
}


232
virXMLNamespace networkDnsmasqXMLNamespace = {
233 234 235
    .parse = networkDnsmasqDefNamespaceParse,
    .free = networkDnsmasqDefNamespaceFree,
    .format = networkDnsmasqDefNamespaceFormatXML,
236
    .prefix = "dnsmasq",
237
    .uri = "http://libvirt.org/schemas/network/dnsmasq/1.0",
238 239 240 241
};


virNetworkXMLOptionPtr
C
Cole Robinson 已提交
242 243
networkDnsmasqCreateXMLConf(void)
{
244
    return virNetworkXMLOptionNew(&networkDnsmasqXMLNamespace);
C
Cole Robinson 已提交
245 246
}

247

248 249 250 251 252
static int
networkStateCleanup(void);

static int
networkStartNetwork(virNetworkDriverStatePtr driver,
253
                    virNetworkObjPtr obj);
254 255 256

static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
257
                       virNetworkObjPtr obj);
258 259 260

static int
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
261
                           virNetworkObjPtr obj);
262 263 264

static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
265
                              virNetworkObjPtr obj);
266

267
static int
268
networkStartNetworkExternal(virNetworkObjPtr obj);
269

270
static int
271
networkShutdownNetworkExternal(virNetworkObjPtr obj);
272

273
static void
274
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup);
275

276 277
static void
networkRefreshDaemons(virNetworkDriverStatePtr driver);
278

279
static int
280
networkPlugBandwidth(virNetworkObjPtr obj,
281 282 283
                     virMacAddrPtr mac,
                     virNetDevBandwidthPtr ifaceBand,
                     unsigned int *class_id);
284

285
static int
286
networkUnplugBandwidth(virNetworkObjPtr obj,
287 288
                       virNetDevBandwidthPtr ifaceBand,
                       unsigned int *class_id);
289

290
static void
291
networkNetworkObjTaint(virNetworkObjPtr obj,
292
                       virNetworkTaintFlags taint);
293

294

295 296 297
static virNetworkObjPtr
networkObjFromNetwork(virNetworkPtr net)
{
298
    virNetworkDriverStatePtr driver = networkGetDriver();
299
    virNetworkObjPtr obj;
300 301
    char uuidstr[VIR_UUID_STRING_BUFLEN];

302 303
    obj = virNetworkObjFindByUUID(driver->networks, net->uuid);
    if (!obj) {
304 305 306 307 308 309
        virUUIDFormat(net->uuid, uuidstr);
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching uuid '%s' (%s)"),
                       uuidstr, net->name);
    }

310
    return obj;
311 312
}

313

314
static int
315
networkRunHook(virNetworkObjPtr obj,
316
               virNetworkPortDefPtr port,
317 318 319
               int op,
               int sub_op)
{
320
    virNetworkDefPtr def;
321
    virBuffer buf = VIR_BUFFER_INITIALIZER;
322
    char *xml = NULL;
323 324 325 326
    int hookret;
    int ret = -1;

    if (virHookPresent(VIR_HOOK_DRIVER_NETWORK)) {
327 328
        if (!obj) {
            VIR_DEBUG("Not running hook as @obj is NULL");
329 330 331
            ret = 0;
            goto cleanup;
        }
332
        def = virNetworkObjGetDef(obj);
333

334 335
        virBufferAddLit(&buf, "<hookData>\n");
        virBufferAdjustIndent(&buf, 2);
336
        if (virNetworkDefFormatBuf(&buf, def, network_driver->xmlopt, 0) < 0)
337
            goto cleanup;
338
        if (port && virNetworkPortDefFormatBuf(&buf, port) < 0)
339 340 341 342 343
            goto cleanup;

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

344
        if (virBufferCheckError(&buf) < 0)
345 346
            goto cleanup;

347
        xml = virBufferContentAndReset(&buf);
348
        hookret = virHookCall(VIR_HOOK_DRIVER_NETWORK, def->name,
349 350 351 352 353 354 355
                              op, sub_op, NULL, xml, NULL);

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

357
        networkNetworkObjTaint(obj, VIR_NETWORK_TAINT_HOOK);
358 359 360
    }

    ret = 0;
361
 cleanup:
362 363 364 365 366
    virBufferFreeAndReset(&buf);
    VIR_FREE(xml);
    return ret;
}

367

368
static char *
369 370
networkDnsmasqLeaseFileNameDefault(virNetworkDriverStatePtr driver,
                                   const char *netname)
371 372 373
{
    char *leasefile;

374
    ignore_value(virAsprintf(&leasefile, "%s/%s.leases",
375
                             driver->dnsmasqStateDir, netname));
376 377 378
    return leasefile;
}

379

380
static char *
381 382
networkDnsmasqLeaseFileNameCustom(virNetworkDriverStatePtr driver,
                                  const char *bridge)
383 384 385 386
{
    char *leasefile;

    ignore_value(virAsprintf(&leasefile, "%s/%s.status",
387
                             driver->dnsmasqStateDir, bridge));
388 389 390
    return leasefile;
}

391

392
static char *
393 394
networkDnsmasqConfigFileName(virNetworkDriverStatePtr driver,
                             const char *netname)
395 396 397
{
    char *conffile;

398
    ignore_value(virAsprintf(&conffile, "%s/%s.conf",
399
                             driver->dnsmasqStateDir, netname));
400 401 402
    return conffile;
}

403

404 405 406 407 408 409
static char *
networkRadvdPidfileBasename(const char *netname)
{
    /* this is simple but we want to be sure it's consistently done */
    char *pidfilebase;

410
    ignore_value(virAsprintf(&pidfilebase, "%s-radvd", netname));
411 412 413
    return pidfilebase;
}

414

415
static char *
416 417
networkRadvdConfigFileName(virNetworkDriverStatePtr driver,
                           const char *netname)
418 419 420
{
    char *configfile;

421
    ignore_value(virAsprintf(&configfile, "%s/%s-radvd.conf",
422
                             driver->radvdStateDir, netname));
423 424
    return configfile;
}
425

426

427 428
/* do needed cleanup steps and remove the network from the list */
static int
429
networkRemoveInactive(virNetworkDriverStatePtr driver,
430
                      virNetworkObjPtr obj)
431 432
{
    char *leasefile = NULL;
433
    char *customleasefile = NULL;
434
    char *radvdconfigfile = NULL;
435
    char *configfile = NULL;
436
    char *radvdpidbase = NULL;
437
    char *statusfile = NULL;
M
Michal Privoznik 已提交
438
    char *macMapFile = NULL;
439
    dnsmasqContext *dctx = NULL;
440
    virNetworkDefPtr def = virNetworkObjGetPersistentDef(obj);
441 442 443 444

    int ret = -1;

    /* remove the (possibly) existing dnsmasq and radvd files */
445
    if (!(dctx = dnsmasqContextNew(def->name,
446
                                   driver->dnsmasqStateDir))) {
447
        goto cleanup;
448
    }
449

450
    if (!(leasefile = networkDnsmasqLeaseFileNameDefault(driver, def->name)))
451 452
        goto cleanup;

453
    if (!(customleasefile = networkDnsmasqLeaseFileNameCustom(driver, def->bridge)))
454 455
        goto cleanup;

456
    if (!(radvdconfigfile = networkRadvdConfigFileName(driver, def->name)))
457
        goto cleanup;
458 459

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
460
        goto cleanup;
461

462
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
463
        goto cleanup;
464

465
    if (!(statusfile = virNetworkConfigFile(driver->stateDir, def->name)))
466
        goto cleanup;
467

468
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir, def->bridge)))
M
Michal Privoznik 已提交
469 470
        goto cleanup;

471 472 473
    /* dnsmasq */
    dnsmasqDelete(dctx);
    unlink(leasefile);
474
    unlink(customleasefile);
475
    unlink(configfile);
476

M
Michal Privoznik 已提交
477 478 479
    /* MAC map manager */
    unlink(macMapFile);

480 481
    /* radvd */
    unlink(radvdconfigfile);
482
    virPidFileDelete(driver->pidDir, radvdpidbase);
483

484 485 486
    /* remove status file */
    unlink(statusfile);

487
    /* remove the network definition */
488
    virNetworkObjRemoveInactive(driver->networks, obj);
489 490 491

    ret = 0;

492
 cleanup:
493
    VIR_FREE(leasefile);
494
    VIR_FREE(configfile);
495
    VIR_FREE(customleasefile);
496 497
    VIR_FREE(radvdconfigfile);
    VIR_FREE(radvdpidbase);
498
    VIR_FREE(statusfile);
M
Michal Privoznik 已提交
499
    VIR_FREE(macMapFile);
500 501 502 503
    dnsmasqContextFree(dctx);
    return ret;
}

504

505 506 507
static char *
networkBridgeDummyNicName(const char *brname)
{
508
    static const char dummyNicSuffix[] = "-nic";
509 510
    char *nicname;

511 512 513 514 515 516 517
    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.
         */
518 519 520 521 522
        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));
523
    } else {
524
        ignore_value(virAsprintf(&nicname, "%s%s", brname, dummyNicSuffix));
525
    }
526 527 528
    return nicname;
}

529

530 531 532 533 534 535 536 537 538 539 540 541 542 543 544
static int
networkNotifyPort(virNetworkObjPtr obj,
                  virNetworkPortDefPtr port);

static bool
networkUpdatePort(virNetworkPortDefPtr port,
                  void *opaque)
{
    virNetworkObjPtr obj = opaque;

    networkNotifyPort(obj, port);

    return false;
}

545 546
static int
networkUpdateState(virNetworkObjPtr obj,
547
                   void *opaque)
548
{
549
    virNetworkDefPtr def;
550
    virNetworkDriverStatePtr driver = opaque;
551
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
552
    virMacMapPtr macmap;
553
    char *macMapFile = NULL;
554
    int ret = -1;
555

556
    virObjectLock(obj);
557
    if (!virNetworkObjIsActive(obj)) {
558 559
        ret = 0;
        goto cleanup;
560
    }
561
    def = virNetworkObjGetDef(obj);
562

563
    switch ((virNetworkForwardType) def->forward.type) {
564 565 566
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
567
    case VIR_NETWORK_FORWARD_OPEN:
568
        /* If bridge doesn't exist, then mark it inactive */
569
        if (!(def->bridge && virNetDevExists(def->bridge) == 1))
570
            virNetworkObjSetActive(obj, false);
571

572
        if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
573
                                             def->bridge)))
574 575
            goto cleanup;

576
        if (!(macmap = virMacMapNew(macMapFile)))
577 578
            goto cleanup;

579 580
        virNetworkObjSetMacMap(obj, macmap);

581
        break;
582

583
    case VIR_NETWORK_FORWARD_BRIDGE:
584 585
        if (def->bridge) {
            if (virNetDevExists(def->bridge) != 1)
586
                virNetworkObjSetActive(obj, false);
587
            break;
588
        }
589 590 591 592 593 594 595 596 597
        /* 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;
598

599 600 601
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
602 603 604 605 606

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, def->forward.type);
        goto cleanup;
607
    }
608

609 610
    virNetworkObjPortForEach(obj, networkUpdatePort, obj);

611
    /* Try and read dnsmasq/radvd pids of active networks */
612
    if (virNetworkObjIsActive(obj) && def->ips && (def->nips > 0)) {
613 614
        pid_t radvdPid;
        pid_t dnsmasqPid;
615
        char *radvdpidbase;
616

617
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
618
                                           def->name,
619
                                           &dnsmasqPid,
620
                                           dnsmasqCapsGetBinaryPath(dnsmasq_caps)));
621
        virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
M
Michal Privoznik 已提交
622

623
        radvdpidbase = networkRadvdPidfileBasename(def->name);
624 625
        if (!radvdpidbase)
            goto cleanup;
626

627 628
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
629 630
                                           &radvdPid, RADVD));
        virNetworkObjSetRadvdPid(obj, radvdPid);
631
        VIR_FREE(radvdpidbase);
632
    }
633

634 635
    ret = 0;
 cleanup:
636
    virObjectUnlock(obj);
637
    virObjectUnref(dnsmasq_caps);
638
    VIR_FREE(macMapFile);
639 640
    return ret;
}
641

642

643
static int
644
networkAutostartConfig(virNetworkObjPtr obj,
645
                       void *opaque)
646
{
647
    virNetworkDriverStatePtr driver = opaque;
648
    int ret = -1;
649

650
    virObjectLock(obj);
651
    if (virNetworkObjIsAutostart(obj) &&
652 653
        !virNetworkObjIsActive(obj) &&
        networkStartNetwork(driver, obj) < 0)
654 655 656 657
        goto cleanup;

    ret = 0;
 cleanup:
658
    virObjectUnlock(obj);
659
    return ret;
660 661
}

662

663
#ifdef WITH_FIREWALLD
664 665
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
666 667
                             DBusMessage *message,
                             void *user_data)
668
{
669
    virNetworkDriverStatePtr driver = user_data;
670
    bool reload = false;
671

672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
    if (dbus_message_is_signal(message,
                               "org.fedoraproject.FirewallD1", "Reloaded")) {
        reload = true;

    } else if (dbus_message_is_signal(message,
                                      DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {

        VIR_AUTOFREE(char *) name = NULL;
        VIR_AUTOFREE(char *) old_owner = NULL;
        VIR_AUTOFREE(char *) new_owner = NULL;

        if (virDBusMessageDecode(message, "sss", &name, &old_owner, &new_owner) < 0) {
            VIR_WARN("Failed to decode DBus NameOwnerChanged message");
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }
        /*
         * if new_owner is empty, firewalld is shutting down. If it is
         * non-empty, then it is starting
         */
        if (new_owner && *new_owner)
            reload = true;
    }

    if (reload) {
696
        VIR_DEBUG("Reload in bridge_driver because of firewalld.");
697
        networkReloadFirewallRules(driver, false);
698 699 700 701 702 703
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

704

705
/**
706
 * networkStateInitialize:
707
 *
J
Ján Tomko 已提交
708
 * Initialization function for the QEMU daemon
709 710
 */
static int
711 712 713
networkStateInitialize(bool privileged,
                       virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
714
{
715
    int ret = VIR_DRV_STATE_INIT_ERROR;
716 717
    char *configdir = NULL;
    char *rundir = NULL;
718
#ifdef WITH_FIREWALLD
719 720
    DBusConnection *sysbus = NULL;
#endif
721

722
    if (VIR_ALLOC(network_driver) < 0)
723
        goto error;
724

725
    network_driver->lockFD = -1;
726 727
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
728 729
        goto error;
    }
730

731 732
    network_driver->privileged = privileged;

C
Cole Robinson 已提交
733 734 735
    if (!(network_driver->xmlopt = networkDnsmasqCreateXMLConf()))
        goto error;

736 737 738 739
    /* configuration/state paths are one of
     * ~/.config/libvirt/... (session/unprivileged)
     * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
     */
740
    if (privileged) {
741
        if (VIR_STRDUP(network_driver->networkConfigDir,
742
                       SYSCONFDIR "/libvirt/qemu/networks") < 0 ||
743
            VIR_STRDUP(network_driver->networkAutostartDir,
744
                       SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
745
            VIR_STRDUP(network_driver->stateDir,
746
                       RUNSTATEDIR "/libvirt/network") < 0 ||
747
            VIR_STRDUP(network_driver->pidDir,
748
                       RUNSTATEDIR "/libvirt/network") < 0 ||
749
            VIR_STRDUP(network_driver->dnsmasqStateDir,
750
                       LOCALSTATEDIR "/lib/libvirt/dnsmasq") < 0 ||
751
            VIR_STRDUP(network_driver->radvdStateDir,
752 753
                       LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
            goto error;
754
    } else {
755 756 757
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
758
            goto error;
759

760
        if ((virAsprintf(&network_driver->networkConfigDir,
761
                         "%s/qemu/networks", configdir) < 0) ||
762
            (virAsprintf(&network_driver->networkAutostartDir,
763
                         "%s/qemu/networks/autostart", configdir) < 0) ||
764
            (virAsprintf(&network_driver->stateDir,
765
                         "%s/network/lib", rundir) < 0) ||
766
            (virAsprintf(&network_driver->pidDir,
767
                         "%s/network/run", rundir) < 0) ||
768
            (virAsprintf(&network_driver->dnsmasqStateDir,
769
                         "%s/dnsmasq/lib", rundir) < 0) ||
770
            (virAsprintf(&network_driver->radvdStateDir,
771
                         "%s/radvd/lib", rundir) < 0)) {
772
            goto error;
773
        }
774 775
    }

776
    if (virFileMakePath(network_driver->stateDir) < 0) {
777 778
        virReportSystemError(errno,
                             _("cannot create directory %s"),
779
                             network_driver->stateDir);
780 781 782
        goto error;
    }

783 784 785 786 787
    if ((network_driver->lockFD =
         virPidFileAcquire(network_driver->stateDir, "driver",
                           true, getpid())) < 0)
        goto error;

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

791
    if (!(network_driver->networks = virNetworkObjListNew()))
792 793
        goto error;

794
    if (virNetworkObjLoadAllState(network_driver->networks,
795 796
                                  network_driver->stateDir,
                                  network_driver->xmlopt) < 0)
797 798
        goto error;

799 800
    if (virNetworkObjLoadAllConfigs(network_driver->networks,
                                    network_driver->networkConfigDir,
801 802
                                    network_driver->networkAutostartDir,
                                    network_driver->xmlopt) < 0)
803 804
        goto error;

805 806 807 808
    /* 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). */
809
    virNetworkObjListForEach(network_driver->networks,
810
                             networkUpdateState,
811 812
                             network_driver);
    virNetworkObjListPrune(network_driver->networks,
813 814
                           VIR_CONNECT_LIST_NETWORKS_INACTIVE |
                           VIR_CONNECT_LIST_NETWORKS_TRANSIENT);
815
    networkReloadFirewallRules(network_driver, true);
816
    networkRefreshDaemons(network_driver);
817

818 819 820 821
    virNetworkObjListForEach(network_driver->networks,
                             networkAutostartConfig,
                             network_driver);

822
    network_driver->networkEventState = virObjectEventStateNew();
823

824
#ifdef WITH_FIREWALLD
825 826
    if (!(sysbus = virDBusGetSystemBus())) {
        VIR_WARN("DBus not available, disabling firewalld support "
827
                 "in bridge_network_driver: %s", virGetLastErrorMessage());
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
    } 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,
845
                                   network_driver, NULL);
846 847 848
    }
#endif

849
    ret = VIR_DRV_STATE_INIT_COMPLETE;
850
 cleanup:
851 852 853
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
854

855
 error:
856
    networkStateCleanup();
857
    goto cleanup;
858 859
}

860

861
/**
862
 * networkStateReload:
863
 *
J
Ján Tomko 已提交
864
 * Function to restart the QEMU daemon, it will recheck the configuration
865 866 867
 * files and update its state and the networking
 */
static int
868 869
networkStateReload(void)
{
870
    if (!network_driver)
871 872
        return 0;

873
    virNetworkObjLoadAllState(network_driver->networks,
874 875
                              network_driver->stateDir,
                              network_driver->xmlopt);
876 877
    virNetworkObjLoadAllConfigs(network_driver->networks,
                                network_driver->networkConfigDir,
878 879
                                network_driver->networkAutostartDir,
                                network_driver->xmlopt);
880
    networkReloadFirewallRules(network_driver, false);
881 882
    networkRefreshDaemons(network_driver);
    virNetworkObjListForEach(network_driver->networks,
883
                             networkAutostartConfig,
884
                             network_driver);
885 886 887 888 889
    return 0;
}


/**
890
 * networkStateCleanup:
891
 *
J
Ján Tomko 已提交
892
 * Shutdown the QEMU daemon, it will stop all active domains and networks
893 894
 */
static int
895 896
networkStateCleanup(void)
{
897
    if (!network_driver)
898 899
        return -1;

900
    virObjectUnref(network_driver->networkEventState);
C
Cole Robinson 已提交
901
    virObjectUnref(network_driver->xmlopt);
902

903
    /* free inactive networks */
904
    virObjectUnref(network_driver->networks);
905

906 907 908 909
    if (network_driver->lockFD != -1)
        virPidFileRelease(network_driver->stateDir, "driver",
                          network_driver->lockFD);

910 911 912 913 914 915
    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);
916

917
    virObjectUnref(network_driver->dnsmasqCaps);
918

919
    virMutexDestroy(&network_driver->lock);
920

921
    VIR_FREE(network_driver);
922 923 924 925 926

    return 0;
}


927 928 929 930 931 932 933 934
static virDrvOpenStatus
networkConnectOpen(virConnectPtr conn,
                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                   virConfPtr conf ATTRIBUTE_UNUSED,
                   unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

935 936 937 938 939 940
    if (network_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("network state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
    }

941 942 943 944
    if (!virConnectValidateURIPath(conn->uri->path,
                                   "network",
                                   network_driver->privileged))
        return VIR_DRV_OPEN_ERROR;
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977

    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

    return VIR_DRV_OPEN_SUCCESS;
}

static int networkConnectClose(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 0;
}


static int networkConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


static int networkConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


static int networkConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}


978 979 980 981 982
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
983 984 985
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
986
{
987 988
    size_t i;
    int ret = -1;
989 990 991 992 993 994 995
    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.
     */
996
    for (i = 0; i < 25; i++) {
997
        int signum = 0;
998
        if (i == 0) {
999
            signum = SIGTERM;
1000
        } else if (i == 15) {
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035
            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);
1036
 cleanup:
1037 1038 1039
    return ret;
}

1040

J
Ján Tomko 已提交
1041 1042 1043
/* the following does not build a file, it builds a list
 * which is later saved into a file
 */
1044
static int
G
Gene Czarcinski 已提交
1045
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
1046
                                 virNetworkIPDefPtr ipdef)
1047
{
1048
    size_t i;
G
Gene Czarcinski 已提交
1049
    bool ipv6 = false;
1050

G
Gene Czarcinski 已提交
1051 1052
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
1053 1054
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
1055
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
1056 1057
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
1058
                return -1;
1059
    }
1060

G
Gene Czarcinski 已提交
1061 1062 1063
    return 0;
}

1064

G
Gene Czarcinski 已提交
1065 1066 1067 1068
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
1069
    size_t i, j;
G
Gene Czarcinski 已提交
1070

1071 1072
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
1073
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
1074
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
1075
                for (j = 0; j < host->nnames; j++)
1076 1077
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
1078 1079
            }
        }
1080 1081
    }

1082
    return 0;
1083 1084 1085
}


1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
static int
networkDnsmasqConfLocalPTRs(virBufferPtr buf,
                            virNetworkDefPtr def)
{
    virNetworkIPDefPtr ip;
    size_t i;
    char *ptr = NULL;
    int rc;

    for (i = 0; i < def->nips; i++) {
        ip = def->ips + i;

        if (ip->localPTR != VIR_TRISTATE_BOOL_YES)
            continue;

        if ((rc = virSocketAddrPTRDomain(&ip->address,
                                         virNetworkIPDefPrefix(ip),
                                         &ptr)) < 0) {
            if (rc == -2) {
                int family = VIR_SOCKET_ADDR_FAMILY(&ip->address);
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("PTR domain for %s network with prefix %u "
                                 "cannot be automatically created"),
                               (family == AF_INET) ? "IPv4" : "IPv6",
                               virNetworkIPDefPrefix(ip));
            }
            return -1;
        }

        virBufferAsprintf(buf, "local=/%s/\n", ptr);
        VIR_FREE(ptr);
    }

    return 0;
}


1123
int
1124
networkDnsmasqConfContents(virNetworkObjPtr obj,
1125 1126 1127 1128
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
                           dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
1129
{
1130
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1131
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1132
    int r, ret = -1;
1133
    int nbleases = 0;
1134
    size_t i;
1135
    virNetworkDNSDefPtr dns = &def->dns;
1136
    bool wantDNS = dns->enable != VIR_TRISTATE_BOOL_NO;
1137
    virNetworkIPDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
G
Gene Czarcinski 已提交
1138
    bool ipv6SLAAC;
1139
    char *saddr = NULL, *eaddr = NULL;
1140

1141 1142
    *configstr = NULL;

1143
    /*
1144 1145 1146
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1147
     *
1148 1149
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1150
     */
1151 1152 1153 1154 1155 1156

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

1157
    /* create dnsmasq config file appropriate for this network */
1158 1159

    /* Don't forget to update networkxml2conftest :-) */
1160
    virBufferAsprintf(&configbuf,
1161 1162 1163 1164 1165 1166 1167
                      "##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"
1168
                      "strict-order\n",
1169
                      def->name);
1170

1171 1172 1173 1174 1175 1176
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1177
    if (wantDNS && def->dns.forwarders) {
1178 1179 1180 1181 1182 1183 1184 1185 1186
        /* addNoResolv should be set to true if there are any entries
         * that specify an IP address for requests, but no domain
         * qualifier (implying that all requests otherwise "unclaimed"
         * should be sent to that address). if it is still false when
         * we've looked at all entries, it means we still need the
         * host's resolv.conf for some cases.
         */
        bool addNoResolv = false;

1187 1188
        for (i = 0; i < def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &def->dns.forwarders[i];
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198

            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);
1199
                VIR_FREE(addr);
1200 1201
                if (!fwd->domain)
                    addNoResolv = true;
1202 1203 1204 1205
            } else {
                /* "don't forward requests for this domain" */
                virBufferAddLit(&configbuf, "#\n");
            }
1206
        }
1207 1208
        if (addNoResolv)
            virBufferAddLit(&configbuf, "no-resolv\n");
1209 1210
    }

1211 1212
    if (def->domain) {
        if (def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1213 1214
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1215
                              def->domain);
1216
        }
1217
        virBufferAsprintf(&configbuf,
1218 1219
                          "domain=%s\n"
                          "expand-hosts\n",
1220
                          def->domain);
1221
    }
1222

1223
    if (wantDNS &&
1224
        networkDnsmasqConfLocalPTRs(&configbuf, def) < 0)
1225 1226
        goto cleanup;

1227
    if (wantDNS && def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1228 1229 1230 1231
        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)
1232
         */
1233
        virBufferAddLit(&configbuf, "local=//\n");
1234
    }
1235

1236
    if (pidfile)
1237
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1238

1239
    /* dnsmasq will *always* listen on localhost unless told otherwise */
P
Pavel Timofeev 已提交
1240
#ifdef __linux__
1241
    virBufferAddLit(&configbuf, "except-interface=lo\n");
P
Pavel Timofeev 已提交
1242 1243 1244 1245
#else
    /* BSD family OSes and Solaris call loopback interface as lo0 */
    virBufferAddLit(&configbuf, "except-interface=lo0\n");
#endif
1246

1247 1248 1249 1250 1251 1252 1253 1254
    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.
         */
1255
        virBufferAsprintf(&configbuf,
1256 1257
                          "bind-dynamic\n"
                          "interface=%s\n",
1258
                          def->bridge);
1259
    } else {
1260
        virBufferAddLit(&configbuf, "bind-interfaces\n");
1261 1262 1263 1264
        /*
         * --interface does not actually work with dnsmasq < 2.47,
         * due to DAD for ipv6 addresses on the interface.
         *
1265
         * virCommandAddArgList(cmd, "--interface", def->bridge, NULL);
1266 1267 1268
         *
         * So listen on all defined IPv[46] addresses
         */
1269
        for (i = 0;
1270
             (tmpipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
1271
             i++) {
1272 1273 1274 1275
            char *ipaddr = virSocketAddrFormat(&tmpipdef->address);

            if (!ipaddr)
                goto cleanup;
1276

1277
            /* also part of CVE 2012-3411 - if the host's version of
1278
             * dnsmasq doesn't have bind-dynamic, only allow listening on
1279 1280
             * private/local IP addresses (see RFC1918/RFC3484/RFC4193)
             */
1281 1282
            if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
                !virSocketAddrIsPrivate(&tmpipdef->address)) {
1283 1284 1285 1286
                unsigned long version = dnsmasqCapsGetVersion(caps);

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
1287
                                 "The version of dnsmasq on this host (%d.%d) "
1288 1289 1290 1291
                                 "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 "
1292 1293 1294 1295 1296 1297
                                 "(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);
1298
                VIR_FREE(ipaddr);
1299 1300
                goto cleanup;
            }
1301
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
1302 1303 1304
            VIR_FREE(ipaddr);
        }
    }
1305

1306 1307
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
1308
     * guaranteed to not work, and set no-resolv so that no dns
1309 1310 1311
     * 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).
1312 1313 1314
     * 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.
1315
     */
1316
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE) {
1317
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
1318
                        "no-resolv\n");
1319 1320 1321 1322
        if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM)) {
            /* interface=* (any), interval=0 (default), lifetime=0 (seconds) */
            virBufferAddLit(&configbuf, "ra-param=*,0,0\n");
        }
1323
    }
1324

1325 1326 1327 1328 1329
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1330
        }
1331

1332 1333 1334 1335 1336 1337 1338 1339
        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'"),
1340
                               def->name);
1341 1342 1343 1344 1345 1346
                goto cleanup;
            }
            if (!dns->srvs[i].protocol) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing required 'service' "
                                 "attribute in SRV record of network '%s'"),
1347
                               def->name);
1348 1349 1350 1351 1352 1353 1354
                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);
1355

1356 1357 1358 1359 1360 1361 1362
            /* 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.
1363
             */
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
            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");
1384
        }
1385 1386
    }

G
Gene Czarcinski 已提交
1387
    /* Find the first dhcp for both IPv4 and IPv6 */
1388
    for (i = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
1389
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
1390
         i++) {
G
Gene Czarcinski 已提交
1391 1392 1393 1394
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1395 1396
                                   _("For IPv4, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
                    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,
1408 1409 1410 1411 1412 1413 1414 1415 1416
                                   _("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 已提交
1417 1418 1419 1420
                    goto cleanup;
                }
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1421 1422
                                   _("For IPv6, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
                    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 "
1436 1437 1438 1439
                 "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 已提交
1440 1441 1442 1443 1444
    }

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1445 1446
        int prefix;

1447
        prefix = virNetworkIPDefPrefix(ipdef);
1448 1449 1450
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1451
                           def->bridge);
1452 1453
            goto cleanup;
        }
1454
        for (r = 0; r < ipdef->nranges; r++) {
1455 1456
            int thisRange;

1457 1458
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1459
                goto cleanup;
1460

1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
               virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%d\n",
                                 saddr, eaddr, prefix);
            } else {
                /* IPv4 - dnsmasq requires a netmask rather than prefix */
                virSocketAddr netmask;
                VIR_AUTOFREE(char *) netmaskStr = NULL;

                if (virSocketAddrPrefixToNetmask(prefix, &netmask, AF_INET) < 0) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Failed to translate bridge '%s' "
                                     "prefix %d to netmask"),
                                   def->bridge, prefix);
                    goto cleanup;
                }

                if (!(netmaskStr = virSocketAddrFormat(&netmask)))
                    goto cleanup;
                virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%s\n",
                                  saddr, eaddr, netmaskStr);
            }
1482

1483
            VIR_FREE(saddr);
1484
            VIR_FREE(eaddr);
1485
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1486 1487
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1488
                                              virNetworkIPDefPrefix(ipdef));
1489 1490 1491
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1492
        }
1493

1494
        /*
1495 1496 1497 1498
         * 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)
1499 1500
         */
        if (!ipdef->nranges && ipdef->nhosts) {
1501
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
1502 1503
            if (!bridgeaddr)
                goto cleanup;
1504 1505 1506
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static",
                              bridgeaddr);
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1507
                virBufferAsprintf(&configbuf, ",%d", prefix);
1508
            virBufferAddLit(&configbuf, "\n");
1509 1510
            VIR_FREE(bridgeaddr);
        }
1511

G
Gene Czarcinski 已提交
1512 1513
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1514

G
Gene Czarcinski 已提交
1515 1516
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
1517
            if (ipdef->nranges || ipdef->nhosts) {
1518
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1519 1520
                virBufferAddLit(&configbuf, "dhcp-authoritative\n");
            }
1521

G
Gene Czarcinski 已提交
1522
            if (ipdef->tftproot) {
1523 1524
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1525
            }
1526

G
Gene Czarcinski 已提交
1527 1528 1529
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1530

1531
                    if (!bootserver)
G
Gene Czarcinski 已提交
1532
                        goto cleanup;
1533
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1534
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1535 1536
                    VIR_FREE(bootserver);
                } else {
1537
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1538 1539 1540 1541 1542
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1543

1544
    if (nbleases > 0)
1545
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1546

G
Gene Czarcinski 已提交
1547 1548
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1549
        goto cleanup;
G
Gene Czarcinski 已提交
1550 1551 1552 1553 1554 1555

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

1559 1560
    /* Likewise, always create this file and put it on the
     * commandline, to allow for runtime additions.
G
Gene Czarcinski 已提交
1561
     */
1562 1563 1564 1565
    if (wantDNS) {
        virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
                          dctx->addnhostsfile->path);
    }
G
Gene Czarcinski 已提交
1566

1567 1568 1569 1570
    /* Configure DHCP to tell clients about the MTU. */
    if (def->mtu > 0)
        virBufferAsprintf(&configbuf, "dhcp-option=option:mtu,%d\n", def->mtu);

G
Gene Czarcinski 已提交
1571 1572
    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
1573
        if (ipv6def) {
1574
            virBufferAddLit(&configbuf, "enable-ra\n");
1575
        } else {
1576
            for (i = 0;
1577
                 (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1578
                 i++) {
G
Gene Czarcinski 已提交
1579 1580 1581 1582
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1583 1584
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1585 1586
                    VIR_FREE(bridgeaddr);
                }
1587
            }
1588
        }
1589 1590
    }

1591 1592 1593 1594 1595 1596
    if (def->namespaceData) {
        networkDnsmasqXmlNsDefPtr dnsmasqxmlns = def->namespaceData;
        for (i = 0; i < dnsmasqxmlns->noptions; i++)
            virBufferAsprintf(&configbuf, "%s\n", dnsmasqxmlns->options[i]);
    }

1597 1598 1599
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1600
    ret = 0;
G
Gene Czarcinski 已提交
1601

1602
 cleanup:
1603 1604
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1605
    virBufferFreeAndReset(&configbuf);
1606
    return ret;
1607 1608
}

1609

1610
/* build the dnsmasq command line */
1611 1612
static int ATTRIBUTE_NONNULL(3)
networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
1613
                                  virNetworkObjPtr obj,
1614
                                  virCommandPtr *cmdout,
1615 1616
                                  char *pidfile,
                                  dnsmasqContext *dctx)
1617
{
1618
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1619
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1620
    virCommandPtr cmd = NULL;
G
Gene Czarcinski 已提交
1621
    int ret = -1;
1622 1623
    char *configfile = NULL;
    char *configstr = NULL;
1624
    char *leaseshelper_path = NULL;
1625

1626
    virNetworkObjSetDnsmasqPid(obj, -1);
1627

1628
    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
1629
                                   dctx, dnsmasq_caps) < 0)
1630 1631 1632 1633 1634
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1635
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
1636 1637 1638 1639 1640
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1641 1642
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1643 1644 1645
        goto cleanup;
    }

1646 1647
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1648
                                                  abs_top_builddir "/src",
1649 1650 1651
                                                  LIBEXECDIR)))
        goto cleanup;

1652
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1653
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1654 1655
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1656
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1657
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", def->bridge);
1658

1659
    *cmdout = cmd;
1660
    ret = 0;
1661
 cleanup:
1662
    virObjectUnref(dnsmasq_caps);
1663 1664
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1665
    VIR_FREE(leaseshelper_path);
1666 1667 1668
    return ret;
}

1669

1670
static int
1671
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1672
                       virNetworkObjPtr obj)
1673
{
1674
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1675 1676 1677
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1678 1679
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
1680
    pid_t dnsmasqPid;
1681
    int ret = -1;
1682
    dnsmasqContext *dctx = NULL;
1683

1684
    /* see if there are any IP addresses that need a dhcp server */
1685
    i = 0;
1686
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i))) {
1687
        i++;
1688 1689 1690 1691
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1692 1693 1694 1695 1696 1697
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1698
    if (!needDnsmasq && def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1699
        /* no DHCP services needed, and user disabled DNS service */
1700 1701 1702 1703
        ret = 0;
        goto cleanup;
    }

1704
    if (virFileMakePath(driver->pidDir) < 0) {
1705
        virReportSystemError(errno,
1706
                             _("cannot create directory %s"),
1707
                             driver->pidDir);
1708
        goto cleanup;
1709 1710
    }

1711
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, def->name)))
1712
        goto cleanup;
1713

1714
    if (virFileMakePath(driver->dnsmasqStateDir) < 0) {
1715
        virReportSystemError(errno,
1716
                             _("cannot create directory %s"),
1717
                             driver->dnsmasqStateDir);
1718 1719 1720
        goto cleanup;
    }

1721
    dctx = dnsmasqContextNew(def->name, driver->dnsmasqStateDir);
1722 1723 1724
    if (dctx == NULL)
        goto cleanup;

1725
    if (networkDnsmasqCapsRefresh(driver) < 0)
1726
        goto cleanup;
1727

1728
    ret = networkBuildDhcpDaemonCommandLine(driver, obj, &cmd, pidfile, dctx);
1729 1730 1731 1732 1733
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1734
        goto cleanup;
1735

G
Guido Günther 已提交
1736
    ret = virCommandRun(cmd, NULL);
1737
    if (ret < 0)
1738 1739 1740
        goto cleanup;

    /*
1741 1742 1743 1744 1745
     * 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
1746 1747
     */

1748
    ret = virPidFileRead(driver->pidDir, def->name, &dnsmasqPid);
1749
    if (ret < 0)
1750
        goto cleanup;
1751
    virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
1752

1753
    ret = 0;
1754
 cleanup:
1755
    VIR_FREE(pidfile);
1756
    virCommandFree(cmd);
1757
    dnsmasqContextFree(dctx);
1758 1759 1760
    return ret;
}

1761

1762 1763
/* networkRefreshDhcpDaemon:
 *  Update dnsmasq config files, then send a SIGHUP so that it rereads
G
Gene Czarcinski 已提交
1764 1765
 *  them.   This only works for the dhcp-hostsfile and the
 *  addn-hosts file.
1766 1767 1768
 *
 *  Returns 0 on success, -1 on failure.
 */
1769
static int
1770
networkRefreshDhcpDaemon(virNetworkDriverStatePtr driver,
1771
                         virNetworkObjPtr obj)
1772
{
1773
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1774 1775
    int ret = -1;
    size_t i;
1776
    pid_t dnsmasqPid;
1777
    virNetworkIPDefPtr ipdef, ipv4def, ipv6def;
1778
    dnsmasqContext *dctx = NULL;
1779

G
Gene Czarcinski 已提交
1780
    /* if no IP addresses specified, nothing to do */
1781
    if (!virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1782 1783
        return 0;

1784
    /* if there's no running dnsmasq, just start it */
1785 1786
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid <= 0 || (kill(dnsmasqPid, 0) < 0))
1787
        return networkStartDhcpDaemon(driver, obj);
1788

1789 1790
    VIR_INFO("Refreshing dnsmasq for network %s", def->bridge);
    if (!(dctx = dnsmasqContextNew(def->name,
1791
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1792
        goto cleanup;
1793
    }
G
Gene Czarcinski 已提交
1794 1795 1796 1797 1798 1799

    /* 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;
1800
    for (i = 0;
1801
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
1802
         i++) {
G
Gene Czarcinski 已提交
1803 1804
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1805 1806
    }

G
Gene Czarcinski 已提交
1807
    ipv6def = NULL;
1808
    for (i = 0;
1809
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1810
         i++) {
G
Gene Czarcinski 已提交
1811 1812
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1813 1814
    }

G
Gene Czarcinski 已提交
1815
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1816
        goto cleanup;
G
Gene Czarcinski 已提交
1817 1818

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

1821
    if (networkBuildDnsmasqHostsList(dctx, &def->dns) < 0)
J
Ján Tomko 已提交
1822
        goto cleanup;
1823 1824

    if ((ret = dnsmasqSave(dctx)) < 0)
1825
        goto cleanup;
1826

1827 1828
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    ret = kill(dnsmasqPid, SIGHUP);
1829
 cleanup:
1830 1831 1832 1833
    dnsmasqContextFree(dctx);
    return ret;
}

1834

1835 1836 1837 1838 1839 1840 1841 1842
/* 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
1843
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1844
                         virNetworkObjPtr obj)
1845
{
1846
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1847 1848
    pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);

1849
    /* if there is a running dnsmasq, kill it */
1850
    if (dnsmasqPid > 0) {
1851
        networkKillDaemon(dnsmasqPid, "dnsmasq", def->name);
1852
        virNetworkObjSetDnsmasqPid(obj, -1);
1853
    }
1854
    /* now start dnsmasq if it should be started */
1855
    return networkStartDhcpDaemon(driver, obj);
1856 1857
}

1858

G
Gene Czarcinski 已提交
1859 1860 1861 1862 1863 1864
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";

1865
static int
1866
networkRadvdConfContents(virNetworkObjPtr obj,
1867
                         char **configstr)
1868
{
1869
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
E
Eric Blake 已提交
1870
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1871 1872
    int ret = -1;
    size_t i;
1873
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1874
    bool v6present = false, dhcp6 = false;
1875 1876

    *configstr = NULL;
1877

G
Gene Czarcinski 已提交
1878
    /* Check if DHCPv6 is needed */
1879
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
G
Gene Czarcinski 已提交
1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892
        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;
    }

1893 1894 1895
    /* create radvd config file appropriate for this network;
     * IgnoreIfMissing allows radvd to start even when the bridge is down
     */
1896
    virBufferAsprintf(&configbuf, "interface %s\n"
1897 1898
                      "{\n"
                      "  AdvSendAdvert on;\n"
1899
                      "  IgnoreIfMissing on;\n"
G
Gene Czarcinski 已提交
1900 1901
                      "  AdvManagedFlag %s;\n"
                      "%s",
1902
                      def->bridge,
G
Gene Czarcinski 已提交
1903 1904
                      dhcp6 ? "on" : "off",
                      dhcp6 ? "\n" : radvd1);
1905 1906

    /* add a section for each IPv6 address in the config */
1907
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
1908 1909 1910
        int prefix;
        char *netaddr;

1911
        prefix = virNetworkIPDefPrefix(ipdef);
1912
        if (prefix < 0) {
1913 1914
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1915
                           def->bridge);
1916 1917
            goto cleanup;
        }
1918
        if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
1919
            goto cleanup;
1920
        virBufferAsprintf(&configbuf,
1921
                          "  prefix %s/%d\n"
G
Gene Czarcinski 已提交
1922 1923 1924
                          "  {\n%s  };\n",
                          netaddr, prefix,
                          dhcp6 ? radvd2 : radvd3);
1925 1926 1927
        VIR_FREE(netaddr);
    }

1928
    virBufferAddLit(&configbuf, "};\n");
1929

1930
    if (virBufferCheckError(&configbuf) < 0)
1931
        goto cleanup;
1932

1933 1934
    *configstr = virBufferContentAndReset(&configbuf);

1935
    ret = 0;
1936
 cleanup:
1937 1938 1939 1940
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1941

1942
/* write file and return its name (which must be freed by caller) */
1943
static int
1944
networkRadvdConfWrite(virNetworkDriverStatePtr driver,
1945
                      virNetworkObjPtr obj,
1946
                      char **configFile)
1947
{
1948
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1949 1950 1951 1952 1953 1954 1955 1956 1957
    int ret = -1;
    char *configStr = NULL;
    char *myConfigFile = NULL;

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

1958
    if (networkRadvdConfContents(obj, &configStr) < 0)
1959 1960 1961 1962
        goto cleanup;

    if (!configStr) {
        ret = 0;
1963 1964 1965 1966
        goto cleanup;
    }

    /* construct the filename */
1967
    if (!(*configFile = networkRadvdConfigFileName(driver, def->name)))
1968 1969
        goto cleanup;
    /* write the file */
1970
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1971 1972
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1973 1974 1975 1976 1977
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1978
 cleanup:
1979 1980 1981 1982 1983
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

1984

1985
static int
1986
networkStartRadvd(virNetworkDriverStatePtr driver,
1987
                  virNetworkObjPtr obj)
1988
{
1989
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1990
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1991
    pid_t radvdPid;
1992 1993 1994 1995 1996 1997
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

1998
    virNetworkObjSetRadvdPid(obj, -1);
1999

G
Gene Czarcinski 已提交
2000
    /* Is dnsmasq handling RA? */
2001
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
2002 2003 2004 2005
        ret = 0;
        goto cleanup;
    }

2006
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
        /* 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);
2017 2018 2019
        goto cleanup;
    }

2020
    if (virFileMakePath(driver->pidDir) < 0) {
2021 2022
        virReportSystemError(errno,
                             _("cannot create directory %s"),
2023
                             driver->pidDir);
2024 2025
        goto cleanup;
    }
2026
    if (virFileMakePath(driver->radvdStateDir) < 0) {
2027 2028
        virReportSystemError(errno,
                             _("cannot create directory %s"),
2029
                             driver->radvdStateDir);
2030 2031 2032 2033
        goto cleanup;
    }

    /* construct pidfile name */
2034
    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
2035
        goto cleanup;
2036
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
2037 2038
        goto cleanup;

2039
    if (networkRadvdConfWrite(driver, obj, &configfile) < 0)
2040 2041
        goto cleanup;

2042 2043 2044 2045
    /* 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
2046
     * virPidFileRead() below will fail if we use them).
2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061
     * 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;

2062
    if (virPidFileRead(driver->pidDir, radvdpidbase, &radvdPid) < 0)
2063
        goto cleanup;
2064
    virNetworkObjSetRadvdPid(obj, radvdPid);
2065 2066

    ret = 0;
2067
 cleanup:
2068
    virObjectUnref(dnsmasq_caps);
2069 2070 2071 2072 2073 2074 2075
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

2076

2077
static int
2078
networkRefreshRadvd(virNetworkDriverStatePtr driver,
2079
                    virNetworkObjPtr obj)
2080
{
2081
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2082
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
2083
    char *radvdpidbase;
2084
    pid_t radvdPid;
G
Gene Czarcinski 已提交
2085 2086

    /* Is dnsmasq handling RA? */
2087 2088
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
        virObjectUnref(dnsmasq_caps);
2089 2090
        radvdPid = virNetworkObjGetRadvdPid(obj);
        if (radvdPid <= 0)
G
Gene Czarcinski 已提交
2091 2092
            return 0;
        /* radvd should not be running but in case it is */
2093 2094
        if ((networkKillDaemon(radvdPid, "radvd", def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(def->name))
G
Gene Czarcinski 已提交
2095
             != NULL)) {
2096
            virPidFileDelete(driver->pidDir, radvdpidbase);
G
Gene Czarcinski 已提交
2097 2098
            VIR_FREE(radvdpidbase);
        }
2099
        virNetworkObjSetRadvdPid(obj, -1);
G
Gene Czarcinski 已提交
2100 2101
        return 0;
    }
2102
    virObjectUnref(dnsmasq_caps);
G
Gene Czarcinski 已提交
2103

2104
    /* if there's no running radvd, just start it */
2105 2106
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid <= 0 || (kill(radvdPid, 0) < 0))
2107
        return networkStartRadvd(driver, obj);
2108

2109
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2110 2111 2112 2113
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

2114
    if (networkRadvdConfWrite(driver, obj, NULL) < 0)
2115 2116
        return -1;

2117
    return kill(radvdPid, SIGHUP);
2118 2119
}

2120

2121 2122
#if 0
/* currently unused, so it causes a build error unless we #if it out */
2123
static int
2124
networkRestartRadvd(virNetworkObjPtr obj)
2125
{
2126
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2127
    char *radvdpidbase;
2128
    pid_t radvdPid = virNeworkObjGetRadvdPid(obj);
2129 2130

    /* if there is a running radvd, kill it */
2131
    if (radvdPid > 0) {
2132 2133 2134 2135
        /* 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).
         */
2136 2137
        if ((networkKillDaemon(radvdPid, "radvd", def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(def->name))
2138
             != NULL)) {
2139
            virPidFileDelete(driver->pidDir, radvdpidbase);
2140 2141
            VIR_FREE(radvdpidbase);
        }
2142
        virNetworkObjSetRadvdPid(obj, -1);
2143 2144
    }
    /* now start radvd if it should be started */
2145
    return networkStartRadvd(obj);
2146 2147 2148
}
#endif /* #if 0 */

2149

2150
static int
2151
networkRefreshDaemonsHelper(virNetworkObjPtr obj,
2152
                            void *opaque)
2153
{
2154
    virNetworkDefPtr def;
2155
    virNetworkDriverStatePtr driver = opaque;
2156

2157
    virObjectLock(obj);
2158
    def = virNetworkObjGetDef(obj);
2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186
    if (virNetworkObjIsActive(obj)) {
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
        case VIR_NETWORK_FORWARD_OPEN:
            /* 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.
             */
            networkRefreshDhcpDaemon(driver, obj);
            networkRefreshRadvd(driver, obj);
            break;

        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
        case VIR_NETWORK_FORWARD_HOSTDEV:
            break;

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, def->forward.type);
            goto cleanup;
        }
2187
    }
2188 2189

 cleanup:
2190
    virObjectUnlock(obj);
2191 2192 2193
    return 0;
}

2194

2195 2196 2197 2198
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2199
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2200 2201
{
    VIR_INFO("Refreshing network daemons");
2202 2203
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2204
                             driver);
2205
}
2206

2207

2208
static int
2209
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
2210 2211
                                 void *opaque ATTRIBUTE_UNUSED)
{
2212
    virNetworkDefPtr def;
2213

2214
    virObjectLock(obj);
2215
    def = virNetworkObjGetDef(obj);
2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241
    if (virNetworkObjIsActive(obj)) {
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
            /* 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.
             */
            networkRemoveFirewallRules(def);
            ignore_value(networkAddFirewallRules(def));
            break;

        case VIR_NETWORK_FORWARD_OPEN:
        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
        case VIR_NETWORK_FORWARD_HOSTDEV:
            break;

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, def->forward.type);
            goto cleanup;
2242 2243
        }
    }
2244 2245

 cleanup:
2246
    virObjectUnlock(obj);
2247
    return 0;
2248 2249
}

2250

2251
static void
2252
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup)
2253
{
2254
    VIR_INFO("Reloading iptables rules");
2255 2256 2257 2258
    /* Ideally we'd not even register the driver when unprivilegd
     * but until we untangle the virt driver that's not viable */
    if (!driver->privileged)
        return;
2259
    networkPreReloadFirewallRules(driver, startup);
2260 2261 2262
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2263
    networkPostReloadFirewallRules(startup);
2264 2265
}

2266

2267
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
2268
static int
2269 2270
networkEnableIPForwarding(bool enableIPv4,
                          bool enableIPv6)
2271
{
2272
    int ret = 0;
2273 2274 2275 2276
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
2277
                           &enabled, sizeof(enabled));
2278 2279
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
2280
                           &enabled, sizeof(enabled));
2281
#else
2282
    if (enableIPv4)
2283
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv4/ip_forward", "1\n", 0);
2284
    if (enableIPv6 && ret == 0)
2285 2286
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv6/conf/all/forwarding", "1\n", 0);

2287
#endif
2288
    return ret;
2289 2290
}

2291

2292
static int
2293
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2294
{
2295
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2296 2297
    char *field = NULL;
    int ret = -1;
2298
    bool enableIPv6 = !!virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2299

2300 2301 2302 2303 2304
    /* 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",
2305
                    def->bridge) < 0)
2306
       goto cleanup;
2307

2308 2309
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2310
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2311
                      def->bridge);
2312 2313 2314
        ret = 0;
        goto cleanup;
    }
2315

2316 2317 2318
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2319
                               "on bridge %s"), field, def->bridge);
2320
        goto cleanup;
2321
    }
2322
    VIR_FREE(field);
2323

2324 2325
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2326 2327 2328 2329 2330 2331
     */

    /* 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",
2332
                    def->bridge) < 0)
2333 2334
        goto cleanup;

2335
    if (virFileWriteStr(field, "0", 0) < 0) {
2336
        virReportSystemError(errno,
2337 2338 2339 2340 2341
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

2342 2343 2344 2345
    /* 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",
2346
                    def->bridge) < 0)
2347 2348
        goto cleanup;

2349
    if (virFileWriteStr(field, "0", 0) < 0) {
2350
        virReportSystemError(errno,
2351
                             _("cannot disable %s"), field);
2352 2353 2354 2355
        goto cleanup;
    }

    ret = 0;
2356
 cleanup:
2357 2358 2359 2360
    VIR_FREE(field);
    return ret;
}

2361

2362
/* add an IP address to a bridge */
2363
static int
2364
networkAddAddrToBridge(virNetworkObjPtr obj,
2365
                       virNetworkIPDefPtr ipdef)
2366
{
2367
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2368
    int prefix = virNetworkIPDefPrefix(ipdef);
2369 2370

    if (prefix < 0) {
2371 2372
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2373
                       def->bridge);
2374 2375 2376
        return -1;
    }

2377
    if (virNetDevIPAddrAdd(def->bridge, &ipdef->address, NULL, prefix) < 0)
2378 2379 2380 2381 2382
        return -1;

    return 0;
}

2383 2384

static int
2385
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2386 2387
                                      const char *macTapIfName)
{
2388 2389
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    const char *brname = def->bridge;
2390 2391

    if (brname &&
2392
        def->macTableManager == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
        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;
}


2406 2407
/* add an IP (static) route to a bridge */
static int
2408
networkAddRouteToBridge(virNetworkObjPtr obj,
2409
                        virNetDevIPRoutePtr routedef)
2410
{
2411
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2412 2413 2414 2415
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2416 2417 2418 2419 2420

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

2425
    if (virNetDevIPRouteAdd(def->bridge, addr, prefix, gateway, metric) < 0)
2426
        return -1;
2427

2428 2429 2430
    return 0;
}

2431
static int
2432
networkWaitDadFinish(virNetworkObjPtr obj)
2433
{
2434
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2435
    virNetworkIPDefPtr ipdef;
2436 2437 2438 2439
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

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

2442
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, naddrs))) {
2443 2444 2445 2446 2447
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2448
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2449 2450 2451 2452

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

2457

2458
static int
2459
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
2460
                           virNetworkObjPtr obj)
2461
{
2462
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2463
    size_t i;
2464
    bool v4present = false, v6present = false;
2465
    virErrorPtr save_err = NULL;
2466
    virNetworkIPDefPtr ipdef;
2467
    virNetDevIPRoutePtr routedef;
2468
    char *macTapIfName = NULL;
2469
    virMacMapPtr macmap;
M
Michal Privoznik 已提交
2470
    char *macMapFile = NULL;
2471
    int tapfd = -1;
2472
    bool dnsmasqStarted = false;
2473
    bool devOnline = false;
2474
    bool firewalRulesAdded = false;
2475

2476
    /* Check to see if any network IP collides with an existing route */
2477
    if (networkCheckRouteCollision(def) < 0)
2478 2479
        return -1;

2480
    /* Create and configure the bridge device */
2481
    if (!def->bridge) {
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
        /* 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"),
2492
                       def->name);
2493 2494
        return -1;
    }
2495
    if (virNetDevBridgeCreate(def->bridge) < 0)
2496 2497
        return -1;

2498
    if (def->mac_specified) {
2499 2500 2501 2502 2503 2504
        /* 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.
         */
2505
        macTapIfName = networkBridgeDummyNicName(def->bridge);
2506
        if (!macTapIfName)
2507
            goto error;
2508
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2509 2510
        if (virNetDevTapCreateInBridgePort(def->bridge,
                                           &macTapIfName, &def->mac,
2511
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2512
                                           NULL, def->mtu, NULL,
2513 2514 2515
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2516
            VIR_FREE(macTapIfName);
2517
            goto error;
2518 2519 2520
        }
    }

2521
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
2522
                                         def->bridge)) ||
2523
        !(macmap = virMacMapNew(macMapFile)))
2524
        goto error;
M
Michal Privoznik 已提交
2525

2526
    virNetworkObjSetMacMap(obj, macmap);
2527
    macmap = NULL;
2528

2529
    /* Set bridge options */
2530 2531 2532 2533

    /* delay is configured in seconds, but virNetDevBridgeSetSTPDelay
     * expects milliseconds
     */
2534
    if (virNetDevBridgeSetSTPDelay(def->bridge, def->delay * 1000) < 0)
2535
        goto error;
2536

2537
    if (virNetDevBridgeSetSTP(def->bridge, def->stp ? true : false) < 0)
2538
        goto error;
2539

2540 2541 2542
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2543
    if (networkSetIPv6Sysctls(obj) < 0)
2544
        goto error;
2545

2546
    /* Add "once per network" rules */
2547 2548
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(def) < 0)
2549
        goto error;
2550

2551 2552
    firewalRulesAdded = true;

2553
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i)); i++) {
2554
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2555
            v4present = true;
2556
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2557
            v6present = true;
2558

2559
        /* Add the IP address/netmask to the bridge */
2560
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2561
            goto error;
2562 2563
    }

2564
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2565
        goto error;
2566

2567
    /* Bring up the bridge interface */
2568
    if (virNetDevSetOnline(def->bridge, 1) < 0)
2569
        goto error;
2570

2571 2572
    devOnline = true;

2573
    for (i = 0; i < def->nroutes; i++) {
2574 2575
        virSocketAddrPtr gateway = NULL;

2576
        routedef = def->routes[i];
2577
        gateway = virNetDevIPRouteGetGateway(routedef);
2578

2579 2580 2581
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2582
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2583
            if (networkAddRouteToBridge(obj, routedef) < 0) {
2584 2585 2586 2587 2588 2589
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2590
    /* If forward.type != NONE, turn on global IP forwarding */
2591
    if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2592
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2593
            goto error; /* Precise error message already provided */
2594 2595 2596 2597

        if (networkEnableIPForwarding(v4present, v6present) < 0) {
            virReportSystemError(errno, "%s",
                                 _("failed to enable IP forwarding"));
2598
            goto error;
2599
        }
2600 2601
    }

2602

2603
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2604
    if ((v4present || v6present) &&
2605
        networkStartDhcpDaemon(driver, obj) < 0)
2606
        goto error;
2607

2608 2609
    dnsmasqStarted = true;

2610
    /* start radvd if there are any ipv6 addresses */
2611
    if (v6present && networkStartRadvd(driver, obj) < 0)
2612
        goto error;
2613

2614 2615 2616
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2617
    if (v6present && networkWaitDadFinish(obj) < 0)
2618
        goto error;
2619 2620 2621

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2622 2623 2624
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
2625
            goto error;
2626 2627 2628
        VIR_FORCE_CLOSE(tapfd);
    }

2629
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
2630
        goto error;
2631

2632
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2633
    VIR_FREE(macMapFile);
2634 2635 2636

    return 0;

2637
 error:
2638
    virErrorPreserveLast(&save_err);
2639 2640
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
2641

2642 2643
    if (dnsmasqStarted) {
        pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
2644 2645
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2646 2647
    }

2648 2649
    if (devOnline)
        ignore_value(virNetDevSetOnline(def->bridge, 0));
2650

2651 2652
    if (firewalRulesAdded &&
        def->forward.type != VIR_NETWORK_FORWARD_OPEN)
2653
        networkRemoveFirewallRules(def);
2654

H
Hu Tao 已提交
2655
    if (macTapIfName) {
2656
        VIR_FORCE_CLOSE(tapfd);
2657
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2658 2659
        VIR_FREE(macTapIfName);
    }
2660
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2661
    VIR_FREE(macMapFile);
2662

2663
    ignore_value(virNetDevBridgeDelete(def->bridge));
2664

2665
    virErrorRestore(&save_err);
2666
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2667 2668 2669
    return -1;
}

2670

2671 2672
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2673
                              virNetworkObjPtr obj)
2674
{
2675
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2676 2677 2678
    pid_t radvdPid;
    pid_t dnsmasqPid;

2679 2680
    if (def->bandwidth)
        virNetDevBandwidthClear(def->bridge);
2681

2682
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2683

2684 2685
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2686 2687
        char *radvdpidbase;

2688
        kill(radvdPid, SIGTERM);
2689
        /* attempt to delete the pidfile we created */
2690
        if ((radvdpidbase = networkRadvdPidfileBasename(def->name))) {
2691
            virPidFileDelete(driver->pidDir, radvdpidbase);
2692 2693 2694 2695
            VIR_FREE(radvdpidbase);
        }
    }

2696 2697 2698
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2699

2700 2701
    if (def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(def->bridge);
2702
        if (macTapIfName) {
2703
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2704 2705 2706 2707
            VIR_FREE(macTapIfName);
        }
    }

2708
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2709

2710 2711
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2712

2713
    ignore_value(virNetDevBridgeDelete(def->bridge));
2714

2715
    /* See if its still alive and really really kill it */
2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0 &&
        (kill(dnsmasqPid, 0) == 0))
        kill(dnsmasqPid, SIGKILL);
    virNetworkObjSetDnsmasqPid(obj, -1);

    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0 &&
        (kill(radvdPid, 0) == 0))
        kill(radvdPid, SIGKILL);
    virNetworkObjSetRadvdPid(obj, -1);
2727

2728 2729 2730
    return 0;
}

2731

2732
static int
2733
networkStartNetworkBridge(virNetworkObjPtr obj)
2734
{
2735 2736
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

2737 2738 2739 2740
    /* 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.
     */
2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
        goto error;

    if (networkStartHandleMACTableManagerMode(obj, NULL) < 0)
        goto error;

    return 0;

 error:
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
    return -1;
2753 2754
}

2755

2756
static int
2757
networkShutdownNetworkBridge(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2758
{
2759 2760
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

2761 2762 2763 2764
    /* 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.
     */
2765 2766 2767
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);

2768 2769 2770 2771
    return 0;
}


2772 2773 2774 2775 2776 2777 2778 2779 2780
/* 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;
2781
    unsigned int maxVirtFns = 0;
2782 2783 2784 2785 2786 2787
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2788 2789 2790
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2791 2792
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807
        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];

2808
        switch ((virNetworkForwardType) netdef->forward.type) {
2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838
        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:
2839
        case VIR_NETWORK_FORWARD_OPEN:
2840 2841
            /* by definition these will never be encountered here */
            break;
2842 2843 2844 2845 2846

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
            goto cleanup;
2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883
        }
    }

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


2884
static int
2885
networkStartNetworkExternal(virNetworkObjPtr obj)
2886 2887
{
    /* put anything here that needs to be done each time a network of
2888
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2889 2890 2891
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2892
    return networkCreateInterfacePool(virNetworkObjGetDef(obj));
2893 2894
}

2895 2896

static int
2897
networkShutdownNetworkExternal(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2898 2899
{
    /* put anything here that needs to be done each time a network of
2900
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2901 2902 2903 2904 2905 2906
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2907

2908
static int
2909
networkStartNetwork(virNetworkDriverStatePtr driver,
2910
                    virNetworkObjPtr obj)
2911
{
2912
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2913 2914
    int ret = -1;

2915
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2916

2917
    if (virNetworkObjIsActive(obj)) {
2918 2919
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2920
        return ret;
2921 2922
    }

2923 2924
    VIR_DEBUG("Beginning network startup process");

2925 2926
    virNetworkObjDeleteAllPorts(obj, driver->stateDir);

2927
    VIR_DEBUG("Setting current network def as transient");
2928
    if (virNetworkObjSetDefTransient(obj, true, network_driver->xmlopt) < 0)
2929
        goto cleanup;
2930

2931 2932
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2933
    if (networkRunHook(obj, NULL,
2934 2935 2936 2937
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2938
    switch ((virNetworkForwardType) def->forward.type) {
2939 2940 2941 2942

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2943
    case VIR_NETWORK_FORWARD_OPEN:
2944
        if (networkStartNetworkVirtual(driver, obj) < 0)
2945
            goto cleanup;
2946 2947 2948
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2949
        if (def->bridge) {
2950
            if (networkStartNetworkBridge(obj) < 0)
2951 2952 2953 2954 2955 2956 2957
                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).
         */
2958 2959
        ATTRIBUTE_FALLTHROUGH;

2960 2961 2962
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2963
    case VIR_NETWORK_FORWARD_HOSTDEV:
2964
        if (networkStartNetworkExternal(obj) < 0)
2965
            goto cleanup;
2966
        break;
2967 2968 2969 2970 2971

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, def->forward.type);
        goto cleanup;
2972 2973
    }

2974 2975
    virNetworkObjSetFloorSum(obj, 0);

2976
    /* finally we can call the 'started' hook script if any */
2977
    if (networkRunHook(obj, NULL,
2978 2979 2980 2981
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2982 2983 2984
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2985
    VIR_DEBUG("Writing network status to disk");
2986 2987
    if (virNetworkObjSaveStatus(driver->stateDir,
                                obj, network_driver->xmlopt) < 0)
2988
        goto cleanup;
2989

2990
    virNetworkObjSetActive(obj, true);
2991
    VIR_INFO("Network '%s' started up", def->name);
2992
    ret = 0;
2993

2994
 cleanup:
2995
    if (ret < 0) {
2996 2997 2998
        virErrorPtr save_err;

        virErrorPreserveLast(&save_err);
2999 3000
        virNetworkObjUnsetDefTransient(obj);
        networkShutdownNetwork(driver, obj);
3001
        virErrorRestore(&save_err);
3002 3003 3004 3005
    }
    return ret;
}

3006

3007 3008
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
3009
                       virNetworkObjPtr obj)
3010
{
3011
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
3012 3013 3014
    int ret = 0;
    char *stateFile;

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

3017
    if (!virNetworkObjIsActive(obj))
3018 3019
        return 0;

3020
    stateFile = virNetworkConfigFile(driver->stateDir, def->name);
3021 3022 3023 3024 3025 3026
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

3027
    switch ((virNetworkForwardType) def->forward.type) {
3028 3029 3030 3031

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
3032
    case VIR_NETWORK_FORWARD_OPEN:
3033
        ret = networkShutdownNetworkVirtual(driver, obj);
3034 3035 3036
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3037
        if (def->bridge) {
3038
            ret = networkShutdownNetworkBridge(obj);
3039 3040 3041 3042 3043 3044
            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).
         */
3045 3046
        ATTRIBUTE_FALLTHROUGH;

3047 3048 3049
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
3050
    case VIR_NETWORK_FORWARD_HOSTDEV:
3051
        ret = networkShutdownNetworkExternal(obj);
3052
        break;
3053 3054 3055 3056 3057

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, def->forward.type);
        return -1;
3058 3059
    }

3060
    /* now that we know it's stopped call the hook if present */
3061
    networkRunHook(obj, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
3062 3063
                   VIR_HOOK_SUBOP_END);

3064
    virNetworkObjSetActive(obj, false);
3065
    virNetworkObjUnsetDefTransient(obj);
3066
    return ret;
3067 3068 3069
}


3070 3071 3072
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
3073
{
3074
    virNetworkDriverStatePtr driver = networkGetDriver();
3075
    virNetworkObjPtr obj;
3076
    virNetworkDefPtr def;
3077
    virNetworkPtr net = NULL;
3078

3079 3080
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
3081 3082
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
3083
        virReportError(VIR_ERR_NO_NETWORK,
3084 3085
                       _("no network with matching uuid '%s'"),
                       uuidstr);
3086
        goto cleanup;
3087
    }
3088
    def = virNetworkObjGetDef(obj);
3089

3090
    if (virNetworkLookupByUUIDEnsureACL(conn, def) < 0)
3091 3092
        goto cleanup;

3093
    net = virGetNetwork(conn, def->name, def->uuid);
3094

3095
 cleanup:
3096 3097
    virNetworkObjEndAPI(&obj);
    return net;
3098 3099
}

3100 3101 3102 3103

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
3104
{
3105
    virNetworkDriverStatePtr driver = networkGetDriver();
3106
    virNetworkObjPtr obj;
3107
    virNetworkDefPtr def;
3108
    virNetworkPtr net = NULL;
3109

3110 3111
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
3112 3113
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
3114
        goto cleanup;
3115
    }
3116
    def = virNetworkObjGetDef(obj);
3117

3118
    if (virNetworkLookupByNameEnsureACL(conn, def) < 0)
3119 3120
        goto cleanup;

3121
    net = virGetNetwork(conn, def->name, def->uuid);
3122

3123
 cleanup:
3124 3125
    virNetworkObjEndAPI(&obj);
    return net;
3126 3127
}

3128 3129 3130

static int
networkConnectNumOfNetworks(virConnectPtr conn)
3131
{
3132
    virNetworkDriverStatePtr driver = networkGetDriver();
3133
    int nactive;
3134

3135 3136 3137
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

3138 3139 3140 3141
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
3142

3143 3144 3145
    return nactive;
}

3146 3147 3148 3149

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
3150
                           int maxnames)
3151 3152
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3153
    int got = 0;
3154

3155 3156 3157
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

3158
    got = virNetworkObjListGetNames(driver->networks,
3159
                                    true, names, maxnames,
3160 3161
                                    virConnectListNetworksCheckACL,
                                    conn);
3162

3163 3164 3165
    return got;
}

3166 3167 3168

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
3169
{
3170
    virNetworkDriverStatePtr driver = networkGetDriver();
3171
    int ninactive = 0;
3172

3173 3174 3175
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3176 3177 3178 3179
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
3180

3181 3182 3183
    return ninactive;
}

3184 3185 3186 3187

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
3188
                                  int maxnames)
3189 3190
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3191
    int got = 0;
3192

3193 3194 3195
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3196
    got = virNetworkObjListGetNames(driver->networks,
3197
                                    false, names, maxnames,
3198 3199
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
3200 3201 3202
    return got;
}

3203

3204
static int
3205 3206 3207
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
3208
{
3209
    virNetworkDriverStatePtr driver = networkGetDriver();
3210 3211 3212 3213
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

3214 3215 3216
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

3217
    ret = virNetworkObjListExport(conn, driver->networks, nets,
3218 3219
                                  virConnectListAllNetworksCheckACL,
                                  flags);
3220

3221
 cleanup:
3222 3223
    return ret;
}
3224

3225

3226 3227 3228 3229 3230 3231 3232 3233
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3234
    virNetworkDriverStatePtr driver = networkGetDriver();
3235 3236 3237 3238 3239 3240
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3241
                                       net, eventID, callback,
3242 3243 3244
                                       opaque, freecb, &ret) < 0)
        ret = -1;

3245
 cleanup:
3246 3247 3248
    return ret;
}

3249

3250 3251 3252 3253
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3254
    virNetworkDriverStatePtr driver = networkGetDriver();
3255 3256 3257 3258 3259
    int ret = -1;

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

3260 3261
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3262
                                        callbackID, true) < 0)
3263 3264 3265
        goto cleanup;

    ret = 0;
3266

3267
 cleanup:
3268 3269 3270
    return ret;
}

3271 3272 3273

static int
networkIsActive(virNetworkPtr net)
3274 3275 3276 3277
{
    virNetworkObjPtr obj;
    int ret = -1;

3278 3279
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3280

3281
    if (virNetworkIsActiveEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3282 3283
        goto cleanup;

3284 3285
    ret = virNetworkObjIsActive(obj);

3286
 cleanup:
3287
    virNetworkObjEndAPI(&obj);
3288 3289 3290
    return ret;
}

3291 3292 3293

static int
networkIsPersistent(virNetworkPtr net)
3294 3295 3296 3297
{
    virNetworkObjPtr obj;
    int ret = -1;

3298 3299
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3300

3301
    if (virNetworkIsPersistentEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3302 3303
        goto cleanup;

3304
    ret = virNetworkObjIsPersistent(obj);
3305

3306
 cleanup:
3307
    virNetworkObjEndAPI(&obj);
3308 3309 3310 3311
    return ret;
}


3312 3313
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
3314 3315 3316
 * 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.
3317 3318 3319 3320 3321 3322 3323
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{
    int ret = -1, id = 0;
    char *newname = NULL;
3324 3325 3326 3327 3328
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3329
        p && p[1] == 'd')
3330
        templ = def->bridge;
3331 3332 3333 3334

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3335 3336 3337 3338 3339
        /* 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).
         */
3340
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3341
              virNetDevExists(newname) == 1)) {
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374
            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")) {
3375
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392
            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;
}


3393
static int
3394
networkValidate(virNetworkDriverStatePtr driver,
3395
                virNetworkDefPtr def)
3396
{
3397
    size_t i, j;
3398 3399
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3400
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3401
    bool ipv4def = false, ipv6def = false;
3402
    bool bandwidthAllowed = false;
3403
    bool usesInterface = false, usesAddress = false;
3404

3405 3406 3407
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3408 3409 3410
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3411 3412 3413 3414 3415
    switch ((virNetworkForwardType) def->forward.type) {
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
    case VIR_NETWORK_FORWARD_OPEN:
3416 3417 3418 3419
        /* 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)
3420 3421 3422
            return -1;

        virNetworkSetBridgeMacAddr(def);
3423
        bandwidthAllowed = true;
3424 3425 3426
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3427 3428 3429 3430 3431
        if (def->bridge != NULL)
            bandwidthAllowed = true;

        ATTRIBUTE_FALLTHROUGH;

3432 3433 3434 3435
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
    case VIR_NETWORK_FORWARD_HOSTDEV:
3436
        /* They are also the only types that currently support setting
3437 3438
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
3439
         */
3440 3441 3442 3443 3444 3445 3446 3447
        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;
        }
3448
        if (virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0)) {
3449 3450 3451 3452
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3453
                           virNetworkForwardTypeToString(def->forward.type));
3454 3455
            return -1;
        }
3456
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
3457 3458 3459 3460
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3461
                           virNetworkForwardTypeToString(def->forward.type));
3462 3463 3464 3465 3466 3467 3468
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3469
                           virNetworkForwardTypeToString(def->forward.type));
3470 3471
            return -1;
        }
3472 3473 3474 3475 3476 3477
        break;

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, def->forward.type);
        return -1;
3478 3479
    }

3480 3481 3482 3483 3484 3485 3486 3487 3488 3489
    if (def->bandwidth &&
        !bandwidthAllowed) {
        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;
    }

3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502
    /* 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++) {
3503 3504 3505
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

3506
        switch ((virNetworkForwardHostdevDeviceType)iface->type) {
3507 3508
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519

            if (def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("hostdev network '%s' lists '%s' "
                                 "in the device pool, but hostdev "
                                 "networks require all devices to "
                                 "be listed by PCI address, not "
                                 "network device name"),
                               def->name, iface->device.dev);
                return -1;
            }
3520
            break;
3521 3522

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3523
            usesAddress = true;
3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548

            if (def->forward.type != VIR_NETWORK_FORWARD_HOSTDEV) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has forward mode '%s' "
                                 " but lists a device by PCI address "
                                 "in the device pool. This is only "
                                 "supported for networks with forward "
                                 "mode 'hostdev'"),
                               def->name,
                               virNetworkForwardTypeToString(def->forward.type));
                return -1;
            }

            if (virPCIDeviceAddressGetSysfsFile(&iface->device.pci, &sysfs_path) < 0)
                return -1;

            if (!virPCIIsVirtualFunction(sysfs_path)) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("device '%s' in network '%s' is not "
                                 "an SR-IOV Virtual Function"),
                               sysfs_path, def->name);
                VIR_FREE(sysfs_path);
                return -1;
            }
            VIR_FREE(sysfs_path);
3549
            break;
3550 3551
        }

3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564
        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 已提交
3565 3566 3567
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
3568
    for (i = 0;
3569
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
3570
         i++) {
G
Gene Czarcinski 已提交
3571 3572 3573 3574 3575
        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 -- "
3576 3577
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594
                    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;
                }
3595 3596 3597
            }
        }
    }
3598 3599 3600 3601 3602 3603

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

3604 3605 3606
    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 已提交
3607 3608
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3609
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3610 3611

    vlanUsed = def->vlan.nTags > 0;
3612 3613
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
3614 3615 3616 3617 3618
            /* 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.
             */
3619
            if (def->portGroups[i].virtPortProfile) {
3620
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
3621
                    def->portGroups[i].virtPortProfile->virtPortType
3622 3623 3624 3625 3626 3627 3628
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
3629
        }
3630
        if (def->portGroups[i].isDefault) {
3631 3632 3633 3634 3635
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
3636
                               def->name, defaultPortGroup->name,
3637
                               def->portGroups[i].name);
3638
                return -1;
3639
            }
3640
            defaultPortGroup = &def->portGroups[i];
3641
        }
3642 3643 3644 3645 3646 3647 3648 3649 3650
        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;
            }
        }
3651 3652 3653 3654 3655 3656 3657 3658
        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;
        }
3659
    }
3660 3661 3662 3663 3664 3665 3666
    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.
         */
3667 3668 3669 3670 3671 3672
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686

    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;
            }
        }
    }
3687 3688 3689
    return 0;
}

3690 3691 3692 3693

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3694
{
3695
    virNetworkDriverStatePtr driver = networkGetDriver();
3696
    virNetworkDefPtr newDef;
3697
    virNetworkObjPtr obj = NULL;
3698
    virNetworkDefPtr def;
3699
    virNetworkPtr net = NULL;
3700
    virObjectEventPtr event = NULL;
3701

3702
    if (!(newDef = virNetworkDefParseString(xml, network_driver->xmlopt)))
3703
        goto cleanup;
3704

3705
    if (virNetworkCreateXMLEnsureACL(conn, newDef) < 0)
3706 3707
        goto cleanup;

3708
    if (networkValidate(driver, newDef) < 0)
J
Ján Tomko 已提交
3709
        goto cleanup;
3710

3711 3712 3713
    /* 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.
3714
     */
3715
    if (!(obj = virNetworkObjAssignDef(driver->networks, newDef,
3716 3717
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3718
        goto cleanup;
3719 3720
    newDef = NULL;
    def = virNetworkObjGetDef(obj);
3721

3722 3723
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3724
        goto cleanup;
3725 3726
    }

3727 3728
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3729 3730
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3731

3732 3733
    VIR_INFO("Creating network '%s'", def->name);
    net = virGetNetwork(conn, def->name, def->uuid);
3734

3735
 cleanup:
3736
    virNetworkDefFree(newDef);
3737
    virObjectEventStateQueue(driver->networkEventState, event);
3738 3739
    virNetworkObjEndAPI(&obj);
    return net;
3740 3741
}

3742 3743 3744 3745

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3746
{
3747
    virNetworkDriverStatePtr driver = networkGetDriver();
3748
    virNetworkDefPtr def = NULL;
3749
    bool freeDef = true;
3750 3751
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3752
    virObjectEventPtr event = NULL;
3753

3754
    if (!(def = virNetworkDefParseString(xml, network_driver->xmlopt)))
3755
        goto cleanup;
3756

3757 3758 3759
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3760
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3761
        goto cleanup;
3762

3763
    if (!(obj = virNetworkObjAssignDef(driver->networks, def, 0)))
J
Ján Tomko 已提交
3764
        goto cleanup;
3765

3766
    /* def was assigned to network object */
3767
    freeDef = false;
3768

3769 3770
    if (virNetworkSaveConfig(driver->networkConfigDir,
                             def, network_driver->xmlopt) < 0) {
3771 3772
        if (!virNetworkObjIsActive(obj)) {
            virNetworkObjRemoveInactive(driver->networks, obj);
3773 3774
            goto cleanup;
        }
3775 3776 3777 3778
        /* if network was active already, just undo new persistent
         * definition by making it transient.
         * XXX - this isn't necessarily the correct thing to do.
         */
3779
        virNetworkObjUpdateAssignDef(obj, NULL, false);
3780 3781 3782
        goto cleanup;
    }

3783
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3784 3785
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3786

3787
    VIR_INFO("Defining network '%s'", def->name);
3788
    net = virGetNetwork(conn, def->name, def->uuid);
3789

3790
 cleanup:
3791
    virObjectEventStateQueue(driver->networkEventState, event);
3792
    if (freeDef)
J
Ján Tomko 已提交
3793
        virNetworkDefFree(def);
3794 3795
    virNetworkObjEndAPI(&obj);
    return net;
3796 3797
}

3798

3799
static int
3800 3801
networkUndefine(virNetworkPtr net)
{
3802
    virNetworkDriverStatePtr driver = networkGetDriver();
3803
    virNetworkObjPtr obj;
3804
    virNetworkDefPtr def;
3805
    int ret = -1;
3806
    bool active = false;
3807
    virObjectEventPtr event = NULL;
3808

3809
    if (!(obj = networkObjFromNetwork(net)))
3810
        goto cleanup;
3811
    def = virNetworkObjGetDef(obj);
3812

3813
    if (virNetworkUndefineEnsureACL(net->conn, def) < 0)
3814 3815
        goto cleanup;

3816
    if (virNetworkObjIsActive(obj))
3817
        active = true;
3818

3819
    if (!virNetworkObjIsPersistent(obj)) {
3820 3821 3822 3823 3824
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3825
    /* remove autostart link */
3826 3827
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3828
                                  obj) < 0)
3829
        goto cleanup;
3830

3831 3832
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3833 3834
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3835

3836
    VIR_INFO("Undefining network '%s'", def->name);
3837
    if (!active) {
3838
        if (networkRemoveInactive(driver, obj) < 0)
3839
            goto cleanup;
3840 3841 3842 3843 3844
    } else {

        /* if the network still exists, it was active, and we need to make
         * it transient (by deleting the persistent def)
         */
3845
        virNetworkObjUpdateAssignDef(obj, NULL, false);
3846 3847
    }

3848
    ret = 0;
3849

3850
 cleanup:
3851
    virObjectEventStateQueue(driver->networkEventState, event);
3852
    virNetworkObjEndAPI(&obj);
3853
    return ret;
3854 3855
}

3856

3857 3858 3859 3860 3861 3862 3863 3864
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3865
    virNetworkDriverStatePtr driver = networkGetDriver();
3866
    virNetworkObjPtr obj = NULL;
3867
    virNetworkDefPtr def;
3868 3869
    int isActive, ret = -1;
    size_t i;
3870
    virNetworkIPDefPtr ipdef;
3871
    bool oldDhcpActive = false;
3872
    bool needFirewallRefresh = false;
3873

3874 3875 3876 3877 3878

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3879
    if (!(obj = networkObjFromNetwork(net)))
3880
        goto cleanup;
3881
    def = virNetworkObjGetDef(obj);
3882

3883
    if (virNetworkUpdateEnsureACL(net->conn, def, flags) < 0)
3884 3885
        goto cleanup;

3886
    /* see if we are listening for dhcp pre-modification */
3887
    for (i = 0;
3888
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3889
         i++) {
3890 3891 3892 3893 3894 3895
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3896 3897
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3898
     */
3899
    isActive = virNetworkObjIsActive(obj);
3900 3901
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3902 3903 3904 3905 3906 3907 3908
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3909 3910 3911 3912
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
3913 3914 3915 3916
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
3917 3918 3919 3920 3921 3922 3923 3924 3925 3926
            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).
                 */
3927 3928
                networkRemoveFirewallRules(def);
                needFirewallRefresh = true;
3929 3930 3931 3932
                break;
            default:
                break;
            }
3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946
            break;

        case VIR_NETWORK_FORWARD_OPEN:
        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
        case VIR_NETWORK_FORWARD_HOSTDEV:
            break;

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, def->forward.type);
            goto cleanup;
3947 3948 3949
        }
    }

3950
    /* update the network config in memory/on disk */
3951 3952 3953
    if (virNetworkObjUpdate(obj, command, section,
                            parentIndex, xml,
                            network_driver->xmlopt, flags) < 0) {
3954
        if (needFirewallRefresh)
3955
            ignore_value(networkAddFirewallRules(def));
3956 3957 3958
        goto cleanup;
    }

3959 3960 3961 3962
    /* @def is replaced */
    def = virNetworkObjGetDef(obj);

    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
3963 3964 3965 3966 3967
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
3968 3969
                                 virNetworkObjGetPersistentDef(obj),
                                 network_driver->xmlopt) < 0) {
3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982
            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 ||
3983 3984 3985 3986 3987 3988 3989 3990
            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)
3991
             */
3992
            if (networkRestartDhcpDaemon(driver, obj) < 0)
3993 3994
                goto cleanup;

3995 3996 3997 3998 3999 4000 4001 4002
        } 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;

4003
            for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
4004
                 i++) {
4005 4006 4007 4008 4009 4010 4011
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
4012 4013
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
4014 4015 4016
                goto cleanup;
            }

4017 4018 4019 4020
        } 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.
4021
             */
4022
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
4023 4024 4025 4026 4027 4028 4029 4030
                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.
             */
4031
            if (networkRefreshRadvd(driver, obj) < 0)
4032 4033 4034 4035
                goto cleanup;
        }

        /* save current network state to disk */
4036 4037
        if ((ret = virNetworkObjSaveStatus(driver->stateDir,
                                           obj, network_driver->xmlopt)) < 0)
4038 4039
            goto cleanup;
    }
4040 4041

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

4046
    ret = 0;
4047
 cleanup:
4048
    virNetworkObjEndAPI(&obj);
4049 4050 4051
    return ret;
}

4052 4053 4054

static int
networkCreate(virNetworkPtr net)
4055
{
4056
    virNetworkDriverStatePtr driver = networkGetDriver();
4057
    virNetworkObjPtr obj;
4058
    virNetworkDefPtr def;
4059
    int ret = -1;
4060
    virObjectEventPtr event = NULL;
4061

4062
    if (!(obj = networkObjFromNetwork(net)))
4063
        goto cleanup;
4064
    def = virNetworkObjGetDef(obj);
4065

4066
    if (virNetworkCreateEnsureACL(net->conn, def) < 0)
4067 4068
        goto cleanup;

4069
    if ((ret = networkStartNetwork(driver, obj)) < 0)
4070
        goto cleanup;
4071

4072 4073
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
4074 4075
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
4076

4077
 cleanup:
4078
    virObjectEventStateQueue(driver->networkEventState, event);
4079
    virNetworkObjEndAPI(&obj);
4080
    return ret;
4081 4082
}

4083 4084 4085

static int
networkDestroy(virNetworkPtr net)
4086
{
4087
    virNetworkDriverStatePtr driver = networkGetDriver();
4088
    virNetworkObjPtr obj;
4089
    virNetworkDefPtr def;
4090
    int ret = -1;
4091
    virObjectEventPtr event = NULL;
4092

4093
    if (!(obj = networkObjFromNetwork(net)))
4094
        goto cleanup;
4095
    def = virNetworkObjGetDef(obj);
4096

4097
    if (virNetworkDestroyEnsureACL(net->conn, def) < 0)
4098 4099
        goto cleanup;

4100
    if (!virNetworkObjIsActive(obj)) {
4101
        virReportError(VIR_ERR_OPERATION_INVALID,
4102
                       _("network '%s' is not active"),
4103
                       def->name);
4104 4105 4106
        goto cleanup;
    }

4107
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
4108
        goto cleanup;
4109 4110 4111

    virNetworkObjDeleteAllPorts(obj, driver->stateDir);

4112 4113
    /* @def replaced in virNetworkObjUnsetDefTransient*/
    def = virNetworkObjGetDef(obj);
4114

4115 4116
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
4117 4118
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
4119

4120 4121
    if (!virNetworkObjIsPersistent(obj) &&
        networkRemoveInactive(driver, obj) < 0) {
4122 4123
        ret = -1;
        goto cleanup;
4124
    }
4125

4126
 cleanup:
4127
    virObjectEventStateQueue(driver->networkEventState, event);
4128
    virNetworkObjEndAPI(&obj);
4129 4130 4131
    return ret;
}

4132 4133 4134 4135

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
4136
{
4137
    virNetworkObjPtr obj;
4138
    virNetworkDefPtr curDef;
4139
    virNetworkDefPtr def;
4140
    virNetworkDefPtr newDef;
4141
    char *ret = NULL;
4142

4143
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
4144

4145
    if (!(obj = networkObjFromNetwork(net)))
4146
        return ret;
4147 4148
    def = virNetworkObjGetDef(obj);
    newDef = virNetworkObjGetNewDef(obj);
4149

4150
    if (virNetworkGetXMLDescEnsureACL(net->conn, def) < 0)
4151 4152
        goto cleanup;

4153 4154
    if ((flags & VIR_NETWORK_XML_INACTIVE) && newDef)
        curDef = newDef;
4155
    else
4156
        curDef = def;
4157

4158
    ret = virNetworkDefFormat(curDef, network_driver->xmlopt, flags);
4159

4160
 cleanup:
4161
    virNetworkObjEndAPI(&obj);
4162
    return ret;
4163 4164
}

4165 4166 4167 4168

static char *
networkGetBridgeName(virNetworkPtr net)
{
4169
    virNetworkObjPtr obj;
4170
    virNetworkDefPtr def;
4171 4172
    char *bridge = NULL;

4173
    if (!(obj = networkObjFromNetwork(net)))
4174
        return bridge;
4175
    def = virNetworkObjGetDef(obj);
4176

4177
    if (virNetworkGetBridgeNameEnsureACL(net->conn, def) < 0)
4178 4179
        goto cleanup;

4180
    if (!(def->bridge)) {
4181 4182
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
4183
                       def->name);
4184 4185 4186
        goto cleanup;
    }

4187
    ignore_value(VIR_STRDUP(bridge, def->bridge));
4188

4189
 cleanup:
4190
    virNetworkObjEndAPI(&obj);
4191 4192 4193
    return bridge;
}

4194 4195 4196 4197

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
4198
{
4199
    virNetworkObjPtr obj;
4200
    int ret = -1;
4201

4202
    if (!(obj = networkObjFromNetwork(net)))
4203
        return ret;
4204

4205
    if (virNetworkGetAutostartEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
4206 4207
        goto cleanup;

4208
    *autostart = virNetworkObjIsAutostart(obj) ? 1 : 0;
4209
    ret = 0;
4210

4211
 cleanup:
4212
    virNetworkObjEndAPI(&obj);
4213
    return ret;
4214 4215
}

4216 4217 4218 4219

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
4220
{
4221
    virNetworkDriverStatePtr driver = networkGetDriver();
4222
    virNetworkObjPtr obj;
4223
    virNetworkDefPtr def;
4224
    char *configFile = NULL, *autostartLink = NULL;
4225 4226
    bool new_autostart;
    bool cur_autostart;
4227
    int ret = -1;
4228

4229
    if (!(obj = networkObjFromNetwork(net)))
4230
        goto cleanup;
4231
    def = virNetworkObjGetDef(obj);
4232

4233
    if (virNetworkSetAutostartEnsureACL(net->conn, def) < 0)
4234 4235
        goto cleanup;

4236
    if (!virNetworkObjIsPersistent(obj)) {
4237 4238
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
4239 4240 4241
        goto cleanup;
    }

4242 4243 4244
    new_autostart = (autostart != 0);
    cur_autostart = virNetworkObjIsAutostart(obj);
    if (cur_autostart != new_autostart) {
4245 4246
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir,
                                               def->name)) == NULL)
4247
            goto cleanup;
4248 4249
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir,
                                                  def->name)) == NULL)
4250 4251
            goto cleanup;

4252
        if (new_autostart) {
4253
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
4254
                virReportSystemError(errno,
4255 4256
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
4257 4258
                goto cleanup;
            }
4259

4260
            if (symlink(configFile, autostartLink) < 0) {
4261
                virReportSystemError(errno,
4262
                                     _("Failed to create symlink '%s' to '%s'"),
4263
                                     autostartLink, configFile);
4264 4265 4266
                goto cleanup;
            }
        } else {
4267
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4268
                virReportSystemError(errno,
4269
                                     _("Failed to delete symlink '%s'"),
4270
                                     autostartLink);
4271 4272
                goto cleanup;
            }
4273 4274
        }

4275
        virNetworkObjSetAutostart(obj, new_autostart);
4276
    }
4277

4278
    ret = 0;
4279

4280
 cleanup:
4281 4282
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4283
    virNetworkObjEndAPI(&obj);
4284
    return ret;
4285 4286
}

4287

4288
static int
4289
networkGetDHCPLeases(virNetworkPtr net,
4290 4291 4292
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
4293
{
4294
    virNetworkDriverStatePtr driver = networkGetDriver();
4295 4296 4297
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
4298
    size_t size = 0;
4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309
    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;
4310
    virNetworkIPDefPtr ipdef_tmp = NULL;
4311 4312
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
4313
    virNetworkObjPtr obj;
4314
    virNetworkDefPtr def;
4315
    virMacAddr mac_addr;
4316 4317 4318

    virCheckFlags(0, -1);

4319 4320 4321 4322 4323 4324
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4325
    if (!(obj = networkObjFromNetwork(net)))
4326
        return -1;
4327
    def = virNetworkObjGetDef(obj);
4328

4329
    if (virNetworkGetDHCPLeasesEnsureACL(net->conn, def) < 0)
4330
        goto cleanup;
4331 4332

    /* Retrieve custom leases file location */
4333
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, def->bridge);
4334 4335

    /* Read entire contents */
4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349
    if ((custom_lease_file_len = virFileReadAllQuiet(custom_lease_file,
                                                     VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX,
                                                     &lease_entries)) < 0) {
        /* Not all networks are guaranteed to have leases file.
         * Only those which run dnsmasq. Therefore, if we failed
         * to read the leases file, don't report error. Return 0
         * leases instead. */
        if (errno == ENOENT) {
            rv = 0;
        } else {
            virReportSystemError(errno,
                                 _("Unable to read leases file: %s"),
                                 custom_lease_file);
        }
4350 4351 4352 4353 4354 4355 4356 4357 4358 4359
        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;
        }

4360
        if (!virJSONValueIsArray(leases_array)) {
4361
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4362
                           _("Malformed lease_entries array"));
4363 4364
            goto error;
        }
4365
        size = virJSONValueArraySize(leases_array);
4366 4367
    }

4368
    currtime = (long long)time(NULL);
4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384

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

4385
        if (mac && virMacAddrCompare(mac, mac_tmp))
4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416
            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 */
4417 4418
            for (j = 0; j < def->nips; j++) {
                ipdef_tmp = &def->ips[j];
4419 4420 4421 4422 4423 4424 4425 4426

                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)) {
4427
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4428 4429 4430 4431 4432 4433 4434 4435
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
4436
                (VIR_STRDUP(lease->iface, def->bridge) < 0))
4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468
                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);
4469
    VIR_FREE(lease_entries);
4470 4471
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4472

4473
    virNetworkObjEndAPI(&obj);
4474

4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485
    return rv;

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

4486

4487 4488 4489 4490 4491
/* A unified function to log network connections and disconnections */

static void
networkLogAllocation(virNetworkDefPtr netdef,
                     virNetworkForwardIfDefPtr dev,
4492
                     virMacAddrPtr mac,
4493 4494 4495 4496 4497
                     bool inUse)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    const char *verb = inUse ? "using" : "releasing";

4498
    virMacAddrFormat(mac, macStr);
4499 4500
    if (!dev) {
        VIR_INFO("MAC %s %s network %s (%d connections)",
4501
                 macStr, verb, netdef->name, netdef->connections);
4502
    } else {
4503
        if (dev->type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI) {
4504 4505
            VIR_INFO("MAC %s %s network %s (%d connections) "
                     "physical device %04x:%02x:%02x.%x (%d connections)",
4506
                     macStr, verb, netdef->name, netdef->connections,
4507 4508 4509 4510 4511 4512
                     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)",
4513
                     macStr, verb, netdef->name, netdef->connections,
4514 4515 4516 4517 4518
                     dev->device.dev, dev->connections);
        }
    }
}

4519

4520 4521 4522 4523 4524 4525 4526 4527
/* 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.
 */

4528 4529 4530
/* networkAllocatePort:
 * @obj: the network to allocate from
 * @port: the port definition to allocate
4531
 *
4532
 * Looks up the network reference by port, allocates a physical
4533
 * device from that network (if appropriate), and returns with the
4534
 * port configuration filled in accordingly.
4535 4536 4537
 *
 * Returns 0 on success, -1 on failure.
 */
4538
static int
4539 4540
networkAllocatePort(virNetworkObjPtr obj,
                    virNetworkPortDefPtr port)
4541
{
4542
    virNetworkDriverStatePtr driver = networkGetDriver();
4543 4544
    virNetworkDefPtr netdef = NULL;
    virPortGroupDefPtr portgroup = NULL;
4545
    virNetworkForwardIfDefPtr dev = NULL;
4546
    size_t i;
4547
    int ret = -1;
4548
    virNetDevVPortProfilePtr portprofile = NULL;
4549

4550
    netdef = virNetworkObjGetDef(obj);
4551
    VIR_DEBUG("Allocating port from net %s", netdef->name);
4552

4553
    if (!virNetworkObjIsActive(obj)) {
4554 4555 4556
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4557
        goto cleanup;
4558 4559
    }

4560
    VIR_DEBUG("Interface port group %s", port->group);
4561 4562 4563
    /* 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 已提交
4564
     */
4565
    portgroup = virPortGroupFindByName(netdef, port->group);
4566

4567 4568 4569 4570
    if (!port->bandwidth) {
        if (portgroup && portgroup->bandwidth &&
            virNetDevBandwidthCopy(&port->bandwidth,
                                   portgroup->bandwidth) < 0)
4571
            goto cleanup;
4572
    }
4573

4574 4575 4576 4577 4578 4579
    if (port->vlan.nTags == 0) {
        virNetDevVlanPtr vlan = NULL;
        if (portgroup && portgroup->vlan.nTags > 0)
            vlan = &portgroup->vlan;
        else if (netdef->vlan.nTags > 0)
            vlan = &netdef->vlan;
4580

4581
        if (vlan && virNetDevVlanCopy(&port->vlan, vlan) < 0)
4582
            goto cleanup;
4583
    }
4584

4585 4586 4587 4588 4589 4590
    if (!port->trustGuestRxFilters) {
        if (portgroup && portgroup->trustGuestRxFilters)
            port->trustGuestRxFilters = portgroup->trustGuestRxFilters;
        else if (netdef->trustGuestRxFilters)
            port->trustGuestRxFilters = netdef->trustGuestRxFilters;
    }
4591

4592 4593 4594
    /* merge virtualports from interface, network, and portgroup to
     * arrive at actual virtualport to use
     */
4595 4596
    if (virNetDevVPortProfileMerge3(&portprofile,
                                    port->virtPortProfile,
4597 4598 4599
                                    netdef->virtPortProfile,
                                    portgroup
                                    ? portgroup->virtPortProfile : NULL) < 0) {
4600
                goto cleanup;
4601 4602 4603 4604
    }
    if (portprofile) {
        VIR_FREE(port->virtPortProfile);
        port->virtPortProfile = portprofile;
4605 4606
    }

4607
    VIR_DEBUG("Processing forward type %d", netdef->forward.type);
4608 4609 4610 4611 4612
    switch ((virNetworkForwardType) netdef->forward.type) {
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
    case VIR_NETWORK_FORWARD_OPEN:
4613 4614 4615 4616
        /* for these forward types, the actual net type really *is*
         * NETWORK; we just keep the info from the portgroup in
         * iface->data.network.actual
         */
4617
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_NETWORK;
4618

4619
        if (VIR_STRDUP(port->plug.bridge.brname, netdef->bridge) < 0)
4620
            goto cleanup;
4621
        port->plug.bridge.macTableManager = netdef->macTableManager;
4622

4623
        if (port->virtPortProfile) {
4624 4625 4626
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("<virtualport type='%s'> not supported for network "
                             "'%s' which uses IP forwarding"),
4627
                           virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4628
                           netdef->name);
4629
            goto cleanup;
4630 4631
        }

4632
        if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4633
            goto cleanup;
4634
        break;
4635

4636
    case VIR_NETWORK_FORWARD_HOSTDEV: {
4637
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI;
4638

4639
        if (networkCreateInterfacePool(netdef) < 0)
4640
            goto cleanup;
4641 4642

        /* pick first dev with 0 connections */
4643 4644 4645
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4646 4647 4648 4649 4650 4651 4652 4653
                break;
            }
        }
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' requires exclusive access "
                             "to interfaces, but none are available"),
                           netdef->name);
4654
            goto cleanup;
4655
        }
4656 4657 4658
        port->plug.hostdevpci.addr = dev->device.pci;
        port->plug.hostdevpci.driver = netdef->forward.driverName;
        port->plug.hostdevpci.managed = netdef->forward.managed;
4659

4660
        if (port->virtPortProfile) {
4661
            /* make sure type is supported for hostdev connections */
4662 4663
            if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
4664 4665 4666 4667
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses an SR-IOV Virtual Function "
                                 "via PCI passthrough"),
4668
                               virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4669
                               netdef->name);
4670
                goto cleanup;
4671 4672
            }
        }
4673 4674
        break;
    }
4675

4676 4677 4678 4679 4680 4681
    case VIR_NETWORK_FORWARD_BRIDGE:
        if (netdef->bridge) {
            /* <forward type='bridge'/> <bridge name='xxx'/>
             * is VIR_DOMAIN_NET_TYPE_BRIDGE
             */

4682 4683
            port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE;
            if (VIR_STRDUP(port->plug.bridge.brname, netdef->bridge) < 0)
4684
                goto cleanup;
4685
            port->plug.bridge.macTableManager = netdef->macTableManager;
4686

4687
            if (port->virtPortProfile) {
4688
                /* only type='openvswitch' is allowed for bridges */
4689
                if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
4690 4691 4692
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport type='%s'> not supported for network "
                                     "'%s' which uses a bridge device"),
4693
                                   virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4694
                                   netdef->name);
4695
                    goto cleanup;
4696 4697
                }
            }
4698

4699
            if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4700
                goto cleanup;
4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711
            break;
        }

        /* intentionally fall through to the direct case for
         * VIR_NETWORK_FORWARD_BRIDGE with no bridge device defined
         */
        ATTRIBUTE_FALLTHROUGH;

    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
4712 4713 4714 4715 4716
        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
4717
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_DIRECT;
4718 4719 4720 4721

        /* NO need to check the value returned from virNetDevMacVLanModeTypeFromString
         * it must be valid for these forward type(bridge|private|vepa|passthrough)
         */
4722
        port->plug.direct.mode =
4723
            virNetDevMacVLanModeTypeFromString(virNetworkForwardTypeToString(netdef->forward.type));
4724

4725
        if (port->virtPortProfile) {
4726
            /* make sure type is supported for macvtap connections */
4727 4728
            if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
4729 4730 4731
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses a macvtap device"),
4732
                               virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4733
                               netdef->name);
4734
                goto cleanup;
4735 4736
            }
        }
4737

4738 4739 4740
        /* 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).
         */
4741
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4742 4743 4744 4745
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4746
            goto cleanup;
4747 4748 4749
        } else {
            /* pick an interface from the pool */

4750
            if (networkCreateInterfacePool(netdef) < 0)
4751
                goto cleanup;
4752

4753 4754 4755 4756 4757
            /* 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.
4758
             */
4759 4760
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4761 4762
                 port->virtPortProfile &&
                 (port->virtPortProfile->virtPortType
4763
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4764

4765
                /* pick first dev with 0 connections */
4766 4767 4768
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4769 4770 4771 4772 4773
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4774
                dev = &netdef->forward.ifs[0];
4775 4776 4777
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4778 4779 4780 4781
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4782 4783 4784 4785
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4786
                goto cleanup;
4787
            }
4788
            if (VIR_STRDUP(port->plug.direct.linkdev,
4789
                           dev->device.dev) < 0)
4790
                goto cleanup;
4791
        }
4792 4793 4794 4795 4796
        break;

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
4797
        goto cleanup;
4798 4799
    }

4800
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
4801 4802
                               port->ownername, &port->mac) < 0)
        goto cleanup;
M
Michal Privoznik 已提交
4803

4804
    if (virNetDevVPortProfileCheckComplete(port->virtPortProfile, true) < 0)
4805
        goto cleanup;
4806

4807 4808 4809 4810
    /* 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.
     */
4811
    VIR_DEBUG("Sanity check port config");
4812

4813
    if (port->vlan.nTags) {
4814 4815 4816 4817
        /* 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
4818
         */
4819 4820 4821
        if (!(port->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI ||
              (port->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_DIRECT &&
               port->plug.direct.mode == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) ||
4822
              (port->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE &&
4823 4824
               port->virtPortProfile &&
               port->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
4825 4826 4827 4828 4829
            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);
4830
            goto cleanup;
4831 4832
        }
    }
4833 4834 4835 4836 4837 4838 4839 4840

    /* bandwidth configuration via libvirt is not supported for
     * hostdev network devices
     */
    if (port->bandwidth && port->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("bandwidth settings are not supported "
                         "for hostdev interfaces"));
4841
        goto cleanup;
4842
    }
4843

4844 4845 4846 4847
    netdef->connections++;
    if (dev)
        dev->connections++;
    /* finally we can call the 'plugged' hook script if any */
4848 4849
    if (networkRunHook(obj, port,
                       VIR_HOOK_NETWORK_OP_PORT_CREATED,
4850 4851 4852
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        netdef->connections--;
4853
        if (dev)
4854
            dev->connections--;
4855
        goto cleanup;
4856
    }
4857
    networkLogAllocation(netdef, dev, &port->mac, true);
4858 4859

    VIR_DEBUG("Port allocated");
4860

4861
    ret = 0;
4862
 cleanup:
4863
    return ret;
4864
}
4865

4866

4867 4868 4869
/* networkNotifyPort:
 * @obj: the network to notify
 * @port: the port definition to notify
4870 4871 4872 4873
 *
 * 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
4874
 * order.
4875
 */
4876
static int
4877 4878
networkNotifyPort(virNetworkObjPtr obj,
                  virNetworkPortDefPtr port)
4879 4880
{
    virNetworkDefPtr netdef;
4881
    virNetworkForwardIfDefPtr dev = NULL;
4882
    size_t i;
4883
    int ret = -1;
4884

4885
    netdef = virNetworkObjGetDef(obj);
4886

4887
    if (!virNetworkObjIsActive(obj)) {
4888 4889 4890
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4891
        goto cleanup;
4892
    }
4893

4894 4895 4896 4897
    switch (port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unexpectedly got a network port without a plug"));
4898
        goto cleanup;
4899

4900 4901 4902 4903
    case VIR_NETWORK_PORT_PLUG_TYPE_NETWORK:
    case VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE:
        /* see if we're connected to the correct bridge */
        if (!netdef->bridge) {
4904
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4905
                           _("Unexpectedly got a network port without a network bridge"));
4906
            goto cleanup;
4907
        }
4908 4909 4910 4911
        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
        if (networkCreateInterfacePool(netdef) < 0)
4912
            goto cleanup;
4913 4914

        /* find the matching interface and increment its connections */
4915 4916
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4917
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4918 4919
                STREQ(port->plug.direct.linkdev,
                      netdef->forward.ifs[i].device.dev)) {
4920
                dev = &netdef->forward.ifs[i];
4921 4922 4923 4924 4925
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4926
            virReportError(VIR_ERR_INTERNAL_ERROR,
4927
                           _("network '%s' doesn't have dev='%s' "
4928 4929 4930
                             "in use by network port '%s'"),
                           netdef->name, port->plug.direct.linkdev,
                           port->uuid);
4931
            goto cleanup;
4932 4933
        }

4934
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4935 4936
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4937
         */
4938
        if ((dev->connections > 0) &&
4939 4940
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4941 4942
              port->virtPortProfile &&
              (port->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4943
            virReportError(VIR_ERR_INTERNAL_ERROR,
4944
                           _("network '%s' claims dev='%s' is already in "
4945 4946
                             "use by a different port"),
                           netdef->name, port->plug.direct.linkdev);
4947
            goto cleanup;
4948
        }
4949
        break;
4950

4951 4952 4953
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:

        if (networkCreateInterfacePool(netdef) < 0)
4954
            goto cleanup;
4955 4956

        /* find the matching interface and increment its connections */
4957 4958
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4959
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4960
                virPCIDeviceAddressEqual(&port->plug.hostdevpci.addr,
4961 4962
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4963 4964 4965 4966 4967 4968 4969
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have "
4970
                             "PCI device %04x:%02x:%02x.%x in use by network port"),
4971
                           netdef->name,
4972 4973 4974 4975
                           port->plug.hostdevpci.addr.domain,
                           port->plug.hostdevpci.addr.bus,
                           port->plug.hostdevpci.addr.slot,
                           port->plug.hostdevpci.addr.function);
4976
            goto cleanup;
4977 4978 4979 4980 4981 4982 4983
        }

        /* 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) &&
4984
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4985 4986 4987
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' claims the PCI device at "
                             "domain=%d bus=%d slot=%d function=%d "
4988
                             "is already in use by a different network port"),
4989 4990 4991
                           netdef->name,
                           dev->device.pci.domain, dev->device.pci.bus,
                           dev->device.pci.slot, dev->device.pci.function);
4992
            goto cleanup;
4993
        }
4994 4995 4996 4997 4998 4999

        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
    default:
        virReportEnumRangeError(virNetworkPortPlugType, port->plugtype);
5000
        goto cleanup;
5001 5002
    }

5003
    netdef->connections++;
5004 5005
    if (dev)
        dev->connections++;
5006
    /* finally we can call the 'plugged' hook script if any */
5007
    if (networkRunHook(obj, port, VIR_HOOK_NETWORK_OP_PORT_CREATED,
5008 5009 5010 5011 5012
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
5013
        goto cleanup;
5014
    }
5015 5016
    networkLogAllocation(netdef, dev, &port->mac, true);

5017
    ret = 0;
5018 5019 5020 5021 5022
 cleanup:
    return ret;
}


5023 5024 5025
/* networkReleasePort:
 * @obj: the network to release from
 * @port: the port definition to release
5026 5027 5028 5029 5030 5031 5032 5033
 *
 * 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.
 */
5034
static int
5035 5036
networkReleasePort(virNetworkObjPtr obj,
                   virNetworkPortDefPtr port)
5037
{
5038
    virNetworkDriverStatePtr driver = networkGetDriver();
5039
    virNetworkDefPtr netdef;
5040
    virNetworkForwardIfDefPtr dev = NULL;
5041 5042
    size_t i;
    int ret = -1;
5043

5044
    netdef = virNetworkObjGetDef(obj);
5045

5046 5047 5048
    switch ((virNetworkPortPlugType)port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        VIR_DEBUG("Releasing network device with no plug type");
5049 5050
        break;

5051 5052 5053 5054 5055
    case VIR_NETWORK_PORT_PLUG_TYPE_NETWORK:
    case VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE:
        if (networkUnplugBandwidth(obj, port->bandwidth,
                                   &port->class_id) < 0)
            goto cleanup;
5056 5057
        break;

5058 5059 5060 5061 5062 5063 5064
    case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
        if (netdef->forward.nifs == 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
            goto cleanup;
5065
        }
5066

5067 5068
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5069
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
5070
                STREQ(port->plug.direct.linkdev, netdef->forward.ifs[i].device.dev)) {
5071
                dev = &netdef->forward.ifs[i];
5072 5073 5074
                break;
            }
        }
5075

5076
        if (!dev) {
5077
            virReportError(VIR_ERR_INTERNAL_ERROR,
5078 5079
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5080 5081
                           netdef->name, port->plug.direct.linkdev);
            goto cleanup;
5082
        }
5083
        break;
5084

5085 5086
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:
        if (netdef->forward.nifs == 0) {
5087
            virReportError(VIR_ERR_INTERNAL_ERROR,
5088 5089 5090 5091
                           _("network '%s' uses a hostdev mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
            goto cleanup;
5092 5093
        }

5094 5095
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5096
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5097
                virPCIDeviceAddressEqual(&port->plug.hostdevpci.addr,
5098 5099
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5100 5101 5102 5103 5104 5105 5106 5107 5108
                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,
5109 5110 5111 5112 5113
                           port->plug.hostdevpci.addr.domain,
                           port->plug.hostdevpci.addr.bus,
                           port->plug.hostdevpci.addr.slot,
                           port->plug.hostdevpci.addr.function);
            goto cleanup;
5114
        }
5115 5116 5117 5118 5119 5120
        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
    default:
        virReportEnumRangeError(virNetworkPortPlugType, port->plugtype);
        goto cleanup;
J
Ján Tomko 已提交
5121
    }
5122

5123
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, port->ownername, &port->mac);
5124 5125 5126 5127 5128

    netdef->connections--;
    if (dev)
        dev->connections--;
    /* finally we can call the 'unplugged' hook script if any */
5129
    networkRunHook(obj, port, VIR_HOOK_NETWORK_OP_PORT_DELETED,
5130 5131
                   VIR_HOOK_SUBOP_BEGIN);
    networkLogAllocation(netdef, dev, &port->mac, false);
M
Michal Privoznik 已提交
5132

5133 5134 5135 5136 5137 5138
    ret = 0;
 cleanup:
    return ret;
}


5139 5140 5141
/**
 * networkCheckBandwidth:
 * @net: network QoS
5142
 * @ifaceBand: interface QoS (may be NULL if no QoS)
5143
 * @oldBandwidth: new interface QoS (may be NULL if no QoS)
5144
 * @ifaceMac: interface MAC (used in error messages for identification)
5145 5146
 * @new_rate: new rate for non guaranteed class
 *
5147 5148 5149 5150 5151 5152 5153 5154
 * 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.
 *
5155 5156 5157 5158 5159
 * 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
5160
networkCheckBandwidth(virNetworkObjPtr obj,
5161
                      virNetDevBandwidthPtr ifaceBand,
5162
                      virNetDevBandwidthPtr oldBandwidth,
5163
                      virMacAddrPtr ifaceMac,
5164 5165 5166
                      unsigned long long *new_rate)
{
    int ret = -1;
5167 5168
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    virNetDevBandwidthPtr netBand = def->bandwidth;
5169
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5170 5171 5172
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5173
    virMacAddrFormat(ifaceMac, ifmac);
5174 5175 5176 5177 5178 5179

    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"),
5180
                       ifmac, def->name);
5181 5182 5183
        return -1;
    }

5184 5185 5186 5187 5188
    if (!netBand || !netBand->in) {
        VIR_DEBUG("No network bandwidth controls present");
        /* no QoS required, claim success */
        return 1;
    }
5189
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
5190 5191
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor))) {
        VIR_DEBUG("No old/new interface bandwidth floor");
5192
        /* no QoS required, claim success */
5193
        return 1;
5194
    }
5195 5196

    tmp_new_rate = netBand->in->average;
5197 5198 5199 5200
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
5201 5202 5203 5204 5205 5206

    /* 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,
5207 5208 5209
                           _("Cannot plug '%s' interface into '%s' because "
                             "new combined inbound floor=%llu would overcommit "
                             "peak=%llu on network '%s'"),
5210
                           ifmac,
5211
                           def->bridge,
5212 5213
                           tmp_floor_sum,
                           netBand->in->peak,
5214
                           def->name);
5215 5216 5217 5218 5219 5220
            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,
5221 5222 5223
                       _("Cannot plug '%s' interface into '%s' because "
                         "new combined inbound floor=%llu would overcommit "
                         "average=%llu on network '%s'"),
5224
                       ifmac,
5225
                       def->bridge,
5226 5227
                       tmp_floor_sum,
                       netBand->in->average,
5228
                       def->name);
5229 5230 5231
        goto cleanup;
    }

5232 5233
    if (new_rate)
        *new_rate = tmp_new_rate;
5234 5235
    ret = 0;

5236
 cleanup:
5237 5238 5239
    return ret;
}

5240

5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251
/**
 * 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
5252
networkNextClassID(virNetworkObjPtr obj)
5253
{
5254
    ssize_t ret = 0;
5255
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5256

5257 5258
    if ((ret = virBitmapNextClearBit(classIdMap, -1)) < 0)
        ret = virBitmapSize(classIdMap);
5259

5260
    if (virBitmapSetBitExpand(classIdMap, ret) < 0)
5261 5262 5263 5264 5265
        return -1;

    return ret;
}

5266

5267
static int
5268
networkPlugBandwidthImpl(virNetworkObjPtr obj,
5269
                         virMacAddrPtr mac,
5270
                         virNetDevBandwidthPtr ifaceBand,
5271
                         unsigned int *class_id,
5272
                         unsigned long long new_rate)
5273
{
5274
    virNetworkDriverStatePtr driver = networkGetDriver();
5275
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5276
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5277
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5278
    ssize_t next_id = 0;
5279 5280
    int plug_ret;
    int ret = -1;
5281 5282

    /* generate new class_id */
5283
    if ((next_id = networkNextClassID(obj)) < 0) {
5284 5285 5286 5287 5288
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate next class ID"));
        goto cleanup;
    }

5289
    plug_ret = virNetDevBandwidthPlug(def->bridge, def->bandwidth,
5290
                                      mac, ifaceBand, next_id);
5291
    if (plug_ret < 0) {
5292
        ignore_value(virNetDevBandwidthUnplug(def->bridge, next_id));
5293 5294 5295 5296
        goto cleanup;
    }

    /* QoS was set, generate new class ID */
5297
    *class_id = next_id;
5298
    /* update sum of 'floor'-s of attached NICs */
5299 5300
    tmp_floor_sum += ifaceBand->in->floor;
    virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5301
    /* update status file */
5302
    if (virNetworkObjSaveStatus(driver->stateDir, obj, network_driver->xmlopt) < 0) {
5303
        ignore_value(virBitmapClearBit(classIdMap, next_id));
5304 5305
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5306 5307
        *class_id = 0;
        ignore_value(virNetDevBandwidthUnplug(def->bridge, next_id));
5308 5309
        goto cleanup;
    }
5310
    /* update rate for non guaranteed NICs */
5311
    new_rate -= tmp_floor_sum;
5312 5313
    if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                     def->bandwidth, new_rate) < 0)
5314
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5315
                 def->bridge);
5316 5317

    ret = 0;
5318 5319 5320 5321 5322 5323
 cleanup:
    return ret;
}


static int
5324
networkPlugBandwidth(virNetworkObjPtr obj,
5325 5326 5327
                     virMacAddrPtr mac,
                     virNetDevBandwidthPtr ifaceBand,
                     unsigned int *class_id)
5328 5329 5330 5331 5332 5333
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5334
    if ((plug_ret = networkCheckBandwidth(obj, ifaceBand, NULL,
5335
                                          mac, &new_rate)) < 0) {
5336 5337 5338 5339 5340 5341 5342 5343 5344 5345
        /* helper reported error */
        goto cleanup;
    }

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

5346
    virMacAddrFormat(mac, ifmac);
5347

5348
    if (networkPlugBandwidthImpl(obj, mac, ifaceBand, class_id, new_rate) < 0)
5349 5350 5351
        goto cleanup;

    ret = 0;
5352

5353
 cleanup:
5354 5355 5356
    return ret;
}

5357

5358
static int
5359
networkUnplugBandwidth(virNetworkObjPtr obj,
5360 5361
                       virNetDevBandwidthPtr ifaceBand,
                       unsigned int *class_id)
5362
{
5363
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5364
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5365
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5366
    virNetworkDriverStatePtr driver = networkGetDriver();
5367 5368 5369
    int ret = 0;
    unsigned long long new_rate;

5370
    if (class_id && *class_id) {
5371
        if (!def->bandwidth || !def->bandwidth->in) {
5372
            VIR_WARN("Network %s has no bandwidth but unplug requested",
5373
                     def->name);
5374 5375
            goto cleanup;
        }
5376
        /* we must remove class from bridge */
5377
        new_rate = def->bandwidth->in->average;
5378

5379 5380
        if (def->bandwidth->in->peak > 0)
            new_rate = def->bandwidth->in->peak;
5381

5382
        ret = virNetDevBandwidthUnplug(def->bridge, *class_id);
5383 5384 5385
        if (ret < 0)
            goto cleanup;
        /* update sum of 'floor'-s of attached NICs */
5386 5387 5388
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);

5389
        /* return class ID */
5390
        ignore_value(virBitmapClearBit(classIdMap, *class_id));
5391
        /* update status file */
5392 5393
        if (virNetworkObjSaveStatus(driver->stateDir,
                                    obj, network_driver->xmlopt) < 0) {
5394 5395
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5396
            ignore_value(virBitmapSetBit(classIdMap, *class_id));
5397 5398
            goto cleanup;
        }
5399
        /* update rate for non guaranteed NICs */
5400
        new_rate -= tmp_floor_sum;
5401 5402
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0)
5403
            VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5404
                     def->bridge);
5405
        /* no class is associated any longer */
5406
        *class_id = 0;
5407 5408
    }

5409
 cleanup:
5410 5411
    return ret;
}
5412

5413

5414
static void
5415
networkNetworkObjTaint(virNetworkObjPtr obj,
5416
                       virNetworkTaintFlags taint)
5417
{
5418 5419
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

5420
    if (virNetworkObjTaint(obj, taint)) {
5421
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5422
        virUUIDFormat(def->uuid, uuidstr);
5423 5424

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5425
                 def->name, uuidstr, virNetworkTaintTypeToString(taint));
5426 5427
    }
}
5428 5429


5430
static int
5431 5432 5433 5434 5435
networkUpdatePortBandwidth(virNetworkObjPtr obj,
                           virMacAddrPtr mac,
                           unsigned int *class_id,
                           virNetDevBandwidthPtr oldBandwidth,
                           virNetDevBandwidthPtr newBandwidth)
5436 5437
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5438
    virNetworkDefPtr def;
5439
    unsigned long long tmp_floor_sum;
5440
    unsigned long long new_rate = 0;
5441
    unsigned long long old_floor, new_floor;
5442
    int plug_ret;
5443 5444 5445

    old_floor = new_floor = 0;

5446 5447
    if (oldBandwidth && oldBandwidth->in)
        old_floor = oldBandwidth->in->floor;
5448 5449 5450 5451
    if (newBandwidth && newBandwidth->in)
        new_floor = newBandwidth->in->floor;

    if (new_floor == old_floor)
5452 5453
        return 0;

5454
    def = virNetworkObjGetDef(obj);
5455

5456 5457
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, oldBandwidth,
                                          mac, &new_rate)) < 0) {
5458
        /* helper reported error */
5459
        return -1;
5460 5461 5462 5463
    }

    if (plug_ret > 0) {
        /* no QoS needs to be set; claim success */
5464
        return 0;
5465 5466 5467 5468
    }

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

5469
    if (oldBandwidth && oldBandwidth->in && oldBandwidth->in->floor &&
5470
        newBandwidth->in && newBandwidth->in->floor) {
5471 5472
        /* Either we just need to update @floor .. */

5473
        if (virNetDevBandwidthUpdateRate(def->bridge,
5474
                                         *class_id,
5475
                                         def->bandwidth,
5476
                                         newBandwidth->in->floor) < 0)
5477
            return -1;
5478

5479
        tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5480
        tmp_floor_sum -= oldBandwidth->in->floor;
5481 5482 5483
        tmp_floor_sum += newBandwidth->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
        new_rate -= tmp_floor_sum;
5484

5485 5486
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0 ||
5487 5488
            virNetworkObjSaveStatus(driver->stateDir,
                                    obj, network_driver->xmlopt) < 0) {
5489
            /* Ouch, rollback */
5490
            tmp_floor_sum -= newBandwidth->in->floor;
5491
            tmp_floor_sum += oldBandwidth->in->floor;
5492
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5493

5494
            ignore_value(virNetDevBandwidthUpdateRate(def->bridge,
5495
                                                      *class_id,
5496
                                                      def->bandwidth,
5497 5498
                                                      oldBandwidth->in->floor));
            return -1;
5499 5500 5501 5502
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5503 5504
        if (networkPlugBandwidthImpl(obj, mac, newBandwidth,
                                     class_id,
5505
                                     new_rate) < 0)
5506
            return -1;
5507 5508 5509
    } else {
        /* .. or unplug old. */

5510 5511
        if (networkUnplugBandwidth(obj, oldBandwidth, class_id) < 0)
            return -1;
5512 5513
    }

5514 5515 5516 5517
    return 0;
}


5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604
static virNetworkPortPtr
networkPortLookupByUUID(virNetworkPtr net,
                        const unsigned char *uuid)
{
    virNetworkObjPtr obj;
    virNetworkDefPtr def;
    virNetworkPortDefPtr portdef = NULL;
    virNetworkPortPtr ret = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virUUIDFormat(uuid, uuidstr);

    if (!(obj = networkObjFromNetwork(net)))
        return ret;

    def = virNetworkObjGetDef(obj);

    if (!(portdef = virNetworkObjLookupPort(obj, uuid)))
        goto cleanup;

    if (virNetworkPortLookupByUUIDEnsureACL(net->conn, def, portdef) < 0)
        goto cleanup;

    if (!virNetworkObjIsActive(obj)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       def->name);
        goto cleanup;
    }

    ret = virGetNetworkPort(net, uuid);

 cleanup:
    virNetworkObjEndAPI(&obj);
    return ret;
}


static virNetworkPortPtr
networkPortCreateXML(virNetworkPtr net,
                     const char *xmldesc,
                     unsigned int flags)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
    virNetworkObjPtr obj;
    virNetworkDefPtr def;
    virNetworkPortDefPtr portdef = NULL;
    virNetworkPortPtr ret = NULL;
    int rc;

    virCheckFlags(VIR_NETWORK_PORT_CREATE_RECLAIM, NULL);

    if (!(obj = networkObjFromNetwork(net)))
        return ret;

    def = virNetworkObjGetDef(obj);

    if (!(portdef = virNetworkPortDefParseString(xmldesc)))
        goto cleanup;

    if (virNetworkPortCreateXMLEnsureACL(net->conn, def, portdef) < 0)
        goto cleanup;

    if (!virNetworkObjIsActive(obj)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       def->name);
        goto cleanup;
    }

    if (portdef->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_NONE) {
        if (flags & VIR_NETWORK_PORT_CREATE_RECLAIM) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Port reclaim requested but plug type is none"));
            goto cleanup;
        }
    } else {
        if (!(flags & VIR_NETWORK_PORT_CREATE_RECLAIM)) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Port reclaim not requested but plug type is not none"));
            goto cleanup;
        }
    }

    if (flags & VIR_NETWORK_PORT_CREATE_RECLAIM)
        rc = networkNotifyPort(obj, portdef);
    else
        rc = networkAllocatePort(obj, portdef);
5605 5606 5607 5608
    if (rc < 0)
        goto cleanup;

    if (virNetworkObjAddPort(obj, portdef, driver->stateDir) < 0) {
5609
        virErrorPtr save_err;
5610

5611
        virErrorPreserveLast(&save_err);
5612
        ignore_value(networkReleasePort(obj, portdef));
5613
        virNetworkPortDefFree(portdef);
5614 5615
        virErrorRestore(&save_err);

5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905
        goto cleanup;
    }

    ret = virGetNetworkPort(net, portdef->uuid);
 cleanup:
    virNetworkObjEndAPI(&obj);
    return ret;
}


static char *
networkPortGetXMLDesc(virNetworkPortPtr port,
                      unsigned int flags)
{
    virNetworkObjPtr obj;
    virNetworkDefPtr def;
    virNetworkPortDefPtr portdef = NULL;
    char *ret = NULL;

    virCheckFlags(0, NULL);

    if (!(obj = networkObjFromNetwork(port->net)))
        return ret;

    def = virNetworkObjGetDef(obj);

    if (!(portdef = virNetworkObjLookupPort(obj, port->uuid)))
        goto cleanup;

    if (virNetworkPortGetXMLDescEnsureACL(port->net->conn, def, portdef) < 0)
        goto cleanup;

    if (!virNetworkObjIsActive(obj)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       def->name);
        goto cleanup;
    }

   if (!(ret = virNetworkPortDefFormat(portdef)))
       goto cleanup;

 cleanup:
    virNetworkObjEndAPI(&obj);
    return ret;
}


static int
networkPortDelete(virNetworkPortPtr port,
                  unsigned int flags)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
    virNetworkObjPtr obj;
    virNetworkDefPtr def;
    virNetworkPortDefPtr portdef;
    int ret = -1;

    virCheckFlags(0, -1);

    if (!(obj = networkObjFromNetwork(port->net)))
        return ret;

    def = virNetworkObjGetDef(obj);

    if (!(portdef = virNetworkObjLookupPort(obj, port->uuid)))
        goto cleanup;

    if (virNetworkPortDeleteEnsureACL(port->net->conn, def, portdef) < 0)
        goto cleanup;

    if (!virNetworkObjIsActive(obj)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       def->name);
        goto cleanup;
    }

    if (networkReleasePort(obj, portdef) < 0)
        goto cleanup;

    virNetworkObjDeletePort(obj, port->uuid, driver->stateDir);

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


static int
networkPortSetParameters(virNetworkPortPtr port,
                         virTypedParameterPtr params,
                         int nparams,
                         unsigned int flags)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
    virNetworkObjPtr obj;
    virNetworkDefPtr def;
    virNetworkPortDefPtr portdef;
    virNetDevBandwidthPtr bandwidth = NULL;
    char *dir = NULL;
    int ret = -1;
    size_t i;

    virCheckFlags(0, -1);

    if (!(obj = networkObjFromNetwork(port->net)))
        return ret;

    def = virNetworkObjGetDef(obj);

    if (!(portdef = virNetworkObjLookupPort(obj, port->uuid)))
        goto cleanup;

    if (virNetworkPortSetParametersEnsureACL(port->net->conn, def, portdef) < 0)
        goto cleanup;

    if (!virNetworkObjIsActive(obj)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       def->name);
        goto cleanup;
    }

    if (!(dir = virNetworkObjGetPortStatusDir(obj, driver->stateDir)))
        goto cleanup;

    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
        (VIR_ALLOC(bandwidth->out) < 0))
        goto cleanup;

    for (i = 0; i < nparams; i++) {
        virTypedParameterPtr param = &params[i];

        if (STREQ(param->field, VIR_NETWORK_PORT_BANDWIDTH_IN_AVERAGE)) {
            bandwidth->in->average = param->value.ui;
        } else if (STREQ(param->field, VIR_NETWORK_PORT_BANDWIDTH_IN_PEAK)) {
            bandwidth->in->peak = param->value.ui;
        } else if (STREQ(param->field, VIR_NETWORK_PORT_BANDWIDTH_IN_BURST)) {
            bandwidth->in->burst = param->value.ui;
        } else if (STREQ(param->field, VIR_NETWORK_PORT_BANDWIDTH_IN_FLOOR)) {
            bandwidth->in->floor = param->value.ui;
        } else if (STREQ(param->field, VIR_NETWORK_PORT_BANDWIDTH_OUT_AVERAGE)) {
            bandwidth->out->average = param->value.ui;
        } else if (STREQ(param->field, VIR_NETWORK_PORT_BANDWIDTH_OUT_PEAK)) {
            bandwidth->out->peak = param->value.ui;
        } else if (STREQ(param->field, VIR_NETWORK_PORT_BANDWIDTH_OUT_BURST)) {
            bandwidth->out->burst = param->value.ui;
        }
    }

    /* average or floor are mandatory, peak and burst are optional.
     * So if no average or floor is given, we free inbound/outbound
     * here which causes inbound/outbound to not be set. */
    if (!bandwidth->in->average && !bandwidth->in->floor)
        VIR_FREE(bandwidth->in);
    if (!bandwidth->out->average)
        VIR_FREE(bandwidth->out);

    if (networkUpdatePortBandwidth(obj,
                                   &portdef->mac,
                                   &portdef->class_id,
                                   portdef->bandwidth,
                                   bandwidth) < 0)
        goto cleanup;

    virNetDevBandwidthFree(portdef->bandwidth);
    portdef->bandwidth = bandwidth;
    bandwidth = NULL;

    if (virNetworkPortDefSaveStatus(portdef, dir) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    virNetDevBandwidthFree(bandwidth);
    virNetworkObjEndAPI(&obj);
    VIR_FREE(dir);
    return ret;
}


static int
networkPortGetParameters(virNetworkPortPtr port,
                         virTypedParameterPtr *params,
                         int *nparams,
                         unsigned int flags)
{
    virNetworkObjPtr obj;
    virNetworkDefPtr def;
    virNetworkPortDefPtr portdef;
    int maxparams = 0;
    int ret = -1;

    virCheckFlags(0, -1);

    *params = NULL;
    *nparams = 0;

    if (!(obj = networkObjFromNetwork(port->net)))
        return ret;

    def = virNetworkObjGetDef(obj);

    if (!(portdef = virNetworkObjLookupPort(obj, port->uuid)))
        goto cleanup;

    if (virNetworkPortGetParametersEnsureACL(port->net->conn, def, portdef) < 0)
        goto cleanup;

    if (!virNetworkObjIsActive(obj)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       def->name);
        goto cleanup;
    }

    if (portdef->bandwidth) {
        if ((portdef->bandwidth->in != NULL) &&
            (virTypedParamsAddUInt(params, nparams, &maxparams,
                                   VIR_NETWORK_PORT_BANDWIDTH_IN_AVERAGE,
                                   portdef->bandwidth->in->average) < 0 ||
             virTypedParamsAddUInt(params, nparams, &maxparams,
                                   VIR_NETWORK_PORT_BANDWIDTH_IN_PEAK,
                                   portdef->bandwidth->in->peak) < 0 ||
             virTypedParamsAddUInt(params, nparams, &maxparams,
                                   VIR_NETWORK_PORT_BANDWIDTH_IN_FLOOR,
                                   portdef->bandwidth->in->floor) < 0 ||
             virTypedParamsAddUInt(params, nparams, &maxparams,
                                   VIR_NETWORK_PORT_BANDWIDTH_IN_BURST,
                                   portdef->bandwidth->in->burst) < 0))
            goto cleanup;

        if ((portdef->bandwidth->out != NULL) &&
            (virTypedParamsAddUInt(params, nparams, &maxparams,
                                   VIR_NETWORK_PORT_BANDWIDTH_OUT_AVERAGE,
                                   portdef->bandwidth->out->average) < 0 ||
             virTypedParamsAddUInt(params, nparams, &maxparams,
                                   VIR_NETWORK_PORT_BANDWIDTH_OUT_PEAK,
                                   portdef->bandwidth->out->peak) < 0 ||
             virTypedParamsAddUInt(params, nparams, &maxparams,
                                   VIR_NETWORK_PORT_BANDWIDTH_OUT_BURST,
                                   portdef->bandwidth->out->burst) < 0))
            goto cleanup;
    }

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


static int
networkListAllPorts(virNetworkPtr net,
                    virNetworkPortPtr **ports,
                    unsigned int flags)
{
    virNetworkObjPtr obj;
    virNetworkDefPtr def;
    int ret = -1;

    virCheckFlags(0, -1);

    if (!(obj = networkObjFromNetwork(net)))
        return ret;

    def = virNetworkObjGetDef(obj);

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

    if (!virNetworkObjIsActive(obj)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       def->name);
        goto cleanup;
    }

    ret = virNetworkObjPortListExport(net, obj, ports,
                                      virNetworkListAllPortsCheckACL);

 cleanup:
    virNetworkObjEndAPI(&obj);
    return ret;
}


5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929
static virNetworkDriver networkDriver = {
    .name = "bridge",
    .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 */
    .connectNetworkEventRegisterAny = networkConnectNetworkEventRegisterAny, /* 1.2.1 */
    .connectNetworkEventDeregisterAny = networkConnectNetworkEventDeregisterAny, /* 1.2.1 */
    .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
    .networkLookupByName = networkLookupByName, /* 0.2.0 */
    .networkCreateXML = networkCreateXML, /* 0.2.0 */
    .networkDefineXML = networkDefineXML, /* 0.2.0 */
    .networkUndefine = networkUndefine, /* 0.2.0 */
    .networkUpdate = networkUpdate, /* 0.10.2 */
    .networkCreate = networkCreate, /* 0.2.0 */
    .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 */
    .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.2.6 */
5930 5931 5932 5933 5934 5935 5936
    .networkPortLookupByUUID = networkPortLookupByUUID, /* 5.5.0 */
    .networkPortCreateXML = networkPortCreateXML, /* 5.5.0 */
    .networkPortGetXMLDesc = networkPortGetXMLDesc, /* 5.5.0 */
    .networkPortDelete = networkPortDelete, /* 5.5.0 */
    .networkListAllPorts = networkListAllPorts, /* 5.5.0 */
    .networkPortGetParameters = networkPortGetParameters, /* 5.5.0 */
    .networkPortSetParameters = networkPortSetParameters, /* 5.5.0 */
5937 5938
};

5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950

static virHypervisorDriver networkHypervisorDriver = {
    .name = "network",
    .connectOpen = networkConnectOpen, /* 4.1.0 */
    .connectClose = networkConnectClose, /* 4.1.0 */
    .connectIsEncrypted = networkConnectIsEncrypted, /* 4.1.0 */
    .connectIsSecure = networkConnectIsSecure, /* 4.1.0 */
    .connectIsAlive = networkConnectIsAlive, /* 4.1.0 */
};


static virConnectDriver networkConnectDriver = {
5951
    .localOnly = true,
5952
    .uriSchemes = (const char *[]){ "network", NULL },
5953 5954 5955 5956 5957
    .hypervisorDriver = &networkHypervisorDriver,
    .networkDriver = &networkDriver,
};


5958 5959 5960 5961 5962 5963 5964 5965 5966 5967
static virStateDriver networkStateDriver = {
    .name = "bridge",
    .stateInitialize  = networkStateInitialize,
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
};

int
networkRegister(void)
{
5968 5969
    if (virRegisterConnectDriver(&networkConnectDriver, false) < 0)
        return -1;
5970 5971 5972 5973 5974 5975
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
    return 0;
}