bridge_driver.c 188.5 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
    leasefile = g_strdup_printf("%s/%s.leases", driver->dnsmasqStateDir, netname);
372 373 374
    return leasefile;
}

375

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

382
    leasefile = g_strdup_printf("%s/%s.status", driver->dnsmasqStateDir, bridge);
383 384 385
    return leasefile;
}

386

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

393
    conffile = g_strdup_printf("%s/%s.conf", driver->dnsmasqStateDir, netname);
394 395 396
    return conffile;
}

397

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

404
    pidfilebase = g_strdup_printf("%s-radvd", netname);
405 406 407
    return pidfilebase;
}

408

409
static char *
410 411
networkRadvdConfigFileName(virNetworkDriverStatePtr driver,
                           const char *netname)
412 413 414
{
    char *configfile;

415
    configfile = g_strdup_printf("%s/%s-radvd.conf", driver->radvdStateDir, netname);
416 417
    return configfile;
}
418

419

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

    int ret = -1;

    /* remove the (possibly) existing dnsmasq and radvd files */
438
    if (!(dctx = dnsmasqContextNew(def->name,
439
                                   driver->dnsmasqStateDir))) {
440
        goto cleanup;
441
    }
442

443
    if (!(leasefile = networkDnsmasqLeaseFileNameDefault(driver, def->name)))
444 445
        goto cleanup;

446
    if (!(customleasefile = networkDnsmasqLeaseFileNameCustom(driver, def->bridge)))
447 448
        goto cleanup;

449
    if (!(radvdconfigfile = networkRadvdConfigFileName(driver, def->name)))
450
        goto cleanup;
451 452

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
453
        goto cleanup;
454

455
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
456
        goto cleanup;
457

458
    if (!(statusfile = virNetworkConfigFile(driver->stateDir, def->name)))
459
        goto cleanup;
460

461
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir, def->bridge)))
M
Michal Privoznik 已提交
462 463
        goto cleanup;

464 465 466
    /* dnsmasq */
    dnsmasqDelete(dctx);
    unlink(leasefile);
467
    unlink(customleasefile);
468
    unlink(configfile);
469

M
Michal Privoznik 已提交
470 471 472
    /* MAC map manager */
    unlink(macMapFile);

473 474
    /* radvd */
    unlink(radvdconfigfile);
475
    virPidFileDelete(driver->pidDir, radvdpidbase);
476

477 478 479
    /* remove status file */
    unlink(statusfile);

480
    /* remove the network definition */
481
    virNetworkObjRemoveInactive(driver->networks, obj);
482 483 484

    ret = 0;

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

497

498 499 500
static char *
networkBridgeDummyNicName(const char *brname)
{
501
    static const char dummyNicSuffix[] = "-nic";
502 503
    char *nicname;

504 505 506 507 508 509 510
    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.
         */
511 512 513 514 515
        nicname = g_strdup_printf("%.*s%s%s",
                                  /* space for last 3 chars + "-nic" + NULL */
                                  (int)(IFNAMSIZ - (3 + sizeof(dummyNicSuffix))),
                                  brname, brname + strlen(brname) - 3,
                                  dummyNicSuffix);
516
    } else {
517
        nicname = g_strdup_printf("%s%s", brname, dummyNicSuffix);
518
    }
519 520 521
    return nicname;
}

522

523 524 525 526 527 528 529 530 531 532 533 534 535 536 537
static int
networkNotifyPort(virNetworkObjPtr obj,
                  virNetworkPortDefPtr port);

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

    networkNotifyPort(obj, port);

    return false;
}

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

549
    virObjectLock(obj);
550
    if (!virNetworkObjIsActive(obj)) {
551 552
        ret = 0;
        goto cleanup;
553
    }
554
    def = virNetworkObjGetDef(obj);
555

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

565
        if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
566
                                             def->bridge)))
567 568
            goto cleanup;

569
        if (!(macmap = virMacMapNew(macMapFile)))
570 571
            goto cleanup;

572 573
        virNetworkObjSetMacMap(obj, macmap);

574
        break;
575

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

592 593 594
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
595 596 597 598 599

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

602 603
    virNetworkObjPortForEach(obj, networkUpdatePort, obj);

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

610
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
611
                                           def->name,
612
                                           &dnsmasqPid,
613
                                           dnsmasqCapsGetBinaryPath(dnsmasq_caps)));
614
        virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
M
Michal Privoznik 已提交
615

616
        radvdpidbase = networkRadvdPidfileBasename(def->name);
617 618
        if (!radvdpidbase)
            goto cleanup;
619

620 621
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
622 623
                                           &radvdPid, RADVD));
        virNetworkObjSetRadvdPid(obj, radvdPid);
624
        VIR_FREE(radvdpidbase);
625
    }
626

627 628
    ret = 0;
 cleanup:
629
    virObjectUnlock(obj);
630
    virObjectUnref(dnsmasq_caps);
631
    VIR_FREE(macMapFile);
632 633
    return ret;
}
634

635

636
static int
637
networkAutostartConfig(virNetworkObjPtr obj,
638
                       void *opaque)
639
{
640
    virNetworkDriverStatePtr driver = opaque;
641
    int ret = -1;
642

643
    virObjectLock(obj);
644
    if (virNetworkObjIsAutostart(obj) &&
645 646
        !virNetworkObjIsActive(obj) &&
        networkStartNetwork(driver, obj) < 0)
647 648 649 650
        goto cleanup;

    ret = 0;
 cleanup:
651
    virObjectUnlock(obj);
652
    return ret;
653 654
}

655

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

665 666 667 668 669 670 671
    if (dbus_message_is_signal(message,
                               "org.fedoraproject.FirewallD1", "Reloaded")) {
        reload = true;

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

672 673 674
        g_autofree char *name = NULL;
        g_autofree char *old_owner = NULL;
        g_autofree char *new_owner = NULL;
675 676 677 678 679 680 681 682 683 684 685 686 687 688

        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) {
689
        VIR_DEBUG("Reload in bridge_driver because of firewalld.");
690
        networkReloadFirewallRules(driver, false);
691 692 693 694 695 696
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

697

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

716
    if (VIR_ALLOC(network_driver) < 0)
717
        goto error;
718

719
    network_driver->lockFD = -1;
720 721
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
722 723
        goto error;
    }
724

725 726
    network_driver->privileged = privileged;

C
Cole Robinson 已提交
727 728 729
    if (!(network_driver->xmlopt = networkDnsmasqCreateXMLConf()))
        goto error;

730 731 732 733
    /* configuration/state paths are one of
     * ~/.config/libvirt/... (session/unprivileged)
     * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
     */
734
    if (privileged) {
735 736 737 738 739 740
        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");
741
    } else {
742 743 744
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
745
            goto error;
746

747 748 749 750 751 752
        network_driver->networkConfigDir = g_strdup_printf("%s/qemu/networks", configdir);
        network_driver->networkAutostartDir = g_strdup_printf("%s/qemu/networks/autostart", configdir);
        network_driver->stateDir = g_strdup_printf("%s/network/lib", rundir);
        network_driver->pidDir = g_strdup_printf("%s/network/run", rundir);
        network_driver->dnsmasqStateDir = g_strdup_printf("%s/dnsmasq/lib", rundir);
        network_driver->radvdStateDir = g_strdup_printf("%s/radvd/lib", rundir);
753 754
    }

755
    if (virFileMakePath(network_driver->stateDir) < 0) {
756 757
        virReportSystemError(errno,
                             _("cannot create directory %s"),
758
                             network_driver->stateDir);
759 760 761
        goto error;
    }

762 763 764 765 766
    if ((network_driver->lockFD =
         virPidFileAcquire(network_driver->stateDir, "driver",
                           true, getpid())) < 0)
        goto error;

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

770
    if (!(network_driver->networks = virNetworkObjListNew()))
771 772
        goto error;

773
    if (virNetworkObjLoadAllState(network_driver->networks,
774 775
                                  network_driver->stateDir,
                                  network_driver->xmlopt) < 0)
776 777
        goto error;

778 779
    if (virNetworkObjLoadAllConfigs(network_driver->networks,
                                    network_driver->networkConfigDir,
780 781
                                    network_driver->networkAutostartDir,
                                    network_driver->xmlopt) < 0)
782 783
        goto error;

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

797 798 799 800 801 802 803 804
    if (virDriverShouldAutostart(network_driver->stateDir, &autostart) < 0)
        goto error;

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

806
    network_driver->networkEventState = virObjectEventStateNew();
807

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

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

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

844

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

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


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

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

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

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

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

901
    virObjectUnref(network_driver->dnsmasqCaps);
902

903
    virMutexDestroy(&network_driver->lock);
904

905
    VIR_FREE(network_driver);
906 907 908 909 910

    return 0;
}


911 912
static virDrvOpenStatus
networkConnectOpen(virConnectPtr conn,
J
Ján Tomko 已提交
913 914
                   virConnectAuthPtr auth G_GNUC_UNUSED,
                   virConfPtr conf G_GNUC_UNUSED,
915 916 917 918
                   unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

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

925 926 927 928
    if (!virConnectValidateURIPath(conn->uri->path,
                                   "network",
                                   network_driver->privileged))
        return VIR_DRV_OPEN_ERROR;
929 930 931 932 933 934 935

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

    return VIR_DRV_OPEN_SUCCESS;
}

J
Ján Tomko 已提交
936
static int networkConnectClose(virConnectPtr conn G_GNUC_UNUSED)
937 938 939 940 941
{
    return 0;
}


J
Ján Tomko 已提交
942
static int networkConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)
943 944 945 946 947 948
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}


J
Ján Tomko 已提交
949
static int networkConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)
950 951 952 953 954 955
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}


J
Ján Tomko 已提交
956
static int networkConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
957 958 959 960 961
{
    return 1;
}


962 963 964 965 966
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
967 968 969
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
970
{
971 972
    size_t i;
    int ret = -1;
973 974 975 976 977 978 979
    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.
     */
980
    for (i = 0; i < 25; i++) {
981
        int signum = 0;
982
        if (i == 0) {
983
            signum = SIGTERM;
984
        } else if (i == 15) {
985 986 987 988 989 990 991 992 993 994 995 996 997
            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)));
            }
998
            return ret;
999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
        }
        /* 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.
         */
1015
        g_usleep(20 * 1000);
1016 1017 1018 1019 1020 1021 1022
    }
    VIR_WARN("Timed out waiting after SIG%s to %s process %d "
             "(network '%s')",
             signame, daemonName, pid, networkName);
    return ret;
}

1023

J
Ján Tomko 已提交
1024 1025 1026
/* the following does not build a file, it builds a list
 * which is later saved into a file
 */
1027
static int
G
Gene Czarcinski 已提交
1028
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
1029
                                 virNetworkIPDefPtr ipdef)
1030
{
1031
    size_t i;
G
Gene Czarcinski 已提交
1032
    bool ipv6 = false;
1033

G
Gene Czarcinski 已提交
1034 1035
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
1036 1037
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
1038
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
1039 1040
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
1041
                return -1;
1042
    }
1043

G
Gene Czarcinski 已提交
1044 1045 1046
    return 0;
}

1047

G
Gene Czarcinski 已提交
1048 1049 1050 1051
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
1052
    size_t i, j;
G
Gene Czarcinski 已提交
1053

1054 1055
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
1056
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
1057
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
1058
                for (j = 0; j < host->nnames; j++)
1059 1060
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
1061 1062
            }
        }
1063 1064
    }

1065
    return 0;
1066 1067 1068
}


1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
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;
}


1106
int
1107
networkDnsmasqConfContents(virNetworkObjPtr obj,
1108 1109 1110
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
J
Ján Tomko 已提交
1111
                           dnsmasqCapsPtr caps G_GNUC_UNUSED)
1112
{
1113
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1114
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1115
    int r, ret = -1;
1116
    int nbleases = 0;
1117
    size_t i;
1118
    virNetworkDNSDefPtr dns = &def->dns;
1119
    bool wantDNS = dns->enable != VIR_TRISTATE_BOOL_NO;
1120
    virNetworkIPDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
G
Gene Czarcinski 已提交
1121
    bool ipv6SLAAC;
1122
    char *saddr = NULL, *eaddr = NULL;
1123

1124 1125
    *configstr = NULL;

1126
    /*
1127 1128 1129
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1130
     *
1131 1132
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1133
     */
1134 1135 1136 1137 1138 1139

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

1140
    /* create dnsmasq config file appropriate for this network */
1141 1142

    /* Don't forget to update networkxml2conftest :-) */
1143
    virBufferAsprintf(&configbuf,
1144 1145 1146 1147 1148 1149 1150
                      "##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"
1151
                      "strict-order\n",
1152
                      def->name);
1153

1154 1155 1156 1157 1158 1159
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1160
    if (wantDNS && def->dns.forwarders) {
1161 1162 1163 1164 1165 1166 1167 1168 1169
        /* 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;

1170 1171
        for (i = 0; i < def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &def->dns.forwarders[i];
1172 1173 1174 1175 1176 1177 1178 1179 1180 1181

            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);
1182
                VIR_FREE(addr);
1183 1184
                if (!fwd->domain)
                    addNoResolv = true;
1185 1186 1187 1188
            } else {
                /* "don't forward requests for this domain" */
                virBufferAddLit(&configbuf, "#\n");
            }
1189
        }
