bridge_driver.c 183.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 37 38
#if HAVE_SYS_SYSCTL_H
# 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

71
#define VIR_FROM_THIS VIR_FROM_NETWORK
72
#define MAX_BRIDGE_ID 256
73

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

81 82
#define SYSCTL_PATH "/proc/sys"

83 84
VIR_LOG_INIT("network.bridge_driver");

85
static virNetworkDriverStatePtr network_driver;
86

87

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

97 98 99

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


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

111

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

122

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

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

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

138

139 140 141 142 143
static int
networkStateCleanup(void);

static int
networkStartNetwork(virNetworkDriverStatePtr driver,
144
                    virNetworkObjPtr obj);
145 146 147

static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
148
                       virNetworkObjPtr obj);
149 150 151

static int
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
152
                           virNetworkObjPtr obj);
153 154 155

static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
156
                              virNetworkObjPtr obj);
157

158
static int
159
networkStartNetworkExternal(virNetworkObjPtr obj);
160

161
static int
162
networkShutdownNetworkExternal(virNetworkObjPtr obj);
163

164
static void
165
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup);
166

167 168
static void
networkRefreshDaemons(virNetworkDriverStatePtr driver);
169

170
static int
171
networkPlugBandwidth(virNetworkObjPtr obj,
172 173 174
                     virMacAddrPtr mac,
                     virNetDevBandwidthPtr ifaceBand,
                     unsigned int *class_id);
175

176
static int
177
networkUnplugBandwidth(virNetworkObjPtr obj,
178 179
                       virNetDevBandwidthPtr ifaceBand,
                       unsigned int *class_id);
180

181
static void
182
networkNetworkObjTaint(virNetworkObjPtr obj,
183
                       virNetworkTaintFlags taint);
184

185

186 187 188
static virNetworkObjPtr
networkObjFromNetwork(virNetworkPtr net)
{
189
    virNetworkDriverStatePtr driver = networkGetDriver();
190
    virNetworkObjPtr obj;
191 192
    char uuidstr[VIR_UUID_STRING_BUFLEN];

193 194
    obj = virNetworkObjFindByUUID(driver->networks, net->uuid);
    if (!obj) {
195 196 197 198 199 200
        virUUIDFormat(net->uuid, uuidstr);
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching uuid '%s' (%s)"),
                       uuidstr, net->name);
    }

201
    return obj;
202 203
}

204

205
static int
206
networkRunHook(virNetworkObjPtr obj,
207
               virDomainDefPtr dom,
208
               virDomainNetDefPtr iface,
209 210 211
               int op,
               int sub_op)
{
212
    virNetworkDefPtr def;
213 214 215 216 217 218
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char *xml = NULL, *net_xml = NULL, *dom_xml = NULL;
    int hookret;
    int ret = -1;

    if (virHookPresent(VIR_HOOK_DRIVER_NETWORK)) {
219 220
        if (!obj) {
            VIR_DEBUG("Not running hook as @obj is NULL");
221 222 223
            ret = 0;
            goto cleanup;
        }
224
        def = virNetworkObjGetDef(obj);
225

226 227
        virBufferAddLit(&buf, "<hookData>\n");
        virBufferAdjustIndent(&buf, 2);
228
        if (iface && virDomainNetDefFormat(&buf, iface, NULL, 0) < 0)
229
            goto cleanup;
230
        if (virNetworkDefFormatBuf(&buf, def, 0) < 0)
231
            goto cleanup;
232
        if (dom && virDomainDefFormatInternal(dom, NULL, 0, &buf, NULL) < 0)
233 234 235 236 237
            goto cleanup;

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

238
        if (virBufferCheckError(&buf) < 0)
239 240
            goto cleanup;

241
        xml = virBufferContentAndReset(&buf);
242
        hookret = virHookCall(VIR_HOOK_DRIVER_NETWORK, def->name,
243 244 245 246 247 248 249
                              op, sub_op, NULL, xml, NULL);

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

251
        networkNetworkObjTaint(obj, VIR_NETWORK_TAINT_HOOK);
252 253 254
    }

    ret = 0;
255
 cleanup:
256 257 258 259 260 261 262
    virBufferFreeAndReset(&buf);
    VIR_FREE(xml);
    VIR_FREE(net_xml);
    VIR_FREE(dom_xml);
    return ret;
}

263

264
static char *
265 266
networkDnsmasqLeaseFileNameDefault(virNetworkDriverStatePtr driver,
                                   const char *netname)
267 268 269
{
    char *leasefile;

270
    ignore_value(virAsprintf(&leasefile, "%s/%s.leases",
271
                             driver->dnsmasqStateDir, netname));
272 273 274
    return leasefile;
}

275

276
static char *
277 278
networkDnsmasqLeaseFileNameCustom(virNetworkDriverStatePtr driver,
                                  const char *bridge)
279 280 281 282
{
    char *leasefile;

    ignore_value(virAsprintf(&leasefile, "%s/%s.status",
283
                             driver->dnsmasqStateDir, bridge));
284 285 286
    return leasefile;
}

287

288
static char *
289 290
networkDnsmasqConfigFileName(virNetworkDriverStatePtr driver,
                             const char *netname)
291 292 293
{
    char *conffile;

294
    ignore_value(virAsprintf(&conffile, "%s/%s.conf",
295
                             driver->dnsmasqStateDir, netname));
296 297 298
    return conffile;
}

299

300 301 302 303 304 305
static char *
networkRadvdPidfileBasename(const char *netname)
{
    /* this is simple but we want to be sure it's consistently done */
    char *pidfilebase;

306
    ignore_value(virAsprintf(&pidfilebase, "%s-radvd", netname));
307 308 309
    return pidfilebase;
}

310

311
static char *
312 313
networkRadvdConfigFileName(virNetworkDriverStatePtr driver,
                           const char *netname)
314 315 316
{
    char *configfile;

317
    ignore_value(virAsprintf(&configfile, "%s/%s-radvd.conf",
318
                             driver->radvdStateDir, netname));
319 320
    return configfile;
}
321

322

323 324
/* do needed cleanup steps and remove the network from the list */
static int
325
networkRemoveInactive(virNetworkDriverStatePtr driver,
326
                      virNetworkObjPtr obj)
327 328
{
    char *leasefile = NULL;
329
    char *customleasefile = NULL;
330
    char *radvdconfigfile = NULL;
331
    char *configfile = NULL;
332
    char *radvdpidbase = NULL;
333
    char *statusfile = NULL;
M
Michal Privoznik 已提交
334
    char *macMapFile = NULL;
335
    dnsmasqContext *dctx = NULL;
336
    virNetworkDefPtr def = virNetworkObjGetPersistentDef(obj);
337 338 339 340

    int ret = -1;

    /* remove the (possibly) existing dnsmasq and radvd files */
341
    if (!(dctx = dnsmasqContextNew(def->name,
342
                                   driver->dnsmasqStateDir))) {
343
        goto cleanup;
344
    }
345

346
    if (!(leasefile = networkDnsmasqLeaseFileNameDefault(driver, def->name)))
347 348
        goto cleanup;

349
    if (!(customleasefile = networkDnsmasqLeaseFileNameCustom(driver, def->bridge)))
350 351
        goto cleanup;

352
    if (!(radvdconfigfile = networkRadvdConfigFileName(driver, def->name)))
353
        goto cleanup;
354 355

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
356
        goto cleanup;
357

358
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
359
        goto cleanup;
360

361
    if (!(statusfile = virNetworkConfigFile(driver->stateDir, def->name)))
362
        goto cleanup;
363

364
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir, def->bridge)))
M
Michal Privoznik 已提交
365 366
        goto cleanup;

367 368 369
    /* dnsmasq */
    dnsmasqDelete(dctx);
    unlink(leasefile);
370
    unlink(customleasefile);
371
    unlink(configfile);
372

M
Michal Privoznik 已提交
373 374 375
    /* MAC map manager */
    unlink(macMapFile);

376 377
    /* radvd */
    unlink(radvdconfigfile);
378
    virPidFileDelete(driver->pidDir, radvdpidbase);
379

380 381 382
    /* remove status file */
    unlink(statusfile);

383
    /* remove the network definition */
384
    virNetworkObjRemoveInactive(driver->networks, obj);
385 386 387

    ret = 0;

388
 cleanup:
389
    VIR_FREE(leasefile);
390
    VIR_FREE(configfile);
391
    VIR_FREE(customleasefile);
392 393
    VIR_FREE(radvdconfigfile);
    VIR_FREE(radvdpidbase);
394
    VIR_FREE(statusfile);
M
Michal Privoznik 已提交
395
    VIR_FREE(macMapFile);
396 397 398 399
    dnsmasqContextFree(dctx);
    return ret;
}

400

401 402 403
static char *
networkBridgeDummyNicName(const char *brname)
{
404
    static const char dummyNicSuffix[] = "-nic";
405 406
    char *nicname;

407 408 409 410 411 412 413
    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.
         */
414 415 416 417 418
        ignore_value(virAsprintf(&nicname, "%.*s%s%s",
                                 /* space for last 3 chars + "-nic" + NULL */
                                 (int)(IFNAMSIZ - (3 + sizeof(dummyNicSuffix))),
                                 brname, brname + strlen(brname) - 3,
                                 dummyNicSuffix));
419
    } else {
420
        ignore_value(virAsprintf(&nicname, "%s%s", brname, dummyNicSuffix));
421
    }
422 423 424
    return nicname;
}

425

426 427
static int
networkUpdateState(virNetworkObjPtr obj,
428
                   void *opaque)
429
{
430
    virNetworkDefPtr def;
431
    virNetworkDriverStatePtr driver = opaque;
432
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
433
    virMacMapPtr macmap;
434
    char *macMapFile = NULL;
435
    int ret = -1;
436

437
    virObjectLock(obj);
438
    if (!virNetworkObjIsActive(obj)) {
439 440
        ret = 0;
        goto cleanup;
441
    }
442
    def = virNetworkObjGetDef(obj);
443

444
    switch ((virNetworkForwardType) def->forward.type) {
445 446 447
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
448
    case VIR_NETWORK_FORWARD_OPEN:
449
        /* If bridge doesn't exist, then mark it inactive */
450
        if (!(def->bridge && virNetDevExists(def->bridge) == 1))
451
            virNetworkObjSetActive(obj, false);
452

453
        if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
454
                                             def->bridge)))
455 456
            goto cleanup;

457
        if (!(macmap = virMacMapNew(macMapFile)))
458 459
            goto cleanup;

460 461
        virNetworkObjSetMacMap(obj, macmap);

462
        break;
463

464
    case VIR_NETWORK_FORWARD_BRIDGE:
465 466
        if (def->bridge) {
            if (virNetDevExists(def->bridge) != 1)
467
                virNetworkObjSetActive(obj, false);
468
            break;
469
        }
470 471 472 473 474 475 476 477 478
        /* 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;
479

480 481 482
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
483 484 485 486 487

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

490
    /* Try and read dnsmasq/radvd pids of active networks */
491
    if (virNetworkObjIsActive(obj) && def->ips && (def->nips > 0)) {
492 493
        pid_t radvdPid;
        pid_t dnsmasqPid;
494
        char *radvdpidbase;
495

496
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
497
                                           def->name,
498
                                           &dnsmasqPid,
499
                                           dnsmasqCapsGetBinaryPath(dnsmasq_caps)));
500
        virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
M
Michal Privoznik 已提交
501

502
        radvdpidbase = networkRadvdPidfileBasename(def->name);
503 504
        if (!radvdpidbase)
            goto cleanup;
505

506 507
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
508 509
                                           &radvdPid, RADVD));
        virNetworkObjSetRadvdPid(obj, radvdPid);
510
        VIR_FREE(radvdpidbase);
511
    }
512

513 514
    ret = 0;
 cleanup:
515
    virObjectUnlock(obj);
516
    virObjectUnref(dnsmasq_caps);
517
    VIR_FREE(macMapFile);
518 519
    return ret;
}
520

521

522
static int
523
networkAutostartConfig(virNetworkObjPtr obj,
524
                       void *opaque)
525
{
526
    virNetworkDriverStatePtr driver = opaque;
527
    int ret = -1;
528

529
    virObjectLock(obj);
530
    if (virNetworkObjIsAutostart(obj) &&
531 532
        !virNetworkObjIsActive(obj) &&
        networkStartNetwork(driver, obj) < 0)
533 534 535 536
        goto cleanup;

    ret = 0;
 cleanup:
537
    virObjectUnlock(obj);
538
    return ret;
539 540
}

541

542
#ifdef WITH_FIREWALLD
543 544
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
545 546
                             DBusMessage *message,
                             void *user_data)
