bridge_driver.c 190.7 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
static DBusHandlerResult
J
Ján Tomko 已提交
665
firewalld_dbus_filter_bridge(DBusConnection *connection G_GNUC_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
networkStateInitialize(bool privileged,
J
Ján Tomko 已提交
712 713
                       virStateInhibitCallback callback G_GNUC_UNUSED,
                       void *opaque G_GNUC_UNUSED)
714
{
715
    int ret = VIR_DRV_STATE_INIT_ERROR;
716 717
    char *configdir = NULL;
    char *rundir = NULL;
718
    bool autostart = true;
719
#ifdef WITH_FIREWALLD
720 721
    DBusConnection *sysbus = NULL;
#endif
722

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

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

732 733
    network_driver->privileged = privileged;

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

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

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

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

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

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

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

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

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

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

819 820 821 822 823 824 825 826
    if (virDriverShouldAutostart(network_driver->stateDir, &autostart) < 0)
        goto error;

    if (autostart) {
        virNetworkObjListForEach(network_driver->networks,
                                 networkAutostartConfig,
                                 network_driver);
    }
827

828
    network_driver->networkEventState = virObjectEventStateNew();
829

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

855
    ret = VIR_DRV_STATE_INIT_COMPLETE;
856
 cleanup:
857 858 859
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
860

861
 error:
862
    networkStateCleanup();
863
    goto cleanup;
864 865
}

866

867
/**
868
 * networkStateReload:
869
 *
J
Ján Tomko 已提交
870
 * Function to restart the QEMU daemon, it will recheck the configuration
871 872 873
 * files and update its state and the networking
 */
static int
874 875
networkStateReload(void)
{
876
    if (!network_driver)
877 878
        return 0;

879
    virNetworkObjLoadAllState(network_driver->networks,
880 881
                              network_driver->stateDir,
                              network_driver->xmlopt);
882 883
    virNetworkObjLoadAllConfigs(network_driver->networks,
                                network_driver->networkConfigDir,
884 885
                                network_driver->networkAutostartDir,
                                network_driver->xmlopt);
886
    networkReloadFirewallRules(network_driver, false);
887 888
    networkRefreshDaemons(network_driver);
    virNetworkObjListForEach(network_driver->networks,
889
                             networkAutostartConfig,
890
                             network_driver);
891 892 893 894 895
    return 0;
}


/**
896
 * networkStateCleanup:
897
 *
J
Ján Tomko 已提交
898
 * Shutdown the QEMU daemon, it will stop all active domains and networks
899 900
 */
static int
901 902
networkStateCleanup(void)
{
903
    if (!network_driver)
904 905
        return -1;

906
    virObjectUnref(network_driver->networkEventState);
C
Cole Robinson 已提交
907
    virObjectUnref(network_driver->xmlopt);
908

909
    /* free inactive networks */
910
    virObjectUnref(network_driver->networks);
911

912 913 914 915
    if (network_driver->lockFD != -1)
        virPidFileRelease(network_driver->stateDir, "driver",
                          network_driver->lockFD);

916 917 918 919 920 921
    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);
922

923
    virObjectUnref(network_driver->dnsmasqCaps);
924

925
    virMutexDestroy(&network_driver->lock);
926

927
    VIR_FREE(network_driver);
928 929 930 931 932

    return 0;
}


933 934
static virDrvOpenStatus
networkConnectOpen(virConnectPtr conn,
J
Ján Tomko 已提交
935 936
                   virConnectAuthPtr auth G_GNUC_UNUSED,
                   virConfPtr conf G_GNUC_UNUSED,
937 938 939 940
                   unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

941 942 943 944 945 946
    if (network_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("network state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
    }

947 948 949 950
    if (!virConnectValidateURIPath(conn->uri->path,
                                   "network",
                                   network_driver->privileged))
        return VIR_DRV_OPEN_ERROR;
951 952 953 954 955 956 957

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

    return VIR_DRV_OPEN_SUCCESS;
}

J
Ján Tomko 已提交
958
static int networkConnectClose(virConnectPtr conn G_GNUC_UNUSED)
959 960 961 962 963
{
    return 0;
}


J
Ján Tomko 已提交
964
static int networkConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)
965 966 967 968 969 970
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


J
Ján Tomko 已提交
971
static int networkConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)
972 973 974 975 976 977
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


J
Ján Tomko 已提交
978
static int networkConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
979 980 981 982 983
{
    return 1;
}


984 985 986 987 988
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
989 990 991
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
992
{
993 994
    size_t i;
    int ret = -1;
995 996 997 998 999 1000 1001
    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.
     */
1002
    for (i = 0; i < 25; i++) {
1003
        int signum = 0;
1004
        if (i == 0) {
1005
            signum = SIGTERM;
1006
        } else if (i == 15) {
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 1036
            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.
         */
1037
        g_usleep(20 * 1000);
1038 1039 1040 1041
    }
    VIR_WARN("Timed out waiting after SIG%s to %s process %d "
             "(network '%s')",
             signame, daemonName, pid, networkName);
1042
 cleanup:
1043 1044 1045
    return ret;
}

1046

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

G
Gene Czarcinski 已提交
1057 1058
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
1059 1060
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
1061
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
1062 1063
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
1064
                return -1;
1065
    }
1066

G
Gene Czarcinski 已提交
1067 1068 1069
    return 0;
}

1070

G
Gene Czarcinski 已提交
1071 1072 1073 1074
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
1075
    size_t i, j;
G
Gene Czarcinski 已提交
1076

1077 1078
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
1079
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
1080
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
1081
                for (j = 0; j < host->nnames; j++)
1082 1083
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
1084 1085
            }
        }
1086 1087
    }

1088
    return 0;
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 1123 1124 1125 1126 1127 1128
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;
}


1129
int
1130
networkDnsmasqConfContents(virNetworkObjPtr obj,
1131 1132 1133
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
J
Ján Tomko 已提交
1134
                           dnsmasqCapsPtr caps G_GNUC_UNUSED)
1135
{
1136
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1137
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1138
    int r, ret = -1;
1139
    int nbleases = 0;
1140
    size_t i;
1141
    virNetworkDNSDefPtr dns = &def->dns;
1142
    bool wantDNS = dns->enable != VIR_TRISTATE_BOOL_NO;
1143
    virNetworkIPDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
G
Gene Czarcinski 已提交
1144
    bool ipv6SLAAC;
1145
    char *saddr = NULL, *eaddr = NULL;
1146

1147 1148
    *configstr = NULL;

1149
    /*
1150 1151 1152
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1153
     *
1154 1155
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1156
     */
1157 1158 1159 1160 1161 1162

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

1163
    /* create dnsmasq config file appropriate for this network */
1164 1165

    /* Don't forget to update networkxml2conftest :-) */
1166
    virBufferAsprintf(&configbuf,
1167 1168 1169 1170 1171 1172 1173
                      "##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"
1174
                      "strict-order\n",
1175
                      def->name);
1176

1177 1178 1179 1180 1181 1182
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1183
    if (wantDNS && def->dns.forwarders) {
1184 1185 1186 1187 1188 1189 1190 1191 1192
        /* 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;

1193 1194
        for (i = 0; i < def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &def->dns.forwarders[i];
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204

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

1217 1218
    if (def->domain) {
        if (def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1219 1220
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1221
                              def->domain);
1222
        }
1223
        virBufferAsprintf(&configbuf,
1224 1225
                          "domain=%s\n"
                          "expand-hosts\n",
1226
                          def->domain);
1227
    }
1228

1229
    if (wantDNS &&
1230
        networkDnsmasqConfLocalPTRs(&configbuf, def) < 0)
1231 1232
        goto cleanup;

1233
    if (wantDNS && def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1234 1235 1236 1237
        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)
1238
         */
1239
        virBufferAddLit(&configbuf, "local=//\n");
1240
    }
1241

1242
    if (pidfile)
1243
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1244

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

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

            if (!ipaddr)
                goto cleanup;
1282

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

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

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

1331 1332 1333 1334 1335
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1336
        }
1337

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

1362 1363 1364 1365 1366 1367 1368
            /* 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.
1369
             */
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389
            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");
1390
        }
1391 1392
    }

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

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1451 1452
        int prefix;

1453
        prefix = virNetworkIPDefPrefix(ipdef);
1454 1455 1456
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1457
                           def->bridge);
1458 1459
            goto cleanup;
        }
1460
        for (r = 0; r < ipdef->nranges; r++) {
1461 1462
            int thisRange;

1463 1464
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1465
                goto cleanup;
1466

1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
            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);
            }
1488

1489
            VIR_FREE(saddr);
1490
            VIR_FREE(eaddr);
1491
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1492 1493
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1494
                                              virNetworkIPDefPrefix(ipdef));
1495 1496 1497
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1498
        }
1499

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

G
Gene Czarcinski 已提交
1518 1519
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1520

G
Gene Czarcinski 已提交
1521 1522
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
1523
            if (ipdef->nranges || ipdef->nhosts) {
1524
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1525 1526
                virBufferAddLit(&configbuf, "dhcp-authoritative\n");
            }
1527

G
Gene Czarcinski 已提交
1528
            if (ipdef->tftproot) {
1529 1530
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1531
            }
