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

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

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

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

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

731
    if (!(network_driver->networks = virNetworkObjListNew()))
732 733
        goto error;

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

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

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

756
    network_driver->networkEventState = virObjectEventStateNew();
757

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

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

789
 error:
790
    networkStateCleanup();
791
    goto cleanup;
792 793
}

794

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

806
    virNetworkObjListForEach(network_driver->networks,
807
                             networkAutostartConfig,
808
                             network_driver);
809 810
}

811

812
/**
813
 * networkStateReload:
814 815 816 817 818
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
819 820
networkStateReload(void)
{
821
    if (!network_driver)
822 823
        return 0;

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


/**
839
 * networkStateCleanup:
840 841 842 843
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
844 845
networkStateCleanup(void)
{
846
    if (!network_driver)
847 848
        return -1;

849
    virObjectUnref(network_driver->networkEventState);
850

851
    /* free inactive networks */
852
    virObjectUnref(network_driver->networks);
853

854 855 856 857 858 859
    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);
860

861
    virObjectUnref(network_driver->dnsmasqCaps);
862

863
    virMutexDestroy(&network_driver->lock);
864

865
    VIR_FREE(network_driver);
866 867 868 869 870

    return 0;
}


871 872 873 874 875
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
876 877 878
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
879
{
880 881
    size_t i;
    int ret = -1;
882 883 884 885 886 887 888
    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.
     */
889
    for (i = 0; i < 25; i++) {
890
        int signum = 0;
891
        if (i == 0) {
892
            signum = SIGTERM;
893
        } else if (i == 15) {
894 895 896 897 898 899 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
            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);
929
 cleanup:
930 931 932
    return ret;
}

933

J
Ján Tomko 已提交
934 935 936
/* the following does not build a file, it builds a list
 * which is later saved into a file
 */
937
static int
G
Gene Czarcinski 已提交
938
networkBuildDnsmasqDhcpHostsList(dnsmasqContext *dctx,
939
                                 virNetworkIPDefPtr ipdef)
940
{
941
    size_t i;
G
Gene Czarcinski 已提交
942
    bool ipv6 = false;
943

G
Gene Czarcinski 已提交
944 945
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
946 947
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
948
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
949 950
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
951
                return -1;
952
    }
953

G
Gene Czarcinski 已提交
954 955 956
    return 0;
}

957

G
Gene Czarcinski 已提交
958 959 960 961
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
962
    size_t i, j;
G
Gene Czarcinski 已提交
963

964 965
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
966
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
967
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
968
                for (j = 0; j < host->nnames; j++)
969 970
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
971 972
            }
        }
973 974
    }

975
    return 0;
976 977 978
}


979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
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;
}


1016
int
1017
networkDnsmasqConfContents(virNetworkObjPtr obj,
1018 1019 1020 1021
                           const char *pidfile,
                           char **configstr,
                           dnsmasqContext *dctx,
                           dnsmasqCapsPtr caps ATTRIBUTE_UNUSED)
1022
{
1023
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1024
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1025
    int r, ret = -1;
1026
    int nbleases = 0;
1027
    size_t i;
1028
    virNetworkDNSDefPtr dns = &def->dns;
1029
    bool wantDNS = dns->enable != VIR_TRISTATE_BOOL_NO;
1030
    virNetworkIPDefPtr tmpipdef, ipdef, ipv4def, ipv6def;
G
Gene Czarcinski 已提交
1031
    bool ipv6SLAAC;
1032
    char *saddr = NULL, *eaddr = NULL;
1033

1034 1035
    *configstr = NULL;

1036
    /*
1037 1038 1039
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1040
     *
1041 1042
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1043
     */
1044 1045 1046 1047 1048 1049

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

1050
    /* create dnsmasq config file appropriate for this network */
1051 1052

    /* Don't forget to update networkxml2conftest :-) */
1053
    virBufferAsprintf(&configbuf,
1054 1055 1056 1057 1058 1059 1060
                      "##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"
1061
                      "strict-order\n",
1062
                      def->name);
1063

1064 1065 1066 1067 1068 1069
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1070
    if (wantDNS && def->dns.forwarders) {
1071 1072 1073 1074 1075 1076 1077 1078 1079
        /* 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;

1080 1081
        for (i = 0; i < def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &def->dns.forwarders[i];
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091

            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);
1092
                VIR_FREE(addr);
1093 1094
                if (!fwd->domain)
                    addNoResolv = true;
1095 1096 1097 1098
            } else {
                /* "don't forward requests for this domain" */
                virBufferAddLit(&configbuf, "#\n");
            }
1099
        }
1100 1101
        if (addNoResolv)
            virBufferAddLit(&configbuf, "no-resolv\n");
1102 1103
    }

1104 1105
    if (def->domain) {
        if (def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1106 1107
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1108
                              def->domain);
1109
        }
1110
        virBufferAsprintf(&configbuf,
1111 1112
                          "domain=%s\n"
                          "expand-hosts\n",
1113
                          def->domain);
1114
    }
1115

1116
    if (wantDNS &&
1117
        networkDnsmasqConfLocalPTRs(&configbuf, def) < 0)
1118 1119
        goto cleanup;

1120
    if (wantDNS && def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1121 1122 1123 1124
        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)
1125
         */
1126
        virBufferAddLit(&configbuf, "local=//\n");
1127
    }
1128

1129
    if (pidfile)
1130
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1131

1132
    /* dnsmasq will *always* listen on localhost unless told otherwise */
P
Pavel Timofeev 已提交
1133
#ifdef __linux__
1134
    virBufferAddLit(&configbuf, "except-interface=lo\n");
P
Pavel Timofeev 已提交
1135 1136 1137 1138
#else
    /* BSD family OSes and Solaris call loopback interface as lo0 */
    virBufferAddLit(&configbuf, "except-interface=lo0\n");
#endif
1139

1140 1141 1142 1143 1144 1145 1146 1147
    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.
         */
1148
        virBufferAsprintf(&configbuf,
1149 1150
                          "bind-dynamic\n"
                          "interface=%s\n",
1151
                          def->bridge);
1152
    } else {
1153
        virBufferAddLit(&configbuf, "bind-interfaces\n");
1154 1155 1156 1157
        /*
         * --interface does not actually work with dnsmasq < 2.47,
         * due to DAD for ipv6 addresses on the interface.
         *
1158
         * virCommandAddArgList(cmd, "--interface", def->bridge, NULL);
1159 1160 1161
         *
         * So listen on all defined IPv[46] addresses
         */
1162
        for (i = 0;
1163
             (tmpipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
1164
             i++) {
1165 1166 1167 1168
            char *ipaddr = virSocketAddrFormat(&tmpipdef->address);

            if (!ipaddr)
                goto cleanup;
1169

1170
            /* also part of CVE 2012-3411 - if the host's version of
1171
             * dnsmasq doesn't have bind-dynamic, only allow listening on
1172 1173
             * private/local IP addresses (see RFC1918/RFC3484/RFC4193)
             */
1174 1175
            if (!dnsmasqCapsGet(caps, DNSMASQ_CAPS_BINDTODEVICE) &&
                !virSocketAddrIsPrivate(&tmpipdef->address)) {
1176 1177 1178 1179
                unsigned long version = dnsmasqCapsGetVersion(caps);

                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("Publicly routable address %s is prohibited. "
1180
                                 "The version of dnsmasq on this host (%d.%d) "
1181 1182 1183 1184
                                 "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 "
1185 1186 1187 1188 1189 1190
                                 "(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);
1191
                VIR_FREE(ipaddr);
1192 1193
                goto cleanup;
            }
1194
            virBufferAsprintf(&configbuf, "listen-address=%s\n", ipaddr);
1195 1196 1197
            VIR_FREE(ipaddr);
        }
    }
1198

1199 1200
    /* If this is an isolated network, set the default route option
     * (3) to be empty to avoid setting a default route that's
1201
     * guaranteed to not work, and set no-resolv so that no dns
1202 1203 1204
     * 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).
1205 1206 1207
     * 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.
1208
     */
1209
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE) {
1210
        virBufferAddLit(&configbuf, "dhcp-option=3\n"
1211
                        "no-resolv\n");
1212 1213 1214 1215
        if (dnsmasqCapsGet(caps, DNSMASQ_CAPS_RA_PARAM)) {
            /* interface=* (any), interval=0 (default), lifetime=0 (seconds) */
            virBufferAddLit(&configbuf, "ra-param=*,0,0\n");
        }
1216
    }
1217

1218 1219 1220 1221 1222
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1223
        }
1224

1225 1226 1227 1228 1229 1230 1231 1232
        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'"),
1233
                               def->name);
1234 1235 1236 1237 1238 1239
                goto cleanup;
            }
            if (!dns->srvs[i].protocol) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing required 'service' "
                                 "attribute in SRV record of network '%s'"),
1240
                               def->name);
1241 1242 1243 1244 1245 1246 1247
                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);
1248

1249 1250 1251 1252 1253 1254 1255
            /* 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.
1256
             */
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
            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");
1277
        }
1278 1279
    }

G
Gene Czarcinski 已提交
1280
    /* Find the first dhcp for both IPv4 and IPv6 */
1281
    for (i = 0, ipv4def = NULL, ipv6def = NULL, ipv6SLAAC = false;
1282
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
1283
         i++) {
G
Gene Czarcinski 已提交
1284 1285 1286 1287
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
            if (ipdef->nranges || ipdef->nhosts) {
                if (ipv4def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1288 1289
                                   _("For IPv4, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300
                    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,
1301 1302 1303 1304 1305 1306 1307 1308 1309
                                   _("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 已提交
1310 1311 1312 1313
                    goto cleanup;
                }
                if (ipv6def) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1314 1315
                                   _("For IPv6, multiple DHCP definitions "
                                     "cannot be specified."));
G
Gene Czarcinski 已提交
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
                    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 "
1329 1330 1331 1332
                 "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 已提交
1333 1334 1335 1336 1337
    }

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1338 1339
        int prefix;

1340
        prefix = virNetworkIPDefPrefix(ipdef);
1341 1342 1343
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1344
                           def->bridge);
1345 1346
            goto cleanup;
        }
