bridge_driver.c 190.1 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
static int
networkUpdateState(virNetworkObjPtr obj,
532
                   void *opaque)
533
{
534
    virNetworkDefPtr def;
535
    virNetworkDriverStatePtr driver = opaque;
536
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
537
    virMacMapPtr macmap;
538
    char *macMapFile = NULL;
539
    int ret = -1;
540

541
    virObjectLock(obj);
542
    if (!virNetworkObjIsActive(obj)) {
543 544
        ret = 0;
        goto cleanup;
545
    }
546
    def = virNetworkObjGetDef(obj);
547

548
    switch ((virNetworkForwardType) def->forward.type) {
549 550 551
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
552
    case VIR_NETWORK_FORWARD_OPEN:
553
        /* If bridge doesn't exist, then mark it inactive */
554
        if (!(def->bridge && virNetDevExists(def->bridge) == 1))
555
            virNetworkObjSetActive(obj, false);
556

557
        if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
558
                                             def->bridge)))
559 560
            goto cleanup;

561
        if (!(macmap = virMacMapNew(macMapFile)))
562 563
            goto cleanup;

564 565
        virNetworkObjSetMacMap(obj, macmap);

566
        break;
567

568
    case VIR_NETWORK_FORWARD_BRIDGE:
569 570
        if (def->bridge) {
            if (virNetDevExists(def->bridge) != 1)
571
                virNetworkObjSetActive(obj, false);
572
            break;
573
        }
574 575 576 577 578 579 580 581 582
        /* 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;
583

584 585 586
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
587 588 589 590 591

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

594
    /* Try and read dnsmasq/radvd pids of active networks */
595
    if (virNetworkObjIsActive(obj) && def->ips && (def->nips > 0)) {
596 597
        pid_t radvdPid;
        pid_t dnsmasqPid;
598
        char *radvdpidbase;
599

600
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
601
                                           def->name,
602
                                           &dnsmasqPid,
603
                                           dnsmasqCapsGetBinaryPath(dnsmasq_caps)));
604
        virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
M
Michal Privoznik 已提交
605

606
        radvdpidbase = networkRadvdPidfileBasename(def->name);
607 608
        if (!radvdpidbase)
            goto cleanup;
609

610 611
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
612 613
                                           &radvdPid, RADVD));
        virNetworkObjSetRadvdPid(obj, radvdPid);
614
        VIR_FREE(radvdpidbase);
615
    }
616

617 618
    ret = 0;
 cleanup:
619
    virObjectUnlock(obj);
620
    virObjectUnref(dnsmasq_caps);
621
    VIR_FREE(macMapFile);
622 623
    return ret;
}
624

625

626
static int
627
networkAutostartConfig(virNetworkObjPtr obj,
628
                       void *opaque)
629
{
630
    virNetworkDriverStatePtr driver = opaque;
631
    int ret = -1;
632

633
    virObjectLock(obj);
634
    if (virNetworkObjIsAutostart(obj) &&
635 636
        !virNetworkObjIsActive(obj) &&
        networkStartNetwork(driver, obj) < 0)
637 638 639 640
        goto cleanup;

    ret = 0;
 cleanup:
641
    virObjectUnlock(obj);
642
    return ret;
643 644
}

645

646
#ifdef WITH_FIREWALLD
647 648
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
649 650
                             DBusMessage *message,
                             void *user_data)
651
{
652
    virNetworkDriverStatePtr driver = user_data;
653
    bool reload = false;
654

655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
    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) {
679
        VIR_DEBUG("Reload in bridge_driver because of firewalld.");
680
        networkReloadFirewallRules(driver, false);
681 682 683 684 685 686
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

687

688
/**
689
 * networkStateInitialize:
690
 *
J
Ján Tomko 已提交
691
 * Initialization function for the QEMU daemon
692 693
 */
static int
694 695 696
networkStateInitialize(bool privileged,
                       virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
697
{
698
    int ret = VIR_DRV_STATE_INIT_ERROR;
699 700
    char *configdir = NULL;
    char *rundir = NULL;
701
#ifdef WITH_FIREWALLD
702 703
    DBusConnection *sysbus = NULL;
#endif
704

705
    if (VIR_ALLOC(network_driver) < 0)
706
        goto error;
707

708
    network_driver->lockFD = -1;
709 710
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
711 712
        goto error;
    }
713

714 715
    network_driver->privileged = privileged;

C
Cole Robinson 已提交
716 717 718
    if (!(network_driver->xmlopt = networkDnsmasqCreateXMLConf()))
        goto error;

719 720 721 722
    /* configuration/state paths are one of
     * ~/.config/libvirt/... (session/unprivileged)
     * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
     */
723
    if (privileged) {
724
        if (VIR_STRDUP(network_driver->networkConfigDir,
725
                       SYSCONFDIR "/libvirt/qemu/networks") < 0 ||
726
            VIR_STRDUP(network_driver->networkAutostartDir,
727
                       SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
728
            VIR_STRDUP(network_driver->stateDir,
729
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
730
            VIR_STRDUP(network_driver->pidDir,
731
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
732
            VIR_STRDUP(network_driver->dnsmasqStateDir,
733
                       LOCALSTATEDIR "/lib/libvirt/dnsmasq") < 0 ||
734
            VIR_STRDUP(network_driver->radvdStateDir,
735 736
                       LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
            goto error;
737
    } else {
738 739 740
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
741
            goto error;
742

743
        if ((virAsprintf(&network_driver->networkConfigDir,
744
                         "%s/qemu/networks", configdir) < 0) ||
745
            (virAsprintf(&network_driver->networkAutostartDir,
746
                         "%s/qemu/networks/autostart", configdir) < 0) ||
747
            (virAsprintf(&network_driver->stateDir,
748
                         "%s/network/lib", rundir) < 0) ||
749
            (virAsprintf(&network_driver->pidDir,
750
                         "%s/network/run", rundir) < 0) ||
751
            (virAsprintf(&network_driver->dnsmasqStateDir,
752
                         "%s/dnsmasq/lib", rundir) < 0) ||
753
            (virAsprintf(&network_driver->radvdStateDir,
754
                         "%s/radvd/lib", rundir) < 0)) {
755
            goto error;
756
        }
757 758
    }

759
    if (virFileMakePath(network_driver->stateDir) < 0) {
760 761
        virReportSystemError(errno,
                             _("cannot create directory %s"),
762
                             network_driver->stateDir);
763 764 765
        goto error;
    }

766 767 768 769 770
    if ((network_driver->lockFD =
         virPidFileAcquire(network_driver->stateDir, "driver",
                           true, getpid())) < 0)
        goto error;

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

774
    if (!(network_driver->networks = virNetworkObjListNew()))
775 776
        goto error;

777
    if (virNetworkObjLoadAllState(network_driver->networks,
778 779
                                  network_driver->stateDir,
                                  network_driver->xmlopt) < 0)
780 781
        goto error;

782 783
    if (virNetworkObjLoadAllConfigs(network_driver->networks,
                                    network_driver->networkConfigDir,
784 785
                                    network_driver->networkAutostartDir,
                                    network_driver->xmlopt) < 0)
786 787
        goto error;

788 789 790 791
    /* 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). */
792
    virNetworkObjListForEach(network_driver->networks,
793
                             networkUpdateState,
794 795
                             network_driver);
    virNetworkObjListPrune(network_driver->networks,
796 797
                           VIR_CONNECT_LIST_NETWORKS_INACTIVE |
                           VIR_CONNECT_LIST_NETWORKS_TRANSIENT);
798
    networkReloadFirewallRules(network_driver, true);
799
    networkRefreshDaemons(network_driver);
800

801 802 803 804
    virNetworkObjListForEach(network_driver->networks,
                             networkAutostartConfig,
                             network_driver);

805
    network_driver->networkEventState = virObjectEventStateNew();
806

807
#ifdef WITH_FIREWALLD
808 809
    if (!(sysbus = virDBusGetSystemBus())) {
        VIR_WARN("DBus not available, disabling firewalld support "
810
                 "in bridge_network_driver: %s", virGetLastErrorMessage());
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827
    } 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,
828
                                   network_driver, NULL);
829 830 831
    }
#endif

832
    ret = VIR_DRV_STATE_INIT_COMPLETE;
833
 cleanup:
834 835 836
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
837

838
 error:
839
    networkStateCleanup();
840
    goto cleanup;
841 842
}

843

844
/**
845
 * networkStateReload:
846
 *
J
Ján Tomko 已提交
847
 * Function to restart the QEMU daemon, it will recheck the configuration
848 849 850
 * files and update its state and the networking
 */
static int
851 852
networkStateReload(void)
{
853
    if (!network_driver)
854 855
        return 0;

856
    virNetworkObjLoadAllState(network_driver->networks,
857 858
                              network_driver->stateDir,
                              network_driver->xmlopt);
859 860
    virNetworkObjLoadAllConfigs(network_driver->networks,
                                network_driver->networkConfigDir,
861 862
                                network_driver->networkAutostartDir,
                                network_driver->xmlopt);
863
    networkReloadFirewallRules(network_driver, false);
864 865
    networkRefreshDaemons(network_driver);
    virNetworkObjListForEach(network_driver->networks,
866
                             networkAutostartConfig,
867
                             network_driver);
868 869 870 871 872
    return 0;
}


/**
873
 * networkStateCleanup:
874
 *
J
Ján Tomko 已提交
875
 * Shutdown the QEMU daemon, it will stop all active domains and networks
876 877
 */
static int
878 879
networkStateCleanup(void)
{
880
    if (!network_driver)
881 882
        return -1;

883
    virObjectUnref(network_driver->networkEventState);
C
Cole Robinson 已提交
884
    virObjectUnref(network_driver->xmlopt);
885

886
    /* free inactive networks */
887
    virObjectUnref(network_driver->networks);
888

889 890 891 892
    if (network_driver->lockFD != -1)
        virPidFileRelease(network_driver->stateDir, "driver",
                          network_driver->lockFD);

893 894 895 896 897 898
    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);
899

900
    virObjectUnref(network_driver->dnsmasqCaps);
901

902
    virMutexDestroy(&network_driver->lock);
903

904
    VIR_FREE(network_driver);
905 906 907 908 909

    return 0;
}


910 911 912 913 914 915 916 917
static virDrvOpenStatus
networkConnectOpen(virConnectPtr conn,
                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                   virConfPtr conf ATTRIBUTE_UNUSED,
                   unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

918 919 920 921 922 923 924 925 926 927 928
    if (network_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("network state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
    }

    if (network_driver->privileged) {
        if (STRNEQ(conn->uri->path, "/system")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected network URI path '%s', try network:///system"),
                           conn->uri->path);
929 930
            return VIR_DRV_OPEN_ERROR;
        }
931 932 933 934 935 936
    } else {
        if (STRNEQ(conn->uri->path, "/session")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected network URI path '%s', try network:///session"),
                           conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
        }
    }

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

    return VIR_DRV_OPEN_SUCCESS;
}

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


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


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


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


972 973 974 975 976
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
977 978 979
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
980
{
981 982
    size_t i;
    int ret = -1;
983 984 985 986 987 988 989
    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.
     */
990
    for (i = 0; i < 25; i++) {
991
        int signum = 0;
992
        if (i == 0) {
993
            signum = SIGTERM;
994
        } else if (i == 15) {
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
            signum = SIGKILL;
            signame = "KILL";
        }
        if (kill(pid, signum) < 0) {
            if (errno == ESRCH) {
                ret = 0;
            } else {
                char ebuf[1024];
                VIR_WARN("Failed to terminate %s process %d "
                         "for network '%s' with SIG%s: %s",
                         daemonName, pid, networkName, signame,
                         virStrerror(errno, ebuf, sizeof(ebuf)));
            }
            goto cleanup;
        }
        /* NB: since networks have no reference count like
         * domains, there is no safe way to unlock the network
         * object temporarily, and so we can't follow the
         * procedure used by the qemu driver of 1) unlock driver
         * 2) sleep, 3) add ref to object 4) unlock object, 5)
         * re-lock driver, 6) re-lock object. We may need to add
         * that functionality eventually, but for now this
         * function is rarely used and, at worst, leaving the
         * network driver locked during this loop of sleeps will
         * have the effect of holding up any other thread trying
         * to make modifications to a network for up to 5 seconds;
         * since modifications to networks are much less common
         * than modifications to domains, this seems a reasonable
         * tradeoff in exchange for less code disruption.
         */
        usleep(20 * 1000);
    }
    VIR_WARN("Timed out waiting after SIG%s to %s process %d "
             "(network '%s')",
             signame, daemonName, pid, networkName);
1030
 cleanup:
1031 1032 1033
    return ret;
}

1034

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

G
Gene Czarcinski 已提交
1045 1046
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
1047 1048
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
1049
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
1050 1051
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
1052
                return -1;
1053
    }
1054

G
Gene Czarcinski 已提交
1055 1056 1057
    return 0;
}

1058

G
Gene Czarcinski 已提交
1059 1060 1061 1062
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
1063
    size_t i, j;
G
Gene Czarcinski 已提交
1064

1065 1066
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
1067
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
1068
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
1069
                for (j = 0; j < host->nnames; j++)
1070 1071
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
1072 1073
            }
        }