1532

G
Gene Czarcinski 已提交
1533 1534 1535
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1536

1537
                    if (!bootserver)
G
Gene Czarcinski 已提交
1538
                        goto cleanup;
1539
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1540
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1541 1542
                    VIR_FREE(bootserver);
                } else {
1543
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1544 1545 1546 1547 1548
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1549

1550
    if (nbleases > 0)
1551
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1552

G
Gene Czarcinski 已提交
1553 1554
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1555
        goto cleanup;
G
Gene Czarcinski 已提交
1556 1557 1558 1559 1560 1561

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

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

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

1597 1598 1599 1600 1601 1602
    if (def->namespaceData) {
        networkDnsmasqXmlNsDefPtr dnsmasqxmlns = def->namespaceData;
        for (i = 0; i < dnsmasqxmlns->noptions; i++)
            virBufferAsprintf(&configbuf, "%s\n", dnsmasqxmlns->options[i]);
    }

1603 1604 1605
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1606
    ret = 0;
G
Gene Czarcinski 已提交
1607

1608
 cleanup:
1609 1610
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1611
    virBufferFreeAndReset(&configbuf);
1612
    return ret;
1613 1614
}

1615

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

1632
    virNetworkObjSetDnsmasqPid(obj, -1);
1633

1634
    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
1635
                                   dctx, dnsmasq_caps) < 0)
1636 1637 1638 1639 1640
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1641
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
1642 1643 1644 1645 1646
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1647 1648
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1649 1650 1651
        goto cleanup;
    }

1652 1653
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1654
                                                  abs_top_builddir "/src",
1655 1656 1657
                                                  LIBEXECDIR)))
        goto cleanup;

1658
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1659
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1660 1661
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1662
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1663
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", def->bridge);
1664

1665
    *cmdout = cmd;
1666
    ret = 0;
1667
 cleanup:
1668
    virObjectUnref(dnsmasq_caps);
1669 1670
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1671
    VIR_FREE(leaseshelper_path);
1672 1673 1674
    return ret;
}

1675

1676
static int
1677
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1678
                       virNetworkObjPtr obj)
1679
{
1680
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1681 1682 1683
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1684 1685
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
1686
    pid_t dnsmasqPid;
1687
    int ret = -1;
1688
    dnsmasqContext *dctx = NULL;
1689

1690
    /* see if there are any IP addresses that need a dhcp server */
1691
    i = 0;
1692
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i))) {
1693
        i++;
1694 1695 1696 1697
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1698 1699 1700 1701 1702 1703
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1704
    if (!needDnsmasq && def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1705
        /* no DHCP services needed, and user disabled DNS service */
1706 1707 1708 1709
        ret = 0;
        goto cleanup;
    }

1710
    if (virFileMakePath(driver->pidDir) < 0) {
1711
        virReportSystemError(errno,
1712
                             _("cannot create directory %s"),
1713
                             driver->pidDir);
1714
        goto cleanup;
1715 1716
    }

1717
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, def->name)))
1718
        goto cleanup;
1719

1720
    if (virFileMakePath(driver->dnsmasqStateDir) < 0) {
1721
        virReportSystemError(errno,
1722
                             _("cannot create directory %s"),
1723
                             driver->dnsmasqStateDir);
1724 1725 1726
        goto cleanup;
    }

1727
    dctx = dnsmasqContextNew(def->name, driver->dnsmasqStateDir);
1728 1729 1730
    if (dctx == NULL)
        goto cleanup;

1731
    if (networkDnsmasqCapsRefresh(driver) < 0)
1732
        goto cleanup;
1733

1734
    ret = networkBuildDhcpDaemonCommandLine(driver, obj, &cmd, pidfile, dctx);
1735 1736 1737 1738 1739
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1740
        goto cleanup;
1741

G
Guido Günther 已提交
1742
    ret = virCommandRun(cmd, NULL);
1743
    if (ret < 0)
1744 1745 1746
        goto cleanup;

    /*
1747 1748 1749 1750 1751
     * 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
1752 1753
     */

1754
    ret = virPidFileRead(driver->pidDir, def->name, &dnsmasqPid);
1755
    if (ret < 0)
1756
        goto cleanup;
1757
    virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
1758

1759
    ret = 0;
1760
 cleanup:
1761
    VIR_FREE(pidfile);
1762
    virCommandFree(cmd);
1763
    dnsmasqContextFree(dctx);
1764 1765 1766
    return ret;
}

1767

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

G
Gene Czarcinski 已提交
1786
    /* if no IP addresses specified, nothing to do */
1787
    if (!virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1788 1789
        return 0;

1790
    /* if there's no running dnsmasq, just start it */
1791 1792
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid <= 0 || (kill(dnsmasqPid, 0) < 0))
1793
        return networkStartDhcpDaemon(driver, obj);
1794

1795 1796
    VIR_INFO("Refreshing dnsmasq for network %s", def->bridge);
    if (!(dctx = dnsmasqContextNew(def->name,
1797
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1798
        goto cleanup;
1799
    }
G
Gene Czarcinski 已提交
1800 1801 1802 1803 1804 1805

    /* 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;
1806
    for (i = 0;
1807
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
1808
         i++) {
G
Gene Czarcinski 已提交
1809 1810
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1811 1812
    }

G
Gene Czarcinski 已提交
1813
    ipv6def = NULL;
1814
    for (i = 0;
1815
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1816
         i++) {
G
Gene Czarcinski 已提交
1817 1818
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1819 1820
    }

G
Gene Czarcinski 已提交
1821
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1822
        goto cleanup;
G
Gene Czarcinski 已提交
1823 1824

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

1827
    if (networkBuildDnsmasqHostsList(dctx, &def->dns) < 0)
J
Ján Tomko 已提交
1828
        goto cleanup;
1829 1830

    if ((ret = dnsmasqSave(dctx)) < 0)
1831
        goto cleanup;
1832

1833 1834
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    ret = kill(dnsmasqPid, SIGHUP);
1835
 cleanup:
1836 1837 1838 1839
    dnsmasqContextFree(dctx);
    return ret;
}

1840

1841 1842 1843 1844 1845 1846 1847 1848
/* 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
1849
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1850
                         virNetworkObjPtr obj)
1851
{
1852
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1853 1854
    pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);

1855
    /* if there is a running dnsmasq, kill it */
1856
    if (dnsmasqPid > 0) {
1857
        networkKillDaemon(dnsmasqPid, "dnsmasq", def->name);
1858
        virNetworkObjSetDnsmasqPid(obj, -1);
1859
    }
1860
    /* now start dnsmasq if it should be started */
1861
    return networkStartDhcpDaemon(driver, obj);
1862 1863
}

1864

G
Gene Czarcinski 已提交
1865 1866 1867 1868 1869 1870
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";

1871
static int
1872
networkRadvdConfContents(virNetworkObjPtr obj,
1873
                         char **configstr)
1874
{
1875
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
E
Eric Blake 已提交
1876
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1877 1878
    int ret = -1;
    size_t i;
1879
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1880
    bool v6present = false, dhcp6 = false;
1881 1882

    *configstr = NULL;
1883

G
Gene Czarcinski 已提交
1884
    /* Check if DHCPv6 is needed */
1885
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
G
Gene Czarcinski 已提交
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898
        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;
    }

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

    /* add a section for each IPv6 address in the config */
1913
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
1914 1915 1916
        int prefix;
        char *netaddr;

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

1934
    virBufferAddLit(&configbuf, "};\n");
1935

1936
    if (virBufferCheckError(&configbuf) < 0)
1937
        goto cleanup;
1938

1939 1940
    *configstr = virBufferContentAndReset(&configbuf);

1941
    ret = 0;
1942
 cleanup:
1943 1944 1945 1946
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1947

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

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

1964
    if (networkRadvdConfContents(obj, &configStr) < 0)
1965 1966 1967 1968
        goto cleanup;

    if (!configStr) {
        ret = 0;
1969 1970 1971 1972
        goto cleanup;
    }

    /* construct the filename */
1973
    if (!(*configFile = networkRadvdConfigFileName(driver, def->name)))
1974 1975
        goto cleanup;
    /* write the file */
1976
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1977 1978
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1979 1980 1981 1982 1983
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1984
 cleanup:
1985 1986 1987 1988 1989
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

1990

1991
static int
1992
networkStartRadvd(virNetworkDriverStatePtr driver,
1993
                  virNetworkObjPtr obj)
1994
{
1995
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1996
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1997
    pid_t radvdPid;
1998 1999 2000 2001 2002 2003
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

2004
    virNetworkObjSetRadvdPid(obj, -1);
2005

G
Gene Czarcinski 已提交
2006
    /* Is dnsmasq handling RA? */
2007
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
2008 2009 2010 2011
        ret = 0;
        goto cleanup;
    }

2012
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2013 2014 2015 2016 2017 2018 2019 2020 2021 2022
        /* 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);
2023 2024 2025
        goto cleanup;
    }

2026
    if (virFileMakePath(driver->pidDir) < 0) {
2027 2028
        virReportSystemError(errno,
                             _("cannot create directory %s"),
2029
                             driver->pidDir);
2030 2031
        goto cleanup;
    }
2032
    if (virFileMakePath(driver->radvdStateDir) < 0) {
2033 2034
        virReportSystemError(errno,
                             _("cannot create directory %s"),
2035
                             driver->radvdStateDir);
2036 2037 2038 2039
        goto cleanup;
    }

    /* construct pidfile name */
2040
    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
2041
        goto cleanup;
2042
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
2043 2044
        goto cleanup;

2045
    if (networkRadvdConfWrite(driver, obj, &configfile) < 0)
2046 2047
        goto cleanup;

2048 2049 2050 2051
    /* 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
2052
     * virPidFileRead() below will fail if we use them).
2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067
     * 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;

2068
    if (virPidFileRead(driver->pidDir, radvdpidbase, &radvdPid) < 0)
2069
        goto cleanup;
2070
    virNetworkObjSetRadvdPid(obj, radvdPid);
2071 2072

    ret = 0;
2073
 cleanup:
2074
    virObjectUnref(dnsmasq_caps);
2075 2076 2077 2078 2079 2080 2081
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

2082

2083
static int
2084
networkRefreshRadvd(virNetworkDriverStatePtr driver,
2085
                    virNetworkObjPtr obj)
2086
{
2087
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2088
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
2089
    char *radvdpidbase;
2090
    pid_t radvdPid;
G
Gene Czarcinski 已提交
2091 2092

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

2110
    /* if there's no running radvd, just start it */
2111 2112
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid <= 0 || (kill(radvdPid, 0) < 0))
2113
        return networkStartRadvd(driver, obj);