1347
        for (r = 0; r < ipdef->nranges; r++) {
1348 1349
            int thisRange;

1350 1351
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1352
                goto cleanup;
1353

1354
            virBufferAsprintf(&configbuf, "dhcp-range=%s,%s",
1355
                              saddr, eaddr);
1356
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1357
                virBufferAsprintf(&configbuf, ",%d", prefix);
1358 1359
            virBufferAddLit(&configbuf, "\n");

1360
            VIR_FREE(saddr);
1361
            VIR_FREE(eaddr);
1362
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1363 1364
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1365
                                              virNetworkIPDefPrefix(ipdef));
1366 1367 1368
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1369
        }
1370

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

G
Gene Czarcinski 已提交
1389 1390
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1391

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

G
Gene Czarcinski 已提交
1399
            if (ipdef->tftproot) {
1400 1401
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1402
            }
1403

G
Gene Czarcinski 已提交
1404 1405 1406
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1407

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

1421
    if (nbleases > 0)
1422
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1423

G
Gene Czarcinski 已提交
1424 1425
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1426
        goto cleanup;
G
Gene Czarcinski 已提交
1427 1428 1429 1430 1431 1432

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

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

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

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

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

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

1476

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

1493
    virNetworkObjSetDnsmasqPid(obj, -1);
1494

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

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

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

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

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

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

1536

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1628

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

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

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

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

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

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

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

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

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

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

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

1701

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

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

1725

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

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

    *configstr = NULL;
1744

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

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

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

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

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

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

1800 1801
    *configstr = virBufferContentAndReset(&configbuf);

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

1808

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

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

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

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

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

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

1851

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

1865
    virNetworkObjSetRadvdPid(obj, -1);
1866

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

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

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

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

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

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

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

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

1943

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

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

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

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

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

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

1987

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

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

2016

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

2024
    virObjectLock(obj);
2025
    def = virNetworkObjGetDef(obj);
2026
    if (virNetworkObjIsActive(obj) &&
2027 2028 2029 2030
        ((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))) {
2031 2032 2033 2034 2035 2036
        /* 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.
         */
2037 2038
        networkRefreshDhcpDaemon(driver, obj);
        networkRefreshRadvd(driver, obj);
2039
    }
2040
    virObjectUnlock(obj);
2041 2042 2043
    return 0;
}

2044

2045 2046 2047 2048
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2049
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2050 2051
{
    VIR_INFO("Refreshing network daemons");
2052 2053
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2054
                             driver);
2055
}
2056

2057

2058
static int
2059
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
2060 2061
                                 void *opaque ATTRIBUTE_UNUSED)
{
2062
    virNetworkDefPtr def;
2063

2064
    virObjectLock(obj);
2065
    def = virNetworkObjGetDef(obj);
2066
    if (virNetworkObjIsActive(obj) &&
2067 2068 2069
        ((def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
         (def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
         (def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
2070 2071 2072 2073
        /* 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.
2074
         */
2075 2076
        networkRemoveFirewallRules(def);
        if (networkAddFirewallRules(def) < 0) {
2077
            /* failed to add but already logged */
2078 2079
        }
    }
2080
    virObjectUnlock(obj);
2081
    return 0;
2082 2083
}

2084

2085
static void
2086
networkReloadFirewallRules(virNetworkDriverStatePtr driver)
2087
{
2088
    VIR_INFO("Reloading iptables rules");
2089 2090 2091
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2092 2093
}

2094

2095
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
2096
static int
2097 2098
networkEnableIPForwarding(bool enableIPv4,
                          bool enableIPv6)
2099
{
2100
    int ret = 0;
2101 2102 2103 2104
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
2105
                           &enabled, sizeof(enabled));
2106 2107
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
2108
                           &enabled, sizeof(enabled));
2109
#else
2110
    if (enableIPv4)
2111
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv4/ip_forward", "1\n", 0);
2112
    if (enableIPv6 && ret == 0)
2113 2114
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv6/conf/all/forwarding", "1\n", 0);

2115
#endif
2116
    return ret;
2117 2118
}

2119

2120
static int
2121
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2122
{
2123
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2124 2125
    char *field = NULL;
    int ret = -1;
2126
    bool enableIPv6 = !!virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2127

2128 2129 2130 2131 2132
    /* 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",
2133
                    def->bridge) < 0)
2134
       goto cleanup;
2135

2136 2137
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2138
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2139
                      def->bridge);
2140 2141 2142
        ret = 0;
        goto cleanup;
    }
2143

2144 2145 2146
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2147
                               "on bridge %s"), field, def->bridge);
2148
        goto cleanup;
2149
    }
2150
    VIR_FREE(field);
2151

2152 2153
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2154 2155 2156 2157 2158 2159
     */

    /* 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",
2160
                    def->bridge) < 0)
2161 2162
        goto cleanup;

2163
    if (virFileWriteStr(field, "0", 0) < 0) {
2164
        virReportSystemError(errno,
2165 2166 2167 2168 2169
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

2170 2171 2172 2173
    /* 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",
2174
                    def->bridge) < 0)
2175 2176
        goto cleanup;

2177
    if (virFileWriteStr(field, "0", 0) < 0) {
2178
        virReportSystemError(errno,
2179
                             _("cannot disable %s"), field);
2180 2181 2182 2183
        goto cleanup;
    }

    ret = 0;
2184
 cleanup:
2185 2186 2187 2188
    VIR_FREE(field);
    return ret;
}

2189

2190
/* add an IP address to a bridge */
2191
static int
2192
networkAddAddrToBridge(virNetworkObjPtr obj,
2193
                       virNetworkIPDefPtr ipdef)
2194
{
2195
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2196
    int prefix = virNetworkIPDefPrefix(ipdef);
2197 2198

    if (prefix < 0) {
2199 2200
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2201
                       def->bridge);
2202 2203 2204
        return -1;
    }

2205
    if (virNetDevIPAddrAdd(def->bridge, &ipdef->address, NULL, prefix) < 0)
2206 2207 2208 2209 2210
        return -1;

    return 0;
}

2211 2212

static int
2213
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2214 2215
                                      const char *macTapIfName)
{
2216 2217
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    const char *brname = def->bridge;
2218 2219

    if (brname &&
2220
        def->macTableManager == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233
        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;
}


2234 2235
/* add an IP (static) route to a bridge */
static int
2236
networkAddRouteToBridge(virNetworkObjPtr obj,
2237
                        virNetDevIPRoutePtr routedef)
2238
{
2239
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2240 2241 2242 2243
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2244 2245 2246 2247 2248

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

2253
    if (virNetDevIPRouteAdd(def->bridge, addr, prefix, gateway, metric) < 0)
2254
        return -1;
2255

2256 2257 2258
    return 0;
}

2259
static int
2260
networkWaitDadFinish(virNetworkObjPtr obj)
2261
{
2262
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2263
    virNetworkIPDefPtr ipdef;
2264 2265 2266 2267
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

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

2270
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, naddrs))) {
2271 2272 2273 2274 2275
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2276
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2277 2278 2279 2280

 cleanup:
    VIR_FREE(addrs);
    VIR_DEBUG("Finished waiting for IPv6 DAD on network %s with status %d",
2281
              def->name, ret);
2282 2283 2284
    return ret;
}

2285

2286
static int
2287
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
2288
                           virNetworkObjPtr obj)
2289
{
2290
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2291
    size_t i;
2292
    bool v4present = false, v6present = false;
2293
    virErrorPtr save_err = NULL;
2294
    virNetworkIPDefPtr ipdef;
2295
    virNetDevIPRoutePtr routedef;
2296
    char *macTapIfName = NULL;
2297
    virMacMapPtr macmap;
M
Michal Privoznik 已提交
2298
    char *macMapFile = NULL;
2299
    int tapfd = -1;
2300
    pid_t dnsmasqPid;
2301

2302
    /* Check to see if any network IP collides with an existing route */
2303
    if (networkCheckRouteCollision(def) < 0)
2304 2305
        return -1;

2306
    /* Create and configure the bridge device */
2307
    if (!def->bridge) {
2308 2309 2310 2311 2312 2313 2314 2315 2316 2317
        /* 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"),
2318
                       def->name);
2319 2320
        return -1;
    }
2321
    if (virNetDevBridgeCreate(def->bridge) < 0)
2322 2323
        return -1;

2324
    if (def->mac_specified) {
2325 2326 2327 2328 2329 2330
        /* 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.
         */
2331
        macTapIfName = networkBridgeDummyNicName(def->bridge);
2332
        if (!macTapIfName)
2333
            goto err0;
2334
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2335 2336
        if (virNetDevTapCreateInBridgePort(def->bridge,
                                           &macTapIfName, &def->mac,
2337
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2338
                                           NULL, def->mtu, NULL,
2339 2340 2341
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2342 2343 2344 2345 2346
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

2347
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
2348
                                         def->bridge)) ||
2349
        !(macmap = virMacMapNew(macMapFile)))
M
Michal Privoznik 已提交
2350 2351
        goto err1;

2352 2353
    virNetworkObjSetMacMap(obj, macmap);

2354
    /* Set bridge options */
2355 2356 2357 2358

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

2362
    if (virNetDevBridgeSetSTP(def->bridge, def->stp ? true : false) < 0)
2363
        goto err1;
2364

2365 2366 2367
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2368
    if (networkSetIPv6Sysctls(obj) < 0)
2369
        goto err1;
2370

2371
    /* Add "once per network" rules */
2372 2373
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(def) < 0)
2374 2375
        goto err1;

2376
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i)); i++) {
2377
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2378
            v4present = true;
2379
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2380
            v6present = true;
2381

2382
        /* Add the IP address/netmask to the bridge */
2383
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2384
            goto err2;
2385 2386
    }

2387
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2388 2389
        goto err2;

2390
    /* Bring up the bridge interface */