1074 1075
    }

1076
    return 0;
1077 1078 1079
}


1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
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;
}


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

1135 1136
    *configstr = NULL;

1137
    /*
1138 1139 1140
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1141
     *
1142 1143
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1144
     */
1145 1146 1147 1148 1149 1150

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

1151
    /* create dnsmasq config file appropriate for this network */
1152 1153

    /* Don't forget to update networkxml2conftest :-) */
1154
    virBufferAsprintf(&configbuf,
1155 1156 1157 1158 1159 1160 1161
                      "##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"
1162
                      "strict-order\n",
1163
                      def->name);
1164

1165 1166 1167 1168 1169 1170
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1171
    if (wantDNS && def->dns.forwarders) {
1172 1173 1174 1175 1176 1177 1178 1179 1180
        /* 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;

1181 1182
        for (i = 0; i < def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &def->dns.forwarders[i];
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192

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

1205 1206
    if (def->domain) {
        if (def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1207 1208
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1209
                              def->domain);
1210
        }
1211
        virBufferAsprintf(&configbuf,
1212 1213
                          "domain=%s\n"
                          "expand-hosts\n",
1214
                          def->domain);
1215
    }
1216

1217
    if (wantDNS &&
1218
        networkDnsmasqConfLocalPTRs(&configbuf, def) < 0)
1219 1220
        goto cleanup;

1221
    if (wantDNS && def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1222 1223 1224 1225
        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)
1226
         */
1227
        virBufferAddLit(&configbuf, "local=//\n");
1228
    }
1229

1230
    if (pidfile)
1231
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1232

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

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

            if (!ipaddr)
                goto cleanup;
1270

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

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

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

1319 1320 1321 1322 1323
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1324
        }
1325

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

1350 1351 1352 1353 1354 1355 1356
            /* 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.
1357
             */
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
            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");
1378
        }
1379 1380
    }

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

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1439 1440
        int prefix;

1441
        prefix = virNetworkIPDefPrefix(ipdef);
1442 1443 1444
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1445
                           def->bridge);
1446 1447
            goto cleanup;
        }
1448
        for (r = 0; r < ipdef->nranges; r++) {
1449 1450
            int thisRange;

1451 1452
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1453
                goto cleanup;
1454

1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475
            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);
            }
1476

1477
            VIR_FREE(saddr);
1478
            VIR_FREE(eaddr);
1479
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1480 1481
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1482
                                              virNetworkIPDefPrefix(ipdef));
1483 1484 1485
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1486
        }
1487

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

G
Gene Czarcinski 已提交
1506 1507
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1508

G
Gene Czarcinski 已提交
1509 1510
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
1511
            if (ipdef->nranges || ipdef->nhosts) {
1512
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1513 1514
                virBufferAddLit(&configbuf, "dhcp-authoritative\n");
            }
1515

G
Gene Czarcinski 已提交
1516
            if (ipdef->tftproot) {
1517 1518
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1519
            }
1520

G
Gene Czarcinski 已提交
1521 1522 1523
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1524

1525
                    if (!bootserver)
G
Gene Czarcinski 已提交
1526
                        goto cleanup;
1527
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1528
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1529 1530
                    VIR_FREE(bootserver);
                } else {
1531
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1532 1533 1534 1535 1536
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1537

1538
    if (nbleases > 0)
1539
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1540

G
Gene Czarcinski 已提交
1541 1542
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1543
        goto cleanup;
G
Gene Czarcinski 已提交
1544 1545 1546 1547 1548 1549

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

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

1561 1562 1563 1564
    /* 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 已提交
1565 1566
    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
1567
        if (ipv6def) {
1568
            virBufferAddLit(&configbuf, "enable-ra\n");
1569
        } else {
1570
            for (i = 0;
1571
                 (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1572
                 i++) {
G
Gene Czarcinski 已提交
1573 1574 1575 1576
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1577 1578
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1579 1580
                    VIR_FREE(bridgeaddr);
                }
1581
            }
1582
        }
1583 1584
    }

1585 1586 1587 1588 1589 1590
    if (def->namespaceData) {
        networkDnsmasqXmlNsDefPtr dnsmasqxmlns = def->namespaceData;
        for (i = 0; i < dnsmasqxmlns->noptions; i++)
            virBufferAsprintf(&configbuf, "%s\n", dnsmasqxmlns->options[i]);
    }

1591 1592 1593
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1594
    ret = 0;
G
Gene Czarcinski 已提交
1595

1596
 cleanup:
1597 1598
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1599
    virBufferFreeAndReset(&configbuf);
1600
    return ret;
1601 1602
}

1603

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

1620
    virNetworkObjSetDnsmasqPid(obj, -1);
1621

1622
    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
1623
                                   dctx, dnsmasq_caps) < 0)
1624 1625 1626 1627 1628
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1629
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
1630 1631 1632 1633 1634
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1635 1636
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1637 1638 1639
        goto cleanup;
    }

1640 1641
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1642
                                                  abs_top_builddir "/src",
1643 1644 1645
                                                  LIBEXECDIR)))
        goto cleanup;

1646
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1647
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1648 1649
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1650
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1651
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", def->bridge);
1652

1653
    *cmdout = cmd;
1654
    ret = 0;
1655
 cleanup:
1656
    virObjectUnref(dnsmasq_caps);
1657 1658
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1659
    VIR_FREE(leaseshelper_path);
1660 1661 1662
    return ret;
}

1663

1664
static int
1665
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1666
                       virNetworkObjPtr obj)
1667
{
1668
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1669 1670 1671
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1672 1673
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
1674
    pid_t dnsmasqPid;
1675
    int ret = -1;
1676
    dnsmasqContext *dctx = NULL;
1677

1678
    /* see if there are any IP addresses that need a dhcp server */
1679
    i = 0;
1680
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i))) {
1681
        i++;
1682 1683 1684 1685
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1686 1687 1688 1689 1690 1691
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1692
    if (!needDnsmasq && def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1693
        /* no DHCP services needed, and user disabled DNS service */
1694 1695 1696 1697
        ret = 0;
        goto cleanup;
    }

1698
    if (virFileMakePath(driver->pidDir) < 0) {
1699
        virReportSystemError(errno,
1700
                             _("cannot create directory %s"),
1701
                             driver->pidDir);
1702
        goto cleanup;
1703 1704
    }

1705
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, def->name)))
1706
        goto cleanup;
1707

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

1715
    dctx = dnsmasqContextNew(def->name, driver->dnsmasqStateDir);
1716 1717 1718
    if (dctx == NULL)
        goto cleanup;

1719
    if (networkDnsmasqCapsRefresh(driver) < 0)
1720
        goto cleanup;
1721

1722
    ret = networkBuildDhcpDaemonCommandLine(driver, obj, &cmd, pidfile, dctx);
1723 1724 1725 1726 1727
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1728
        goto cleanup;
1729

G
Guido Günther 已提交
1730
    ret = virCommandRun(cmd, NULL);
1731
    if (ret < 0)
1732 1733 1734
        goto cleanup;

    /*
1735 1736 1737 1738 1739
     * 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
1740 1741
     */

1742
    ret = virPidFileRead(driver->pidDir, def->name, &dnsmasqPid);
1743
    if (ret < 0)
1744
        goto cleanup;
1745
    virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
1746

1747
    ret = 0;
1748
 cleanup:
1749
    VIR_FREE(pidfile);
1750
    virCommandFree(cmd);
1751
    dnsmasqContextFree(dctx);
1752 1753 1754
    return ret;
}

1755

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

G
Gene Czarcinski 已提交
1774
    /* if no IP addresses specified, nothing to do */
1775
    if (!virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1776 1777
        return 0;

1778
    /* if there's no running dnsmasq, just start it */
1779 1780
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid <= 0 || (kill(dnsmasqPid, 0) < 0))
1781
        return networkStartDhcpDaemon(driver, obj);
1782

1783 1784
    VIR_INFO("Refreshing dnsmasq for network %s", def->bridge);
    if (!(dctx = dnsmasqContextNew(def->name,
1785
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1786
        goto cleanup;
1787
    }
G
Gene Czarcinski 已提交
1788 1789 1790 1791 1792 1793

    /* 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;
1794
    for (i = 0;
1795
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
1796
         i++) {
G
Gene Czarcinski 已提交
1797 1798
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1799 1800
    }

G
Gene Czarcinski 已提交
1801
    ipv6def = NULL;
1802
    for (i = 0;
1803
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1804
         i++) {
G
Gene Czarcinski 已提交
1805 1806
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1807 1808
    }

G
Gene Czarcinski 已提交
1809
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1810
        goto cleanup;
G
Gene Czarcinski 已提交
1811 1812

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

1815
    if (networkBuildDnsmasqHostsList(dctx, &def->dns) < 0)
J
Ján Tomko 已提交
1816
        goto cleanup;
1817 1818

    if ((ret = dnsmasqSave(dctx)) < 0)
1819
        goto cleanup;
1820

1821 1822
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    ret = kill(dnsmasqPid, SIGHUP);
1823
 cleanup:
1824 1825 1826 1827
    dnsmasqContextFree(dctx);
    return ret;
}

1828

1829 1830 1831 1832 1833 1834 1835 1836
/* 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
1837
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1838
                         virNetworkObjPtr obj)
1839
{
1840
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1841 1842
    pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);

1843
    /* if there is a running dnsmasq, kill it */
1844
    if (dnsmasqPid > 0) {
1845
        networkKillDaemon(dnsmasqPid, "dnsmasq", def->name);
1846
        virNetworkObjSetDnsmasqPid(obj, -1);
1847
    }
1848
    /* now start dnsmasq if it should be started */
1849
    return networkStartDhcpDaemon(driver, obj);
1850 1851
}

1852

G
Gene Czarcinski 已提交
1853 1854 1855 1856 1857 1858
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";

1859
static int
1860
networkRadvdConfContents(virNetworkObjPtr obj,
1861
                         char **configstr)
1862
{
1863
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
E
Eric Blake 已提交
1864
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1865 1866
    int ret = -1;
    size_t i;
1867
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1868
    bool v6present = false, dhcp6 = false;
1869 1870

    *configstr = NULL;
1871

G
Gene Czarcinski 已提交
1872
    /* Check if DHCPv6 is needed */
1873
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
G
Gene Czarcinski 已提交
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886
        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;
    }

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

    /* add a section for each IPv6 address in the config */
1901
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
1902 1903 1904
        int prefix;
        char *netaddr;

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

1922
    virBufferAddLit(&configbuf, "};\n");
1923

1924
    if (virBufferCheckError(&configbuf) < 0)
1925
        goto cleanup;
1926

1927 1928
    *configstr = virBufferContentAndReset(&configbuf);

1929
    ret = 0;
1930
 cleanup:
1931 1932 1933 1934
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1935

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

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

1952
    if (networkRadvdConfContents(obj, &configStr) < 0)
1953 1954 1955 1956
        goto cleanup;

    if (!configStr) {
        ret = 0;
1957 1958 1959 1960
        goto cleanup;
    }

    /* construct the filename */
1961
    if (!(*configFile = networkRadvdConfigFileName(driver, def->name)))
1962 1963
        goto cleanup;
    /* write the file */
1964
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1965 1966
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1967 1968 1969 1970 1971
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1972
 cleanup:
1973 1974 1975 1976 1977
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

1978

1979
static int
1980
networkStartRadvd(virNetworkDriverStatePtr driver,
1981
                  virNetworkObjPtr obj)
1982
{
1983
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1984
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1985
    pid_t radvdPid;
1986 1987 1988 1989 1990 1991
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

1992
    virNetworkObjSetRadvdPid(obj, -1);
1993

G
Gene Czarcinski 已提交
1994
    /* Is dnsmasq handling RA? */
1995
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
1996 1997 1998 1999
        ret = 0;
        goto cleanup;
    }

2000
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
        /* 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);
2011 2012 2013
        goto cleanup;
    }

2014
    if (virFileMakePath(driver->pidDir) < 0) {
2015 2016
        virReportSystemError(errno,
                             _("cannot create directory %s"),
2017
                             driver->pidDir);
2018 2019
        goto cleanup;
    }
2020
    if (virFileMakePath(driver->radvdStateDir) < 0) {
2021 2022
        virReportSystemError(errno,
                             _("cannot create directory %s"),
2023
                             driver->radvdStateDir);
2024 2025 2026 2027
        goto cleanup;
    }

    /* construct pidfile name */
2028
    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
2029
        goto cleanup;
2030
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
2031 2032
        goto cleanup;

2033
    if (networkRadvdConfWrite(driver, obj, &configfile) < 0)
2034 2035
        goto cleanup;

2036 2037 2038 2039
    /* 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
2040
     * virPidFileRead() below will fail if we use them).
2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055
     * 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;

2056
    if (virPidFileRead(driver->pidDir, radvdpidbase, &radvdPid) < 0)
2057
        goto cleanup;
2058
    virNetworkObjSetRadvdPid(obj, radvdPid);
2059 2060

    ret = 0;
2061
 cleanup:
2062
    virObjectUnref(dnsmasq_caps);
2063 2064 2065 2066 2067 2068 2069
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

2070

2071
static int
2072
networkRefreshRadvd(virNetworkDriverStatePtr driver,
2073
                    virNetworkObjPtr obj)
2074
{
2075
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2076
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
2077
    char *radvdpidbase;
2078
    pid_t radvdPid;
G
Gene Czarcinski 已提交
2079 2080

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

2098
    /* if there's no running radvd, just start it */
2099 2100
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid <= 0 || (kill(radvdPid, 0) < 0))
2101
        return networkStartRadvd(driver, obj);
