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

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.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>
42
#include <net/if.h>
43
#include <dirent.h>
44 45 46
#if HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
47

48
#include "virerror.h"
49
#include "datatypes.h"
50
#include "bridge_driver.h"
51
#include "bridge_driver_platform.h"
52
#include "device_conf.h"
53
#include "driver.h"
54
#include "virbuffer.h"
55
#include "virpidfile.h"
56
#include "vircommand.h"
57
#include "viralloc.h"
58
#include "viruuid.h"
59
#include "viriptables.h"
60
#include "virlog.h"
61
#include "virdnsmasq.h"
62
#include "configmake.h"
63
#include "virnetlink.h"
64
#include "virnetdev.h"
65
#include "virnetdevip.h"
66 67
#include "virnetdevbridge.h"
#include "virnetdevtap.h"
68
#include "virnetdevvportprofile.h"
69
#include "virpci.h"
70
#include "virdbus.h"
71
#include "virfile.h"
72
#include "virstring.h"
73
#include "viraccessapicheck.h"
74
#include "network_event.h"
75
#include "virhook.h"
76
#include "virjson.h"
77

78
#define VIR_FROM_THIS VIR_FROM_NETWORK
79
#define MAX_BRIDGE_ID 256
80

81 82 83 84 85 86 87
/**
 * 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)

88 89
#define SYSCTL_PATH "/proc/sys"

90 91
VIR_LOG_INIT("network.bridge_driver");

92
static virNetworkDriverStatePtr network_driver;
93

94

95 96 97 98 99 100 101 102
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;
}
103

104 105 106

static void
networkDriverLock(virNetworkDriverStatePtr driver)
107
{
108
    virMutexLock(&driver->lock);
109
}
110 111 112 113


static void
networkDriverUnlock(virNetworkDriverStatePtr driver)
114
{
115
    virMutexUnlock(&driver->lock);
116 117
}

118

119 120 121 122
static dnsmasqCapsPtr
networkGetDnsmasqCaps(virNetworkDriverStatePtr driver)
{
    dnsmasqCapsPtr ret;
123
    networkDriverLock(driver);
124
    ret = virObjectRef(driver->dnsmasqCaps);
125
    networkDriverUnlock(driver);
126 127 128
    return ret;
}

129

130 131 132 133 134 135 136 137
static int
networkDnsmasqCapsRefresh(virNetworkDriverStatePtr driver)
{
    dnsmasqCapsPtr caps;

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

138
    networkDriverLock(driver);
139 140
    virObjectUnref(driver->dnsmasqCaps);
    driver->dnsmasqCaps = caps;
141
    networkDriverUnlock(driver);
142 143 144
    return 0;
}

145

146 147 148 149 150
static int
networkStateCleanup(void);

static int
networkStartNetwork(virNetworkDriverStatePtr driver,
151
                    virNetworkObjPtr obj);
152 153 154

static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
155
                       virNetworkObjPtr obj);
156 157 158

static int
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
159
                           virNetworkObjPtr obj);
160 161 162

static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
163
                              virNetworkObjPtr obj);
164

165
static int
166
networkStartNetworkExternal(virNetworkObjPtr obj);
167

168
static int
169
networkShutdownNetworkExternal(virNetworkObjPtr obj);
170

171 172
static void
networkReloadFirewallRules(virNetworkDriverStatePtr driver);
173

174 175
static void
networkRefreshDaemons(virNetworkDriverStatePtr driver);
176

177
static int
178
networkPlugBandwidth(virNetworkObjPtr obj,
179
                     virDomainNetDefPtr iface);
180

181
static int
182
networkUnplugBandwidth(virNetworkObjPtr obj,
183
                       virDomainNetDefPtr iface);
184

185
static void
186
networkNetworkObjTaint(virNetworkObjPtr obj,
187
                       virNetworkTaintFlags taint);
188

189

190 191 192
static virNetworkObjPtr
networkObjFromNetwork(virNetworkPtr net)
{
193
    virNetworkDriverStatePtr driver = networkGetDriver();
194
    virNetworkObjPtr obj;
195 196
    char uuidstr[VIR_UUID_STRING_BUFLEN];

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

205
    return obj;
206 207
}

208

209
static int
210
networkRunHook(virNetworkObjPtr obj,
211
               virDomainDefPtr dom,
212
               virDomainNetDefPtr iface,
213 214 215
               int op,
               int sub_op)
{
216
    virNetworkDefPtr def;
217 218 219 220 221 222
    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)) {
223 224
        if (!obj) {
            VIR_DEBUG("Not running hook as @obj is NULL");
225 226 227
            ret = 0;
            goto cleanup;
        }
228
        def = virNetworkObjGetDef(obj);
229

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

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

242
        if (virBufferCheckError(&buf) < 0)
243 244
            goto cleanup;

245
        xml = virBufferContentAndReset(&buf);
246
        hookret = virHookCall(VIR_HOOK_DRIVER_NETWORK, def->name,
247 248 249 250 251 252 253
                              op, sub_op, NULL, xml, NULL);

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

255
        networkNetworkObjTaint(obj, VIR_NETWORK_TAINT_HOOK);
256 257 258
    }

    ret = 0;
259
 cleanup:
260 261 262 263 264 265 266
    virBufferFreeAndReset(&buf);
    VIR_FREE(xml);
    VIR_FREE(net_xml);
    VIR_FREE(dom_xml);
    return ret;
}

267

268
static char *
269 270
networkDnsmasqLeaseFileNameDefault(virNetworkDriverStatePtr driver,
                                   const char *netname)
271 272 273
{
    char *leasefile;

274
    ignore_value(virAsprintf(&leasefile, "%s/%s.leases",
275
                             driver->dnsmasqStateDir, netname));
276 277 278
    return leasefile;
}

279

280
static char *
281 282
networkDnsmasqLeaseFileNameCustom(virNetworkDriverStatePtr driver,
                                  const char *bridge)
283 284 285 286
{
    char *leasefile;

    ignore_value(virAsprintf(&leasefile, "%s/%s.status",
287
                             driver->dnsmasqStateDir, bridge));
288 289 290
    return leasefile;
}

291

292
static char *
293 294
networkDnsmasqConfigFileName(virNetworkDriverStatePtr driver,
                             const char *netname)
295 296 297
{
    char *conffile;

298
    ignore_value(virAsprintf(&conffile, "%s/%s.conf",
299
                             driver->dnsmasqStateDir, netname));
300 301 302
    return conffile;
}

303

304 305 306 307 308 309
static char *
networkRadvdPidfileBasename(const char *netname)
{
    /* this is simple but we want to be sure it's consistently done */
    char *pidfilebase;

310
    ignore_value(virAsprintf(&pidfilebase, "%s-radvd", netname));
311 312 313
    return pidfilebase;
}

314

315
static char *
316 317
networkRadvdConfigFileName(virNetworkDriverStatePtr driver,
                           const char *netname)
318 319 320
{
    char *configfile;

321
    ignore_value(virAsprintf(&configfile, "%s/%s-radvd.conf",
322
                             driver->radvdStateDir, netname));
323 324
    return configfile;
}
325

326

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

    int ret = -1;

    /* remove the (possibly) existing dnsmasq and radvd files */
345
    if (!(dctx = dnsmasqContextNew(def->name,
346
                                   driver->dnsmasqStateDir))) {
347
        goto cleanup;
348
    }
349

350
    if (!(leasefile = networkDnsmasqLeaseFileNameDefault(driver, def->name)))
351 352
        goto cleanup;

353
    if (!(customleasefile = networkDnsmasqLeaseFileNameCustom(driver, def->bridge)))
354 355
        goto cleanup;

356
    if (!(radvdconfigfile = networkRadvdConfigFileName(driver, def->name)))
357
        goto cleanup;
358 359

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
360
        goto cleanup;
361

362
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
363
        goto cleanup;
364

365
    if (!(statusfile = virNetworkConfigFile(driver->stateDir, def->name)))
366
        goto cleanup;
367

368
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir, def->bridge)))
M
Michal Privoznik 已提交
369 370
        goto cleanup;

371 372 373
    /* dnsmasq */
    dnsmasqDelete(dctx);
    unlink(leasefile);
374
    unlink(customleasefile);
375
    unlink(configfile);
376

M
Michal Privoznik 已提交
377 378 379
    /* MAC map manager */
    unlink(macMapFile);

380 381
    /* radvd */
    unlink(radvdconfigfile);
382
    virPidFileDelete(driver->pidDir, radvdpidbase);
383

384 385 386
    /* remove status file */
    unlink(statusfile);

387
    /* remove the network definition */
388
    virNetworkObjRemoveInactive(driver->networks, obj);
389 390 391

    ret = 0;

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

404

405 406 407
static char *
networkBridgeDummyNicName(const char *brname)
{
408
    static const char dummyNicSuffix[] = "-nic";
409 410
    char *nicname;

411 412 413 414 415 416 417
    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.
         */
418 419 420 421 422
        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));
423
    } else {
424
        ignore_value(virAsprintf(&nicname, "%s%s", brname, dummyNicSuffix));
425
    }
426 427 428
    return nicname;
}

429

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

441
    virObjectLock(obj);
442
    if (!virNetworkObjIsActive(obj)) {
443 444
        ret = 0;
        goto cleanup;
445
    }
446
    def = virNetworkObjGetDef(obj);
447

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

457
        if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
458
                                             def->bridge)))
459 460
            goto cleanup;

461
        if (!(macmap = virMacMapNew(macMapFile)))
462 463
            goto cleanup;

464 465
        virNetworkObjSetMacMap(obj, macmap);

466
        break;
467

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

484 485 486
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
487
    }
488

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

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

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

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

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

520

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

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

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

540

541 542 543
#if HAVE_FIREWALLD
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
544 545
                             DBusMessage *message,
                             void *user_data)
