bridge_driver.c 189.6 KB
Newer Older
1
/*
2
 * bridge_driver.c: core driver methods for managing network
3
 *
4
 * Copyright (C) 2006-2016 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
 */

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
35
#include <net/if.h>
36
#ifdef HAVE_SYSCTLBYNAME
37 38
# include <sys/sysctl.h>
#endif
39

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

72
#define VIR_FROM_THIS VIR_FROM_NETWORK
73
#define MAX_BRIDGE_ID 256
74

75 76 77 78 79 80 81
/**
 * VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX:
 *
 * Macro providing the upper limit on the size of leases file
 */
#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (32 * 1024 * 1024)

82 83
#define SYSCTL_PATH "/proc/sys"

84 85
VIR_LOG_INIT("network.bridge_driver");

86
static virNetworkDriverStatePtr network_driver;
87

88

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

98 99 100

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


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

112

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

123

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

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

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

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

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)
{
157
    g_autofree xmlNodePtr *nodes = NULL;
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
    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)
197
        *data = g_steal_pointer(&nsdata);
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

    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
        xml = virBufferContentAndReset(&buf);
345
        hookret = virHookCall(VIR_HOOK_DRIVER_NETWORK, def->name,
346 347 348 349 350 351 352
                              op, sub_op, NULL, xml, NULL);

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

354
        networkNetworkObjTaint(obj, VIR_NETWORK_TAINT_HOOK);
355 356 357
    }

    ret = 0;
358
 cleanup:
359 360 361 362 363
    virBufferFreeAndReset(&buf);
    VIR_FREE(xml);
    return ret;
}

364

365
static char *
366 367
networkDnsmasqLeaseFileNameDefault(virNetworkDriverStatePtr driver,
                                   const char *netname)
368 369 370
{
    char *leasefile;

371
    ignore_value(virAsprintf(&leasefile, "%s/%s.leases",
372
                             driver->dnsmasqStateDir, netname));
373 374 375
    return leasefile;
}

376

377
static char *
378 379
networkDnsmasqLeaseFileNameCustom(virNetworkDriverStatePtr driver,
                                  const char *bridge)
380 381 382 383
{
    char *leasefile;

    ignore_value(virAsprintf(&leasefile, "%s/%s.status",
384
                             driver->dnsmasqStateDir, bridge));
385 386 387
    return leasefile;
}

388

389
static char *
390 391
networkDnsmasqConfigFileName(virNetworkDriverStatePtr driver,
                             const char *netname)
392 393 394
{
    char *conffile;

395
    ignore_value(virAsprintf(&conffile, "%s/%s.conf",
396
                             driver->dnsmasqStateDir, netname));
397 398 399
    return conffile;
}

400

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

407
    ignore_value(virAsprintf(&pidfilebase, "%s-radvd", netname));
408 409 410
    return pidfilebase;
}

411

412
static char *
413 414
networkRadvdConfigFileName(virNetworkDriverStatePtr driver,
                           const char *netname)
415 416 417
{
    char *configfile;

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

423

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

    int ret = -1;

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

447
    if (!(leasefile = networkDnsmasqLeaseFileNameDefault(driver, def->name)))
448 449
        goto cleanup;

450
    if (!(customleasefile = networkDnsmasqLeaseFileNameCustom(driver, def->bridge)))
451 452
        goto cleanup;

453
    if (!(radvdconfigfile = networkRadvdConfigFileName(driver, def->name)))
454
        goto cleanup;
455 456

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
457
        goto cleanup;
458

459
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
460
        goto cleanup;
461

462
    if (!(statusfile = virNetworkConfigFile(driver->stateDir, def->name)))
463
        goto cleanup;
464

465
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir, def->bridge)))
M
Michal Privoznik 已提交
466 467
        goto cleanup;

468 469 470
    /* dnsmasq */
    dnsmasqDelete(dctx);
    unlink(leasefile);
471
    unlink(customleasefile);
472
    unlink(configfile);
473

M
Michal Privoznik 已提交
474 475 476
    /* MAC map manager */
    unlink(macMapFile);

477 478
    /* radvd */
    unlink(radvdconfigfile);
479
    virPidFileDelete(driver->pidDir, radvdpidbase);
480

481 482 483
    /* remove status file */
    unlink(statusfile);

484
    /* remove the network definition */
485
    virNetworkObjRemoveInactive(driver->networks, obj);
486 487 488

    ret = 0;

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

501

502 503 504
static char *
networkBridgeDummyNicName(const char *brname)
{
505
    static const char dummyNicSuffix[] = "-nic";
506 507
    char *nicname;

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

526

527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
static int
networkNotifyPort(virNetworkObjPtr obj,
                  virNetworkPortDefPtr port);

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

    networkNotifyPort(obj, port);

    return false;
}

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

553
    virObjectLock(obj);
554
    if (!virNetworkObjIsActive(obj)) {
555 556
        ret = 0;
        goto cleanup;
557
    }
558
    def = virNetworkObjGetDef(obj);
559

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

569
        if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
570
                                             def->bridge)))
571 572
            goto cleanup;

573
        if (!(macmap = virMacMapNew(macMapFile)))
574 575
            goto cleanup;

576 577
        virNetworkObjSetMacMap(obj, macmap);

578
        break;
579

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