2102

2103
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2104 2105 2106 2107
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

2108
    if (networkRadvdConfWrite(driver, obj, NULL) < 0)
2109 2110
        return -1;

2111
    return kill(radvdPid, SIGHUP);
2112 2113
}

2114

2115 2116
#if 0
/* currently unused, so it causes a build error unless we #if it out */
2117
static int
2118
networkRestartRadvd(virNetworkObjPtr obj)
2119
{
2120
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2121
    char *radvdpidbase;
2122
    pid_t radvdPid = virNeworkObjGetRadvdPid(obj);
2123 2124

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

2143

2144
static int
2145
networkRefreshDaemonsHelper(virNetworkObjPtr obj,
2146
                            void *opaque)
2147
{
2148
    virNetworkDefPtr def;
2149
    virNetworkDriverStatePtr driver = opaque;
2150

2151
    virObjectLock(obj);
2152
    def = virNetworkObjGetDef(obj);
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180
    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;
        }
2181
    }
2182 2183

 cleanup:
2184
    virObjectUnlock(obj);
2185 2186 2187
    return 0;
}

2188

2189 2190 2191 2192
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2193
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2194 2195
{
    VIR_INFO("Refreshing network daemons");
2196 2197
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2198
                             driver);
2199
}
2200

2201

2202
static int
2203
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
2204 2205
                                 void *opaque ATTRIBUTE_UNUSED)
{
2206
    virNetworkDefPtr def;
2207

2208
    virObjectLock(obj);
2209
    def = virNetworkObjGetDef(obj);
2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235
    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;
2236 2237
        }
    }
2238 2239

 cleanup:
2240
    virObjectUnlock(obj);
2241
    return 0;
2242 2243
}

2244

2245
static void
2246
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup)
2247
{
2248
    VIR_INFO("Reloading iptables rules");
2249 2250 2251 2252
    /* 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;
2253
    networkPreReloadFirewallRules(driver, startup);
2254 2255 2256
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2257
    networkPostReloadFirewallRules(startup);
2258 2259
}

2260

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

2281
#endif
2282
    return ret;
2283 2284
}

2285

2286
static int
2287
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2288
{
2289
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2290 2291
    char *field = NULL;
    int ret = -1;
2292
    bool enableIPv6 = !!virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2293

2294 2295 2296 2297 2298
    /* 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",
2299
                    def->bridge) < 0)
2300
       goto cleanup;
2301

2302 2303
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2304
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2305
                      def->bridge);
2306 2307 2308
        ret = 0;
        goto cleanup;
    }
2309

2310 2311 2312
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2313
                               "on bridge %s"), field, def->bridge);
2314
        goto cleanup;
2315
    }
2316
    VIR_FREE(field);
2317

2318 2319
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2320 2321 2322 2323 2324 2325
     */

    /* 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",
2326
                    def->bridge) < 0)
2327 2328
        goto cleanup;

2329
    if (virFileWriteStr(field, "0", 0) < 0) {
2330
        virReportSystemError(errno,
2331 2332 2333 2334 2335
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

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

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

    ret = 0;
2350
 cleanup:
2351 2352 2353 2354
    VIR_FREE(field);
    return ret;
}

2355

2356
/* add an IP address to a bridge */
2357
static int
2358
networkAddAddrToBridge(virNetworkObjPtr obj,
2359
                       virNetworkIPDefPtr ipdef)
2360
{
2361
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2362
    int prefix = virNetworkIPDefPrefix(ipdef);
2363 2364

    if (prefix < 0) {
2365 2366
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2367
                       def->bridge);
2368 2369 2370
        return -1;
    }

2371
    if (virNetDevIPAddrAdd(def->bridge, &ipdef->address, NULL, prefix) < 0)
2372 2373 2374 2375 2376
        return -1;

    return 0;
}

2377 2378

static int
2379
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2380 2381
                                      const char *macTapIfName)
{
2382 2383
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    const char *brname = def->bridge;
2384 2385

    if (brname &&
2386
        def->macTableManager == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399
        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;
}


2400 2401
/* add an IP (static) route to a bridge */
static int
2402
networkAddRouteToBridge(virNetworkObjPtr obj,
2403
                        virNetDevIPRoutePtr routedef)
2404
{
2405
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2406 2407 2408 2409
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2410 2411 2412 2413 2414

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

2419
    if (virNetDevIPRouteAdd(def->bridge, addr, prefix, gateway, metric) < 0)
2420
        return -1;
2421

2422 2423 2424
    return 0;
}

2425
static int
2426
networkWaitDadFinish(virNetworkObjPtr obj)
2427
{
2428
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2429
    virNetworkIPDefPtr ipdef;
2430 2431 2432 2433
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

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

2436
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, naddrs))) {
2437 2438 2439 2440 2441
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2442
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2443 2444 2445 2446

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

2451

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

2470
    /* Check to see if any network IP collides with an existing route */
2471
    if (networkCheckRouteCollision(def) < 0)
2472 2473
        return -1;

2474
    /* Create and configure the bridge device */
2475
    if (!def->bridge) {
2476 2477 2478 2479 2480 2481 2482 2483 2484 2485
        /* 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"),
2486
                       def->name);
2487 2488
        return -1;
    }
2489
    if (virNetDevBridgeCreate(def->bridge) < 0)
2490 2491
        return -1;

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

2515
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
2516
                                         def->bridge)) ||
2517
        !(macmap = virMacMapNew(macMapFile)))
2518
        goto error;
M
Michal Privoznik 已提交
2519

2520
    virNetworkObjSetMacMap(obj, macmap);
2521
    macmap = NULL;
2522

2523
    /* Set bridge options */
2524 2525 2526 2527

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

2531
    if (virNetDevBridgeSetSTP(def->bridge, def->stp ? true : false) < 0)
2532
        goto error;
2533

2534 2535 2536
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2537
    if (networkSetIPv6Sysctls(obj) < 0)
2538
        goto error;
2539

2540
    /* Add "once per network" rules */
2541 2542
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(def) < 0)
2543
        goto error;
2544

2545 2546
    firewalRulesAdded = true;

2547
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i)); i++) {
2548
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2549
            v4present = true;
2550
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2551
            v6present = true;
2552

2553
        /* Add the IP address/netmask to the bridge */
2554
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2555
            goto error;
2556 2557
    }

2558
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2559
        goto error;
2560

2561
    /* Bring up the bridge interface */
2562
    if (virNetDevSetOnline(def->bridge, 1) < 0)
2563
        goto error;
2564

2565 2566
    devOnline = true;

2567
    for (i = 0; i < def->nroutes; i++) {
2568 2569
        virSocketAddrPtr gateway = NULL;

2570
        routedef = def->routes[i];
2571
        gateway = virNetDevIPRouteGetGateway(routedef);
2572

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

2584
    /* If forward.type != NONE, turn on global IP forwarding */
2585
    if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2586
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2587
            goto error; /* Precise error message already provided */
2588 2589 2590 2591

        if (networkEnableIPForwarding(v4present, v6present) < 0) {
            virReportSystemError(errno, "%s",
                                 _("failed to enable IP forwarding"));
2592
            goto error;
2593
        }
2594 2595
    }

2596

2597
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2598
    if ((v4present || v6present) &&
2599
        networkStartDhcpDaemon(driver, obj) < 0)
2600
        goto error;
2601

2602 2603
    dnsmasqStarted = true;

2604
    /* start radvd if there are any ipv6 addresses */
2605
    if (v6present && networkStartRadvd(driver, obj) < 0)
2606
        goto error;
2607

2608 2609 2610
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2611
    if (v6present && networkWaitDadFinish(obj) < 0)
2612
        goto error;
2613 2614 2615

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2616 2617 2618
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
2619
            goto error;
2620 2621 2622
        VIR_FORCE_CLOSE(tapfd);
    }

2623
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
2624
        goto error;
2625

2626
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2627
    VIR_FREE(macMapFile);
2628 2629 2630

    return 0;

2631
 error:
2632
    virErrorPreserveLast(&save_err);
2633 2634
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
2635

2636 2637
    if (dnsmasqStarted) {
        pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
2638 2639
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2640 2641
    }

2642 2643
    if (devOnline)
        ignore_value(virNetDevSetOnline(def->bridge, 0));
2644

2645 2646
    if (firewalRulesAdded &&
        def->forward.type != VIR_NETWORK_FORWARD_OPEN)
2647
        networkRemoveFirewallRules(def);
2648

H
Hu Tao 已提交
2649
    if (macTapIfName) {
2650
        VIR_FORCE_CLOSE(tapfd);
2651
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2652 2653
        VIR_FREE(macTapIfName);
    }
2654
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2655
    VIR_FREE(macMapFile);
2656

2657
    ignore_value(virNetDevBridgeDelete(def->bridge));
2658

2659
    virErrorRestore(&save_err);
2660
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2661 2662 2663
    return -1;
}

2664

2665 2666
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2667
                              virNetworkObjPtr obj)
2668
{
2669
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2670 2671 2672
    pid_t radvdPid;
    pid_t dnsmasqPid;

2673 2674
    if (def->bandwidth)
        virNetDevBandwidthClear(def->bridge);
2675

2676
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2677

2678 2679
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2680 2681
        char *radvdpidbase;

2682
        kill(radvdPid, SIGTERM);
2683
        /* attempt to delete the pidfile we created */
2684
        if ((radvdpidbase = networkRadvdPidfileBasename(def->name))) {
2685
            virPidFileDelete(driver->pidDir, radvdpidbase);
2686 2687 2688 2689
            VIR_FREE(radvdpidbase);
        }
    }

2690 2691 2692
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2693