546
{
547 548
    virNetworkDriverStatePtr driver = user_data;

549 550 551 552 553 554
    if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS,
                               "NameOwnerChanged") ||
        dbus_message_is_signal(message, "org.fedoraproject.FirewallD1",
                               "Reloaded"))
    {
        VIR_DEBUG("Reload in bridge_driver because of firewalld.");
555
        networkReloadFirewallRules(driver);
556 557 558 559 560 561
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

562

563
static int
564
networkMigrateStateFiles(virNetworkDriverStatePtr driver)
565 566 567 568 569 570 571 572 573 574 575 576 577
{
    /* Due to a change in location of network state xml beginning in
     * libvirt 1.2.4 (from /var/lib/libvirt/network to
     * /var/run/libvirt/network), we must check for state files in two
     * locations. Anything found in the old location must be written
     * to the new location, then erased from the old location. (Note
     * that we read/write the file rather than calling rename()
     * because the old and new state directories are likely in
     * different filesystems).
     */
    int ret = -1;
    const char *oldStateDir = LOCALSTATEDIR "/lib/libvirt/network";
    DIR *dir;
578
    int direrr;
579 580 581
    struct dirent *entry;
    char *oldPath = NULL, *newPath = NULL;
    char *contents = NULL;
J
Ján Tomko 已提交
582
    int rc;
583

J
Ján Tomko 已提交
584 585
    if ((rc = virDirOpenIfExists(&dir, oldStateDir)) <= 0)
        return rc;
586 587 588 589 590 591 592

    if (virFileMakePath(driver->stateDir) < 0) {
        virReportSystemError(errno, _("cannot create directory %s"),
                             driver->stateDir);
        goto cleanup;
    }

593
    while ((direrr = virDirRead(dir, &entry, oldStateDir)) > 0) {
594 595 596
        if (entry->d_type != DT_UNKNOWN &&
            entry->d_type != DT_REG)
            continue;
597 598 599

        if (virAsprintf(&oldPath, "%s/%s",
                        oldStateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
600
            goto cleanup;
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617

        if (entry->d_type == DT_UNKNOWN) {
            struct stat st;

            if (lstat(oldPath, &st) < 0) {
                virReportSystemError(errno,
                                     _("failed to stat network status file '%s'"),
                                     oldPath);
                goto cleanup;
            }

            if (!S_ISREG(st.st_mode)) {
                VIR_FREE(oldPath);
                continue;
            }
        }

618
        if (virFileReadAll(oldPath, 1024*1024, &contents) < 0)
J
Ján Tomko 已提交
619
            goto cleanup;
620 621 622

        if (virAsprintf(&newPath, "%s/%s",
                        driver->stateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
623
            goto cleanup;
624 625 626 627 628 629 630 631 632 633 634 635
        if (virFileWriteStr(newPath, contents, S_IRUSR | S_IWUSR) < 0) {
            virReportSystemError(errno,
                                 _("failed to write network status file '%s'"),
                                 newPath);
            goto cleanup;
        }

        unlink(oldPath);
        VIR_FREE(oldPath);
        VIR_FREE(newPath);
        VIR_FREE(contents);
    }
636
    if (direrr < 0)
J
Ján Tomko 已提交
637
        goto cleanup;
638 639 640

    ret = 0;
 cleanup:
J
Ján Tomko 已提交
641
    VIR_DIR_CLOSE(dir);
642 643 644 645 646 647
    VIR_FREE(oldPath);
    VIR_FREE(newPath);
    VIR_FREE(contents);
    return ret;
}

648

649
/**
650
 * networkStateInitialize:
651
 *
J
Ján Tomko 已提交
652
 * Initialization function for the QEMU daemon
653 654
 */
static int
655 656 657
networkStateInitialize(bool privileged,
                       virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
658
{
659 660 661
    int ret = -1;
    char *configdir = NULL;
    char *rundir = NULL;
662 663 664
#ifdef HAVE_FIREWALLD
    DBusConnection *sysbus = NULL;
#endif
665

666
    if (VIR_ALLOC(network_driver) < 0)
667
        goto error;
668

669 670
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
671 672
        goto error;
    }
673

674 675
    network_driver->privileged = privileged;

676 677 678 679
    /* configuration/state paths are one of
     * ~/.config/libvirt/... (session/unprivileged)
     * /etc/libvirt/... && /var/(run|lib)/libvirt/... (system/privileged).
     */
680
    if (privileged) {
681
        if (VIR_STRDUP(network_driver->networkConfigDir,
682
                       SYSCONFDIR "/libvirt/qemu/networks") < 0 ||
683
            VIR_STRDUP(network_driver->networkAutostartDir,
684
                       SYSCONFDIR "/libvirt/qemu/networks/autostart") < 0 ||
685
            VIR_STRDUP(network_driver->stateDir,
686
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
687
            VIR_STRDUP(network_driver->pidDir,
688
                       LOCALSTATEDIR "/run/libvirt/network") < 0 ||
689
            VIR_STRDUP(network_driver->dnsmasqStateDir,
690
                       LOCALSTATEDIR "/lib/libvirt/dnsmasq") < 0 ||
691
            VIR_STRDUP(network_driver->radvdStateDir,
692 693
                       LOCALSTATEDIR "/lib/libvirt/radvd") < 0)
            goto error;
694 695 696 697 698

        /* migration from old to new location is only applicable for
         * privileged mode - unprivileged mode directories haven't
         * changed location.
         */
699
        if (networkMigrateStateFiles(network_driver) < 0)
700
            goto error;
701
    } else {
702 703 704
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
705
            goto error;
706

707
        if ((virAsprintf(&network_driver->networkConfigDir,
708
                         "%s/qemu/networks", configdir) < 0) ||
709
            (virAsprintf(&network_driver->networkAutostartDir,
710
                         "%s/qemu/networks/autostart", configdir) < 0) ||
711
            (virAsprintf(&network_driver->stateDir,
712
                         "%s/network/lib", rundir) < 0) ||
713
            (virAsprintf(&network_driver->pidDir,
714
                         "%s/network/run", rundir) < 0) ||
715
            (virAsprintf(&network_driver->dnsmasqStateDir,
716
                         "%s/dnsmasq/lib", rundir) < 0) ||
717
            (virAsprintf(&network_driver->radvdStateDir,
718
                         "%s/radvd/lib", rundir) < 0)) {
719
            goto error;
720
        }
721 722
    }

723
    if (virFileMakePath(network_driver->stateDir) < 0) {
724 725
        virReportSystemError(errno,
                             _("cannot create directory %s"),
726
                             network_driver->stateDir);
727 728 729
        goto error;
    }

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

733
    if (!(network_driver->networks = virNetworkObjListNew()))
734 735
        goto error;

736 737
    if (virNetworkObjLoadAllState(network_driver->networks,
                                  network_driver->stateDir) < 0)
738 739
        goto error;

740 741 742
    if (virNetworkObjLoadAllConfigs(network_driver->networks,
                                    network_driver->networkConfigDir,
                                    network_driver->networkAutostartDir) < 0)
743 744
        goto error;

745 746 747 748
    /* 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). */
749
    virNetworkObjListForEach(network_driver->networks,
750
                             networkUpdateState,
751 752
                             network_driver);
    virNetworkObjListPrune(network_driver->networks,
753 754
                           VIR_CONNECT_LIST_NETWORKS_INACTIVE |
                           VIR_CONNECT_LIST_NETWORKS_TRANSIENT);
755 756
    networkReloadFirewallRules(network_driver);
    networkRefreshDaemons(network_driver);
757

758
    network_driver->networkEventState = virObjectEventStateNew();
759

760 761 762
#ifdef HAVE_FIREWALLD
    if (!(sysbus = virDBusGetSystemBus())) {
        VIR_WARN("DBus not available, disabling firewalld support "
763
                 "in bridge_network_driver: %s", virGetLastErrorMessage());
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
    } 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,
781
                                   network_driver, NULL);
782 783 784
    }
#endif

785
    ret = 0;
786
 cleanup:
787 788 789
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
790

791
 error:
792
    networkStateCleanup();
793
    goto cleanup;
794 795
}

796

797 798 799 800 801 802 803 804
/**
 * networkStateAutoStart:
 *
 * Function to AutoStart the bridge configs
 */
static void
networkStateAutoStart(void)
{
805
    if (!network_driver)
806 807
        return;

808
    virNetworkObjListForEach(network_driver->networks,
809
                             networkAutostartConfig,
810
                             network_driver);
811 812
}

813

814
/**
815
 * networkStateReload:
816
 *
J
Ján Tomko 已提交
817
 * Function to restart the QEMU daemon, it will recheck the configuration
818 819 820
 * files and update its state and the networking
 */
static int
821 822
networkStateReload(void)
{
823
    if (!network_driver)
824 825
        return 0;

826 827 828 829 830
    virNetworkObjLoadAllState(network_driver->networks,
                              network_driver->stateDir);
    virNetworkObjLoadAllConfigs(network_driver->networks,
                                network_driver->networkConfigDir,
                                network_driver->networkAutostartDir);
831 832 833
    networkReloadFirewallRules(network_driver);
    networkRefreshDaemons(network_driver);
    virNetworkObjListForEach(network_driver->networks,
834
                             networkAutostartConfig,
835
                             network_driver);
836 837 838 839 840
    return 0;
}


/**
841
 * networkStateCleanup:
842
 *
J
Ján Tomko 已提交
843
 * Shutdown the QEMU daemon, it will stop all active domains and networks
844 845
 */
static int
846 847
networkStateCleanup(void)
{
848
    if (!network_driver)
849 850
        return -1;

851
    virObjectUnref(network_driver->networkEventState);
852

853
    /* free inactive networks */
854
    virObjectUnref(network_driver->networks);
855

856 857 858 859 860 861
    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);
862

863
    virObjectUnref(network_driver->dnsmasqCaps);
864

865
    virMutexDestroy(&network_driver->lock);
866

867
    VIR_FREE(network_driver);
868 869 870 871 872

    return 0;
}


873 874 875 876 877 878 879 880
static virDrvOpenStatus
networkConnectOpen(virConnectPtr conn,
                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                   virConfPtr conf ATTRIBUTE_UNUSED,
                   unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

881 882 883 884 885 886 887 888 889 890 891
    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);
892 893
            return VIR_DRV_OPEN_ERROR;
        }
894 895 896 897 898 899
    } 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;
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
        }
    }

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


935 936 937 938 939
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
940 941 942
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
943
{
944 945
    size_t i;
    int ret = -1;
946 947 948 949 950 951 952
    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.
     */
953
    for (i = 0; i < 25; i++) {
954
        int signum = 0;
955
        if (i == 0) {
956
            signum = SIGTERM;
957
        } else if (i == 15) {
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
            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);
993
 cleanup:
994 995 996
    return ret;
}

997

J
Ján Tomko 已提交
998 999 1000
/* the following does not build a file, it builds a list
 * which is later saved into a file
 */
1001
static int
G
Gene Czarcinski 已提交
1002
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
1003
                                 virNetworkIPDefPtr ipdef)
1004
{
1005
    size_t i;
G
Gene Czarcinski 已提交
1006
    bool ipv6 = false;
1007

G
Gene Czarcinski 已提交
1008 1009
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
1010 1011
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
1012
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
1013 1014
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
1015
                return -1;
1016
    }
1017

G
Gene Czarcinski 已提交
1018 1019 1020
    return 0;
}

1021

G
Gene Czarcinski 已提交
1022 1023 1024 1025
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
1026
    size_t i, j;
G
Gene Czarcinski 已提交
1027

1028 1029
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
1030
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
1031
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
1032
                for (j = 0; j < host->nnames; j++)
1033 1034
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
1035 1036
            }
        }
1037 1038
    }

1039
    return 0;
1040 1041 1042
}


1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
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;
}


1080
int
1081
networkDnsmasqConfContents(virNetworkObjPtr obj,
1082 1083 1084 1085
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
                           dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
1086
{
1087
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1088
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1089
    int r, ret = -1;
1090
    int nbleases = 0;
1091
    size_t i;
1092
    virNetworkDNSDefPtr dns = &def->dns;
1093
    bool wantDNS = dns->enable != VIR_TRISTATE_BOOL_NO;
1094
    virNetworkIPDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
G
Gene Czarcinski 已提交
1095
    bool ipv6SLAAC;
1096
    char *saddr = NULL, *eaddr = NULL;
1097

1098 1099
    *configstr = NULL;

1100
    /*
1101 1102 1103
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1104
     *
1105 1106
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1107
     */
1108 1109 1110 1111 1112 1113

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

1114
    /* create dnsmasq config file appropriate for this network */
1115 1116

    /* Don't forget to update networkxml2conftest :-) */
1117
    virBufferAsprintf(&configbuf,
1118 1119 1120 1121 1122 1123 1124
                      "##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"
1125
                      "strict-order\n",
1126
                      def->name);
1127

1128 1129 1130 1131 1132 1133
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1134
    if (wantDNS && def->dns.forwarders) {
1135 1136 1137 1138 1139 1140 1141 1142 1143
        /* 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;

1144 1145
        for (i = 0; i < def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &def->dns.forwarders[i];
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155

            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);
1156
                VIR_FREE(addr);
1157 1158
                if (!fwd->domain)
                    addNoResolv = true;
1159 1160 1161 1162
            } else {
                /* "don't forward requests for this domain" */
                virBufferAddLit(&configbuf, "#\n");
            }
1163
        }
1164 1165
        if (addNoResolv)
            virBufferAddLit(&configbuf, "no-resolv\n");
1166 1167
    }

1168 1169
    if (def->domain) {
        if (def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1170 1171
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1172
                              def->domain);
1173
        }
1174
        virBufferAsprintf(&configbuf,
1175 1176
                          "domain=%s\n"
                          "expand-hosts\n",
1177
                          def->domain);
1178
    }
1179

1180
    if (wantDNS &&
1181
        networkDnsmasqConfLocalPTRs(&configbuf, def) < 0)
1182 1183
        goto cleanup;

1184
    if (wantDNS && def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1185 1186 1187 1188
        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)
1189
         */
1190
        virBufferAddLit(&configbuf, "local=//\n");
1191
    }
1192

1193
    if (pidfile)
1194
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1195

1196
    /* dnsmasq will *always* listen on localhost unless told otherwise */
P
Pavel Timofeev 已提交
1197
#ifdef __linux__
1198
    virBufferAddLit(&configbuf, "except-interface=lo\n");
P
Pavel Timofeev 已提交
1199 1200 1201 1202
#else
    /* BSD family OSes and Solaris call loopback interface as lo0 */
    virBufferAddLit(&configbuf, "except-interface=lo0\n");
#endif
1203

1204 1205 1206 1207 1208 1209 1210 1211
    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.
         */
1212
        virBufferAsprintf(&configbuf,
1213 1214
                          "bind-dynamic\n"
                          "interface=%s\n",
1215
                          def->bridge);
1216
    } else {
1217
        virBufferAddLit(&configbuf, "bind-interfaces\n");
1218 1219 1220 1221
        /*
         * --interface does not actually work with dnsmasq < 2.47,
         * due to DAD for ipv6 addresses on the interface.
         *
1222
         * virCommandAddArgList(cmd, "--interface", def->bridge, NULL);
1223 1224 1225
         *
         * So listen on all defined IPv[46] addresses
         */
1226
        for (i = 0;
1227
             (tmpipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
1228
             i++) {
1229 1230 1231 1232
            char *ipaddr = virSocketAddrFormat(&tmpipdef->address);

            if (!ipaddr)
                goto cleanup;
1233

1234
            /* also part of CVE 2012-3411 - if the host's version of
1235
             * dnsmasq doesn't have bind-dynamic, only allow listening on
1236 1237
             * private/local IP addresses (see RFC1918/RFC3484/RFC4193)
             */
1238 1239
            if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
                !virSocketAddrIsPrivate(&tmpipdef->address)) {
1240 1241 1242 1243
                unsigned long version = dnsmasqCapsGetVersion(caps);

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
1244
                                 "The version of dnsmasq on this host (%d.%d) "
1245 1246 1247 1248
                                 "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 "
1249 1250 1251 1252 1253 1254
                                 "(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);
1255
                VIR_FREE(ipaddr);
1256 1257
                goto cleanup;
            }
1258
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
1259 1260 1261
            VIR_FREE(ipaddr);
        }
    }
1262

1263 1264
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
1265
     * guaranteed to not work, and set no-resolv so that no dns
1266 1267 1268
     * 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).
1269 1270 1271
     * 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.
1272
     */
1273
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE) {
1274
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
1275
                        "no-resolv\n");
1276 1277 1278 1279
        if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM)) {
            /* interface=* (any), interval=0 (default), lifetime=0 (seconds) */
            virBufferAddLit(&configbuf, "ra-param=*,0,0\n");
        }
1280
    }
1281

1282 1283 1284 1285 1286
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1287
        }
1288

1289 1290 1291 1292 1293 1294 1295 1296
        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'"),
1297
                               def->name);
1298 1299 1300 1301 1302 1303
                goto cleanup;
            }
            if (!dns->srvs[i].protocol) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing required 'service' "
                                 "attribute in SRV record of network '%s'"),
1304
                               def->name);
1305 1306 1307 1308 1309 1310 1311
                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);
1312

1313 1314 1315 1316 1317 1318 1319
            /* 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.
1320
             */
1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
            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");
1341
        }
1342 1343
    }

G
Gene Czarcinski 已提交
1344
    /* Find the first dhcp for both IPv4 and IPv6 */