2114

2115
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2116 2117 2118 2119
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

2120
    if (networkRadvdConfWrite(driver, obj, NULL) < 0)
2121 2122
        return -1;

2123
    return kill(radvdPid, SIGHUP);
2124 2125
}

2126

2127 2128
#if 0
/* currently unused, so it causes a build error unless we #if it out */
2129
static int
2130
networkRestartRadvd(virNetworkObjPtr obj)
2131
{
2132
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2133
    char *radvdpidbase;
2134
    pid_t radvdPid = virNeworkObjGetRadvdPid(obj);
2135 2136

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

2155

2156
static int
2157
networkRefreshDaemonsHelper(virNetworkObjPtr obj,
2158
                            void *opaque)
2159
{
2160
    virNetworkDefPtr def;
2161
    virNetworkDriverStatePtr driver = opaque;
2162

2163
    virObjectLock(obj);
2164
    def = virNetworkObjGetDef(obj);
2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
    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;
        }
2193
    }
2194 2195

 cleanup:
2196
    virObjectUnlock(obj);
2197 2198 2199
    return 0;
}

2200

2201 2202 2203 2204
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2205
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2206 2207
{
    VIR_INFO("Refreshing network daemons");
2208 2209
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2210
                             driver);
2211
}
2212

2213

2214
static int
2215
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
J
Ján Tomko 已提交
2216
                                 void *opaque G_GNUC_UNUSED)
2217
{
2218
    virNetworkDefPtr def;
2219

2220
    virObjectLock(obj);
2221
    def = virNetworkObjGetDef(obj);
2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247
    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;
2248 2249
        }
    }
2250 2251

 cleanup:
2252
    virObjectUnlock(obj);
2253
    return 0;
2254 2255
}

2256

2257
static void
2258
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup)
2259
{
2260
    VIR_INFO("Reloading iptables rules");
2261 2262 2263 2264
    /* 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;
2265
    networkPreReloadFirewallRules(driver, startup);
2266 2267 2268
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2269
    networkPostReloadFirewallRules(startup);
2270 2271
}

2272

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

2293
#endif
2294
    return ret;
2295 2296
}

2297

2298
static int
2299
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2300
{
2301
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2302 2303
    char *field = NULL;
    int ret = -1;
2304
    bool enableIPv6 = !!virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2305

2306 2307 2308 2309 2310
    /* 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",
2311
                    def->bridge) < 0)
2312
       goto cleanup;
2313

2314 2315
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2316
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2317
                      def->bridge);
2318 2319 2320
        ret = 0;
        goto cleanup;
    }
2321

2322 2323 2324
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2325
                               "on bridge %s"), field, def->bridge);
2326
        goto cleanup;
2327
    }
2328
    VIR_FREE(field);
2329

2330 2331
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2332 2333 2334 2335 2336 2337
     */

    /* 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",
2338
                    def->bridge) < 0)
2339 2340
        goto cleanup;

2341
    if (virFileWriteStr(field, "0", 0) < 0) {
2342
        virReportSystemError(errno,
2343 2344 2345 2346 2347
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

2348 2349 2350 2351
    /* 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",
2352
                    def->bridge) < 0)
2353 2354
        goto cleanup;

2355
    if (virFileWriteStr(field, "0", 0) < 0) {
2356
        virReportSystemError(errno,
2357
                             _("cannot disable %s"), field);
2358 2359 2360 2361
        goto cleanup;
    }

    ret = 0;
2362
 cleanup:
2363 2364 2365 2366
    VIR_FREE(field);
    return ret;
}

2367

2368
/* add an IP address to a bridge */
2369
static int
2370
networkAddAddrToBridge(virNetworkObjPtr obj,
2371
                       virNetworkIPDefPtr ipdef)
2372
{
2373
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2374
    int prefix = virNetworkIPDefPrefix(ipdef);
2375 2376

    if (prefix < 0) {
2377 2378
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2379
                       def->bridge);
2380 2381 2382
        return -1;
    }

2383
    if (virNetDevIPAddrAdd(def->bridge, &ipdef->address, NULL, prefix) < 0)
2384 2385 2386 2387 2388
        return -1;

    return 0;
}

2389 2390

static int
2391
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2392 2393
                                      const char *macTapIfName)
{
2394 2395
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    const char *brname = def->bridge;
2396 2397

    if (brname &&
2398
        def->macTableManager == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411
        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;
}


2412 2413
/* add an IP (static) route to a bridge */
static int
2414
networkAddRouteToBridge(virNetworkObjPtr obj,
2415
                        virNetDevIPRoutePtr routedef)
2416
{
2417
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2418 2419 2420 2421
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2422 2423 2424 2425 2426

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

2431
    if (virNetDevIPRouteAdd(def->bridge, addr, prefix, gateway, metric) < 0)
2432
        return -1;
2433

2434 2435 2436
    return 0;
}

2437
static int
2438
networkWaitDadFinish(virNetworkObjPtr obj)
2439
{
2440
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2441
    virNetworkIPDefPtr ipdef;
2442 2443 2444 2445
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

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

2448
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, naddrs))) {
2449 2450 2451 2452 2453
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2454
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2455 2456 2457 2458

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

2463

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

2482
    /* Check to see if any network IP collides with an existing route */
2483
    if (networkCheckRouteCollision(def) < 0)
2484 2485
        return -1;

2486
    /* Create and configure the bridge device */
2487
    if (!def->bridge) {
2488 2489 2490 2491 2492 2493 2494 2495 2496 2497
        /* 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"),
2498
                       def->name);
2499 2500
        return -1;
    }
2501
    if (virNetDevBridgeCreate(def->bridge) < 0)
2502 2503
        return -1;

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

2527
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
2528
                                         def->bridge)) ||
2529
        !(macmap = virMacMapNew(macMapFile)))
2530
        goto error;
M
Michal Privoznik 已提交
2531

2532
    virNetworkObjSetMacMap(obj, macmap);
2533
    macmap = NULL;
2534

2535
    /* Set bridge options */
2536 2537 2538 2539

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

2543
    if (virNetDevBridgeSetSTP(def->bridge, def->stp ? true : false) < 0)
2544
        goto error;
2545

2546 2547 2548
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2549
    if (networkSetIPv6Sysctls(obj) < 0)
2550
        goto error;
2551

2552
    /* Add "once per network" rules */
2553 2554
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(def) < 0)
2555
        goto error;
2556

2557 2558
    firewalRulesAdded = true;

2559
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i)); i++) {
2560
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2561
            v4present = true;
2562
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2563
            v6present = true;
2564

2565
        /* Add the IP address/netmask to the bridge */
2566
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2567
            goto error;
2568 2569
    }

2570
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2571
        goto error;
2572

2573
    /* Bring up the bridge interface */
2574
    if (virNetDevSetOnline(def->bridge, 1) < 0)
2575
        goto error;
2576

2577 2578
    devOnline = true;

2579
    for (i = 0; i < def->nroutes; i++) {
2580 2581
        virSocketAddrPtr gateway = NULL;

2582
        routedef = def->routes[i];
2583
        gateway = virNetDevIPRouteGetGateway(routedef);
2584

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

2596
    /* If forward.type != NONE, turn on global IP forwarding */
2597
    if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2598
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2599
            goto error; /* Precise error message already provided */
2600 2601 2602 2603

        if (networkEnableIPForwarding(v4present, v6present) < 0) {
            virReportSystemError(errno, "%s",
                                 _("failed to enable IP forwarding"));
2604
            goto error;
2605
        }
2606 2607
    }

2608

2609
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2610
    if ((v4present || v6present) &&
2611
        networkStartDhcpDaemon(driver, obj) < 0)