2694 2695
    if (def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(def->bridge);
2696
        if (macTapIfName) {
2697
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2698 2699 2700 2701
            VIR_FREE(macTapIfName);
        }
    }

2702
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2703

2704 2705
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2706

2707
    ignore_value(virNetDevBridgeDelete(def->bridge));
2708

2709
    /* See if its still alive and really really kill it */
2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720
    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);
2721

2722 2723 2724
    return 0;
}

2725

2726
static int
2727
networkStartNetworkBridge(virNetworkObjPtr obj)
2728 2729 2730 2731 2732
{
    /* 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.
     */
2733
    return networkStartHandleMACTableManagerMode(obj, NULL);
2734 2735
}

2736

2737
static int
2738
networkShutdownNetworkBridge(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2739 2740 2741 2742 2743 2744 2745 2746 2747
{
    /* put anything here that needs to be done each time a network of
     * type BRIDGE is shutdown. On failure, undo anything you've done,
     * and return -1. On success return 0.
     */
    return 0;
}


2748 2749 2750 2751 2752 2753 2754 2755 2756
/* 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;
2757
    unsigned int maxVirtFns = 0;
2758 2759 2760 2761 2762 2763
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2764 2765 2766
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2767 2768
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783
        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];

2784
        switch ((virNetworkForwardType) netdef->forward.type) {
2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814
        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:
2815
        case VIR_NETWORK_FORWARD_OPEN:
2816 2817
            /* by definition these will never be encountered here */
            break;
2818 2819 2820 2821 2822

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
            goto cleanup;
2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859
        }
    }

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


2860
static int
2861
networkStartNetworkExternal(virNetworkObjPtr obj)
2862 2863
{
    /* put anything here that needs to be done each time a network of
2864
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2865 2866 2867
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2868
    return networkCreateInterfacePool(virNetworkObjGetDef(obj));
2869 2870
}

2871 2872

static int
2873
networkShutdownNetworkExternal(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2874 2875
{
    /* put anything here that needs to be done each time a network of
2876
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2877 2878 2879 2880 2881 2882
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2883

2884
static int
2885
networkStartNetwork(virNetworkDriverStatePtr driver,
2886
                    virNetworkObjPtr obj)
2887
{
2888
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2889 2890
    int ret = -1;

2891
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2892

2893
    if (virNetworkObjIsActive(obj)) {
2894 2895
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2896
        return ret;
2897 2898
    }

2899 2900
    VIR_DEBUG("Beginning network startup process");

2901 2902
    virNetworkObjDeleteAllPorts(obj, driver->stateDir);

2903
    VIR_DEBUG("Setting current network def as transient");
2904
    if (virNetworkObjSetDefTransient(obj, true, network_driver->xmlopt) < 0)
2905
        goto cleanup;
2906

2907 2908
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2909
    if (networkRunHook(obj, NULL,
2910 2911 2912 2913
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2914
    switch ((virNetworkForwardType) def->forward.type) {
2915 2916 2917 2918

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2919
    case VIR_NETWORK_FORWARD_OPEN:
2920
        if (networkStartNetworkVirtual(driver, obj) < 0)
2921
            goto cleanup;
2922 2923 2924
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2925
        if (def->bridge) {
2926
            if (networkStartNetworkBridge(obj) < 0)
2927 2928 2929 2930 2931 2932 2933
                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).
         */
2934 2935
        ATTRIBUTE_FALLTHROUGH;

2936 2937 2938
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2939
    case VIR_NETWORK_FORWARD_HOSTDEV:
2940
        if (networkStartNetworkExternal(obj) < 0)
2941
            goto cleanup;
2942
        break;
2943 2944 2945 2946 2947

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

2950 2951
    virNetworkObjSetFloorSum(obj, 0);

2952
    /* finally we can call the 'started' hook script if any */
2953
    if (networkRunHook(obj, NULL,
2954 2955 2956 2957
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2958 2959 2960
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2961
    VIR_DEBUG("Writing network status to disk");
2962 2963
    if (virNetworkObjSaveStatus(driver->stateDir,
                                obj, network_driver->xmlopt) < 0)
2964
        goto cleanup;
2965

2966
    virNetworkObjSetActive(obj, true);
2967
    VIR_INFO("Network '%s' started up", def->name);
2968
    ret = 0;
2969

2970
 cleanup:
2971
    if (ret < 0) {
2972 2973 2974
        virErrorPtr save_err;

        virErrorPreserveLast(&save_err);
2975 2976
        virNetworkObjUnsetDefTransient(obj);
        networkShutdownNetwork(driver, obj);
2977
        virErrorRestore(&save_err);
2978 2979 2980 2981
    }
    return ret;
}

2982

2983 2984
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
2985
                       virNetworkObjPtr obj)
2986
{
2987
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2988 2989 2990
    int ret = 0;
    char *stateFile;

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

2993
    if (!virNetworkObjIsActive(obj))
2994 2995
        return 0;

2996
    stateFile = virNetworkConfigFile(driver->stateDir, def->name);
2997 2998 2999 3000 3001 3002
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

3003
    switch ((virNetworkForwardType) def->forward.type) {
3004 3005 3006 3007

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
3008
    case VIR_NETWORK_FORWARD_OPEN:
3009
        ret = networkShutdownNetworkVirtual(driver, obj);
3010 3011 3012
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3013
        if (def->bridge) {
3014
            ret = networkShutdownNetworkBridge(obj);
3015 3016 3017 3018 3019 3020
            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).
         */
3021 3022
        ATTRIBUTE_FALLTHROUGH;

3023 3024 3025
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
3026
    case VIR_NETWORK_FORWARD_HOSTDEV:
3027
        ret = networkShutdownNetworkExternal(obj);
3028
        break;
3029 3030 3031 3032 3033

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

3036
    /* now that we know it's stopped call the hook if present */
3037
    networkRunHook(obj, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
3038 3039
                   VIR_HOOK_SUBOP_END);

3040
    virNetworkObjSetActive(obj, false);
3041
    virNetworkObjUnsetDefTransient(obj);
3042
    return ret;
3043 3044 3045
}


3046 3047 3048
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
3049
{
3050
    virNetworkDriverStatePtr driver = networkGetDriver();
3051
    virNetworkObjPtr obj;
3052
    virNetworkDefPtr def;
3053
    virNetworkPtr net = NULL;
3054

3055 3056
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
3057 3058
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
3059
        virReportError(VIR_ERR_NO_NETWORK,
3060 3061
                       _("no network with matching uuid '%s'"),
                       uuidstr);
3062
        goto cleanup;
3063
    }
3064
    def = virNetworkObjGetDef(obj);
3065

3066
    if (virNetworkLookupByUUIDEnsureACL(conn, def) < 0)
3067 3068
        goto cleanup;

3069
    net = virGetNetwork(conn, def->name, def->uuid);
3070

3071
 cleanup:
3072 3073
    virNetworkObjEndAPI(&obj);
    return net;
3074 3075
}

3076 3077 3078 3079

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
3080
{
3081
    virNetworkDriverStatePtr driver = networkGetDriver();
3082
    virNetworkObjPtr obj;
3083
    virNetworkDefPtr def;
3084
    virNetworkPtr net = NULL;
3085

3086 3087
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
3088 3089
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
3090
        goto cleanup;
3091
    }
3092
    def = virNetworkObjGetDef(obj);
3093

3094
    if (virNetworkLookupByNameEnsureACL(conn, def) < 0)
3095 3096
        goto cleanup;

3097
    net = virGetNetwork(conn, def->name, def->uuid);
3098

3099
 cleanup:
3100 3101
    virNetworkObjEndAPI(&obj);
    return net;
3102 3103
}

3104 3105 3106

static int
networkConnectNumOfNetworks(virConnectPtr conn)
3107
{
3108
    virNetworkDriverStatePtr driver = networkGetDriver();
3109
    int nactive;
3110

3111 3112 3113
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

3114 3115 3116 3117
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
3118

3119 3120 3121
    return nactive;
}

3122 3123 3124 3125

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
3126
                           int maxnames)
3127 3128
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3129
    int got = 0;
3130

3131 3132 3133
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

3134
    got = virNetworkObjListGetNames(driver->networks,
3135
                                    true, names, maxnames,
3136 3137
                                    virConnectListNetworksCheckACL,
                                    conn);
3138

3139 3140 3141
    return got;
}

3142 3143 3144

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
3145
{
3146
    virNetworkDriverStatePtr driver = networkGetDriver();
3147
    int ninactive = 0;
3148

3149 3150 3151
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3152 3153 3154 3155
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
3156

3157 3158 3159
    return ninactive;
}

3160 3161 3162 3163

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
3164
                                  int maxnames)
3165 3166
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3167
    int got = 0;
3168

3169 3170 3171
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3172
    got = virNetworkObjListGetNames(driver->networks,
3173
                                    false, names, maxnames,
3174 3175
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
3176 3177 3178
    return got;
}

3179

3180
static int
3181 3182 3183
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
3184
{
3185
    virNetworkDriverStatePtr driver = networkGetDriver();
3186 3187 3188 3189
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

3190 3191 3192
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

3193
    ret = virNetworkObjListExport(conn, driver->networks, nets,
3194 3195
                                  virConnectListAllNetworksCheckACL,
                                  flags);
3196

3197
 cleanup:
3198 3199
    return ret;
}
3200

3201

3202 3203 3204 3205 3206 3207 3208 3209
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3210
    virNetworkDriverStatePtr driver = networkGetDriver();
3211 3212 3213 3214 3215 3216
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3217
                                       net, eventID, callback,
3218 3219 3220
                                       opaque, freecb, &ret) < 0)
        ret = -1;

3221
 cleanup:
3222 3223 3224
    return ret;
}

3225

3226 3227 3228 3229
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3230
    virNetworkDriverStatePtr driver = networkGetDriver();
3231 3232 3233 3234 3235
    int ret = -1;

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

3236 3237
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3238
                                        callbackID, true) < 0)
3239 3240 3241
        goto cleanup;

    ret = 0;
3242

3243
 cleanup:
3244 3245 3246
    return ret;
}

3247 3248 3249

static int
networkIsActive(virNetworkPtr net)
3250 3251 3252 3253
{
    virNetworkObjPtr obj;
    int ret = -1;

3254 3255
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3256

3257
    if (virNetworkIsActiveEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3258 3259
        goto cleanup;

3260 3261
    ret = virNetworkObjIsActive(obj);

3262
 cleanup:
3263
    virNetworkObjEndAPI(&obj);
3264 3265 3266
    return ret;
}

3267 3268 3269

static int
networkIsPersistent(virNetworkPtr net)
3270 3271 3272 3273
{
    virNetworkObjPtr obj;
    int ret = -1;

3274 3275
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3276

3277
    if (virNetworkIsPersistentEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3278 3279
        goto cleanup;

3280
    ret = virNetworkObjIsPersistent(obj);
3281

3282
 cleanup:
3283
    virNetworkObjEndAPI(&obj);
3284 3285 3286 3287
    return ret;
}


3288 3289
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
3290 3291 3292
 * 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.
3293 3294 3295 3296 3297 3298 3299
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{
    int ret = -1, id = 0;
    char *newname = NULL;
3300 3301 3302 3303 3304
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3305
        p && p[1] == 'd')
3306
        templ = def->bridge;
3307 3308 3309 3310

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3311 3312 3313 3314 3315
        /* 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).
         */
3316
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3317
              virNetDevExists(newname) == 1)) {
3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350
            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")) {
3351
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368
            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;
}


3369
static int
3370
networkValidate(virNetworkDriverStatePtr driver,
3371
                virNetworkDefPtr def)
3372
{
3373
    size_t i, j;
3374 3375
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3376
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3377
    bool ipv4def = false, ipv6def = false;
3378
    bool bandwidthAllowed = false;
3379
    bool usesInterface = false, usesAddress = false;
3380

3381 3382 3383
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3384 3385 3386
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3387 3388 3389 3390 3391
    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:
3392 3393 3394 3395
        /* 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)
3396 3397 3398
            return -1;

        virNetworkSetBridgeMacAddr(def);
3399
        bandwidthAllowed = true;
3400 3401 3402
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3403 3404 3405 3406 3407
        if (def->bridge != NULL)
            bandwidthAllowed = true;

        ATTRIBUTE_FALLTHROUGH;

3408 3409 3410 3411
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
    case VIR_NETWORK_FORWARD_HOSTDEV:
3412
        /* They are also the only types that currently support setting
3413 3414
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
3415
         */
3416 3417 3418 3419 3420 3421 3422 3423
        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;
        }