1345
    for (i = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
1346
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
1347
         i++) {
G
Gene Czarcinski 已提交
1348 1349 1350 1351
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1352 1353
                                   _("For IPv4, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
                    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,
1365 1366 1367 1368 1369 1370 1371 1372 1373
                                   _("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 已提交
1374 1375 1376 1377
                    goto cleanup;
                }
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1378 1379
                                   _("For IPv6, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392
                    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 "
1393 1394 1395 1396
                 "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 已提交
1397 1398 1399 1400 1401
    }

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1402 1403
        int prefix;

1404
        prefix = virNetworkIPDefPrefix(ipdef);
1405 1406 1407
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1408
                           def->bridge);
1409 1410
            goto cleanup;
        }
1411
        for (r = 0; r < ipdef->nranges; r++) {
1412 1413
            int thisRange;

1414 1415
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1416
                goto cleanup;
1417

1418
            virBufferAsprintf(&configbuf, "dhcp-range=%s,%s",
1419
                              saddr, eaddr);
1420
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1421
                virBufferAsprintf(&configbuf, ",%d", prefix);
1422 1423
            virBufferAddLit(&configbuf, "\n");

1424
            VIR_FREE(saddr);
1425
            VIR_FREE(eaddr);
1426
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1427 1428
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1429
                                              virNetworkIPDefPrefix(ipdef));
1430 1431 1432
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1433
        }
1434

1435
        /*
1436 1437 1438 1439
         * 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)
1440 1441
         */
        if (!ipdef->nranges && ipdef->nhosts) {
1442
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
1443 1444
            if (!bridgeaddr)
                goto cleanup;
1445 1446 1447
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static",
                              bridgeaddr);
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1448
                virBufferAsprintf(&configbuf, ",%d", prefix);
1449
            virBufferAddLit(&configbuf, "\n");
1450 1451
            VIR_FREE(bridgeaddr);
        }
1452

G
Gene Czarcinski 已提交
1453 1454
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1455

G
Gene Czarcinski 已提交
1456 1457
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
1458
            if (ipdef->nranges || ipdef->nhosts) {
1459
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1460 1461
                virBufferAddLit(&configbuf, "dhcp-authoritative\n");
            }
1462

G
Gene Czarcinski 已提交
1463
            if (ipdef->tftproot) {
1464 1465
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1466
            }
1467

G
Gene Czarcinski 已提交
1468 1469 1470
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1471

1472
                    if (!bootserver)
G
Gene Czarcinski 已提交
1473
                        goto cleanup;
1474
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1475
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1476 1477
                    VIR_FREE(bootserver);
                } else {
1478
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1479 1480 1481 1482 1483
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1484

1485
    if (nbleases > 0)
1486
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1487

G
Gene Czarcinski 已提交
1488 1489
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1490
        goto cleanup;
G
Gene Czarcinski 已提交
1491 1492 1493 1494 1495 1496

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

1500 1501
    /* Likewise, always create this file and put it on the
     * commandline, to allow for runtime additions.
G
Gene Czarcinski 已提交
1502
     */
1503 1504 1505 1506
    if (wantDNS) {
        virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
                          dctx->addnhostsfile->path);
    }
G
Gene Czarcinski 已提交
1507 1508 1509

    /* Are we doing RA instead of radvd? */
    if (DNSMASQ_RA_SUPPORT(caps)) {
1510
        if (ipv6def) {
1511
            virBufferAddLit(&configbuf, "enable-ra\n");
1512
        } else {
1513
            for (i = 0;
1514
                 (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1515
                 i++) {
G
Gene Czarcinski 已提交
1516 1517 1518 1519
                if (!(ipdef->nranges || ipdef->nhosts)) {
                    char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
                    if (!bridgeaddr)
                        goto cleanup;
1520 1521
                    virBufferAsprintf(&configbuf,
                                      "dhcp-range=%s,ra-only\n", bridgeaddr);
G
Gene Czarcinski 已提交
1522 1523
                    VIR_FREE(bridgeaddr);
                }
1524
            }
1525
        }
1526 1527
    }

1528 1529 1530
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1531
    ret = 0;
G
Gene Czarcinski 已提交
1532

1533
 cleanup:
1534 1535
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1536
    virBufferFreeAndReset(&configbuf);
1537
    return ret;
1538 1539
}

1540

1541
/* build the dnsmasq command line */
1542 1543
static int ATTRIBUTE_NONNULL(3)
networkBuildDhcpDaemonCommandLine(virNetworkDriverStatePtr driver,
1544
                                  virNetworkObjPtr obj,
1545
                                  virCommandPtr *cmdout,
1546 1547
                                  char *pidfile,
                                  dnsmasqContext *dctx)
1548
{
1549
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1550
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1551
    virCommandPtr cmd = NULL;
G
Gene Czarcinski 已提交
1552
    int ret = -1;
1553 1554
    char *configfile = NULL;
    char *configstr = NULL;
1555
    char *leaseshelper_path = NULL;
1556

1557
    virNetworkObjSetDnsmasqPid(obj, -1);
1558

1559
    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
1560
                                   dctx, dnsmasq_caps) < 0)
1561 1562 1563 1564 1565
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1566
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
1567 1568 1569 1570 1571
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1572 1573
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1574 1575 1576
        goto cleanup;
    }

1577 1578
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1579
                                                  abs_topbuilddir "/src",
1580 1581 1582
                                                  LIBEXECDIR)))
        goto cleanup;

1583
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1584
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1585 1586
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1587
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1588
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", def->bridge);
1589

1590
    *cmdout = cmd;
1591
    ret = 0;
1592
 cleanup:
1593
    virObjectUnref(dnsmasq_caps);
1594 1595
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1596
    VIR_FREE(leaseshelper_path);
1597 1598 1599
    return ret;
}

1600

1601
static int
1602
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1603
                       virNetworkObjPtr obj)
1604
{
1605
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1606 1607 1608
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1609 1610
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
1611
    pid_t dnsmasqPid;
1612
    int ret = -1;
1613
    dnsmasqContext *dctx = NULL;
1614

1615
    /* see if there are any IP addresses that need a dhcp server */
1616
    i = 0;
1617
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i))) {
1618
        i++;
1619 1620 1621 1622
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1623 1624 1625 1626 1627 1628
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1629
    if (!needDnsmasq && def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1630
        /* no DHCP services needed, and user disabled DNS service */
1631 1632 1633 1634
        ret = 0;
        goto cleanup;
    }

1635
    if (virFileMakePath(driver->pidDir) < 0) {
1636
        virReportSystemError(errno,
1637
                             _("cannot create directory %s"),
1638
                             driver->pidDir);
1639
        goto cleanup;
1640 1641
    }

1642
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, def->name)))
1643
        goto cleanup;
1644

1645
    if (virFileMakePath(driver->dnsmasqStateDir) < 0) {
1646
        virReportSystemError(errno,
1647
                             _("cannot create directory %s"),
1648
                             driver->dnsmasqStateDir);
1649 1650 1651
        goto cleanup;
    }

1652
    dctx = dnsmasqContextNew(def->name, driver->dnsmasqStateDir);
1653 1654 1655
    if (dctx == NULL)
        goto cleanup;

1656
    if (networkDnsmasqCapsRefresh(driver) < 0)
1657
        goto cleanup;
1658

1659
    ret = networkBuildDhcpDaemonCommandLine(driver, obj, &cmd, pidfile, dctx);
1660 1661 1662 1663 1664
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1665
        goto cleanup;
1666

G
Guido Günther 已提交
1667
    ret = virCommandRun(cmd, NULL);
1668
    if (ret < 0)
1669 1670 1671
        goto cleanup;

    /*
1672 1673 1674 1675 1676
     * 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
1677 1678
     */

1679
    ret = virPidFileRead(driver->pidDir, def->name, &dnsmasqPid);
1680
    if (ret < 0)
1681
        goto cleanup;
1682
    virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
1683

1684
    ret = 0;
1685
 cleanup:
1686
    VIR_FREE(pidfile);
1687
    virCommandFree(cmd);
1688
    dnsmasqContextFree(dctx);
1689 1690 1691
    return ret;
}

1692

1693 1694
/* networkRefreshDhcpDaemon:
 *  Update dnsmasq config files, then send a SIGHUP so that it rereads
G
Gene Czarcinski 已提交
1695 1696
 *  them.   This only works for the dhcp-hostsfile and the
 *  addn-hosts file.
1697 1698 1699
 *
 *  Returns 0 on success, -1 on failure.
 */
1700
static int
1701
networkRefreshDhcpDaemon(virNetworkDriverStatePtr driver,
1702
                         virNetworkObjPtr obj)
1703
{
1704
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1705 1706
    int ret = -1;
    size_t i;
1707
    pid_t dnsmasqPid;
1708
    virNetworkIPDefPtr ipdef, ipv4def, ipv6def;
1709
    dnsmasqContext *dctx = NULL;
1710

G
Gene Czarcinski 已提交
1711
    /* if no IP addresses specified, nothing to do */
1712
    if (!virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1713 1714
        return 0;

1715
    /* if there's no running dnsmasq, just start it */
1716 1717
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid <= 0 || (kill(dnsmasqPid, 0) < 0))
1718
        return networkStartDhcpDaemon(driver, obj);
1719

1720 1721
    VIR_INFO("Refreshing dnsmasq for network %s", def->bridge);
    if (!(dctx = dnsmasqContextNew(def->name,
1722
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1723
        goto cleanup;
1724
    }
G
Gene Czarcinski 已提交
1725 1726 1727 1728 1729 1730

    /* 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;
1731
    for (i = 0;
1732
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
1733
         i++) {
G
Gene Czarcinski 已提交
1734 1735
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1736 1737
    }

G
Gene Czarcinski 已提交
1738
    ipv6def = NULL;
1739
    for (i = 0;
1740
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1741
         i++) {
G
Gene Czarcinski 已提交
1742 1743
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1744 1745
    }

G
Gene Czarcinski 已提交
1746
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1747
        goto cleanup;
G
Gene Czarcinski 已提交
1748 1749

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

1752
    if (networkBuildDnsmasqHostsList(dctx, &def->dns) < 0)
J
Ján Tomko 已提交
1753
        goto cleanup;
1754 1755

    if ((ret = dnsmasqSave(dctx)) < 0)
1756
        goto cleanup;
1757

1758 1759
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    ret = kill(dnsmasqPid, SIGHUP);
1760
 cleanup:
1761 1762 1763 1764
    dnsmasqContextFree(dctx);
    return ret;
}

1765

1766 1767 1768 1769 1770 1771 1772 1773
/* 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
1774
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1775
                         virNetworkObjPtr obj)
1776
{
1777
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1778 1779
    pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);

1780
    /* if there is a running dnsmasq, kill it */
1781
    if (dnsmasqPid > 0) {
1782
        networkKillDaemon(dnsmasqPid, "dnsmasq", def->name);
1783
        virNetworkObjSetDnsmasqPid(obj, -1);
1784
    }
1785
    /* now start dnsmasq if it should be started */
1786
    return networkStartDhcpDaemon(driver, obj);
1787 1788
}

1789

G
Gene Czarcinski 已提交
1790 1791 1792 1793 1794 1795
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";

1796
static int
1797
networkRadvdConfContents(virNetworkObjPtr obj,
1798
                         char **configstr)
1799
{
1800
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
E
Eric Blake 已提交
1801
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1802 1803
    int ret = -1;
    size_t i;
1804
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1805
    bool v6present = false, dhcp6 = false;
1806 1807

    *configstr = NULL;
1808

G
Gene Czarcinski 已提交
1809
    /* Check if DHCPv6 is needed */
1810
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
G
Gene Czarcinski 已提交
1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
        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;
    }

1824 1825 1826
    /* create radvd config file appropriate for this network;
     * IgnoreIfMissing allows radvd to start even when the bridge is down
     */
1827
    virBufferAsprintf(&configbuf, "interface %s\n"
1828 1829
                      "{\n"
                      "  AdvSendAdvert on;\n"
1830
                      "  IgnoreIfMissing on;\n"
G
Gene Czarcinski 已提交
1831 1832
                      "  AdvManagedFlag %s;\n"
                      "%s",
1833
                      def->bridge,
G
Gene Czarcinski 已提交
1834 1835
                      dhcp6 ? "on" : "off",
                      dhcp6 ? "\n" : radvd1);
1836 1837

    /* add a section for each IPv6 address in the config */
1838
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
1839 1840 1841
        int prefix;
        char *netaddr;

1842
        prefix = virNetworkIPDefPrefix(ipdef);
1843
        if (prefix < 0) {
1844 1845
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1846
                           def->bridge);
1847 1848
            goto cleanup;
        }
1849
        if (!(netaddr = virSocketAddrFormat(&ipdef->address)))
1850
            goto cleanup;
1851
        virBufferAsprintf(&configbuf,
1852
                          "  prefix %s/%d\n"
G
Gene Czarcinski 已提交
1853 1854 1855
                          "  {\n%s  };\n",
                          netaddr, prefix,
                          dhcp6 ? radvd2 : radvd3);
1856 1857 1858
        VIR_FREE(netaddr);
    }

1859
    virBufferAddLit(&configbuf, "};\n");
1860

1861
    if (virBufferCheckError(&configbuf) < 0)
1862
        goto cleanup;
1863

1864 1865
    *configstr = virBufferContentAndReset(&configbuf);

1866
    ret = 0;
1867
 cleanup:
1868 1869 1870 1871
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1872

1873
/* write file and return its name (which must be freed by caller) */
1874
static int
1875
networkRadvdConfWrite(virNetworkDriverStatePtr driver,
1876
                      virNetworkObjPtr obj,
1877
                      char **configFile)