2612
        goto error;
2613

2614 2615
    dnsmasqStarted = true;

2616
    /* start radvd if there are any ipv6 addresses */
2617
    if (v6present && networkStartRadvd(driver, obj) < 0)
2618
        goto error;
2619

2620 2621 2622
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2623
    if (v6present && networkWaitDadFinish(obj) < 0)
2624
        goto error;
2625 2626 2627

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2628 2629 2630
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
2631
            goto error;
2632 2633 2634
        VIR_FORCE_CLOSE(tapfd);
    }

2635
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
2636
        goto error;
2637

2638
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2639
    VIR_FREE(macMapFile);
2640 2641 2642

    return 0;

2643
 error:
2644
    virErrorPreserveLast(&save_err);
2645 2646
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
2647

2648 2649
    if (dnsmasqStarted) {
        pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
2650 2651
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2652 2653
    }

2654 2655
    if (devOnline)
        ignore_value(virNetDevSetOnline(def->bridge, 0));
2656

2657 2658
    if (firewalRulesAdded &&
        def->forward.type != VIR_NETWORK_FORWARD_OPEN)
2659
        networkRemoveFirewallRules(def);
2660

H
Hu Tao 已提交
2661
    if (macTapIfName) {
2662
        VIR_FORCE_CLOSE(tapfd);
2663
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2664 2665
        VIR_FREE(macTapIfName);
    }
2666
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2667
    VIR_FREE(macMapFile);
2668

2669
    ignore_value(virNetDevBridgeDelete(def->bridge));
2670

2671
    virErrorRestore(&save_err);
2672
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2673 2674 2675
    return -1;
}

2676

2677 2678
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2679
                              virNetworkObjPtr obj)
2680
{
2681
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2682 2683 2684
    pid_t radvdPid;
    pid_t dnsmasqPid;

2685 2686
    if (def->bandwidth)
        virNetDevBandwidthClear(def->bridge);
2687

2688
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2689

2690 2691
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2692 2693
        char *radvdpidbase;

2694
        kill(radvdPid, SIGTERM);
2695
        /* attempt to delete the pidfile we created */
2696
        if ((radvdpidbase = networkRadvdPidfileBasename(def->name))) {
2697
            virPidFileDelete(driver->pidDir, radvdpidbase);
2698 2699 2700 2701
            VIR_FREE(radvdpidbase);
        }
    }

2702 2703 2704
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2705

2706 2707
    if (def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(def->bridge);
2708
        if (macTapIfName) {
2709
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2710 2711 2712 2713
            VIR_FREE(macTapIfName);
        }
    }

2714
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2715

2716 2717
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2718

2719
    ignore_value(virNetDevBridgeDelete(def->bridge));
2720

2721
    /* See if its still alive and really really kill it */
2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732
    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);
2733

2734 2735 2736
    return 0;
}

2737

2738
static int
2739
networkStartNetworkBridge(virNetworkObjPtr obj)
2740
{
2741 2742
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

2743 2744 2745 2746
    /* 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.
     */
2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758
    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;
2759 2760
}

2761

2762
static int
J
Ján Tomko 已提交
2763
networkShutdownNetworkBridge(virNetworkObjPtr obj G_GNUC_UNUSED)
2764
{
2765 2766
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

2767 2768 2769 2770
    /* 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.
     */
2771 2772 2773
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);

2774 2775 2776 2777
    return 0;
}


2778 2779 2780 2781 2782 2783 2784 2785 2786
/* 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;
2787
    unsigned int maxVirtFns = 0;
2788 2789 2790 2791 2792 2793
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2794 2795 2796
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2797 2798
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813
        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];

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

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

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


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

2901 2902

static int
J
Ján Tomko 已提交
2903
networkShutdownNetworkExternal(virNetworkObjPtr obj G_GNUC_UNUSED)
2904 2905
{
    /* put anything here that needs to be done each time a network of
2906
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2907 2908 2909 2910 2911 2912
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2913

2914
static int
2915
networkStartNetwork(virNetworkDriverStatePtr driver,
2916
                    virNetworkObjPtr obj)
2917
{
2918
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2919 2920
    int ret = -1;

2921
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2922

2923
    if (virNetworkObjIsActive(obj)) {
2924 2925
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2926
        return ret;
2927 2928
    }

2929 2930
    VIR_DEBUG("Beginning network startup process");

2931 2932
    virNetworkObjDeleteAllPorts(obj, driver->stateDir);

2933
    VIR_DEBUG("Setting current network def as transient");
2934
    if (virNetworkObjSetDefTransient(obj, true, network_driver->xmlopt) < 0)
2935
        goto cleanup;
2936

2937 2938
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2939
    if (networkRunHook(obj, NULL,
2940 2941 2942 2943
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2944
    switch ((virNetworkForwardType) def->forward.type) {
2945 2946 2947 2948

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2949
    case VIR_NETWORK_FORWARD_OPEN:
2950
        if (networkStartNetworkVirtual(driver, obj) < 0)
2951
            goto cleanup;
2952 2953 2954
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2955
        if (def->bridge) {
2956
            if (networkStartNetworkBridge(obj) < 0)
2957 2958 2959 2960 2961 2962 2963
                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).
         */
2964 2965
        ATTRIBUTE_FALLTHROUGH;

2966 2967 2968
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2969
    case VIR_NETWORK_FORWARD_HOSTDEV:
2970
        if (networkStartNetworkExternal(obj) < 0)
2971
            goto cleanup;
2972
        break;
2973 2974 2975 2976 2977

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

2980 2981
    virNetworkObjSetFloorSum(obj, 0);

2982
    /* finally we can call the 'started' hook script if any */
2983
    if (networkRunHook(obj, NULL,
2984 2985 2986 2987
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2988 2989 2990
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2991
    VIR_DEBUG("Writing network status to disk");
2992 2993
    if (virNetworkObjSaveStatus(driver->stateDir,
                                obj, network_driver->xmlopt) < 0)
2994
        goto cleanup;
2995

2996
    virNetworkObjSetActive(obj, true);
2997
    VIR_INFO("Network '%s' started up", def->name);
2998
    ret = 0;
2999

3000
 cleanup:
3001
    if (ret < 0) {
3002 3003 3004
        virErrorPtr save_err;

        virErrorPreserveLast(&save_err);
3005 3006
        virNetworkObjUnsetDefTransient(obj);
        networkShutdownNetwork(driver, obj);
3007
        virErrorRestore(&save_err);
3008 3009 3010 3011
    }
    return ret;
}

3012

3013 3014
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
3015
                       virNetworkObjPtr obj)
3016
{
3017
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
3018 3019 3020
    int ret = 0;
    char *stateFile;

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

3023
    if (!virNetworkObjIsActive(obj))
3024 3025
        return 0;

3026
    stateFile = virNetworkConfigFile(driver->stateDir, def->name);
3027 3028 3029 3030 3031 3032
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

3033
    switch ((virNetworkForwardType) def->forward.type) {
3034 3035 3036 3037

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
3038
    case VIR_NETWORK_FORWARD_OPEN:
3039
        ret = networkShutdownNetworkVirtual(driver, obj);
3040 3041 3042
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3043
        if (def->bridge) {
3044
            ret = networkShutdownNetworkBridge(obj);
3045 3046 3047 3048 3049 3050
            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).
         */
3051 3052
        ATTRIBUTE_FALLTHROUGH;

3053 3054 3055
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
3056
    case VIR_NETWORK_FORWARD_HOSTDEV:
3057
        ret = networkShutdownNetworkExternal(obj);
3058
        break;
3059 3060 3061 3062 3063

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

3066
    /* now that we know it's stopped call the hook if present */
3067
    networkRunHook(obj, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
3068 3069
                   VIR_HOOK_SUBOP_END);

3070
    virNetworkObjSetActive(obj, false);
3071
    virNetworkObjUnsetDefTransient(obj);
3072
    return ret;
3073 3074 3075
}


3076 3077 3078
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
3079
{
3080
    virNetworkDriverStatePtr driver = networkGetDriver();
3081
    virNetworkObjPtr obj;
3082
    virNetworkDefPtr def;
3083
    virNetworkPtr net = NULL;
3084

3085 3086
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
3087 3088
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
3089
        virReportError(VIR_ERR_NO_NETWORK,
3090 3091
                       _("no network with matching uuid '%s'"),
                       uuidstr);
3092
        goto cleanup;
3093
    }
3094
    def = virNetworkObjGetDef(obj);
3095

3096
    if (virNetworkLookupByUUIDEnsureACL(conn, def) < 0)
3097 3098
        goto cleanup;

3099
    net = virGetNetwork(conn, def->name, def->uuid);
3100

3101
 cleanup:
3102 3103
    virNetworkObjEndAPI(&obj);
    return net;
3104 3105
}

3106 3107 3108 3109

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
3110
{
3111
    virNetworkDriverStatePtr driver = networkGetDriver();
3112
    virNetworkObjPtr obj;
3113
    virNetworkDefPtr def;
3114
    virNetworkPtr net = NULL;
3115

3116 3117
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
3118 3119
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
3120
        goto cleanup;
3121
    }
3122
    def = virNetworkObjGetDef(obj);
3123