547
{
548
    virNetworkDriverStatePtr driver = user_data;
549
    bool reload = false;
550

551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
    if (dbus_message_is_signal(message,
                               "org.fedoraproject.FirewallD1", "Reloaded")) {
        reload = true;

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

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

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

    if (reload) {
575
        VIR_DEBUG("Reload in bridge_driver because of firewalld.");
576
        networkReloadFirewallRules(driver, false);
577 578 579 580 581 582
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

583

584
/**
585
 * networkStateInitialize:
586
 *
J
Ján Tomko 已提交
587
 * Initialization function for the QEMU daemon
588 589
 */
static int
590 591 592
networkStateInitialize(bool privileged,
                       virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
593
{
594 595 596
    int ret = -1;
    char *configdir = NULL;
    char *rundir = NULL;
597
#ifdef WITH_FIREWALLD
598 599
    DBusConnection *sysbus = NULL;
#endif
600

601
    if (VIR_ALLOC(network_driver) < 0)
602
        goto error;
603

604 605
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
606 607
        goto error;
    }
608

609 610
    network_driver->privileged = privileged;

611 612 613 614
    /* configuration/state paths are one of
     * ~/.config/libvirt/... (session/unprivileged)
     * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
     */
615
    if (privileged) {
616
        if (VIR_STRDUP(network_driver->networkConfigDir,
617
                       SYSCONFDIR "/libvirt/qemu/networks") < 0 ||
618
            VIR_STRDUP(network_driver->networkAutostartDir,
619
                       SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
620
            VIR_STRDUP(network_driver->stateDir,
621
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
622
            VIR_STRDUP(network_driver->pidDir,
623
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
624
            VIR_STRDUP(network_driver->dnsmasqStateDir,
625
                       LOCALSTATEDIR "/lib/libvirt/dnsmasq") < 0 ||
626
            VIR_STRDUP(network_driver->radvdStateDir,
627 628
                       LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
            goto error;
629
    } else {
630 631 632
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
633
            goto error;
634

635
        if ((virAsprintf(&network_driver->networkConfigDir,
636
                         "%s/qemu/networks", configdir) < 0) ||
637
            (virAsprintf(&network_driver->networkAutostartDir,
638
                         "%s/qemu/networks/autostart", configdir) < 0) ||
639
            (virAsprintf(&network_driver->stateDir,
640
                         "%s/network/lib", rundir) < 0) ||
641
            (virAsprintf(&network_driver->pidDir,
642
                         "%s/network/run", rundir) < 0) ||
643
            (virAsprintf(&network_driver->dnsmasqStateDir,
644
                         "%s/dnsmasq/lib", rundir) < 0) ||
645
            (virAsprintf(&network_driver->radvdStateDir,
646
                         "%s/radvd/lib", rundir) < 0)) {
647
            goto error;
648
        }
649 650
    }

651
    if (virFileMakePath(network_driver->stateDir) < 0) {
652 653
        virReportSystemError(errno,
                             _("cannot create directory %s"),
654
                             network_driver->stateDir);
655 656 657
        goto error;
    }

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

661
    if (!(network_driver->networks = virNetworkObjListNew()))
662 663
        goto error;

664 665
    if (virNetworkObjLoadAllState(network_driver->networks,
                                  network_driver->stateDir) < 0)
666 667
        goto error;

668 669 670
    if (virNetworkObjLoadAllConfigs(network_driver->networks,
                                    network_driver->networkConfigDir,
                                    network_driver->networkAutostartDir) < 0)
671 672
        goto error;

673 674 675 676
    /* 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). */
677
    virNetworkObjListForEach(network_driver->networks,
678
                             networkUpdateState,
679 680
                             network_driver);
    virNetworkObjListPrune(network_driver->networks,
681 682
                           VIR_CONNECT_LIST_NETWORKS_INACTIVE |
                           VIR_CONNECT_LIST_NETWORKS_TRANSIENT);
683
    networkReloadFirewallRules(network_driver, true);
684
    networkRefreshDaemons(network_driver);
685

686 687 688 689
    virNetworkObjListForEach(network_driver->networks,
                             networkAutostartConfig,
                             network_driver);

690
    network_driver->networkEventState = virObjectEventStateNew();
691

692
#ifdef WITH_FIREWALLD
693 694
    if (!(sysbus = virDBusGetSystemBus())) {
        VIR_WARN("DBus not available, disabling firewalld support "
695
                 "in bridge_network_driver: %s", virGetLastErrorMessage());
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
    } 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,
713
                                   network_driver, NULL);
714 715 716
    }
#endif

717
    ret = 0;
718
 cleanup:
719 720 721
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
722

723
 error:
724
    networkStateCleanup();
725
    goto cleanup;
726 727
}

728

729
/**
730
 * networkStateReload:
731
 *
J
Ján Tomko 已提交
732
 * Function to restart the QEMU daemon, it will recheck the configuration
733 734 735
 * files and update its state and the networking
 */
static int
736 737
networkStateReload(void)
{
738
    if (!network_driver)
739 740
        return 0;

741 742 743 744 745
    virNetworkObjLoadAllState(network_driver->networks,
                              network_driver->stateDir);
    virNetworkObjLoadAllConfigs(network_driver->networks,
                                network_driver->networkConfigDir,
                                network_driver->networkAutostartDir);
746
    networkReloadFirewallRules(network_driver, false);
747 748
    networkRefreshDaemons(network_driver);
    virNetworkObjListForEach(network_driver->networks,
749
                             networkAutostartConfig,
750
                             network_driver);
751 752 753 754 755
    return 0;
}


/**
756
 * networkStateCleanup:
757
 *
J
Ján Tomko 已提交
758
 * Shutdown the QEMU daemon, it will stop all active domains and networks
759 760
 */
static int
761 762
networkStateCleanup(void)
{
763
    if (!network_driver)
764 765
        return -1;

766
    virObjectUnref(network_driver->networkEventState);
767

768
    /* free inactive networks */
769
    virObjectUnref(network_driver->networks);
770

771 772 773 774 775 776
    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);
777

778
    virObjectUnref(network_driver->dnsmasqCaps);
779

780
    virMutexDestroy(&network_driver->lock);
781

782
    VIR_FREE(network_driver);
783 784 785 786 787

    return 0;
}


788 789 790 791 792 793 794 795
static virDrvOpenStatus
networkConnectOpen(virConnectPtr conn,
                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                   virConfPtr conf ATTRIBUTE_UNUSED,
                   unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

796 797 798 799 800 801 802 803 804 805 806
    if (network_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("network state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
    }

    if (network_driver->privileged) {
        if (STRNEQ(conn->uri->path, "/system")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected network URI path '%s', try network:///system"),
                           conn->uri->path);
807 808
            return VIR_DRV_OPEN_ERROR;
        }
809 810 811 812 813 814
    } else {
        if (STRNEQ(conn->uri->path, "/session")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected network URI path '%s', try network:///session"),
                           conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
        }
    }

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

    return VIR_DRV_OPEN_SUCCESS;
}

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


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


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


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


850 851 852 853 854
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
855 856 857
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
858
{
859 860
    size_t i;
    int ret = -1;
861 862 863 864 865 866 867
    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.
     */
868
    for (i = 0; i < 25; i++) {
869
        int signum = 0;
870
        if (i == 0) {
871
            signum = SIGTERM;
872
        } else if (i == 15) {
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
            signum = SIGKILL;
            signame = "KILL";
        }
        if (kill(pid, signum) < 0) {
            if (errno == ESRCH) {
                ret = 0;
            } else {
                char ebuf[1024];
                VIR_WARN("Failed to terminate %s process %d "
                         "for network '%s' with SIG%s: %s",
                         daemonName, pid, networkName, signame,
                         virStrerror(errno, ebuf, sizeof(ebuf)));
            }
            goto cleanup;
        }
        /* NB: since networks have no reference count like
         * domains, there is no safe way to unlock the network
         * object temporarily, and so we can't follow the
         * procedure used by the qemu driver of 1) unlock driver
         * 2) sleep, 3) add ref to object 4) unlock object, 5)
         * re-lock driver, 6) re-lock object. We may need to add
         * that functionality eventually, but for now this
         * function is rarely used and, at worst, leaving the
         * network driver locked during this loop of sleeps will
         * have the effect of holding up any other thread trying
         * to make modifications to a network for up to 5 seconds;
         * since modifications to networks are much less common
         * than modifications to domains, this seems a reasonable
         * tradeoff in exchange for less code disruption.
         */
        usleep(20 * 1000);
    }
    VIR_WARN("Timed out waiting after SIG%s to %s process %d "
             "(network '%s')",
             signame, daemonName, pid, networkName);
908
 cleanup:
909 910 911
    return ret;
}

912

J
Ján Tomko 已提交
913 914 915
/* the following does not build a file, it builds a list
 * which is later saved into a file
 */
916
static int
G
Gene Czarcinski 已提交
917
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
918
                                 virNetworkIPDefPtr ipdef)
919
{
920
    size_t i;
G
Gene Czarcinski 已提交
921
    bool ipv6 = false;
922

G
Gene Czarcinski 已提交
923 924
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
925 926
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
927
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
928 929
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
930
                return -1;
931
    }
932

G
Gene Czarcinski 已提交
933 934 935
    return 0;
}

936

G
Gene Czarcinski 已提交
937 938 939 940
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
941
    size_t i, j;
G
Gene Czarcinski 已提交
942

943 944
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
945
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
946
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
947
                for (j = 0; j < host->nnames; j++)
948 949
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
950 951
            }
        }
952 953
    }

954
    return 0;
955 956 957
}


958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
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;
}


995
int
996
networkDnsmasqConfContents(virNetworkObjPtr obj,
997 998 999 1000
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
                           dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
1001
{
1002
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1003
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1004
    int r, ret = -1;
1005
    int nbleases = 0;
1006
    size_t i;
1007
    virNetworkDNSDefPtr dns = &def->dns;
1008
    bool wantDNS = dns->enable != VIR_TRISTATE_BOOL_NO;
1009
    virNetworkIPDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
G
Gene Czarcinski 已提交
1010
    bool ipv6SLAAC;
1011
    char *saddr = NULL, *eaddr = NULL;
1012

1013 1014
    *configstr = NULL;

1015
    /*
1016 1017 1018
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1019
     *
1020 1021
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1022
     */
1023 1024 1025 1026 1027 1028

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

1029
    /* create dnsmasq config file appropriate for this network */
1030 1031

    /* Don't forget to update networkxml2conftest :-) */
1032
    virBufferAsprintf(&configbuf,
1033 1034 1035 1036 1037 1038 1039
                      "##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"
1040
                      "strict-order\n",
1041
                      def->name);
1042

1043 1044 1045 1046 1047 1048
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1049
    if (wantDNS && def->dns.forwarders) {
1050 1051 1052 1053 1054 1055 1056 1057 1058
        /* 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;

1059 1060
        for (i = 0; i < def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &def->dns.forwarders[i];
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070

            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);
1071
                VIR_FREE(addr);
1072 1073
                if (!fwd->domain)
                    addNoResolv = true;
1074 1075 1076 1077
            } else {
                /* "don't forward requests for this domain" */
                virBufferAddLit(&configbuf, "#\n");
            }
1078
        }
1079 1080
        if (addNoResolv)
            virBufferAddLit(&configbuf, "no-resolv\n");
1081 1082
    }

1083 1084
    if (def->domain) {
        if (def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1085 1086
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1087
                              def->domain);
1088
        }
1089
        virBufferAsprintf(&configbuf,
1090 1091
                          "domain=%s\n"
                          "expand-hosts\n",
1092
                          def->domain);
1093
    }
1094

1095
    if (wantDNS &&
1096
        networkDnsmasqConfLocalPTRs(&configbuf, def) < 0)
1097 1098
        goto cleanup;

1099
    if (wantDNS && def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1100 1101 1102 1103
        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)
1104
         */
1105
        virBufferAddLit(&configbuf, "local=//\n");
1106
    }
1107

1108
    if (pidfile)
1109
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1110

1111
    /* dnsmasq will *always* listen on localhost unless told otherwise */
P
Pavel Timofeev 已提交
1112
#ifdef __linux__
1113
    virBufferAddLit(&configbuf, "except-interface=lo\n");
P
Pavel Timofeev 已提交
1114 1115 1116 1117
#else
    /* BSD family OSes and Solaris call loopback interface as lo0 */
    virBufferAddLit(&configbuf, "except-interface=lo0\n");
#endif
1118

1119 1120 1121 1122 1123 1124 1125 1126
    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.
         */
1127
        virBufferAsprintf(&configbuf,
1128 1129
                          "bind-dynamic\n"
                          "interface=%s\n",
1130
                          def->bridge);
1131
    } else {
1132
        virBufferAddLit(&configbuf, "bind-interfaces\n");
1133 1134 1135 1136
        /*
         * --interface does not actually work with dnsmasq < 2.47,
         * due to DAD for ipv6 addresses on the interface.
         *
1137
         * virCommandAddArgList(cmd, "--interface", def->bridge, NULL);
1138 1139 1140
         *
         * So listen on all defined IPv[46] addresses
         */
1141
        for (i = 0;
1142
             (tmpipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
1143
             i++) {
1144 1145 1146 1147
            char *ipaddr = virSocketAddrFormat(&tmpipdef->address);

            if (!ipaddr)
                goto cleanup;
1148

1149
            /* also part of CVE 2012-3411 - if the host's version of
1150
             * dnsmasq doesn't have bind-dynamic, only allow listening on
1151 1152
             * private/local IP addresses (see RFC1918/RFC3484/RFC4193)
             */
1153 1154
            if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
                !virSocketAddrIsPrivate(&tmpipdef->address)) {
1155 1156 1157 1158
                unsigned long version = dnsmasqCapsGetVersion(caps);

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
1159
                                 "The version of dnsmasq on this host (%d.%d) "
1160 1161 1162 1163
                                 "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 "
1164 1165 1166 1167 1168 1169
                                 "(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);
1170
                VIR_FREE(ipaddr);
1171 1172
                goto cleanup;
            }
1173
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
1174 1175 1176
            VIR_FREE(ipaddr);
        }
    }
1177

1178 1179
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
1180
     * guaranteed to not work, and set no-resolv so that no dns
1181 1182 1183
     * 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).
1184 1185 1186
     * 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.
1187
     */
1188
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE) {
1189
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
1190
                        "no-resolv\n");
1191 1192 1193 1194
        if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM)) {
            /* interface=* (any), interval=0 (default), lifetime=0 (seconds) */
            virBufferAddLit(&configbuf, "ra-param=*,0,0\n");
        }
1195
    }
1196

1197 1198 1199 1200 1201
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1202
        }
1203

1204 1205 1206 1207 1208 1209 1210 1211
        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'"),
1212
                               def->name);
1213 1214 1215 1216 1217 1218
                goto cleanup;
            }
            if (!dns->srvs[i].protocol) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing required 'service' "
                                 "attribute in SRV record of network '%s'"),
1219
                               def->name);
1220 1221 1222 1223 1224 1225 1226
                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);
1227

1228 1229 1230 1231 1232 1233 1234
            /* 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.
1235
             */
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
            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");
1256
        }
1257 1258
    }

G
Gene Czarcinski 已提交
1259
    /* Find the first dhcp for both IPv4 and IPv6 */
1260
    for (i = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
1261
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
1262
         i++) {
G
Gene Czarcinski 已提交
1263 1264 1265 1266
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1267 1268
                                   _("For IPv4, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279
                    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,
1280 1281 1282 1283 1284 1285 1286 1287 1288
                                   _("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 已提交
1289 1290 1291 1292
                    goto cleanup;
                }
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1293 1294
                                   _("For IPv6, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
                    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 "
1308 1309 1310 1311
                 "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 已提交
1312 1313 1314 1315 1316
    }

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1317 1318
        int prefix;

1319
        prefix = virNetworkIPDefPrefix(ipdef);
1320 1321 1322
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1323
                           def->bridge);
1324 1325
            goto cleanup;
        }
1326
        for (r = 0; r < ipdef->nranges; r++) {
1327 1328
            int thisRange;

1329 1330
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1331
                goto cleanup;
1332

1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6)) {
               virBufferAsprintf(&configbuf, "dhcp-range=%s,%s,%d\n",
                                 saddr, eaddr, prefix);
            } else {
                /* IPv4 - dnsmasq requires a netmask rather than prefix */
                virSocketAddr netmask;
                VIR_AUTOFREE(char *) netmaskStr = NULL;

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

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

1355
            VIR_FREE(saddr);
1356
            VIR_FREE(eaddr);
1357
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1358 1359
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1360
                                              virNetworkIPDefPrefix(ipdef));
1361 1362 1363
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1364
        }
1365

1366
        /*
1367 1368 1369 1370
         * 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)
1371 1372
         */
        if (!ipdef->nranges && ipdef->nhosts) {
1373
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
1374 1375
            if (!bridgeaddr)
                goto cleanup;
1376 1377 1378
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static",
                              bridgeaddr);
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1379
                virBufferAsprintf(&configbuf, ",%d", prefix);
1380
            virBufferAddLit(&configbuf, "\n");
1381 1382
            VIR_FREE(bridgeaddr);
        }
1383

G
Gene Czarcinski 已提交
1384 1385
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1386