1878
{
1879
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1880 1881 1882 1883 1884 1885 1886 1887 1888
    int ret = -1;
    char *configStr = NULL;
    char *myConfigFile = NULL;

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

1889
    if (networkRadvdConfContents(obj, &configStr) < 0)
1890 1891 1892 1893
        goto cleanup;

    if (!configStr) {
        ret = 0;
1894 1895 1896 1897
        goto cleanup;
    }

    /* construct the filename */
1898
    if (!(*configFile = networkRadvdConfigFileName(driver, def->name)))
1899 1900
        goto cleanup;
    /* write the file */
1901
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1902 1903
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1904 1905 1906 1907 1908
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1909
 cleanup:
1910 1911 1912 1913 1914
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

1915

1916
static int
1917
networkStartRadvd(virNetworkDriverStatePtr driver,
1918
                  virNetworkObjPtr obj)
1919
{
1920
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1921
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1922
    pid_t radvdPid;
1923 1924 1925 1926 1927 1928
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

1929
    virNetworkObjSetRadvdPid(obj, -1);
1930

G
Gene Czarcinski 已提交
1931
    /* Is dnsmasq handling RA? */
1932
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
1933 1934 1935 1936
        ret = 0;
        goto cleanup;
    }

1937
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
1938 1939 1940 1941 1942 1943 1944 1945 1946 1947
        /* 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);
1948 1949 1950
        goto cleanup;
    }

1951
    if (virFileMakePath(driver->pidDir) < 0) {
1952 1953
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1954
                             driver->pidDir);
1955 1956
        goto cleanup;
    }
1957
    if (virFileMakePath(driver->radvdStateDir) < 0) {
1958 1959
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1960
                             driver->radvdStateDir);
1961 1962 1963 1964
        goto cleanup;
    }

    /* construct pidfile name */
1965
    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
1966
        goto cleanup;
1967
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
1968 1969
        goto cleanup;

1970
    if (networkRadvdConfWrite(driver, obj, &configfile) < 0)
1971 1972
        goto cleanup;

1973 1974 1975 1976
    /* 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
1977
     * virPidFileRead() below will fail if we use them).
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992
     * 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;

1993
    if (virPidFileRead(driver->pidDir, radvdpidbase, &radvdPid) < 0)
1994
        goto cleanup;
1995
    virNetworkObjSetRadvdPid(obj, radvdPid);
1996 1997

    ret = 0;
1998
 cleanup:
1999
    virObjectUnref(dnsmasq_caps);
2000 2001 2002 2003 2004 2005 2006
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

2007

2008
static int
2009
networkRefreshRadvd(virNetworkDriverStatePtr driver,
2010
                    virNetworkObjPtr obj)
2011
{
2012
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2013
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
2014
    char *radvdpidbase;
2015
    pid_t radvdPid;
G
Gene Czarcinski 已提交
2016 2017

    /* Is dnsmasq handling RA? */
2018 2019
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
        virObjectUnref(dnsmasq_caps);
2020 2021
        radvdPid = virNetworkObjGetRadvdPid(obj);
        if (radvdPid <= 0)
G
Gene Czarcinski 已提交
2022 2023
            return 0;
        /* radvd should not be running but in case it is */
2024 2025
        if ((networkKillDaemon(radvdPid, "radvd", def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(def->name))
G
Gene Czarcinski 已提交
2026
             != NULL)) {
2027
            virPidFileDelete(driver->pidDir, radvdpidbase);
G
Gene Czarcinski 已提交
2028 2029
            VIR_FREE(radvdpidbase);
        }
2030
        virNetworkObjSetRadvdPid(obj, -1);
G
Gene Czarcinski 已提交
2031 2032
        return 0;
    }
2033
    virObjectUnref(dnsmasq_caps);
G
Gene Czarcinski 已提交
2034

2035
    /* if there's no running radvd, just start it */
2036 2037
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid <= 0 || (kill(radvdPid, 0) < 0))
2038
        return networkStartRadvd(driver, obj);
2039

2040
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2041 2042 2043 2044
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

2045
    if (networkRadvdConfWrite(driver, obj, NULL) < 0)
2046 2047
        return -1;

2048
    return kill(radvdPid, SIGHUP);
2049 2050
}

2051

2052 2053
#if 0
/* currently unused, so it causes a build error unless we #if it out */
2054
static int
2055
networkRestartRadvd(virNetworkObjPtr obj)
2056
{
2057
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2058
    char *radvdpidbase;
2059
    pid_t radvdPid = virNeworkObjGetRadvdPid(obj);
2060 2061

    /* if there is a running radvd, kill it */
2062
    if (radvdPid > 0) {
2063 2064 2065 2066
        /* 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).
         */
2067 2068
        if ((networkKillDaemon(radvdPid, "radvd", def->name) >= 0) &&
            ((radvdpidbase = networkRadvdPidfileBasename(def->name))
2069
             != NULL)) {
2070
            virPidFileDelete(driver->pidDir, radvdpidbase);
2071 2072
            VIR_FREE(radvdpidbase);
        }
2073
        virNetworkObjSetRadvdPid(obj, -1);
2074 2075
    }
    /* now start radvd if it should be started */
2076
    return networkStartRadvd(obj);
2077 2078 2079
}
#endif /* #if 0 */

2080

2081
static int
2082
networkRefreshDaemonsHelper(virNetworkObjPtr obj,
2083
                            void *opaque)
2084
{
2085
    virNetworkDefPtr def;
2086
    virNetworkDriverStatePtr driver = opaque;
2087

2088
    virObjectLock(obj);
2089
    def = virNetworkObjGetDef(obj);
2090
    if (virNetworkObjIsActive(obj) &&
2091 2092 2093 2094
        ((def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
         (def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
         (def->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
         (def->forward.type == VIR_NETWORK_FORWARD_OPEN))) {
2095 2096 2097 2098 2099 2100
        /* 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.
         */
2101 2102
        networkRefreshDhcpDaemon(driver, obj);
        networkRefreshRadvd(driver, obj);
2103
    }
2104
    virObjectUnlock(obj);
2105 2106 2107
    return 0;
}

2108

2109 2110 2111 2112
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2113
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2114 2115
{
    VIR_INFO("Refreshing network daemons");
2116 2117
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2118
                             driver);
2119
}
2120

2121

2122
static int
2123
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
2124 2125
                                 void *opaque ATTRIBUTE_UNUSED)
{
2126
    virNetworkDefPtr def;
2127

2128
    virObjectLock(obj);
2129
    def = virNetworkObjGetDef(obj);
2130
    if (virNetworkObjIsActive(obj) &&
2131 2132 2133
        ((def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
         (def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
         (def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
2134 2135 2136 2137
        /* 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.
2138
         */
2139 2140
        networkRemoveFirewallRules(def);
        if (networkAddFirewallRules(def) < 0) {
2141
            /* failed to add but already logged */
2142 2143
        }
    }
2144
    virObjectUnlock(obj);
2145
    return 0;
2146 2147
}

2148

2149
static void
2150
networkReloadFirewallRules(virNetworkDriverStatePtr driver)
2151
{
2152
    VIR_INFO("Reloading iptables rules");
2153 2154 2155
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2156 2157
}

2158

2159
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
2160
static int
2161 2162
networkEnableIPForwarding(bool enableIPv4,
                          bool enableIPv6)
2163
{
2164
    int ret = 0;
2165 2166 2167 2168
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
2169
                           &enabled, sizeof(enabled));
2170 2171
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
2172
                           &enabled, sizeof(enabled));
2173
#else
2174
    if (enableIPv4)
2175
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv4/ip_forward", "1\n", 0);
2176
    if (enableIPv6 && ret == 0)
2177 2178
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv6/conf/all/forwarding", "1\n", 0);

2179
#endif
2180
    return ret;
2181 2182
}

2183

2184
static int
2185
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2186
{
2187
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2188 2189
    char *field = NULL;
    int ret = -1;
2190
    bool enableIPv6 = !!virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2191

2192 2193 2194 2195 2196
    /* 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",
2197
                    def->bridge) < 0)
2198
       goto cleanup;
2199

2200 2201
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2202
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2203
                      def->bridge);
2204 2205 2206
        ret = 0;
        goto cleanup;
    }
2207

2208 2209 2210
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2211
                               "on bridge %s"), field, def->bridge);
2212
        goto cleanup;
2213
    }
2214
    VIR_FREE(field);
2215

2216 2217
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2218 2219 2220 2221 2222 2223
     */

    /* 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",
2224
                    def->bridge) < 0)
2225 2226
        goto cleanup;

2227
    if (virFileWriteStr(field, "0", 0) < 0) {
2228
        virReportSystemError(errno,
2229 2230 2231 2232 2233
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

2234 2235 2236 2237
    /* 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",
2238
                    def->bridge) < 0)
2239 2240
        goto cleanup;

2241
    if (virFileWriteStr(field, "0", 0) < 0) {
2242
        virReportSystemError(errno,
2243
                             _("cannot disable %s"), field);
2244 2245 2246 2247
        goto cleanup;
    }

    ret = 0;
2248
 cleanup:
2249 2250 2251 2252
    VIR_FREE(field);
    return ret;
}

2253

2254
/* add an IP address to a bridge */
2255
static int
2256
networkAddAddrToBridge(virNetworkObjPtr obj,
2257
                       virNetworkIPDefPtr ipdef)
2258
{
2259
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2260
    int prefix = virNetworkIPDefPrefix(ipdef);
2261 2262

    if (prefix < 0) {
2263 2264
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2265
                       def->bridge);
2266 2267 2268
        return -1;
    }

2269
    if (virNetDevIPAddrAdd(def->bridge, &ipdef->address, NULL, prefix) < 0)
2270 2271 2272 2273 2274
        return -1;

    return 0;
}

2275 2276

static int
2277
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2278 2279
                                      const char *macTapIfName)
{
2280 2281
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    const char *brname = def->bridge;
2282 2283

    if (brname &&
2284
        def->macTableManager == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297
        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;
}


2298 2299
/* add an IP (static) route to a bridge */
static int
2300
networkAddRouteToBridge(virNetworkObjPtr obj,
2301
                        virNetDevIPRoutePtr routedef)
2302
{
2303
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2304 2305 2306 2307
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2308 2309 2310 2311 2312

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

2317
    if (virNetDevIPRouteAdd(def->bridge, addr, prefix, gateway, metric) < 0)
2318
        return -1;
2319

2320 2321 2322
    return 0;
}

2323
static int
2324
networkWaitDadFinish(virNetworkObjPtr obj)
2325
{
2326
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2327
    virNetworkIPDefPtr ipdef;
2328 2329 2330 2331
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

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

2334
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, naddrs))) {
2335 2336 2337 2338 2339
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2340
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2341 2342 2343 2344

 cleanup:
    VIR_FREE(addrs);
    VIR_DEBUG("Finished waiting for IPv6 DAD on network %s with status %d",
2345
              def->name, ret);
2346 2347 2348
    return ret;
}

2349

2350
static int
2351
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
2352
                           virNetworkObjPtr obj)
2353
{
2354
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2355
    size_t i;
2356
    bool v4present = false, v6present = false;
2357
    virErrorPtr save_err = NULL;
2358
    virNetworkIPDefPtr ipdef;
2359
    virNetDevIPRoutePtr routedef;
2360
    char *macTapIfName = NULL;
2361
    virMacMapPtr macmap;
M
Michal Privoznik 已提交
2362
    char *macMapFile = NULL;
2363
    int tapfd = -1;
2364
    pid_t dnsmasqPid;
2365

2366
    /* Check to see if any network IP collides with an existing route */
2367
    if (networkCheckRouteCollision(def) < 0)
2368 2369
        return -1;

2370
    /* Create and configure the bridge device */
2371
    if (!def->bridge) {
2372 2373 2374 2375 2376 2377 2378 2379 2380 2381
        /* 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"),
2382
                       def->name);
2383 2384
        return -1;
    }
2385
    if (virNetDevBridgeCreate(def->bridge) < 0)
2386 2387
        return -1;

2388
    if (def->mac_specified) {
2389 2390 2391 2392 2393 2394
        /* 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.
         */
2395
        macTapIfName = networkBridgeDummyNicName(def->bridge);
2396
        if (!macTapIfName)
2397
            goto err0;
2398
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2399 2400
        if (virNetDevTapCreateInBridgePort(def->bridge,
                                           &macTapIfName, &def->mac,
2401
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2402
                                           NULL, def->mtu, NULL,
2403 2404 2405
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2406 2407 2408 2409 2410
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

2411
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
2412
                                         def->bridge)) ||
2413
        !(macmap = virMacMapNew(macMapFile)))
M
Michal Privoznik 已提交
2414 2415
        goto err1;

2416 2417
    virNetworkObjSetMacMap(obj, macmap);

2418
    /* Set bridge options */
2419 2420 2421 2422

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

2426
    if (virNetDevBridgeSetSTP(def->bridge, def->stp ? true : false) < 0)
2427
        goto err1;
2428

2429 2430 2431
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2432
    if (networkSetIPv6Sysctls(obj) < 0)
2433
        goto err1;
2434

2435
    /* Add "once per network" rules */
2436 2437
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(def) < 0)
2438 2439
        goto err1;

2440
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i)); i++) {
2441
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2442
            v4present = true;
2443
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2444
            v6present = true;
2445

2446
        /* Add the IP address/netmask to the bridge */
2447
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2448
            goto err2;
2449 2450
    }

2451
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2452 2453
        goto err2;

2454
    /* Bring up the bridge interface */
2455
    if (virNetDevSetOnline(def->bridge, 1) < 0)