3124
    if (virNetworkLookupByNameEnsureACL(conn, def) < 0)
3125 3126
        goto cleanup;

3127
    net = virGetNetwork(conn, def->name, def->uuid);
3128

3129
 cleanup:
3130 3131
    virNetworkObjEndAPI(&obj);
    return net;
3132 3133
}

3134 3135 3136

static int
networkConnectNumOfNetworks(virConnectPtr conn)
3137
{
3138
    virNetworkDriverStatePtr driver = networkGetDriver();
3139
    int nactive;
3140

3141 3142 3143
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

3144 3145 3146 3147
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
3148

3149 3150 3151
    return nactive;
}

3152 3153 3154 3155

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
3156
                           int maxnames)
3157 3158
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3159
    int got = 0;
3160

3161 3162 3163
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

3164
    got = virNetworkObjListGetNames(driver->networks,
3165
                                    true, names, maxnames,
3166 3167
                                    virConnectListNetworksCheckACL,
                                    conn);
3168

3169 3170 3171
    return got;
}

3172 3173 3174

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
3175
{
3176
    virNetworkDriverStatePtr driver = networkGetDriver();
3177
    int ninactive = 0;
3178

3179 3180 3181
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3182 3183 3184 3185
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
3186

3187 3188 3189
    return ninactive;
}

3190 3191 3192 3193

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
3194
                                  int maxnames)
3195 3196
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3197
    int got = 0;
3198

3199 3200 3201
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3202
    got = virNetworkObjListGetNames(driver->networks,
3203
                                    false, names, maxnames,
3204 3205
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
3206 3207 3208
    return got;
}

3209

3210
static int
3211 3212 3213
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
3214
{
3215
    virNetworkDriverStatePtr driver = networkGetDriver();
3216 3217 3218 3219
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

3220 3221 3222
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

3223
    ret = virNetworkObjListExport(conn, driver->networks, nets,
3224 3225
                                  virConnectListAllNetworksCheckACL,
                                  flags);
3226

3227
 cleanup:
3228 3229
    return ret;
}
3230

3231

3232 3233 3234 3235 3236 3237 3238 3239
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3240
    virNetworkDriverStatePtr driver = networkGetDriver();
3241 3242 3243 3244 3245 3246
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3247
                                       net, eventID, callback,
3248 3249 3250
                                       opaque, freecb, &ret) < 0)
        ret = -1;

3251
 cleanup:
3252 3253 3254
    return ret;
}

3255

3256 3257 3258 3259
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3260
    virNetworkDriverStatePtr driver = networkGetDriver();
3261 3262 3263 3264 3265
    int ret = -1;

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

3266 3267
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3268
                                        callbackID, true) < 0)
3269 3270 3271
        goto cleanup;

    ret = 0;
3272

3273
 cleanup:
3274 3275 3276
    return ret;
}

3277 3278 3279

static int
networkIsActive(virNetworkPtr net)
3280 3281 3282 3283
{
    virNetworkObjPtr obj;
    int ret = -1;

3284 3285
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3286

3287
    if (virNetworkIsActiveEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3288 3289
        goto cleanup;

3290 3291
    ret = virNetworkObjIsActive(obj);

3292
 cleanup:
3293
    virNetworkObjEndAPI(&obj);
3294 3295 3296
    return ret;
}

3297 3298 3299

static int
networkIsPersistent(virNetworkPtr net)
3300 3301 3302 3303
{
    virNetworkObjPtr obj;
    int ret = -1;

3304 3305
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3306

3307
    if (virNetworkIsPersistentEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3308 3309
        goto cleanup;

3310
    ret = virNetworkObjIsPersistent(obj);
3311

3312
 cleanup:
3313
    virNetworkObjEndAPI(&obj);
3314 3315 3316 3317
    return ret;
}


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

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3335
        p && p[1] == 'd')
3336
        templ = def->bridge;
3337 3338 3339 3340

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3341 3342 3343 3344 3345
        /* 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).
         */
3346
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3347
              virNetDevExists(newname) == 1)) {
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 3375 3376 3377 3378 3379 3380
            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")) {
3381
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398
            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;
}


3399
static int
3400
networkValidate(virNetworkDriverStatePtr driver,
3401
                virNetworkDefPtr def)
3402
{
3403
    size_t i, j;
3404 3405
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3406
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3407
    bool ipv4def = false, ipv6def = false;
3408
    bool bandwidthAllowed = false;
3409
    bool usesInterface = false, usesAddress = false;
3410

3411 3412 3413
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3414 3415 3416
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3417 3418 3419 3420 3421
    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:
3422 3423 3424 3425
        /* 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)
3426 3427 3428
            return -1;

        virNetworkSetBridgeMacAddr(def);
3429
        bandwidthAllowed = true;
3430 3431 3432
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3433 3434 3435 3436 3437
        if (def->bridge != NULL)
            bandwidthAllowed = true;

        ATTRIBUTE_FALLTHROUGH;

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

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

3486 3487 3488 3489 3490 3491 3492 3493 3494 3495
    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;
    }

3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508
    /* 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++) {
3509 3510 3511
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

3512
        switch ((virNetworkForwardHostdevDeviceType)iface->type) {
3513 3514
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525

            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;
            }
3526
            break;
3527 3528

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3529
            usesAddress = true;
3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554

            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);
3555
            break;
3556 3557
        }

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

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

3610 3611 3612
    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 已提交
3613 3614
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3615
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3616 3617

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

    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;
            }
        }
    }
3693 3694 3695
    return 0;
}

3696 3697 3698 3699

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3700
{
3701
    virNetworkDriverStatePtr driver = networkGetDriver();
3702
    virNetworkDefPtr newDef;
3703
    virNetworkObjPtr obj = NULL;
3704
    virNetworkDefPtr def;
3705
    virNetworkPtr net = NULL;
3706
    virObjectEventPtr event = NULL;
3707

3708
    if (!(newDef = virNetworkDefParseString(xml, network_driver->xmlopt)))
3709
        goto cleanup;
3710

3711
    if (virNetworkCreateXMLEnsureACL(conn, newDef) < 0)
3712 3713
        goto cleanup;

3714
    if (networkValidate(driver, newDef) < 0)
J
Ján Tomko 已提交
3715
        goto cleanup;
3716

3717 3718 3719
    /* 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.
3720
     */
3721
    if (!(obj = virNetworkObjAssignDef(driver->networks, newDef,
3722 3723
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3724
        goto cleanup;
3725 3726
    newDef = NULL;
    def = virNetworkObjGetDef(obj);
3727

3728 3729
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3730
        goto cleanup;
3731 3732
    }

3733 3734
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3735 3736
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3737

3738 3739
    VIR_INFO("Creating network '%s'", def->name);
    net = virGetNetwork(conn, def->name, def->uuid);
3740

3741
 cleanup:
3742
    virNetworkDefFree(newDef);
3743
    virObjectEventStateQueue(driver->networkEventState, event);
3744 3745
    virNetworkObjEndAPI(&obj);
    return net;
3746 3747
}

3748 3749 3750 3751

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3752
{
3753
    virNetworkDriverStatePtr driver = networkGetDriver();
3754
    virNetworkDefPtr def = NULL;
3755
    bool freeDef = true;
3756 3757
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3758
    virObjectEventPtr event = NULL;
3759

3760
    if (!(def = virNetworkDefParseString(xml, network_driver->xmlopt)))
3761
        goto cleanup;
3762

3763 3764 3765
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3766
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3767
        goto cleanup;
3768

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

3772
    /* def was assigned to network object */
3773
    freeDef = false;
3774

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

3789
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3790 3791
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3792

3793
    VIR_INFO("Defining network '%s'", def->name);
3794
    net = virGetNetwork(conn, def->name, def->uuid);
3795

3796
 cleanup:
3797
    virObjectEventStateQueue(driver->networkEventState, event);
3798
    if (freeDef)
J
Ján Tomko 已提交
3799
        virNetworkDefFree(def);
3800 3801
    virNetworkObjEndAPI(&obj);
    return net;
3802 3803
}

3804

3805
static int
3806 3807
networkUndefine(virNetworkPtr net)
{
3808
    virNetworkDriverStatePtr driver = networkGetDriver();
3809
    virNetworkObjPtr obj;
3810
    virNetworkDefPtr def;
3811
    int ret = -1;
3812
    bool active = false;
3813
    virObjectEventPtr event = NULL;
3814

3815
    if (!(obj = networkObjFromNetwork(net)))
3816
        goto cleanup;
3817
    def = virNetworkObjGetDef(obj);
3818

3819
    if (virNetworkUndefineEnsureACL(net->conn, def) < 0)
3820 3821
        goto cleanup;

3822
    if (virNetworkObjIsActive(obj))
3823
        active = true;
3824

3825
    if (!virNetworkObjIsPersistent(obj)) {
3826 3827 3828 3829 3830
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3831
    /* remove autostart link */
3832 3833
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3834
                                  obj) < 0)
3835
        goto cleanup;
3836

3837 3838
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3839 3840
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3841

3842
    VIR_INFO("Undefining network '%s'", def->name);
3843
    if (!active) {
3844
        if (networkRemoveInactive(driver, obj) < 0)
3845
            goto cleanup;
3846 3847 3848 3849 3850
    } else {

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

3854
    ret = 0;
3855

3856
 cleanup:
3857
    virObjectEventStateQueue(driver->networkEventState, event);
3858
    virNetworkObjEndAPI(&obj);
3859
    return ret;
3860 3861
}

3862

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

3880 3881 3882 3883 3884

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3885
    if (!(obj = networkObjFromNetwork(net)))
3886
        goto cleanup;
3887
    def = virNetworkObjGetDef(obj);
3888

3889
    if (virNetworkUpdateEnsureACL(net->conn, def, flags) < 0)
3890 3891
        goto cleanup;

3892
    /* see if we are listening for dhcp pre-modification */
3893
    for (i = 0;
3894
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3895
         i++) {
3896 3897 3898 3899 3900 3901
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3902 3903
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3904
     */
3905
    isActive = virNetworkObjIsActive(obj);
3906 3907
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3908 3909 3910 3911 3912 3913 3914
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

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

3956
    /* update the network config in memory/on disk */
3957 3958 3959
    if (virNetworkObjUpdate(obj, command, section,
                            parentIndex, xml,
                            network_driver->xmlopt, flags) < 0) {
3960
        if (needFirewallRefresh)
3961
            ignore_value(networkAddFirewallRules(def));
3962 3963 3964
        goto cleanup;
    }

3965 3966 3967 3968
    /* @def is replaced */
    def = virNetworkObjGetDef(obj);

    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
3969 3970 3971 3972 3973
        goto cleanup;

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

4001 4002 4003 4004 4005 4006 4007 4008
        } 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;

4009
            for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
4010
                 i++) {
4011 4012 4013 4014 4015 4016 4017
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
4018 4019
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
4020 4021 4022
                goto cleanup;
            }

4023 4024 4025 4026
        } 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.