G
Gene Czarcinski 已提交
1387 1388
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
1389
            if (ipdef->nranges || ipdef->nhosts) {
1390
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1391 1392
                virBufferAddLit(&configbuf, "dhcp-authoritative\n");
            }
1393

G
Gene Czarcinski 已提交
1394
            if (ipdef->tftproot) {
1395 1396
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1397
            }
1398

G
Gene Czarcinski 已提交
1399 1400 1401
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1402

1403
                    if (!bootserver)
G
Gene Czarcinski 已提交
1404
                        goto cleanup;
1405
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1406
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1407 1408
                    VIR_FREE(bootserver);
                } else {
1409
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1410 1411 1412 1413 1414
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1415

1416
    if (nbleases > 0)
1417
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1418

G
Gene Czarcinski 已提交
1419 1420
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1421
        goto cleanup;
G
Gene Czarcinski 已提交
1422 1423 1424 1425 1426 1427

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

1431 1432
    /* Likewise, always create this file and put it on the
     * commandline, to allow for runtime additions.
G
Gene Czarcinski 已提交
1433
     */
1434 1435 1436 1437
    if (wantDNS) {
        virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
                          dctx->addnhostsfile->path);
    }
G
Gene Czarcinski 已提交
1438

1439 1440 1441 1442
    /* 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 已提交
1443 1444
    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
1445
        if (ipv6def) {
1446
            virBufferAddLit(&configbuf, "enable-ra\n");
1447
        } else {
1448
            for (i = 0;
1449
                 (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1450
                 i++) {
G
Gene Czarcinski 已提交
1451 1452 1453 1454
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1455 1456
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1457 1458
                    VIR_FREE(bridgeaddr);
                }
1459
            }
1460
        }
1461 1462
    }

1463 1464 1465
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1466
    ret = 0;
G
Gene Czarcinski 已提交
1467

1468
 cleanup:
1469 1470
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1471
    virBufferFreeAndReset(&configbuf);
1472
    return ret;
1473 1474
}

1475

1476
/* build the dnsmasq command line */
1477 1478
static int ATTRIBUTE_NONNULL(3)
networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
1479
                                  virNetworkObjPtr obj,
1480
                                  virCommandPtr *cmdout,
1481 1482
                                  char *pidfile,
                                  dnsmasqContext *dctx)
1483
{
1484
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1485
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1486
    virCommandPtr cmd = NULL;
G
Gene Czarcinski 已提交
1487
    int ret = -1;
1488 1489
    char *configfile = NULL;
    char *configstr = NULL;
1490
    char *leaseshelper_path = NULL;
1491

1492
    virNetworkObjSetDnsmasqPid(obj, -1);
1493

1494
    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
1495
                                   dctx, dnsmasq_caps) < 0)
1496 1497 1498 1499 1500
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1501
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
1502 1503 1504 1505 1506
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1507 1508
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1509 1510 1511
        goto cleanup;
    }

1512 1513
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1514
                                                  abs_top_builddir "/src",
1515 1516 1517
                                                  LIBEXECDIR)))
        goto cleanup;

1518
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1519
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1520 1521
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1522
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1523
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", def->bridge);
1524

1525
    *cmdout = cmd;
1526
    ret = 0;
1527
 cleanup:
1528
    virObjectUnref(dnsmasq_caps);
1529 1530
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1531
    VIR_FREE(leaseshelper_path);
1532 1533 1534
    return ret;
}

1535

1536
static int
1537
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1538
                       virNetworkObjPtr obj)
1539
{
1540
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1541 1542 1543
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1544 1545
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
1546
    pid_t dnsmasqPid;
1547
    int ret = -1;
1548
    dnsmasqContext *dctx = NULL;
1549

1550
    /* see if there are any IP addresses that need a dhcp server */
1551
    i = 0;
1552
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i))) {
1553
        i++;
1554 1555 1556 1557
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1558 1559 1560 1561 1562 1563
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1564
    if (!needDnsmasq && def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1565
        /* no DHCP services needed, and user disabled DNS service */
1566 1567 1568 1569
        ret = 0;
        goto cleanup;
    }

1570
    if (virFileMakePath(driver->pidDir) < 0) {
1571
        virReportSystemError(errno,
1572
                             _("cannot create directory %s"),
1573
                             driver->pidDir);
1574
        goto cleanup;
1575 1576
    }

1577
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, def->name)))
1578
        goto cleanup;
1579

1580
    if (virFileMakePath(driver->dnsmasqStateDir) < 0) {
1581
        virReportSystemError(errno,
1582
                             _("cannot create directory %s"),
1583
                             driver->dnsmasqStateDir);
1584 1585 1586
        goto cleanup;
    }

1587
    dctx = dnsmasqContextNew(def->name, driver->dnsmasqStateDir);
1588 1589 1590
    if (dctx == NULL)
        goto cleanup;

1591
    if (networkDnsmasqCapsRefresh(driver) < 0)
1592
        goto cleanup;
1593

1594
    ret = networkBuildDhcpDaemonCommandLine(driver, obj, &cmd, pidfile, dctx);
1595 1596 1597 1598 1599
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1600
        goto cleanup;
1601

G
Guido Günther 已提交
1602
    ret = virCommandRun(cmd, NULL);
1603
    if (ret < 0)
1604 1605 1606
        goto cleanup;

    /*
1607 1608 1609 1610 1611
     * 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
1612 1613
     */

1614
    ret = virPidFileRead(driver->pidDir, def->name, &dnsmasqPid);
1615
    if (ret < 0)
1616
        goto cleanup;
1617
    virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
1618

1619
    ret = 0;
1620
 cleanup:
1621
    VIR_FREE(pidfile);
1622
    virCommandFree(cmd);
1623
    dnsmasqContextFree(dctx);
1624 1625 1626
    return ret;
}

1627

1628 1629
/* networkRefreshDhcpDaemon:
 *  Update dnsmasq config files, then send a SIGHUP so that it rereads
G
Gene Czarcinski 已提交
1630 1631
 *  them.   This only works for the dhcp-hostsfile and the
 *  addn-hosts file.
1632 1633 1634
 *
 *  Returns 0 on success, -1 on failure.
 */
1635
static int
1636
networkRefreshDhcpDaemon(virNetworkDriverStatePtr driver,
1637
                         virNetworkObjPtr obj)
1638
{
1639
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1640 1641
    int ret = -1;
    size_t i;
1642
    pid_t dnsmasqPid;
1643
    virNetworkIPDefPtr ipdef, ipv4def, ipv6def;
1644
    dnsmasqContext *dctx = NULL;
1645

G
Gene Czarcinski 已提交
1646
    /* if no IP addresses specified, nothing to do */
1647
    if (!virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1648 1649
        return 0;

1650
    /* if there's no running dnsmasq, just start it */
1651 1652
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid <= 0 || (kill(dnsmasqPid, 0) < 0))
1653
        return networkStartDhcpDaemon(driver, obj);
1654

1655 1656
    VIR_INFO("Refreshing dnsmasq for network %s", def->bridge);
    if (!(dctx = dnsmasqContextNew(def->name,
1657
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1658
        goto cleanup;
1659
    }
G
Gene Czarcinski 已提交
1660 1661 1662 1663 1664 1665

    /* 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;
1666
    for (i = 0;
1667
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
1668
         i++) {
G
Gene Czarcinski 已提交
1669 1670
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1671 1672
    }

G
Gene Czarcinski 已提交
1673
    ipv6def = NULL;
1674
    for (i = 0;
1675
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1676
         i++) {
G
Gene Czarcinski 已提交
1677 1678
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1679 1680
    }

G
Gene Czarcinski 已提交
1681
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1682
        goto cleanup;
G
Gene Czarcinski 已提交
1683 1684

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

1687
    if (networkBuildDnsmasqHostsList(dctx, &def->dns) < 0)
J
Ján Tomko 已提交
1688
        goto cleanup;
1689 1690

    if ((ret = dnsmasqSave(dctx)) < 0)
1691
        goto cleanup;
1692

1693 1694
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    ret = kill(dnsmasqPid, SIGHUP);
1695
 cleanup:
1696 1697 1698 1699
    dnsmasqContextFree(dctx);
    return ret;
}

1700

1701 1702 1703 1704 1705 1706 1707 1708
/* 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
1709
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1710
                         virNetworkObjPtr obj)
1711
{
1712
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1713 1714
    pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);

1715
    /* if there is a running dnsmasq, kill it */
1716
    if (dnsmasqPid > 0) {
1717
        networkKillDaemon(dnsmasqPid, "dnsmasq", def->name);
1718
        virNetworkObjSetDnsmasqPid(obj, -1);
1719
    }
1720
    /* now start dnsmasq if it should be started */
1721
    return networkStartDhcpDaemon(driver, obj);
1722 1723
}

1724

G
Gene Czarcinski 已提交
1725 1726 1727 1728 1729 1730
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";

1731
static int
1732
networkRadvdConfContents(virNetworkObjPtr obj,
1733
                         char **configstr)
1734
{
1735
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
E
Eric Blake 已提交
1736
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1737 1738
    int ret = -1;
    size_t i;
1739
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1740
    bool v6present = false, dhcp6 = false;
1741 1742

    *configstr = NULL;
1743

G
Gene Czarcinski 已提交
1744
    /* Check if DHCPv6 is needed */
1745
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
G
Gene Czarcinski 已提交
1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
        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;
    }

1759 1760 1761
    /* create radvd config file appropriate for this network;
     * IgnoreIfMissing allows radvd to start even when the bridge is down
     */
1762
    virBufferAsprintf(&configbuf, "interface %s\n"
1763 1764
                      "{\n"
                      "  AdvSendAdvert on;\n"
1765
                      "  IgnoreIfMissing on;\n"
G
Gene Czarcinski 已提交
1766 1767
                      "  AdvManagedFlag %s;\n"
                      "%s",
1768
                      def->bridge,
G
Gene Czarcinski 已提交
1769 1770
                      dhcp6 ? "on" : "off",
                      dhcp6 ? "\n" : radvd1);
1771 1772

    /* add a section for each IPv6 address in the config */
1773
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
1774 1775 1776
        int prefix;
        char *netaddr;

1777
        prefix = virNetworkIPDefPrefix(ipdef);
1778
        if (prefix < 0) {
1779 1780
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1781
                           def->bridge);
1782 1783
            goto cleanup;
        }
1784
        if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
1785
            goto cleanup;
1786
        virBufferAsprintf(&configbuf,
1787
                          "  prefix %s/%d\n"
G
Gene Czarcinski 已提交
1788 1789 1790
                          "  {\n%s  };\n",
                          netaddr, prefix,
                          dhcp6 ? radvd2 : radvd3);
1791 1792 1793
        VIR_FREE(netaddr);
    }

1794
    virBufferAddLit(&configbuf, "};\n");
1795

1796
    if (virBufferCheckError(&configbuf) < 0)
1797
        goto cleanup;
1798

1799 1800
    *configstr = virBufferContentAndReset(&configbuf);

1801
    ret = 0;
1802
 cleanup:
1803 1804 1805 1806
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1807

1808
/* write file and return its name (which must be freed by caller) */
1809
static int
1810
networkRadvdConfWrite(virNetworkDriverStatePtr driver,
1811
                      virNetworkObjPtr obj,
1812
                      char **configFile)
1813
{
1814
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1815 1816 1817 1818 1819 1820 1821 1822 1823
    int ret = -1;
    char *configStr = NULL;
    char *myConfigFile = NULL;

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

1824
    if (networkRadvdConfContents(obj, &configStr) < 0)
1825 1826 1827 1828
        goto cleanup;

    if (!configStr) {
        ret = 0;
1829 1830 1831 1832
        goto cleanup;
    }

    /* construct the filename */
1833
    if (!(*configFile = networkRadvdConfigFileName(driver, def->name)))
1834 1835
        goto cleanup;
    /* write the file */
1836
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1837 1838
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1839 1840 1841 1842 1843
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1844
 cleanup:
1845 1846 1847 1848 1849
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

1850

1851
static int
1852
networkStartRadvd(virNetworkDriverStatePtr driver,
1853
                  virNetworkObjPtr obj)
1854
{
1855
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1856
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1857
    pid_t radvdPid;
1858 1859 1860 1861 1862 1863
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

1864
    virNetworkObjSetRadvdPid(obj, -1);
1865

G
Gene Czarcinski 已提交
1866
    /* Is dnsmasq handling RA? */
1867
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
1868 1869 1870 1871
        ret = 0;
        goto cleanup;
    }

1872
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
        /* 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);
1883 1884 1885
        goto cleanup;
    }

1886
    if (virFileMakePath(driver->pidDir) < 0) {
1887 1888
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1889
                             driver->pidDir);
1890 1891
        goto cleanup;
    }
1892
    if (virFileMakePath(driver->radvdStateDir) < 0) {
1893 1894
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1895
                             driver->radvdStateDir);
1896 1897 1898 1899
        goto cleanup;
    }

    /* construct pidfile name */
1900
    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
1901
        goto cleanup;
1902
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
1903 1904
        goto cleanup;

1905
    if (networkRadvdConfWrite(driver, obj, &configfile) < 0)
1906 1907
        goto cleanup;

1908 1909 1910 1911
    /* 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
1912
     * virPidFileRead() below will fail if we use them).
1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927
     * 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;

1928
    if (virPidFileRead(driver->pidDir, radvdpidbase, &radvdPid) < 0)
1929
        goto cleanup;
1930
    virNetworkObjSetRadvdPid(obj, radvdPid);
1931 1932

    ret = 0;
1933
 cleanup:
1934
    virObjectUnref(dnsmasq_caps);
1935 1936 1937 1938 1939 1940 1941
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

1942

1943
static int
1944
networkRefreshRadvd(virNetworkDriverStatePtr driver,
1945
                    virNetworkObjPtr obj)
1946
{
1947
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1948
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
1949
    char *radvdpidbase;
1950
    pid_t radvdPid;
G
Gene Czarcinski 已提交
1951 1952

    /* Is dnsmasq handling RA? */
1953 1954
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
        virObjectUnref(dnsmasq_caps);
1955 1956
        radvdPid = virNetworkObjGetRadvdPid(obj);
        if (radvdPid <= 0)
G
Gene Czarcinski 已提交
1957 1958
            return 0;
        /* radvd should not be running but in case it is */
1959 1960
        if ((networkKillDaemon(radvdPid, "radvd", def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(def->name))
G
Gene Czarcinski 已提交
1961
             != NULL)) {
1962
            virPidFileDelete(driver->pidDir, radvdpidbase);
G
Gene Czarcinski 已提交
1963 1964
            VIR_FREE(radvdpidbase);
        }
1965
        virNetworkObjSetRadvdPid(obj, -1);
G
Gene Czarcinski 已提交
1966 1967
        return 0;
    }
1968
    virObjectUnref(dnsmasq_caps);
G
Gene Czarcinski 已提交
1969

1970
    /* if there's no running radvd, just start it */
1971 1972
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid <= 0 || (kill(radvdPid, 0) < 0))
1973
        return networkStartRadvd(driver, obj);