596 597 598
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
599 600 601 602 603

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

606 607
    virNetworkObjPortForEach(obj, networkUpdatePort, obj);

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

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

620
        radvdpidbase = networkRadvdPidfileBasename(def->name);
621 622
        if (!radvdpidbase)
            goto cleanup;
623

624 625
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
626 627
                                           &radvdPid, RADVD));
        virNetworkObjSetRadvdPid(obj, radvdPid);
628
        VIR_FREE(radvdpidbase);
629
    }
630

631 632
    ret = 0;
 cleanup:
633
    virObjectUnlock(obj);
634
    virObjectUnref(dnsmasq_caps);
635
    VIR_FREE(macMapFile);
636 637
    return ret;
}
638

639

640
static int
641
networkAutostartConfig(virNetworkObjPtr obj,
642
                       void *opaque)
643
{
644
    virNetworkDriverStatePtr driver = opaque;
645
    int ret = -1;
646

647
    virObjectLock(obj);
648
    if (virNetworkObjIsAutostart(obj) &&
649 650
        !virNetworkObjIsActive(obj) &&
        networkStartNetwork(driver, obj) < 0)
651 652 653 654
        goto cleanup;

    ret = 0;
 cleanup:
655
    virObjectUnlock(obj);
656
    return ret;
657 658
}

659

660
#ifdef WITH_FIREWALLD
661
static DBusHandlerResult
J
Ján Tomko 已提交
662
firewalld_dbus_filter_bridge(DBusConnection *connection G_GNUC_UNUSED,
663 664
                             DBusMessage *message,
                             void *user_data)
665
{
666
    virNetworkDriverStatePtr driver = user_data;
667
    bool reload = false;
668

669 670 671 672 673 674 675
    if (dbus_message_is_signal(message,
                               "org.fedoraproject.FirewallD1", "Reloaded")) {
        reload = true;

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

676 677 678
        g_autofree char *name = NULL;
        g_autofree char *old_owner = NULL;
        g_autofree char *new_owner = NULL;
679 680 681 682 683 684 685 686 687 688 689 690 691 692

        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) {
693
        VIR_DEBUG("Reload in bridge_driver because of firewalld.");
694
        networkReloadFirewallRules(driver, false);
695 696 697 698 699 700
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

701

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

720
    if (VIR_ALLOC(network_driver) < 0)
721
        goto error;
722

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

729 730
    network_driver->privileged = privileged;

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

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

751
        if ((virAsprintf(&network_driver->networkConfigDir,
752
                         "%s/qemu/networks", configdir) < 0) ||
753
            (virAsprintf(&network_driver->networkAutostartDir,
754
                         "%s/qemu/networks/autostart", configdir) < 0) ||
755
            (virAsprintf(&network_driver->stateDir,
756
                         "%s/network/lib", rundir) < 0) ||
757
            (virAsprintf(&network_driver->pidDir,
758
                         "%s/network/run", rundir) < 0) ||
759
            (virAsprintf(&network_driver->dnsmasqStateDir,
760
                         "%s/dnsmasq/lib", rundir) < 0) ||
761
            (virAsprintf(&network_driver->radvdStateDir,
762
                         "%s/radvd/lib", rundir) < 0)) {
763
            goto error;
764
        }
765 766
    }

767
    if (virFileMakePath(network_driver->stateDir) < 0) {
768 769
        virReportSystemError(errno,
                             _("cannot create directory %s"),
770
                             network_driver->stateDir);
771 772 773
        goto error;
    }

774 775 776 777 778
    if ((network_driver->lockFD =
         virPidFileAcquire(network_driver->stateDir, "driver",
                           true, getpid())) < 0)
        goto error;

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

782
    if (!(network_driver->networks = virNetworkObjListNew()))
783 784
        goto error;

785
    if (virNetworkObjLoadAllState(network_driver->networks,
786 787
                                  network_driver->stateDir,
                                  network_driver->xmlopt) < 0)
788 789
        goto error;

790 791
    if (virNetworkObjLoadAllConfigs(network_driver->networks,
                                    network_driver->networkConfigDir,
792 793
                                    network_driver->networkAutostartDir,
                                    network_driver->xmlopt) < 0)
794 795
        goto error;

796 797 798 799
    /* 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). */
800
    virNetworkObjListForEach(network_driver->networks,
801
                             networkUpdateState,
802 803
                             network_driver);
    virNetworkObjListPrune(network_driver->networks,
804 805
                           VIR_CONNECT_LIST_NETWORKS_INACTIVE |
                           VIR_CONNECT_LIST_NETWORKS_TRANSIENT);
806
    networkReloadFirewallRules(network_driver, true);
807
    networkRefreshDaemons(network_driver);
808

809 810 811 812 813 814 815 816
    if (virDriverShouldAutostart(network_driver->stateDir, &autostart) < 0)
        goto error;

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

818
    network_driver->networkEventState = virObjectEventStateNew();
819

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

845
    ret = VIR_DRV_STATE_INIT_COMPLETE;
846
 cleanup:
847 848 849
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
850

851
 error:
852
    networkStateCleanup();
853
    goto cleanup;
854 855
}

856

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

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


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

896
    virObjectUnref(network_driver->networkEventState);
C
Cole Robinson 已提交
897
    virObjectUnref(network_driver->xmlopt);
898