4027
             */
4028
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
4029 4030 4031 4032 4033 4034 4035 4036
                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.
             */
4037
            if (networkRefreshRadvd(driver, obj) < 0)
4038 4039 4040 4041
                goto cleanup;
        }

        /* save current network state to disk */
4042 4043
        if ((ret = virNetworkObjSaveStatus(driver->stateDir,
                                           obj, network_driver->xmlopt)) < 0)
4044 4045
            goto cleanup;
    }
4046 4047

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

4052
    ret = 0;
4053
 cleanup:
4054
    virNetworkObjEndAPI(&obj);
4055 4056 4057
    return ret;
}

4058 4059 4060

static int
networkCreate(virNetworkPtr net)
4061
{
4062
    virNetworkDriverStatePtr driver = networkGetDriver();
4063
    virNetworkObjPtr obj;
4064
    virNetworkDefPtr def;
4065
    int ret = -1;
4066
    virObjectEventPtr event = NULL;
4067

4068
    if (!(obj = networkObjFromNetwork(net)))
4069
        goto cleanup;
4070
    def = virNetworkObjGetDef(obj);
4071

4072
    if (virNetworkCreateEnsureACL(net->conn, def) < 0)
4073 4074
        goto cleanup;

4075
    if ((ret = networkStartNetwork(driver, obj)) < 0)
4076
        goto cleanup;
4077

4078 4079
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
4080 4081
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
4082

4083
 cleanup:
4084
    virObjectEventStateQueue(driver->networkEventState, event);
4085
    virNetworkObjEndAPI(&obj);
4086
    return ret;
4087 4088
}

4089 4090 4091

static int
networkDestroy(virNetworkPtr net)
4092
{
4093
    virNetworkDriverStatePtr driver = networkGetDriver();
4094
    virNetworkObjPtr obj;
4095
    virNetworkDefPtr def;
4096
    int ret = -1;
4097
    virObjectEventPtr event = NULL;
4098

4099
    if (!(obj = networkObjFromNetwork(net)))
4100
        goto cleanup;
4101
    def = virNetworkObjGetDef(obj);
4102

4103
    if (virNetworkDestroyEnsureACL(net->conn, def) < 0)
4104 4105
        goto cleanup;

4106
    if (!virNetworkObjIsActive(obj)) {
4107
        virReportError(VIR_ERR_OPERATION_INVALID,
4108
                       _("network '%s' is not active"),
4109
                       def->name);
4110 4111 4112
        goto cleanup;
    }

4113
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
4114
        goto cleanup;
4115 4116 4117

    virNetworkObjDeleteAllPorts(obj, driver->stateDir);

4118 4119
    /* @def replaced in virNetworkObjUnsetDefTransient*/
    def = virNetworkObjGetDef(obj);
4120

4121 4122
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
4123 4124
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
4125

4126 4127
    if (!virNetworkObjIsPersistent(obj) &&
        networkRemoveInactive(driver, obj) < 0) {
4128 4129
        ret = -1;
        goto cleanup;
4130
    }
4131

4132
 cleanup:
4133
    virObjectEventStateQueue(driver->networkEventState, event);
4134
    virNetworkObjEndAPI(&obj);
4135 4136 4137
    return ret;
}

4138 4139 4140 4141

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
4142
{
4143
    virNetworkObjPtr obj;
4144
    virNetworkDefPtr curDef;
4145
    virNetworkDefPtr def;
4146
    virNetworkDefPtr newDef;
4147
    char *ret = NULL;
4148

4149
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
4150

4151
    if (!(obj = networkObjFromNetwork(net)))
4152
        return ret;
4153 4154
    def = virNetworkObjGetDef(obj);
    newDef = virNetworkObjGetNewDef(obj);
4155

4156
    if (virNetworkGetXMLDescEnsureACL(net->conn, def) < 0)
4157 4158
        goto cleanup;

4159 4160
    if ((flags & VIR_NETWORK_XML_INACTIVE) && newDef)
        curDef = newDef;
4161
    else
4162
        curDef = def;
4163

4164
    ret = virNetworkDefFormat(curDef, network_driver->xmlopt, flags);
4165

4166
 cleanup:
4167
    virNetworkObjEndAPI(&obj);
4168
    return ret;
4169 4170
}

4171 4172 4173 4174

static char *
networkGetBridgeName(virNetworkPtr net)
{
4175
    virNetworkObjPtr obj;
4176
    virNetworkDefPtr def;
4177 4178
    char *bridge = NULL;

4179
    if (!(obj = networkObjFromNetwork(net)))
4180
        return bridge;
4181
    def = virNetworkObjGetDef(obj);
4182

4183
    if (virNetworkGetBridgeNameEnsureACL(net->conn, def) < 0)
4184 4185
        goto cleanup;

4186
    if (!(def->bridge)) {
4187 4188
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
4189
                       def->name);
4190 4191 4192
        goto cleanup;
    }

4193
    ignore_value(VIR_STRDUP(bridge, def->bridge));
4194

4195
 cleanup:
4196
    virNetworkObjEndAPI(&obj);
4197 4198 4199
    return bridge;
}

4200 4201 4202 4203

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
4204
{
4205
    virNetworkObjPtr obj;
4206
    int ret = -1;
4207

4208
    if (!(obj = networkObjFromNetwork(net)))
4209
        return ret;
4210

4211
    if (virNetworkGetAutostartEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
4212 4213
        goto cleanup;

4214
    *autostart = virNetworkObjIsAutostart(obj) ? 1 : 0;
4215
    ret = 0;
4216

4217
 cleanup:
4218
    virNetworkObjEndAPI(&obj);
4219
    return ret;
4220 4221
}

4222 4223 4224 4225

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
4226
{
4227
    virNetworkDriverStatePtr driver = networkGetDriver();
4228
    virNetworkObjPtr obj;
4229
    virNetworkDefPtr def;
4230
    char *configFile = NULL, *autostartLink = NULL;
4231 4232
    bool new_autostart;
    bool cur_autostart;
4233
    int ret = -1;
4234

4235
    if (!(obj = networkObjFromNetwork(net)))
4236
        goto cleanup;
4237
    def = virNetworkObjGetDef(obj);
4238

4239
    if (virNetworkSetAutostartEnsureACL(net->conn, def) < 0)
4240 4241
        goto cleanup;

4242
    if (!virNetworkObjIsPersistent(obj)) {
4243 4244
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
4245 4246 4247
        goto cleanup;
    }

4248 4249 4250
    new_autostart = (autostart != 0);
    cur_autostart = virNetworkObjIsAutostart(obj);
    if (cur_autostart != new_autostart) {
4251 4252
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir,
                                               def->name)) == NULL)
4253
            goto cleanup;
4254 4255
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir,
                                                  def->name)) == NULL)
4256 4257
            goto cleanup;

4258
        if (new_autostart) {
4259
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
4260
                virReportSystemError(errno,
4261 4262
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
4263 4264
                goto cleanup;
            }
4265

4266
            if (symlink(configFile, autostartLink) < 0) {
4267
                virReportSystemError(errno,
4268
                                     _("Failed to create symlink '%s' to '%s'"),
4269
                                     autostartLink, configFile);
4270 4271 4272
                goto cleanup;
            }
        } else {
4273
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4274
                virReportSystemError(errno,
4275
                                     _("Failed to delete symlink '%s'"),
4276
                                     autostartLink);
4277 4278
                goto cleanup;
            }