2391
    if (virNetDevSetOnline(def->bridge, 1) < 0)
2392
        goto err2;
2393

2394
    for (i = 0; i < def->nroutes; i++) {
2395 2396
        virSocketAddrPtr gateway = NULL;

2397
        routedef = def->routes[i];
2398
        gateway = virNetDevIPRouteGetGateway(routedef);
2399

2400 2401 2402
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2403
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2404
            if (networkAddRouteToBridge(obj, routedef) < 0) {
2405 2406 2407 2408 2409 2410
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2411
    /* If forward.type != NONE, turn on global IP forwarding */
2412
    if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2413
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2414 2415 2416 2417 2418 2419 2420
            goto err3; /* Precise error message already provided */

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

2423

2424
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2425
    if ((v4present || v6present) &&
2426
        networkStartDhcpDaemon(driver, obj) < 0)
2427
        goto err3;
2428

2429
    /* start radvd if there are any ipv6 addresses */
2430
    if (v6present && networkStartRadvd(driver, obj) < 0)
2431 2432
        goto err4;

2433 2434 2435
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2436
    if (v6present && networkWaitDadFinish(obj) < 0)
2437 2438 2439 2440
        goto err4;

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2441 2442 2443 2444 2445 2446 2447
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
            goto err4;
        VIR_FORCE_CLOSE(tapfd);
    }

2448
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
2449 2450
        goto err5;

2451
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2452
    VIR_FREE(macMapFile);
2453 2454 2455

    return 0;

2456
 err5:
2457 2458
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
2459

2460 2461 2462 2463
 err4:
    if (!save_err)
        save_err = virSaveLastError();

2464 2465 2466 2467
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0) {
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2468 2469
    }

2470 2471 2472
 err3:
    if (!save_err)
        save_err = virSaveLastError();
2473
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2474

2475 2476 2477
 err2:
    if (!save_err)
        save_err = virSaveLastError();
2478 2479
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2480 2481

 err1:
2482 2483 2484
    if (!save_err)
        save_err = virSaveLastError();

H
Hu Tao 已提交
2485
    if (macTapIfName) {
2486
        VIR_FORCE_CLOSE(tapfd);
2487
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2488 2489
        VIR_FREE(macTapIfName);
    }
M
Michal Privoznik 已提交
2490
    VIR_FREE(macMapFile);
2491 2492

 err0:
2493 2494
    if (!save_err)
        save_err = virSaveLastError();
2495
    ignore_value(virNetDevBridgeDelete(def->bridge));
2496

2497 2498 2499 2500
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
2501
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2502 2503 2504
    return -1;
}

2505

2506 2507
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2508
                              virNetworkObjPtr obj)
2509
{
2510
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2511 2512 2513
    pid_t radvdPid;
    pid_t dnsmasqPid;

2514 2515
    if (def->bandwidth)
        virNetDevBandwidthClear(def->bridge);
2516

2517
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2518

2519 2520
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2521 2522
        char *radvdpidbase;

2523
        kill(radvdPid, SIGTERM);
2524
        /* attempt to delete the pidfile we created */
2525
        if ((radvdpidbase = networkRadvdPidfileBasename(def->name))) {
2526
            virPidFileDelete(driver->pidDir, radvdpidbase);
2527 2528 2529 2530
            VIR_FREE(radvdpidbase);
        }
    }

2531 2532 2533
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2534

2535 2536
    if (def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(def->bridge);
2537
        if (macTapIfName) {
2538
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2539 2540 2541 2542
            VIR_FREE(macTapIfName);
        }
    }

2543
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2544

2545 2546
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2547

2548
    ignore_value(virNetDevBridgeDelete(def->bridge));
2549

2550
    /* See if its still alive and really really kill it */
2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561
    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);
2562

2563 2564 2565
    return 0;
}

2566

2567
static int
2568
networkStartNetworkBridge(virNetworkObjPtr obj)
2569 2570 2571 2572 2573
{
    /* 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.
     */
2574
    return networkStartHandleMACTableManagerMode(obj, NULL);
2575 2576
}

2577

2578
static int
2579
networkShutdownNetworkBridge(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2580 2581 2582 2583 2584 2585 2586 2587 2588
{
    /* 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;
}


2589 2590 2591 2592 2593 2594 2595 2596 2597
/* 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;
2598
    unsigned int maxVirtFns = 0;
2599 2600 2601 2602 2603 2604
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2605 2606 2607
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2608 2609
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655
        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:
2656
        case VIR_NETWORK_FORWARD_OPEN:
2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696
        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;
}


2697
static int
2698
networkStartNetworkExternal(virNetworkObjPtr obj)
2699 2700
{
    /* put anything here that needs to be done each time a network of
2701
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2702 2703 2704
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2705
    return networkCreateInterfacePool(virNetworkObjGetDef(obj));
2706 2707
}

2708 2709

static int
2710
networkShutdownNetworkExternal(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2711 2712
{
    /* put anything here that needs to be done each time a network of
2713
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2714 2715 2716 2717 2718 2719
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2720

2721
static int
2722
networkStartNetwork(virNetworkDriverStatePtr driver,
2723
                    virNetworkObjPtr obj)
2724
{
2725
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2726 2727
    int ret = -1;

2728
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2729

2730
    if (virNetworkObjIsActive(obj)) {
2731 2732
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2733
        return ret;
2734 2735
    }

2736 2737 2738
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2739
    if (virNetworkObjSetDefTransient(obj, true) < 0)
2740
        goto cleanup;
2741

2742 2743
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2744
    if (networkRunHook(obj, NULL, NULL,
2745 2746 2747 2748
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2749
    switch (def->forward.type) {
2750 2751 2752 2753

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2754
    case VIR_NETWORK_FORWARD_OPEN:
2755
        if (networkStartNetworkVirtual(driver, obj) < 0)
2756
            goto cleanup;
2757 2758 2759
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2760
        if (def->bridge) {
2761
            if (networkStartNetworkBridge(obj) < 0)
2762 2763 2764 2765 2766 2767 2768
                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).
         */
2769 2770
        ATTRIBUTE_FALLTHROUGH;

2771 2772 2773
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2774
    case VIR_NETWORK_FORWARD_HOSTDEV:
2775
        if (networkStartNetworkExternal(obj) < 0)
2776
            goto cleanup;
2777 2778 2779
        break;
    }

2780
    /* finally we can call the 'started' hook script if any */
2781
    if (networkRunHook(obj, NULL, NULL,
2782 2783 2784 2785
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2786 2787 2788
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2789
    VIR_DEBUG("Writing network status to disk");
2790
    if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0)
2791
        goto cleanup;
2792

2793
    virNetworkObjSetActive(obj, true);
2794
    VIR_INFO("Network '%s' started up", def->name);
2795
    ret = 0;
2796

2797
 cleanup:
2798
    if (ret < 0) {
2799
        virNetworkObjUnsetDefTransient(obj);
2800 2801
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
2802
        networkShutdownNetwork(driver, obj);
2803 2804 2805 2806 2807 2808 2809
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2810

2811 2812
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
2813
                       virNetworkObjPtr obj)
2814
{
2815
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2816 2817 2818
    int ret = 0;
    char *stateFile;

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

2821
    if (!virNetworkObjIsActive(obj))
2822 2823
        return 0;

2824
    stateFile = virNetworkConfigFile(driver->stateDir, def->name);
2825 2826 2827 2828 2829 2830
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2831
    switch (def->forward.type) {
2832 2833 2834 2835

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2836
    case VIR_NETWORK_FORWARD_OPEN:
2837
        ret = networkShutdownNetworkVirtual(driver, obj);
2838 2839 2840
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2841
        if (def->bridge) {
2842
            ret = networkShutdownNetworkBridge(obj);
2843 2844 2845 2846 2847 2848
            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).
         */
2849 2850
        ATTRIBUTE_FALLTHROUGH;

2851 2852 2853
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2854
    case VIR_NETWORK_FORWARD_HOSTDEV:
2855
        ret = networkShutdownNetworkExternal(obj);
2856 2857 2858
        break;
    }

2859
    /* now that we know it's stopped call the hook if present */
2860
    networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2861 2862
                   VIR_HOOK_SUBOP_END);

2863
    virNetworkObjSetActive(obj, false);
2864
    virNetworkObjUnsetDefTransient(obj);
2865
    return ret;
2866 2867 2868
}


2869 2870 2871
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
2872
{
2873
    virNetworkDriverStatePtr driver = networkGetDriver();
2874
    virNetworkObjPtr obj;
2875
    virNetworkDefPtr def;
2876
    virNetworkPtr net = NULL;
2877

2878 2879
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
2880 2881
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
2882
        virReportError(VIR_ERR_NO_NETWORK,
2883 2884
                       _("no network with matching uuid '%s'"),
                       uuidstr);
2885
        goto cleanup;
2886
    }
2887
    def = virNetworkObjGetDef(obj);
2888

2889
    if (virNetworkLookupByUUIDEnsureACL(conn, def) < 0)
2890 2891
        goto cleanup;

2892
    net = virGetNetwork(conn, def->name, def->uuid);
2893

2894
 cleanup:
2895 2896
    virNetworkObjEndAPI(&obj);
    return net;
2897 2898
}

2899 2900 2901 2902

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
2903
{
2904
    virNetworkDriverStatePtr driver = networkGetDriver();
2905
    virNetworkObjPtr obj;
2906
    virNetworkDefPtr def;
2907
    virNetworkPtr net = NULL;
2908

2909 2910
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
2911 2912
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
2913
        goto cleanup;
2914
    }
2915
    def = virNetworkObjGetDef(obj);
2916

2917
    if (virNetworkLookupByNameEnsureACL(conn, def) < 0)
2918 2919
        goto cleanup;

2920
    net = virGetNetwork(conn, def->name, def->uuid);
2921

2922
 cleanup:
2923 2924
    virNetworkObjEndAPI(&obj);
    return net;
2925 2926
}

2927 2928 2929