899
    /* free inactive networks */
900
    virObjectUnref(network_driver->networks);
901

902 903 904 905
    if (network_driver->lockFD != -1)
        virPidFileRelease(network_driver->stateDir, "driver",
                          network_driver->lockFD);

906 907 908 909 910 911
    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);
912

913
    virObjectUnref(network_driver->dnsmasqCaps);
914

915
    virMutexDestroy(&network_driver->lock);
916

917
    VIR_FREE(network_driver);
918 919 920 921 922

    return 0;
}


923 924
static virDrvOpenStatus
networkConnectOpen(virConnectPtr conn,
J
Ján Tomko 已提交
925 926
                   virConnectAuthPtr auth G_GNUC_UNUSED,
                   virConfPtr conf G_GNUC_UNUSED,
927 928 929 930
                   unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

931 932 933 934 935 936
    if (network_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("network state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
    }

937 938 939 940
    if (!virConnectValidateURIPath(conn->uri->path,
                                   "network",
                                   network_driver->privileged))
        return VIR_DRV_OPEN_ERROR;
941 942 943 944 945 946 947

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

    return VIR_DRV_OPEN_SUCCESS;
}

J
Ján Tomko 已提交
948
static int networkConnectClose(virConnectPtr conn G_GNUC_UNUSED)
949 950 951 952 953
{
    return 0;
}


J
Ján Tomko 已提交
954
static int networkConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)
955 956 957 958 959 960
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


J
Ján Tomko 已提交
961
static int networkConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)
962 963 964 965 966 967
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


J
Ján Tomko 已提交
968
static int networkConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
969 970 971 972 973
{
    return 1;
}


974 975 976 977 978
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
979 980 981
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
982
{
983 984
    size_t i;
    int ret = -1;
985 986 987 988 989 990 991
    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.
     */
992
    for (i = 0; i < 25; i++) {
993
        int signum = 0;
994
        if (i == 0) {
995
            signum = SIGTERM;
996
        } else if (i == 15) {
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
            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.
         */
1027
        g_usleep(20 * 1000);
1028 1029 1030 1031
    }
    VIR_WARN("Timed out waiting after SIG%s to %s process %d "
             "(network '%s')",
             signame, daemonName, pid, networkName);
1032
 cleanup:
1033 1034 1035
    return ret;
}

1036

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

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

G
Gene Czarcinski 已提交
1057 1058 1059
    return 0;
}

1060

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

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

1078
    return 0;
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 1117 1118
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;
}


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

1137 1138
    *configstr = NULL;

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

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

1153
    /* create dnsmasq config file appropriate for this network */
1154 1155

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

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

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

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

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

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

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

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

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

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

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

            if (!ipaddr)
                goto cleanup;
1272

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

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

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

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

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

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

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

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1441 1442
        int prefix;

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

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

1457 1458 1459 1460 1461 1462
            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;
1463
                g_autofree char *netmaskStr = NULL;
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1593 1594 1595
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1596
    ret = 0;
G
Gene Czarcinski 已提交
1597

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

1605

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

1622
    virNetworkObjSetDnsmasqPid(obj, -1);
1623

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

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

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

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

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

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

1665

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

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

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

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

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

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

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

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

1721
    if (networkDnsmasqCapsRefresh(driver) < 0)
1722
        goto cleanup;
1723

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

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1730
        goto cleanup;
1731

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

    /*
1737 1738 1739 1740 1741
     * 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
1742 1743
     */

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

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

1757

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

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

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

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

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

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

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

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

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

    if ((ret = dnsmasqSave(dctx)) < 0)
1821
        goto cleanup;
1822

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

1830

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

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

1854

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

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

    *configstr = NULL;
1873

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

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

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

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

1924
    virBufferAddLit(&configbuf, "};\n");
1925

1926 1927
    *configstr = virBufferContentAndReset(&configbuf);

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

1934

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

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

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

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

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

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

1977

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

1991
    virNetworkObjSetRadvdPid(obj, -1);
1992

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

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

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

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

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

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

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

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

2069

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

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

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

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

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

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

2113

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

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

2142

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

2150
    virObjectLock(obj);
2151
    def = virNetworkObjGetDef(obj);
2152 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
    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;
        }
2180
    }
2181 2182

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

2187

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

2200

2201
static int
2202
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
J
Ján Tomko 已提交
2203
                                 void *opaque G_GNUC_UNUSED)
2204
{
2205
    virNetworkDefPtr def;
2206

2207
    virObjectLock(obj);
2208
    def = virNetworkObjGetDef(obj);
2209 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
    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;
2235 2236
        }
    }
2237 2238

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

2243

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

2259

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

2280
#endif
2281
    return ret;
2282 2283
}

2284

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

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

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

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

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

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

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

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

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

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

2354

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

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

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

    return 0;
}

2376 2377

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

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


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

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

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

2421 2422 2423
    return 0;
}

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

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

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

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

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

2450

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

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

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

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

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

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

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

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

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

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

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

2544 2545
    firewalRulesAdded = true;

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

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

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

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

2564 2565
    devOnline = true;

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

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

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

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

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

2595

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

2601 2602
    dnsmasqStarted = true;

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

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

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

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

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

    return 0;

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

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

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

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

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

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

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

2663

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

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

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

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

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

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

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

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

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

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

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