2456
        goto err2;
2457

2458
    for (i = 0; i < def->nroutes; i++) {
2459 2460
        virSocketAddrPtr gateway = NULL;

2461
        routedef = def->routes[i];
2462
        gateway = virNetDevIPRouteGetGateway(routedef);
2463

2464 2465 2466
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2467
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2468
            if (networkAddRouteToBridge(obj, routedef) < 0) {
2469 2470 2471 2472 2473 2474
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2475
    /* If forward.type != NONE, turn on global IP forwarding */
2476
    if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2477
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2478 2479 2480 2481 2482 2483 2484
            goto err3; /* Precise error message already provided */

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

2487

2488
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2489
    if ((v4present || v6present) &&
2490
        networkStartDhcpDaemon(driver, obj) < 0)
2491
        goto err3;
2492

2493
    /* start radvd if there are any ipv6 addresses */
2494
    if (v6present && networkStartRadvd(driver, obj) < 0)
2495 2496
        goto err4;

2497 2498 2499
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2500
    if (v6present && networkWaitDadFinish(obj) < 0)
2501 2502 2503 2504
        goto err4;

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2505 2506 2507 2508 2509 2510 2511
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
            goto err4;
        VIR_FORCE_CLOSE(tapfd);
    }

2512
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
2513 2514
        goto err5;

2515
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2516
    VIR_FREE(macMapFile);
2517 2518 2519

    return 0;

2520
 err5:
2521 2522
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
2523

2524 2525 2526 2527
 err4:
    if (!save_err)
        save_err = virSaveLastError();

2528 2529 2530 2531
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0) {
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2532 2533
    }

2534 2535 2536
 err3:
    if (!save_err)
        save_err = virSaveLastError();
2537
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2538

2539 2540 2541
 err2:
    if (!save_err)
        save_err = virSaveLastError();
2542 2543
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2544 2545

 err1:
2546 2547 2548
    if (!save_err)
        save_err = virSaveLastError();

H
Hu Tao 已提交
2549
    if (macTapIfName) {
2550
        VIR_FORCE_CLOSE(tapfd);
2551
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2552 2553
        VIR_FREE(macTapIfName);
    }
M
Michal Privoznik 已提交
2554
    VIR_FREE(macMapFile);
2555 2556

 err0:
2557 2558
    if (!save_err)
        save_err = virSaveLastError();
2559
    ignore_value(virNetDevBridgeDelete(def->bridge));
2560

2561 2562 2563 2564
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
2565
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2566 2567 2568
    return -1;
}

2569

2570 2571
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2572
                              virNetworkObjPtr obj)
2573
{
2574
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2575 2576 2577
    pid_t radvdPid;
    pid_t dnsmasqPid;

2578 2579
    if (def->bandwidth)
        virNetDevBandwidthClear(def->bridge);
2580

2581
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2582

2583 2584
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2585 2586
        char *radvdpidbase;

2587
        kill(radvdPid, SIGTERM);
2588
        /* attempt to delete the pidfile we created */
2589
        if ((radvdpidbase = networkRadvdPidfileBasename(def->name))) {
2590
            virPidFileDelete(driver->pidDir, radvdpidbase);
2591 2592 2593 2594
            VIR_FREE(radvdpidbase);
        }
    }

2595 2596 2597
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2598

2599 2600
    if (def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(def->bridge);
2601
        if (macTapIfName) {
2602
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2603 2604 2605 2606
            VIR_FREE(macTapIfName);
        }
    }

2607
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2608

2609 2610
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2611

2612
    ignore_value(virNetDevBridgeDelete(def->bridge));
2613

2614
    /* See if its still alive and really really kill it */
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625
    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);
2626

2627 2628 2629
    return 0;
}

2630

2631
static int
2632
networkStartNetworkBridge(virNetworkObjPtr obj)
2633 2634 2635 2636 2637
{
    /* 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.
     */
2638
    return networkStartHandleMACTableManagerMode(obj, NULL);
2639 2640
}

2641

2642
static int
2643
networkShutdownNetworkBridge(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2644 2645 2646 2647 2648 2649 2650 2651 2652
{
    /* 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;
}


2653 2654 2655 2656 2657 2658 2659 2660 2661
/* 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;
2662
    unsigned int maxVirtFns = 0;
2663 2664 2665 2666 2667 2668
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2669 2670 2671
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2672 2673
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719
        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];

        switch (netdef->forward.type) {
        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:
2720
        case VIR_NETWORK_FORWARD_OPEN:
2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760
        case VIR_NETWORK_FORWARD_LAST:
            /* by definition these will never be encountered here */
            break;
        }
    }

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


2761
static int
2762
networkStartNetworkExternal(virNetworkObjPtr obj)
2763 2764
{
    /* put anything here that needs to be done each time a network of
2765
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2766 2767 2768
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2769
    return networkCreateInterfacePool(virNetworkObjGetDef(obj));
2770 2771
}

2772 2773

static int
2774
networkShutdownNetworkExternal(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2775 2776
{
    /* put anything here that needs to be done each time a network of
2777
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2778 2779 2780 2781 2782 2783
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2784

2785
static int
2786
networkStartNetwork(virNetworkDriverStatePtr driver,
2787
                    virNetworkObjPtr obj)
2788
{
2789
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2790 2791
    int ret = -1;

2792
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2793

2794
    if (virNetworkObjIsActive(obj)) {
2795 2796
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2797
        return ret;
2798 2799
    }

2800 2801 2802
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2803
    if (virNetworkObjSetDefTransient(obj, true) < 0)
2804
        goto cleanup;
2805

2806 2807
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2808
    if (networkRunHook(obj, NULL, NULL,
2809 2810 2811 2812
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2813
    switch (def->forward.type) {
2814 2815 2816 2817

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2818
    case VIR_NETWORK_FORWARD_OPEN:
2819
        if (networkStartNetworkVirtual(driver, obj) < 0)
2820
            goto cleanup;
2821 2822 2823
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2824
        if (def->bridge) {
2825
            if (networkStartNetworkBridge(obj) < 0)
2826 2827 2828 2829 2830 2831 2832
                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).
         */
2833 2834
        ATTRIBUTE_FALLTHROUGH;

2835 2836 2837
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2838
    case VIR_NETWORK_FORWARD_HOSTDEV:
2839
        if (networkStartNetworkExternal(obj) < 0)
2840
            goto cleanup;
2841 2842 2843
        break;
    }

2844
    /* finally we can call the 'started' hook script if any */
2845
    if (networkRunHook(obj, NULL, NULL,
2846 2847 2848 2849
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2850 2851 2852
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2853
    VIR_DEBUG("Writing network status to disk");
2854
    if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0)
2855
        goto cleanup;
2856

2857
    virNetworkObjSetActive(obj, true);
2858
    VIR_INFO("Network '%s' started up", def->name);
2859
    ret = 0;
2860

2861
 cleanup:
2862
    if (ret < 0) {
2863
        virNetworkObjUnsetDefTransient(obj);
2864 2865
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
2866
        networkShutdownNetwork(driver, obj);
2867 2868 2869 2870 2871 2872 2873
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2874

2875 2876
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
2877
                       virNetworkObjPtr obj)
2878
{
2879
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2880 2881 2882
    int ret = 0;
    char *stateFile;

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

2885
    if (!virNetworkObjIsActive(obj))
2886 2887
        return 0;

2888
    stateFile = virNetworkConfigFile(driver->stateDir, def->name);
2889 2890 2891 2892 2893 2894
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2895
    switch (def->forward.type) {
2896 2897 2898 2899

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2900
    case VIR_NETWORK_FORWARD_OPEN:
2901
        ret = networkShutdownNetworkVirtual(driver, obj);
2902 2903 2904
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2905
        if (def->bridge) {
2906
            ret = networkShutdownNetworkBridge(obj);
2907 2908 2909 2910 2911 2912
            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).
         */
2913 2914
        ATTRIBUTE_FALLTHROUGH;

2915 2916 2917
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2918
    case VIR_NETWORK_FORWARD_HOSTDEV:
2919
        ret = networkShutdownNetworkExternal(obj);
2920 2921 2922
        break;
    }

2923
    /* now that we know it's stopped call the hook if present */
2924
    networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2925 2926
                   VIR_HOOK_SUBOP_END);

2927
    virNetworkObjSetActive(obj, false);
2928
    virNetworkObjUnsetDefTransient(obj);
2929
    return ret;
2930 2931 2932
}


2933 2934 2935
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
2936
{
2937
    virNetworkDriverStatePtr driver = networkGetDriver();
2938
    virNetworkObjPtr obj;
2939
    virNetworkDefPtr def;
2940
    virNetworkPtr net = NULL;
2941

2942 2943
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
2944 2945
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
2946
        virReportError(VIR_ERR_NO_NETWORK,
2947 2948
                       _("no network with matching uuid '%s'"),
                       uuidstr);
2949
        goto cleanup;
2950
    }
2951
    def = virNetworkObjGetDef(obj);
2952

2953
    if (virNetworkLookupByUUIDEnsureACL(conn, def) < 0)
2954 2955
        goto cleanup;

2956
    net = virGetNetwork(conn, def->name, def->uuid);
2957

2958
 cleanup:
2959 2960
    virNetworkObjEndAPI(&obj);
    return net;
2961 2962
}

2963 2964 2965 2966

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
2967
{
2968
    virNetworkDriverStatePtr driver = networkGetDriver();
2969
    virNetworkObjPtr obj;
2970
    virNetworkDefPtr def;
2971
    virNetworkPtr net = NULL;
2972

2973 2974
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
2975 2976
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
2977
        goto cleanup;
2978
    }
2979
    def = virNetworkObjGetDef(obj);
2980

2981
    if (virNetworkLookupByNameEnsureACL(conn, def) < 0)
2982 2983
        goto cleanup;

2984
    net = virGetNetwork(conn, def->name, def->uuid);
2985

2986
 cleanup:
2987 2988
    virNetworkObjEndAPI(&obj);
    return net;
2989 2990
}

2991 2992 2993

static int
networkConnectNumOfNetworks(virConnectPtr conn)
2994
{
2995
    virNetworkDriverStatePtr driver = networkGetDriver();
2996
    int nactive;
2997

2998 2999 3000
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

3001 3002 3003 3004
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
3005

3006 3007 3008
    return nactive;
}

3009 3010 3011 3012

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
3013
                           int maxnames)
3014 3015
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3016
    int got = 0;
3017

3018 3019 3020
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

3021
    got = virNetworkObjListGetNames(driver->networks,
3022
                                    true, names, maxnames,
3023 3024
                                    virConnectListNetworksCheckACL,
                                    conn);
3025

3026 3027 3028
    return got;
}

3029 3030 3031

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
3032
{
3033
    virNetworkDriverStatePtr driver = networkGetDriver();
3034
    int ninactive = 0;
3035

3036 3037 3038
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3039 3040 3041 3042
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
3043

3044 3045 3046
    return ninactive;
}

3047 3048 3049 3050

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
3051
                                  int maxnames)
3052 3053
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3054
    int got = 0;
3055

3056 3057 3058
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3059
    got = virNetworkObjListGetNames(driver->networks,
3060
                                    false, names, maxnames,
3061 3062
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
3063 3064 3065
    return got;
}

3066

3067
static int
3068 3069 3070
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
3071
{
3072
    virNetworkDriverStatePtr driver = networkGetDriver();
3073 3074 3075 3076
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

3077 3078 3079
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

3080
    ret = virNetworkObjListExport(conn, driver->networks, nets,
3081 3082
                                  virConnectListAllNetworksCheckACL,
                                  flags);
3083

3084
 cleanup:
3085 3086
    return ret;
}
3087

3088

3089 3090 3091 3092 3093 3094 3095 3096
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3097
    virNetworkDriverStatePtr driver = networkGetDriver();
3098 3099 3100 3101 3102 3103
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3104
                                       net, eventID, callback,
3105 3106 3107
                                       opaque, freecb, &ret) < 0)
        ret = -1;

3108
 cleanup:
3109 3110 3111
    return ret;
}

3112

3113 3114 3115 3116
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3117
    virNetworkDriverStatePtr driver = networkGetDriver();
3118 3119 3120 3121 3122
    int ret = -1;

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

3123 3124
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3125
                                        callbackID, true) < 0)
3126 3127 3128
        goto cleanup;

    ret = 0;
3129

3130
 cleanup:
3131 3132 3133
    return ret;
}

3134 3135 3136

static int
networkIsActive(virNetworkPtr net)
3137 3138 3139 3140
{
    virNetworkObjPtr obj;
    int ret = -1;

3141 3142
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3143

3144
    if (virNetworkIsActiveEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3145 3146
        goto cleanup;

3147 3148
    ret = virNetworkObjIsActive(obj);

3149
 cleanup:
3150
    virNetworkObjEndAPI(&obj);
3151 3152 3153
    return ret;
}

3154 3155 3156

static int
networkIsPersistent(virNetworkPtr net)
3157 3158 3159 3160
{
    virNetworkObjPtr obj;
    int ret = -1;

3161 3162
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3163

3164
    if (virNetworkIsPersistentEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3165 3166
        goto cleanup;

3167
    ret = virNetworkObjIsPersistent(obj);
3168

3169
 cleanup:
3170
    virNetworkObjEndAPI(&obj);
3171 3172 3173 3174
    return ret;
}


3175 3176
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
3177 3178 3179
 * 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.
3180 3181 3182 3183 3184 3185 3186 3187
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{

    int ret = -1, id = 0;
    char *newname = NULL;
3188 3189 3190 3191 3192
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3193
        p && p[1] == 'd')
3194
        templ = def->bridge;
3195 3196 3197 3198

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3199 3200 3201 3202 3203
        /* 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).
         */
3204
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3205
              virNetDevExists(newname) == 1)) {
3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238
            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")) {
3239
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256
            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;
}