1190 1191
        if (addNoResolv)
            virBufferAddLit(&configbuf, "no-resolv\n");
1192 1193
    }

1194 1195
    if (def->domain) {
        if (def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1196 1197
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1198
                              def->domain);
1199
        }
1200
        virBufferAsprintf(&configbuf,
1201 1202
                          "domain=%s\n"
                          "expand-hosts\n",
1203
                          def->domain);
1204
    }
1205

1206
    if (wantDNS &&
1207
        networkDnsmasqConfLocalPTRs(&configbuf, def) < 0)
1208 1209
        goto cleanup;

1210
    if (wantDNS && def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1211 1212 1213 1214
        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)
1215
         */
1216
        virBufferAddLit(&configbuf, "local=//\n");
1217
    }
1218

1219
    if (pidfile)
1220
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1221

1222
    /* dnsmasq will *always* listen on localhost unless told otherwise */
P
Pavel Timofeev 已提交
1223
#ifdef __linux__
1224
    virBufferAddLit(&configbuf, "except-interface=lo\n");
P
Pavel Timofeev 已提交
1225 1226 1227 1228
#else
    /* BSD family OSes and Solaris call loopback interface as lo0 */
    virBufferAddLit(&configbuf, "except-interface=lo0\n");
#endif
1229

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

            if (!ipaddr)
                goto cleanup;
1259

1260
            /* also part of CVE 2012-3411 - if the host's version of
1261
             * dnsmasq doesn't have bind-dynamic, only allow listening on
1262 1263
             * private/local IP addresses (see RFC1918/RFC3484/RFC4193)
             */
1264 1265
            if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
                !virSocketAddrIsPrivate(&tmpipdef->address)) {
1266 1267 1268 1269
                unsigned long version = dnsmasqCapsGetVersion(caps);

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
1270
                                 "The version of dnsmasq on this host (%d.%d) "
1271 1272 1273 1274
                                 "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 "
1275 1276 1277 1278 1279 1280
                                 "(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);
1281
                VIR_FREE(ipaddr);
1282 1283
                goto cleanup;
            }
1284
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
1285 1286 1287
            VIR_FREE(ipaddr);
        }
    }
1288

1289 1290
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
1291
     * guaranteed to not work, and set no-resolv so that no dns
1292 1293 1294
     * 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).
1295 1296 1297
     * 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.
1298
     */
1299
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE) {
1300
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
1301
                        "no-resolv\n");
1302 1303 1304 1305
        if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM)) {
            /* interface=* (any), interval=0 (default), lifetime=0 (seconds) */
            virBufferAddLit(&configbuf, "ra-param=*,0,0\n");
        }
1306
    }
1307

1308 1309 1310 1311 1312
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1313
        }
1314

1315 1316 1317 1318 1319 1320 1321 1322
        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'"),
1323
                               def->name);
1324 1325 1326 1327 1328 1329
                goto cleanup;
            }
            if (!dns->srvs[i].protocol) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing required 'service' "
                                 "attribute in SRV record of network '%s'"),
1330
                               def->name);
1331 1332 1333 1334 1335 1336 1337
                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);
1338

1339 1340 1341 1342 1343 1344 1345
            /* 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.
1346
             */
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
            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");
1367
        }
1368 1369
    }

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

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1428 1429
        int prefix;

1430
        prefix = virNetworkIPDefPrefix(ipdef);
1431 1432 1433
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1434
                           def->bridge);
1435 1436
            goto cleanup;
        }
1437
        for (r = 0; r < ipdef->nranges; r++) {
1438 1439
            int thisRange;

1440 1441
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1442
                goto cleanup;
1443

1444 1445 1446 1447 1448 1449
            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;
1450
                g_autofree char *netmaskStr = NULL;
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464

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

1466
            VIR_FREE(saddr);
1467
            VIR_FREE(eaddr);
1468
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1469 1470
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1471
                                              virNetworkIPDefPrefix(ipdef));
1472 1473 1474
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1475
        }
1476

1477
        /*
1478 1479 1480 1481
         * 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)
1482 1483
         */
        if (!ipdef->nranges && ipdef->nhosts) {
1484
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
1485 1486
            if (!bridgeaddr)
                goto cleanup;
1487 1488 1489
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static",
                              bridgeaddr);
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1490
                virBufferAsprintf(&configbuf, ",%d", prefix);
1491
            virBufferAddLit(&configbuf, "\n");
1492 1493
            VIR_FREE(bridgeaddr);
        }
1494

G
Gene Czarcinski 已提交
1495 1496
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1497

G
Gene Czarcinski 已提交
1498 1499
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
1500
            if (ipdef->nranges || ipdef->nhosts) {
1501
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1502 1503
                virBufferAddLit(&configbuf, "dhcp-authoritative\n");
            }
1504

G
Gene Czarcinski 已提交
1505
            if (ipdef->tftproot) {
1506 1507
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1508
            }
1509

G
Gene Czarcinski 已提交
1510 1511 1512
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1513

1514
                    if (!bootserver)
G
Gene Czarcinski 已提交
1515
                        goto cleanup;
1516
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1517
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1518 1519
                    VIR_FREE(bootserver);
                } else {
1520
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1521 1522 1523 1524 1525
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1526

1527
    if (nbleases > 0)
1528
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1529

G
Gene Czarcinski 已提交
1530 1531
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1532
        goto cleanup;
G
Gene Czarcinski 已提交
1533 1534 1535 1536 1537 1538

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

1542 1543
    /* Likewise, always create this file and put it on the
     * commandline, to allow for runtime additions.
G
Gene Czarcinski 已提交
1544
     */
1545 1546 1547 1548
    if (wantDNS) {
        virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
                          dctx->addnhostsfile->path);
    }
G
Gene Czarcinski 已提交
1549

1550 1551 1552 1553
    /* 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 已提交
1554 1555
    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
1556
        if (ipv6def) {
1557
            virBufferAddLit(&configbuf, "enable-ra\n");
1558
        } else {
1559
            for (i = 0;
1560
                 (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1561
                 i++) {
G
Gene Czarcinski 已提交
1562 1563 1564 1565
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1566 1567
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1568 1569
                    VIR_FREE(bridgeaddr);
                }
1570
            }
1571
        }
1572 1573
    }

1574 1575 1576 1577 1578 1579
    if (def->namespaceData) {
        networkDnsmasqXmlNsDefPtr dnsmasqxmlns = def->namespaceData;
        for (i = 0; i < dnsmasqxmlns->noptions; i++)
            virBufferAsprintf(&configbuf, "%s\n", dnsmasqxmlns->options[i]);
    }

1580 1581 1582
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1583
    ret = 0;
G
Gene Czarcinski 已提交
1584

1585
 cleanup:
1586 1587
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1588
    virBufferFreeAndReset(&configbuf);
1589
    return ret;
1590 1591
}

1592

1593
/* build the dnsmasq command line */
1594 1595
static int ATTRIBUTE_NONNULL(3)
networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
1596
                                  virNetworkObjPtr obj,
1597
                                  virCommandPtr *cmdout,
1598 1599
                                  char *pidfile,
                                  dnsmasqContext *dctx)
1600
{
1601
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1602
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1603
    virCommandPtr cmd = NULL;
G
Gene Czarcinski 已提交
1604
    int ret = -1;
1605 1606
    char *configfile = NULL;
    char *configstr = NULL;
1607
    char *leaseshelper_path = NULL;
1608

1609
    virNetworkObjSetDnsmasqPid(obj, -1);
1610

1611
    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
1612
                                   dctx, dnsmasq_caps) < 0)
1613 1614 1615 1616 1617
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1618
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
1619 1620 1621 1622 1623
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1624 1625
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1626 1627 1628
        goto cleanup;
    }

1629 1630
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1631
                                                  abs_top_builddir "/src",
1632 1633 1634
                                                  LIBEXECDIR)))
        goto cleanup;

1635
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1636
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1637 1638
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1639
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1640
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", def->bridge);
1641

1642
    *cmdout = cmd;
1643
    ret = 0;
1644
 cleanup:
1645
    virObjectUnref(dnsmasq_caps);
1646 1647
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1648
    VIR_FREE(leaseshelper_path);
1649 1650 1651
    return ret;
}

1652

1653
static int
1654
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1655
                       virNetworkObjPtr obj)
1656
{
1657
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1658 1659 1660
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1661 1662
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
1663
    pid_t dnsmasqPid;
1664
    int ret = -1;
1665
    dnsmasqContext *dctx = NULL;
1666

1667
    /* see if there are any IP addresses that need a dhcp server */
1668
    i = 0;
1669
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i))) {
1670
        i++;
1671 1672 1673 1674
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1675 1676 1677 1678 1679 1680
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1681
    if (!needDnsmasq && def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1682
        /* no DHCP services needed, and user disabled DNS service */
1683 1684 1685 1686
        ret = 0;
        goto cleanup;
    }

1687
    if (virFileMakePath(driver->pidDir) < 0) {
1688
        virReportSystemError(errno,
1689
                             _("cannot create directory %s"),
1690
                             driver->pidDir);
1691
        goto cleanup;
1692 1693
    }

1694
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, def->name)))
1695
        goto cleanup;
1696

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

1704
    dctx = dnsmasqContextNew(def->name, driver->dnsmasqStateDir);
1705 1706 1707
    if (dctx == NULL)
        goto cleanup;

1708
    if (networkDnsmasqCapsRefresh(driver) < 0)
1709
        goto cleanup;
1710

1711
    ret = networkBuildDhcpDaemonCommandLine(driver, obj, &cmd, pidfile, dctx);
1712 1713 1714 1715 1716
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1717
        goto cleanup;
1718

G
Guido Günther 已提交
1719
    ret = virCommandRun(cmd, NULL);
1720
    if (ret < 0)
1721 1722 1723
        goto cleanup;

    /*
1724 1725 1726 1727 1728
     * 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
1729 1730
     */

1731
    ret = virPidFileRead(driver->pidDir, def->name, &dnsmasqPid);
1732
    if (ret < 0)
1733
        goto cleanup;
1734
    virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
1735

1736
    ret = 0;
1737
 cleanup:
1738
    VIR_FREE(pidfile);
1739
    virCommandFree(cmd);
1740
    dnsmasqContextFree(dctx);
1741 1742 1743
    return ret;
}

1744

1745 1746
/* networkRefreshDhcpDaemon:
 *  Update dnsmasq config files, then send a SIGHUP so that it rereads
G
Gene Czarcinski 已提交
1747 1748
 *  them.   This only works for the dhcp-hostsfile and the
 *  addn-hosts file.
1749 1750 1751
 *
 *  Returns 0 on success, -1 on failure.
 */
1752
static int
1753
networkRefreshDhcpDaemon(virNetworkDriverStatePtr driver,
1754
                         virNetworkObjPtr obj)