2721 2722 2723
    return 0;
}

2724

2725
static int
2726
networkStartNetworkBridge(virNetworkObjPtr obj)
2727
{
2728 2729
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

2730 2731 2732 2733
    /* 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.
     */
2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
        goto error;

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

    return 0;

 error:
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
    return -1;
2746 2747
}

2748

2749
static int
J
Ján Tomko 已提交
2750
networkShutdownNetworkBridge(virNetworkObjPtr obj G_GNUC_UNUSED)
2751
{
2752 2753
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

2754 2755 2756 2757
    /* 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.
     */
2758 2759 2760
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);

2761 2762 2763 2764
    return 0;
}


2765 2766 2767 2768 2769 2770 2771 2772 2773
/* 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;
2774
    unsigned int maxVirtFns = 0;
2775 2776 2777 2778 2779 2780
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2781 2782 2783
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2784 2785
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800
        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];

2801
        switch ((virNetworkForwardType) netdef->forward.type) {
2802 2803 2804 2805 2806
        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
            if (thisName) {
2807
                thisIf->device.dev = g_strdup(thisName);
2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830
                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:
2831
        case VIR_NETWORK_FORWARD_OPEN:
2832 2833
            /* by definition these will never be encountered here */
            break;
2834 2835 2836 2837 2838

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
            goto cleanup;
2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875
        }
    }

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


2876
static int
2877
networkStartNetworkExternal(virNetworkObjPtr obj)
2878 2879
{
    /* put anything here that needs to be done each time a network of
2880
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2881 2882 2883
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2884
    return networkCreateInterfacePool(virNetworkObjGetDef(obj));
2885 2886
}

2887 2888

static int
J
Ján Tomko 已提交
2889
networkShutdownNetworkExternal(virNetworkObjPtr obj G_GNUC_UNUSED)
2890 2891
{
    /* put anything here that needs to be done each time a network of
2892
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2893 2894 2895 2896 2897 2898
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2899

2900
static int
2901
networkStartNetwork(virNetworkDriverStatePtr driver,
2902
                    virNetworkObjPtr obj)
2903
{
2904
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2905 2906
    int ret = -1;

2907
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2908

2909
    if (virNetworkObjIsActive(obj)) {
2910 2911
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2912
        return ret;
2913 2914
    }

2915 2916
    VIR_DEBUG("Beginning network startup process");

2917 2918
    virNetworkObjDeleteAllPorts(obj, driver->stateDir);

2919
    VIR_DEBUG("Setting current network def as transient");
2920
    if (virNetworkObjSetDefTransient(obj, true, network_driver->xmlopt) < 0)
2921
        goto cleanup;
2922

2923 2924
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2925
    if (networkRunHook(obj, NULL,
2926 2927 2928 2929
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2930
    switch ((virNetworkForwardType) def->forward.type) {
2931 2932 2933 2934

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2935
    case VIR_NETWORK_FORWARD_OPEN:
2936
        if (networkStartNetworkVirtual(driver, obj) < 0)
2937
            goto cleanup;
2938 2939 2940
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2941
        if (def->bridge) {
2942
            if (networkStartNetworkBridge(obj) < 0)
2943 2944 2945 2946 2947 2948 2949
                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).
         */
2950
        G_GNUC_FALLTHROUGH;
2951

2952 2953 2954
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2955
    case VIR_NETWORK_FORWARD_HOSTDEV:
2956
        if (networkStartNetworkExternal(obj) < 0)
2957
            goto cleanup;
2958
        break;
2959 2960 2961 2962 2963

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

2966 2967
    virNetworkObjSetFloorSum(obj, 0);

2968
    /* finally we can call the 'started' hook script if any */
2969
    if (networkRunHook(obj, NULL,
2970 2971 2972 2973
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2974 2975 2976
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2977
    VIR_DEBUG("Writing network status to disk");
2978 2979
    if (virNetworkObjSaveStatus(driver->stateDir,
                                obj, network_driver->xmlopt) < 0)
2980
        goto cleanup;
2981

2982
    virNetworkObjSetActive(obj, true);
2983
    VIR_INFO("Network '%s' started up", def->name);
2984
    ret = 0;
2985

2986
 cleanup:
2987
    if (ret < 0) {
2988 2989 2990
        virErrorPtr save_err;

        virErrorPreserveLast(&save_err);
2991 2992
        virNetworkObjUnsetDefTransient(obj);
        networkShutdownNetwork(driver, obj);
2993
        virErrorRestore(&save_err);
2994 2995 2996 2997
    }
    return ret;
}

2998

2999 3000
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
3001
                       virNetworkObjPtr obj)
3002
{
3003
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
3004 3005 3006
    int ret = 0;
    char *stateFile;

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

3009
    if (!virNetworkObjIsActive(obj))
3010 3011
        return 0;

3012
    stateFile = virNetworkConfigFile(driver->stateDir, def->name);
3013 3014 3015 3016 3017 3018
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

3019
    switch ((virNetworkForwardType) def->forward.type) {
3020 3021 3022 3023

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
3024
    case VIR_NETWORK_FORWARD_OPEN:
3025
        ret = networkShutdownNetworkVirtual(driver, obj);
3026 3027 3028
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3029
        if (def->bridge) {
3030
            ret = networkShutdownNetworkBridge(obj);
3031 3032 3033 3034 3035 3036
            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).
         */
3037
        G_GNUC_FALLTHROUGH;
3038

3039 3040 3041
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
3042
    case VIR_NETWORK_FORWARD_HOSTDEV:
3043
        ret = networkShutdownNetworkExternal(obj);
3044
        break;
3045 3046 3047 3048 3049

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

3052
    /* now that we know it's stopped call the hook if present */
3053
    networkRunHook(obj, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
3054 3055
                   VIR_HOOK_SUBOP_END);

3056
    virNetworkObjSetActive(obj, false);
3057
    virNetworkObjUnsetDefTransient(obj);
3058
    return ret;
3059 3060 3061
}


3062 3063 3064
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
3065
{
3066
    virNetworkDriverStatePtr driver = networkGetDriver();
3067
    virNetworkObjPtr obj;
3068
    virNetworkDefPtr def;
3069
    virNetworkPtr net = NULL;
3070

3071 3072
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
3073 3074
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
3075
        virReportError(VIR_ERR_NO_NETWORK,
3076 3077
                       _("no network with matching uuid '%s'"),
                       uuidstr);
3078
        goto cleanup;
3079
    }
3080
    def = virNetworkObjGetDef(obj);
3081

3082
    if (virNetworkLookupByUUIDEnsureACL(conn, def) < 0)
3083 3084
        goto cleanup;

3085
    net = virGetNetwork(conn, def->name, def->uuid);
3086

3087
 cleanup:
3088 3089
    virNetworkObjEndAPI(&obj);
    return net;
3090 3091
}

3092 3093 3094 3095

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
3096
{
3097
    virNetworkDriverStatePtr driver = networkGetDriver();
3098
    virNetworkObjPtr obj;
3099
    virNetworkDefPtr def;
3100
    virNetworkPtr net = NULL;
3101

3102 3103
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
3104 3105
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
3106
        goto cleanup;
3107
    }
3108
    def = virNetworkObjGetDef(obj);
3109

3110
    if (virNetworkLookupByNameEnsureACL(conn, def) < 0)
3111 3112
        goto cleanup;

3113
    net = virGetNetwork(conn, def->name, def->uuid);
3114

3115
 cleanup:
3116 3117
    virNetworkObjEndAPI(&obj);
    return net;
3118 3119
}