1974

1975
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
1976 1977 1978 1979
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

1980
    if (networkRadvdConfWrite(driver, obj, NULL) < 0)
1981 1982
        return -1;

1983
    return kill(radvdPid, SIGHUP);
1984 1985
}

1986

1987 1988
#if 0
/* currently unused, so it causes a build error unless we #if it out */
1989
static int
1990
networkRestartRadvd(virNetworkObjPtr obj)
1991
{
1992
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1993
    char *radvdpidbase;
1994
    pid_t radvdPid = virNeworkObjGetRadvdPid(obj);
1995 1996

    /* if there is a running radvd, kill it */
1997
    if (radvdPid > 0) {
1998 1999 2000 2001
        /* 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).
         */
2002 2003
        if ((networkKillDaemon(radvdPid, "radvd", def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(def->name))
2004
             != NULL)) {
2005
            virPidFileDelete(driver->pidDir, radvdpidbase);
2006 2007
            VIR_FREE(radvdpidbase);
        }
2008
        virNetworkObjSetRadvdPid(obj, -1);
2009 2010
    }
    /* now start radvd if it should be started */
2011
    return networkStartRadvd(obj);
2012 2013 2014
}
#endif /* #if 0 */

2015

2016
static int
2017
networkRefreshDaemonsHelper(virNetworkObjPtr obj,
2018
                            void *opaque)
2019
{
2020
    virNetworkDefPtr def;
2021
    virNetworkDriverStatePtr driver = opaque;
2022

2023
    virObjectLock(obj);
2024
    def = virNetworkObjGetDef(obj);
2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
    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;
        }
2053
    }
2054 2055

 cleanup:
2056
    virObjectUnlock(obj);
2057 2058 2059
    return 0;
}

2060

2061 2062 2063 2064
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2065
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2066 2067
{
    VIR_INFO("Refreshing network daemons");
2068 2069
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2070
                             driver);
2071
}
2072

2073

2074
static int
2075
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
2076 2077
                                 void *opaque ATTRIBUTE_UNUSED)
{
2078
    virNetworkDefPtr def;
2079

2080
    virObjectLock(obj);
2081
    def = virNetworkObjGetDef(obj);
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107
    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;
2108 2109
        }
    }
2110 2111

 cleanup:
2112
    virObjectUnlock(obj);
2113
    return 0;
2114 2115
}

2116

2117
static void
2118
networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup)
2119
{
2120
    VIR_INFO("Reloading iptables rules");
2121 2122 2123 2124
    /* 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;
2125
    networkPreReloadFirewallRules(startup);
2126 2127 2128
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2129
    networkPostReloadFirewallRules(startup);
2130 2131
}

2132

2133
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
2134
static int
2135 2136
networkEnableIPForwarding(bool enableIPv4,
                          bool enableIPv6)
2137
{
2138
    int ret = 0;
2139 2140 2141 2142
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
2143
                           &enabled, sizeof(enabled));
2144 2145
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
2146
                           &enabled, sizeof(enabled));
2147
#else
2148
    if (enableIPv4)
2149
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv4/ip_forward", "1\n", 0);
2150
    if (enableIPv6 && ret == 0)
2151 2152
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv6/conf/all/forwarding", "1\n", 0);

2153
#endif
2154
    return ret;
2155 2156
}

2157

2158
static int
2159
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2160
{
2161
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2162 2163
    char *field = NULL;
    int ret = -1;
2164
    bool enableIPv6 = !!virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2165

2166 2167 2168 2169 2170
    /* set disable_ipv6 if there are no ipv6 addresses defined for the
     * network. But also unset it if there *are* ipv6 addresses, as we
     * can't be sure of its default value.
     */
    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/disable_ipv6",
2171
                    def->bridge) < 0)
2172
       goto cleanup;
2173

2174 2175
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2176
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2177
                      def->bridge);
2178 2179 2180
        ret = 0;
        goto cleanup;
    }
2181

2182 2183 2184
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2185
                               "on bridge %s"), field, def->bridge);
2186
        goto cleanup;
2187
    }
2188
    VIR_FREE(field);
2189

2190 2191
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2192 2193 2194 2195 2196 2197
     */

    /* Prevent guests from hijacking the host network by sending out
     * their own router advertisements.
     */
    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/accept_ra",
2198
                    def->bridge) < 0)
2199 2200
        goto cleanup;

2201
    if (virFileWriteStr(field, "0", 0) < 0) {
2202
        virReportSystemError(errno,
2203 2204 2205 2206 2207
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

2208 2209 2210 2211
    /* All interfaces used as a gateway (which is what this is, by
     * definition), must always have autoconf=0.
     */
    if (virAsprintf(&field, SYSCTL_PATH "/net/ipv6/conf/%s/autoconf",
2212
                    def->bridge) < 0)
2213 2214
        goto cleanup;

2215
    if (virFileWriteStr(field, "0", 0) < 0) {
2216
        virReportSystemError(errno,
2217
                             _("cannot disable %s"), field);
2218 2219 2220 2221
        goto cleanup;
    }

    ret = 0;
2222
 cleanup:
2223 2224 2225 2226
    VIR_FREE(field);
    return ret;
}

2227

2228
/* add an IP address to a bridge */
2229
static int
2230
networkAddAddrToBridge(virNetworkObjPtr obj,
2231
                       virNetworkIPDefPtr ipdef)
2232
{
2233
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2234
    int prefix = virNetworkIPDefPrefix(ipdef);
2235 2236

    if (prefix < 0) {
2237 2238
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2239
                       def->bridge);
2240 2241 2242
        return -1;
    }

2243
    if (virNetDevIPAddrAdd(def->bridge, &ipdef->address, NULL, prefix) < 0)
2244 2245 2246 2247 2248
        return -1;

    return 0;
}

2249 2250

static int
2251
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2252 2253
                                      const char *macTapIfName)
{
2254 2255
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    const char *brname = def->bridge;
2256 2257

    if (brname &&
2258
        def->macTableManager == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271
        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;
}


2272 2273
/* add an IP (static) route to a bridge */
static int
2274
networkAddRouteToBridge(virNetworkObjPtr obj,
2275
                        virNetDevIPRoutePtr routedef)
2276
{
2277
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2278 2279 2280 2281
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2282 2283 2284 2285 2286

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

2291
    if (virNetDevIPRouteAdd(def->bridge, addr, prefix, gateway, metric) < 0)
2292
        return -1;
2293

2294 2295 2296
    return 0;
}

2297
static int
2298
networkWaitDadFinish(virNetworkObjPtr obj)
2299
{
2300
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2301
    virNetworkIPDefPtr ipdef;
2302 2303 2304 2305
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

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

2308
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, naddrs))) {
2309 2310 2311 2312 2313
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2314
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2315 2316 2317 2318

 cleanup:
    VIR_FREE(addrs);
    VIR_DEBUG("Finished waiting for IPv6 DAD on network %s with status %d",
2319
              def->name, ret);
2320 2321 2322
    return ret;
}

2323

2324
static int
2325
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
2326
                           virNetworkObjPtr obj)
2327
{
2328
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2329
    size_t i;
2330
    bool v4present = false, v6present = false;
2331
    virErrorPtr save_err = NULL;
2332
    virNetworkIPDefPtr ipdef;
2333
    virNetDevIPRoutePtr routedef;
2334
    char *macTapIfName = NULL;
2335
    virMacMapPtr macmap;
M
Michal Privoznik 已提交
2336
    char *macMapFile = NULL;
2337
    int tapfd = -1;
2338
    pid_t dnsmasqPid;
2339

2340
    /* Check to see if any network IP collides with an existing route */
2341
    if (networkCheckRouteCollision(def) < 0)
2342 2343
        return -1;

2344
    /* Create and configure the bridge device */
2345
    if (!def->bridge) {
2346 2347 2348 2349 2350 2351 2352 2353 2354 2355
        /* 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"),
2356
                       def->name);
2357 2358
        return -1;
    }
2359
    if (virNetDevBridgeCreate(def->bridge) < 0)
2360 2361
        return -1;

2362
    if (def->mac_specified) {
2363 2364 2365 2366 2367 2368
        /* 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.
         */
2369
        macTapIfName = networkBridgeDummyNicName(def->bridge);
2370
        if (!macTapIfName)
2371
            goto err0;
2372
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2373 2374
        if (virNetDevTapCreateInBridgePort(def->bridge,
                                           &macTapIfName, &def->mac,
2375
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2376
                                           NULL, def->mtu, NULL,
2377 2378 2379
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2380 2381 2382 2383 2384
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

2385
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
2386
                                         def->bridge)) ||
2387
        !(macmap = virMacMapNew(macMapFile)))
M
Michal Privoznik 已提交
2388 2389
        goto err1;

2390
    virNetworkObjSetMacMap(obj, macmap);
2391
    macmap = NULL;
2392

2393
    /* Set bridge options */
2394 2395 2396 2397

    /* delay is configured in seconds, but virNetDevBridgeSetSTPDelay
     * expects milliseconds
     */
2398
    if (virNetDevBridgeSetSTPDelay(def->bridge, def->delay * 1000) < 0)
2399
        goto err1;
2400

2401
    if (virNetDevBridgeSetSTP(def->bridge, def->stp ? true : false) < 0)
2402
        goto err1;
2403

2404 2405 2406
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2407
    if (networkSetIPv6Sysctls(obj) < 0)
2408
        goto err1;
2409

2410
    /* Add "once per network" rules */
2411 2412
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(def) < 0)
2413 2414
        goto err1;

2415
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i)); i++) {
2416
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2417
            v4present = true;
2418
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2419
            v6present = true;
2420

2421
        /* Add the IP address/netmask to the bridge */
2422
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2423
            goto err2;
2424 2425
    }

2426
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2427 2428
        goto err2;

2429
    /* Bring up the bridge interface */
2430
    if (virNetDevSetOnline(def->bridge, 1) < 0)
2431
        goto err2;
2432

2433
    for (i = 0; i < def->nroutes; i++) {
2434 2435
        virSocketAddrPtr gateway = NULL;

2436
        routedef = def->routes[i];
2437
        gateway = virNetDevIPRouteGetGateway(routedef);
2438

2439 2440 2441
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2442
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2443
            if (networkAddRouteToBridge(obj, routedef) < 0) {
2444 2445 2446 2447 2448 2449
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2450
    /* If forward.type != NONE, turn on global IP forwarding */
2451
    if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2452
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2453 2454 2455 2456 2457 2458 2459
            goto err3; /* Precise error message already provided */

        if (networkEnableIPForwarding(v4present, v6present) < 0) {
            virReportSystemError(errno, "%s",
                                 _("failed to enable IP forwarding"));
            goto err3;
        }
2460 2461
    }

2462

2463
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2464
    if ((v4present || v6present) &&
2465
        networkStartDhcpDaemon(driver, obj) < 0)
2466
        goto err3;
2467

2468
    /* start radvd if there are any ipv6 addresses */
2469
    if (v6present && networkStartRadvd(driver, obj) < 0)
2470 2471
        goto err4;

2472 2473 2474
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2475
    if (v6present && networkWaitDadFinish(obj) < 0)
2476 2477 2478 2479
        goto err4;

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2480 2481 2482 2483 2484 2485 2486
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
            goto err4;
        VIR_FORCE_CLOSE(tapfd);
    }

2487
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
2488 2489
        goto err5;

2490
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2491
    VIR_FREE(macMapFile);
2492 2493 2494

    return 0;

2495
 err5:
2496 2497
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
2498

2499 2500
 err4:
    if (!save_err)
2501
        virErrorPreserveLast(&save_err);
2502

2503 2504 2505 2506
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0) {
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2507 2508
    }

2509 2510
 err3:
    if (!save_err)
2511
        virErrorPreserveLast(&save_err);
2512
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2513

2514 2515
 err2:
    if (!save_err)
2516
        virErrorPreserveLast(&save_err);
2517 2518
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2519 2520

 err1:
2521
    if (!save_err)
2522
        virErrorPreserveLast(&save_err);
2523

H
Hu Tao 已提交
2524
    if (macTapIfName) {
2525
        VIR_FORCE_CLOSE(tapfd);
2526
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2527 2528
        VIR_FREE(macTapIfName);
    }
2529
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2530
    VIR_FREE(macMapFile);
2531 2532

 err0:
2533
    if (!save_err)
2534
        virErrorPreserveLast(&save_err);
2535
    ignore_value(virNetDevBridgeDelete(def->bridge));
2536

2537
    virErrorRestore(&save_err);
2538
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2539 2540 2541
    return -1;
}

2542

2543 2544
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2545
                              virNetworkObjPtr obj)
2546
{
2547
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2548 2549 2550
    pid_t radvdPid;
    pid_t dnsmasqPid;

2551 2552
    if (def->bandwidth)
        virNetDevBandwidthClear(def->bridge);
2553

2554
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2555

2556 2557
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2558 2559
        char *radvdpidbase;

2560
        kill(radvdPid, SIGTERM);
2561
        /* attempt to delete the pidfile we created */
2562
        if ((radvdpidbase = networkRadvdPidfileBasename(def->name))) {
2563
            virPidFileDelete(driver->pidDir, radvdpidbase);
2564 2565 2566 2567
            VIR_FREE(radvdpidbase);
        }
    }

2568 2569 2570
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2571

2572 2573
    if (def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(def->bridge);
2574
        if (macTapIfName) {
2575
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2576 2577 2578 2579
            VIR_FREE(macTapIfName);
        }
    }

2580
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2581

2582 2583
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2584

2585
    ignore_value(virNetDevBridgeDelete(def->bridge));
2586

2587
    /* See if its still alive and really really kill it */
2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598
    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);
2599

2600 2601 2602
    return 0;
}

2603

2604
static int
2605
networkStartNetworkBridge(virNetworkObjPtr obj)
2606 2607 2608 2609 2610
{
    /* 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.
     */
2611
    return networkStartHandleMACTableManagerMode(obj, NULL);
2612 2613
}

2614

2615
static int
2616
networkShutdownNetworkBridge(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2617 2618 2619 2620 2621 2622 2623 2624 2625
{
    /* put anything here that needs to be done each time a network of
     * type BRIDGE is shutdown. On failure, undo anything you've done,
     * and return -1. On success return 0.
     */
    return 0;
}


2626 2627 2628 2629 2630 2631 2632 2633 2634
/* 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;
2635
    unsigned int maxVirtFns = 0;
2636 2637 2638 2639 2640 2641
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2642 2643 2644
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2645 2646
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661
        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];

2662
        switch ((virNetworkForwardType) netdef->forward.type) {
2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692
        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
            if (thisName) {
                if (VIR_STRDUP(thisIf->device.dev, thisName) < 0)
                    goto cleanup;
                thisIf->type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
                netdef->forward.nifs++;
            } else {
                VIR_WARN("VF %zu of SRIOV PF %s couldn't be added to the "
                         "interface pool because it isn't bound "
                         "to a network driver - possibly in use elsewhere",
                         i, netdef->forward.pfs->dev);
            }
            break;

        case VIR_NETWORK_FORWARD_HOSTDEV:
            /* VF's are always PCI devices */
            thisIf->type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI;
            thisIf->device.pci.domain = thisVirtFn->domain;
            thisIf->device.pci.bus = thisVirtFn->bus;
            thisIf->device.pci.slot = thisVirtFn->slot;
            thisIf->device.pci.function = thisVirtFn->function;
            netdef->forward.nifs++;
            break;

        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
2693
        case VIR_NETWORK_FORWARD_OPEN:
2694 2695
            /* by definition these will never be encountered here */
            break;
2696 2697 2698 2699 2700

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
            goto cleanup;
2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737
        }
    }

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