4279 4280
        }

4281
        virNetworkObjSetAutostart(obj, new_autostart);
4282
    }
4283

4284
    ret = 0;
4285

4286
 cleanup:
4287 4288
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4289
    virNetworkObjEndAPI(&obj);
4290
    return ret;
4291 4292
}

4293

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

    virCheckFlags(0, -1);

4325 4326 4327 4328 4329 4330
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4331
    if (!(obj = networkObjFromNetwork(net)))
4332
        return -1;
4333
    def = virNetworkObjGetDef(obj);
4334

4335
    if (virNetworkGetDHCPLeasesEnsureACL(net->conn, def) < 0)
4336
        goto cleanup;
4337 4338

    /* Retrieve custom leases file location */
4339
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, def->bridge);
4340 4341

    /* Read entire contents */
4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355
    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);
        }
4356 4357 4358 4359 4360 4361 4362 4363 4364 4365
        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;
        }

4366
        if (!virJSONValueIsArray(leases_array)) {
4367
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4368
                           _("Malformed lease_entries array"));
4369 4370
            goto error;
        }
4371
        size = virJSONValueArraySize(leases_array);
4372 4373
    }

4374
    currtime = (long long)time(NULL);
4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390

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

4391
        if (mac && virMacAddrCompare(mac, mac_tmp))
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 4417 4418 4419 4420 4421 4422
            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 */
4423 4424
            for (j = 0; j < def->nips; j++) {
                ipdef_tmp = &def->ips[j];
4425 4426 4427 4428 4429 4430 4431 4432

                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)) {
4433
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4434 4435 4436 4437 4438 4439 4440 4441
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
4442
                (VIR_STRDUP(lease->iface, def->bridge) < 0))
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 4469 4470 4471 4472 4473 4474
                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);
4475
    VIR_FREE(lease_entries);
4476 4477
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4478

4479
    virNetworkObjEndAPI(&obj);
4480

4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491
    return rv;

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

4492

4493 4494 4495 4496 4497
/* A unified function to log network connections and disconnections */

static void
networkLogAllocation(virNetworkDefPtr netdef,
                     virNetworkForwardIfDefPtr dev,
4498
                     virMacAddrPtr mac,
4499 4500 4501 4502 4503
                     bool inUse)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    const char *verb = inUse ? "using" : "releasing";

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

4525

4526 4527 4528 4529 4530 4531 4532 4533
/* 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.
 */

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

4556
    netdef = virNetworkObjGetDef(obj);
4557
    VIR_DEBUG("Allocating port from net %s", netdef->name);
4558

4559
    if (!virNetworkObjIsActive(obj)) {
4560 4561 4562
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4563
        goto cleanup;
4564 4565
    }

4566
    VIR_DEBUG("Interface port group %s", port->group);
4567 4568 4569
    /* 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 已提交
4570
     */
4571
    portgroup = virPortGroupFindByName(netdef, port->group);
4572

4573 4574 4575 4576
    if (!port->bandwidth) {
        if (portgroup && portgroup->bandwidth &&
            virNetDevBandwidthCopy(&port->bandwidth,
                                   portgroup->bandwidth) < 0)
4577
            goto cleanup;
4578
    }
4579

4580 4581 4582 4583 4584 4585
    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;
4586

4587
        if (vlan && virNetDevVlanCopy(&port->vlan, vlan) < 0)
4588
            goto cleanup;
4589
    }
4590

4591 4592 4593 4594 4595 4596
    if (!port->trustGuestRxFilters) {
        if (portgroup && portgroup->trustGuestRxFilters)
            port->trustGuestRxFilters = portgroup->trustGuestRxFilters;
        else if (netdef->trustGuestRxFilters)
            port->trustGuestRxFilters = netdef->trustGuestRxFilters;
    }
4597

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

4613
    VIR_DEBUG("Processing forward type %d", netdef->forward.type);
4614 4615 4616 4617 4618
    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:
4619 4620 4621 4622
        /* for these forward types, the actual net type really *is*
         * NETWORK; we just keep the info from the portgroup in
         * iface->data.network.actual
         */
4623
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_NETWORK;
4624

4625
        if (VIR_STRDUP(port->plug.bridge.brname, netdef->bridge) < 0)
4626
            goto cleanup;
4627
        port->plug.bridge.macTableManager = netdef->macTableManager;
4628

4629
        if (port->virtPortProfile) {
4630 4631 4632
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("<virtualport type='%s'> not supported for network "
                             "'%s' which uses IP forwarding"),
4633
                           virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4634
                           netdef->name);
4635
            goto cleanup;
4636 4637
        }

4638
        if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4639
            goto cleanup;
4640
        break;
4641

4642
    case VIR_NETWORK_FORWARD_HOSTDEV: {
4643
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI;
4644

4645
        if (networkCreateInterfacePool(netdef) < 0)
4646
            goto cleanup;
4647 4648

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

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

4682 4683 4684 4685 4686 4687
    case VIR_NETWORK_FORWARD_BRIDGE:
        if (netdef->bridge) {
            /* <forward type='bridge'/> <bridge name='xxx'/>
             * is VIR_DOMAIN_NET_TYPE_BRIDGE
             */

4688 4689
            port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE;
            if (VIR_STRDUP(port->plug.bridge.brname, netdef->bridge) < 0)
4690
                goto cleanup;
4691
            port->plug.bridge.macTableManager = netdef->macTableManager;
4692

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

4705
            if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4706
                goto cleanup;
4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717
            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:
4718 4719 4720 4721 4722
        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
4723
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_DIRECT;
4724 4725 4726 4727

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

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

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

4756
            if (networkCreateInterfacePool(netdef) < 0)
4757
                goto cleanup;
4758

4759 4760 4761 4762 4763
            /* 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.
4764
             */
4765 4766
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4767 4768
                 port->virtPortProfile &&
                 (port->virtPortProfile->virtPortType
4769
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4770

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

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
4803
        goto cleanup;
4804 4805
    }

4806
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
4807 4808
                               port->ownername, &port->mac) < 0)
        goto cleanup;
M
Michal Privoznik 已提交
4809

4810
    if (virNetDevVPortProfileCheckComplete(port->virtPortProfile, true) < 0)
4811
        goto cleanup;
4812

4813 4814 4815 4816
    /* 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.
     */
4817
    VIR_DEBUG("Sanity check port config");
4818

4819
    if (port->vlan.nTags) {
4820 4821 4822 4823
        /* 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
4824
         */
4825 4826 4827
        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) ||
4828
              (port->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE &&
4829 4830
               port->virtPortProfile &&
               port->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
4831 4832 4833 4834 4835
            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);
4836
            goto cleanup;
4837 4838
        }
    }
4839 4840 4841 4842 4843 4844 4845 4846

    /* 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"));
4847
        goto cleanup;
4848
    }
4849

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

    VIR_DEBUG("Port allocated");
4866

4867
    ret = 0;
4868
 cleanup:
4869
    return ret;
4870
}
4871

4872

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

4891
    netdef = virNetworkObjGetDef(obj);
4892

4893
    if (!virNetworkObjIsActive(obj)) {
4894 4895 4896
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4897
        goto cleanup;
4898
    }
4899

4900 4901 4902 4903
    switch (port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unexpectedly got a network port without a plug"));
4904
        goto cleanup;
4905

4906 4907 4908 4909
    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) {
4910
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4911
                           _("Unexpectedly got a network port without a network bridge"));
4912
            goto cleanup;
4913
        }
4914 4915 4916 4917
        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
        if (networkCreateInterfacePool(netdef) < 0)
4918
            goto cleanup;
4919 4920

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

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

4957 4958 4959
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:

        if (networkCreateInterfacePool(netdef) < 0)
4960
            goto cleanup;
4961 4962

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

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

        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
    default:
        virReportEnumRangeError(virNetworkPortPlugType, port->plugtype);
5006
        goto cleanup;
5007 5008
    }

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

5023
    ret = 0;
5024 5025 5026 5027 5028
 cleanup:
    return ret;
}


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

5050
    netdef = virNetworkObjGetDef(obj);
5051

5052 5053 5054
    switch ((virNetworkPortPlugType)port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        VIR_DEBUG("Releasing network device with no plug type");
5055 5056
        break;

5057 5058 5059 5060 5061
    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;
5062 5063
        break;

5064 5065 5066 5067 5068 5069 5070
    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;
5071
        }
5072

5073 5074
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5075
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
5076
                STREQ(port->plug.direct.linkdev, netdef->forward.ifs[i].device.dev)) {
5077
                dev = &netdef->forward.ifs[i];
5078 5079 5080
                break;
            }
        }
5081

5082
        if (!dev) {
5083
            virReportError(VIR_ERR_INTERNAL_ERROR,
5084 5085
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5086 5087
                           netdef->name, port->plug.direct.linkdev);
            goto cleanup;
5088
        }
5089
        break;
5090

5091 5092
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:
        if (netdef->forward.nifs == 0) {
5093
            virReportError(VIR_ERR_INTERNAL_ERROR,
5094 5095 5096 5097
                           _("network '%s' uses a hostdev mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
            goto cleanup;
5098 5099
        }

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

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

5129
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, port->ownername, &port->mac);
5130 5131 5132 5133 5134

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

5139 5140 5141 5142 5143 5144
    ret = 0;
 cleanup:
    return ret;
}


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

5179
    virMacAddrFormat(ifaceMac, ifmac);
5180 5181 5182 5183 5184 5185

    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"),
5186
                       ifmac, def->name);
5187 5188 5189
        return -1;
    }

5190 5191 5192 5193 5194
    if (!netBand || !netBand->in) {
        VIR_DEBUG("No network bandwidth controls present");
        /* no QoS required, claim success */
        return 1;
    }