3120 3121 3122

static int
networkConnectNumOfNetworks(virConnectPtr conn)
3123
{
3124
    virNetworkDriverStatePtr driver = networkGetDriver();
3125

3126 3127 3128
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3129 3130 3131
    return virNetworkObjListNumOfNetworks(driver->networks, true,
                                          virConnectNumOfNetworksCheckACL,
                                          conn);
3132 3133
}

3134 3135 3136 3137

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
3138
                           int maxnames)
3139 3140
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3141

3142 3143 3144
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3145 3146
    return virNetworkObjListGetNames(driver->networks, true, names, maxnames,
                                     virConnectListNetworksCheckACL, conn);
3147 3148
}

3149 3150 3151

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
3152
{
3153
    virNetworkDriverStatePtr driver = networkGetDriver();
3154

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

M
Michal Privoznik 已提交
3158 3159 3160
    return virNetworkObjListNumOfNetworks(driver->networks, false,
                                          virConnectNumOfDefinedNetworksCheckACL,
                                          conn);
3161 3162
}

3163 3164 3165 3166

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
3167
                                  int maxnames)
3168 3169
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3170

3171 3172 3173
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3174 3175 3176
    return virNetworkObjListGetNames(driver->networks, false, names, maxnames,
                                     virConnectListDefinedNetworksCheckACL,
                                     conn);
3177 3178
}

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
        if (def->bridge != NULL)
            bandwidthAllowed = true;

3406
        G_GNUC_FALLTHROUGH;
3407

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
    bridge = g_strdup(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
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

4410 4411 4412
            lease->mac = g_strdup(mac_tmp);
            lease->ipaddr = g_strdup(ip_tmp);
            lease->iface = g_strdup(def->bridge);
4413 4414

            /* Fields that can be NULL */
4415 4416 4417
            lease->iaid = g_strdup(virJSONValueObjectGetString(lease_tmp, "iaid"));
            lease->clientid = g_strdup(virJSONValueObjectGetString(lease_tmp, "client-id"));
            lease->hostname = g_strdup(virJSONValueObjectGetString(lease_tmp, "hostname"));
4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439

            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);
4440
    VIR_FREE(lease_entries);
4441 4442
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4443

4444
    virNetworkObjEndAPI(&obj);
4445

4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456
    return rv;

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

4457

4458 4459 4460 4461 4462
/* A unified function to log network connections and disconnections */

static void
networkLogAllocation(virNetworkDefPtr netdef,
                     virNetworkForwardIfDefPtr dev,
4463
                     virMacAddrPtr mac,
4464 4465 4466 4467 4468
                     bool inUse)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    const char *verb = inUse ? "using" : "releasing";

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

4490

4491 4492 4493 4494 4495 4496 4497 4498
/* 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.
 */

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

4521
    netdef = virNetworkObjGetDef(obj);
4522
    VIR_DEBUG("Allocating port from net %s", netdef->name);
4523

4524
    if (!virNetworkObjIsActive(obj)) {
4525 4526 4527
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4528
        goto cleanup;
4529 4530
    }