1755
{
1756
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1757 1758
    int ret = -1;
    size_t i;
1759
    pid_t dnsmasqPid;
1760
    virNetworkIPDefPtr ipdef, ipv4def, ipv6def;
1761
    dnsmasqContext *dctx = NULL;
1762

G
Gene Czarcinski 已提交
1763
    /* if no IP addresses specified, nothing to do */
1764
    if (!virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1765 1766
        return 0;

1767
    /* if there's no running dnsmasq, just start it */
1768 1769
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid <= 0 || (kill(dnsmasqPid, 0) < 0))
1770
        return networkStartDhcpDaemon(driver, obj);
1771

1772 1773
    VIR_INFO("Refreshing dnsmasq for network %s", def->bridge);
    if (!(dctx = dnsmasqContextNew(def->name,
1774
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1775
        goto cleanup;
1776
    }
G
Gene Czarcinski 已提交
1777 1778 1779 1780 1781 1782

    /* 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;
1783
    for (i = 0;
1784
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
1785
         i++) {
G
Gene Czarcinski 已提交
1786 1787
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1788 1789
    }

G
Gene Czarcinski 已提交
1790
    ipv6def = NULL;
1791
    for (i = 0;
1792
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1793
         i++) {
G
Gene Czarcinski 已提交
1794 1795
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1796 1797
    }

G
Gene Czarcinski 已提交
1798
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1799
        goto cleanup;
G
Gene Czarcinski 已提交
1800 1801

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

1804
    if (networkBuildDnsmasqHostsList(dctx, &def->dns) < 0)
J
Ján Tomko 已提交
1805
        goto cleanup;
1806 1807

    if ((ret = dnsmasqSave(dctx)) < 0)
1808
        goto cleanup;
1809

1810 1811
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    ret = kill(dnsmasqPid, SIGHUP);
1812
 cleanup:
1813 1814 1815 1816
    dnsmasqContextFree(dctx);
    return ret;
}

1817

1818 1819 1820 1821 1822 1823 1824 1825
/* 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
1826
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1827
                         virNetworkObjPtr obj)
1828
{
1829
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1830 1831
    pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);

1832
    /* if there is a running dnsmasq, kill it */
1833
    if (dnsmasqPid > 0) {
1834
        networkKillDaemon(dnsmasqPid, "dnsmasq", def->name);
1835
        virNetworkObjSetDnsmasqPid(obj, -1);
1836
    }
1837
    /* now start dnsmasq if it should be started */
1838
    return networkStartDhcpDaemon(driver, obj);
1839 1840
}

1841

G
Gene Czarcinski 已提交
1842 1843 1844 1845 1846 1847
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";

1848
static int
1849
networkRadvdConfContents(virNetworkObjPtr obj,
1850
                         char **configstr)
1851
{
1852
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
E
Eric Blake 已提交
1853
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1854 1855
    int ret = -1;
    size_t i;
1856
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1857
    bool v6present = false, dhcp6 = false;
1858 1859

    *configstr = NULL;
1860

G
Gene Czarcinski 已提交
1861
    /* Check if DHCPv6 is needed */
1862
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
G
Gene Czarcinski 已提交
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875
        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;
    }

1876 1877 1878
    /* create radvd config file appropriate for this network;
     * IgnoreIfMissing allows radvd to start even when the bridge is down
     */
1879
    virBufferAsprintf(&configbuf, "interface %s\n"
1880 1881
                      "{\n"
                      "  AdvSendAdvert on;\n"
1882
                      "  IgnoreIfMissing on;\n"
G
Gene Czarcinski 已提交
1883 1884
                      "  AdvManagedFlag %s;\n"
                      "%s",
1885
                      def->bridge,
G
Gene Czarcinski 已提交
1886 1887
                      dhcp6 ? "on" : "off",
                      dhcp6 ? "\n" : radvd1);
1888 1889

    /* add a section for each IPv6 address in the config */
1890
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
1891 1892 1893
        int prefix;
        char *netaddr;

1894
        prefix = virNetworkIPDefPrefix(ipdef);
1895
        if (prefix < 0) {
1896 1897
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1898
                           def->bridge);
1899 1900
            goto cleanup;
        }
1901
        if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
1902
            goto cleanup;
1903
        virBufferAsprintf(&configbuf,
1904
                          "  prefix %s/%d\n"
G
Gene Czarcinski 已提交
1905 1906 1907
                          "  {\n%s  };\n",
                          netaddr, prefix,
                          dhcp6 ? radvd2 : radvd3);
1908 1909 1910
        VIR_FREE(netaddr);
    }

1911
    virBufferAddLit(&configbuf, "};\n");
1912

1913 1914
    *configstr = virBufferContentAndReset(&configbuf);

1915
    ret = 0;
1916
 cleanup:
1917 1918 1919 1920
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1921

1922
/* write file and return its name (which must be freed by caller) */
1923
static int
1924
networkRadvdConfWrite(virNetworkDriverStatePtr driver,
1925
                      virNetworkObjPtr obj,
1926
                      char **configFile)
1927
{
1928
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1929 1930 1931 1932 1933 1934 1935 1936 1937
    int ret = -1;
    char *configStr = NULL;
    char *myConfigFile = NULL;

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

1938
    if (networkRadvdConfContents(obj, &configStr) < 0)
1939 1940 1941 1942
        goto cleanup;

    if (!configStr) {
        ret = 0;
1943 1944 1945 1946
        goto cleanup;
    }

    /* construct the filename */
1947
    if (!(*configFile = networkRadvdConfigFileName(driver, def->name)))
1948 1949
        goto cleanup;
    /* write the file */
1950
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1951 1952
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1953 1954 1955 1956 1957
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1958
 cleanup:
1959 1960 1961 1962 1963
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

1964

1965
static int
1966
networkStartRadvd(virNetworkDriverStatePtr driver,
1967
                  virNetworkObjPtr obj)
1968
{
1969
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1970
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1971
    pid_t radvdPid;
1972 1973 1974 1975 1976 1977
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

1978
    virNetworkObjSetRadvdPid(obj, -1);
1979

G
Gene Czarcinski 已提交
1980
    /* Is dnsmasq handling RA? */
1981
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
1982 1983 1984 1985
        ret = 0;
        goto cleanup;
    }

1986
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
1987 1988 1989 1990 1991 1992 1993 1994 1995 1996
        /* 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);
1997 1998 1999
        goto cleanup;
    }

2000
    if (virFileMakePath(driver->pidDir) < 0) {
2001 2002
        virReportSystemError(errno,
                             _("cannot create directory %s"),
2003
                             driver->pidDir);
2004 2005
        goto cleanup;
    }
2006
    if (virFileMakePath(driver->radvdStateDir) < 0) {
2007 2008
        virReportSystemError(errno,
                             _("cannot create directory %s"),
2009
                             driver->radvdStateDir);
2010 2011 2012 2013
        goto cleanup;
    }

    /* construct pidfile name */
2014
    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
2015
        goto cleanup;
2016
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
2017 2018
        goto cleanup;

2019
    if (networkRadvdConfWrite(driver, obj, &configfile) < 0)
2020 2021
        goto cleanup;

2022 2023 2024 2025
    /* 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
2026
     * virPidFileRead() below will fail if we use them).
2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
     * 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;

2042
    if (virPidFileRead(driver->pidDir, radvdpidbase, &radvdPid) < 0)
2043
        goto cleanup;
2044
    virNetworkObjSetRadvdPid(obj, radvdPid);
2045 2046

    ret = 0;
2047
 cleanup:
2048
    virObjectUnref(dnsmasq_caps);
2049 2050 2051 2052 2053 2054 2055
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

2056

2057
static int
2058
networkRefreshRadvd(virNetworkDriverStatePtr driver,
2059
                    virNetworkObjPtr obj)
2060
{
2061
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2062
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
2063
    char *radvdpidbase;
2064
    pid_t radvdPid;
G
Gene Czarcinski 已提交
2065 2066

    /* Is dnsmasq handling RA? */
2067 2068
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
        virObjectUnref(dnsmasq_caps);
2069 2070
        radvdPid = virNetworkObjGetRadvdPid(obj);
        if (radvdPid <= 0)
G
Gene Czarcinski 已提交
2071 2072
            return 0;
        /* radvd should not be running but in case it is */
2073 2074
        if ((networkKillDaemon(radvdPid, "radvd", def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(def->name))
G
Gene Czarcinski 已提交
2075
             != NULL)) {
2076
            virPidFileDelete(driver->pidDir, radvdpidbase);
G
Gene Czarcinski 已提交
2077 2078
            VIR_FREE(radvdpidbase);
        }
2079
        virNetworkObjSetRadvdPid(obj, -1);
G
Gene Czarcinski 已提交
2080 2081
        return 0;
    }
2082
    virObjectUnref(dnsmasq_caps);
G
Gene Czarcinski 已提交
2083

2084
    /* if there's no running radvd, just start it */
2085 2086
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid <= 0 || (kill(radvdPid, 0) < 0))
2087
        return networkStartRadvd(driver, obj);
2088

2089
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2090 2091 2092 2093
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

2094
    if (networkRadvdConfWrite(driver, obj, NULL) < 0)
2095 2096
        return -1;

2097
    return kill(radvdPid, SIGHUP);
2098 2099
}

2100

2101 2102
#if 0
/* currently unused, so it causes a build error unless we #if it out */
2103
static int
2104
networkRestartRadvd(virNetworkObjPtr obj)
2105
{
2106
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2107
    char *radvdpidbase;
2108
    pid_t radvdPid = virNeworkObjGetRadvdPid(obj);
2109 2110

    /* if there is a running radvd, kill it */
2111
    if (radvdPid > 0) {
2112 2113 2114 2115
        /* 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).
         */
2116 2117
        if ((networkKillDaemon(radvdPid, "radvd", def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(def->name))
2118
             != NULL)) {
2119
            virPidFileDelete(driver->pidDir, radvdpidbase);
2120 2121
            VIR_FREE(radvdpidbase);
        }
2122
        virNetworkObjSetRadvdPid(obj, -1);
2123 2124
    }
    /* now start radvd if it should be started */
2125
    return networkStartRadvd(obj);
2126 2127 2128
}
#endif /* #if 0 */

2129

2130
static int
2131
networkRefreshDaemonsHelper(virNetworkObjPtr obj,
2132
                            void *opaque)
2133
{
2134
    virNetworkDefPtr def;
2135
    virNetworkDriverStatePtr driver = opaque;
2136

2137
    virObjectLock(obj);
2138
    def = virNetworkObjGetDef(obj);
2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166
    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;
        }
2167
    }
2168 2169

 cleanup:
2170
    virObjectUnlock(obj);
2171 2172 2173
    return 0;
}

2174

2175 2176 2177 2178
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2179
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2180 2181
{
    VIR_INFO("Refreshing network daemons");
2182 2183
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2184
                             driver);
2185
}
2186

2187

2188
static int
2189
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
J
Ján Tomko 已提交
2190
                                 void *opaque G_GNUC_UNUSED)
2191
{
2192
    virNetworkDefPtr def;
2193

2194
    virObjectLock(obj);
2195
    def = virNetworkObjGetDef(obj);
2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221
    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;
2222 2223
        }
    }
2224 2225

 cleanup:
2226
    virObjectUnlock(obj);
2227
    return 0;
2228 2229
}

2230

2231
static void
2232
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup)
2233
{
2234
    VIR_INFO("Reloading iptables rules");
2235 2236 2237 2238
    /* 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;
2239
    networkPreReloadFirewallRules(driver, startup);
2240 2241 2242
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2243
    networkPostReloadFirewallRules(startup);
2244 2245
}

2246

2247
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
2248
static int
2249 2250
networkEnableIPForwarding(bool enableIPv4,
                          bool enableIPv6)
2251
{
2252
    int ret = 0;
2253 2254 2255 2256
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
2257
                           &enabled, sizeof(enabled));
2258 2259
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
2260
                           &enabled, sizeof(enabled));
2261
#else
2262
    if (enableIPv4)
2263
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv4/ip_forward", "1\n", 0);
2264
    if (enableIPv6 && ret == 0)
2265 2266
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv6/conf/all/forwarding", "1\n", 0);

2267
#endif
2268
    return ret;
2269 2270
}

2271

2272
static int
2273
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2274
{
2275
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2276 2277
    char *field = NULL;
    int ret = -1;
2278
    bool enableIPv6 = !!virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2279

2280 2281 2282 2283
    /* 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.
     */
2284 2285
    field = g_strdup_printf(SYSCTL_PATH "/net/ipv6/conf/%s/disable_ipv6",
                            def->bridge);
2286

2287 2288
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2289
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2290
                      def->bridge);
2291 2292 2293
        ret = 0;
        goto cleanup;
    }
2294

2295 2296 2297
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2298
                               "on bridge %s"), field, def->bridge);
2299
        goto cleanup;
2300
    }
2301
    VIR_FREE(field);
2302

2303 2304
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2305 2306 2307 2308 2309
     */

    /* Prevent guests from hijacking the host network by sending out
     * their own router advertisements.
     */
2310 2311
    field = g_strdup_printf(SYSCTL_PATH "/net/ipv6/conf/%s/accept_ra",
                            def->bridge);
2312

2313
    if (virFileWriteStr(field, "0", 0) < 0) {
2314
        virReportSystemError(errno,
2315 2316 2317 2318 2319
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

2320 2321 2322
    /* All interfaces used as a gateway (which is what this is, by
     * definition), must always have autoconf=0.
     */
2323
    field = g_strdup_printf(SYSCTL_PATH "/net/ipv6/conf/%s/autoconf", def->bridge);
2324

2325
    if (virFileWriteStr(field, "0", 0) < 0) {
2326
        virReportSystemError(errno,
2327
                             _("cannot disable %s"), field);
2328 2329 2330 2331
        goto cleanup;
    }

    ret = 0;
2332
 cleanup:
2333 2334 2335 2336
    VIR_FREE(field);
    return ret;
}

2337

2338
/* add an IP address to a bridge */
2339
static int
2340
networkAddAddrToBridge(virNetworkObjPtr obj,
2341
                       virNetworkIPDefPtr ipdef)
2342
{
2343
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2344
    int prefix = virNetworkIPDefPrefix(ipdef);
2345 2346

    if (prefix < 0) {
2347 2348
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2349
                       def->bridge);
2350 2351 2352
        return -1;
    }

2353
    if (virNetDevIPAddrAdd(def->bridge, &ipdef->address, NULL, prefix) < 0)
2354 2355 2356 2357 2358
        return -1;

    return 0;
}