3257
static int
3258
networkValidate(virNetworkDriverStatePtr driver,
3259
                virNetworkDefPtr def)
3260
{
3261
    size_t i, j;
3262 3263
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3264
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3265
    bool ipv4def = false, ipv6def = false;
3266
    bool bandwidthAllowed = true;
3267
    bool usesInterface = false, usesAddress = false;
3268

3269 3270 3271
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3272 3273 3274
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3275 3276
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
3277 3278
        def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
        def->forward.type == VIR_NETWORK_FORWARD_OPEN) {
3279

3280 3281 3282 3283
        /* 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)
3284 3285 3286
            return -1;

        virNetworkSetBridgeMacAddr(def);
3287 3288
    } else {
        /* 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 3330 3331
        if (def->bandwidth) {
            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;
        }
3332
        bandwidthAllowed = false;
3333 3334
    }

3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347
    /* 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++) {
3348 3349 3350
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

3351
        switch ((virNetworkForwardHostdevDeviceType)iface->type) {
3352 3353
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364

            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;
            }
3365
            break;
3366 3367

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3368
            usesAddress = true;
3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393

            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);
3394
            break;
3395 3396
        }

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

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

3449 3450 3451
    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 已提交
3452 3453
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3454
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3455 3456

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

    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;
            }
        }
    }
3532 3533 3534
    return 0;
}

3535 3536 3537 3538

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3539
{
3540
    virNetworkDriverStatePtr driver = networkGetDriver();
3541
    virNetworkDefPtr newDef;
3542
    virNetworkObjPtr obj = NULL;
3543
    virNetworkDefPtr def;
3544
    virNetworkPtr net = NULL;
3545
    virObjectEventPtr event = NULL;
3546

3547
    if (!(newDef = virNetworkDefParseString(xml)))
3548
        goto cleanup;
3549

3550
    if (virNetworkCreateXMLEnsureACL(conn, newDef) < 0)
3551 3552
        goto cleanup;

3553
    if (networkValidate(driver, newDef) < 0)
J
Ján Tomko 已提交
3554
        goto cleanup;
3555

3556 3557 3558
    /* 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.
3559
     */
3560
    if (!(obj = virNetworkObjAssignDef(driver->networks, newDef,
3561 3562
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3563
        goto cleanup;
3564 3565
    newDef = NULL;
    def = virNetworkObjGetDef(obj);
3566

3567 3568
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3569
        goto cleanup;
3570 3571
    }

3572 3573
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3574 3575
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3576

3577 3578
    VIR_INFO("Creating network '%s'", def->name);
    net = virGetNetwork(conn, def->name, def->uuid);
3579

3580
 cleanup:
3581
    virNetworkDefFree(newDef);
3582 3583
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3584 3585
    virNetworkObjEndAPI(&obj);
    return net;
3586 3587
}

3588 3589 3590 3591

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3592
{
3593
    virNetworkDriverStatePtr driver = networkGetDriver();
3594
    virNetworkDefPtr def = NULL;
3595
    bool freeDef = true;
3596 3597
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3598
    virObjectEventPtr event = NULL;
3599

3600
    if (!(def = virNetworkDefParseString(xml)))
3601
        goto cleanup;
3602

3603 3604 3605
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3606
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3607
        goto cleanup;
3608

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

3612
    /* def was assigned to network object */
3613
    freeDef = false;
3614 3615

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

3628
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3629 3630
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3631

3632
    VIR_INFO("Defining network '%s'", def->name);
3633
    net = virGetNetwork(conn, def->name, def->uuid);
3634

3635
 cleanup:
3636 3637
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3638
    if (freeDef)
J
Ján Tomko 已提交
3639
        virNetworkDefFree(def);
3640 3641
    virNetworkObjEndAPI(&obj);
    return net;
3642 3643
}

3644

3645
static int
3646 3647
networkUndefine(virNetworkPtr net)
{
3648
    virNetworkDriverStatePtr driver = networkGetDriver();
3649
    virNetworkObjPtr obj;
3650
    virNetworkDefPtr def;
3651
    int ret = -1;
3652
    bool active = false;
3653
    virObjectEventPtr event = NULL;
3654

3655
    if (!(obj = networkObjFromNetwork(net)))
3656
        goto cleanup;
3657
    def = virNetworkObjGetDef(obj);
3658

3659
    if (virNetworkUndefineEnsureACL(net->conn, def) < 0)
3660 3661
        goto cleanup;

3662
    if (virNetworkObjIsActive(obj))
3663
        active = true;
3664

3665
    if (!virNetworkObjIsPersistent(obj)) {
3666 3667 3668 3669 3670
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3671
    /* remove autostart link */
3672 3673
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3674
                                  obj) < 0)
3675
        goto cleanup;
3676

3677 3678
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3679 3680
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3681

3682
    VIR_INFO("Undefining network '%s'", def->name);
3683
    if (!active) {
3684
        if (networkRemoveInactive(driver, obj) < 0)
3685
            goto cleanup;
3686 3687 3688 3689 3690
    } else {

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

3694
    ret = 0;
3695

3696
 cleanup:
3697 3698
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3699
    virNetworkObjEndAPI(&obj);
3700
    return ret;
3701 3702
}

3703

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

3721 3722 3723 3724 3725

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3726
    if (!(obj = networkObjFromNetwork(net)))
3727
        goto cleanup;
3728
    def = virNetworkObjGetDef(obj);
3729

3730
    if (virNetworkUpdateEnsureACL(net->conn, def, flags) < 0)
3731 3732
        goto cleanup;

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

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

3756 3757 3758 3759
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
3760 3761 3762
        if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
            def->forward.type == VIR_NETWORK_FORWARD_NAT ||
            def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
3763 3764 3765 3766 3767 3768 3769 3770 3771 3772
            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).
                 */
3773 3774
                if (def->forward.type != VIR_NETWORK_FORWARD_OPEN) {
                    networkRemoveFirewallRules(def);
3775 3776
                    needFirewallRefresh = true;
                }
3777 3778 3779 3780 3781 3782 3783
                break;
            default:
                break;
            }
        }
    }

3784
    /* update the network config in memory/on disk */
3785
    if (virNetworkObjUpdate(obj, command, section, parentIndex, xml, flags) < 0) {
3786
        if (needFirewallRefresh)
3787
            ignore_value(networkAddFirewallRules(def));
3788 3789 3790
        goto cleanup;
    }

3791 3792 3793 3794
    /* @def is replaced */
    def = virNetworkObjGetDef(obj);

    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
3795 3796 3797 3798 3799
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
3800
                                 virNetworkObjGetPersistentDef(obj)) < 0) {
3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813
            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 ||
3814 3815 3816 3817 3818 3819 3820 3821
            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)
3822
             */
3823
            if (networkRestartDhcpDaemon(driver, obj) < 0)
3824 3825
                goto cleanup;

3826 3827 3828 3829 3830 3831 3832 3833
        } 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;

3834
            for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3835
                 i++) {
3836 3837 3838 3839 3840 3841 3842
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3843 3844
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
3845 3846 3847
                goto cleanup;
            }

3848 3849 3850 3851
        } 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.
3852
             */
3853
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
3854 3855 3856 3857 3858 3859 3860 3861
                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.
             */
3862
            if (networkRefreshRadvd(driver, obj) < 0)
3863 3864 3865 3866
                goto cleanup;
        }

        /* save current network state to disk */
3867
        if ((ret = virNetworkObjSaveStatus(driver->stateDir, obj)) < 0)
3868 3869
            goto cleanup;
    }
3870 3871

    /* call the 'updated' network hook script */
3872
    if (networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_UPDATED,
3873 3874 3875
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

3876
    ret = 0;
3877
 cleanup:
3878
    virNetworkObjEndAPI(&obj);
3879 3880 3881
    return ret;
}

3882 3883 3884

static int
networkCreate(virNetworkPtr net)
3885
{
3886
    virNetworkDriverStatePtr driver = networkGetDriver();
3887
    virNetworkObjPtr obj;
3888
    virNetworkDefPtr def;
3889
    int ret = -1;
3890
    virObjectEventPtr event = NULL;
3891

3892
    if (!(obj = networkObjFromNetwork(net)))
3893
        goto cleanup;
3894
    def = virNetworkObjGetDef(obj);
3895

3896
    if (virNetworkCreateEnsureACL(net->conn, def) < 0)
3897 3898
        goto cleanup;

3899
    if ((ret = networkStartNetwork(driver, obj)) < 0)
3900
        goto cleanup;
3901

3902 3903
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3904 3905
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3906

3907
 cleanup:
3908 3909
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3910
    virNetworkObjEndAPI(&obj);
3911
    return ret;
3912 3913
}

3914 3915 3916

static int
networkDestroy(virNetworkPtr net)
3917
{
3918
    virNetworkDriverStatePtr driver = networkGetDriver();
3919
    virNetworkObjPtr obj;
3920
    virNetworkDefPtr def;
3921
    int ret = -1;
3922
    virObjectEventPtr event = NULL;
3923

3924
    if (!(obj = networkObjFromNetwork(net)))
3925
        goto cleanup;
3926
    def = virNetworkObjGetDef(obj);
3927

3928
    if (virNetworkDestroyEnsureACL(net->conn, def) < 0)
3929 3930
        goto cleanup;

3931
    if (!virNetworkObjIsActive(obj)) {
3932
        virReportError(VIR_ERR_OPERATION_INVALID,
3933
                       _("network '%s' is not active"),
3934
                       def->name);
3935 3936 3937
        goto cleanup;
    }

3938
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
3939
        goto cleanup;
3940 3941
    /* @def replaced in virNetworkObjUnsetDefTransient*/
    def = virNetworkObjGetDef(obj);
3942

3943 3944
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3945 3946
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
3947

3948 3949
    if (!virNetworkObjIsPersistent(obj) &&
        networkRemoveInactive(driver, obj) < 0) {
3950 3951
        ret = -1;
        goto cleanup;
3952
    }
3953

3954
 cleanup:
3955 3956
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3957
    virNetworkObjEndAPI(&obj);
3958 3959 3960
    return ret;
}

3961 3962 3963 3964

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
3965
{
3966
    virNetworkObjPtr obj;
3967
    virNetworkDefPtr curDef;
3968
    virNetworkDefPtr def;
3969
    virNetworkDefPtr newDef;
3970
    char *ret = NULL;
3971

3972
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
3973

3974
    if (!(obj = networkObjFromNetwork(net)))
3975
        return ret;
3976 3977
    def = virNetworkObjGetDef(obj);
    newDef = virNetworkObjGetNewDef(obj);
3978

3979
    if (virNetworkGetXMLDescEnsureACL(net->conn, def) < 0)
3980 3981
        goto cleanup;

3982 3983
    if ((flags & VIR_NETWORK_XML_INACTIVE) && newDef)
        curDef = newDef;
3984
    else
3985
        curDef = def;
3986

3987
    ret = virNetworkDefFormat(curDef, flags);
3988

3989
 cleanup:
3990
    virNetworkObjEndAPI(&obj);
3991
    return ret;
3992 3993
}

3994 3995 3996 3997

static char *
networkGetBridgeName(virNetworkPtr net)
{
3998
    virNetworkObjPtr obj;
3999
    virNetworkDefPtr def;
4000 4001
    char *bridge = NULL;

4002
    if (!(obj = networkObjFromNetwork(net)))
4003
        return bridge;
4004
    def = virNetworkObjGetDef(obj);
4005

4006
    if (virNetworkGetBridgeNameEnsureACL(net->conn, def) < 0)
4007 4008
        goto cleanup;

4009
    if (!(def->bridge)) {
4010 4011
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
4012
                       def->name);
4013 4014 4015
        goto cleanup;
    }

4016
    ignore_value(VIR_STRDUP(bridge, def->bridge));
4017

4018
 cleanup:
4019
    virNetworkObjEndAPI(&obj);
4020 4021 4022
    return bridge;
}

4023 4024 4025 4026

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
4027
{
4028
    virNetworkObjPtr obj;
4029
    int ret = -1;
4030

4031
    if (!(obj = networkObjFromNetwork(net)))
4032
        return ret;
4033

4034
    if (virNetworkGetAutostartEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
4035 4036
        goto cleanup;

4037
    *autostart = virNetworkObjIsAutostart(obj) ? 1 : 0;
4038
    ret = 0;
4039

4040
 cleanup:
4041
    virNetworkObjEndAPI(&obj);
4042
    return ret;
4043 4044
}

4045 4046 4047 4048

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
4049
{
4050
    virNetworkDriverStatePtr driver = networkGetDriver();
4051
    virNetworkObjPtr obj;
4052
    virNetworkDefPtr def;
4053
    char *configFile = NULL, *autostartLink = NULL;
4054 4055
    bool new_autostart;
    bool cur_autostart;
4056
    int ret = -1;
4057

4058
    if (!(obj = networkObjFromNetwork(net)))
4059
        goto cleanup;
4060
    def = virNetworkObjGetDef(obj);
4061

4062
    if (virNetworkSetAutostartEnsureACL(net->conn, def) < 0)
4063 4064
        goto cleanup;

4065
    if (!virNetworkObjIsPersistent(obj)) {
4066 4067
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
4068 4069 4070
        goto cleanup;
    }

4071 4072 4073
    new_autostart = (autostart != 0);
    cur_autostart = virNetworkObjIsAutostart(obj);
    if (cur_autostart != new_autostart) {
4074 4075
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir,
                                               def->name)) == NULL)