4531
    VIR_DEBUG("Interface port group %s", port->group);
4532 4533 4534
    /* 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 已提交
4535
     */
4536
    portgroup = virPortGroupFindByName(netdef, port->group);
4537

4538 4539 4540 4541
    if (!port->bandwidth) {
        if (portgroup && portgroup->bandwidth &&
            virNetDevBandwidthCopy(&port->bandwidth,
                                   portgroup->bandwidth) < 0)
4542
            goto cleanup;
4543
    }
4544

4545 4546 4547 4548 4549 4550
    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;
4551

4552
        if (vlan && virNetDevVlanCopy(&port->vlan, vlan) < 0)
4553
            goto cleanup;
4554
    }
4555

4556 4557 4558 4559 4560 4561
    if (!port->trustGuestRxFilters) {
        if (portgroup && portgroup->trustGuestRxFilters)
            port->trustGuestRxFilters = portgroup->trustGuestRxFilters;
        else if (netdef->trustGuestRxFilters)
            port->trustGuestRxFilters = netdef->trustGuestRxFilters;
    }
4562

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

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

4590
        port->plug.bridge.brname = g_strdup(netdef->bridge);
4591
        port->plug.bridge.macTableManager = netdef->macTableManager;
4592

4593
        if (port->virtPortProfile) {
4594 4595 4596
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("<virtualport type='%s'> not supported for network "
                             "'%s' which uses IP forwarding"),
4597
                           virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4598
                           netdef->name);
4599
            goto cleanup;
4600 4601
        }

4602
        if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4603
            goto cleanup;
4604
        break;
4605

4606
    case VIR_NETWORK_FORWARD_HOSTDEV: {
4607
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI;
4608

4609
        if (networkCreateInterfacePool(netdef) < 0)
4610
            goto cleanup;
4611 4612

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

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

4646 4647 4648 4649 4650 4651
    case VIR_NETWORK_FORWARD_BRIDGE:
        if (netdef->bridge) {
            /* <forward type='bridge'/> <bridge name='xxx'/>
             * is VIR_DOMAIN_NET_TYPE_BRIDGE
             */

4652
            port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE;
4653
            port->plug.bridge.brname = g_strdup(netdef->bridge);
4654
            port->plug.bridge.macTableManager = netdef->macTableManager;
4655

4656
            if (port->virtPortProfile) {
4657
                /* only type='openvswitch' is allowed for bridges */
4658
                if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
4659 4660 4661
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport type='%s'> not supported for network "
                                     "'%s' which uses a bridge device"),
4662
                                   virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4663
                                   netdef->name);
4664
                    goto cleanup;
4665 4666
                }
            }
4667

4668
            if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4669
                goto cleanup;
4670 4671 4672 4673 4674 4675
            break;
        }

        /* intentionally fall through to the direct case for
         * VIR_NETWORK_FORWARD_BRIDGE with no bridge device defined
         */
4676
        G_GNUC_FALLTHROUGH;
4677 4678 4679 4680

    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
4681 4682 4683 4684 4685
        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
4686
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_DIRECT;
4687 4688 4689 4690

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

4694
        if (port->virtPortProfile) {
4695
            /* make sure type is supported for macvtap connections */
4696 4697
            if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
4698 4699 4700
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses a macvtap device"),
4701
                               virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4702
                               netdef->name);
4703
                goto cleanup;
4704 4705
            }
        }
4706

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

4719
            if (networkCreateInterfacePool(netdef) < 0)
4720
                goto cleanup;
4721

4722 4723 4724 4725 4726
            /* 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.
4727
             */
4728 4729
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4730 4731
                 port->virtPortProfile &&
                 (port->virtPortProfile->virtPortType
4732
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4733

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

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
4764
        goto cleanup;
4765 4766
    }

4767
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
4768 4769
                               port->ownername, &port->mac) < 0)
        goto cleanup;
M
Michal Privoznik 已提交
4770

4771
    if (virNetDevVPortProfileCheckComplete(port->virtPortProfile, true) < 0)
4772
        goto cleanup;
4773

4774 4775 4776 4777
    /* 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.
     */
4778
    VIR_DEBUG("Sanity check port config");
4779

4780
    if (port->vlan.nTags) {
4781 4782 4783 4784
        /* 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
4785
         */
4786 4787 4788
        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) ||
4789
              (port->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE &&
4790 4791
               port->virtPortProfile &&
               port->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
4792 4793 4794 4795 4796
            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);
4797
            goto cleanup;
4798 4799
        }
    }
4800 4801 4802 4803 4804 4805 4806 4807

    /* 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"));
4808
        goto cleanup;
4809
    }
4810

4811 4812 4813 4814
    netdef->connections++;
    if (dev)
        dev->connections++;
    /* finally we can call the 'plugged' hook script if any */
4815 4816
    if (networkRunHook(obj, port,
                       VIR_HOOK_NETWORK_OP_PORT_CREATED,
4817 4818 4819
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        netdef->connections--;
4820
        if (dev)
4821
            dev->connections--;
4822
        goto cleanup;
4823
    }
4824
    networkLogAllocation(netdef, dev, &port->mac, true);
4825 4826

    VIR_DEBUG("Port allocated");
4827

4828
    ret = 0;
4829
 cleanup:
4830
    return ret;
4831
}
4832