static int
networkConnectNumOfNetworks(virConnectPtr conn)
2930
{
2931
    virNetworkDriverStatePtr driver = networkGetDriver();
2932
    int nactive;
2933

2934 2935 2936
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

2937 2938 2939 2940
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
2941

2942 2943 2944
    return nactive;
}

2945 2946 2947 2948

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
2949
                           int maxnames)
2950 2951
{
    virNetworkDriverStatePtr driver = networkGetDriver();
2952
    int got = 0;
2953

2954 2955 2956
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

2957
    got = virNetworkObjListGetNames(driver->networks,
2958
                                    true, names, maxnames,
2959 2960
                                    virConnectListNetworksCheckACL,
                                    conn);
2961

2962 2963 2964
    return got;
}

2965 2966 2967

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
2968
{
2969
    virNetworkDriverStatePtr driver = networkGetDriver();
2970
    int ninactive = 0;
2971

2972 2973 2974
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2975 2976 2977 2978
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
2979

2980 2981 2982
    return ninactive;
}

2983 2984 2985 2986

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
2987
                                  int maxnames)
2988 2989
{
    virNetworkDriverStatePtr driver = networkGetDriver();
2990
    int got = 0;
2991

2992 2993 2994
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2995
    got = virNetworkObjListGetNames(driver->networks,
2996
                                    false, names, maxnames,
2997 2998
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
2999 3000 3001
    return got;
}

3002

3003
static int
3004 3005 3006
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
3007
{
3008
    virNetworkDriverStatePtr driver = networkGetDriver();
3009 3010 3011 3012
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

3013 3014 3015
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

3016
    ret = virNetworkObjListExport(conn, driver->networks, nets,
3017 3018
                                  virConnectListAllNetworksCheckACL,
                                  flags);
3019

3020
 cleanup:
3021 3022
    return ret;
}
3023

3024

3025 3026 3027 3028 3029 3030 3031 3032
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3033
    virNetworkDriverStatePtr driver = networkGetDriver();
3034 3035 3036 3037 3038 3039
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3040
                                       net, eventID, callback,
3041 3042 3043
                                       opaque, freecb, &ret) < 0)
        ret = -1;

3044
 cleanup:
3045 3046 3047
    return ret;
}

3048

3049 3050 3051 3052
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3053
    virNetworkDriverStatePtr driver = networkGetDriver();
3054 3055 3056 3057 3058
    int ret = -1;

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

3059 3060
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3061
                                        callbackID, true) < 0)
3062 3063 3064
        goto cleanup;

    ret = 0;
3065

3066
 cleanup:
3067 3068 3069
    return ret;
}

3070 3071 3072

static int
networkIsActive(virNetworkPtr net)
3073 3074 3075 3076
{
    virNetworkObjPtr obj;
    int ret = -1;

3077 3078
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3079

3080
    if (virNetworkIsActiveEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3081 3082
        goto cleanup;

3083 3084
    ret = virNetworkObjIsActive(obj);

3085
 cleanup:
3086
    virNetworkObjEndAPI(&obj);
3087 3088 3089
    return ret;
}

3090 3091 3092

static int
networkIsPersistent(virNetworkPtr net)
3093 3094 3095 3096
{
    virNetworkObjPtr obj;
    int ret = -1;

3097 3098
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3099

3100
    if (virNetworkIsPersistentEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3101 3102
        goto cleanup;

3103
    ret = virNetworkObjIsPersistent(obj);
3104

3105
 cleanup:
3106
    virNetworkObjEndAPI(&obj);
3107 3108 3109 3110
    return ret;
}


3111 3112
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
3113 3114 3115
 * 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.
3116 3117 3118 3119 3120 3121 3122 3123
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{

    int ret = -1, id = 0;
    char *newname = NULL;
3124 3125 3126 3127 3128
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3129
        p && p[1] == 'd')
3130
        templ = def->bridge;
3131 3132 3133 3134

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3135 3136 3137 3138 3139
        /* 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).
         */
3140
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3141
              virNetDevExists(newname) == 1)) {
3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174
            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")) {
3175
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192
            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;
}


3193
static int
3194
networkValidate(virNetworkDriverStatePtr driver,
3195
                virNetworkDefPtr def)
3196
{
3197
    size_t i, j;
3198 3199
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3200
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3201
    bool ipv4def = false, ipv6def = false;
3202
    bool bandwidthAllowed = true;
3203
    bool usesInterface = false, usesAddress = false;
3204

3205 3206 3207
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3208 3209 3210
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3211 3212
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
3213 3214
        def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
        def->forward.type == VIR_NETWORK_FORWARD_OPEN) {
3215

3216 3217 3218 3219
        /* 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)
3220 3221 3222
            return -1;

        virNetworkSetBridgeMacAddr(def);
3223 3224
    } else {
        /* They are also the only types that currently support setting
3225 3226
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
3227
         */
3228 3229 3230 3231 3232 3233 3234 3235
        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;
        }
3236
        if (virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0)) {
3237 3238 3239 3240
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3241
                           virNetworkForwardTypeToString(def->forward.type));
3242 3243
            return -1;
        }
3244
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
3245 3246 3247 3248
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3249
                           virNetworkForwardTypeToString(def->forward.type));
3250 3251 3252 3253 3254 3255 3256
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3257
                           virNetworkForwardTypeToString(def->forward.type));
3258 3259
            return -1;
        }
3260 3261 3262 3263 3264 3265 3266 3267
        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;
        }
3268
        bandwidthAllowed = false;
3269 3270
    }

3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283
    /* 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++) {
3284 3285 3286 3287
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

        switch ((virNetworkForwardHostdevDeviceType) iface->type) {
3288 3289
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300

            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;
            }
3301
            break;
3302 3303

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3304
            usesAddress = true;
3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329

            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);
3330
            break;
3331 3332
        }

3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345
        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 已提交
3346 3347 3348
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
3349
    for (i = 0;
3350
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
3351
         i++) {
G
Gene Czarcinski 已提交
3352 3353 3354 3355 3356
        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 -- "
3357 3358
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375
                    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;
                }
3376 3377 3378
            }
        }
    }
3379 3380 3381 3382 3383 3384

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

3385 3386 3387
    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 已提交
3388 3389
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3390
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3391 3392

    vlanUsed = def->vlan.nTags > 0;
3393 3394
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
3395 3396 3397 3398 3399
            /* 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.
             */
3400
            if (def->portGroups[i].virtPortProfile) {
3401
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
3402
                    def->portGroups[i].virtPortProfile->virtPortType
3403 3404 3405 3406 3407 3408 3409
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
3410
        }
3411
        if (def->portGroups[i].isDefault) {
3412 3413 3414 3415 3416
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
3417
                               def->name, defaultPortGroup->name,
3418
                               def->portGroups[i].name);
3419
                return -1;
3420
            }
3421
            defaultPortGroup = &def->portGroups[i];
3422
        }
3423 3424 3425 3426 3427 3428 3429 3430 3431
        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;
            }
        }
3432 3433 3434 3435 3436 3437 3438 3439
        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;
        }
3440
    }
3441 3442 3443 3444 3445 3446 3447
    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.
         */
3448 3449 3450 3451 3452 3453
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467

    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;
            }
        }
    }
3468 3469 3470
    return 0;
}