2738
static int
2739
networkStartNetworkExternal(virNetworkObjPtr obj)
2740 2741
{
    /* put anything here that needs to be done each time a network of
2742
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2743 2744 2745
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2746
    return networkCreateInterfacePool(virNetworkObjGetDef(obj));
2747 2748
}

2749 2750

static int
2751
networkShutdownNetworkExternal(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2752 2753
{
    /* put anything here that needs to be done each time a network of
2754
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2755 2756 2757 2758 2759 2760
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2761

2762
static int
2763
networkStartNetwork(virNetworkDriverStatePtr driver,
2764
                    virNetworkObjPtr obj)
2765
{
2766
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2767 2768
    int ret = -1;

2769
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2770

2771
    if (virNetworkObjIsActive(obj)) {
2772 2773
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2774
        return ret;
2775 2776
    }

2777 2778 2779
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2780
    if (virNetworkObjSetDefTransient(obj, true) < 0)
2781
        goto cleanup;
2782

2783 2784
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2785
    if (networkRunHook(obj, NULL, NULL,
2786 2787 2788 2789
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2790
    switch ((virNetworkForwardType) def->forward.type) {
2791 2792 2793 2794

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2795
    case VIR_NETWORK_FORWARD_OPEN:
2796
        if (networkStartNetworkVirtual(driver, obj) < 0)
2797
            goto cleanup;
2798 2799 2800
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2801
        if (def->bridge) {
2802
            if (networkStartNetworkBridge(obj) < 0)
2803 2804 2805 2806 2807 2808 2809
                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).
         */
2810 2811
        ATTRIBUTE_FALLTHROUGH;

2812 2813 2814
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2815
    case VIR_NETWORK_FORWARD_HOSTDEV:
2816
        if (networkStartNetworkExternal(obj) < 0)
2817
            goto cleanup;
2818
        break;
2819 2820 2821 2822 2823

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

2826 2827
    virNetworkObjSetFloorSum(obj, 0);

2828
    /* finally we can call the 'started' hook script if any */
2829
    if (networkRunHook(obj, NULL, NULL,
2830 2831 2832 2833
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2834 2835 2836
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2837
    VIR_DEBUG("Writing network status to disk");
2838
    if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0)
2839
        goto cleanup;
2840

2841
    virNetworkObjSetActive(obj, true);
2842
    VIR_INFO("Network '%s' started up", def->name);
2843
    ret = 0;
2844

2845
 cleanup:
2846
    if (ret < 0) {
2847
        virNetworkObjUnsetDefTransient(obj);
2848 2849
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
2850
        networkShutdownNetwork(driver, obj);
2851 2852 2853 2854 2855 2856 2857
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2858

2859 2860
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
2861
                       virNetworkObjPtr obj)
2862
{
2863
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2864 2865 2866
    int ret = 0;
    char *stateFile;

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

2869
    if (!virNetworkObjIsActive(obj))
2870 2871
        return 0;

2872
    stateFile = virNetworkConfigFile(driver->stateDir, def->name);
2873 2874 2875 2876 2877 2878
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2879
    switch ((virNetworkForwardType) def->forward.type) {
2880 2881 2882 2883

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2884
    case VIR_NETWORK_FORWARD_OPEN:
2885
        ret = networkShutdownNetworkVirtual(driver, obj);
2886 2887 2888
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2889
        if (def->bridge) {
2890
            ret = networkShutdownNetworkBridge(obj);
2891 2892 2893 2894 2895 2896
            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).
         */
2897 2898
        ATTRIBUTE_FALLTHROUGH;

2899 2900 2901
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2902
    case VIR_NETWORK_FORWARD_HOSTDEV:
2903
        ret = networkShutdownNetworkExternal(obj);
2904
        break;
2905 2906 2907 2908 2909

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

2912
    /* now that we know it's stopped call the hook if present */
2913
    networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2914 2915
                   VIR_HOOK_SUBOP_END);

2916
    virNetworkObjSetActive(obj, false);
2917
    virNetworkObjUnsetDefTransient(obj);
2918
    return ret;
2919 2920 2921
}


2922 2923 2924
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
2925
{
2926
    virNetworkDriverStatePtr driver = networkGetDriver();
2927
    virNetworkObjPtr obj;
2928
    virNetworkDefPtr def;
2929
    virNetworkPtr net = NULL;
2930

2931 2932
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
2933 2934
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
2935
        virReportError(VIR_ERR_NO_NETWORK,
2936 2937
                       _("no network with matching uuid '%s'"),
                       uuidstr);
2938
        goto cleanup;
2939
    }
2940
    def = virNetworkObjGetDef(obj);
2941

2942
    if (virNetworkLookupByUUIDEnsureACL(conn, def) < 0)
2943 2944
        goto cleanup;

2945
    net = virGetNetwork(conn, def->name, def->uuid);
2946

2947
 cleanup:
2948 2949
    virNetworkObjEndAPI(&obj);
    return net;
2950 2951
}

2952 2953 2954 2955

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
2956
{
2957
    virNetworkDriverStatePtr driver = networkGetDriver();
2958
    virNetworkObjPtr obj;
2959
    virNetworkDefPtr def;
2960
    virNetworkPtr net = NULL;
2961

2962 2963
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
2964 2965
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
2966
        goto cleanup;
2967
    }
2968
    def = virNetworkObjGetDef(obj);
2969

2970
    if (virNetworkLookupByNameEnsureACL(conn, def) < 0)
2971 2972
        goto cleanup;

2973
    net = virGetNetwork(conn, def->name, def->uuid);
2974

2975
 cleanup:
2976 2977
    virNetworkObjEndAPI(&obj);
    return net;
2978 2979
}

2980 2981 2982

static int
networkConnectNumOfNetworks(virConnectPtr conn)
2983
{
2984
    virNetworkDriverStatePtr driver = networkGetDriver();
2985
    int nactive;
2986

2987 2988 2989
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

2990 2991 2992 2993
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
2994

2995 2996 2997
    return nactive;
}

2998 2999 3000 3001

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
3002
                           int maxnames)
3003 3004
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3005
    int got = 0;
3006

3007 3008 3009
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

3010
    got = virNetworkObjListGetNames(driver->networks,
3011
                                    true, names, maxnames,
3012 3013
                                    virConnectListNetworksCheckACL,
                                    conn);
3014

3015 3016 3017
    return got;
}

3018 3019 3020

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
3021
{
3022
    virNetworkDriverStatePtr driver = networkGetDriver();
3023
    int ninactive = 0;
3024

3025 3026 3027
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3028 3029 3030 3031
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
3032

3033 3034 3035
    return ninactive;
}

3036 3037 3038 3039

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
3040
                                  int maxnames)
3041 3042
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3043
    int got = 0;
3044

3045 3046 3047
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3048
    got = virNetworkObjListGetNames(driver->networks,
3049
                                    false, names, maxnames,
3050 3051
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
3052 3053 3054
    return got;
}

3055

3056
static int
3057 3058 3059
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
3060
{
3061
    virNetworkDriverStatePtr driver = networkGetDriver();
3062 3063 3064 3065
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

3066 3067 3068
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

3069
    ret = virNetworkObjListExport(conn, driver->networks, nets,
3070 3071
                                  virConnectListAllNetworksCheckACL,
                                  flags);
3072

3073
 cleanup:
3074 3075
    return ret;
}
3076

3077

3078 3079 3080 3081 3082 3083 3084 3085
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3086
    virNetworkDriverStatePtr driver = networkGetDriver();
3087 3088 3089 3090 3091 3092
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3093
                                       net, eventID, callback,
3094 3095 3096
                                       opaque, freecb, &ret) < 0)
        ret = -1;

3097
 cleanup:
3098 3099 3100
    return ret;
}

3101

3102 3103 3104 3105
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3106
    virNetworkDriverStatePtr driver = networkGetDriver();
3107 3108 3109 3110 3111
    int ret = -1;

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

3112 3113
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3114
                                        callbackID, true) < 0)
3115 3116 3117
        goto cleanup;

    ret = 0;
3118

3119
 cleanup:
3120 3121 3122
    return ret;
}

3123 3124 3125

static int
networkIsActive(virNetworkPtr net)
3126 3127 3128 3129
{
    virNetworkObjPtr obj;
    int ret = -1;

3130 3131
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3132

3133
    if (virNetworkIsActiveEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3134 3135
        goto cleanup;

3136 3137
    ret = virNetworkObjIsActive(obj);

3138
 cleanup:
3139
    virNetworkObjEndAPI(&obj);
3140 3141 3142
    return ret;
}

3143 3144 3145

static int
networkIsPersistent(virNetworkPtr net)
3146 3147 3148 3149
{
    virNetworkObjPtr obj;
    int ret = -1;

3150 3151
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3152

3153
    if (virNetworkIsPersistentEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3154 3155
        goto cleanup;

3156
    ret = virNetworkObjIsPersistent(obj);
3157

3158
 cleanup:
3159
    virNetworkObjEndAPI(&obj);
3160 3161 3162 3163
    return ret;
}


3164 3165
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
3166 3167 3168
 * 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.
3169 3170 3171 3172 3173 3174 3175
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{
    int ret = -1, id = 0;
    char *newname = NULL;
3176 3177 3178 3179 3180
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3181
        p && p[1] == 'd')
3182
        templ = def->bridge;
3183 3184 3185 3186

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3187 3188 3189 3190 3191
        /* 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).
         */
3192
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3193
              virNetDevExists(newname) == 1)) {
3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226
            VIR_FREE(def->bridge); /*could contain template */
            def->bridge = newname;
            ret = 0;
            goto cleanup;
        }
        VIR_FREE(newname);
    } while (++id <= MAX_BRIDGE_ID);

    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Bridge generation exceeded max id %d"),
                   MAX_BRIDGE_ID);
    ret = 0;
 cleanup:
    if (ret < 0)
        VIR_FREE(newname);
    return ret;
}


/*
 * networkValidateBridgeName() - if no bridge name is set, or if the
 * bridge name contains a %d (indicating that this is a template for
 * the actual name) try to set an appropriate bridge name.  If a
 * bridge name *is* set, make sure it doesn't conflict with any other
 * network's bridge name.
 */
static int
networkBridgeNameValidate(virNetworkObjListPtr nets,
                          virNetworkDefPtr def)
{
    int ret = -1;

    if (def->bridge && !strstr(def->bridge, "%d")) {
3227
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge name '%s' already in use."),
                           def->bridge);
            goto cleanup;
        }
    } else {
        /* Allocate a bridge name */
        if (networkFindUnusedBridgeName(nets, def) < 0)
            goto cleanup;
    }

    ret = 0;
 cleanup:
    return ret;
}


3245
static int
3246
networkValidate(virNetworkDriverStatePtr driver,
3247
                virNetworkDefPtr def)
3248
{
3249
    size_t i, j;
3250 3251
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3252
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3253
    bool ipv4def = false, ipv6def = false;
3254
    bool bandwidthAllowed = false;
3255
    bool usesInterface = false, usesAddress = false;
3256

3257 3258 3259
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3260 3261 3262
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3263 3264 3265 3266 3267
    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:
3268 3269 3270 3271
        /* 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)
3272 3273 3274
            return -1;

        virNetworkSetBridgeMacAddr(def);
3275
        bandwidthAllowed = true;
3276 3277 3278
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
3279 3280 3281 3282 3283
        if (def->bridge != NULL)
            bandwidthAllowed = true;

        ATTRIBUTE_FALLTHROUGH;

3284 3285 3286 3287
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
    case VIR_NETWORK_FORWARD_HOSTDEV:
3288
        /* They are also the only types that currently support setting
3289 3290
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
3291
         */
3292 3293 3294 3295 3296 3297 3298 3299
        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;
        }
3300
        if (virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0)) {
3301 3302 3303 3304
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3305
                           virNetworkForwardTypeToString(def->forward.type));
3306 3307
            return -1;
        }
3308
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
3309 3310 3311 3312
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3313
                           virNetworkForwardTypeToString(def->forward.type));
3314 3315 3316 3317 3318 3319 3320
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3321
                           virNetworkForwardTypeToString(def->forward.type));
3322 3323
            return -1;
        }
3324 3325 3326 3327 3328 3329
        break;

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

3332 3333 3334 3335 3336 3337 3338 3339 3340 3341
    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;
    }

3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354
    /* 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++) {
3355 3356 3357
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

3358
        switch ((virNetworkForwardHostdevDeviceType)iface->type) {
3359 3360
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371

            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;
            }
3372
            break;
3373 3374

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3375
            usesAddress = true;
3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400

            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);
3401
            break;
3402 3403
        }

3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416
        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 已提交
3417 3418 3419
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
3420
    for (i = 0;
3421
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
3422
         i++) {
G
Gene Czarcinski 已提交
3423 3424 3425 3426 3427
        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 -- "
3428 3429
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446
                    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;
                }
3447 3448 3449
            }
        }
    }
3450 3451 3452 3453 3454 3455

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

3456 3457 3458
    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 已提交
3459 3460
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3461
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3462 3463

    vlanUsed = def->vlan.nTags > 0;
3464 3465
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
3466 3467 3468 3469 3470
            /* 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.
             */
3471
            if (def->portGroups[i].virtPortProfile) {
3472
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
3473
                    def->portGroups[i].virtPortProfile->virtPortType
3474 3475 3476 3477 3478 3479 3480
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
3481
        }
3482
        if (def->portGroups[i].isDefault) {
3483 3484 3485 3486 3487
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
3488
                               def->name, defaultPortGroup->name,
3489
                               def->portGroups[i].name);
3490
                return -1;
3491
            }
3492
            defaultPortGroup = &def->portGroups[i];
3493
        }
3494 3495 3496 3497 3498 3499 3500 3501 3502
        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;
            }
        }
3503 3504 3505 3506 3507 3508 3509 3510
        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;
        }
3511
    }
3512 3513 3514 3515 3516 3517 3518
    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.
         */
3519 3520 3521 3522 3523 3524
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538

    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;
            }
        }
    }
3539 3540 3541
    return 0;
}