4833

4834 4835 4836
/* networkNotifyPort:
 * @obj: the network to notify
 * @port: the port definition to notify
4837 4838 4839 4840
 *
 * 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
4841
 * order.
4842
 */
4843
static int
4844 4845
networkNotifyPort(virNetworkObjPtr obj,
                  virNetworkPortDefPtr port)
4846 4847
{
    virNetworkDefPtr netdef;
4848
    virNetworkForwardIfDefPtr dev = NULL;
4849
    size_t i;
4850
    int ret = -1;
4851

4852
    netdef = virNetworkObjGetDef(obj);
4853

4854
    if (!virNetworkObjIsActive(obj)) {
4855 4856 4857
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4858
        goto cleanup;
4859
    }
4860

4861 4862 4863 4864
    switch (port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unexpectedly got a network port without a plug"));
4865
        goto cleanup;
4866

4867 4868 4869 4870
    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) {
4871
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4872
                           _("Unexpectedly got a network port without a network bridge"));
4873
            goto cleanup;
4874
        }
4875 4876 4877 4878
        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
        if (networkCreateInterfacePool(netdef) < 0)
4879
            goto cleanup;
4880 4881

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

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

4918 4919 4920
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:

        if (networkCreateInterfacePool(netdef) < 0)
4921
            goto cleanup;
4922 4923

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

        /* 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) &&
4951
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4952 4953 4954
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' claims the PCI device at "
                             "domain=%d bus=%d slot=%d function=%d "
4955
                             "is already in use by a different network port"),
4956 4957 4958
                           netdef->name,
                           dev->device.pci.domain, dev->device.pci.bus,
                           dev->device.pci.slot, dev->device.pci.function);
4959
            goto cleanup;
4960
        }
4961 4962 4963 4964 4965 4966

        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
    default:
        virReportEnumRangeError(virNetworkPortPlugType, port->plugtype);
4967
        goto cleanup;
4968 4969
    }

4970
    netdef->connections++;
4971 4972
    if (dev)
        dev->connections++;
4973
    /* finally we can call the 'plugged' hook script if any */
4974
    if (networkRunHook(obj, port, VIR_HOOK_NETWORK_OP_PORT_CREATED,
4975 4976 4977 4978 4979
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
4980
        goto cleanup;
4981
    }
4982 4983
    networkLogAllocation(netdef, dev, &port->mac, true);

4984
    ret = 0;
4985 4986 4987 4988 4989
 cleanup:
    return ret;
}


4990 4991 4992
/* networkReleasePort:
 * @obj: the network to release from
 * @port: the port definition to release
4993 4994 4995 4996 4997 4998 4999 5000
 *
 * 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.
 */
5001
static int
5002 5003
networkReleasePort(virNetworkObjPtr obj,
                   virNetworkPortDefPtr port)
5004
{
5005
    virNetworkDriverStatePtr driver = networkGetDriver();
5006
    virNetworkDefPtr netdef;
5007
    virNetworkForwardIfDefPtr dev = NULL;
5008 5009
    size_t i;
    int ret = -1;
5010

5011
    netdef = virNetworkObjGetDef(obj);
5012

5013 5014 5015
    switch ((virNetworkPortPlugType)port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        VIR_DEBUG("Releasing network device with no plug type");
5016 5017
        break;

5018 5019 5020 5021 5022
    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;
5023 5024
        break;

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

5034 5035
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5036
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
5037
                STREQ(port->plug.direct.linkdev, netdef->forward.ifs[i].device.dev)) {
5038
                dev = &netdef->forward.ifs[i];
5039 5040 5041
                break;
            }
        }
5042

5043
        if (!dev) {
5044
            virReportError(VIR_ERR_INTERNAL_ERROR,
5045 5046
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5047 5048
                           netdef->name, port->plug.direct.linkdev);
            goto cleanup;
5049
        }
5050
        break;
5051

5052 5053
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:
        if (netdef->forward.nifs == 0) {
5054
            virReportError(VIR_ERR_INTERNAL_ERROR,
5055 5056 5057 5058
                           _("network '%s' uses a hostdev mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
            goto cleanup;
5059 5060
        }

5061 5062
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5063
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5064
                virPCIDeviceAddressEqual(&port->plug.hostdevpci.addr,
5065 5066
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5067 5068 5069 5070 5071 5072 5073 5074 5075
                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,
5076 5077 5078 5079 5080
                           port->plug.hostdevpci.addr.domain,
                           port->plug.hostdevpci.addr.bus,
                           port->plug.hostdevpci.addr.slot,
                           port->plug.hostdevpci.addr.function);
            goto cleanup;
5081
        }
5082 5083 5084 5085 5086 5087
        break;

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

5090
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, port->ownername, &port->mac);
5091 5092 5093 5094 5095

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

5100 5101 5102 5103 5104 5105
    ret = 0;
 cleanup:
    return ret;
}


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

5140
    virMacAddrFormat(ifaceMac, ifmac);
5141 5142 5143 5144 5145 5146

    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"),
5147
                       ifmac, def->name);
5148 5149 5150
        return -1;
    }

5151 5152 5153 5154 5155
    if (!netBand || !netBand->in) {
        VIR_DEBUG("No network bandwidth controls present");
        /* no QoS required, claim success */
        return 1;
    }