3424
        if (virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0)) {
3425 3426 3427 3428
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3429
                           virNetworkForwardTypeToString(def->forward.type));
3430 3431
            return -1;
        }
3432
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
3433 3434 3435 3436
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3437
                           virNetworkForwardTypeToString(def->forward.type));
3438 3439 3440 3441 3442 3443 3444
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3445
                           virNetworkForwardTypeToString(def->forward.type));
3446 3447
            return -1;
        }
3448 3449 3450 3451 3452 3453
        break;

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

3456 3457 3458 3459 3460 3461 3462 3463 3464 3465
    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;
    }

3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478
    /* 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++) {
3479 3480 3481
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

3482
        switch ((virNetworkForwardHostdevDeviceType)iface->type) {
3483 3484
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495

            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;
            }
3496
            break;
3497 3498

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3499
            usesAddress = true;
3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524

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

3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540
        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 已提交
3541 3542 3543
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
3544
    for (i = 0;
3545
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
3546
         i++) {
G
Gene Czarcinski 已提交
3547 3548 3549 3550 3551
        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 -- "
3552 3553
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570
                    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;
                }
3571 3572 3573
            }
        }
    }
3574 3575 3576 3577 3578 3579

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

3580 3581 3582
    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 已提交
3583 3584
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3585
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3586 3587

    vlanUsed = def->vlan.nTags > 0;
3588 3589
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
3590 3591 3592 3593 3594
            /* 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.
             */
3595
            if (def->portGroups[i].virtPortProfile) {
3596
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
3597
                    def->portGroups[i].virtPortProfile->virtPortType
3598 3599 3600 3601 3602 3603 3604
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
3605
        }
3606
        if (def->portGroups[i].isDefault) {
3607 3608 3609 3610 3611
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
3612
                               def->name, defaultPortGroup->name,
3613
                               def->portGroups[i].name);
3614
                return -1;
3615
            }
3616
            defaultPortGroup = &def->portGroups[i];
3617
        }
3618 3619 3620 3621 3622 3623 3624 3625 3626
        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;
            }
        }
3627 3628 3629 3630 3631 3632 3633 3634
        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;
        }
3635
    }
3636 3637 3638 3639 3640 3641 3642
    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.
         */
3643 3644 3645 3646 3647 3648
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662

    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;
            }
        }
    }
3663 3664 3665
    return 0;
}

3666 3667 3668 3669

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3670
{
3671
    virNetworkDriverStatePtr driver = networkGetDriver();
3672
    virNetworkDefPtr newDef;
3673
    virNetworkObjPtr obj = NULL;
3674
    virNetworkDefPtr def;
3675
    virNetworkPtr net = NULL;
3676
    virObjectEventPtr event = NULL;
3677

3678
    if (!(newDef = virNetworkDefParseString(xml, network_driver->xmlopt)))
3679
        goto cleanup;
3680

3681
    if (virNetworkCreateXMLEnsureACL(conn, newDef) < 0)
3682 3683
        goto cleanup;

3684
    if (networkValidate(driver, newDef) < 0)
J
Ján Tomko 已提交
3685
        goto cleanup;
3686

3687 3688 3689
    /* 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.
3690
     */
3691
    if (!(obj = virNetworkObjAssignDef(driver->networks, newDef,
3692 3693
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3694
        goto cleanup;
3695 3696
    newDef = NULL;
    def = virNetworkObjGetDef(obj);
3697

3698 3699
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3700
        goto cleanup;
3701 3702
    }

3703 3704
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3705 3706
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3707

3708 3709
    VIR_INFO("Creating network '%s'", def->name);
    net = virGetNetwork(conn, def->name, def->uuid);
3710

3711
 cleanup:
3712
    virNetworkDefFree(newDef);
3713
    virObjectEventStateQueue(driver->networkEventState, event);
3714 3715
    virNetworkObjEndAPI(&obj);
    return net;
3716 3717
}

3718 3719 3720 3721

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3722
{
3723
    virNetworkDriverStatePtr driver = networkGetDriver();
3724
    virNetworkDefPtr def = NULL;
3725
    bool freeDef = true;
3726 3727
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3728
    virObjectEventPtr event = NULL;
3729

3730
    if (!(def = virNetworkDefParseString(xml, network_driver->xmlopt)))
3731
        goto cleanup;
3732

3733 3734 3735
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3736
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3737
        goto cleanup;
3738

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

3742
    /* def was assigned to network object */
3743
    freeDef = false;
3744

3745 3746
    if (virNetworkSaveConfig(driver->networkConfigDir,
                             def, network_driver->xmlopt) < 0) {
3747 3748
        if (!virNetworkObjIsActive(obj)) {
            virNetworkObjRemoveInactive(driver->networks, obj);
3749 3750
            goto cleanup;
        }
3751 3752 3753 3754
        /* if network was active already, just undo new persistent
         * definition by making it transient.
         * XXX - this isn't necessarily the correct thing to do.
         */
3755
        virNetworkObjUpdateAssignDef(obj, NULL, false);
3756 3757 3758
        goto cleanup;
    }

3759
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3760 3761
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3762

3763
    VIR_INFO("Defining network '%s'", def->name);
3764
    net = virGetNetwork(conn, def->name, def->uuid);
3765

3766
 cleanup:
3767
    virObjectEventStateQueue(driver->networkEventState, event);
3768
    if (freeDef)
J
Ján Tomko 已提交
3769
        virNetworkDefFree(def);
3770 3771
    virNetworkObjEndAPI(&obj);
    return net;
3772 3773
}

3774

3775
static int
3776 3777
networkUndefine(virNetworkPtr net)
{
3778
    virNetworkDriverStatePtr driver = networkGetDriver();
3779
    virNetworkObjPtr obj;
3780
    virNetworkDefPtr def;
3781
    int ret = -1;
3782
    bool active = false;
3783
    virObjectEventPtr event = NULL;
3784

3785
    if (!(obj = networkObjFromNetwork(net)))
3786
        goto cleanup;
3787
    def = virNetworkObjGetDef(obj);
3788

3789
    if (virNetworkUndefineEnsureACL(net->conn, def) < 0)
3790 3791
        goto cleanup;

3792
    if (virNetworkObjIsActive(obj))
3793
        active = true;
3794

3795
    if (!virNetworkObjIsPersistent(obj)) {
3796 3797 3798 3799 3800
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3801
    /* remove autostart link */
3802 3803
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3804
                                  obj) < 0)
3805
        goto cleanup;
3806

3807 3808
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3809 3810
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3811

3812
    VIR_INFO("Undefining network '%s'", def->name);
3813
    if (!active) {
3814
        if (networkRemoveInactive(driver, obj) < 0)
3815
            goto cleanup;
3816 3817 3818 3819 3820
    } else {

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

3824
    ret = 0;
3825

3826
 cleanup:
3827
    virObjectEventStateQueue(driver->networkEventState, event);
3828
    virNetworkObjEndAPI(&obj);
3829
    return ret;
3830 3831
}

3832

3833 3834 3835 3836 3837 3838 3839 3840
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3841
    virNetworkDriverStatePtr driver = networkGetDriver();
3842
    virNetworkObjPtr obj = NULL;
3843
    virNetworkDefPtr def;
3844 3845
    int isActive, ret = -1;
    size_t i;
3846
    virNetworkIPDefPtr ipdef;
3847
    bool oldDhcpActive = false;
3848
    bool needFirewallRefresh = false;
3849

3850 3851 3852 3853 3854

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3855
    if (!(obj = networkObjFromNetwork(net)))
3856
        goto cleanup;
3857
    def = virNetworkObjGetDef(obj);
3858

3859
    if (virNetworkUpdateEnsureACL(net->conn, def, flags) < 0)
3860 3861
        goto cleanup;

3862
    /* see if we are listening for dhcp pre-modification */
3863
    for (i = 0;
3864
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3865
         i++) {
3866 3867 3868 3869 3870 3871
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3872 3873
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3874
     */
3875
    isActive = virNetworkObjIsActive(obj);
3876 3877
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3878 3879 3880 3881 3882 3883 3884
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3885 3886 3887 3888
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
3889 3890 3891 3892
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
3893 3894 3895 3896 3897 3898 3899 3900 3901 3902
            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).
                 */
3903 3904
                networkRemoveFirewallRules(def);
                needFirewallRefresh = true;
3905 3906 3907 3908
                break;
            default:
                break;
            }
3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922
            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;
3923 3924 3925
        }
    }

3926
    /* update the network config in memory/on disk */
3927 3928 3929
    if (virNetworkObjUpdate(obj, command, section,
                            parentIndex, xml,
                            network_driver->xmlopt, flags) < 0) {
3930
        if (needFirewallRefresh)
3931
            ignore_value(networkAddFirewallRules(def));
3932 3933 3934
        goto cleanup;
    }

3935 3936 3937 3938
    /* @def is replaced */
    def = virNetworkObjGetDef(obj);

    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
3939 3940 3941 3942 3943
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
3944 3945
                                 virNetworkObjGetPersistentDef(obj),
                                 network_driver->xmlopt) < 0) {
3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958
            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 ||
3959 3960 3961 3962 3963 3964 3965 3966
            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)
3967
             */
3968
            if (networkRestartDhcpDaemon(driver, obj) < 0)
3969 3970
                goto cleanup;

3971 3972 3973 3974 3975 3976 3977 3978
        } 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;

3979
            for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3980
                 i++) {
3981 3982 3983 3984 3985 3986 3987
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3988 3989
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
3990 3991 3992
                goto cleanup;
            }

3993 3994 3995 3996
        } 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.
3997
             */
3998
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
3999 4000 4001 4002 4003 4004 4005 4006
                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.
             */
4007
            if (networkRefreshRadvd(driver, obj) < 0)
4008 4009 4010 4011
                goto cleanup;
        }

        /* save current network state to disk */
4012 4013
        if ((ret = virNetworkObjSaveStatus(driver->stateDir,
                                           obj, network_driver->xmlopt)) < 0)
4014 4015
            goto cleanup;
    }
4016 4017

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

4022
    ret = 0;
4023
 cleanup:
4024
    virNetworkObjEndAPI(&obj);
4025 4026 4027
    return ret;
}

4028 4029 4030

static int
networkCreate(virNetworkPtr net)
4031
{
4032
    virNetworkDriverStatePtr driver = networkGetDriver();
4033
    virNetworkObjPtr obj;
4034
    virNetworkDefPtr def;
4035
    int ret = -1;
4036
    virObjectEventPtr event = NULL;
4037

4038
    if (!(obj = networkObjFromNetwork(net)))
4039
        goto cleanup;
4040
    def = virNetworkObjGetDef(obj);
4041

4042
    if (virNetworkCreateEnsureACL(net->conn, def) < 0)
4043 4044
        goto cleanup;

4045
    if ((ret = networkStartNetwork(driver, obj)) < 0)
4046
        goto cleanup;
4047

4048 4049
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
4050 4051
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
4052

4053
 cleanup:
4054
    virObjectEventStateQueue(driver->networkEventState, event);
4055
    virNetworkObjEndAPI(&obj);
4056
    return ret;
4057 4058
}

4059 4060 4061

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

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

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

4076
    if (!virNetworkObjIsActive(obj)) {
4077
        virReportError(VIR_ERR_OPERATION_INVALID,
4078
                       _("network '%s' is not active"),
4079
                       def->name);
4080 4081 4082
        goto cleanup;
    }

4083
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
4084
        goto cleanup;
4085 4086 4087

    virNetworkObjDeleteAllPorts(obj, driver->stateDir);

4088 4089
    /* @def replaced in virNetworkObjUnsetDefTransient*/
    def = virNetworkObjGetDef(obj);
4090

4091 4092
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
4093 4094
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
4095

4096 4097
    if (!virNetworkObjIsPersistent(obj) &&
        networkRemoveInactive(driver, obj) < 0) {
4098 4099
        ret = -1;
        goto cleanup;
4100
    }