2359 2360

static int
2361
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2362 2363
                                      const char *macTapIfName)
{
2364 2365
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    const char *brname = def->bridge;
2366 2367

    if (brname &&
2368
        def->macTableManager == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381
        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;
}


2382 2383
/* add an IP (static) route to a bridge */
static int
2384
networkAddRouteToBridge(virNetworkObjPtr obj,
2385
                        virNetDevIPRoutePtr routedef)
2386
{
2387
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2388 2389 2390 2391
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2392 2393 2394 2395 2396

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

2401
    if (virNetDevIPRouteAdd(def->bridge, addr, prefix, gateway, metric) < 0)
2402
        return -1;
2403

2404 2405 2406
    return 0;
}

2407
static int
2408
networkWaitDadFinish(virNetworkObjPtr obj)
2409
{
2410
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2411
    virNetworkIPDefPtr ipdef;
2412 2413 2414 2415
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

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

2418
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, naddrs))) {
2419 2420 2421 2422 2423
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2424
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2425 2426 2427 2428

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

2433

2434
static int
2435
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
2436
                           virNetworkObjPtr obj)
2437
{
2438
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2439
    size_t i;
2440
    bool v4present = false, v6present = false;
2441
    virErrorPtr save_err = NULL;
2442
    virNetworkIPDefPtr ipdef;
2443
    virNetDevIPRoutePtr routedef;
2444
    char *macTapIfName = NULL;
2445
    virMacMapPtr macmap;
M
Michal Privoznik 已提交
2446
    char *macMapFile = NULL;
2447
    int tapfd = -1;
2448
    bool dnsmasqStarted = false;
2449
    bool devOnline = false;
2450
    bool firewalRulesAdded = false;
2451

2452
    /* Check to see if any network IP collides with an existing route */
2453
    if (networkCheckRouteCollision(def) < 0)
2454 2455
        return -1;

2456
    /* Create and configure the bridge device */
2457
    if (!def->bridge) {
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467
        /* 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"),
2468
                       def->name);
2469 2470
        return -1;
    }
2471
    if (virNetDevBridgeCreate(def->bridge, &def->mac) < 0)
2472 2473
        return -1;

2474
    if (def->mac_specified) {
2475 2476 2477 2478 2479 2480
        /* 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.
         */
2481
        macTapIfName = networkBridgeDummyNicName(def->bridge);
2482
        if (!macTapIfName)
2483
            goto error;
2484
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2485 2486
        if (virNetDevTapCreateInBridgePort(def->bridge,
                                           &macTapIfName, &def->mac,
2487
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2488
                                           NULL, def->mtu, NULL,
2489 2490 2491
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2492
            VIR_FREE(macTapIfName);
2493
            goto error;
2494 2495 2496
        }
    }

2497
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
2498
                                         def->bridge)) ||
2499
        !(macmap = virMacMapNew(macMapFile)))
2500
        goto error;
M
Michal Privoznik 已提交
2501

2502
    virNetworkObjSetMacMap(obj, macmap);
2503
    macmap = NULL;
2504

2505
    /* Set bridge options */
2506 2507 2508 2509

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

2513
    if (virNetDevBridgeSetSTP(def->bridge, def->stp ? true : false) < 0)
2514
        goto error;
2515

2516 2517 2518
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2519
    if (networkSetIPv6Sysctls(obj) < 0)
2520
        goto error;
2521

2522
    /* Add "once per network" rules */
2523 2524
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(def) < 0)
2525
        goto error;
2526

2527 2528
    firewalRulesAdded = true;

2529
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i)); i++) {
2530
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2531
            v4present = true;
2532
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2533
            v6present = true;
2534

2535
        /* Add the IP address/netmask to the bridge */
2536
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2537
            goto error;
2538 2539
    }

2540
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2541
        goto error;
2542

2543
    /* Bring up the bridge interface */
2544
    if (virNetDevSetOnline(def->bridge, 1) < 0)
2545
        goto error;
2546

2547 2548
    devOnline = true;

2549
    for (i = 0; i < def->nroutes; i++) {
2550 2551
        virSocketAddrPtr gateway = NULL;

2552
        routedef = def->routes[i];
2553
        gateway = virNetDevIPRouteGetGateway(routedef);
2554

2555 2556 2557
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2558
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2559
            if (networkAddRouteToBridge(obj, routedef) < 0) {
2560 2561 2562 2563 2564 2565
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2566
    /* If forward.type != NONE, turn on global IP forwarding */
2567
    if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2568
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2569
            goto error; /* Precise error message already provided */
2570 2571 2572 2573

        if (networkEnableIPForwarding(v4present, v6present) < 0) {
            virReportSystemError(errno, "%s",
                                 _("failed to enable IP forwarding"));
2574
            goto error;
2575
        }
2576 2577
    }

2578

2579
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2580
    if ((v4present || v6present) &&
2581
        networkStartDhcpDaemon(driver, obj) < 0)
2582
        goto error;
2583

2584 2585
    dnsmasqStarted = true;

2586
    /* start radvd if there are any ipv6 addresses */
2587
    if (v6present && networkStartRadvd(driver, obj) < 0)
2588
        goto error;
2589

2590 2591 2592
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2593
    if (v6present && networkWaitDadFinish(obj) < 0)
2594
        goto error;
2595 2596 2597

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2598 2599 2600
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
2601
            goto error;
2602 2603 2604
        VIR_FORCE_CLOSE(tapfd);
    }

2605
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
2606
        goto error;
2607

2608
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2609
    VIR_FREE(macMapFile);
2610 2611 2612

    return 0;

2613
 error:
2614
    virErrorPreserveLast(&save_err);
2615 2616
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
2617

2618 2619
    if (dnsmasqStarted) {
        pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
2620 2621
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2622 2623
    }

2624 2625
    if (devOnline)
        ignore_value(virNetDevSetOnline(def->bridge, 0));
2626

2627 2628
    if (firewalRulesAdded &&
        def->forward.type != VIR_NETWORK_FORWARD_OPEN)
2629
        networkRemoveFirewallRules(def);
2630

H
Hu Tao 已提交
2631
    if (macTapIfName) {
2632
        VIR_FORCE_CLOSE(tapfd);
2633
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2634 2635
        VIR_FREE(macTapIfName);
    }
2636
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2637
    VIR_FREE(macMapFile);
2638

2639
    ignore_value(virNetDevBridgeDelete(def->bridge));
2640

2641
    virErrorRestore(&save_err);
2642
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2643 2644 2645
    return -1;
}

2646

2647 2648
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2649
                              virNetworkObjPtr obj)
2650
{
2651
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2652 2653 2654
    pid_t radvdPid;
    pid_t dnsmasqPid;

2655 2656
    if (def->bandwidth)
        virNetDevBandwidthClear(def->bridge);
2657

2658
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2659

2660 2661
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2662 2663
        char *radvdpidbase;

2664
        kill(radvdPid, SIGTERM);
2665
        /* attempt to delete the pidfile we created */
2666
        if ((radvdpidbase = networkRadvdPidfileBasename(def->name))) {
2667
            virPidFileDelete(driver->pidDir, radvdpidbase);
2668 2669 2670 2671
            VIR_FREE(radvdpidbase);
        }
    }

2672 2673 2674
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2675

2676 2677
    if (def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(def->bridge);
2678
        if (macTapIfName) {
2679
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2680 2681 2682 2683
            VIR_FREE(macTapIfName);
        }
    }

2684
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2685

2686 2687
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2688

2689
    ignore_value(virNetDevBridgeDelete(def->bridge));
2690

2691
    /* See if its still alive and really really kill it */
2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702
    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);
2703

2704 2705 2706
    return 0;
}

2707

2708
static int
2709
networkStartNetworkBridge(virNetworkObjPtr obj)
2710
{
2711 2712
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

2713 2714 2715 2716
    /* 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.
     */
2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728
    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;
2729 2730
}

2731

2732
static int
J
Ján Tomko 已提交
2733
networkShutdownNetworkBridge(virNetworkObjPtr obj G_GNUC_UNUSED)
2734
{
2735 2736
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

2737 2738 2739 2740
    /* put anything here that needs to be done each time a network of
     * type BRIDGE is shutdown. On failure, undo anything you've done,
     * and return -1. On success return 0.
     */
2741 2742 2743
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);

2744 2745 2746 2747
    return 0;
}


2748 2749 2750 2751 2752 2753 2754 2755 2756
/* networkCreateInterfacePool:
 * @netdef: the original NetDef from the network
 *
 * Creates an implicit interface pool of VF's when a PF dev is given
 */
static int
networkCreateInterfacePool(virNetworkDefPtr netdef)
{
    size_t numVirtFns = 0;
2757
    unsigned int maxVirtFns = 0;
2758 2759 2760 2761 2762 2763
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

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

2767 2768
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get Virtual functions on %s"),
                       netdef->forward.pfs->dev);
        goto cleanup;
    }

    if (VIR_ALLOC_N(netdef->forward.ifs, numVirtFns) < 0)
        goto cleanup;

    for (i = 0; i < numVirtFns; i++) {
        virPCIDeviceAddressPtr thisVirtFn = virtFns[i];
        const char *thisName = vfNames[i];
        virNetworkForwardIfDefPtr thisIf
            = &netdef->forward.ifs[netdef->forward.nifs];

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

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

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


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

2870 2871

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

2882

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

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

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

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

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

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

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

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

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

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

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

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

2949 2950
    virNetworkObjSetFloorSum(obj, 0);

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

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

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

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

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

2981

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

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

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

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

    unlink(stateFile);
    VIR_FREE(stateFile);

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

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

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

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

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

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

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


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

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

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

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

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

3075 3076 3077 3078

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

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

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

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

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

3103 3104 3105

static int
networkConnectNumOfNetworks(virConnectPtr conn)
3106
{
3107
    virNetworkDriverStatePtr driver = networkGetDriver();
3108

3109 3110 3111
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3112 3113 3114
    return virNetworkObjListNumOfNetworks(driver->networks, true,
                                          virConnectNumOfNetworksCheckACL,
                                          conn);
3115 3116
}

3117 3118 3119 3120

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
3121
                           int maxnames)
3122 3123
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3124

3125 3126 3127
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3128 3129
    return virNetworkObjListGetNames(driver->networks, true, names, maxnames,
                                     virConnectListNetworksCheckACL, conn);
3130 3131
}

3132 3133 3134

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
3135
{
3136
    virNetworkDriverStatePtr driver = networkGetDriver();
3137

3138 3139 3140
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3141 3142 3143
    return virNetworkObjListNumOfNetworks(driver->networks, false,
                                          virConnectNumOfDefinedNetworksCheckACL,
                                          conn);
3144 3145
}

3146 3147 3148 3149

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

3154 3155 3156
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

M
Michal Privoznik 已提交
3157 3158 3159
    return virNetworkObjListGetNames(driver->networks, false, names, maxnames,
                                     virConnectListDefinedNetworksCheckACL,
                                     conn);
3160 3161
}

3162

3163
static int
3164 3165 3166
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
3167
{
3168
    virNetworkDriverStatePtr driver = networkGetDriver();
3169 3170 3171

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

3172
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
3173
        return -1;
3174

3175 3176 3177
    return virNetworkObjListExport(conn, driver->networks, nets,
                                   virConnectListAllNetworksCheckACL,
                                   flags);
3178
}
3179

3180

3181 3182 3183 3184 3185 3186 3187 3188
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3189
    virNetworkDriverStatePtr driver = networkGetDriver();
3190 3191 3192
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3196
                                       net, eventID, callback,
3197 3198 3199 3200 3201 3202
                                       opaque, freecb, &ret) < 0)
        ret = -1;

    return ret;
}

3203

3204 3205 3206 3207
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3208
    virNetworkDriverStatePtr driver = networkGetDriver();
3209 3210

    if (virConnectNetworkEventDeregisterAnyEnsureACL(conn) < 0)
3211
        return -1;
3212

3213 3214
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3215
                                        callbackID, true) < 0)
3216
        return -1;
3217

3218
    return 0;
3219 3220
}

3221 3222 3223