3471 3472 3473 3474

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3475
{
3476
    virNetworkDriverStatePtr driver = networkGetDriver();
3477
    virNetworkDefPtr newDef;
3478
    virNetworkObjPtr obj = NULL;
3479
    virNetworkDefPtr def;
3480
    virNetworkPtr net = NULL;
3481
    virObjectEventPtr event = NULL;
3482

3483
    if (!(newDef = virNetworkDefParseString(xml)))
3484
        goto cleanup;
3485

3486
    if (virNetworkCreateXMLEnsureACL(conn, newDef) < 0)
3487 3488
        goto cleanup;

3489
    if (networkValidate(driver, newDef) < 0)
J
Ján Tomko 已提交
3490
        goto cleanup;
3491

3492 3493 3494
    /* 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.
3495
     */
3496
    if (!(obj = virNetworkObjAssignDef(driver->networks, newDef,
3497 3498
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3499
        goto cleanup;
3500 3501
    newDef = NULL;
    def = virNetworkObjGetDef(obj);
3502

3503 3504
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3505
        goto cleanup;
3506 3507
    }

3508 3509
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3510 3511
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3512

3513 3514
    VIR_INFO("Creating network '%s'", def->name);
    net = virGetNetwork(conn, def->name, def->uuid);
3515

3516
 cleanup:
3517
    virNetworkDefFree(newDef);
3518 3519
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3520 3521
    virNetworkObjEndAPI(&obj);
    return net;
3522 3523
}

3524 3525 3526 3527

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3528
{
3529
    virNetworkDriverStatePtr driver = networkGetDriver();
3530
    virNetworkDefPtr def = NULL;
3531
    bool freeDef = true;
3532 3533
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3534
    virObjectEventPtr event = NULL;
3535

3536
    if (!(def = virNetworkDefParseString(xml)))
3537
        goto cleanup;
3538

3539 3540 3541
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3542
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3543
        goto cleanup;
3544

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

3548
    /* def was assigned to network object */
3549
    freeDef = false;
3550 3551

    if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
3552 3553
        if (!virNetworkObjIsActive(obj)) {
            virNetworkObjRemoveInactive(driver->networks, obj);
3554 3555
            goto cleanup;
        }
3556 3557 3558 3559
        /* if network was active already, just undo new persistent
         * definition by making it transient.
         * XXX - this isn't necessarily the correct thing to do.
         */
3560
        virNetworkObjUpdateAssignDef(obj, NULL, false);
3561 3562 3563
        goto cleanup;
    }

3564
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3565 3566
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3567

3568
    VIR_INFO("Defining network '%s'", def->name);
3569
    net = virGetNetwork(conn, def->name, def->uuid);
3570

3571
 cleanup:
3572 3573
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3574
    if (freeDef)
J
Ján Tomko 已提交
3575
        virNetworkDefFree(def);
3576 3577
    virNetworkObjEndAPI(&obj);
    return net;
3578 3579
}

3580

3581
static int
3582 3583
networkUndefine(virNetworkPtr net)
{
3584
    virNetworkDriverStatePtr driver = networkGetDriver();
3585
    virNetworkObjPtr obj;
3586
    virNetworkDefPtr def;
3587
    int ret = -1;
3588
    bool active = false;
3589
    virObjectEventPtr event = NULL;
3590

3591
    if (!(obj = networkObjFromNetwork(net)))
3592
        goto cleanup;
3593
    def = virNetworkObjGetDef(obj);
3594

3595
    if (virNetworkUndefineEnsureACL(net->conn, def) < 0)
3596 3597
        goto cleanup;

3598
    if (virNetworkObjIsActive(obj))
3599
        active = true;
3600

3601
    if (!virNetworkObjIsPersistent(obj)) {
3602 3603 3604 3605 3606
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3607
    /* remove autostart link */
3608 3609
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3610
                                  obj) < 0)
3611
        goto cleanup;
3612

3613 3614
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3615 3616
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3617

3618
    VIR_INFO("Undefining network '%s'", def->name);
3619
    if (!active) {
3620
        if (networkRemoveInactive(driver, obj) < 0)
3621
            goto cleanup;
3622 3623 3624 3625 3626
    } else {

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

3630
    ret = 0;
3631

3632
 cleanup:
3633 3634
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3635
    virNetworkObjEndAPI(&obj);
3636
    return ret;
3637 3638
}

3639

3640 3641 3642 3643 3644 3645 3646 3647
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3648
    virNetworkDriverStatePtr driver = networkGetDriver();
3649
    virNetworkObjPtr obj = NULL;
3650
    virNetworkDefPtr def;
3651 3652
    int isActive, ret = -1;
    size_t i;
3653
    virNetworkIPDefPtr ipdef;
3654
    bool oldDhcpActive = false;
3655
    bool needFirewallRefresh = false;
3656

3657 3658 3659 3660 3661

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3662
    if (!(obj = networkObjFromNetwork(net)))
3663
        goto cleanup;
3664
    def = virNetworkObjGetDef(obj);
3665

3666
    if (virNetworkUpdateEnsureACL(net->conn, def, flags) < 0)
3667 3668
        goto cleanup;

3669
    /* see if we are listening for dhcp pre-modification */
3670
    for (i = 0;
3671
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3672
         i++) {
3673 3674 3675 3676 3677 3678
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3679 3680
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3681
     */
3682
    isActive = virNetworkObjIsActive(obj);
3683 3684
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3685 3686 3687 3688 3689 3690 3691
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3692 3693 3694 3695
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
3696 3697 3698
        if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
            def->forward.type == VIR_NETWORK_FORWARD_NAT ||
            def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
3699 3700 3701 3702 3703 3704 3705 3706 3707 3708
            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).
                 */
3709 3710
                if (def->forward.type != VIR_NETWORK_FORWARD_OPEN) {
                    networkRemoveFirewallRules(def);
3711 3712
                    needFirewallRefresh = true;
                }
3713 3714 3715 3716 3717 3718 3719
                break;
            default:
                break;
            }
        }
    }

3720
    /* update the network config in memory/on disk */
3721
    if (virNetworkObjUpdate(obj, command, section, parentIndex, xml, flags) < 0) {
3722
        if (needFirewallRefresh)
3723
            ignore_value(networkAddFirewallRules(def));
3724 3725 3726
        goto cleanup;
    }

3727 3728 3729 3730
    /* @def is replaced */
    def = virNetworkObjGetDef(obj);

    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
3731 3732 3733 3734 3735
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
3736
                                 virNetworkObjGetPersistentDef(obj)) < 0) {
3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749
            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 ||
3750 3751 3752 3753 3754 3755 3756 3757
            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)
3758
             */
3759
            if (networkRestartDhcpDaemon(driver, obj) < 0)
3760 3761
                goto cleanup;

3762 3763 3764 3765 3766 3767 3768 3769
        } 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;

3770
            for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3771
                 i++) {
3772 3773 3774 3775 3776 3777 3778
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3779 3780
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
3781 3782 3783
                goto cleanup;
            }

3784 3785 3786 3787
        } 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.
3788
             */
3789
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
3790 3791 3792 3793 3794 3795 3796 3797
                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.
             */
3798
            if (networkRefreshRadvd(driver, obj) < 0)
3799 3800 3801 3802
                goto cleanup;
        }

        /* save current network state to disk */
3803
        if ((ret = virNetworkObjSaveStatus(driver->stateDir, obj)) < 0)
3804 3805
            goto cleanup;
    }
3806 3807

    /* call the 'updated' network hook script */
3808
    if (networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_UPDATED,
3809 3810 3811
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

3812
    ret = 0;
3813
 cleanup:
3814
    virNetworkObjEndAPI(&obj);
3815 3816 3817
    return ret;
}

3818 3819 3820

static int
networkCreate(virNetworkPtr net)
3821
{
3822
    virNetworkDriverStatePtr driver = networkGetDriver();
3823
    virNetworkObjPtr obj;
3824
    virNetworkDefPtr def;
3825
    int ret = -1;
3826
    virObjectEventPtr event = NULL;
3827

3828
    if (!(obj = networkObjFromNetwork(net)))
3829
        goto cleanup;
3830
    def = virNetworkObjGetDef(obj);
3831

3832
    if (virNetworkCreateEnsureACL(net->conn, def) < 0)
3833 3834
        goto cleanup;

3835
    if ((ret = networkStartNetwork(driver, obj)) < 0)
3836
        goto cleanup;
3837

3838 3839
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3840 3841
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3842

3843
 cleanup:
3844 3845
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3846
    virNetworkObjEndAPI(&obj);
3847
    return ret;
3848 3849
}

3850 3851 3852

static int
networkDestroy(virNetworkPtr net)
3853
{
3854
    virNetworkDriverStatePtr driver = networkGetDriver();
3855
    virNetworkObjPtr obj;
3856
    virNetworkDefPtr def;
3857
    int ret = -1;
3858
    virObjectEventPtr event = NULL;
3859

3860
    if (!(obj = networkObjFromNetwork(net)))
3861
        goto cleanup;
3862
    def = virNetworkObjGetDef(obj);
3863

3864
    if (virNetworkDestroyEnsureACL(net->conn, def) < 0)
3865 3866
        goto cleanup;

3867
    if (!virNetworkObjIsActive(obj)) {
3868
        virReportError(VIR_ERR_OPERATION_INVALID,
3869
                       _("network '%s' is not active"),
3870
                       def->name);
3871 3872 3873
        goto cleanup;
    }

3874
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
3875
        goto cleanup;
3876 3877
    /* @def replaced in virNetworkObjUnsetDefTransient*/
    def = virNetworkObjGetDef(obj);
3878

3879 3880
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3881 3882
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
3883

3884 3885
    if (!virNetworkObjIsPersistent(obj) &&
        networkRemoveInactive(driver, obj) < 0) {
3886 3887
        ret = -1;
        goto cleanup;
3888
    }
3889

3890
 cleanup:
3891 3892
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3893
    virNetworkObjEndAPI(&obj);
3894 3895 3896
    return ret;
}

3897 3898 3899 3900

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
3901
{
3902
    virNetworkObjPtr obj;
3903
    virNetworkDefPtr curDef;
3904
    virNetworkDefPtr def;
3905
    virNetworkDefPtr newDef;
3906
    char *ret = NULL;
3907

3908
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
3909

3910
    if (!(obj = networkObjFromNetwork(net)))
3911
        return ret;
3912 3913
    def = virNetworkObjGetDef(obj);
    newDef = virNetworkObjGetNewDef(obj);
3914

3915
    if (virNetworkGetXMLDescEnsureACL(net->conn, def) < 0)
3916 3917
        goto cleanup;

3918 3919
    if ((flags & VIR_NETWORK_XML_INACTIVE) && newDef)
        curDef = newDef;
3920
    else
3921
        curDef = def;
3922

3923
    ret = virNetworkDefFormat(curDef, flags);
3924

3925
 cleanup:
3926
    virNetworkObjEndAPI(&obj);
3927
    return ret;
3928 3929
}

3930 3931 3932 3933

static char *
networkGetBridgeName(virNetworkPtr net)
{
3934
    virNetworkObjPtr obj;
3935
    virNetworkDefPtr def;
3936 3937
    char *bridge = NULL;

3938
    if (!(obj = networkObjFromNetwork(net)))
3939
        return bridge;
3940
    def = virNetworkObjGetDef(obj);
3941

3942
    if (virNetworkGetBridgeNameEnsureACL(net->conn, def) < 0)
3943 3944
        goto cleanup;

3945
    if (!(def->bridge)) {
3946 3947
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
3948
                       def->name);
3949 3950 3951
        goto cleanup;
    }

3952
    ignore_value(VIR_STRDUP(bridge, def->bridge));
3953

3954
 cleanup:
3955
    virNetworkObjEndAPI(&obj);
3956 3957 3958
    return bridge;
}

3959 3960 3961 3962

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
3963
{
3964
    virNetworkObjPtr obj;
3965
    int ret = -1;
3966

3967
    if (!(obj = networkObjFromNetwork(net)))
3968
        return ret;
3969

3970
    if (virNetworkGetAutostartEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3971 3972
        goto cleanup;

3973
    *autostart = virNetworkObjIsAutostart(obj) ? 1 : 0;
3974
    ret = 0;
3975

3976
 cleanup:
3977
    virNetworkObjEndAPI(&obj);
3978
    return ret;
3979 3980
}

3981 3982 3983 3984

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
3985
{
3986
    virNetworkDriverStatePtr driver = networkGetDriver();
3987
    virNetworkObjPtr obj;
3988
    virNetworkDefPtr def;
3989
    char *configFile = NULL, *autostartLink = NULL;
3990 3991
    bool new_autostart;
    bool cur_autostart;
3992
    int ret = -1;
3993

3994
    if (!(obj = networkObjFromNetwork(net)))
3995
        goto cleanup;
3996
    def = virNetworkObjGetDef(obj);
3997

3998
    if (virNetworkSetAutostartEnsureACL(net->conn, def) < 0)
3999 4000
        goto cleanup;

4001
    if (!virNetworkObjIsPersistent(obj)) {
4002 4003
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
4004 4005 4006
        goto cleanup;
    }

4007 4008 4009
    new_autostart = (autostart != 0);
    cur_autostart = virNetworkObjIsAutostart(obj);
    if (cur_autostart != new_autostart) {
4010 4011
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir,
                                               def->name)) == NULL)