3542 3543 3544 3545

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3546
{
3547
    virNetworkDriverStatePtr driver = networkGetDriver();
3548
    virNetworkDefPtr newDef;
3549
    virNetworkObjPtr obj = NULL;
3550
    virNetworkDefPtr def;
3551
    virNetworkPtr net = NULL;
3552
    virObjectEventPtr event = NULL;
3553

3554
    if (!(newDef = virNetworkDefParseString(xml)))
3555
        goto cleanup;
3556

3557
    if (virNetworkCreateXMLEnsureACL(conn, newDef) < 0)
3558 3559
        goto cleanup;

3560
    if (networkValidate(driver, newDef) < 0)
J
Ján Tomko 已提交
3561
        goto cleanup;
3562

3563 3564 3565
    /* 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.
3566
     */
3567
    if (!(obj = virNetworkObjAssignDef(driver->networks, newDef,
3568 3569
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3570
        goto cleanup;
3571 3572
    newDef = NULL;
    def = virNetworkObjGetDef(obj);
3573

3574 3575
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3576
        goto cleanup;
3577 3578
    }

3579 3580
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3581 3582
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3583

3584 3585
    VIR_INFO("Creating network '%s'", def->name);
    net = virGetNetwork(conn, def->name, def->uuid);
3586

3587
 cleanup:
3588
    virNetworkDefFree(newDef);
3589
    virObjectEventStateQueue(driver->networkEventState, event);
3590 3591
    virNetworkObjEndAPI(&obj);
    return net;
3592 3593
}

3594 3595 3596 3597

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3598
{
3599
    virNetworkDriverStatePtr driver = networkGetDriver();
3600
    virNetworkDefPtr def = NULL;
3601
    bool freeDef = true;
3602 3603
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3604
    virObjectEventPtr event = NULL;
3605

3606
    if (!(def = virNetworkDefParseString(xml)))
3607
        goto cleanup;
3608

3609 3610 3611
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3612
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3613
        goto cleanup;
3614

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

3618
    /* def was assigned to network object */
3619
    freeDef = false;
3620 3621

    if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
3622 3623
        if (!virNetworkObjIsActive(obj)) {
            virNetworkObjRemoveInactive(driver->networks, obj);
3624 3625
            goto cleanup;
        }
3626 3627 3628 3629
        /* if network was active already, just undo new persistent
         * definition by making it transient.
         * XXX - this isn't necessarily the correct thing to do.
         */
3630
        virNetworkObjUpdateAssignDef(obj, NULL, false);
3631 3632 3633
        goto cleanup;
    }

3634
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3635 3636
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3637

3638
    VIR_INFO("Defining network '%s'", def->name);
3639
    net = virGetNetwork(conn, def->name, def->uuid);
3640

3641
 cleanup:
3642
    virObjectEventStateQueue(driver->networkEventState, event);
3643
    if (freeDef)
J
Ján Tomko 已提交
3644
        virNetworkDefFree(def);
3645 3646
    virNetworkObjEndAPI(&obj);
    return net;
3647 3648
}

3649

3650
static int
3651 3652
networkUndefine(virNetworkPtr net)
{
3653
    virNetworkDriverStatePtr driver = networkGetDriver();
3654
    virNetworkObjPtr obj;
3655
    virNetworkDefPtr def;
3656
    int ret = -1;
3657
    bool active = false;
3658
    virObjectEventPtr event = NULL;
3659

3660
    if (!(obj = networkObjFromNetwork(net)))
3661
        goto cleanup;
3662
    def = virNetworkObjGetDef(obj);
3663

3664
    if (virNetworkUndefineEnsureACL(net->conn, def) < 0)
3665 3666
        goto cleanup;

3667
    if (virNetworkObjIsActive(obj))
3668
        active = true;
3669

3670
    if (!virNetworkObjIsPersistent(obj)) {
3671 3672 3673 3674 3675
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3676
    /* remove autostart link */
3677 3678
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3679
                                  obj) < 0)
3680
        goto cleanup;
3681

3682 3683
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3684 3685
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3686

3687
    VIR_INFO("Undefining network '%s'", def->name);
3688
    if (!active) {
3689
        if (networkRemoveInactive(driver, obj) < 0)
3690
            goto cleanup;
3691 3692 3693 3694 3695
    } else {

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

3699
    ret = 0;
3700

3701
 cleanup:
3702
    virObjectEventStateQueue(driver->networkEventState, event);
3703
    virNetworkObjEndAPI(&obj);
3704
    return ret;
3705 3706
}

3707

3708 3709 3710 3711 3712 3713 3714 3715
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3716
    virNetworkDriverStatePtr driver = networkGetDriver();
3717
    virNetworkObjPtr obj = NULL;
3718
    virNetworkDefPtr def;
3719 3720
    int isActive, ret = -1;
    size_t i;
3721
    virNetworkIPDefPtr ipdef;
3722
    bool oldDhcpActive = false;
3723
    bool needFirewallRefresh = false;
3724

3725 3726 3727 3728 3729

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3730
    if (!(obj = networkObjFromNetwork(net)))
3731
        goto cleanup;
3732
    def = virNetworkObjGetDef(obj);
3733

3734
    if (virNetworkUpdateEnsureACL(net->conn, def, flags) < 0)
3735 3736
        goto cleanup;

3737
    /* see if we are listening for dhcp pre-modification */
3738
    for (i = 0;
3739
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3740
         i++) {
3741 3742 3743 3744 3745 3746
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3747 3748
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3749
     */
3750
    isActive = virNetworkObjIsActive(obj);
3751 3752
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3753 3754 3755 3756 3757 3758 3759
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3760 3761 3762 3763
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
3764 3765 3766 3767
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
3768 3769 3770 3771 3772 3773 3774 3775 3776 3777
            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).
                 */
3778 3779
                networkRemoveFirewallRules(def);
                needFirewallRefresh = true;
3780 3781 3782 3783
                break;
            default:
                break;
            }
3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797
            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;
3798 3799 3800
        }
    }

3801
    /* update the network config in memory/on disk */
3802
    if (virNetworkObjUpdate(obj, command, section, parentIndex, xml, flags) < 0) {
3803
        if (needFirewallRefresh)
3804
            ignore_value(networkAddFirewallRules(def));
3805 3806 3807
        goto cleanup;
    }

3808 3809 3810 3811
    /* @def is replaced */
    def = virNetworkObjGetDef(obj);

    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
3812 3813 3814 3815 3816
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
3817
                                 virNetworkObjGetPersistentDef(obj)) < 0) {
3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830
            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 ||
3831 3832 3833 3834 3835 3836 3837 3838
            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)
3839
             */
3840
            if (networkRestartDhcpDaemon(driver, obj) < 0)
3841 3842
                goto cleanup;

3843 3844 3845 3846 3847 3848 3849 3850
        } 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;

3851
            for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3852
                 i++) {
3853 3854 3855 3856 3857 3858 3859
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3860 3861
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
3862 3863 3864
                goto cleanup;
            }

3865 3866 3867 3868
        } 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.
3869
             */
3870
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
3871 3872 3873 3874 3875 3876 3877 3878
                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.
             */
3879
            if (networkRefreshRadvd(driver, obj) < 0)
3880 3881 3882 3883
                goto cleanup;
        }

        /* save current network state to disk */
3884
        if ((ret = virNetworkObjSaveStatus(driver->stateDir, obj)) < 0)
3885 3886
            goto cleanup;
    }
3887 3888

    /* call the 'updated' network hook script */
3889
    if (networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_UPDATED,
3890 3891 3892
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

3893
    ret = 0;
3894
 cleanup:
3895
    virNetworkObjEndAPI(&obj);
3896 3897 3898
    return ret;
}

3899 3900 3901

static int
networkCreate(virNetworkPtr net)
3902
{
3903
    virNetworkDriverStatePtr driver = networkGetDriver();
3904
    virNetworkObjPtr obj;
3905
    virNetworkDefPtr def;
3906
    int ret = -1;
3907
    virObjectEventPtr event = NULL;
3908

3909
    if (!(obj = networkObjFromNetwork(net)))
3910
        goto cleanup;
3911
    def = virNetworkObjGetDef(obj);
3912

3913
    if (virNetworkCreateEnsureACL(net->conn, def) < 0)
3914 3915
        goto cleanup;

3916
    if ((ret = networkStartNetwork(driver, obj)) < 0)
3917
        goto cleanup;
3918

3919 3920
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3921 3922
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3923

3924
 cleanup:
3925
    virObjectEventStateQueue(driver->networkEventState, event);
3926
    virNetworkObjEndAPI(&obj);
3927
    return ret;
3928 3929
}

3930 3931 3932

static int
networkDestroy(virNetworkPtr net)
3933
{
3934
    virNetworkDriverStatePtr driver = networkGetDriver();
3935
    virNetworkObjPtr obj;
3936
    virNetworkDefPtr def;
3937
    int ret = -1;
3938
    virObjectEventPtr event = NULL;
3939

3940
    if (!(obj = networkObjFromNetwork(net)))
3941
        goto cleanup;
3942
    def = virNetworkObjGetDef(obj);
3943

3944
    if (virNetworkDestroyEnsureACL(net->conn, def) < 0)
3945 3946
        goto cleanup;

3947
    if (!virNetworkObjIsActive(obj)) {
3948
        virReportError(VIR_ERR_OPERATION_INVALID,
3949
                       _("network '%s' is not active"),
3950
                       def->name);
3951 3952 3953
        goto cleanup;
    }

3954
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
3955
        goto cleanup;
3956 3957
    /* @def replaced in virNetworkObjUnsetDefTransient*/
    def = virNetworkObjGetDef(obj);
3958

3959 3960
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3961 3962
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
3963

3964 3965
    if (!virNetworkObjIsPersistent(obj) &&
        networkRemoveInactive(driver, obj) < 0) {
3966 3967
        ret = -1;
        goto cleanup;
3968
    }
3969

3970
 cleanup:
3971
    virObjectEventStateQueue(driver->networkEventState, event);
3972
    virNetworkObjEndAPI(&obj);
3973 3974 3975
    return ret;
}

3976 3977 3978 3979

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
3980
{
3981
    virNetworkObjPtr obj;
3982
    virNetworkDefPtr curDef;
3983
    virNetworkDefPtr def;
3984
    virNetworkDefPtr newDef;
3985
    char *ret = NULL;
3986

3987
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
3988

3989
    if (!(obj = networkObjFromNetwork(net)))
3990
        return ret;
3991 3992
    def = virNetworkObjGetDef(obj);
    newDef = virNetworkObjGetNewDef(obj);
3993

3994
    if (virNetworkGetXMLDescEnsureACL(net->conn, def) < 0)
3995 3996
        goto cleanup;

3997 3998
    if ((flags & VIR_NETWORK_XML_INACTIVE) && newDef)
        curDef = newDef;
3999
    else
4000
        curDef = def;
4001

4002
    ret = virNetworkDefFormat(curDef, flags);
4003

4004
 cleanup:
4005
    virNetworkObjEndAPI(&obj);
4006
    return ret;
4007 4008
}

4009 4010 4011 4012

static char *
networkGetBridgeName(virNetworkPtr net)
{
4013
    virNetworkObjPtr obj;
4014
    virNetworkDefPtr def;
4015 4016
    char *bridge = NULL;

4017
    if (!(obj = networkObjFromNetwork(net)))
4018
        return bridge;
4019
    def = virNetworkObjGetDef(obj);
4020

4021
    if (virNetworkGetBridgeNameEnsureACL(net->conn, def) < 0)
4022 4023
        goto cleanup;

4024
    if (!(def->bridge)) {
4025 4026
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
4027
                       def->name);
4028 4029 4030
        goto cleanup;
    }

4031
    ignore_value(VIR_STRDUP(bridge, def->bridge));
4032

4033
 cleanup:
4034
    virNetworkObjEndAPI(&obj);
4035 4036 4037
    return bridge;
}

4038 4039 4040 4041

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
4042
{
4043
    virNetworkObjPtr obj;
4044
    int ret = -1;
4045

4046
    if (!(obj = networkObjFromNetwork(net)))
4047
        return ret;
4048

4049
    if (virNetworkGetAutostartEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
4050 4051
        goto cleanup;

4052
    *autostart = virNetworkObjIsAutostart(obj) ? 1 : 0;
4053
    ret = 0;
4054

4055
 cleanup:
4056
    virNetworkObjEndAPI(&obj);
4057
    return ret;
4058 4059
}

4060 4061 4062 4063

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
4064
{
4065
    virNetworkDriverStatePtr driver = networkGetDriver();
4066
    virNetworkObjPtr obj;
4067
    virNetworkDefPtr def;
4068
    char *configFile = NULL, *autostartLink = NULL;
4069 4070
    bool new_autostart;
    bool cur_autostart;
4071
    int ret = -1;
4072

4073
    if (!(obj = networkObjFromNetwork(net)))
4074
        goto cleanup;
4075
    def = virNetworkObjGetDef(obj);
4076

4077
    if (virNetworkSetAutostartEnsureACL(net->conn, def) < 0)
4078 4079
        goto cleanup;

4080
    if (!virNetworkObjIsPersistent(obj)) {
4081 4082
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
4083 4084 4085
        goto cleanup;
    }

4086 4087 4088
    new_autostart = (autostart != 0);
    cur_autostart = virNetworkObjIsAutostart(obj);
    if (cur_autostart != new_autostart) {
4089 4090
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir,
                                               def->name)) == NULL)
4091
            goto cleanup;
4092 4093
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir,
                                                  def->name)) == NULL)
4094 4095
            goto cleanup;

4096
        if (new_autostart) {
4097
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
4098
                virReportSystemError(errno,
4099 4100
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
4101 4102
                goto cleanup;
            }
4103

4104
            if (symlink(configFile, autostartLink) < 0) {
4105
                virReportSystemError(errno,
4106
                                     _("Failed to create symlink '%s' to '%s'"),
4107
                                     autostartLink, configFile);
4108 4109 4110
                goto cleanup;
            }
        } else {
4111
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4112
                virReportSystemError(errno,
4113
                                     _("Failed to delete symlink '%s'"),
4114
                                     autostartLink);
4115 4116
                goto cleanup;
            }
4117 4118
        }

4119
        virNetworkObjSetAutostart(obj, new_autostart);
4120
    }
4121

4122
    ret = 0;
4123

4124
 cleanup:
4125 4126
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4127
    virNetworkObjEndAPI(&obj);
4128
    return ret;
4129 4130
}

4131

4132
static int
4133
networkGetDHCPLeases(virNetworkPtr net,
4134 4135 4136
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
4137
{
4138
    virNetworkDriverStatePtr driver = networkGetDriver();
4139 4140 4141
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
4142
    size_t size = 0;
4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153
    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;
4154
    virNetworkIPDefPtr ipdef_tmp = NULL;
4155 4156
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
4157
    virNetworkObjPtr obj;
4158
    virNetworkDefPtr def;
4159
    virMacAddr mac_addr;
4160 4161 4162

    virCheckFlags(0, -1);

4163 4164 4165 4166 4167 4168
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4169
    if (!(obj = networkObjFromNetwork(net)))
4170
        return -1;
4171
    def = virNetworkObjGetDef(obj);
4172

4173
    if (virNetworkGetDHCPLeasesEnsureACL(net->conn, def) < 0)
4174
        goto cleanup;
4175 4176

    /* Retrieve custom leases file location */
4177
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, def->bridge);
4178 4179

    /* Read entire contents */
4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193
    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);
        }