4101

4102
 cleanup:
4103
    virObjectEventStateQueue(driver->networkEventState, event);
4104
    virNetworkObjEndAPI(&obj);
4105 4106 4107
    return ret;
}

4108 4109 4110 4111

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
4112
{
4113
    virNetworkObjPtr obj;
4114
    virNetworkDefPtr curDef;
4115
    virNetworkDefPtr def;
4116
    virNetworkDefPtr newDef;
4117
    char *ret = NULL;
4118

4119
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
4120

4121
    if (!(obj = networkObjFromNetwork(net)))
4122
        return ret;
4123 4124
    def = virNetworkObjGetDef(obj);
    newDef = virNetworkObjGetNewDef(obj);
4125

4126
    if (virNetworkGetXMLDescEnsureACL(net->conn, def) < 0)
4127 4128
        goto cleanup;

4129 4130
    if ((flags & VIR_NETWORK_XML_INACTIVE) && newDef)
        curDef = newDef;
4131
    else
4132
        curDef = def;
4133

4134
    ret = virNetworkDefFormat(curDef, network_driver->xmlopt, flags);
4135

4136
 cleanup:
4137
    virNetworkObjEndAPI(&obj);
4138
    return ret;
4139 4140
}

4141 4142 4143 4144

static char *
networkGetBridgeName(virNetworkPtr net)
{
4145
    virNetworkObjPtr obj;
4146
    virNetworkDefPtr def;
4147 4148
    char *bridge = NULL;

4149
    if (!(obj = networkObjFromNetwork(net)))
4150
        return bridge;
4151
    def = virNetworkObjGetDef(obj);
4152

4153
    if (virNetworkGetBridgeNameEnsureACL(net->conn, def) < 0)
4154 4155
        goto cleanup;

4156
    if (!(def->bridge)) {
4157 4158
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
4159
                       def->name);
4160 4161 4162
        goto cleanup;
    }

4163
    ignore_value(VIR_STRDUP(bridge, def->bridge));
4164

4165
 cleanup:
4166
    virNetworkObjEndAPI(&obj);
4167 4168 4169
    return bridge;
}

4170 4171 4172 4173

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
4174
{
4175
    virNetworkObjPtr obj;
4176
    int ret = -1;
4177

4178
    if (!(obj = networkObjFromNetwork(net)))
4179
        return ret;
4180

4181
    if (virNetworkGetAutostartEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
4182 4183
        goto cleanup;

4184
    *autostart = virNetworkObjIsAutostart(obj) ? 1 : 0;
4185
    ret = 0;
4186

4187
 cleanup:
4188
    virNetworkObjEndAPI(&obj);
4189
    return ret;
4190 4191
}

4192 4193 4194 4195

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
4196
{
4197
    virNetworkDriverStatePtr driver = networkGetDriver();
4198
    virNetworkObjPtr obj;
4199
    virNetworkDefPtr def;
4200
    char *configFile = NULL, *autostartLink = NULL;
4201 4202
    bool new_autostart;
    bool cur_autostart;
4203
    int ret = -1;
4204

4205
    if (!(obj = networkObjFromNetwork(net)))
4206
        goto cleanup;
4207
    def = virNetworkObjGetDef(obj);
4208

4209
    if (virNetworkSetAutostartEnsureACL(net->conn, def) < 0)
4210 4211
        goto cleanup;

4212
    if (!virNetworkObjIsPersistent(obj)) {
4213 4214
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
4215 4216 4217
        goto cleanup;
    }

4218 4219 4220
    new_autostart = (autostart != 0);
    cur_autostart = virNetworkObjIsAutostart(obj);
    if (cur_autostart != new_autostart) {
4221 4222
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir,
                                               def->name)) == NULL)
4223
            goto cleanup;
4224 4225
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir,
                                                  def->name)) == NULL)
4226 4227
            goto cleanup;

4228
        if (new_autostart) {
4229
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
4230
                virReportSystemError(errno,
4231 4232
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
4233 4234
                goto cleanup;
            }
4235

4236
            if (symlink(configFile, autostartLink) < 0) {
4237
                virReportSystemError(errno,
4238
                                     _("Failed to create symlink '%s' to '%s'"),
4239
                                     autostartLink, configFile);
4240 4241 4242
                goto cleanup;
            }
        } else {
4243
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4244
                virReportSystemError(errno,
4245
                                     _("Failed to delete symlink '%s'"),
4246
                                     autostartLink);
4247 4248
                goto cleanup;
            }
4249 4250
        }

4251
        virNetworkObjSetAutostart(obj, new_autostart);
4252
    }
4253

4254
    ret = 0;
4255

4256
 cleanup:
4257 4258
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4259
    virNetworkObjEndAPI(&obj);
4260
    return ret;
4261 4262
}

4263

4264
static int
4265
networkGetDHCPLeases(virNetworkPtr net,
4266 4267 4268
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
4269
{
4270
    virNetworkDriverStatePtr driver = networkGetDriver();
4271 4272 4273
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
4274
    size_t size = 0;
4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285
    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;
4286
    virNetworkIPDefPtr ipdef_tmp = NULL;
4287 4288
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
4289
    virNetworkObjPtr obj;
4290
    virNetworkDefPtr def;
4291
    virMacAddr mac_addr;
4292 4293 4294

    virCheckFlags(0, -1);

4295 4296 4297 4298 4299 4300
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4301
    if (!(obj = networkObjFromNetwork(net)))
4302
        return -1;
4303
    def = virNetworkObjGetDef(obj);
4304

4305
    if (virNetworkGetDHCPLeasesEnsureACL(net->conn, def) < 0)
4306
        goto cleanup;
4307 4308

    /* Retrieve custom leases file location */
4309
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, def->bridge);
4310 4311

    /* Read entire contents */
4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325
    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);
        }
4326 4327 4328 4329 4330 4331 4332 4333 4334 4335
        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;
        }

4336
        if (!virJSONValueIsArray(leases_array)) {
4337
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4338
                           _("Malformed lease_entries array"));
4339 4340
            goto error;
        }
4341
        size = virJSONValueArraySize(leases_array);
4342 4343
    }

4344
    currtime = (long long)time(NULL);
4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360

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

4361
        if (mac && virMacAddrCompare(mac, mac_tmp))
4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392
            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 */
4393 4394
            for (j = 0; j < def->nips; j++) {
                ipdef_tmp = &def->ips[j];
4395 4396 4397 4398 4399 4400 4401 4402

                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)) {
4403
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4404 4405 4406 4407 4408 4409 4410 4411
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
4412
                (VIR_STRDUP(lease->iface, def->bridge) < 0))
4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444
                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);
4445
    VIR_FREE(lease_entries);
4446 4447
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4448

4449
    virNetworkObjEndAPI(&obj);
4450

4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461
    return rv;

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

4462

4463 4464 4465 4466 4467
/* A unified function to log network connections and disconnections */

static void
networkLogAllocation(virNetworkDefPtr netdef,
                     virNetworkForwardIfDefPtr dev,
4468
                     virMacAddrPtr mac,
4469 4470 4471 4472 4473
                     bool inUse)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    const char *verb = inUse ? "using" : "releasing";

4474
    virMacAddrFormat(mac, macStr);
4475 4476
    if (!dev) {
        VIR_INFO("MAC %s %s network %s (%d connections)",
4477
                 macStr, verb, netdef->name, netdef->connections);
4478
    } else {
4479
        if (dev->type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI) {
4480 4481
            VIR_INFO("MAC %s %s network %s (%d connections) "
                     "physical device %04x:%02x:%02x.%x (%d connections)",
4482
                     macStr, verb, netdef->name, netdef->connections,
4483 4484 4485 4486 4487 4488
                     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)",
4489
                     macStr, verb, netdef->name, netdef->connections,
4490 4491 4492 4493 4494
                     dev->device.dev, dev->connections);
        }
    }
}

4495

4496 4497 4498 4499 4500 4501 4502 4503
/* 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.
 */

4504 4505 4506
/* networkAllocatePort:
 * @obj: the network to allocate from
 * @port: the port definition to allocate
4507
 *
4508
 * Looks up the network reference by port, allocates a physical
4509
 * device from that network (if appropriate), and returns with the
4510
 * port configuration filled in accordingly.
4511 4512 4513
 *
 * Returns 0 on success, -1 on failure.
 */
4514
static int
4515 4516
networkAllocatePort(virNetworkObjPtr obj,
                    virNetworkPortDefPtr port)
4517
{
4518
    virNetworkDriverStatePtr driver = networkGetDriver();
4519 4520
    virNetworkDefPtr netdef = NULL;
    virPortGroupDefPtr portgroup = NULL;
4521
    virNetworkForwardIfDefPtr dev = NULL;
4522
    size_t i;
4523
    int ret = -1;
4524
    virNetDevVPortProfilePtr portprofile = NULL;
4525

4526
    netdef = virNetworkObjGetDef(obj);
4527
    VIR_DEBUG("Allocating port from net %s", netdef->name);
4528

4529
    if (!virNetworkObjIsActive(obj)) {
4530 4531 4532
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4533
        goto cleanup;
4534 4535
    }

4536
    VIR_DEBUG("Interface port group %s", port->group);
4537 4538 4539
    /* 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 已提交
4540
     */
4541
    portgroup = virPortGroupFindByName(netdef, port->group);
4542

4543 4544 4545 4546
    if (!port->bandwidth) {
        if (portgroup && portgroup->bandwidth &&
            virNetDevBandwidthCopy(&port->bandwidth,
                                   portgroup->bandwidth) < 0)
4547
            goto cleanup;
4548
    }
4549

4550 4551 4552 4553 4554 4555
    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;
4556

4557
        if (vlan && virNetDevVlanCopy(&port->vlan, vlan) < 0)
4558
            goto cleanup;
4559
    }
4560

4561 4562 4563 4564 4565 4566
    if (!port->trustGuestRxFilters) {
        if (portgroup && portgroup->trustGuestRxFilters)
            port->trustGuestRxFilters = portgroup->trustGuestRxFilters;
        else if (netdef->trustGuestRxFilters)
            port->trustGuestRxFilters = netdef->trustGuestRxFilters;
    }
4567

4568 4569 4570
    /* merge virtualports from interface, network, and portgroup to
     * arrive at actual virtualport to use
     */
4571 4572
    if (virNetDevVPortProfileMerge3(&portprofile,
                                    port->virtPortProfile,
4573 4574 4575
                                    netdef->virtPortProfile,
                                    portgroup
                                    ? portgroup->virtPortProfile : NULL) < 0) {
4576
                goto cleanup;
4577 4578 4579 4580
    }
    if (portprofile) {
        VIR_FREE(port->virtPortProfile);
        port->virtPortProfile = portprofile;
4581 4582
    }

4583
    VIR_DEBUG("Processing forward type %d", netdef->forward.type);
4584 4585 4586 4587 4588
    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:
4589 4590 4591 4592
        /* for these forward types, the actual net type really *is*
         * NETWORK; we just keep the info from the portgroup in
         * iface->data.network.actual
         */
4593
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_NETWORK;
4594

4595
        if (VIR_STRDUP(port->plug.bridge.brname, netdef->bridge) < 0)
4596
            goto cleanup;
4597
        port->plug.bridge.macTableManager = netdef->macTableManager;
4598

4599
        if (port->virtPortProfile) {
4600 4601 4602
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("<virtualport type='%s'> not supported for network "
                             "'%s' which uses IP forwarding"),
4603
                           virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4604
                           netdef->name);
4605
            goto cleanup;
4606 4607
        }

4608
        if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4609
            goto cleanup;
4610
        break;
4611

4612
    case VIR_NETWORK_FORWARD_HOSTDEV: {
4613
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI;
4614

4615
        if (networkCreateInterfacePool(netdef) < 0)
4616
            goto cleanup;
4617 4618

        /* pick first dev with 0 connections */
4619 4620 4621
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4622 4623 4624 4625 4626 4627 4628 4629
                break;
            }
        }
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' requires exclusive access "
                             "to interfaces, but none are available"),
                           netdef->name);
4630
            goto cleanup;
4631
        }