static int
networkIsActive(virNetworkPtr net)
3224 3225 3226 3227
{
    virNetworkObjPtr obj;
    int ret = -1;

3228 3229
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3230

3231
    if (virNetworkIsActiveEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3232 3233
        goto cleanup;

3234 3235
    ret = virNetworkObjIsActive(obj);

3236
 cleanup:
3237
    virNetworkObjEndAPI(&obj);
3238 3239 3240
    return ret;
}

3241 3242 3243

static int
networkIsPersistent(virNetworkPtr net)
3244 3245 3246 3247
{
    virNetworkObjPtr obj;
    int ret = -1;

3248 3249
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3250

3251
    if (virNetworkIsPersistentEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3252 3253
        goto cleanup;

3254
    ret = virNetworkObjIsPersistent(obj);
3255

3256
 cleanup:
3257
    virNetworkObjEndAPI(&obj);
3258 3259 3260 3261
    return ret;
}


3262 3263
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
3264 3265 3266
 * 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.
3267 3268 3269 3270 3271 3272 3273
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{
    int ret = -1, id = 0;
    char *newname = NULL;
3274 3275 3276 3277 3278
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3279
        p && p[1] == 'd')
3280
        templ = def->bridge;
3281 3282

    do {
3283
        newname = g_strdup_printf(templ, id);
3284 3285 3286 3287 3288
        /* 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).
         */
3289
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3290
              virNetDevExists(newname) == 1)) {
3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321
            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)
{
    if (def->bridge && !strstr(def->bridge, "%d")) {
3322
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3323 3324 3325
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge name '%s' already in use."),
                           def->bridge);
3326
            return -1;
3327 3328 3329 3330
        }
    } else {
        /* Allocate a bridge name */
        if (networkFindUnusedBridgeName(nets, def) < 0)
3331
            return -1;
3332 3333
    }

3334
    return 0;
3335 3336 3337
}


3338
static int
3339
networkValidate(virNetworkDriverStatePtr driver,
3340
                virNetworkDefPtr def)
3341
{
3342
    size_t i, j;
3343 3344
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3345
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3346
    bool ipv4def = false, ipv6def = false;
3347
    bool bandwidthAllowed = false;
3348
    bool usesInterface = false, usesAddress = false;
3349

3350 3351 3352
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3353 3354 3355
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3356 3357 3358 3359 3360
    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:
3361 3362 3363 3364
        /* 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)
3365 3366 3367
            return -1;

        virNetworkSetBridgeMacAddr(def);
3368
        bandwidthAllowed = true;
3369 3370 3371
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3372 3373 3374
        if (def->bridge != NULL)
            bandwidthAllowed = true;

3375
        G_GNUC_FALLTHROUGH;
3376

3377 3378 3379 3380
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
    case VIR_NETWORK_FORWARD_HOSTDEV:
3381
        /* They are also the only types that currently support setting
3382 3383
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
3384
         */
3385 3386 3387 3388 3389 3390 3391 3392
        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;
        }
3393
        if (virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0)) {
3394 3395 3396 3397
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3398
                           virNetworkForwardTypeToString(def->forward.type));
3399 3400
            return -1;
        }
3401
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
3402 3403 3404 3405
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3406
                           virNetworkForwardTypeToString(def->forward.type));
3407 3408 3409 3410 3411 3412 3413
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3414
                           virNetworkForwardTypeToString(def->forward.type));
3415 3416
            return -1;
        }
3417 3418 3419 3420 3421 3422
        break;

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

3425 3426 3427 3428 3429 3430 3431 3432 3433 3434
    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;
    }

3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447
    /* 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++) {
3448 3449 3450
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

3451
        switch ((virNetworkForwardHostdevDeviceType)iface->type) {
3452 3453
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464

            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;
            }
3465
            break;
3466 3467

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3468
            usesAddress = true;
3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493

            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);
3494
            break;
3495 3496
        }

3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509
        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 已提交
3510 3511 3512
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
3513
    for (i = 0;
3514
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
3515
         i++) {
G
Gene Czarcinski 已提交
3516 3517 3518 3519 3520
        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 -- "
3521 3522
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539
                    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;
                }
3540 3541 3542
            }
        }
    }
3543 3544 3545 3546 3547 3548

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

3549 3550 3551
    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 已提交
3552 3553
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3554
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3555 3556

    vlanUsed = def->vlan.nTags > 0;
3557 3558
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
3559 3560 3561 3562 3563
            /* 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.
             */
3564
            if (def->portGroups[i].virtPortProfile) {
3565
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
3566
                    def->portGroups[i].virtPortProfile->virtPortType
3567 3568 3569 3570 3571 3572 3573
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
3574
        }
3575
        if (def->portGroups[i].isDefault) {
3576 3577 3578 3579 3580
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
3581
                               def->name, defaultPortGroup->name,
3582
                               def->portGroups[i].name);
3583
                return -1;
3584
            }
3585
            defaultPortGroup = &def->portGroups[i];
3586
        }
3587 3588 3589 3590 3591 3592 3593 3594 3595
        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;
            }
        }
3596 3597 3598 3599 3600 3601 3602 3603
        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;
        }
3604
    }
3605 3606 3607 3608 3609 3610 3611
    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.
         */
3612 3613 3614 3615 3616 3617
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631

    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;
            }
        }
    }
3632 3633 3634
    return 0;
}

3635 3636 3637 3638

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3639
{
3640
    virNetworkDriverStatePtr driver = networkGetDriver();
3641
    virNetworkDefPtr newDef;
3642
    virNetworkObjPtr obj = NULL;
3643
    virNetworkDefPtr def;
3644
    virNetworkPtr net = NULL;
3645
    virObjectEventPtr event = NULL;
3646

3647
    if (!(newDef = virNetworkDefParseString(xml, network_driver->xmlopt)))
3648
        goto cleanup;
3649

3650
    if (virNetworkCreateXMLEnsureACL(conn, newDef) < 0)
3651 3652
        goto cleanup;

3653
    if (networkValidate(driver, newDef) < 0)
J
Ján Tomko 已提交
3654
        goto cleanup;
3655

3656 3657 3658
    /* 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.
3659
     */
3660
    if (!(obj = virNetworkObjAssignDef(driver->networks, newDef,
3661 3662
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3663
        goto cleanup;
3664 3665
    newDef = NULL;
    def = virNetworkObjGetDef(obj);
3666

3667 3668
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3669
        goto cleanup;
3670 3671
    }

3672 3673
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3674 3675
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3676

3677 3678
    VIR_INFO("Creating network '%s'", def->name);
    net = virGetNetwork(conn, def->name, def->uuid);
3679

3680
 cleanup:
3681
    virNetworkDefFree(newDef);
3682
    virObjectEventStateQueue(driver->networkEventState, event);
3683 3684
    virNetworkObjEndAPI(&obj);
    return net;
3685 3686
}

3687 3688 3689 3690

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3691
{
3692
    virNetworkDriverStatePtr driver = networkGetDriver();
3693
    virNetworkDefPtr def = NULL;
3694
    bool freeDef = true;
3695 3696
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3697
    virObjectEventPtr event = NULL;
3698

3699
    if (!(def = virNetworkDefParseString(xml, network_driver->xmlopt)))
3700
        goto cleanup;
3701

3702 3703 3704
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3705
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3706
        goto cleanup;
3707

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

3711
    /* def was assigned to network object */
3712
    freeDef = false;
3713

3714 3715
    if (virNetworkSaveConfig(driver->networkConfigDir,
                             def, network_driver->xmlopt) < 0) {
3716 3717
        if (!virNetworkObjIsActive(obj)) {
            virNetworkObjRemoveInactive(driver->networks, obj);
3718 3719
            goto cleanup;
        }
3720 3721 3722 3723
        /* if network was active already, just undo new persistent
         * definition by making it transient.
         * XXX - this isn't necessarily the correct thing to do.
         */
3724
        virNetworkObjUpdateAssignDef(obj, NULL, false);
3725 3726 3727
        goto cleanup;
    }

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

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

3735
 cleanup:
3736
    virObjectEventStateQueue(driver->networkEventState, event);
3737
    if (freeDef)
J
Ján Tomko 已提交
3738
        virNetworkDefFree(def);
3739 3740
    virNetworkObjEndAPI(&obj);
    return net;
3741 3742
}

3743

3744
static int
3745 3746
networkUndefine(virNetworkPtr net)
{
3747
    virNetworkDriverStatePtr driver = networkGetDriver();
3748
    virNetworkObjPtr obj;
3749
    virNetworkDefPtr def;
3750
    int ret = -1;
3751
    bool active = false;
3752
    virObjectEventPtr event = NULL;
3753

3754
    if (!(obj = networkObjFromNetwork(net)))
3755
        goto cleanup;
3756
    def = virNetworkObjGetDef(obj);
3757

3758
    if (virNetworkUndefineEnsureACL(net->conn, def) < 0)
3759 3760
        goto cleanup;

3761
    if (virNetworkObjIsActive(obj))
3762
        active = true;
3763

3764
    if (!virNetworkObjIsPersistent(obj)) {
3765 3766 3767 3768 3769
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3770
    /* remove autostart link */
3771 3772
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3773
                                  obj) < 0)
3774
        goto cleanup;
3775

3776 3777
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3778 3779
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3780

3781
    VIR_INFO("Undefining network '%s'", def->name);
3782
    if (!active) {
3783
        if (networkRemoveInactive(driver, obj) < 0)
3784
            goto cleanup;
3785 3786 3787 3788 3789
    } else {

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

3793
    ret = 0;
3794

3795
 cleanup:
3796
    virObjectEventStateQueue(driver->networkEventState, event);
3797
    virNetworkObjEndAPI(&obj);
3798
    return ret;
3799 3800
}

3801

3802 3803 3804 3805 3806 3807 3808 3809
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3810
    virNetworkDriverStatePtr driver = networkGetDriver();
3811
    virNetworkObjPtr obj = NULL;
3812
    virNetworkDefPtr def;
3813 3814
    int isActive, ret = -1;
    size_t i;
3815
    virNetworkIPDefPtr ipdef;
3816
    bool oldDhcpActive = false;
3817
    bool needFirewallRefresh = false;
3818

3819 3820 3821 3822 3823

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3824
    if (!(obj = networkObjFromNetwork(net)))
3825
        goto cleanup;
3826
    def = virNetworkObjGetDef(obj);
3827

3828
    if (virNetworkUpdateEnsureACL(net->conn, def, flags) < 0)
3829 3830
        goto cleanup;

3831
    /* see if we are listening for dhcp pre-modification */
3832
    for (i = 0;
3833
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3834
         i++) {
3835 3836 3837 3838 3839 3840
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3841 3842
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3843
     */
3844
    isActive = virNetworkObjIsActive(obj);
3845 3846
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3847 3848 3849 3850 3851 3852 3853
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3854 3855 3856 3857
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
3858 3859 3860 3861
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
3862 3863 3864 3865 3866 3867 3868 3869 3870 3871
            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).
                 */
3872 3873
                networkRemoveFirewallRules(def);
                needFirewallRefresh = true;
3874 3875 3876 3877
                break;
            default:
                break;
            }
3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891
            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;
3892 3893 3894
        }
    }

3895
    /* update the network config in memory/on disk */
3896 3897 3898
    if (virNetworkObjUpdate(obj, command, section,
                            parentIndex, xml,
                            network_driver->xmlopt, flags) < 0) {
3899
        if (needFirewallRefresh)
3900
            ignore_value(networkAddFirewallRules(def));
3901 3902 3903
        goto cleanup;
    }

3904 3905 3906 3907
    /* @def is replaced */
    def = virNetworkObjGetDef(obj);

    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
3908 3909 3910 3911 3912
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
3913 3914
                                 virNetworkObjGetPersistentDef(obj),
                                 network_driver->xmlopt) < 0) {
3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927
            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 ||
3928 3929 3930 3931 3932 3933 3934 3935
            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)
3936
             */
3937
            if (networkRestartDhcpDaemon(driver, obj) < 0)
3938 3939
                goto cleanup;

3940 3941 3942 3943 3944 3945 3946 3947
        } 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;

3948
            for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3949
                 i++) {
3950 3951 3952 3953 3954 3955 3956
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3957 3958
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
3959 3960 3961
                goto cleanup;
            }

3962 3963 3964 3965
        } 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.
3966
             */
3967
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
3968 3969 3970 3971 3972 3973 3974 3975
                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.
             */
3976
            if (networkRefreshRadvd(driver, obj) < 0)
3977 3978 3979 3980
                goto cleanup;
        }

        /* save current network state to disk */
3981 3982
        if ((ret = virNetworkObjSaveStatus(driver->stateDir,
                                           obj, network_driver->xmlopt)) < 0)
3983 3984
            goto cleanup;
    }
3985 3986

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

3991
    ret = 0;
3992
 cleanup:
3993
    virNetworkObjEndAPI(&obj);
3994 3995 3996
    return ret;
}