5156
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
5157 5158
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor))) {
        VIR_DEBUG("No old/new interface bandwidth floor");
5159
        /* no QoS required, claim success */
5160
        return 1;
5161
    }
5162 5163

    tmp_new_rate = netBand->in->average;
5164 5165 5166 5167
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
5168 5169 5170 5171 5172 5173

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

5199 5200
    if (new_rate)
        *new_rate = tmp_new_rate;
5201 5202
    ret = 0;

5203
 cleanup:
5204 5205 5206
    return ret;
}

5207

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

5224 5225
    if ((ret = virBitmapNextClearBit(classIdMap, -1)) < 0)
        ret = virBitmapSize(classIdMap);
5226

5227
    if (virBitmapSetBitExpand(classIdMap, ret) < 0)
5228 5229 5230 5231 5232
        return -1;

    return ret;
}

5233

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

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

5256
    plug_ret = virNetDevBandwidthPlug(def->bridge, def->bandwidth,
5257
                                      mac, ifaceBand, next_id);
5258
    if (plug_ret < 0) {
5259
        ignore_value(virNetDevBandwidthUnplug(def->bridge, next_id));
5260 5261 5262 5263
        goto cleanup;
    }

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

    ret = 0;
5285 5286 5287 5288 5289 5290
 cleanup:
    return ret;
}


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

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

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

5313
    virMacAddrFormat(mac, ifmac);
5314

5315
    if (networkPlugBandwidthImpl(obj, mac, ifaceBand, class_id, new_rate) < 0)
5316 5317 5318
        goto cleanup;

    ret = 0;
5319

5320
 cleanup:
5321 5322 5323
    return ret;
}

5324

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

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

5346 5347
        if (def->bandwidth->in->peak > 0)
            new_rate = def->bandwidth->in->peak;
5348

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

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

5376
 cleanup:
5377 5378
    return ret;
}
5379

5380

5381
static void
5382
networkNetworkObjTaint(virNetworkObjPtr obj,
5383
                       virNetworkTaintFlags taint)
5384
{
5385 5386
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

5387
    if (virNetworkObjTaint(obj, taint)) {
5388
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5389
        virUUIDFormat(def->uuid, uuidstr);
5390 5391

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5392
                 def->name, uuidstr, virNetworkTaintTypeToString(taint));
5393 5394
    }
}
5395 5396


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

    old_floor = new_floor = 0;

5413 5414
    if (oldBandwidth && oldBandwidth->in)
        old_floor = oldBandwidth->in->floor;
5415 5416 5417 5418
    if (newBandwidth && newBandwidth->in)
        new_floor = newBandwidth->in->floor;

    if (new_floor == old_floor)
5419 5420
        return 0;

5421
    def = virNetworkObjGetDef(obj);
5422

5423 5424
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, oldBandwidth,
                                          mac, &new_rate)) < 0) {
5425
        /* helper reported error */
5426
        return -1;
5427 5428 5429 5430
    }

    if (plug_ret > 0) {
        /* no QoS needs to be set; claim success */
5431
        return 0;
5432 5433 5434 5435
    }

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

5436
    if (oldBandwidth && oldBandwidth->in && oldBandwidth->in->floor &&
5437
        newBandwidth->in && newBandwidth->in->floor) {
5438 5439
        /* Either we just need to update @floor .. */

5440
        if (virNetDevBandwidthUpdateRate(def->bridge,
5441
                                         *class_id,
5442
                                         def->bandwidth,
5443
                                         newBandwidth->in->floor) < 0)
5444
            return -1;
5445

5446
        tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5447
        tmp_floor_sum -= oldBandwidth->in->floor;
5448 5449 5450
        tmp_floor_sum += newBandwidth->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
        new_rate -= tmp_floor_sum;
5451

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

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

5470 5471
        if (networkPlugBandwidthImpl(obj, mac, newBandwidth,
                                     class_id,
5472
                                     new_rate) < 0)
5473
            return -1;
5474 5475 5476
    } else {
        /* .. or unplug old. */

5477 5478
        if (networkUnplugBandwidth(obj, oldBandwidth, class_id) < 0)
            return -1;
5479 5480
    }

5481 5482 5483 5484
    return 0;
}


5485 5486 5487 5488 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
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;
J
Ján Tomko 已提交
5530
    g_autoptr(virNetworkPortDef) portdef = NULL;
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
    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);
5572 5573 5574 5575
    if (rc < 0)
        goto cleanup;

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

5578
        virErrorPreserveLast(&save_err);
5579
        ignore_value(networkReleasePort(obj, portdef));
5580 5581
        virErrorRestore(&save_err);

5582 5583 5584 5585
        goto cleanup;
    }

    ret = virGetNetworkPort(net, portdef->uuid);
5586
    portdef = NULL;
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
 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;
}


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

5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917

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


5925 5926 5927 5928 5929 5930 5931 5932 5933 5934
static virStateDriver networkStateDriver = {
    .name = "bridge",
    .stateInitialize  = networkStateInitialize,
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
};

int
networkRegister(void)
{
5935 5936
    if (virRegisterConnectDriver(&networkConnectDriver, false) < 0)
        return -1;
5937 5938 5939 5940 5941 5942
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
    return 0;
}