4632 4633 4634
        port->plug.hostdevpci.addr = dev->device.pci;
        port->plug.hostdevpci.driver = netdef->forward.driverName;
        port->plug.hostdevpci.managed = netdef->forward.managed;
4635

4636
        if (port->virtPortProfile) {
4637
            /* make sure type is supported for hostdev connections */
4638 4639
            if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
4640 4641 4642 4643
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses an SR-IOV Virtual Function "
                                 "via PCI passthrough"),
4644
                               virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4645
                               netdef->name);
4646
                goto cleanup;
4647 4648
            }
        }
4649 4650
        break;
    }
4651

4652 4653 4654 4655 4656 4657
    case VIR_NETWORK_FORWARD_BRIDGE:
        if (netdef->bridge) {
            /* <forward type='bridge'/> <bridge name='xxx'/>
             * is VIR_DOMAIN_NET_TYPE_BRIDGE
             */

4658 4659
            port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE;
            if (VIR_STRDUP(port->plug.bridge.brname, netdef->bridge) < 0)
4660
                goto cleanup;
4661
            port->plug.bridge.macTableManager = netdef->macTableManager;
4662

4663
            if (port->virtPortProfile) {
4664
                /* only type='openvswitch' is allowed for bridges */
4665
                if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
4666 4667 4668
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport type='%s'> not supported for network "
                                     "'%s' which uses a bridge device"),
4669
                                   virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4670
                                   netdef->name);
4671
                    goto cleanup;
4672 4673
                }
            }
4674

4675
            if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4676
                goto cleanup;
4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687
            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:
4688 4689 4690 4691 4692
        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
4693
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_DIRECT;
4694 4695 4696 4697

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

4701
        if (port->virtPortProfile) {
4702
            /* make sure type is supported for macvtap connections */
4703 4704
            if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
4705 4706 4707
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses a macvtap device"),
4708
                               virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4709
                               netdef->name);
4710
                goto cleanup;
4711 4712
            }
        }
4713

4714 4715 4716
        /* 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).
         */
4717
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4718 4719 4720 4721
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4722
            goto cleanup;
4723 4724 4725
        } else {
            /* pick an interface from the pool */

4726
            if (networkCreateInterfacePool(netdef) < 0)
4727
                goto cleanup;
4728

4729 4730 4731 4732 4733
            /* 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.
4734
             */
4735 4736
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4737 4738
                 port->virtPortProfile &&
                 (port->virtPortProfile->virtPortType
4739
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4740

4741
                /* pick first dev with 0 connections */
4742 4743 4744
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4745 4746 4747 4748 4749
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4750
                dev = &netdef->forward.ifs[0];
4751 4752 4753
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4754 4755 4756 4757
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4758 4759 4760 4761
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4762
                goto cleanup;
4763
            }
4764
            if (VIR_STRDUP(port->plug.direct.linkdev,
4765
                           dev->device.dev) < 0)
4766
                goto cleanup;
4767
        }
4768 4769 4770 4771 4772
        break;

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
4773
        goto cleanup;
4774 4775
    }

4776
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
4777 4778
                               port->ownername, &port->mac) < 0)
        goto cleanup;
M
Michal Privoznik 已提交
4779

4780
    if (virNetDevVPortProfileCheckComplete(port->virtPortProfile, true) < 0)
4781
        goto cleanup;
4782

4783 4784 4785 4786
    /* 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.
     */
4787
    VIR_DEBUG("Sanity check port config");
4788

4789
    if (port->vlan.nTags) {
4790 4791 4792 4793
        /* 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
4794
         */
4795 4796 4797
        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) ||
4798
              (port->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE &&
4799 4800
               port->virtPortProfile &&
               port->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
4801 4802 4803 4804 4805
            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);
4806
            goto cleanup;
4807 4808
        }
    }
4809 4810 4811 4812 4813 4814 4815 4816

    /* 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"));
4817
        goto cleanup;
4818
    }
4819

4820 4821 4822 4823
    netdef->connections++;
    if (dev)
        dev->connections++;
    /* finally we can call the 'plugged' hook script if any */
4824 4825
    if (networkRunHook(obj, port,
                       VIR_HOOK_NETWORK_OP_PORT_CREATED,
4826 4827 4828
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        netdef->connections--;
4829
        if (dev)
4830
            dev->connections--;
4831
        goto cleanup;
4832
    }
4833
    networkLogAllocation(netdef, dev, &port->mac, true);
4834 4835

    VIR_DEBUG("Port allocated");
4836

4837
    ret = 0;
4838
 cleanup:
4839
    return ret;
4840
}
4841

4842

4843 4844 4845
/* networkNotifyPort:
 * @obj: the network to notify
 * @port: the port definition to notify
4846 4847 4848 4849
 *
 * 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
4850
 * order.
4851
 */
4852
static int
4853 4854
networkNotifyPort(virNetworkObjPtr obj,
                  virNetworkPortDefPtr port)
4855 4856
{
    virNetworkDefPtr netdef;
4857
    virNetworkForwardIfDefPtr dev = NULL;
4858
    size_t i;
4859
    int ret = -1;
4860

4861
    netdef = virNetworkObjGetDef(obj);
4862

4863
    if (!virNetworkObjIsActive(obj)) {
4864 4865 4866
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4867
        goto cleanup;
4868
    }
4869

4870 4871 4872 4873
    switch (port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unexpectedly got a network port without a plug"));
4874
        goto cleanup;
4875

4876 4877 4878 4879
    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) {
4880
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4881
                           _("Unexpectedly got a network port without a network bridge"));
4882
            goto cleanup;
4883
        }
4884 4885 4886 4887
        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
        if (networkCreateInterfacePool(netdef) < 0)
4888
            goto cleanup;
4889 4890

        /* find the matching interface and increment its connections */
4891 4892
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4893
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4894 4895
                STREQ(port->plug.direct.linkdev,
                      netdef->forward.ifs[i].device.dev)) {
4896
                dev = &netdef->forward.ifs[i];
4897 4898 4899 4900 4901
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4902
            virReportError(VIR_ERR_INTERNAL_ERROR,
4903
                           _("network '%s' doesn't have dev='%s' "
4904 4905 4906
                             "in use by network port '%s'"),
                           netdef->name, port->plug.direct.linkdev,
                           port->uuid);
4907
            goto cleanup;
4908 4909
        }

4910
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4911 4912
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4913
         */
4914
        if ((dev->connections > 0) &&
4915 4916
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4917 4918
              port->virtPortProfile &&
              (port->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4919
            virReportError(VIR_ERR_INTERNAL_ERROR,
4920
                           _("network '%s' claims dev='%s' is already in "
4921 4922
                             "use by a different port"),
                           netdef->name, port->plug.direct.linkdev);
4923
            goto cleanup;
4924
        }
4925
        break;
4926

4927 4928 4929
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:

        if (networkCreateInterfacePool(netdef) < 0)
4930
            goto cleanup;
4931 4932

        /* find the matching interface and increment its connections */
4933 4934
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4935
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4936
                virPCIDeviceAddressEqual(&port->plug.hostdevpci.addr,
4937 4938
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4939 4940 4941 4942 4943 4944 4945
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have "
4946
                             "PCI device %04x:%02x:%02x.%x in use by network port"),
4947
                           netdef->name,
4948 4949 4950 4951
                           port->plug.hostdevpci.addr.domain,
                           port->plug.hostdevpci.addr.bus,
                           port->plug.hostdevpci.addr.slot,
                           port->plug.hostdevpci.addr.function);
4952
            goto cleanup;
4953 4954 4955 4956 4957 4958 4959
        }

        /* 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) &&
4960
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4961 4962 4963
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' claims the PCI device at "
                             "domain=%d bus=%d slot=%d function=%d "
4964
                             "is already in use by a different network port"),
4965 4966 4967
                           netdef->name,
                           dev->device.pci.domain, dev->device.pci.bus,
                           dev->device.pci.slot, dev->device.pci.function);
4968
            goto cleanup;
4969
        }
4970 4971 4972 4973 4974 4975

        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
    default:
        virReportEnumRangeError(virNetworkPortPlugType, port->plugtype);
4976
        goto cleanup;
4977 4978
    }

4979
    netdef->connections++;
4980 4981
    if (dev)
        dev->connections++;
4982
    /* finally we can call the 'plugged' hook script if any */
4983
    if (networkRunHook(obj, port, VIR_HOOK_NETWORK_OP_PORT_CREATED,
4984 4985 4986 4987 4988
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
4989
        goto cleanup;
4990
    }
4991 4992
    networkLogAllocation(netdef, dev, &port->mac, true);

4993
    ret = 0;
4994 4995 4996 4997 4998
 cleanup:
    return ret;
}


4999 5000 5001
/* networkReleasePort:
 * @obj: the network to release from
 * @port: the port definition to release
5002 5003 5004 5005 5006 5007 5008 5009
 *
 * 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.
 */
5010
static int
5011 5012
networkReleasePort(virNetworkObjPtr obj,
                   virNetworkPortDefPtr port)
5013
{
5014
    virNetworkDriverStatePtr driver = networkGetDriver();
5015
    virNetworkDefPtr netdef;
5016
    virNetworkForwardIfDefPtr dev = NULL;
5017 5018
    size_t i;
    int ret = -1;
5019

5020
    netdef = virNetworkObjGetDef(obj);
5021

5022 5023 5024
    switch ((virNetworkPortPlugType)port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        VIR_DEBUG("Releasing network device with no plug type");
5025 5026
        break;

5027 5028 5029 5030 5031
    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;
5032 5033
        break;

5034 5035 5036 5037 5038 5039 5040
    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;
5041
        }
5042

5043 5044
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5045
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
5046
                STREQ(port->plug.direct.linkdev, netdef->forward.ifs[i].device.dev)) {
5047
                dev = &netdef->forward.ifs[i];
5048 5049 5050
                break;
            }
        }
5051

5052
        if (!dev) {
5053
            virReportError(VIR_ERR_INTERNAL_ERROR,
5054 5055
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5056 5057
                           netdef->name, port->plug.direct.linkdev);
            goto cleanup;
5058
        }
5059
        break;
5060

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

5070 5071
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5072
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5073
                virPCIDeviceAddressEqual(&port->plug.hostdevpci.addr,
5074 5075
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5076 5077 5078 5079 5080 5081 5082 5083 5084
                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,
5085 5086 5087 5088 5089
                           port->plug.hostdevpci.addr.domain,
                           port->plug.hostdevpci.addr.bus,
                           port->plug.hostdevpci.addr.slot,
                           port->plug.hostdevpci.addr.function);
            goto cleanup;
5090
        }
5091 5092 5093 5094 5095 5096
        break;

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

5099
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, port->ownername, &port->mac);
5100 5101 5102 5103 5104

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

5109 5110 5111 5112 5113 5114
    ret = 0;
 cleanup:
    return ret;
}