4012
            goto cleanup;
4013 4014
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir,
                                                  def->name)) == NULL)
4015 4016
            goto cleanup;

4017
        if (new_autostart) {
4018
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
4019
                virReportSystemError(errno,
4020 4021
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
4022 4023
                goto cleanup;
            }
4024

4025
            if (symlink(configFile, autostartLink) < 0) {
4026
                virReportSystemError(errno,
4027
                                     _("Failed to create symlink '%s' to '%s'"),
4028
                                     autostartLink, configFile);
4029 4030 4031
                goto cleanup;
            }
        } else {
4032
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4033
                virReportSystemError(errno,
4034
                                     _("Failed to delete symlink '%s'"),
4035
                                     autostartLink);
4036 4037
                goto cleanup;
            }
4038 4039
        }

4040
        virNetworkObjSetAutostart(obj, new_autostart);
4041
    }
4042

4043
    ret = 0;
4044

4045
 cleanup:
4046 4047
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4048
    virNetworkObjEndAPI(&obj);
4049
    return ret;
4050 4051
}

4052

4053
static int
4054
networkGetDHCPLeases(virNetworkPtr net,
4055 4056 4057
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
4058
{
4059
    virNetworkDriverStatePtr driver = networkGetDriver();
4060 4061 4062
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
4063
    ssize_t size = 0;
4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074
    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;
4075
    virNetworkIPDefPtr ipdef_tmp = NULL;
4076 4077
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
4078
    virNetworkObjPtr obj;
4079
    virNetworkDefPtr def;
4080
    virMacAddr mac_addr;
4081 4082 4083

    virCheckFlags(0, -1);

4084 4085 4086 4087 4088 4089
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4090
    if (!(obj = networkObjFromNetwork(net)))
4091
        return -1;
4092
    def = virNetworkObjGetDef(obj);
4093

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

    /* Retrieve custom leases file location */
4098
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, def->bridge);
4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141

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

    currtime = (long long) time(NULL);

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

4142
        if (mac && virMacAddrCompare(mac, mac_tmp))
4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173
            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 */
4174 4175
            for (j = 0; j < def->nips; j++) {
                ipdef_tmp = &def->ips[j];
4176 4177 4178 4179 4180 4181 4182 4183

                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)) {
4184
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4185 4186 4187 4188 4189 4190 4191 4192
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
4193
                (VIR_STRDUP(lease->iface, def->bridge) < 0))
4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225
                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);
4226
    VIR_FREE(lease_entries);
4227 4228
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4229

4230
    virNetworkObjEndAPI(&obj);
4231

4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242
    return rv;

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

4243 4244

static virNetworkDriver networkDriver = {
4245
    .name = "bridge",
4246 4247 4248 4249 4250
    .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 */
4251 4252
    .connectNetworkEventRegisterAny = networkConnectNetworkEventRegisterAny, /* 1.2.1 */
    .connectNetworkEventDeregisterAny = networkConnectNetworkEventDeregisterAny, /* 1.2.1 */
4253 4254
    .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
    .networkLookupByName = networkLookupByName, /* 0.2.0 */
4255 4256
    .networkCreateXML = networkCreateXML, /* 0.2.0 */
    .networkDefineXML = networkDefineXML, /* 0.2.0 */
4257
    .networkUndefine = networkUndefine, /* 0.2.0 */
4258
    .networkUpdate = networkUpdate, /* 0.10.2 */
4259
    .networkCreate = networkCreate, /* 0.2.0 */
4260 4261 4262 4263 4264 4265 4266
    .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 */
4267
    .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.2.6 */
4268 4269 4270
};

static virStateDriver networkStateDriver = {
4271
    .name = "bridge",
4272
    .stateInitialize  = networkStateInitialize,
4273
    .stateAutoStart  = networkStateAutoStart,
4274 4275
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
4276 4277
};

4278 4279
int
networkRegister(void)
4280
{
4281
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
4282
        return -1;
4283 4284
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
4285 4286
    return 0;
}
4287

4288

4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323
/* 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);
        }
    }
}

4324

4325 4326 4327 4328 4329 4330 4331 4332 4333
/* 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:
4334
 * @dom: domain definition that @iface belongs to
4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345
 * @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.
 */
int
4346 4347
networkAllocateActualDevice(virDomainDefPtr dom,
                            virDomainNetDefPtr iface)
4348
{
4349
    virNetworkDriverStatePtr driver = networkGetDriver();
4350
    virDomainNetType actualType = iface->type;
4351
    virNetworkObjPtr obj = NULL;
4352
    virNetworkDefPtr netdef = NULL;
4353
    virNetDevBandwidthPtr bandwidth = NULL;
4354 4355 4356
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
4357
    virNetworkForwardIfDefPtr dev = NULL;
4358
    size_t i;
4359 4360 4361
    int ret = -1;

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4362
        goto validate;
4363 4364 4365 4366

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

4367 4368
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4369 4370 4371
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4372
        goto error;
4373
    }
4374
    netdef = virNetworkObjGetDef(obj);
4375

4376
    if (!virNetworkObjIsActive(obj)) {
4377 4378 4379 4380 4381 4382
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4383 4384 4385
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

4386 4387 4388
    /* 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 已提交
4389
     */
4390 4391 4392 4393 4394 4395
    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.
     */
4396 4397 4398 4399 4400 4401

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

4402 4403
    if (bandwidth && virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
                                            bandwidth) < 0)
4404
        goto error;
4405

4406 4407 4408 4409 4410 4411 4412 4413
    /* 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;

4414 4415
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
4416

4417 4418 4419 4420 4421 4422 4423 4424 4425 4426
    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;

4427 4428
    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
4429 4430
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
4431
        /* for these forward types, the actual net type really *is*
4432
         * NETWORK; we just keep the info from the portgroup in
4433
         * iface->data.network.actual
J
Ján Tomko 已提交
4434
         */
4435
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
4436

4437
        /* we also store the bridge device and macTableManager settings
4438 4439 4440 4441 4442 4443 4444
         * 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;
4445 4446
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4447

4448
        if (networkPlugBandwidth(obj, iface) < 0)
4449 4450
            goto error;

4451
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
4452
               netdef->bridge) {
4453 4454 4455 4456 4457

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

4458
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
4459 4460
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
4461
            goto error;
4462 4463
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4464

4465 4466 4467 4468 4469 4470 4471 4472
        /* 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) {
4473
            goto error;
4474 4475 4476 4477 4478 4479 4480 4481 4482 4483
        }
        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);
4484
                goto error;
4485 4486 4487
            }
        }

4488
    } else if (netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4489

4490
        virDomainHostdevSubsysPCIBackendType backend;
4491

4492
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
4493
        if (networkCreateInterfacePool(netdef) < 0)
4494 4495 4496
            goto error;

        /* pick first dev with 0 connections */
4497 4498 4499
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513
                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;
4514
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
4515
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
4516
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
4517

E
Eric Blake 已提交
4518
        switch (netdef->forward.driverName) {
4519
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
4520
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4521 4522
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
4523
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
4524 4525
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
4526
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537
            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;

4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562
        /* 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;
            }
        }

4563 4564 4565 4566
    } 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)) {
4567 4568 4569 4570 4571 4572

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

        /* Set type=direct and appropriate <source mode='xxx'/> */
4573
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
4574
        switch (netdef->forward.type) {
4575
        case VIR_NETWORK_FORWARD_BRIDGE:
4576
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
4577 4578
            break;
        case VIR_NETWORK_FORWARD_PRIVATE:
4579
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
4580 4581
            break;
        case VIR_NETWORK_FORWARD_VEPA:
4582
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
4583 4584
            break;
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
4585
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PASSTHRU;
4586 4587 4588
            break;
        }

4589 4590 4591 4592 4593 4594 4595 4596
        /* 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) {
4597
            goto error;
4598
        }
4599
        virtport = iface->data.network.actual->virtPortProfile;
4600
        if (virtport) {
4601 4602 4603 4604 4605 4606 4607 4608
            /* 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);
4609
                goto error;
4610 4611
            }
        }
4612

4613 4614 4615
        /* 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).
         */
4616
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4617 4618 4619 4620
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4621
            goto error;
4622 4623 4624
        } else {
            /* pick an interface from the pool */

4625
            if (networkCreateInterfacePool(netdef) < 0)
4626 4627
                goto error;

4628 4629 4630 4631 4632
            /* 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.
4633
             */
4634 4635
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4636 4637 4638
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4639

4640
                /* pick first dev with 0 connections */
4641 4642 4643
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4644 4645 4646 4647 4648
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4649
                dev = &netdef->forward.ifs[0];
4650 4651 4652
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4653 4654 4655 4656
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4657 4658 4659 4660
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4661
                goto error;
4662
            }
4663 4664
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
4665
                goto error;
4666 4667 4668
        }
    }

4669 4670
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
                               dom->name, &iface->mac) < 0)
M
Michal Privoznik 已提交
4671 4672
        goto error;

4673
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
4674
        goto error;
4675

4676
 validate:
4677 4678 4679 4680 4681
    /* 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.
     */

4682
    if (virDomainNetGetActualVlan(iface)) {
4683 4684 4685 4686
        /* 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
4687 4688
         */
        if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
4689 4690 4691
              (actualType == VIR_DOMAIN_NET_TYPE_DIRECT &&
               virDomainNetGetActualDirectMode(iface)
               == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) ||
4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710
              (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;
        }
    }