4194 4195 4196 4197 4198 4199 4200 4201 4202 4203
        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;
        }

4204
        if (!virJSONValueIsArray(leases_array)) {
4205
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4206
                           _("Malformed lease_entries array"));
4207 4208
            goto error;
        }
4209
        size = virJSONValueArraySize(leases_array);
4210 4211
    }

4212
    currtime = (long long)time(NULL);
4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228

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

4229
        if (mac && virMacAddrCompare(mac, mac_tmp))
4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260
            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 */
4261 4262
            for (j = 0; j < def->nips; j++) {
                ipdef_tmp = &def->ips[j];
4263 4264 4265 4266 4267 4268 4269 4270

                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)) {
4271
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4272 4273 4274 4275 4276 4277 4278 4279
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
4280
                (VIR_STRDUP(lease->iface, def->bridge) < 0))
4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312
                goto error;

            /* Fields that can be NULL */
            if ((VIR_STRDUP(lease->iaid,
                            virJSONValueObjectGetString(lease_tmp, "iaid")) < 0) ||
                (VIR_STRDUP(lease->clientid,
                            virJSONValueObjectGetString(lease_tmp, "client-id")) < 0) ||
                (VIR_STRDUP(lease->hostname,
                            virJSONValueObjectGetString(lease_tmp, "hostname")) < 0))
                goto error;

            if (VIR_INSERT_ELEMENT(leases_ret, nleases, nleases, lease) < 0)
                goto error;

        } else {
            nleases++;
        }

        VIR_FREE(lease);
    }

    if (leases_ret) {
        /* NULL terminated array */
        ignore_value(VIR_REALLOC_N(leases_ret, nleases + 1));
        *leases = leases_ret;
        leases_ret = NULL;
    }

    rv = nleases;

 cleanup:
    VIR_FREE(lease);
4313
    VIR_FREE(lease_entries);
4314 4315
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4316

4317
    virNetworkObjEndAPI(&obj);
4318

4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329
    return rv;

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

4330

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 4362 4363 4364 4365
/* A unified function to log network connections and disconnections */

static void
networkLogAllocation(virNetworkDefPtr netdef,
                     virDomainNetType actualType,
                     virNetworkForwardIfDefPtr dev,
                     virDomainNetDefPtr iface,
                     bool inUse)
{
    char macStr[VIR_MAC_STRING_BUFLEN];
    const char *verb = inUse ? "using" : "releasing";

    if (!dev) {
        VIR_INFO("MAC %s %s network %s (%d connections)",
                 virMacAddrFormat(&iface->mac, macStr), verb,
                 netdef->name, netdef->connections);
    } else {
        if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
            VIR_INFO("MAC %s %s network %s (%d connections) "
                     "physical device %04x:%02x:%02x.%x (%d connections)",
                     virMacAddrFormat(&iface->mac, macStr), verb,
                     netdef->name, netdef->connections,
                     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)",
                     virMacAddrFormat(&iface->mac, macStr), verb,
                     netdef->name, netdef->connections,
                     dev->device.dev, dev->connections);
        }
    }
}

4366

4367 4368 4369 4370 4371 4372 4373 4374 4375
/* 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.
 */

/* networkAllocateActualDevice:
4376
 * @dom: domain definition that @iface belongs to
4377 4378 4379 4380 4381 4382 4383 4384 4385 4386
 * @iface: the original NetDef from the domain
 *
 * Looks up the network reference by iface, allocates a physical
 * device from that network (if appropriate), and returns with the
 * virDomainActualNetDef filled in accordingly. If there are no
 * changes to be made in the netdef, then just leave the actualdef
 * empty.
 *
 * Returns 0 on success, -1 on failure.
 */
4387
static int
4388 4389
networkAllocateActualDevice(virNetworkPtr net,
                            virDomainDefPtr dom,
4390
                            virDomainNetDefPtr iface)
4391
{
4392
    virNetworkDriverStatePtr driver = networkGetDriver();
4393
    virDomainNetType actualType = iface->type;
4394
    virNetworkObjPtr obj = NULL;
4395
    virNetworkDefPtr netdef = NULL;
4396
    virNetDevBandwidthPtr bandwidth = NULL;
4397 4398 4399
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
4400
    virNetworkForwardIfDefPtr dev = NULL;
4401
    size_t i;
4402 4403
    int ret = -1;

4404 4405 4406 4407 4408 4409 4410 4411
    obj = virNetworkObjFindByName(driver->networks, net->name);
    if (!obj) {
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       net->name);
        goto error;
    }

4412 4413 4414 4415 4416
    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expected an interface for a virtual network"));
        goto error;
    }
4417 4418 4419 4420

    virDomainActualNetDefFree(iface->data.network.actual);
    iface->data.network.actual = NULL;

4421
    netdef = virNetworkObjGetDef(obj);
4422

4423
    if (!virNetworkObjIsActive(obj)) {
4424 4425 4426 4427 4428 4429
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4430 4431 4432
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

4433 4434 4435
    /* 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 已提交
4436
     */
4437 4438 4439 4440 4441 4442
    portgroup = virPortGroupFindByName(netdef, iface->data.network.portgroup);

    /* If there is already interface-specific bandwidth, just use that
     * (already in NetDef). Otherwise, if there is bandwidth info in
     * the portgroup, fill that into the ActualDef.
     */
4443 4444 4445 4446 4447 4448

    if (iface->bandwidth)
        bandwidth = iface->bandwidth;
    else if (portgroup && portgroup->bandwidth)
        bandwidth = portgroup->bandwidth;

4449 4450
    if (bandwidth && virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
                                            bandwidth) < 0)
4451
        goto error;
4452

4453 4454 4455 4456 4457 4458 4459 4460
    /* copy appropriate vlan info to actualNet */
    if (iface->vlan.nTags > 0)
        vlan = &iface->vlan;
    else if (portgroup && portgroup->vlan.nTags > 0)
        vlan = &portgroup->vlan;
    else if (netdef->vlan.nTags > 0)
        vlan = &netdef->vlan;

4461 4462
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
4463

4464 4465 4466 4467 4468 4469 4470 4471 4472 4473
    if (iface->trustGuestRxFilters)
       iface->data.network.actual->trustGuestRxFilters
          = iface->trustGuestRxFilters;
    else if (portgroup && portgroup->trustGuestRxFilters)
       iface->data.network.actual->trustGuestRxFilters
          = portgroup->trustGuestRxFilters;
    else if (netdef->trustGuestRxFilters)
       iface->data.network.actual->trustGuestRxFilters
          = netdef->trustGuestRxFilters;

4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485
    /* merge virtualports from interface, network, and portgroup to
     * arrive at actual virtualport to use
     */
    if (virNetDevVPortProfileMerge3(&iface->data.network.actual->virtPortProfile,
                                    iface->virtPortProfile,
                                    netdef->virtPortProfile,
                                    portgroup
                                    ? portgroup->virtPortProfile : NULL) < 0) {
        goto error;
    }
    virtport = iface->data.network.actual->virtPortProfile;

4486 4487 4488 4489 4490
    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:
4491
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
4492

4493
        /* we also store the bridge device and macTableManager settings
4494 4495 4496 4497 4498 4499 4500
         * in iface->data.network.actual->data.bridge for later use
         * after the domain's tap device is created (to attach to the
         * bridge and set flood/learning mode on the tap device)
         */
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
            goto error;
4501 4502
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4503

4504 4505 4506 4507 4508 4509 4510 4511 4512
        if (virtport) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("<virtualport type='%s'> not supported for network "
                             "'%s' which uses IP forwarding"),
                           virNetDevVPortTypeToString(virtport->virtPortType),
                           netdef->name);
            goto error;
        }

4513 4514 4515
        if (networkPlugBandwidth(obj, &iface->mac, iface->bandwidth,
                                 iface->data.network.actual ?
                                 &iface->data.network.actual->class_id : NULL) < 0)
4516
            goto error;
4517
        break;
4518

4519
    case VIR_NETWORK_FORWARD_HOSTDEV: {
4520
        virDomainHostdevSubsysPCIBackendType backend;
4521

4522
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
4523
        if (networkCreateInterfacePool(netdef) < 0)
4524 4525 4526
            goto error;

        /* pick first dev with 0 connections */
4527 4528 4529
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4530 4531 4532 4533 4534 4535 4536 4537 4538 4539
                break;
            }
        }
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' requires exclusive access "
                             "to interfaces, but none are available"),
                           netdef->name);
            goto error;
        }
4540
        iface->data.network.actual->data.hostdev.def.parentnet = iface;
4541 4542
        iface->data.network.actual->data.hostdev.def.info = &iface->info;
        iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
4543
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
4544
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
4545
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
4546

E
Eric Blake 已提交
4547
        switch (netdef->forward.driverName) {
4548
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
4549
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4550 4551
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
4552
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
4553 4554
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
4555
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566
            break;
        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unrecognized driver name value %d "
                             " in network '%s'"),
                           netdef->forward.driverName, netdef->name);
            goto error;
        }
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.backend
            = backend;

4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579
        if (virtport) {
            /* make sure type is supported for hostdev connections */
            if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses an SR-IOV Virtual Function "
                                 "via PCI passthrough"),
                               virNetDevVPortTypeToString(virtport->virtPortType),
                               netdef->name);
                goto error;
            }
        }
4580 4581
        break;
    }
4582

4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594
    case VIR_NETWORK_FORWARD_BRIDGE:
        if (netdef->bridge) {
            /* <forward type='bridge'/> <bridge name='xxx'/>
             * is VIR_DOMAIN_NET_TYPE_BRIDGE
             */

            iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
            if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                           netdef->bridge) < 0)
                goto error;
            iface->data.network.actual->data.bridge.macTableManager
               = netdef->macTableManager;
4595

4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606
            if (virtport) {
                /* only type='openvswitch' is allowed for bridges */
                if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport type='%s'> not supported for network "
                                     "'%s' which uses a bridge device"),
                                   virNetDevVPortTypeToString(virtport->virtPortType),
                                   netdef->name);
                    goto error;
                }
            }
4607

4608 4609 4610
            if (networkPlugBandwidth(obj, &iface->mac, iface->bandwidth,
                                     iface->data.network.actual ?
                                     &iface->data.network.actual->class_id : NULL) < 0)
4611
                goto error;
4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622
            break;
        }

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

    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
4623 4624 4625 4626 4627
        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
4628
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
4629 4630 4631 4632 4633 4634

        /* NO need to check the value returned from virNetDevMacVLanModeTypeFromString
         * it must be valid for these forward type(bridge|private|vepa|passthrough)
         */
        iface->data.network.actual->data.direct.mode =
            virNetDevMacVLanModeTypeFromString(virNetworkForwardTypeToString(netdef->forward.type));
4635 4636

        if (virtport) {
4637 4638 4639 4640 4641 4642 4643 4644
            /* make sure type is supported for macvtap connections */
            if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBG &&
                virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_8021QBH) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("<virtualport type='%s'> not supported for network "
                                 "'%s' which uses a macvtap device"),
                               virNetDevVPortTypeToString(virtport->virtPortType),
                               netdef->name);
4645
                goto error;
4646 4647
            }
        }
4648

4649 4650 4651
        /* 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).
         */
4652
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4653 4654 4655 4656
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4657
            goto error;
4658 4659 4660
        } else {
            /* pick an interface from the pool */

4661
            if (networkCreateInterfacePool(netdef) < 0)
4662 4663
                goto error;

4664 4665 4666 4667 4668
            /* 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.
4669
             */
4670 4671
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4672 4673 4674
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4675

4676
                /* pick first dev with 0 connections */
4677 4678 4679
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4680 4681 4682 4683 4684
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4685
                dev = &netdef->forward.ifs[0];
4686 4687 4688
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4689 4690 4691 4692
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4693 4694 4695 4696
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4697
                goto error;
4698
            }
4699 4700
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
4701
                goto error;
4702
        }
4703 4704 4705 4706 4707 4708
        break;

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
        goto error;
4709 4710
    }

4711 4712
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
                               dom->name, &iface->mac) < 0)
M
Michal Privoznik 已提交
4713 4714
        goto error;

4715
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
4716
        goto error;
4717

4718 4719 4720 4721 4722
    /* 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.
     */

4723
    if (virDomainNetGetActualVlan(iface)) {
4724 4725 4726 4727
        /* 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
4728 4729
         */
        if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
4730 4731 4732
              (actualType == VIR_DOMAIN_NET_TYPE_DIRECT &&
               virDomainNetGetActualDirectMode(iface)
               == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) ||
4733 4734 4735
              (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE &&
               virtport && virtport->virtPortType
               == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
4736 4737 4738 4739 4740
            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);
4741 4742 4743
            goto error;
        }
    }
4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754
    if (virDomainNetGetActualBandwidth(iface)) {
        /* bandwidth configuration via libvirt is not supported for
         * hostdev network devices
         */
        if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("bandwidth settings are not supported "
                             "for hostdev interfaces"));
            goto error;
        }
    }
4755

4756 4757 4758 4759 4760 4761 4762 4763 4764
    netdef->connections++;
    if (dev)
        dev->connections++;
    /* finally we can call the 'plugged' hook script if any */
    if (networkRunHook(obj, dom, iface,
                       VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        netdef->connections--;
4765
        if (dev)
4766 4767
            dev->connections--;
        goto error;
4768
    }
4769
    networkLogAllocation(netdef, actualType, dev, iface, true);
4770

4771
    ret = 0;
4772

4773
 cleanup:
4774
    virNetworkObjEndAPI(&obj);
4775 4776
    return ret;

4777
 error:
4778
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4779 4780 4781
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4782
    goto cleanup;
4783 4784
}

4785

4786
/* networkNotifyActualDevice:
4787
 * @dom: domain definition that @iface belongs to
4788 4789 4790 4791 4792
 * @iface:  the domain's NetDef with an "actual" device already filled in.
 *
 * 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
4793
 * order.
4794
 *
4795
 * Returns 0 on success, -1 on failure.
4796
 */
4797
static int
4798 4799
networkNotifyActualDevice(virNetworkPtr net,
                          virDomainDefPtr dom,
4800
                          virDomainNetDefPtr iface)
4801
{
4802
    virNetworkDriverStatePtr driver = networkGetDriver();
4803
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4804
    virNetworkObjPtr obj;
4805
    virNetworkDefPtr netdef;
4806
    virNetworkForwardIfDefPtr dev = NULL;
4807
    size_t i;
4808
    int ret = -1;
4809

4810 4811 4812 4813 4814 4815 4816 4817
    obj = virNetworkObjFindByName(driver->networks, net->name);
    if (!obj) {
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       net->name);
        goto error;
    }