3997 3998 3999

static int
networkCreate(virNetworkPtr net)
4000
{
4001
    virNetworkDriverStatePtr driver = networkGetDriver();
4002
    virNetworkObjPtr obj;
4003
    virNetworkDefPtr def;
4004
    int ret = -1;
4005
    virObjectEventPtr event = NULL;
4006

4007
    if (!(obj = networkObjFromNetwork(net)))
4008
        goto cleanup;
4009
    def = virNetworkObjGetDef(obj);
4010

4011
    if (virNetworkCreateEnsureACL(net->conn, def) < 0)
4012 4013
        goto cleanup;

4014
    if ((ret = networkStartNetwork(driver, obj)) < 0)
4015
        goto cleanup;
4016

4017 4018
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
4019 4020
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
4021

4022
 cleanup:
4023
    virObjectEventStateQueue(driver->networkEventState, event);
4024
    virNetworkObjEndAPI(&obj);
4025
    return ret;
4026 4027
}

4028 4029 4030

static int
networkDestroy(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 (virNetworkDestroyEnsureACL(net->conn, def) < 0)
4043 4044
        goto cleanup;

4045
    if (!virNetworkObjIsActive(obj)) {
4046
        virReportError(VIR_ERR_OPERATION_INVALID,
4047
                       _("network '%s' is not active"),
4048
                       def->name);
4049 4050 4051
        goto cleanup;
    }

4052
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
4053
        goto cleanup;
4054 4055 4056

    virNetworkObjDeleteAllPorts(obj, driver->stateDir);

4057 4058
    /* @def replaced in virNetworkObjUnsetDefTransient*/
    def = virNetworkObjGetDef(obj);
4059

4060 4061
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
4062 4063
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
4064

4065 4066
    if (!virNetworkObjIsPersistent(obj) &&
        networkRemoveInactive(driver, obj) < 0) {
4067 4068
        ret = -1;
        goto cleanup;
4069
    }
4070

4071
 cleanup:
4072
    virObjectEventStateQueue(driver->networkEventState, event);
4073
    virNetworkObjEndAPI(&obj);
4074 4075 4076
    return ret;
}

4077 4078 4079 4080

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
4081
{
4082
    virNetworkObjPtr obj;
4083
    virNetworkDefPtr curDef;
4084
    virNetworkDefPtr def;
4085
    virNetworkDefPtr newDef;
4086
    char *ret = NULL;
4087

4088
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
4089

4090
    if (!(obj = networkObjFromNetwork(net)))
4091
        return ret;
4092 4093
    def = virNetworkObjGetDef(obj);
    newDef = virNetworkObjGetNewDef(obj);
4094

4095
    if (virNetworkGetXMLDescEnsureACL(net->conn, def) < 0)
4096 4097
        goto cleanup;

4098 4099
    if ((flags & VIR_NETWORK_XML_INACTIVE) && newDef)
        curDef = newDef;
4100
    else
4101
        curDef = def;
4102

4103
    ret = virNetworkDefFormat(curDef, network_driver->xmlopt, flags);
4104

4105
 cleanup:
4106
    virNetworkObjEndAPI(&obj);
4107
    return ret;
4108 4109
}

4110 4111 4112 4113

static char *
networkGetBridgeName(virNetworkPtr net)
{
4114
    virNetworkObjPtr obj;
4115
    virNetworkDefPtr def;
4116 4117
    char *bridge = NULL;

4118
    if (!(obj = networkObjFromNetwork(net)))
4119
        return bridge;
4120
    def = virNetworkObjGetDef(obj);
4121

4122
    if (virNetworkGetBridgeNameEnsureACL(net->conn, def) < 0)
4123 4124
        goto cleanup;

4125
    if (!(def->bridge)) {
4126 4127
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
4128
                       def->name);
4129 4130 4131
        goto cleanup;
    }

4132
    bridge = g_strdup(def->bridge);
4133

4134
 cleanup:
4135
    virNetworkObjEndAPI(&obj);
4136 4137 4138
    return bridge;
}

4139 4140 4141 4142

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
4143
{
4144
    virNetworkObjPtr obj;
4145
    int ret = -1;
4146

4147
    if (!(obj = networkObjFromNetwork(net)))
4148
        return ret;
4149

4150
    if (virNetworkGetAutostartEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
4151 4152
        goto cleanup;

4153
    *autostart = virNetworkObjIsAutostart(obj) ? 1 : 0;
4154
    ret = 0;
4155

4156
 cleanup:
4157
    virNetworkObjEndAPI(&obj);
4158
    return ret;
4159 4160
}

4161 4162 4163 4164

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
4165
{
4166
    virNetworkDriverStatePtr driver = networkGetDriver();
4167
    virNetworkObjPtr obj;
4168
    virNetworkDefPtr def;
4169
    char *configFile = NULL, *autostartLink = NULL;
4170 4171
    bool new_autostart;
    bool cur_autostart;
4172
    int ret = -1;
4173

4174
    if (!(obj = networkObjFromNetwork(net)))
4175
        goto cleanup;
4176
    def = virNetworkObjGetDef(obj);
4177

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

4181
    if (!virNetworkObjIsPersistent(obj)) {
4182 4183
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
4184 4185 4186
        goto cleanup;
    }

4187 4188 4189
    new_autostart = (autostart != 0);
    cur_autostart = virNetworkObjIsAutostart(obj);
    if (cur_autostart != new_autostart) {
4190 4191
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir,
                                               def->name)) == NULL)
4192
            goto cleanup;
4193 4194
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir,
                                                  def->name)) == NULL)
4195 4196
            goto cleanup;

4197
        if (new_autostart) {
4198
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
4199
                virReportSystemError(errno,
4200 4201
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
4202 4203
                goto cleanup;
            }
4204

4205
            if (symlink(configFile, autostartLink) < 0) {
4206
                virReportSystemError(errno,
4207
                                     _("Failed to create symlink '%s' to '%s'"),
4208
                                     autostartLink, configFile);
4209 4210 4211
                goto cleanup;
            }
        } else {
4212
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4213
                virReportSystemError(errno,
4214
                                     _("Failed to delete symlink '%s'"),
4215
                                     autostartLink);
4216 4217
                goto cleanup;
            }
4218 4219
        }

4220
        virNetworkObjSetAutostart(obj, new_autostart);
4221
    }
4222

4223
    ret = 0;
4224

4225
 cleanup:
4226 4227
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4228
    virNetworkObjEndAPI(&obj);
4229
    return ret;
4230 4231
}

4232

4233
static int
4234
networkGetDHCPLeases(virNetworkPtr net,
4235 4236 4237
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
4238
{
4239
    virNetworkDriverStatePtr driver = networkGetDriver();
4240 4241 4242
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
4243
    size_t size = 0;
4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254
    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;
4255
    virNetworkIPDefPtr ipdef_tmp = NULL;
4256 4257
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
4258
    virNetworkObjPtr obj;
4259
    virNetworkDefPtr def;
4260
    virMacAddr mac_addr;
4261 4262 4263

    virCheckFlags(0, -1);

4264 4265 4266 4267 4268 4269
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4270
    if (!(obj = networkObjFromNetwork(net)))
4271
        return -1;
4272
    def = virNetworkObjGetDef(obj);
4273

4274
    if (virNetworkGetDHCPLeasesEnsureACL(net->conn, def) < 0)
4275
        goto cleanup;
4276 4277

    /* Retrieve custom leases file location */
4278
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, def->bridge);
4279 4280

    /* Read entire contents */
4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294
    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);
        }
4295 4296 4297 4298 4299 4300 4301 4302 4303 4304
        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;
        }

4305
        if (!virJSONValueIsArray(leases_array)) {
4306
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4307
                           _("Malformed lease_entries array"));
4308 4309
            goto error;
        }
4310
        size = virJSONValueArraySize(leases_array);
4311 4312
    }

4313
    currtime = (long long)time(NULL);
4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329

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

4330
        if (mac && virMacAddrCompare(mac, mac_tmp))
4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361
            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 */
4362 4363
            for (j = 0; j < def->nips; j++) {
                ipdef_tmp = &def->ips[j];
4364 4365 4366 4367 4368 4369 4370 4371

                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)) {
4372
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4373 4374 4375 4376 4377 4378
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

4379 4380 4381
            lease->mac = g_strdup(mac_tmp);
            lease->ipaddr = g_strdup(ip_tmp);
            lease->iface = g_strdup(def->bridge);
4382 4383

            /* Fields that can be NULL */
4384 4385 4386
            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"));
4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408

            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);
4409
    VIR_FREE(lease_entries);
4410 4411
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4412

4413
    virNetworkObjEndAPI(&obj);
4414

4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425
    return rv;

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

4426

4427 4428 4429 4430 4431
/* A unified function to log network connections and disconnections */

static void
networkLogAllocation(virNetworkDefPtr netdef,
                     virNetworkForwardIfDefPtr dev,
4432
                     virMacAddrPtr mac,
4433 4434 4435 4436 4437
                     bool inUse)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    const char *verb = inUse ? "using" : "releasing";

4438
    virMacAddrFormat(mac, macStr);
4439 4440
    if (!dev) {
        VIR_INFO("MAC %s %s network %s (%d connections)",
4441
                 macStr, verb, netdef->name, netdef->connections);
4442
    } else {
4443
        if (dev->type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI) {
4444 4445
            VIR_INFO("MAC %s %s network %s (%d connections) "
                     "physical device %04x:%02x:%02x.%x (%d connections)",
4446
                     macStr, verb, netdef->name, netdef->connections,
4447 4448 4449 4450 4451 4452
                     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)",
4453
                     macStr, verb, netdef->name, netdef->connections,
4454 4455 4456 4457 4458
                     dev->device.dev, dev->connections);
        }
    }
}

4459

4460 4461 4462 4463 4464 4465 4466 4467
/* 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.
 */

4468 4469 4470
/* networkAllocatePort:
 * @obj: the network to allocate from
 * @port: the port definition to allocate
4471
 *
4472
 * Looks up the network reference by port, allocates a physical
4473
 * device from that network (if appropriate), and returns with the
4474
 * port configuration filled in accordingly.
4475 4476 4477
 *
 * Returns 0 on success, -1 on failure.
 */
4478
static int
4479 4480
networkAllocatePort(virNetworkObjPtr obj,
                    virNetworkPortDefPtr port)
4481
{
4482
    virNetworkDriverStatePtr driver = networkGetDriver();
4483 4484
    virNetworkDefPtr netdef = NULL;
    virPortGroupDefPtr portgroup = NULL;
4485
    virNetworkForwardIfDefPtr dev = NULL;
4486
    size_t i;
4487
    virNetDevVPortProfilePtr portprofile = NULL;
4488

4489
    netdef = virNetworkObjGetDef(obj);
4490
    VIR_DEBUG("Allocating port from net %s", netdef->name);
4491

4492
    if (!virNetworkObjIsActive(obj)) {
4493 4494 4495
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4496
        return -1;
4497 4498
    }

4499
    VIR_DEBUG("Interface port group %s", port->group);
4500 4501 4502
    /* 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 已提交
4503
     */
4504
    portgroup = virPortGroupFindByName(netdef, port->group);
4505

4506 4507 4508 4509
    if (!port->bandwidth) {
        if (portgroup && portgroup->bandwidth &&
            virNetDevBandwidthCopy(&port->bandwidth,
                                   portgroup->bandwidth) < 0)
4510
            return -1;
4511
    }
4512

4513 4514 4515 4516 4517 4518
    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;
4519

4520
        if (vlan && virNetDevVlanCopy(&port->vlan, vlan) < 0)
4521
            return -1;
4522
    }
4523

4524 4525 4526 4527 4528 4529
    if (!port->trustGuestRxFilters) {
        if (portgroup && portgroup->trustGuestRxFilters)
            port->trustGuestRxFilters = portgroup->trustGuestRxFilters;
        else if (netdef->trustGuestRxFilters)
            port->trustGuestRxFilters = netdef->trustGuestRxFilters;
    }
4530

4531 4532 4533
    /* merge virtualports from interface, network, and portgroup to
     * arrive at actual virtualport to use
     */
4534 4535
    if (virNetDevVPortProfileMerge3(&portprofile,
                                    port->virtPortProfile,
4536 4537 4538
                                    netdef->virtPortProfile,
                                    portgroup
                                    ? portgroup->virtPortProfile : NULL) < 0) {
4539
                return -1;
4540 4541 4542 4543
    }
    if (portprofile) {
        VIR_FREE(port->virtPortProfile);
        port->virtPortProfile = portprofile;
4544 4545
    }

4546
    VIR_DEBUG("Processing forward type %d", netdef->forward.type);
4547 4548 4549 4550 4551
    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:
4552 4553 4554 4555
        /* for these forward types, the actual net type really *is*
         * NETWORK; we just keep the info from the portgroup in
         * iface->data.network.actual
         */
4556
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_NETWORK;
4557

4558
        port->plug.bridge.brname = g_strdup(netdef->bridge);
4559
        port->plug.bridge.macTableManager = netdef->macTableManager;
4560

4561
        if (port->virtPortProfile) {
4562 4563 4564
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("<virtualport type='%s'> not supported for network "
                             "'%s' which uses IP forwarding"),
4565
                           virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4566
                           netdef->name);
4567
            return -1;
4568 4569
        }

4570
        if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4571
            return -1;
4572
        break;
4573

4574
    case VIR_NETWORK_FORWARD_HOSTDEV: {
4575
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI;
4576

4577
        if (networkCreateInterfacePool(netdef) < 0)
4578
            return -1;
4579 4580

        /* pick first dev with 0 connections */
4581 4582 4583
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4584 4585 4586 4587 4588 4589 4590 4591
                break;
            }
        }
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' requires exclusive access "
                             "to interfaces, but none are available"),
                           netdef->name);
4592
            return -1;
4593
        }
4594 4595 4596
        port->plug.hostdevpci.addr = dev->device.pci;
        port->plug.hostdevpci.driver = netdef->forward.driverName;
        port->plug.hostdevpci.managed = netdef->forward.managed;
4597

4598
        if (port->virtPortProfile) {
4599
            /* make sure type is supported for hostdev connections */
4600 4601
            if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
4602 4603 4604 4605
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses an SR-IOV Virtual Function "
                                 "via PCI passthrough"),
4606
                               virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4607
                               netdef->name);
4608
                return -1;
4609 4610
            }
        }
4611 4612
        break;
    }
4613

4614 4615 4616 4617 4618 4619
    case VIR_NETWORK_FORWARD_BRIDGE:
        if (netdef->bridge) {
            /* <forward type='bridge'/> <bridge name='xxx'/>
             * is VIR_DOMAIN_NET_TYPE_BRIDGE
             */

4620
            port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE;
4621
            port->plug.bridge.brname = g_strdup(netdef->bridge);
4622
            port->plug.bridge.macTableManager = netdef->macTableManager;
4623

4624
            if (port->virtPortProfile) {
4625
                /* only type='openvswitch' is allowed for bridges */
4626
                if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
4627 4628 4629
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport type='%s'> not supported for network "
                                     "'%s' which uses a bridge device"),
4630
                                   virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4631
                                   netdef->name);
4632
                    return -1;
4633 4634
                }
            }
4635

4636
            if (networkPlugBandwidth(obj, &port->mac, port->bandwidth, &port->class_id) < 0)
4637
                return -1;
4638 4639 4640 4641 4642 4643
            break;
        }

        /* intentionally fall through to the direct case for
         * VIR_NETWORK_FORWARD_BRIDGE with no bridge device defined
         */
4644
        G_GNUC_FALLTHROUGH;
4645 4646 4647 4648

    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
4649 4650 4651 4652 4653
        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
4654
        port->plugtype = VIR_NETWORK_PORT_PLUG_TYPE_DIRECT;
4655 4656 4657 4658

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

4662
        if (port->virtPortProfile) {
4663
            /* make sure type is supported for macvtap connections */
4664 4665
            if (port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                port->virtPortProfile->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
4666 4667 4668
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses a macvtap device"),
4669
                               virNetDevVPortTypeToString(port->virtPortProfile->virtPortType),
4670
                               netdef->name);
4671
                return -1;
4672 4673
            }
        }
4674

4675 4676 4677
        /* 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).
         */
4678
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4679 4680 4681 4682
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4683
            return -1;
4684 4685 4686
        } else {
            /* pick an interface from the pool */

4687
            if (networkCreateInterfacePool(netdef) < 0)
4688
                return -1;
4689

4690 4691 4692 4693 4694
            /* 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.
4695
             */
4696 4697
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4698 4699
                 port->virtPortProfile &&
                 (port->virtPortProfile->virtPortType
4700
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4701

4702
                /* pick first dev with 0 connections */
4703 4704 4705
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4706 4707 4708 4709 4710
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4711
                dev = &netdef->forward.ifs[0];
4712 4713 4714
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4715 4716 4717 4718
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4719 4720 4721 4722
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4723
                return -1;
4724
            }
4725
            port->plug.direct.linkdev = g_strdup(dev->device.dev);
4726
        }
4727 4728 4729 4730 4731
        break;

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
4732
        return -1;
4733 4734
    }

4735
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
4736
                               port->ownername, &port->mac) < 0)
4737
        return -1;
M
Michal Privoznik 已提交
4738

4739
    if (virNetDevVPortProfileCheckComplete(port->virtPortProfile, true) < 0)
4740
        return -1;
4741

4742 4743 4744 4745
    /* 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.
     */
4746
    VIR_DEBUG("Sanity check port config");
4747

4748
    if (port->vlan.nTags) {
4749 4750 4751 4752
        /* 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
4753
         */
4754 4755 4756
        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) ||
4757
              (port->plugtype == VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE &&
4758 4759
               port->virtPortProfile &&
               port->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
4760 4761 4762 4763 4764
            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);
4765
            return -1;
4766 4767
        }
    }
4768 4769 4770 4771 4772 4773 4774 4775

    /* 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"));
4776
        return -1;
4777
    }
4778

4779 4780 4781 4782
    netdef->connections++;
    if (dev)
        dev->connections++;
    /* finally we can call the 'plugged' hook script if any */
4783 4784
    if (networkRunHook(obj, port,
                       VIR_HOOK_NETWORK_OP_PORT_CREATED,
4785 4786 4787
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        netdef->connections--;
4788
        if (dev)
4789
            dev->connections--;
4790
        return -1;
4791
    }
4792
    networkLogAllocation(netdef, dev, &port->mac, true);
4793 4794

    VIR_DEBUG("Port allocated");
4795

4796
    return 0;
4797
}
4798

4799

4800 4801 4802
/* networkNotifyPort:
 * @obj: the network to notify
 * @port: the port definition to notify
4803 4804 4805 4806
 *
 * 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
4807
 * order.
4808
 */
4809
static int
4810 4811
networkNotifyPort(virNetworkObjPtr obj,
                  virNetworkPortDefPtr port)
4812 4813
{
    virNetworkDefPtr netdef;
4814
    virNetworkForwardIfDefPtr dev = NULL;
4815
    size_t i;
4816

4817
    netdef = virNetworkObjGetDef(obj);
4818

4819
    if (!virNetworkObjIsActive(obj)) {
4820 4821 4822
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
4823
        return -1;
4824
    }
4825

4826 4827 4828 4829
    switch (port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Unexpectedly got a network port without a plug"));
4830
        return -1;
4831

4832 4833 4834 4835
    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) {
4836
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4837
                           _("Unexpectedly got a network port without a network bridge"));
4838
            return -1;
4839
        }
4840 4841 4842 4843
        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_DIRECT:
        if (networkCreateInterfacePool(netdef) < 0)
4844
            return -1;
4845 4846

        /* find the matching interface and increment its connections */
4847 4848
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4849
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4850 4851
                STREQ(port->plug.direct.linkdev,
                      netdef->forward.ifs[i].device.dev)) {
4852
                dev = &netdef->forward.ifs[i];
4853 4854 4855 4856 4857
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4858
            virReportError(VIR_ERR_INTERNAL_ERROR,
4859
                           _("network '%s' doesn't have dev='%s' "
4860 4861 4862
                             "in use by network port '%s'"),
                           netdef->name, port->plug.direct.linkdev,
                           port->uuid);
4863
            return -1;
4864 4865
        }

4866
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4867 4868
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4869
         */
4870
        if ((dev->connections > 0) &&
4871 4872
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4873 4874
              port->virtPortProfile &&
              (port->virtPortProfile->virtPortType == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4875
            virReportError(VIR_ERR_INTERNAL_ERROR,
4876
                           _("network '%s' claims dev='%s' is already in "
4877 4878
                             "use by a different port"),
                           netdef->name, port->plug.direct.linkdev);
4879
            return -1;
4880
        }
4881
        break;
4882

4883 4884 4885
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:

        if (networkCreateInterfacePool(netdef) < 0)
4886
            return -1;
4887 4888

        /* find the matching interface and increment its connections */
4889 4890
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4891
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4892
                virPCIDeviceAddressEqual(&port->plug.hostdevpci.addr,
4893 4894
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4895 4896 4897 4898 4899 4900 4901
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have "
4902
                             "PCI device %04x:%02x:%02x.%x in use by network port"),
4903
                           netdef->name,
4904 4905 4906 4907
                           port->plug.hostdevpci.addr.domain,
                           port->plug.hostdevpci.addr.bus,
                           port->plug.hostdevpci.addr.slot,
                           port->plug.hostdevpci.addr.function);
4908
            return -1;
4909 4910 4911 4912 4913 4914 4915
        }

        /* 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) &&
4916
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4917 4918 4919
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' claims the PCI device at "
                             "domain=%d bus=%d slot=%d function=%d "
4920
                             "is already in use by a different network port"),
4921 4922 4923
                           netdef->name,
                           dev->device.pci.domain, dev->device.pci.bus,
                           dev->device.pci.slot, dev->device.pci.function);
4924
            return -1;
4925
        }
4926 4927 4928 4929 4930 4931

        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
    default:
        virReportEnumRangeError(virNetworkPortPlugType, port->plugtype);
4932
        return -1;
4933 4934
    }

4935
    netdef->connections++;
4936 4937
    if (dev)
        dev->connections++;
4938
    /* finally we can call the 'plugged' hook script if any */
4939
    if (networkRunHook(obj, port, VIR_HOOK_NETWORK_OP_PORT_CREATED,
4940 4941 4942 4943 4944
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
4945
        return -1;
4946
    }
4947 4948
    networkLogAllocation(netdef, dev, &port->mac, true);

4949
    return 0;
4950 4951 4952
}


4953 4954 4955
/* networkReleasePort:
 * @obj: the network to release from
 * @port: the port definition to release
4956 4957 4958 4959 4960 4961 4962 4963
 *
 * 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.
 */
4964
static int
4965 4966
networkReleasePort(virNetworkObjPtr obj,
                   virNetworkPortDefPtr port)
4967
{
4968
    virNetworkDriverStatePtr driver = networkGetDriver();
4969
    virNetworkDefPtr netdef;
4970
    virNetworkForwardIfDefPtr dev = NULL;
4971
    size_t i;
4972

4973
    netdef = virNetworkObjGetDef(obj);
4974

4975 4976 4977
    switch ((virNetworkPortPlugType)port->plugtype) {
    case VIR_NETWORK_PORT_PLUG_TYPE_NONE:
        VIR_DEBUG("Releasing network device with no plug type");
4978 4979
        break;

4980 4981 4982 4983
    case VIR_NETWORK_PORT_PLUG_TYPE_NETWORK:
    case VIR_NETWORK_PORT_PLUG_TYPE_BRIDGE:
        if (networkUnplugBandwidth(obj, port->bandwidth,
                                   &port->class_id) < 0)
4984
            return -1;
4985 4986
        break;

4987 4988 4989 4990 4991 4992
    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);
4993
            return -1;
4994
        }
4995

4996 4997
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4998
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4999
                STREQ(port->plug.direct.linkdev, netdef->forward.ifs[i].device.dev)) {
5000
                dev = &netdef->forward.ifs[i];
5001 5002 5003
                break;
            }
        }
5004

5005
        if (!dev) {
5006
            virReportError(VIR_ERR_INTERNAL_ERROR,
5007 5008
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5009
                           netdef->name, port->plug.direct.linkdev);
5010
            return -1;
5011
        }
5012
        break;
5013

5014 5015
    case VIR_NETWORK_PORT_PLUG_TYPE_HOSTDEV_PCI:
        if (netdef->forward.nifs == 0) {
5016
            virReportError(VIR_ERR_INTERNAL_ERROR,
5017 5018 5019
                           _("network '%s' uses a hostdev mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
5020
            return -1;
5021 5022
        }

5023 5024
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5025
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5026
                virPCIDeviceAddressEqual(&port->plug.hostdevpci.addr,
5027 5028
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5029 5030 5031 5032 5033 5034 5035 5036 5037
                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,
5038 5039 5040 5041
                           port->plug.hostdevpci.addr.domain,
                           port->plug.hostdevpci.addr.bus,
                           port->plug.hostdevpci.addr.slot,
                           port->plug.hostdevpci.addr.function);
5042
            return -1;
5043
        }
5044 5045 5046 5047 5048
        break;

    case VIR_NETWORK_PORT_PLUG_TYPE_LAST:
    default:
        virReportEnumRangeError(virNetworkPortPlugType, port->plugtype);
5049
        return -1;
J
Ján Tomko 已提交
5050
    }