4076
            goto cleanup;
4077 4078
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir,
                                                  def->name)) == NULL)
4079 4080
            goto cleanup;

4081
        if (new_autostart) {
4082
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
4083
                virReportSystemError(errno,
4084 4085
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
4086 4087
                goto cleanup;
            }
4088

4089
            if (symlink(configFile, autostartLink) < 0) {
4090
                virReportSystemError(errno,
4091
                                     _("Failed to create symlink '%s' to '%s'"),
4092
                                     autostartLink, configFile);
4093 4094 4095
                goto cleanup;
            }
        } else {
4096
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4097
                virReportSystemError(errno,
4098
                                     _("Failed to delete symlink '%s'"),
4099
                                     autostartLink);
4100 4101
                goto cleanup;
            }
4102 4103
        }

4104
        virNetworkObjSetAutostart(obj, new_autostart);
4105
    }
4106

4107
    ret = 0;
4108

4109
 cleanup:
4110 4111
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4112
    virNetworkObjEndAPI(&obj);
4113
    return ret;
4114 4115
}

4116

4117
static int
4118
networkGetDHCPLeases(virNetworkPtr net,
4119 4120 4121
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
4122
{
4123
    virNetworkDriverStatePtr driver = networkGetDriver();
4124 4125 4126
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
4127
    ssize_t size = 0;
4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138
    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;
4139
    virNetworkIPDefPtr ipdef_tmp = NULL;
4140 4141
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
4142
    virNetworkObjPtr obj;
4143
    virNetworkDefPtr def;
4144
    virMacAddr mac_addr;
4145 4146 4147

    virCheckFlags(0, -1);

4148 4149 4150 4151 4152 4153
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4154
    if (!(obj = networkObjFromNetwork(net)))
4155
        return -1;
4156
    def = virNetworkObjGetDef(obj);
4157

4158
    if (virNetworkGetDHCPLeasesEnsureACL(net->conn, def) < 0)
4159
        goto cleanup;
4160 4161

    /* Retrieve custom leases file location */
4162
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, def->bridge);
4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188

    /* Read entire contents */
    if ((custom_lease_file_len = virFileReadAll(custom_lease_file,
                                                VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX,
                                                &lease_entries)) < 0) {
        /* Even though src/network/leaseshelper.c guarantees the existence of
         * leases file (even if no leases are present), and the control reaches
         * here, instead of reporting error, return 0 leases */
        rv = 0;
        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;
        }

        if ((size = virJSONValueArraySize(leases_array)) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("couldn't fetch array of leases"));
            goto error;
        }
    }

4189
    currtime = (long long)time(NULL);
4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205

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

4206
        if (mac && virMacAddrCompare(mac, mac_tmp))
4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237
            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 */
4238 4239
            for (j = 0; j < def->nips; j++) {
                ipdef_tmp = &def->ips[j];
4240 4241 4242 4243 4244 4245 4246 4247

                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)) {
4248
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4249 4250 4251 4252 4253 4254 4255 4256
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
4257
                (VIR_STRDUP(lease->iface, def->bridge) < 0))
4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289
                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);
4290
    VIR_FREE(lease_entries);
4291 4292
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4293

4294
    virNetworkObjEndAPI(&obj);
4295

4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306
    return rv;

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

4307

4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342
/* 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);
        }
    }
}

4343

4344 4345 4346 4347 4348 4349 4350 4351 4352
/* 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:
4353
 * @dom: domain definition that @iface belongs to
4354 4355 4356 4357 4358 4359 4360 4361 4362 4363
 * @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.
 */
4364
static int
4365 4366
networkAllocateActualDevice(virDomainDefPtr dom,
                            virDomainNetDefPtr iface)
4367
{
4368
    virNetworkDriverStatePtr driver = networkGetDriver();
4369
    virDomainNetType actualType = iface->type;
4370
    virNetworkObjPtr obj = NULL;
4371
    virNetworkDefPtr netdef = NULL;
4372
    virNetDevBandwidthPtr bandwidth = NULL;
4373 4374 4375
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
4376
    virNetworkForwardIfDefPtr dev = NULL;
4377
    size_t i;
4378 4379 4380
    int ret = -1;

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4381
        goto validate;
4382 4383 4384 4385

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

4386 4387
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4388 4389 4390
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4391
        goto error;
4392
    }
4393
    netdef = virNetworkObjGetDef(obj);
4394

4395
    if (!virNetworkObjIsActive(obj)) {
4396 4397 4398 4399 4400 4401
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4402 4403 4404
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

4405 4406 4407
    /* 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 已提交
4408
     */
4409 4410 4411 4412 4413 4414
    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.
     */
4415 4416 4417 4418 4419 4420

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

4421 4422
    if (bandwidth && virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
                                            bandwidth) < 0)
4423
        goto error;
4424

4425 4426 4427 4428 4429 4430 4431 4432
    /* 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;

4433 4434
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
4435

4436 4437 4438 4439 4440 4441 4442 4443 4444 4445
    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;

4446 4447
    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
4448 4449
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
4450
        /* for these forward types, the actual net type really *is*
4451
         * NETWORK; we just keep the info from the portgroup in
4452
         * iface->data.network.actual
J
Ján Tomko 已提交
4453
         */
4454
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
4455

4456
        /* we also store the bridge device and macTableManager settings
4457 4458 4459 4460 4461 4462 4463
         * 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;
4464 4465
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4466

4467
        if (networkPlugBandwidth(obj, iface) < 0)
4468 4469
            goto error;

4470
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
4471
               netdef->bridge) {
4472 4473 4474 4475 4476

        /* <forward type='bridge'/> <bridge name='xxx'/>
         * is VIR_DOMAIN_NET_TYPE_BRIDGE
         */

4477
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
4478 4479
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
4480
            goto error;
4481 4482
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4483

4484 4485 4486 4487 4488 4489 4490 4491
        /* 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) {
4492
            goto error;
4493 4494 4495 4496 4497 4498 4499 4500 4501 4502
        }
        virtport = iface->data.network.actual->virtPortProfile;
        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);
4503
                goto error;
4504 4505 4506
            }
        }

4507
    } else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4508

4509
        virDomainHostdevSubsysPCIBackendType backend;
4510

4511
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
4512
        if (networkCreateInterfacePool(netdef) < 0)
4513 4514 4515
            goto error;

        /* pick first dev with 0 connections */
4516 4517 4518
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532
                break;
            }
        }
        if (!dev) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' requires exclusive access "
                             "to interfaces, but none are available"),
                           netdef->name);
            goto error;
        }
        iface->data.network.actual->data.hostdev.def.parent.type = VIR_DOMAIN_DEVICE_NET;
        iface->data.network.actual->data.hostdev.def.parent.data.net = iface;
        iface->data.network.actual->data.hostdev.def.info = &iface->info;
        iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
4533
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
4534
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
4535
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
4536

E
Eric Blake 已提交
4537
        switch (netdef->forward.driverName) {
4538
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
4539
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4540 4541
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
4542
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
4543 4544
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
4545
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556
            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;

4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581
        /* 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;
        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;
            }
        }

4582 4583 4584 4585
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) ||
               (netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) ||
               (netdef->forward.type == VIR_NETWORK_FORWARD_VEPA) ||
               (netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH)) {
4586 4587 4588 4589 4590 4591

        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
4592
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
4593
        switch (netdef->forward.type) {
4594
        case VIR_NETWORK_FORWARD_BRIDGE:
4595
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
4596 4597
            break;
        case VIR_NETWORK_FORWARD_PRIVATE:
4598
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
4599 4600
            break;
        case VIR_NETWORK_FORWARD_VEPA:
4601
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
4602 4603
            break;
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
4604
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PASSTHRU;
4605 4606 4607
            break;
        }

4608 4609 4610 4611 4612 4613 4614 4615
        /* 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) {
4616
            goto error;
4617
        }
4618
        virtport = iface->data.network.actual->virtPortProfile;
4619
        if (virtport) {
4620 4621 4622 4623 4624 4625 4626 4627
            /* 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);
4628
                goto error;
4629 4630
            }
        }
4631

4632 4633 4634
        /* 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).
         */
4635
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4636 4637 4638 4639
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4640
            goto error;
4641 4642 4643
        } else {
            /* pick an interface from the pool */

4644
            if (networkCreateInterfacePool(netdef) < 0)
4645 4646
                goto error;

4647 4648 4649 4650 4651
            /* 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.
4652
             */
4653 4654
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4655 4656 4657
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4658

4659
                /* pick first dev with 0 connections */
4660 4661 4662
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4663 4664 4665 4666 4667
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4668
                dev = &netdef->forward.ifs[0];
4669 4670 4671
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4672 4673 4674 4675
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4676 4677 4678 4679
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4680
                goto error;
4681
            }
4682 4683
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
4684
                goto error;
4685 4686 4687
        }
    }

4688 4689
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
                               dom->name, &iface->mac) < 0)
M
Michal Privoznik 已提交
4690 4691
        goto error;

4692
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
4693
        goto error;
4694

4695
 validate:
4696 4697 4698 4699 4700
    /* 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.
     */

4701
    if (virDomainNetGetActualVlan(iface)) {
4702 4703 4704 4705
        /* 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
4706 4707
         */
        if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
4708 4709 4710
              (actualType == VIR_DOMAIN_NET_TYPE_DIRECT &&
               virDomainNetGetActualDirectMode(iface)
               == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) ||
4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729
              (actualType == VIR_DOMAIN_NET_TYPE_BRIDGE &&
               virtport && virtport->virtPortType
               == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH))) {
            if (netdef) {
                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);
            } else {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("an interface of type '%s' "
                                 "is requesting a vlan tag, but that is not "
                                 "supported for this type of connection"),
                               virDomainNetTypeToString(iface->type));
            }
            goto error;
        }
    }
4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740
    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;
        }
    }
4741 4742 4743

    if (netdef) {
        netdef->connections++;
4744
        if (dev)
4745 4746
            dev->connections++;
        /* finally we can call the 'plugged' hook script if any */
4747
        if (networkRunHook(obj, dom, iface,
4748 4749 4750
                           VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
                           VIR_HOOK_SUBOP_BEGIN) < 0) {
            /* adjust for failure */
4751
            netdef->connections--;
4752 4753 4754 4755
            if (dev)
                dev->connections--;
            goto error;
        }
4756
        networkLogAllocation(netdef, actualType, dev, iface, true);
4757 4758
    }

4759
    ret = 0;
4760

4761
 cleanup:
4762
    virNetworkObjEndAPI(&obj);
4763 4764
    return ret;

4765
 error:
4766
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4767 4768 4769
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4770
    goto cleanup;
4771 4772
}

4773

4774
/* networkNotifyActualDevice:
4775
 * @dom: domain definition that @iface belongs to
4776 4777 4778 4779 4780
 * @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
4781 4782
 * order, or re-attach the interface's tap device to the network's
 * bridge.
4783
 *
4784
 * No return value (but does log any failures)
4785
 */
4786
static void
4787 4788
networkNotifyActualDevice(virDomainDefPtr dom,
                          virDomainNetDefPtr iface)
4789
{
4790
    virNetworkDriverStatePtr driver = networkGetDriver();
4791
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4792
    virNetworkObjPtr obj;
4793
    virNetworkDefPtr netdef;
4794
    virNetworkForwardIfDefPtr dev = NULL;
4795
    size_t i;
4796
    char *master = NULL;
4797 4798

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4799
        return;
4800

4801 4802
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4803 4804 4805
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4806 4807
        goto error;
    }
4808
    netdef = virNetworkObjGetDef(obj);
4809

4810
    if (!virNetworkObjIsActive(obj)) {
4811 4812 4813 4814 4815 4816
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827
    /* if we're restarting libvirtd after an upgrade from a version
     * that didn't save bridge name in actualNetDef for
     * actualType==network, we need to copy it in so that it will be
     * available in all cases
     */
    if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK &&
        !iface->data.network.actual->data.bridge.brname &&
        (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                    netdef->bridge) < 0))
            goto error;

4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852
    /* see if we're connected to the correct bridge */
    if (netdef->bridge) {
        if (virNetDevGetMaster(iface->ifname, &master) < 0)
            goto error;

        if (STRNEQ_NULLABLE(netdef->bridge, master)) {
            /* disconnect from current (incorrect) bridge */
            if (master)
                ignore_value(virNetDevBridgeRemovePort(master, iface->ifname));

            /* attach/reattach to correct bridge.
             * NB: we can't notify the guest of any MTU change anyway,
             * so there is no point in trying to learn the actualMTU
             * (final arg to virNetDevTapAttachBridge())
             */
            if (virNetDevTapAttachBridge(iface->ifname, netdef->bridge,
                                         &iface->mac, dom->uuid,
                                         virDomainNetGetActualVirtPortProfile(iface),
                                         virDomainNetGetActualVlan(iface),
                                         iface->mtu, NULL) < 0) {
                goto error;
            }
        }
    }

4853
    if (!iface->data.network.actual ||
4854 4855
        (actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
4856 4857
        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
        goto success;
4858 4859
    }

4860
    if (networkCreateInterfacePool(netdef) < 0)
4861
        goto error;
4862

4863
    if (netdef->forward.nifs == 0) {
4864
        virReportError(VIR_ERR_INTERNAL_ERROR,
4865 4866
                       _("network '%s' uses a direct or hostdev mode, "
                         "but has no forward dev and no interface pool"),
4867
                       netdef->name);
4868
        goto error;
4869
    }
4870

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

4874 4875 4876 4877 4878 4879 4880 4881 4882
        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 */
4883 4884
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4885
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4886 4887
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4888 4889 4890 4891 4892
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4893
            virReportError(VIR_ERR_INTERNAL_ERROR,
4894 4895
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4896
                           netdef->name, actualDev);
4897
            goto error;
4898 4899
        }