4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721
    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;
        }
    }
4722 4723 4724

    if (netdef) {
        netdef->connections++;
4725
        if (dev)
4726 4727
            dev->connections++;
        /* finally we can call the 'plugged' hook script if any */
4728
        if (networkRunHook(obj, dom, iface,
4729 4730 4731
                           VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
                           VIR_HOOK_SUBOP_BEGIN) < 0) {
            /* adjust for failure */
4732
            netdef->connections--;
4733 4734 4735 4736
            if (dev)
                dev->connections--;
            goto error;
        }
4737
        networkLogAllocation(netdef, actualType, dev, iface, true);
4738 4739
    }

4740
    ret = 0;
4741

4742
 cleanup:
4743
    virNetworkObjEndAPI(&obj);
4744 4745
    return ret;

4746
 error:
4747
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4748 4749 4750
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4751
    goto cleanup;
4752 4753
}

4754

4755
/* networkNotifyActualDevice:
4756
 * @dom: domain definition that @iface belongs to
4757 4758 4759 4760 4761
 * @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
4762 4763
 * order, or re-attach the interface's tap device to the network's
 * bridge.
4764
 *
4765
 * No return value (but does log any failures)
4766
 */
4767
void
4768 4769
networkNotifyActualDevice(virDomainDefPtr dom,
                          virDomainNetDefPtr iface)
4770
{
4771
    virNetworkDriverStatePtr driver = networkGetDriver();
4772
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4773
    virNetworkObjPtr obj;
4774
    virNetworkDefPtr netdef;
4775
    virNetworkForwardIfDefPtr dev = NULL;
4776
    size_t i;
4777
    char *master = NULL;
4778 4779

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4780
        return;
4781

4782 4783
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4784 4785 4786
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4787 4788
        goto error;
    }
4789
    netdef = virNetworkObjGetDef(obj);
4790

4791
    if (!virNetworkObjIsActive(obj)) {
4792 4793 4794 4795 4796 4797
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808
    /* 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;

4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833
    /* 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;
            }
        }
    }

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

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

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

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

4855 4856 4857 4858 4859 4860 4861 4862 4863
        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 */
4864 4865
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4866
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4867 4868
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4869 4870 4871 4872 4873
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4874
            virReportError(VIR_ERR_INTERNAL_ERROR,
4875 4876
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4877
                           netdef->name, actualDev);
4878
            goto error;
4879 4880
        }

4881
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4882 4883
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4884
         */
4885
        if ((dev->connections > 0) &&
4886 4887
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4888 4889
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
4890
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4891
            virReportError(VIR_ERR_INTERNAL_ERROR,
4892 4893
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
4894
                           netdef->name, actualDev);
4895
            goto error;
4896
        }
4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908
    }  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 */
4909 4910
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4911
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4912
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
4913 4914
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4915 4916 4917 4918 4919 4920 4921 4922 4923
                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,
4924 4925 4926 4927
                           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 已提交
4928
            goto error;
4929 4930 4931 4932 4933 4934 4935
        }

        /* 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) &&
4936
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4937 4938 4939 4940 4941 4942 4943 4944 4945
            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;
        }
4946 4947
    }

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

4963
 cleanup:
4964
    virNetworkObjEndAPI(&obj);
4965
    VIR_FREE(master);
4966
    return;
4967

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


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

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

4999 5000
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5001 5002 5003
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
5004 5005
        goto error;
    }
5006
    netdef = virNetworkObjGetDef(obj);
5007

5008 5009
    if (iface->data.network.actual &&
        (netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
5010
         netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
5011 5012
         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
         netdef->forward.type == VIR_NETWORK_FORWARD_OPEN) &&
5013
        networkUnplugBandwidth(obj, iface) < 0)
5014 5015
        goto error;

5016 5017 5018
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
5019 5020
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
5021 5022
    }

5023
    if (netdef->forward.nifs == 0) {
5024
        virReportError(VIR_ERR_INTERNAL_ERROR,
5025
                       _("network '%s' uses a direct/hostdev mode, but "
5026 5027
                         "has no forward dev and no interface pool"),
                       netdef->name);
5028
        goto error;
5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040
    }

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

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

5051
        if (!dev) {
5052
            virReportError(VIR_ERR_INTERNAL_ERROR,
5053 5054
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5055
                           netdef->name, actualDev);
5056
            goto error;
5057
        }
5058 5059 5060 5061 5062 5063 5064 5065 5066 5067
    } 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;
        }

5068 5069
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5070
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5071
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
5072 5073
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5074 5075 5076 5077 5078 5079 5080 5081 5082
                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,
5083 5084 5085 5086
                           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 已提交
5087
            goto error;
5088
        }
J
Ján Tomko 已提交
5089
    }
5090

5091
 success:
5092
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, dom->name, &iface->mac);
M
Michal Privoznik 已提交
5093

5094
    if (iface->data.network.actual) {
5095
        netdef->connections--;
5096 5097
        if (dev)
            dev->connections--;
5098
        /* finally we can call the 'unplugged' hook script if any */
5099
        networkRunHook(obj, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
5100
                       VIR_HOOK_SUBOP_BEGIN);
5101
        networkLogAllocation(netdef, actualType, dev, iface, false);
5102
    }
5103
    ret = 0;
5104
 cleanup:
5105
    virNetworkObjEndAPI(&obj);
5106 5107 5108 5109
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
5110
    return ret;
5111

5112
 error:
5113
    goto cleanup;
5114
}
5115

5116

5117 5118 5119 5120 5121
/*
 * networkGetNetworkAddress:
 * @netname: the name of a network
 * @netaddr: string representation of IP address for that network.
 *
5122
 * Attempt to return an IP address associated with the named
5123 5124 5125 5126
 * network. If a libvirt virtual network, that will be provided in the
 * configuration. For host bridge and direct (macvtap) networks, we
 * must do an ioctl to learn the address.
 *
5127
 * Note: This function returns the first IP address it finds. It might
5128 5129 5130 5131 5132 5133 5134 5135 5136
 * be useful if it was more flexible, but the current use (getting a
 * listen address for qemu's vnc/spice graphics server) can only use a
 * single address anyway.
 *
 * Returns 0 on success, and puts a string (which must be free'd by
 * the caller) into *netaddr. Returns -1 on failure or -2 if
 * completely unsupported.
 */
int
5137 5138
networkGetNetworkAddress(const char *netname,
                         char **netaddr)
5139
{
5140
    virNetworkDriverStatePtr driver = networkGetDriver();
5141
    int ret = -1;
5142
    virNetworkObjPtr obj;
5143
    virNetworkDefPtr netdef;
5144
    virNetworkIPDefPtr ipdef;
5145 5146
    virSocketAddr addr;
    virSocketAddrPtr addrptr = NULL;
5147
    char *dev_name = NULL;
5148 5149

    *netaddr = NULL;
5150 5151
    obj = virNetworkObjFindByName(driver->networks, netname);
    if (!obj) {
5152 5153 5154
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       netname);
5155
        goto cleanup;
5156
    }
5157
    netdef = virNetworkObjGetDef(obj);
5158

5159
    switch (netdef->forward.type) {
5160 5161 5162
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
5163
    case VIR_NETWORK_FORWARD_OPEN:
5164
        ipdef = virNetworkDefGetIPByIndex(netdef, AF_UNSPEC, 0);
5165
        if (!ipdef) {
5166
            virReportError(VIR_ERR_INTERNAL_ERROR,
5167
                           _("network '%s' doesn't have an IP address"),
5168
                           netdef->name);
5169
            goto cleanup;
5170 5171 5172 5173 5174
        }
        addrptr = &ipdef->address;
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
5175
        if ((dev_name = netdef->bridge))
5176 5177
            break;
        /*
5178 5179
         * fall through if netdef->bridge wasn't set, since that is
         * macvtap bridge mode network.
5180
         */
5181 5182
        ATTRIBUTE_FALLTHROUGH;

5183 5184 5185
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
5186 5187
        if ((netdef->forward.nifs > 0) && netdef->forward.ifs)
            dev_name = netdef->forward.ifs[0].device.dev;
5188

5189
        if (!dev_name) {
5190 5191 5192
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' has no associated interface or bridge"),
                           netdef->name);
5193
            goto cleanup;
5194 5195 5196 5197
        }
        break;
    }

5198
    if (dev_name) {
5199
        if (virNetDevIPAddrGet(dev_name, &addr) < 0)
5200
            goto cleanup;
5201
        addrptr = &addr;
5202 5203
    }

5204 5205
    if (!(addrptr &&
          (*netaddr = virSocketAddrFormat(addrptr)))) {
5206
        goto cleanup;
5207 5208
    }

5209
    ret = 0;
5210
 cleanup:
5211
    virNetworkObjEndAPI(&obj);
5212 5213
    return ret;
}
5214

5215

5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228
/* networkGetActualType:
 * @dom: domain definition that @iface belongs to
 * @iface: the original NetDef from the domain
 *
 * Looks up the network reference by iface, and returns the actual
 * type of the connection without allocating any resources.
 *
 * Returns 0 on success, -1 on failure.
 */
int
networkGetActualType(virDomainNetDefPtr iface)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5229
    virNetworkObjPtr obj = NULL;
5230 5231 5232 5233 5234 5235 5236 5237 5238
    virNetworkDefPtr netdef = NULL;
    int ret = -1;

    if (!driver || iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
        return iface->type;

    if (iface->data.network.actual)
        return iface->data.network.actual->type;

5239 5240
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5241 5242 5243 5244 5245
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return -1;
    }
5246
    netdef = virNetworkObjGetDef(obj);
5247 5248 5249

    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
5250 5251
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283
        /* for these forward types, the actual net type really *is*
         * NETWORK; we just keep the info from the portgroup in
         * iface->data.network.actual
         */
        ret = VIR_DOMAIN_NET_TYPE_NETWORK;

    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
               netdef->bridge) {

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

        ret = VIR_DOMAIN_NET_TYPE_BRIDGE;

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

        ret = VIR_DOMAIN_NET_TYPE_HOSTDEV;

    } 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)) {

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

        ret = VIR_DOMAIN_NET_TYPE_DIRECT;

    }