5195
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
5196 5197
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor))) {
        VIR_DEBUG("No old/new interface bandwidth floor");
5198
        /* no QoS required, claim success */
5199
        return 1;
5200
    }
5201 5202

    tmp_new_rate = netBand->in->average;
5203 5204 5205 5206
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
5207 5208 5209 5210 5211 5212

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

5238 5239
    if (new_rate)
        *new_rate = tmp_new_rate;
5240 5241
    ret = 0;

5242
 cleanup:
5243 5244 5245
    return ret;
}

5246

5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257
/**
 * 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
5258
networkNextClassID(virNetworkObjPtr obj)
5259
{
5260
    ssize_t ret = 0;
5261
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5262

5263 5264
    if ((ret = virBitmapNextClearBit(classIdMap, -1)) < 0)
        ret = virBitmapSize(classIdMap);
5265

5266
    if (virBitmapSetBitExpand(classIdMap, ret) < 0)
5267 5268 5269 5270 5271
        return -1;

    return ret;
}

5272

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

    /* generate new class_id */
5289
    if ((next_id = networkNextClassID(obj)) < 0) {
5290 5291 5292 5293 5294
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate next class ID"));
        goto cleanup;
    }

5295
    plug_ret = virNetDevBandwidthPlug(def->bridge, def->bandwidth,
5296
                                      mac, ifaceBand, next_id);
5297
    if (plug_ret < 0) {
5298
        ignore_value(virNetDevBandwidthUnplug(def->bridge, next_id));
5299 5300 5301 5302
        goto cleanup;
    }

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

    ret = 0;
5324 5325 5326 5327 5328 5329
 cleanup:
    return ret;
}


static int
5330
networkPlugBandwidth(virNetworkObjPtr obj,
5331 5332 5333
                     virMacAddrPtr mac,
                     virNetDevBandwidthPtr ifaceBand,
                     unsigned int *class_id)
5334 5335 5336 5337 5338 5339
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5340
    if ((plug_ret = networkCheckBandwidth(obj, ifaceBand, NULL,
5341
                                          mac, &new_rate)) < 0) {
5342 5343 5344 5345 5346 5347 5348 5349 5350 5351
        /* helper reported error */
        goto cleanup;
    }

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

5352
    virMacAddrFormat(mac, ifmac);
5353

5354
    if (networkPlugBandwidthImpl(obj, mac, ifaceBand, class_id, new_rate) < 0)
5355 5356 5357
        goto cleanup;

    ret = 0;
5358

5359
 cleanup:
5360 5361 5362
    return ret;
}

5363

5364
static int
5365
networkUnplugBandwidth(virNetworkObjPtr obj,
5366 5367
                       virNetDevBandwidthPtr ifaceBand,
                       unsigned int *class_id)
5368
{
5369
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5370
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5371
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5372
    virNetworkDriverStatePtr driver = networkGetDriver();
5373 5374 5375
    int ret = 0;
    unsigned long long new_rate;

5376
    if (class_id && *class_id) {
5377
        if (!def->bandwidth || !def->bandwidth->in) {
5378
            VIR_WARN("Network %s has no bandwidth but unplug requested",
5379
                     def->name);
5380 5381
            goto cleanup;
        }
5382
        /* we must remove class from bridge */
5383
        new_rate = def->bandwidth->in->average;
5384

5385 5386
        if (def->bandwidth->in->peak > 0)
            new_rate = def->bandwidth->in->peak;
5387

5388
        ret = virNetDevBandwidthUnplug(def->bridge, *class_id);
5389 5390 5391
        if (ret < 0)
            goto cleanup;
        /* update sum of 'floor'-s of attached NICs */
5392 5393 5394
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);

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

5415
 cleanup:
5416 5417
    return ret;
}
5418

5419

5420
static void
5421
networkNetworkObjTaint(virNetworkObjPtr obj,
5422
                       virNetworkTaintFlags taint)
5423
{
5424 5425
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

5426
    if (virNetworkObjTaint(obj, taint)) {
5427
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5428
        virUUIDFormat(def->uuid, uuidstr);
5429 5430

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5431
                 def->name, uuidstr, virNetworkTaintTypeToString(taint));
5432 5433
    }
}
5434 5435


5436
static int
5437 5438 5439 5440 5441
networkUpdatePortBandwidth(virNetworkObjPtr obj,
                           virMacAddrPtr mac,
                           unsigned int *class_id,
                           virNetDevBandwidthPtr oldBandwidth,
                           virNetDevBandwidthPtr newBandwidth)
5442 5443
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5444
    virNetworkDefPtr def;
5445
    unsigned long long tmp_floor_sum;
5446
    unsigned long long new_rate = 0;
5447
    unsigned long long old_floor, new_floor;
5448
    int plug_ret;
5449 5450 5451

    old_floor = new_floor = 0;

5452 5453
    if (oldBandwidth && oldBandwidth->in)
        old_floor = oldBandwidth->in->floor;
5454 5455 5456 5457
    if (newBandwidth && newBandwidth->in)
        new_floor = newBandwidth->in->floor;

    if (new_floor == old_floor)
5458 5459
        return 0;

5460
    def = virNetworkObjGetDef(obj);
5461

5462 5463
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, oldBandwidth,
                                          mac, &new_rate)) < 0) {
5464
        /* helper reported error */
5465
        return -1;
5466 5467 5468 5469
    }

    if (plug_ret > 0) {
        /* no QoS needs to be set; claim success */
5470
        return 0;
5471 5472 5473 5474
    }

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

5475
    if (oldBandwidth && oldBandwidth->in && oldBandwidth->in->floor &&
5476
        newBandwidth->in && newBandwidth->in->floor) {
5477 5478
        /* Either we just need to update @floor .. */

5479
        if (virNetDevBandwidthUpdateRate(def->bridge,
5480
                                         *class_id,
5481
                                         def->bandwidth,
5482
                                         newBandwidth->in->floor) < 0)
5483
            return -1;
5484

5485
        tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5486
        tmp_floor_sum -= oldBandwidth->in->floor;
5487 5488 5489
        tmp_floor_sum += newBandwidth->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
        new_rate -= tmp_floor_sum;
5490

5491 5492
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0 ||
5493 5494
            virNetworkObjSaveStatus(driver->stateDir,
                                    obj, network_driver->xmlopt) < 0) {
5495
            /* Ouch, rollback */
5496
            tmp_floor_sum -= newBandwidth->in->floor;
5497
            tmp_floor_sum += oldBandwidth->in->floor;
5498
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5499

5500
            ignore_value(virNetDevBandwidthUpdateRate(def->bridge,
5501
                                                      *class_id,
5502
                                                      def->bandwidth,
5503 5504
                                                      oldBandwidth->in->floor));
            return -1;
5505 5506 5507 5508
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5509 5510
        if (networkPlugBandwidthImpl(obj, mac, newBandwidth,
                                     class_id,
5511
                                     new_rate) < 0)
5512
            return -1;
5513 5514 5515
    } else {
        /* .. or unplug old. */

5516 5517
        if (networkUnplugBandwidth(obj, oldBandwidth, class_id) < 0)
            return -1;
5518 5519
    }

5520 5521 5522 5523
    return 0;
}


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
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;
5569
    VIR_AUTOPTR(virNetworkPortDef) portdef = NULL;
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 5605 5606 5607 5608 5609 5610
    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);
5611 5612 5613 5614
    if (rc < 0)
        goto cleanup;

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

5617
        virErrorPreserveLast(&save_err);
5618
        ignore_value(networkReleasePort(obj, portdef));
5619 5620
        virErrorRestore(&save_err);

5621 5622 5623 5624
        goto cleanup;
    }

    ret = virGetNetworkPort(net, portdef->uuid);
5625
    portdef = NULL;
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 5906 5907 5908 5909 5910 5911
 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;
}


5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935
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 */
5936 5937 5938 5939 5940 5941 5942
    .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 */
5943 5944
};

5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956

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 = {
5957
    .localOnly = true,
5958
    .uriSchemes = (const char *[]){ "network", NULL },
5959 5960 5961 5962 5963
    .hypervisorDriver = &networkHypervisorDriver,
    .networkDriver = &networkDriver,
};


5964 5965 5966 5967 5968 5969 5970 5971 5972 5973
static virStateDriver networkStateDriver = {
    .name = "bridge",
    .stateInitialize  = networkStateInitialize,
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
};

int
networkRegister(void)
{
5974 5975
    if (virRegisterConnectDriver(&networkConnectDriver, false) < 0)
        return -1;
5976 5977 5978 5979 5980 5981
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
    return 0;
}