4900
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4901 4902
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4903
         */
4904
        if ((dev->connections > 0) &&
4905 4906
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4907 4908
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
4909
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4910
            virReportError(VIR_ERR_INTERNAL_ERROR,
4911 4912
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
4913
                           netdef->name, actualDev);
4914
            goto error;
4915
        }
4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927
    }  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 */
4928 4929
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4930
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4931
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
4932 4933
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4934 4935 4936 4937 4938 4939 4940 4941 4942
                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,
4943 4944 4945 4946
                           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 已提交
4947
            goto error;
4948 4949 4950 4951 4952 4953 4954
        }

        /* 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) &&
4955
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4956 4957 4958 4959 4960 4961 4962 4963 4964
            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;
        }
4965 4966
    }

4967
 success:
4968
    netdef->connections++;
4969 4970
    if (dev)
        dev->connections++;
4971
    /* finally we can call the 'plugged' hook script if any */
4972
    if (networkRunHook(obj, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
4973 4974 4975 4976 4977 4978 4979
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
        goto error;
    }
4980
    networkLogAllocation(netdef, actualType, dev, iface, true);
4981

4982
 cleanup:
4983
    virNetworkObjEndAPI(&obj);
4984
    VIR_FREE(master);
4985
    return;
4986

4987
 error:
4988
    goto cleanup;
4989 4990 4991 4992
}


/* networkReleaseActualDevice:
4993
 * @dom: domain definition that @iface belongs to
4994 4995 4996 4997 4998 4999 5000 5001 5002
 * @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.
 */
5003
static int
5004 5005
networkReleaseActualDevice(virDomainDefPtr dom,
                           virDomainNetDefPtr iface)
5006
{
5007
    virNetworkDriverStatePtr driver = networkGetDriver();
5008
    virDomainNetType actualType = virDomainNetGetActualType(iface);
5009
    virNetworkObjPtr obj;
5010
    virNetworkDefPtr netdef;
5011
    virNetworkForwardIfDefPtr dev = NULL;
5012 5013
    size_t i;
    int ret = -1;
5014 5015

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
J
Ján Tomko 已提交
5016
        return 0;
5017

5018 5019
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5020 5021 5022
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
5023 5024
        goto error;
    }
5025
    netdef = virNetworkObjGetDef(obj);
5026

5027 5028
    if (iface->data.network.actual &&
        (netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
5029
         netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
5030 5031
         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
         netdef->forward.type == VIR_NETWORK_FORWARD_OPEN) &&
5032
        networkUnplugBandwidth(obj, iface) < 0)
5033 5034
        goto error;

5035 5036 5037
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
5038 5039
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
5040 5041
    }

5042
    if (netdef->forward.nifs == 0) {
5043
        virReportError(VIR_ERR_INTERNAL_ERROR,
5044
                       _("network '%s' uses a direct/hostdev mode, but "
5045 5046
                         "has no forward dev and no interface pool"),
                       netdef->name);
5047
        goto error;
5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059
    }

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

5061 5062
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5063
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
5064 5065
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
5066 5067 5068
                break;
            }
        }
5069

5070
        if (!dev) {
5071
            virReportError(VIR_ERR_INTERNAL_ERROR,
5072 5073
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5074
                           netdef->name, actualDev);
5075
            goto error;
5076
        }
5077 5078 5079 5080 5081 5082 5083 5084 5085 5086
    } 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;
        }

5087 5088
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5089
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5090
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
5091 5092
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5093 5094 5095 5096 5097 5098 5099 5100 5101
                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,
5102 5103 5104 5105
                           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 已提交
5106
            goto error;
5107
        }
J
Ján Tomko 已提交
5108
    }
5109

5110
 success:
5111
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, dom->name, &iface->mac);
M
Michal Privoznik 已提交
5112

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

5131
 error:
5132
    goto cleanup;
5133
}
5134

5135

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

5170
    virMacAddrFormat(&ifaceMac, ifmac);
5171 5172 5173 5174 5175 5176

    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"),
5177
                       ifmac, def->name);
5178 5179 5180
        return -1;
    }

5181 5182
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor)) ||
5183 5184
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
5185
        return 1;
5186
    }
5187 5188

    tmp_new_rate = netBand->in->average;
5189 5190 5191 5192
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
5193 5194 5195 5196 5197 5198 5199 5200 5201

    /* 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,
                           _("Cannot plug '%s' interface into '%s' because it "
                             "would overcommit 'peak' on network '%s'"),
                           ifmac,
5202 5203
                           def->bridge,
                           def->name);
5204 5205 5206 5207 5208 5209 5210 5211 5212
            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,
                       _("Cannot plug '%s' interface into '%s' because it "
                         "would overcommit 'average' on network '%s'"),
                       ifmac,
5213 5214
                       def->bridge,
                       def->name);
5215 5216 5217
        goto cleanup;
    }

5218 5219
    if (new_rate)
        *new_rate = tmp_new_rate;
5220 5221
    ret = 0;

5222
 cleanup:
5223 5224 5225
    return ret;
}

5226

5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237
/**
 * 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
5238
networkNextClassID(virNetworkObjPtr obj)
5239
{
5240
    ssize_t ret = 0;
5241
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5242

5243 5244
    if ((ret = virBitmapNextClearBit(classIdMap, -1)) < 0)
        ret = virBitmapSize(classIdMap);
5245

5246
    if (virBitmapSetBitExpand(classIdMap, ret) < 0)
5247 5248 5249 5250 5251
        return -1;

    return ret;
}

5252

5253
static int
5254
networkPlugBandwidthImpl(virNetworkObjPtr obj,
5255 5256 5257
                         virDomainNetDefPtr iface,
                         virNetDevBandwidthPtr ifaceBand,
                         unsigned long long new_rate)
5258
{
5259
    virNetworkDriverStatePtr driver = networkGetDriver();
5260
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5261
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5262
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5263
    ssize_t class_id = 0;
5264 5265
    int plug_ret;
    int ret = -1;
5266 5267

    /* generate new class_id */
5268
    if ((class_id = networkNextClassID(obj)) < 0) {
5269 5270 5271 5272 5273
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate next class ID"));
        goto cleanup;
    }

5274
    plug_ret = virNetDevBandwidthPlug(def->bridge, def->bandwidth,
5275
                                      &iface->mac, ifaceBand, class_id);
5276
    if (plug_ret < 0) {
5277
        ignore_value(virNetDevBandwidthUnplug(def->bridge, class_id));
5278 5279 5280 5281 5282 5283
        goto cleanup;
    }

    /* QoS was set, generate new class ID */
    iface->data.network.actual->class_id = class_id;
    /* update sum of 'floor'-s of attached NICs */
5284 5285
    tmp_floor_sum += ifaceBand->in->floor;
    virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5286
    /* update status file */
5287
    if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5288
        ignore_value(virBitmapClearBit(classIdMap, class_id));
5289 5290
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5291
        iface->data.network.actual->class_id = 0;
5292
        ignore_value(virNetDevBandwidthUnplug(def->bridge, class_id));
5293 5294
        goto cleanup;
    }
5295
    /* update rate for non guaranteed NICs */
5296
    new_rate -= tmp_floor_sum;
5297 5298
    if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                     def->bandwidth, new_rate) < 0)
5299
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5300
                 def->bridge);
5301 5302

    ret = 0;
5303 5304 5305 5306 5307 5308
 cleanup:
    return ret;
}


static int
5309
networkPlugBandwidth(virNetworkObjPtr obj,
5310 5311 5312 5313 5314 5315 5316 5317
                     virDomainNetDefPtr iface)
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);

5318
    if ((plug_ret = networkCheckBandwidth(obj, ifaceBand, NULL,
5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338
                                          iface->mac, &new_rate)) < 0) {
        /* helper reported error */
        goto cleanup;
    }

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

    virMacAddrFormat(&iface->mac, ifmac);
    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK ||
        !iface->data.network.actual) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot set bandwidth on interface '%s' of type %d"),
                       ifmac, iface->type);
        goto cleanup;
    }

5339
    if (networkPlugBandwidthImpl(obj, iface, ifaceBand, new_rate) < 0)
5340 5341 5342
        goto cleanup;

    ret = 0;
5343

5344
 cleanup:
5345 5346 5347
    return ret;
}

5348

5349
static int
5350
networkUnplugBandwidth(virNetworkObjPtr obj,
5351 5352
                       virDomainNetDefPtr iface)
{
5353
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5354
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5355
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5356
    virNetworkDriverStatePtr driver = networkGetDriver();
5357 5358
    int ret = 0;
    unsigned long long new_rate;
5359
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
5360 5361 5362

    if (iface->data.network.actual &&
        iface->data.network.actual->class_id) {
5363
        if (!def->bandwidth || !def->bandwidth->in) {
5364
            VIR_WARN("Network %s has no bandwidth but unplug requested",
5365
                     def->name);
5366 5367
            goto cleanup;
        }
5368
        /* we must remove class from bridge */
5369
        new_rate = def->bandwidth->in->average;
5370

5371 5372
        if (def->bandwidth->in->peak > 0)
            new_rate = def->bandwidth->in->peak;
5373

5374
        ret = virNetDevBandwidthUnplug(def->bridge,
5375 5376 5377 5378
                                       iface->data.network.actual->class_id);
        if (ret < 0)
            goto cleanup;
        /* update sum of 'floor'-s of attached NICs */
5379 5380 5381
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);

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

5403
 cleanup:
5404 5405
    return ret;
}
5406

5407

5408
static void
5409
networkNetworkObjTaint(virNetworkObjPtr obj,
5410
                       virNetworkTaintFlags taint)
5411
{
5412 5413
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

5414
    if (virNetworkObjTaint(obj, taint)) {
5415
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5416
        virUUIDFormat(def->uuid, uuidstr);
5417 5418

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5419
                 def->name, uuidstr, virNetworkTaintTypeToString(taint));
5420 5421
    }
}
5422 5423 5424 5425 5426 5427


static bool
networkBandwidthGenericChecks(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
5428
    virNetDevBandwidthPtr ifaceBand;
5429 5430 5431 5432 5433 5434 5435 5436
    unsigned long long old_floor, new_floor;

    if (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_NETWORK) {
        /* 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;
    }

5437
    ifaceBand = virDomainNetGetActualBandwidth(iface);
5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448
    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;
}


5449
static bool
5450 5451 5452 5453
networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5454
    virNetworkObjPtr obj = NULL;
5455 5456 5457 5458 5459 5460
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    bool ret = false;

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

5461 5462
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5463 5464 5465 5466 5467 5468
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return false;
    }

5469
    if (networkCheckBandwidth(obj, newBandwidth, ifaceBand, iface->mac, NULL) < 0)
5470 5471 5472 5473 5474
        goto cleanup;

    ret = true;

 cleanup:
5475
    virNetworkObjEndAPI(&obj);
5476 5477
    return ret;
}
5478 5479


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

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

5496 5497
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5498 5499 5500 5501 5502
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return ret;
    }
5503
    def = virNetworkObjGetDef(obj);
5504

5505
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, ifaceBand,
5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518
                                          iface->mac, &new_rate)) < 0) {
        /* 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: */

5519
    if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
5520
        newBandwidth->in && newBandwidth->in->floor) {
5521 5522
        /* Either we just need to update @floor .. */

5523
        if (virNetDevBandwidthUpdateRate(def->bridge,
5524
                                         iface->data.network.actual->class_id,
5525
                                         def->bandwidth,
5526 5527 5528
                                         newBandwidth->in->floor) < 0)
            goto cleanup;

5529 5530 5531 5532 5533
        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;
5534

5535 5536
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0 ||
5537
            virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5538
            /* Ouch, rollback */
5539 5540 5541
            tmp_floor_sum -= newBandwidth->in->floor;
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5542

5543
            ignore_value(virNetDevBandwidthUpdateRate(def->bridge,
5544
                                                      iface->data.network.actual->class_id,
5545
                                                      def->bandwidth,
5546 5547 5548 5549 5550 5551
                                                      ifaceBand->in->floor));
            goto cleanup;
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5552
        if (networkPlugBandwidthImpl(obj, iface, newBandwidth, new_rate) < 0)
5553 5554 5555 5556
            goto cleanup;
    } else {
        /* .. or unplug old. */

5557
        if (networkUnplugBandwidth(obj, iface) < 0)
5558 5559 5560 5561 5562
            goto cleanup;
    }

    ret = 0;
 cleanup:
5563
    virNetworkObjEndAPI(&obj);
5564 5565
    return ret;
}
5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593


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

5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605

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 = {
5606
    .localOnly = true,
5607
    .uriSchemes = (const char *[]){ "network", NULL },
5608 5609 5610 5611 5612
    .hypervisorDriver = &networkHypervisorDriver,
    .networkDriver = &networkDriver,
};


5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623
static virStateDriver networkStateDriver = {
    .name = "bridge",
    .stateInitialize  = networkStateInitialize,
    .stateAutoStart  = networkStateAutoStart,
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
};

int
networkRegister(void)
{
5624 5625
    if (virRegisterConnectDriver(&networkConnectDriver, false) < 0)
        return -1;
5626 5627 5628 5629
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
5630 5631 5632 5633

    virDomainNetSetDeviceImpl(
        networkAllocateActualDevice,
        networkNotifyActualDevice,
5634 5635
        networkReleaseActualDevice,
        networkBandwidthChangeAllowed,
5636
        networkBandwidthUpdate);
5637

5638 5639
    return 0;
}