5284
    virNetworkObjEndAPI(&obj);
5285 5286 5287 5288
    return ret;
}


5289 5290 5291
/**
 * networkCheckBandwidth:
 * @net: network QoS
5292
 * @ifaceBand: interface QoS (may be NULL if no QoS)
5293
 * @oldBandwidth: new interface QoS (may be NULL if no QoS)
5294
 * @ifaceMac: interface MAC (used in error messages for identification)
5295 5296
 * @new_rate: new rate for non guaranteed class
 *
5297 5298 5299 5300 5301 5302 5303 5304
 * 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.
 *
5305 5306 5307 5308 5309
 * 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
5310
networkCheckBandwidth(virNetworkObjPtr obj,
5311
                      virNetDevBandwidthPtr ifaceBand,
5312
                      virNetDevBandwidthPtr oldBandwidth,
5313
                      virMacAddr ifaceMac,
5314 5315 5316
                      unsigned long long *new_rate)
{
    int ret = -1;
5317 5318
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    virNetDevBandwidthPtr netBand = def->bandwidth;
5319
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5320 5321 5322
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5323
    virMacAddrFormat(&ifaceMac, ifmac);
5324 5325 5326 5327 5328 5329

    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"),
5330
                       ifmac, def->name);
5331 5332 5333
        return -1;
    }

5334 5335
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor)) ||
5336 5337
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
5338
        return 1;
5339
    }
5340 5341

    tmp_new_rate = netBand->in->average;
5342 5343 5344 5345
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
5346 5347 5348 5349 5350 5351 5352 5353 5354

    /* 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,
5355 5356
                           def->bridge,
                           def->name);
5357 5358 5359 5360 5361 5362 5363 5364 5365
            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,
5366 5367
                       def->bridge,
                       def->name);
5368 5369 5370
        goto cleanup;
    }

5371 5372
    if (new_rate)
        *new_rate = tmp_new_rate;
5373 5374
    ret = 0;

5375
 cleanup:
5376 5377 5378
    return ret;
}

5379

5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390
/**
 * 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
5391
networkNextClassID(virNetworkObjPtr obj)
5392
{
5393
    ssize_t ret = 0;
5394
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5395

5396 5397
    if ((ret = virBitmapNextClearBit(classIdMap, -1)) < 0)
        ret = virBitmapSize(classIdMap);
5398

5399
    if (virBitmapSetBitExpand(classIdMap, ret) < 0)
5400 5401 5402 5403 5404
        return -1;

    return ret;
}

5405

5406
static int
5407
networkPlugBandwidthImpl(virNetworkObjPtr obj,
5408 5409 5410
                         virDomainNetDefPtr iface,
                         virNetDevBandwidthPtr ifaceBand,
                         unsigned long long new_rate)
5411
{
5412
    virNetworkDriverStatePtr driver = networkGetDriver();
5413
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5414
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5415
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5416
    ssize_t class_id = 0;
5417 5418
    int plug_ret;
    int ret = -1;
5419 5420

    /* generate new class_id */
5421
    if ((class_id = networkNextClassID(obj)) < 0) {
5422 5423 5424 5425 5426
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate next class ID"));
        goto cleanup;
    }

5427
    plug_ret = virNetDevBandwidthPlug(def->bridge, def->bandwidth,
5428
                                      &iface->mac, ifaceBand, class_id);
5429
    if (plug_ret < 0) {
5430
        ignore_value(virNetDevBandwidthUnplug(def->bridge, class_id));
5431 5432 5433 5434 5435 5436
        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 */
5437 5438
    tmp_floor_sum += ifaceBand->in->floor;
    virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5439
    /* update status file */
5440
    if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5441
        ignore_value(virBitmapClearBit(classIdMap, class_id));
5442 5443
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5444
        iface->data.network.actual->class_id = 0;
5445
        ignore_value(virNetDevBandwidthUnplug(def->bridge, class_id));
5446 5447
        goto cleanup;
    }
5448
    /* update rate for non guaranteed NICs */
5449
    new_rate -= tmp_floor_sum;
5450 5451
    if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                     def->bandwidth, new_rate) < 0)
5452
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5453
                 def->bridge);
5454 5455

    ret = 0;
5456 5457 5458 5459 5460 5461
 cleanup:
    return ret;
}


static int
5462
networkPlugBandwidth(virNetworkObjPtr obj,
5463 5464 5465 5466 5467 5468 5469 5470
                     virDomainNetDefPtr iface)
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);

5471
    if ((plug_ret = networkCheckBandwidth(obj, ifaceBand, NULL,
5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491
                                          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;
    }

5492
    if (networkPlugBandwidthImpl(obj, iface, ifaceBand, new_rate) < 0)
5493 5494 5495
        goto cleanup;

    ret = 0;
5496

5497
 cleanup:
5498 5499 5500
    return ret;
}

5501

5502
static int
5503
networkUnplugBandwidth(virNetworkObjPtr obj,
5504 5505
                       virDomainNetDefPtr iface)
{
5506
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5507
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5508
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5509
    virNetworkDriverStatePtr driver = networkGetDriver();
5510 5511
    int ret = 0;
    unsigned long long new_rate;
5512
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
5513 5514 5515

    if (iface->data.network.actual &&
        iface->data.network.actual->class_id) {
5516
        if (!def->bandwidth || !def->bandwidth->in) {
5517
            VIR_WARN("Network %s has no bandwidth but unplug requested",
5518
                     def->name);
5519 5520
            goto cleanup;
        }
5521
        /* we must remove class from bridge */
5522
        new_rate = def->bandwidth->in->average;
5523

5524 5525
        if (def->bandwidth->in->peak > 0)
            new_rate = def->bandwidth->in->peak;
5526

5527
        ret = virNetDevBandwidthUnplug(def->bridge,
5528 5529 5530 5531
                                       iface->data.network.actual->class_id);
        if (ret < 0)
            goto cleanup;
        /* update sum of 'floor'-s of attached NICs */
5532 5533 5534
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);

5535
        /* return class ID */
5536
        ignore_value(virBitmapClearBit(classIdMap,
5537 5538
                                       iface->data.network.actual->class_id));
        /* update status file */
5539
        if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5540 5541
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5542
            ignore_value(virBitmapSetBit(classIdMap,
5543 5544 5545
                                         iface->data.network.actual->class_id));
            goto cleanup;
        }
5546
        /* update rate for non guaranteed NICs */
5547
        new_rate -= tmp_floor_sum;
5548 5549
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0)
5550
            VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5551
                     def->bridge);
5552 5553 5554 5555
        /* no class is associated any longer */
        iface->data.network.actual->class_id = 0;
    }

5556
 cleanup:
5557 5558
    return ret;
}
5559

5560

5561
static void
5562
networkNetworkObjTaint(virNetworkObjPtr obj,
5563
                       virNetworkTaintFlags taint)
5564
{
5565 5566
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

5567
    if (virNetworkObjTaint(obj, taint)) {
5568
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5569
        virUUIDFormat(def->uuid, uuidstr);
5570 5571

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5572
                 def->name, uuidstr, virNetworkTaintTypeToString(taint));
5573 5574
    }
}
5575 5576 5577 5578 5579 5580


static bool
networkBandwidthGenericChecks(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
5581
    virNetDevBandwidthPtr ifaceBand;
5582 5583 5584 5585 5586 5587 5588 5589
    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;
    }

5590
    ifaceBand = virDomainNetGetActualBandwidth(iface);
5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606
    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;
}


bool
networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5607
    virNetworkObjPtr obj = NULL;
5608 5609 5610 5611 5612 5613
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    bool ret = false;

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

5614 5615
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5616 5617 5618 5619 5620 5621
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return false;
    }

5622
    if (networkCheckBandwidth(obj, newBandwidth, ifaceBand, iface->mac, NULL) < 0)
5623 5624 5625 5626 5627
        goto cleanup;

    ret = true;

 cleanup:
5628
    virNetworkObjEndAPI(&obj);
5629 5630
    return ret;
}
5631 5632 5633 5634 5635 5636 5637


int
networkBandwidthUpdate(virDomainNetDefPtr iface,
                       virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5638
    virNetworkObjPtr obj = NULL;
5639
    virNetworkDefPtr def;
5640
    unsigned long long tmp_floor_sum;
5641 5642 5643 5644 5645 5646 5647 5648
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    unsigned long long new_rate = 0;
    int plug_ret;
    int ret = -1;

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

5649 5650
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5651 5652 5653 5654 5655
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return ret;
    }
5656
    def = virNetworkObjGetDef(obj);
5657

5658
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, ifaceBand,
5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671
                                          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: */

5672
    if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
5673
        newBandwidth->in && newBandwidth->in->floor) {
5674 5675
        /* Either we just need to update @floor .. */

5676
        if (virNetDevBandwidthUpdateRate(def->bridge,
5677
                                         iface->data.network.actual->class_id,
5678
                                         def->bandwidth,
5679 5680 5681
                                         newBandwidth->in->floor) < 0)
            goto cleanup;

5682 5683 5684 5685 5686
        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;
5687

5688 5689
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0 ||
5690
            virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5691
            /* Ouch, rollback */
5692 5693 5694
            tmp_floor_sum -= newBandwidth->in->floor;
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5695

5696
            ignore_value(virNetDevBandwidthUpdateRate(def->bridge,
5697
                                                      iface->data.network.actual->class_id,
5698
                                                      def->bandwidth,
5699 5700 5701 5702 5703 5704
                                                      ifaceBand->in->floor));
            goto cleanup;
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5705
        if (networkPlugBandwidthImpl(obj, iface, newBandwidth, new_rate) < 0)
5706 5707 5708 5709
            goto cleanup;
    } else {
        /* .. or unplug old. */

5710
        if (networkUnplugBandwidth(obj, iface) < 0)
5711 5712 5713 5714 5715
            goto cleanup;
    }

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