4818 4819 4820 4821 4822
    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expected an interface for a virtual network"));
        goto error;
    }
4823

4824
    netdef = virNetworkObjGetDef(obj);
4825

4826
    if (!virNetworkObjIsActive(obj)) {
4827 4828 4829 4830 4831 4832
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4833
    if (!iface->data.network.actual ||
4834 4835
        (actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
4836 4837
        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
        goto success;
4838 4839
    }

4840
    if (networkCreateInterfacePool(netdef) < 0)
4841
        goto error;
4842

4843
    if (netdef->forward.nifs == 0) {
4844
        virReportError(VIR_ERR_INTERNAL_ERROR,
4845 4846
                       _("network '%s' uses a direct or hostdev mode, "
                         "but has no forward dev and no interface pool"),
4847
                       netdef->name);
4848
        goto error;
4849
    }
4850

4851 4852
    if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
        const char *actualDev;
4853

4854 4855 4856 4857 4858 4859 4860 4861 4862
        actualDev = virDomainNetGetActualDirectDev(iface);
        if (!actualDev) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("the interface uses a direct mode, "
                             "but has no source dev"));
            goto error;
        }

        /* find the matching interface and increment its connections */
4863 4864
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4865
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4866 4867
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4868 4869 4870 4871 4872
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4873
            virReportError(VIR_ERR_INTERNAL_ERROR,
4874 4875
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4876
                           netdef->name, actualDev);
4877
            goto error;
4878 4879
        }

4880
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4881 4882
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4883
         */
4884
        if ((dev->connections > 0) &&
4885 4886
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4887 4888
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
4889
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4890
            virReportError(VIR_ERR_INTERNAL_ERROR,
4891 4892
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
4893
                           netdef->name, actualDev);
4894
            goto error;
4895
        }
4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907
    }  else /* if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) */ {
        virDomainHostdevDefPtr hostdev;

        hostdev = virDomainNetGetActualHostdev(iface);
        if (!hostdev) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("the interface uses a hostdev mode, "
                             "but has no hostdev"));
            goto error;
        }

        /* find the matching interface and increment its connections */
4908 4909
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4910
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4911
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
4912 4913
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4914 4915 4916 4917 4918 4919 4920 4921 4922
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have "
                             "PCI device %04x:%02x:%02x.%x in use by domain"),
                           netdef->name,
4923 4924 4925 4926
                           hostdev->source.subsys.u.pci.addr.domain,
                           hostdev->source.subsys.u.pci.addr.bus,
                           hostdev->source.subsys.u.pci.addr.slot,
                           hostdev->source.subsys.u.pci.addr.function);
J
Ján Tomko 已提交
4927
            goto error;
4928 4929 4930 4931 4932 4933 4934
        }

        /* 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) &&
4935
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4936 4937 4938 4939 4940 4941 4942 4943 4944
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' claims the PCI device at "
                             "domain=%d bus=%d slot=%d function=%d "
                             "is already in use by a different domain"),
                           netdef->name,
                           dev->device.pci.domain, dev->device.pci.bus,
                           dev->device.pci.slot, dev->device.pci.function);
            goto error;
        }
4945 4946
    }

4947
 success:
4948
    netdef->connections++;
4949 4950
    if (dev)
        dev->connections++;
4951
    /* finally we can call the 'plugged' hook script if any */
4952
    if (networkRunHook(obj, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
4953 4954 4955 4956 4957 4958 4959
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
        goto error;
    }
4960
    networkLogAllocation(netdef, actualType, dev, iface, true);
4961
    ret = 0;
4962

4963
 cleanup:
4964
    virNetworkObjEndAPI(&obj);
4965
    return ret;
4966

4967
 error:
4968
    goto cleanup;
4969 4970 4971 4972
}


/* networkReleaseActualDevice:
4973
 * @dom: domain definition that @iface belongs to
4974 4975 4976 4977 4978 4979 4980 4981 4982
 * @iface:  a domain's NetDef (interface definition)
 *
 * 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.
 */
4983
static int
4984 4985
networkReleaseActualDevice(virNetworkPtr net,
                           virDomainDefPtr dom,
4986
                           virDomainNetDefPtr iface)
4987
{
4988
    virNetworkDriverStatePtr driver = networkGetDriver();
4989
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4990
    virNetworkObjPtr obj;
4991
    virNetworkDefPtr netdef;
4992
    virNetworkForwardIfDefPtr dev = NULL;
4993 4994
    size_t i;
    int ret = -1;
4995

4996 4997 4998 4999 5000 5001 5002 5003
    obj = virNetworkObjFindByName(driver->networks, net->name);
    if (!obj) {
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       net->name);
        goto error;
    }

5004 5005 5006 5007 5008
    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expected an interface for a virtual network"));
        goto error;
    }
5009

5010
    netdef = virNetworkObjGetDef(obj);
5011

5012 5013 5014 5015 5016
    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:
5017 5018 5019
        if (iface->data.network.actual &&
            networkUnplugBandwidth(obj, iface->bandwidth,
                                   &iface->data.network.actual->class_id) < 0)
5020 5021 5022 5023
            goto error;
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
5024 5025
        if (iface->data.network.actual &&
            actualType == VIR_DOMAIN_NET_TYPE_BRIDGE &&
5026 5027
            networkUnplugBandwidth(obj, iface->bandwidth,
                                   &iface->data.network.actual->class_id) < 0)
5028 5029
            goto error;
        break;
5030 5031 5032 5033 5034 5035 5036 5037 5038
    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, netdef->forward.type);
5039
        goto error;
5040
    }
5041

5042 5043 5044
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
5045 5046
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
5047 5048
    }

5049
    if (netdef->forward.nifs == 0) {
5050
        virReportError(VIR_ERR_INTERNAL_ERROR,
5051
                       _("network '%s' uses a direct/hostdev mode, but "
5052 5053
                         "has no forward dev and no interface pool"),
                       netdef->name);
5054
        goto error;
5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066
    }

    if (actualType == VIR_DOMAIN_NET_TYPE_DIRECT) {
        const char *actualDev;

        actualDev = virDomainNetGetActualDirectDev(iface);
        if (!actualDev) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("the interface uses a direct mode, "
                             "but has no source dev"));
            goto error;
        }
5067

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

5077
        if (!dev) {
5078
            virReportError(VIR_ERR_INTERNAL_ERROR,
5079 5080
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5081
                           netdef->name, actualDev);
5082
            goto error;
5083
        }
5084 5085 5086 5087 5088 5089 5090 5091 5092 5093
    } else /* if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) */ {
        virDomainHostdevDefPtr hostdev;

        hostdev = virDomainNetGetActualHostdev(iface);
        if (!hostdev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("the interface uses a hostdev mode, but has no hostdev"));
            goto error;
        }

5094 5095
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5096
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5097
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
5098 5099
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5100 5101 5102 5103 5104 5105 5106 5107 5108
                break;
            }
        }

        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' doesn't have "
                             "PCI device %04x:%02x:%02x.%x in use by domain"),
                           netdef->name,
5109 5110 5111 5112
                           hostdev->source.subsys.u.pci.addr.domain,
                           hostdev->source.subsys.u.pci.addr.bus,
                           hostdev->source.subsys.u.pci.addr.slot,
                           hostdev->source.subsys.u.pci.addr.function);
J
Ján Tomko 已提交
5113
            goto error;
5114
        }
J
Ján Tomko 已提交
5115
    }
5116

5117
 success:
5118
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, dom->name, &iface->mac);
M
Michal Privoznik 已提交
5119

5120
    if (iface->data.network.actual) {
5121
        netdef->connections--;
5122 5123
        if (dev)
            dev->connections--;
5124
        /* finally we can call the 'unplugged' hook script if any */
5125
        networkRunHook(obj, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
5126
                       VIR_HOOK_SUBOP_BEGIN);
5127
        networkLogAllocation(netdef, actualType, dev, iface, false);
5128
    }
5129
    ret = 0;
5130
 cleanup:
5131
    virNetworkObjEndAPI(&obj);
5132 5133 5134 5135
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
5136
    return ret;
5137

5138
 error:
5139
    goto cleanup;
5140
}
5141

5142

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

5177
    virMacAddrFormat(ifaceMac, ifmac);
5178 5179 5180 5181 5182 5183

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

5188 5189
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor)) ||
5190 5191
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
5192
        return 1;
5193
    }
5194 5195

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

    /* 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,
5206 5207 5208
                           _("Cannot plug '%s' interface into '%s' because "
                             "new combined inbound floor=%llu would overcommit "
                             "peak=%llu on network '%s'"),
5209
                           ifmac,
5210
                           def->bridge,
5211 5212
                           tmp_floor_sum,
                           netBand->in->peak,
5213
                           def->name);
5214 5215 5216 5217 5218 5219
            goto cleanup;
        }
    } else if (tmp_floor_sum > netBand->in->average) {
        /* tmp_floor_sum can be between 'average' and 'peak' iff 'peak' is set.
         * Otherwise, tmp_floor_sum must be below 'average'. */
        virReportError(VIR_ERR_OPERATION_INVALID,
5220 5221 5222
                       _("Cannot plug '%s' interface into '%s' because "
                         "new combined inbound floor=%llu would overcommit "
                         "average=%llu on network '%s'"),
5223
                       ifmac,
5224
                       def->bridge,
5225 5226
                       tmp_floor_sum,
                       netBand->in->average,
5227
                       def->name);
5228 5229 5230
        goto cleanup;
    }

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

5235
 cleanup:
5236 5237 5238
    return ret;
}

5239

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

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

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

    return ret;
}

5265

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

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

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

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

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


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

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

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

5345
    virMacAddrFormat(mac, ifmac);
5346

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

    ret = 0;
5351

5352
 cleanup:
5353 5354 5355
    return ret;
}

5356

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

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

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

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

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

5407
 cleanup:
5408 5409
    return ret;
}
5410

5411

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

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

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


static bool
networkBandwidthGenericChecks(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
5432
    virNetDevBandwidthPtr ifaceBand;
5433 5434
    unsigned long long old_floor, new_floor;

5435 5436
    if (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_BRIDGE ||
        iface->data.network.actual->data.bridge.brname == NULL) {
5437 5438 5439 5440 5441
        /* This is not an interface that's plugged into a network.
         * We don't care. Thus from our POV bandwidth change is allowed. */
        return false;
    }

5442
    ifaceBand = virDomainNetGetActualBandwidth(iface);
5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453
    old_floor = new_floor = 0;

    if (ifaceBand && ifaceBand->in)
        old_floor = ifaceBand->in->floor;
    if (newBandwidth && newBandwidth->in)
        new_floor = newBandwidth->in->floor;

    return new_floor != old_floor;
}


5454
static bool
5455 5456 5457 5458
networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5459
    virNetworkObjPtr obj = NULL;
5460 5461 5462 5463 5464 5465
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    bool ret = false;

    if (!networkBandwidthGenericChecks(iface, newBandwidth))
        return true;

5466 5467
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5468 5469 5470 5471 5472 5473
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return false;
    }

5474
    if (networkCheckBandwidth(obj, newBandwidth, ifaceBand, &iface->mac, NULL) < 0)
5475 5476 5477 5478 5479
        goto cleanup;

    ret = true;

 cleanup:
5480
    virNetworkObjEndAPI(&obj);
5481 5482
    return ret;
}
5483 5484


5485
static int
5486 5487 5488 5489
networkBandwidthUpdate(virDomainNetDefPtr iface,
                       virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5490
    virNetworkObjPtr obj = NULL;
5491
    virNetworkDefPtr def;
5492
    unsigned long long tmp_floor_sum;
5493 5494 5495 5496 5497
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    unsigned long long new_rate = 0;
    int plug_ret;
    int ret = -1;

5498 5499 5500 5501 5502 5503
    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expected an interface for a virtual network"));
        return -1;
    }

5504 5505 5506
    if (!networkBandwidthGenericChecks(iface, newBandwidth))
        return 0;

5507 5508
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5509 5510 5511 5512 5513
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return ret;
    }
5514
    def = virNetworkObjGetDef(obj);
5515

5516
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, ifaceBand,
5517
                                          &iface->mac, &new_rate)) < 0) {
5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529
        /* helper reported error */
        goto cleanup;
    }

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

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

5530
    if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
5531
        newBandwidth->in && newBandwidth->in->floor) {
5532 5533
        /* Either we just need to update @floor .. */

5534
        if (virNetDevBandwidthUpdateRate(def->bridge,
5535
                                         iface->data.network.actual->class_id,
5536
                                         def->bandwidth,
5537 5538 5539
                                         newBandwidth->in->floor) < 0)
            goto cleanup;

5540 5541 5542 5543 5544
        tmp_floor_sum = virNetworkObjGetFloorSum(obj);
        tmp_floor_sum -= ifaceBand->in->floor;
        tmp_floor_sum += newBandwidth->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
        new_rate -= tmp_floor_sum;
5545

5546 5547
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0 ||
5548
            virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5549
            /* Ouch, rollback */
5550 5551 5552
            tmp_floor_sum -= newBandwidth->in->floor;
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5553

5554
            ignore_value(virNetDevBandwidthUpdateRate(def->bridge,
5555
                                                      iface->data.network.actual->class_id,
5556
                                                      def->bandwidth,
5557 5558 5559 5560 5561 5562
                                                      ifaceBand->in->floor));
            goto cleanup;
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5563 5564 5565 5566
        if (networkPlugBandwidthImpl(obj, &iface->mac, newBandwidth,
                                     iface->data.network.actual ?
                                     &iface->data.network.actual->class_id : NULL,
                                     new_rate) < 0)
5567 5568 5569 5570
            goto cleanup;
    } else {
        /* .. or unplug old. */

5571 5572 5573
        if (networkUnplugBandwidth(obj, iface->bandwidth,
                                   iface->data.network.actual ?
                                   &iface->data.network.actual->class_id : NULL) < 0)
5574 5575 5576 5577 5578
            goto cleanup;
    }

    ret = 0;
 cleanup:
5579
    virNetworkObjEndAPI(&obj);
5580 5581
    return ret;
}
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


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

5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621

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 = {
5622
    .localOnly = true,
5623
    .uriSchemes = (const char *[]){ "network", NULL },
5624 5625 5626 5627 5628
    .hypervisorDriver = &networkHypervisorDriver,
    .networkDriver = &networkDriver,
};


5629 5630 5631 5632 5633 5634 5635 5636 5637 5638
static virStateDriver networkStateDriver = {
    .name = "bridge",
    .stateInitialize  = networkStateInitialize,
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
};

int
networkRegister(void)
{
5639 5640
    if (virRegisterConnectDriver(&networkConnectDriver, false) < 0)
        return -1;
5641 5642 5643 5644
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
5645 5646 5647 5648

    virDomainNetSetDeviceImpl(
        networkAllocateActualDevice,
        networkNotifyActualDevice,
5649 5650
        networkReleaseActualDevice,
        networkBandwidthChangeAllowed,
5651
        networkBandwidthUpdate);
5652

5653 5654
    return 0;
}