5115 5116 5117
/**
 * networkCheckBandwidth:
 * @net: network QoS
5118
 * @ifaceBand: interface QoS (may be NULL if no QoS)
5119
 * @oldBandwidth: new interface QoS (may be NULL if no QoS)
5120
 * @ifaceMac: interface MAC (used in error messages for identification)
5121 5122
 * @new_rate: new rate for non guaranteed class
 *
5123 5124 5125 5126 5127 5128 5129 5130
 * 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.
 *
5131 5132 5133 5134 5135
 * 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
5136
networkCheckBandwidth(virNetworkObjPtr obj,
5137
                      virNetDevBandwidthPtr ifaceBand,
5138
                      virNetDevBandwidthPtr oldBandwidth,
5139
                      virMacAddrPtr ifaceMac,
5140 5141 5142
                      unsigned long long *new_rate)
{
    int ret = -1;
5143 5144
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    virNetDevBandwidthPtr netBand = def->bandwidth;
5145
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5146 5147 5148
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5149
    virMacAddrFormat(ifaceMac, ifmac);
5150 5151 5152 5153 5154 5155

    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"),
5156
                       ifmac, def->name);
5157 5158 5159
        return -1;
    }

5160 5161
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor)) ||
5162 5163
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
5164
        return 1;
5165
    }
5166 5167

    tmp_new_rate = netBand->in->average;
5168 5169 5170 5171
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
5172 5173 5174 5175 5176 5177

    /* 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,
5178 5179 5180
                           _("Cannot plug '%s' interface into '%s' because "
                             "new combined inbound floor=%llu would overcommit "
                             "peak=%llu on network '%s'"),
5181
                           ifmac,
5182
                           def->bridge,
5183 5184
                           tmp_floor_sum,
                           netBand->in->peak,
5185
                           def->name);
5186 5187 5188 5189 5190 5191
            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,
5192 5193 5194
                       _("Cannot plug '%s' interface into '%s' because "
                         "new combined inbound floor=%llu would overcommit "
                         "average=%llu on network '%s'"),
5195
                       ifmac,
5196
                       def->bridge,
5197 5198
                       tmp_floor_sum,
                       netBand->in->average,
5199
                       def->name);
5200 5201 5202
        goto cleanup;
    }

5203 5204
    if (new_rate)
        *new_rate = tmp_new_rate;
5205 5206
    ret = 0;

5207
 cleanup:
5208 5209 5210
    return ret;
}

5211

5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222
/**
 * 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
5223
networkNextClassID(virNetworkObjPtr obj)
5224
{
5225
    ssize_t ret = 0;
5226
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5227

5228 5229
    if ((ret = virBitmapNextClearBit(classIdMap, -1)) < 0)
        ret = virBitmapSize(classIdMap);
5230

5231
    if (virBitmapSetBitExpand(classIdMap, ret) < 0)
5232 5233 5234 5235 5236
        return -1;

    return ret;
}

5237

5238
static int
5239
networkPlugBandwidthImpl(virNetworkObjPtr obj,
5240
                         virMacAddrPtr mac,
5241
                         virNetDevBandwidthPtr ifaceBand,
5242
                         unsigned int *class_id,
5243
                         unsigned long long new_rate)
5244
{
5245
    virNetworkDriverStatePtr driver = networkGetDriver();
5246
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5247
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5248
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5249
    ssize_t next_id = 0;
5250 5251
    int plug_ret;
    int ret = -1;
5252 5253

    /* generate new class_id */
5254
    if ((next_id = networkNextClassID(obj)) < 0) {
5255 5256 5257 5258 5259
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate next class ID"));
        goto cleanup;
    }

5260
    plug_ret = virNetDevBandwidthPlug(def->bridge, def->bandwidth,
5261
                                      mac, ifaceBand, next_id);
5262
    if (plug_ret < 0) {
5263
        ignore_value(virNetDevBandwidthUnplug(def->bridge, next_id));
5264 5265 5266 5267
        goto cleanup;
    }

    /* QoS was set, generate new class ID */
5268
    *class_id = next_id;
5269
    /* update sum of 'floor'-s of attached NICs */
5270 5271
    tmp_floor_sum += ifaceBand->in->floor;
    virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5272
    /* update status file */
5273
    if (virNetworkObjSaveStatus(driver->stateDir, obj, network_driver->xmlopt) < 0) {
5274
        ignore_value(virBitmapClearBit(classIdMap, next_id));
5275 5276
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5277 5278
        *class_id = 0;
        ignore_value(virNetDevBandwidthUnplug(def->bridge, next_id));
5279 5280
        goto cleanup;
    }
5281
    /* update rate for non guaranteed NICs */
5282
    new_rate -= tmp_floor_sum;
5283 5284
    if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                     def->bandwidth, new_rate) < 0)
5285
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5286
                 def->bridge);
5287 5288

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


static int
5295
networkPlugBandwidth(virNetworkObjPtr obj,
5296 5297 5298
                     virMacAddrPtr mac,
                     virNetDevBandwidthPtr ifaceBand,
                     unsigned int *class_id)
5299 5300 5301 5302 5303 5304
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5305
    if ((plug_ret = networkCheckBandwidth(obj, ifaceBand, NULL,
5306
                                          mac, &new_rate)) < 0) {
5307 5308 5309 5310 5311 5312 5313 5314 5315 5316
        /* helper reported error */
        goto cleanup;
    }

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

5317
    virMacAddrFormat(mac, ifmac);
5318

5319
    if (networkPlugBandwidthImpl(obj, mac, ifaceBand, class_id, new_rate) < 0)
5320 5321 5322
        goto cleanup;

    ret = 0;
5323

5324
 cleanup:
5325 5326 5327
    return ret;
}

5328

5329
static int
5330
networkUnplugBandwidth(virNetworkObjPtr obj,
5331 5332
                       virNetDevBandwidthPtr ifaceBand,
                       unsigned int *class_id)
5333
{
5334
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5335
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5336
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5337
    virNetworkDriverStatePtr driver = networkGetDriver();
5338 5339 5340
    int ret = 0;
    unsigned long long new_rate;

5341
    if (class_id && *class_id) {
5342
        if (!def->bandwidth || !def->bandwidth->in) {
5343
            VIR_WARN("Network %s has no bandwidth but unplug requested",
5344
                     def->name);
5345 5346
            goto cleanup;
        }
5347
        /* we must remove class from bridge */
5348
        new_rate = def->bandwidth->in->average;
5349

5350 5351
        if (def->bandwidth->in->peak > 0)
            new_rate = def->bandwidth->in->peak;
5352

5353
        ret = virNetDevBandwidthUnplug(def->bridge, *class_id);
5354 5355 5356
        if (ret < 0)
            goto cleanup;
        /* update sum of 'floor'-s of attached NICs */
5357 5358 5359
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);

5360
        /* return class ID */
5361
        ignore_value(virBitmapClearBit(classIdMap, *class_id));
5362
        /* update status file */
5363 5364
        if (virNetworkObjSaveStatus(driver->stateDir,
                                    obj, network_driver->xmlopt) < 0) {
5365 5366
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5367
            ignore_value(virBitmapSetBit(classIdMap, *class_id));
5368 5369
            goto cleanup;
        }
5370
        /* update rate for non guaranteed NICs */
5371
        new_rate -= tmp_floor_sum;
5372 5373
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0)
5374
            VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5375
                     def->bridge);
5376
        /* no class is associated any longer */
5377
        *class_id = 0;
5378 5379
    }

5380
 cleanup:
5381 5382
    return ret;
}
5383

5384

5385
static void
5386
networkNetworkObjTaint(virNetworkObjPtr obj,
5387
                       virNetworkTaintFlags taint)
5388
{
5389 5390
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

5391
    if (virNetworkObjTaint(obj, taint)) {
5392
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5393
        virUUIDFormat(def->uuid, uuidstr);
5394 5395

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5396
                 def->name, uuidstr, virNetworkTaintTypeToString(taint));
5397 5398
    }
}
5399 5400


5401
static int
5402 5403 5404 5405 5406
networkUpdatePortBandwidth(virNetworkObjPtr obj,
                           virMacAddrPtr mac,
                           unsigned int *class_id,
                           virNetDevBandwidthPtr oldBandwidth,
                           virNetDevBandwidthPtr newBandwidth)
5407 5408
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5409
    virNetworkDefPtr def;
5410
    unsigned long long tmp_floor_sum;
5411
    unsigned long long new_rate = 0;
5412
    unsigned long long old_floor, new_floor;
5413
    int plug_ret;
5414 5415 5416

    old_floor = new_floor = 0;

5417 5418
    if (oldBandwidth && oldBandwidth->in)
        old_floor = oldBandwidth->in->floor;
5419 5420 5421 5422
    if (newBandwidth && newBandwidth->in)
        new_floor = newBandwidth->in->floor;

    if (new_floor == old_floor)
5423 5424
        return 0;

5425
    def = virNetworkObjGetDef(obj);
5426

5427 5428
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, oldBandwidth,
                                          mac, &new_rate)) < 0) {
5429
        /* helper reported error */
5430
        return -1;
5431 5432 5433 5434
    }

    if (plug_ret > 0) {
        /* no QoS needs to be set; claim success */
5435
        return 0;
5436 5437 5438 5439
    }

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

5440
    if (oldBandwidth && oldBandwidth->in && oldBandwidth->in->floor &&
5441
        newBandwidth->in && newBandwidth->in->floor) {
5442 5443
        /* Either we just need to update @floor .. */

5444
        if (virNetDevBandwidthUpdateRate(def->bridge,
5445
                                         *class_id,
5446
                                         def->bandwidth,
5447
                                         newBandwidth->in->floor) < 0)
5448
            return -1;
5449

5450
        tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5451
        tmp_floor_sum -= oldBandwidth->in->floor;
5452 5453 5454
        tmp_floor_sum += newBandwidth->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
        new_rate -= tmp_floor_sum;
5455

5456 5457
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0 ||
5458 5459
            virNetworkObjSaveStatus(driver->stateDir,
                                    obj, network_driver->xmlopt) < 0) {
5460
            /* Ouch, rollback */
5461
            tmp_floor_sum -= newBandwidth->in->floor;
5462
            tmp_floor_sum += oldBandwidth->in->floor;
5463
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5464

5465
            ignore_value(virNetDevBandwidthUpdateRate(def->bridge,
5466
                                                      *class_id,
5467
                                                      def->bandwidth,
5468 5469
                                                      oldBandwidth->in->floor));
            return -1;
5470 5471 5472 5473
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5474 5475
        if (networkPlugBandwidthImpl(obj, mac, newBandwidth,
                                     class_id,
5476
                                     new_rate) < 0)
5477
            return -1;
5478 5479 5480
    } else {
        /* .. or unplug old. */

5481 5482
        if (networkUnplugBandwidth(obj, oldBandwidth, class_id) < 0)
            return -1;
5483 5484
    }

5485 5486 5487 5488
    return 0;
}


5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575
static virNetworkPortPtr
networkPortLookupByUUID(virNetworkPtr net,
                        const unsigned char *uuid)
{
    virNetworkObjPtr obj;
    virNetworkDefPtr def;
    virNetworkPortDefPtr portdef = NULL;
    virNetworkPortPtr ret = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virUUIDFormat(uuid, uuidstr);

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

    def = virNetworkObjGetDef(obj);

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

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

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

    ret = virGetNetworkPort(net, uuid);

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


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

    virCheckFlags(VIR_NETWORK_PORT_CREATE_RECLAIM, NULL);

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

    def = virNetworkObjGetDef(obj);

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

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

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

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

    if (flags & VIR_NETWORK_PORT_CREATE_RECLAIM)
        rc = networkNotifyPort(obj, portdef);
    else
        rc = networkAllocatePort(obj, portdef);
5576 5577 5578 5579
    if (rc < 0)
        goto cleanup;

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

5582
        virErrorPreserveLast(&save_err);
5583
        ignore_value(networkReleasePort(obj, portdef));
5584
        virNetworkPortDefFree(portdef);
5585 5586
        virErrorRestore(&save_err);

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

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


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

    virCheckFlags(0, NULL);

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

    def = virNetworkObjGetDef(obj);

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

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

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

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

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


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

    virCheckFlags(0, -1);

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

    def = virNetworkObjGetDef(obj);

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

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

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

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

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

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


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

    virCheckFlags(0, -1);

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

    def = virNetworkObjGetDef(obj);

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

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

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

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

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

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

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

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

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

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

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

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


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

    virCheckFlags(0, -1);

    *params = NULL;
    *nparams = 0;

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

    def = virNetworkObjGetDef(obj);

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

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

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

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

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

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


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

    virCheckFlags(0, -1);

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

    def = virNetworkObjGetDef(obj);

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

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

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

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


5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900
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 */
5901 5902 5903 5904 5905 5906 5907
    .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 */
5908 5909
};

5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921

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 = {
5922
    .localOnly = true,
5923
    .uriSchemes = (const char *[]){ "network", NULL },
5924 5925 5926 5927 5928
    .hypervisorDriver = &networkHypervisorDriver,
    .networkDriver = &networkDriver,
};


5929 5930 5931 5932 5933 5934 5935 5936 5937 5938
static virStateDriver networkStateDriver = {
    .name = "bridge",
    .stateInitialize  = networkStateInitialize,
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
};

int
networkRegister(void)
{
5939 5940
    if (virRegisterConnectDriver(&networkConnectDriver, false) < 0)
        return -1;
5941 5942 5943 5944 5945 5946
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
    return 0;
}