5051

5052
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, port->ownername, &port->mac);
5053 5054 5055 5056 5057

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

5062
    return 0;
5063 5064 5065
}


5066 5067 5068
/**
 * networkCheckBandwidth:
 * @net: network QoS
5069
 * @ifaceBand: interface QoS (may be NULL if no QoS)
5070
 * @oldBandwidth: new interface QoS (may be NULL if no QoS)
5071
 * @ifaceMac: interface MAC (used in error messages for identification)
5072 5073
 * @new_rate: new rate for non guaranteed class
 *
5074 5075 5076 5077 5078 5079 5080 5081
 * 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.
 *
5082 5083 5084 5085 5086
 * 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
5087
networkCheckBandwidth(virNetworkObjPtr obj,
5088
                      virNetDevBandwidthPtr ifaceBand,
5089
                      virNetDevBandwidthPtr oldBandwidth,
5090
                      virMacAddrPtr ifaceMac,
5091 5092
                      unsigned long long *new_rate)
{
5093 5094
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    virNetDevBandwidthPtr netBand = def->bandwidth;
5095
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5096 5097 5098
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5099
    virMacAddrFormat(ifaceMac, ifmac);
5100 5101 5102 5103 5104 5105

    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"),
5106
                       ifmac, def->name);
5107 5108 5109
        return -1;
    }

5110 5111 5112 5113 5114
    if (!netBand || !netBand->in) {
        VIR_DEBUG("No network bandwidth controls present");
        /* no QoS required, claim success */
        return 1;
    }
5115
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
5116 5117
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor))) {
        VIR_DEBUG("No old/new interface bandwidth floor");
5118
        /* no QoS required, claim success */
5119
        return 1;
5120
    }
5121 5122

    tmp_new_rate = netBand->in->average;
5123 5124 5125 5126
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
5127 5128 5129 5130 5131 5132

    /* 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,
5133 5134 5135
                           _("Cannot plug '%s' interface into '%s' because "
                             "new combined inbound floor=%llu would overcommit "
                             "peak=%llu on network '%s'"),
5136
                           ifmac,
5137
                           def->bridge,
5138 5139
                           tmp_floor_sum,
                           netBand->in->peak,
5140
                           def->name);
5141
            return -1;
5142 5143 5144 5145 5146
        }
    } 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,
5147 5148 5149
                       _("Cannot plug '%s' interface into '%s' because "
                         "new combined inbound floor=%llu would overcommit "
                         "average=%llu on network '%s'"),
5150
                       ifmac,
5151
                       def->bridge,
5152 5153
                       tmp_floor_sum,
                       netBand->in->average,
5154
                       def->name);
5155
        return -1;
5156 5157
    }

5158 5159
    if (new_rate)
        *new_rate = tmp_new_rate;
5160

5161
    return 0;
5162 5163
}

5164

5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175
/**
 * 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
5176
networkNextClassID(virNetworkObjPtr obj)
5177
{
5178
    ssize_t ret = 0;
5179
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5180

5181 5182
    if ((ret = virBitmapNextClearBit(classIdMap, -1)) < 0)
        ret = virBitmapSize(classIdMap);
5183

5184
    if (virBitmapSetBitExpand(classIdMap, ret) < 0)
5185 5186 5187 5188 5189
        return -1;

    return ret;
}

5190

5191
static int
5192
networkPlugBandwidthImpl(virNetworkObjPtr obj,
5193
                         virMacAddrPtr mac,
5194
                         virNetDevBandwidthPtr ifaceBand,
5195
                         unsigned int *class_id,
5196
                         unsigned long long new_rate)
5197
{
5198
    virNetworkDriverStatePtr driver = networkGetDriver();
5199
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5200
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5201
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5202
    ssize_t next_id = 0;
5203
    int plug_ret;
5204 5205

    /* generate new class_id */
5206
    if ((next_id = networkNextClassID(obj)) < 0) {
5207 5208
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate next class ID"));
5209
        return -1;
5210 5211
    }

5212
    plug_ret = virNetDevBandwidthPlug(def->bridge, def->bandwidth,
5213
                                      mac, ifaceBand, next_id);
5214
    if (plug_ret < 0) {
5215
        ignore_value(virNetDevBandwidthUnplug(def->bridge, next_id));
5216
        return -1;
5217 5218 5219
    }

    /* QoS was set, generate new class ID */
5220
    *class_id = next_id;
5221
    /* update sum of 'floor'-s of attached NICs */
5222 5223
    tmp_floor_sum += ifaceBand->in->floor;
    virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5224
    /* update status file */
5225
    if (virNetworkObjSaveStatus(driver->stateDir, obj, network_driver->xmlopt) < 0) {
5226
        ignore_value(virBitmapClearBit(classIdMap, next_id));
5227 5228
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5229 5230
        *class_id = 0;
        ignore_value(virNetDevBandwidthUnplug(def->bridge, next_id));
5231
        return -1;
5232
    }
5233
    /* update rate for non guaranteed NICs */
5234
    new_rate -= tmp_floor_sum;
5235 5236
    if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                     def->bandwidth, new_rate) < 0)
5237
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5238
                 def->bridge);
5239

5240
    return 0;
5241 5242 5243 5244
}


static int
5245
networkPlugBandwidth(virNetworkObjPtr obj,
5246 5247 5248
                     virMacAddrPtr mac,
                     virNetDevBandwidthPtr ifaceBand,
                     unsigned int *class_id)
5249 5250 5251 5252 5253
{
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5254
    if ((plug_ret = networkCheckBandwidth(obj, ifaceBand, NULL,
5255
                                          mac, &new_rate)) < 0) {
5256
        /* helper reported error */
5257
        return -1;
5258 5259
    }

5260
    if (plug_ret > 0)
5261
        /* no QoS needs to be set; claim success */
5262
        return 0;
5263

5264
    virMacAddrFormat(mac, ifmac);
5265

5266
    if (networkPlugBandwidthImpl(obj, mac, ifaceBand, class_id, new_rate) < 0)
5267
        return -1;
5268

5269
    return 0;
5270 5271
}

5272

5273
static int
5274
networkUnplugBandwidth(virNetworkObjPtr obj,
5275 5276
                       virNetDevBandwidthPtr ifaceBand,
                       unsigned int *class_id)
5277
{
5278
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5279
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5280
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5281
    virNetworkDriverStatePtr driver = networkGetDriver();
5282 5283 5284
    int ret = 0;
    unsigned long long new_rate;

5285
    if (class_id && *class_id) {
5286
        if (!def->bandwidth || !def->bandwidth->in) {
5287
            VIR_WARN("Network %s has no bandwidth but unplug requested",
5288
                     def->name);
5289
            return 0;
5290
        }
5291
        /* we must remove class from bridge */
5292
        new_rate = def->bandwidth->in->average;
5293

5294 5295
        if (def->bandwidth->in->peak > 0)
            new_rate = def->bandwidth->in->peak;
5296

5297
        ret = virNetDevBandwidthUnplug(def->bridge, *class_id);
5298
        if (ret < 0)
5299
            return ret;
5300
        /* update sum of 'floor'-s of attached NICs */
5301 5302 5303
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);

5304
        /* return class ID */
5305
        ignore_value(virBitmapClearBit(classIdMap, *class_id));
5306
        /* update status file */
5307 5308
        if (virNetworkObjSaveStatus(driver->stateDir,
                                    obj, network_driver->xmlopt) < 0) {
5309 5310
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5311
            ignore_value(virBitmapSetBit(classIdMap, *class_id));
5312
            return ret;
5313
        }
5314
        /* update rate for non guaranteed NICs */
5315
        new_rate -= tmp_floor_sum;
5316 5317
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0)
5318
            VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5319
                     def->bridge);
5320
        /* no class is associated any longer */
5321
        *class_id = 0;
5322 5323 5324 5325
    }

    return ret;
}
5326

5327

5328
static void
5329
networkNetworkObjTaint(virNetworkObjPtr obj,
5330
                       virNetworkTaintFlags taint)
5331
{
5332 5333
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

5334
    if (virNetworkObjTaint(obj, taint)) {
5335
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5336
        virUUIDFormat(def->uuid, uuidstr);
5337 5338

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5339
                 def->name, uuidstr, virNetworkTaintTypeToString(taint));
5340 5341
    }
}
5342 5343


5344
static int
5345 5346 5347 5348 5349
networkUpdatePortBandwidth(virNetworkObjPtr obj,
                           virMacAddrPtr mac,
                           unsigned int *class_id,
                           virNetDevBandwidthPtr oldBandwidth,
                           virNetDevBandwidthPtr newBandwidth)
5350 5351
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5352
    virNetworkDefPtr def;
5353
    unsigned long long tmp_floor_sum;
5354
    unsigned long long new_rate = 0;
5355
    unsigned long long old_floor, new_floor;
5356
    int plug_ret;
5357 5358 5359

    old_floor = new_floor = 0;

5360 5361
    if (oldBandwidth && oldBandwidth->in)
        old_floor = oldBandwidth->in->floor;
5362 5363 5364 5365
    if (newBandwidth && newBandwidth->in)
        new_floor = newBandwidth->in->floor;

    if (new_floor == old_floor)
5366 5367
        return 0;

5368
    def = virNetworkObjGetDef(obj);
5369

5370 5371
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, oldBandwidth,
                                          mac, &new_rate)) < 0) {
5372
        /* helper reported error */
5373
        return -1;
5374 5375 5376 5377
    }

    if (plug_ret > 0) {
        /* no QoS needs to be set; claim success */
5378
        return 0;
5379 5380 5381 5382
    }

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

5383
    if (oldBandwidth && oldBandwidth->in && oldBandwidth->in->floor &&
5384
        newBandwidth->in && newBandwidth->in->floor) {
5385 5386
        /* Either we just need to update @floor .. */

5387
        if (virNetDevBandwidthUpdateRate(def->bridge,
5388
                                         *class_id,
5389
                                         def->bandwidth,
5390
                                         newBandwidth->in->floor) < 0)
5391
            return -1;
5392

5393
        tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5394
        tmp_floor_sum -= oldBandwidth->in->floor;
5395 5396 5397
        tmp_floor_sum += newBandwidth->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
        new_rate -= tmp_floor_sum;
5398

5399 5400
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0 ||
5401 5402
            virNetworkObjSaveStatus(driver->stateDir,
                                    obj, network_driver->xmlopt) < 0) {
5403
            /* Ouch, rollback */
5404
            tmp_floor_sum -= newBandwidth->in->floor;
5405
            tmp_floor_sum += oldBandwidth->in->floor;
5406
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5407

5408
            ignore_value(virNetDevBandwidthUpdateRate(def->bridge,
5409
                                                      *class_id,
5410
                                                      def->bandwidth,
5411 5412
                                                      oldBandwidth->in->floor));
            return -1;
5413 5414 5415 5416
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5417 5418
        if (networkPlugBandwidthImpl(obj, mac, newBandwidth,
                                     class_id,
5419
                                     new_rate) < 0)
5420
            return -1;
5421 5422 5423
    } else {
        /* .. or unplug old. */

5424 5425
        if (networkUnplugBandwidth(obj, oldBandwidth, class_id) < 0)
            return -1;
5426 5427
    }

5428 5429 5430 5431
    return 0;
}


5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476
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 已提交
5477
    g_autoptr(virNetworkPortDef) portdef = NULL;
5478 5479 5480 5481 5482 5483 5484 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
    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);
5519 5520 5521 5522
    if (rc < 0)
        goto cleanup;

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

5525
        virErrorPreserveLast(&save_err);
5526
        ignore_value(networkReleasePort(obj, portdef));
5527 5528
        virErrorRestore(&save_err);

5529 5530 5531 5532
        goto cleanup;
    }

    ret = virGetNetworkPort(net, portdef->uuid);
5533
    portdef = NULL;
5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 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
 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;
}


5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843
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 */
5844 5845 5846 5847 5848 5849 5850
    .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 */
5851 5852
};

5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864

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 = {
5865
    .localOnly = true,
5866
    .uriSchemes = (const char *[]){ "network", NULL },
5867 5868 5869 5870 5871
    .hypervisorDriver = &networkHypervisorDriver,
    .networkDriver = &networkDriver,
};


5872 5873 5874 5875 5876 5877 5878 5879 5880 5881
static virStateDriver networkStateDriver = {
    .name = "bridge",
    .stateInitialize  = networkStateInitialize,
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
};

int
networkRegister(void)
{
5882 5883
    if (virRegisterConnectDriver(&networkConnectDriver, false) < 0)
        return -1;
5884 5885 5886 5887 5888 5889
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
    return 0;
}