bridge_driver.c 184.2 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 216 217 218 219 220 221
               int op,
               int sub_op)
{
    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)) {
222 223
        if (!obj) {
            VIR_DEBUG("Not running hook as @obj is NULL");
224 225 226 227
            ret = 0;
            goto cleanup;
        }

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

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

240
        if (virBufferCheckError(&buf) < 0)
241 242
            goto cleanup;

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

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

253
        networkNetworkObjTaint(obj, VIR_NETWORK_TAINT_HOOK);
254 255 256
    }

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

265

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

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

277

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

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

289

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

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

301

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

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

312

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

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

324

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

    int ret = -1;

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

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

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

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

    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
358
        goto cleanup;
359

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

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

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

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

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

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

382 383 384
    /* remove status file */
    unlink(statusfile);

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

    ret = 0;

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

402

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

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

427

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

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

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

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

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

460 461
        virNetworkObjSetMacMap(obj, macmap);

462
        break;
463

464
    case VIR_NETWORK_FORWARD_BRIDGE:
465 466
        if (obj->def->bridge) {
            if (virNetDevExists(obj->def->bridge) != 1)
467 468
                obj->active = 0;
            break;
469
        }
470 471 472 473 474 475 476 477 478
        /* intentionally drop through to common case for all
         * macvtap networks (forward='bridge' with no bridge
         * device defined is macvtap using its 'bridge' mode)
         */
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
        /* so far no extra checks */
        break;
479

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

485 486
    /* Try and read dnsmasq/radvd pids of active networks */
    if (obj->active && obj->def->ips && (obj->def->nips > 0)) {
487 488
        pid_t radvdPid;
        pid_t dnsmasqPid;
489
        char *radvdpidbase;
490

491 492
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           obj->def->name,
493
                                           &dnsmasqPid,
494
                                           dnsmasqCapsGetBinaryPath(dnsmasq_caps)));
495
        virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
M
Michal Privoznik 已提交
496

497 498 499
        radvdpidbase = networkRadvdPidfileBasename(obj->def->name);
        if (!radvdpidbase)
            goto cleanup;
500

501 502
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
503 504
                                           &radvdPid, RADVD));
        virNetworkObjSetRadvdPid(obj, radvdPid);
505
        VIR_FREE(radvdpidbase);
506
    }
507

508 509
    ret = 0;
 cleanup:
510
    virObjectUnlock(obj);
511
    virObjectUnref(dnsmasq_caps);
512
    VIR_FREE(macMapFile);
513 514
    return ret;
}
515

516

517
static int
518
networkAutostartConfig(virNetworkObjPtr obj,
519
                       void *opaque)
520
{
521
    virNetworkDriverStatePtr driver = opaque;
522
    int ret = -1;
523

524 525 526 527
    virObjectLock(obj);
    if (obj->autostart &&
        !virNetworkObjIsActive(obj) &&
        networkStartNetwork(driver, obj) < 0)
528 529 530 531
        goto cleanup;

    ret = 0;
 cleanup:
532
    virObjectUnlock(obj);
533
    return ret;
534 535
}

536

537 538 539
#if HAVE_FIREWALLD
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
540 541
                             DBusMessage *message,
                             void *user_data)
542
{
543 544
    virNetworkDriverStatePtr driver = user_data;

545 546 547 548 549 550
    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.");
551
        networkReloadFirewallRules(driver);
552 553 554 555 556 557
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

558

559
static int
560
networkMigrateStateFiles(virNetworkDriverStatePtr driver)
561 562 563 564 565 566 567 568 569 570 571 572 573
{
    /* 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;
574
    int direrr;
575 576 577
    struct dirent *entry;
    char *oldPath = NULL, *newPath = NULL;
    char *contents = NULL;
J
Ján Tomko 已提交
578
    int rc;
579

J
Ján Tomko 已提交
580 581
    if ((rc = virDirOpenIfExists(&dir, oldStateDir)) <= 0)
        return rc;
582 583 584 585 586 587 588

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

589
    while ((direrr = virDirRead(dir, &entry, oldStateDir)) > 0) {
590 591 592
        if (entry->d_type != DT_UNKNOWN &&
            entry->d_type != DT_REG)
            continue;
593 594 595

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

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

614
        if (virFileReadAll(oldPath, 1024*1024, &contents) < 0)
J
Ján Tomko 已提交
615
            goto cleanup;
616 617 618

        if (virAsprintf(&newPath, "%s/%s",
                        driver->stateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
619
            goto cleanup;
620 621 622 623 624 625 626 627 628 629 630 631
        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);
    }
632
    if (direrr < 0)
J
Ján Tomko 已提交
633
        goto cleanup;
634 635 636

    ret = 0;
 cleanup:
J
Ján Tomko 已提交
637
    VIR_DIR_CLOSE(dir);
638 639 640 641 642 643
    VIR_FREE(oldPath);
    VIR_FREE(newPath);
    VIR_FREE(contents);
    return ret;
}

644

645
/**
646
 * networkStateInitialize:
647 648 649 650
 *
 * Initialization function for the QEmu daemon
 */
static int
651 652 653
networkStateInitialize(bool privileged,
                       virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                       void *opaque ATTRIBUTE_UNUSED)
654
{
655 656 657
    int ret = -1;
    char *configdir = NULL;
    char *rundir = NULL;
658 659 660
#ifdef HAVE_FIREWALLD
    DBusConnection *sysbus = NULL;
#endif
661

662
    if (VIR_ALLOC(network_driver) < 0)
663
        goto error;
664

665 666
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
667 668
        goto error;
    }
669

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

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

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

717
    if (virFileMakePath(network_driver->stateDir) < 0) {
718 719
        virReportSystemError(errno,
                             _("cannot create directory %s"),
720
                             network_driver->stateDir);
721 722 723
        goto error;
    }

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

727
    if (!(network_driver->networks = virNetworkObjListNew()))
728 729
        goto error;

730 731
    if (virNetworkObjLoadAllState(network_driver->networks,
                                  network_driver->stateDir) < 0)
732 733
        goto error;

734 735 736
    if (virNetworkObjLoadAllConfigs(network_driver->networks,
                                    network_driver->networkConfigDir,
                                    network_driver->networkAutostartDir) < 0)
737 738
        goto error;

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

752
    network_driver->networkEventState = virObjectEventStateNew();
753

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

779
    ret = 0;
780
 cleanup:
781 782 783
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
784

785
 error:
786
    networkStateCleanup();
787
    goto cleanup;
788 789
}

790

791 792 793 794 795 796 797 798
/**
 * networkStateAutoStart:
 *
 * Function to AutoStart the bridge configs
 */
static void
networkStateAutoStart(void)
{
799
    if (!network_driver)
800 801
        return;

802
    virNetworkObjListForEach(network_driver->networks,
803
                             networkAutostartConfig,
804
                             network_driver);
805 806
}

807

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

820 821 822 823 824
    virNetworkObjLoadAllState(network_driver->networks,
                              network_driver->stateDir);
    virNetworkObjLoadAllConfigs(network_driver->networks,
                                network_driver->networkConfigDir,
                                network_driver->networkAutostartDir);
825 826 827
    networkReloadFirewallRules(network_driver);
    networkRefreshDaemons(network_driver);
    virNetworkObjListForEach(network_driver->networks,
828
                             networkAutostartConfig,
829
                             network_driver);
830 831 832 833 834
    return 0;
}


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

845
    virObjectUnref(network_driver->networkEventState);
846

847
    /* free inactive networks */
848
    virObjectUnref(network_driver->networks);
849

850 851 852 853 854 855
    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);
856

857
    virObjectUnref(network_driver->dnsmasqCaps);
858

859
    virMutexDestroy(&network_driver->lock);
860

861
    VIR_FREE(network_driver);
862 863 864 865 866

    return 0;
}


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

929

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

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

G
Gene Czarcinski 已提交
950 951 952
    return 0;
}

953

G
Gene Czarcinski 已提交
954 955 956 957
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
958
    size_t i, j;
G
Gene Czarcinski 已提交
959

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

971
    return 0;
972 973 974
}


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


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

1029 1030
    *configstr = NULL;

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

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

1045
    /* create dnsmasq config file appropriate for this network */
1046 1047

    /* Don't forget to update networkxml2conftest :-) */
1048
    virBufferAsprintf(&configbuf,
1049 1050 1051 1052 1053 1054 1055
                      "##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"
1056
                      "strict-order\n",
1057
                      obj->def->name);
1058

1059 1060 1061 1062 1063 1064
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1065
    if (wantDNS && obj->def->dns.forwarders) {
1066 1067 1068 1069 1070 1071 1072 1073 1074
        /* 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;

1075 1076
        for (i = 0; i < obj->def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &obj->def->dns.forwarders[i];
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086

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

1099 1100
    if (obj->def->domain) {
        if (obj->def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1101 1102
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1103
                              obj->def->domain);
1104
        }
1105
        virBufferAsprintf(&configbuf,
1106 1107
                          "domain=%s\n"
                          "expand-hosts\n",
1108
                          obj->def->domain);
1109
    }
1110

1111
    if (wantDNS &&
1112
        networkDnsmasqConfLocalPTRs(&configbuf, obj->def) < 0)
1113 1114
        goto cleanup;

1115
    if (wantDNS && obj->def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1116 1117 1118 1119
        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)
1120
         */
1121
        virBufferAddLit(&configbuf, "local=//\n");
1122
    }
1123

1124
    if (pidfile)
1125
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1126

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

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

            if (!ipaddr)
                goto cleanup;
1164

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

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

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

1213 1214 1215 1216 1217
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1218
        }
1219

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

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

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

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1333 1334
        int prefix;

1335
        prefix = virNetworkIPDefPrefix(ipdef);
1336 1337 1338
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1339
                           obj->def->bridge);
1340 1341
            goto cleanup;
        }
1342
        for (r = 0; r < ipdef->nranges; r++) {
1343 1344
            int thisRange;

1345 1346
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1347
                goto cleanup;
1348

1349
            virBufferAsprintf(&configbuf, "dhcp-range=%s,%s",
1350
                              saddr, eaddr);
1351
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1352
                virBufferAsprintf(&configbuf, ",%d", prefix);
1353 1354
            virBufferAddLit(&configbuf, "\n");

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

1366
        /*
1367 1368 1369 1370
         * For static-only DHCP, i.e. with no range but at least one
         * host element, we have to add a special --dhcp-range option
         * to enable the service in dnsmasq. (this is for dhcp-hosts=
         * support)
1371 1372
         */
        if (!ipdef->nranges && ipdef->nhosts) {
1373
            char *bridgeaddr = virSocketAddrFormat(&ipdef->address);
1374 1375
            if (!bridgeaddr)
                goto cleanup;
1376 1377 1378
            virBufferAsprintf(&configbuf, "dhcp-range=%s,static",
                              bridgeaddr);
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1379
                virBufferAsprintf(&configbuf, ",%d", prefix);
1380
            virBufferAddLit(&configbuf, "\n");
1381 1382
            VIR_FREE(bridgeaddr);
        }
1383

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

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

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

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

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

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

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

    /* Even if there are currently no static hosts, if we're
     * listening for DHCP, we should write a 0-length hosts
     * file to allow for runtime additions.
     */
    if (ipv4def || ipv6def)
1428 1429
        virBufferAsprintf(&configbuf, "dhcp-hostsfile=%s\n",
                          dctx->hostsfile->path);
G
Gene Czarcinski 已提交
1430

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

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

1459 1460 1461
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1462
    ret = 0;
G
Gene Czarcinski 已提交
1463

1464
 cleanup:
1465 1466
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1467
    virBufferFreeAndReset(&configbuf);
1468
    return ret;
1469 1470
}

1471

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

1487
    virNetworkObjSetDnsmasqPid(obj, -1);
1488

1489
    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
1490
                                   dctx, dnsmasq_caps) < 0)
1491 1492 1493 1494 1495
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1496
    if (!(configfile = networkDnsmasqConfigFileName(driver, obj->def->name)))
1497 1498 1499 1500 1501
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1502 1503
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1504 1505 1506
        goto cleanup;
    }

1507 1508
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1509
                                                  abs_topbuilddir "/src",
1510 1511 1512
                                                  LIBEXECDIR)))
        goto cleanup;

1513
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1514
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1515 1516
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1517
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1518
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", obj->def->bridge);
1519

1520
    *cmdout = cmd;
1521
    ret = 0;
1522
 cleanup:
1523
    virObjectUnref(dnsmasq_caps);
1524 1525
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1526
    VIR_FREE(leaseshelper_path);
1527 1528 1529
    return ret;
}

1530

1531
static int
1532
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1533
                       virNetworkObjPtr obj)
1534
{
1535 1536 1537
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1538 1539
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
1540
    pid_t dnsmasqPid;
1541
    int ret = -1;
1542
    dnsmasqContext *dctx = NULL;
1543

1544
    /* see if there are any IP addresses that need a dhcp server */
1545
    i = 0;
1546
    while ((ipdef = virNetworkDefGetIPByIndex(obj->def, AF_UNSPEC, i))) {
1547
        i++;
1548 1549 1550 1551
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1552 1553 1554 1555 1556 1557
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1558
    if (!needDnsmasq && obj->def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1559
        /* no DHCP services needed, and user disabled DNS service */
1560 1561 1562 1563
        ret = 0;
        goto cleanup;
    }

1564
    if (virFileMakePath(driver->pidDir) < 0) {
1565
        virReportSystemError(errno,
1566
                             _("cannot create directory %s"),
1567
                             driver->pidDir);
1568
        goto cleanup;
1569 1570
    }

1571
    if (!(pidfile = virPidFileBuildPath(driver->pidDir,
1572
                                        obj->def->name)))
1573
        goto cleanup;
1574

1575
    if (virFileMakePath(driver->dnsmasqStateDir) < 0) {
1576
        virReportSystemError(errno,
1577
                             _("cannot create directory %s"),
1578
                             driver->dnsmasqStateDir);
1579 1580 1581
        goto cleanup;
    }

1582
    dctx = dnsmasqContextNew(obj->def->name, driver->dnsmasqStateDir);
1583 1584 1585
    if (dctx == NULL)
        goto cleanup;

1586
    if (networkDnsmasqCapsRefresh(driver) < 0)
1587
        goto cleanup;
1588

1589
    ret = networkBuildDhcpDaemonCommandLine(driver, obj, &cmd, pidfile, dctx);
1590 1591 1592 1593 1594
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1595
        goto cleanup;
1596

G
Guido Günther 已提交
1597
    ret = virCommandRun(cmd, NULL);
1598
    if (ret < 0)
1599 1600 1601
        goto cleanup;

    /*
1602 1603 1604 1605 1606
     * 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
1607 1608
     */

1609
    ret = virPidFileRead(driver->pidDir, obj->def->name, &dnsmasqPid);
1610
    if (ret < 0)
1611
        goto cleanup;
1612
    virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
1613

1614
    ret = 0;
1615
 cleanup:
1616
    VIR_FREE(pidfile);
1617
    virCommandFree(cmd);
1618
    dnsmasqContextFree(dctx);
1619 1620 1621
    return ret;
}

1622

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

G
Gene Czarcinski 已提交
1640
    /* if no IP addresses specified, nothing to do */
1641
    if (!virNetworkDefGetIPByIndex(obj->def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1642 1643
        return 0;

1644
    /* if there's no running dnsmasq, just start it */
1645 1646
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid <= 0 || (kill(dnsmasqPid, 0) < 0))
1647
        return networkStartDhcpDaemon(driver, obj);
1648

1649 1650
    VIR_INFO("Refreshing dnsmasq for network %s", obj->def->bridge);
    if (!(dctx = dnsmasqContextNew(obj->def->name,
1651
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1652
        goto cleanup;
1653
    }
G
Gene Czarcinski 已提交
1654 1655 1656 1657 1658 1659

    /* 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;
1660
    for (i = 0;
1661
         (ipdef = virNetworkDefGetIPByIndex(obj->def, AF_INET, i));
1662
         i++) {
G
Gene Czarcinski 已提交
1663 1664
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1665 1666
    }

G
Gene Czarcinski 已提交
1667
    ipv6def = NULL;
1668
    for (i = 0;
1669
         (ipdef = virNetworkDefGetIPByIndex(obj->def, AF_INET6, i));
1670
         i++) {
G
Gene Czarcinski 已提交
1671 1672
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1673 1674
    }

G
Gene Czarcinski 已提交
1675
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1676
        goto cleanup;
G
Gene Czarcinski 已提交
1677 1678

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

1681
    if (networkBuildDnsmasqHostsList(dctx, &obj->def->dns) < 0)
J
Ján Tomko 已提交
1682
        goto cleanup;
1683 1684

    if ((ret = dnsmasqSave(dctx)) < 0)
1685
        goto cleanup;
1686

1687 1688
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    ret = kill(dnsmasqPid, SIGHUP);
1689
 cleanup:
1690 1691 1692 1693
    dnsmasqContextFree(dctx);
    return ret;
}

1694

1695 1696 1697 1698 1699 1700 1701 1702
/* 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
1703
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1704
                         virNetworkObjPtr obj)
1705
{
1706 1707
    pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);

1708
    /* if there is a running dnsmasq, kill it */
1709 1710 1711
    if (dnsmasqPid > 0) {
        networkKillDaemon(dnsmasqPid, "dnsmasq", obj->def->name);
        virNetworkObjSetDnsmasqPid(obj, -1);
1712
    }
1713
    /* now start dnsmasq if it should be started */
1714
    return networkStartDhcpDaemon(driver, obj);
1715 1716
}

1717

G
Gene Czarcinski 已提交
1718 1719 1720 1721 1722 1723
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";

1724
static int
1725
networkRadvdConfContents(virNetworkObjPtr obj,
1726
                         char **configstr)
1727
{
E
Eric Blake 已提交
1728
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1729 1730
    int ret = -1;
    size_t i;
1731
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1732
    bool v6present = false, dhcp6 = false;
1733 1734

    *configstr = NULL;
1735

G
Gene Czarcinski 已提交
1736
    /* Check if DHCPv6 is needed */
1737
    for (i = 0;
1738
         (ipdef = virNetworkDefGetIPByIndex(obj->def, AF_INET6, i));
1739
         i++) {
G
Gene Czarcinski 已提交
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
        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;
    }

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

    /* add a section for each IPv6 address in the config */
1767
    for (i = 0;
1768
         (ipdef = virNetworkDefGetIPByIndex(obj->def, AF_INET6, i));
1769
         i++) {
1770 1771 1772
        int prefix;
        char *netaddr;

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

1790
    virBufferAddLit(&configbuf, "};\n");
1791

1792
    if (virBufferCheckError(&configbuf) < 0)
1793
        goto cleanup;
1794

1795 1796
    *configstr = virBufferContentAndReset(&configbuf);

1797
    ret = 0;
1798
 cleanup:
1799 1800 1801 1802
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1803

1804
/* write file and return its name (which must be freed by caller) */
1805
static int
1806
networkRadvdConfWrite(virNetworkDriverStatePtr driver,
1807
                      virNetworkObjPtr obj,
1808
                      char **configFile)
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818
{
    int ret = -1;
    char *configStr = NULL;
    char *myConfigFile = NULL;

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

1819
    if (networkRadvdConfContents(obj, &configStr) < 0)
1820 1821 1822 1823
        goto cleanup;

    if (!configStr) {
        ret = 0;
1824 1825 1826 1827
        goto cleanup;
    }

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

    ret = 0;
1839
 cleanup:
1840 1841 1842 1843 1844
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

1845

1846
static int
1847
networkStartRadvd(virNetworkDriverStatePtr driver,
1848
                  virNetworkObjPtr obj)
1849
{
1850
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1851
    pid_t radvdPid;
1852 1853 1854 1855 1856 1857
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

1858
    virNetworkObjSetRadvdPid(obj, -1);
1859

G
Gene Czarcinski 已提交
1860
    /* Is dnsmasq handling RA? */
1861
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
1862 1863 1864 1865
        ret = 0;
        goto cleanup;
    }

1866
    if (!virNetworkDefGetIPByIndex(obj->def, AF_INET6, 0)) {
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876
        /* 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);
1877 1878 1879
        goto cleanup;
    }

1880
    if (virFileMakePath(driver->pidDir) < 0) {
1881 1882
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1883
                             driver->pidDir);
1884 1885
        goto cleanup;
    }
1886
    if (virFileMakePath(driver->radvdStateDir) < 0) {
1887 1888
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1889
                             driver->radvdStateDir);
1890 1891 1892 1893
        goto cleanup;
    }

    /* construct pidfile name */
1894
    if (!(radvdpidbase = networkRadvdPidfileBasename(obj->def->name)))
1895
        goto cleanup;
1896
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
1897 1898
        goto cleanup;

1899
    if (networkRadvdConfWrite(driver, obj, &configfile) < 0)
1900 1901
        goto cleanup;

1902 1903 1904 1905
    /* 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
1906
     * virPidFileRead() below will fail if we use them).
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
     * 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;

1922
    if (virPidFileRead(driver->pidDir, radvdpidbase, &radvdPid) < 0)
1923
        goto cleanup;
1924
    virNetworkObjSetRadvdPid(obj, radvdPid);
1925 1926

    ret = 0;
1927
 cleanup:
1928
    virObjectUnref(dnsmasq_caps);
1929 1930 1931 1932 1933 1934 1935
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

1936

1937
static int
1938
networkRefreshRadvd(virNetworkDriverStatePtr driver,
1939
                    virNetworkObjPtr obj)
1940
{
1941
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
1942
    char *radvdpidbase;
1943
    pid_t radvdPid;
G
Gene Czarcinski 已提交
1944 1945

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

1963
    /* if there's no running radvd, just start it */
1964 1965
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid <= 0 || (kill(radvdPid, 0) < 0))
1966
        return networkStartRadvd(driver, obj);
1967

1968
    if (!virNetworkDefGetIPByIndex(obj->def, AF_INET6, 0)) {
1969 1970 1971 1972
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

1973
    if (networkRadvdConfWrite(driver, obj, NULL) < 0)
1974 1975
        return -1;

1976
    return kill(radvdPid, SIGHUP);
1977 1978
}

1979

1980 1981
#if 0
/* currently unused, so it causes a build error unless we #if it out */
1982
static int
1983
networkRestartRadvd(virNetworkObjPtr obj)
1984 1985
{
    char *radvdpidbase;
1986
    pid_t radvdPid = virNeworkObjGetRadvdPid(obj);
1987 1988

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

2008

2009
static int
2010
networkRefreshDaemonsHelper(virNetworkObjPtr obj,
2011
                            void *opaque)
2012
{
2013
    virNetworkDriverStatePtr driver = opaque;
2014

2015 2016 2017 2018 2019 2020
    virObjectLock(obj);
    if (virNetworkObjIsActive(obj) &&
        ((obj->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
         (obj->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
         (obj->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
         (obj->def->forward.type == VIR_NETWORK_FORWARD_OPEN))) {
2021 2022 2023 2024 2025 2026
        /* 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.
         */
2027 2028
        networkRefreshDhcpDaemon(driver, obj);
        networkRefreshRadvd(driver, obj);
2029
    }
2030
    virObjectUnlock(obj);
2031 2032 2033
    return 0;
}

2034

2035 2036 2037 2038
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2039
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2040 2041
{
    VIR_INFO("Refreshing network daemons");
2042 2043
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2044
                             driver);
2045
}
2046

2047

2048
static int
2049
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
2050 2051 2052
                                 void *opaque ATTRIBUTE_UNUSED)
{

2053 2054 2055 2056 2057
    virObjectLock(obj);
    if (virNetworkObjIsActive(obj) &&
        ((obj->def->forward.type == VIR_NETWORK_FORWARD_NONE) ||
         (obj->def->forward.type == VIR_NETWORK_FORWARD_NAT) ||
         (obj->def->forward.type == VIR_NETWORK_FORWARD_ROUTE))) {
2058 2059 2060 2061
        /* 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.
2062
         */
2063 2064
        networkRemoveFirewallRules(obj->def);
        if (networkAddFirewallRules(obj->def) < 0) {
2065
            /* failed to add but already logged */
2066 2067
        }
    }
2068
    virObjectUnlock(obj);
2069
    return 0;
2070 2071
}

2072

2073
static void
2074
networkReloadFirewallRules(virNetworkDriverStatePtr driver)
2075
{
2076
    VIR_INFO("Reloading iptables rules");
2077 2078 2079
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2080 2081
}

2082

2083
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
2084
static int
2085 2086
networkEnableIPForwarding(bool enableIPv4,
                          bool enableIPv6)
2087
{
2088
    int ret = 0;
2089 2090 2091 2092
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
2093
                           &enabled, sizeof(enabled));
2094 2095
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
2096
                           &enabled, sizeof(enabled));
2097
#else
2098
    if (enableIPv4)
2099
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv4/ip_forward", "1\n", 0);
2100
    if (enableIPv6 && ret == 0)
2101 2102
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv6/conf/all/forwarding", "1\n", 0);

2103
#endif
2104
    return ret;
2105 2106
}

2107

2108
static int
2109
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2110 2111 2112
{
    char *field = NULL;
    int ret = -1;
2113
    bool enableIPv6 =  !!virNetworkDefGetIPByIndex(obj->def, AF_INET6, 0);
2114

2115 2116 2117 2118 2119
    /* 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",
2120
                    obj->def->bridge) < 0)
2121
       goto cleanup;
2122

2123 2124
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2125
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2126
                      obj->def->bridge);
2127 2128 2129
        ret = 0;
        goto cleanup;
    }
2130

2131 2132 2133
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2134
                               "on bridge %s"), field, obj->def->bridge);
2135
        goto cleanup;
2136
    }
2137
    VIR_FREE(field);
2138

2139 2140
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2141 2142 2143 2144 2145 2146
     */

    /* 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",
2147
                    obj->def->bridge) < 0)
2148 2149
        goto cleanup;

2150
    if (virFileWriteStr(field, "0", 0) < 0) {
2151
        virReportSystemError(errno,
2152 2153 2154 2155 2156
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

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

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

    ret = 0;
2171
 cleanup:
2172 2173 2174 2175
    VIR_FREE(field);
    return ret;
}

2176

2177
/* add an IP address to a bridge */
2178
static int
2179
networkAddAddrToBridge(virNetworkObjPtr obj,
2180
                       virNetworkIPDefPtr ipdef)
2181
{
2182
    int prefix = virNetworkIPDefPrefix(ipdef);
2183 2184

    if (prefix < 0) {
2185 2186
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2187
                       obj->def->bridge);
2188 2189 2190
        return -1;
    }

2191
    if (virNetDevIPAddrAdd(obj->def->bridge,
2192
                           &ipdef->address, NULL, prefix) < 0)
2193 2194 2195 2196 2197
        return -1;

    return 0;
}

2198 2199

static int
2200
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2201 2202
                                      const char *macTapIfName)
{
2203
    const char *brname = obj->def->bridge;
2204 2205

    if (brname &&
2206
        obj->def->macTableManager
2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220
        == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
        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;
}


2221 2222
/* add an IP (static) route to a bridge */
static int
2223
networkAddRouteToBridge(virNetworkObjPtr obj,
2224
                        virNetDevIPRoutePtr routedef)
2225
{
2226 2227 2228 2229
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2230 2231 2232 2233 2234

    if (prefix < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' has an invalid netmask "
                         "or IP address in route definition"),
2235
                       obj->def->name);
2236 2237 2238
        return -1;
    }

2239
    if (virNetDevIPRouteAdd(obj->def->bridge, addr,
2240
                            prefix, gateway, metric) < 0) {
2241 2242 2243 2244 2245
        return -1;
    }
    return 0;
}

2246
static int
2247
networkWaitDadFinish(virNetworkObjPtr obj)
2248
{
2249
    virNetworkIPDefPtr ipdef;
2250 2251 2252 2253
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

2254
    VIR_DEBUG("Begin waiting for IPv6 DAD on network %s", obj->def->name);
2255

2256
    while ((ipdef = virNetworkDefGetIPByIndex(obj->def, AF_INET6, naddrs))) {
2257 2258 2259 2260 2261
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2262
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2263 2264 2265 2266

 cleanup:
    VIR_FREE(addrs);
    VIR_DEBUG("Finished waiting for IPv6 DAD on network %s with status %d",
2267
              obj->def->name, ret);
2268 2269 2270
    return ret;
}

2271

2272
static int
2273
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
2274
                           virNetworkObjPtr obj)
2275
{
2276
    size_t i;
2277
    bool v4present = false, v6present = false;
2278
    virErrorPtr save_err = NULL;
2279
    virNetworkIPDefPtr ipdef;
2280
    virNetDevIPRoutePtr routedef;
2281
    char *macTapIfName = NULL;
2282
    virMacMapPtr macmap;
M
Michal Privoznik 已提交
2283
    char *macMapFile = NULL;
2284
    int tapfd = -1;
2285
    pid_t dnsmasqPid;
2286

2287
    /* Check to see if any network IP collides with an existing route */
2288
    if (networkCheckRouteCollision(obj->def) < 0)
2289 2290
        return -1;

2291
    /* Create and configure the bridge device */
2292
    if (!obj->def->bridge) {
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302
        /* 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"),
2303
                       obj->def->name);
2304 2305
        return -1;
    }
2306
    if (virNetDevBridgeCreate(obj->def->bridge) < 0)
2307 2308
        return -1;

2309
    if (obj->def->mac_specified) {
2310 2311 2312 2313 2314 2315
        /* 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.
         */
2316
        macTapIfName = networkBridgeDummyNicName(obj->def->bridge);
2317
        if (!macTapIfName)
2318
            goto err0;
2319
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2320 2321
        if (virNetDevTapCreateInBridgePort(obj->def->bridge,
                                           &macTapIfName, &obj->def->mac,
2322
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2323
                                           NULL, obj->def->mtu, NULL,
2324 2325 2326
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2327 2328 2329 2330 2331
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

2332 2333
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
                                         obj->def->bridge)) ||
2334
        !(macmap = virMacMapNew(macMapFile)))
M
Michal Privoznik 已提交
2335 2336
        goto err1;

2337 2338
    virNetworkObjSetMacMap(obj, macmap);

2339
    /* Set bridge options */
2340 2341 2342 2343

    /* delay is configured in seconds, but virNetDevBridgeSetSTPDelay
     * expects milliseconds
     */
2344 2345
    if (virNetDevBridgeSetSTPDelay(obj->def->bridge,
                                   obj->def->delay * 1000) < 0)
2346
        goto err1;
2347

2348 2349
    if (virNetDevBridgeSetSTP(obj->def->bridge,
                              obj->def->stp ? true : false) < 0)
2350
        goto err1;
2351

2352 2353 2354
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2355
    if (networkSetIPv6Sysctls(obj) < 0)
2356
        goto err1;
2357

2358
    /* Add "once per network" rules */
2359 2360
    if (obj->def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(obj->def) < 0)
2361 2362
        goto err1;

2363
    for (i = 0;
2364
         (ipdef = virNetworkDefGetIPByIndex(obj->def, AF_UNSPEC, i));
2365
         i++) {
2366
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2367
            v4present = true;
2368
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2369
            v6present = true;
2370

2371
        /* Add the IP address/netmask to the bridge */
2372
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2373
            goto err2;
2374 2375
    }

2376
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2377 2378
        goto err2;

2379
    /* Bring up the bridge interface */
2380
    if (virNetDevSetOnline(obj->def->bridge, 1) < 0)
2381
        goto err2;
2382

2383
    for (i = 0; i < obj->def->nroutes; i++) {
2384 2385
        virSocketAddrPtr gateway = NULL;

2386
        routedef = obj->def->routes[i];
2387
        gateway = virNetDevIPRouteGetGateway(routedef);
2388

2389 2390 2391
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2392
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2393
            if (networkAddRouteToBridge(obj, routedef) < 0) {
2394 2395 2396 2397 2398 2399
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2400
    /* If forward.type != NONE, turn on global IP forwarding */
2401
    if (obj->def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2402
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2403 2404 2405 2406 2407 2408 2409
            goto err3; /* Precise error message already provided */

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

2412

2413
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2414
    if ((v4present || v6present) &&
2415
        networkStartDhcpDaemon(driver, obj) < 0)
2416
        goto err3;
2417

2418
    /* start radvd if there are any ipv6 addresses */
2419
    if (v6present && networkStartRadvd(driver, obj) < 0)
2420 2421
        goto err4;

2422 2423 2424
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2425
    if (v6present && networkWaitDadFinish(obj) < 0)
2426 2427 2428 2429
        goto err4;

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2430 2431 2432 2433 2434 2435 2436
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
            goto err4;
        VIR_FORCE_CLOSE(tapfd);
    }

2437
    if (virNetDevBandwidthSet(obj->def->bridge, obj->def->bandwidth, true) < 0)
2438 2439
        goto err5;

2440
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2441
    VIR_FREE(macMapFile);
2442 2443 2444

    return 0;

2445
 err5:
2446 2447
    if (obj->def->bandwidth)
       virNetDevBandwidthClear(obj->def->bridge);
2448

2449 2450 2451 2452
 err4:
    if (!save_err)
        save_err = virSaveLastError();

2453 2454 2455 2456
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0) {
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2457 2458
    }

2459 2460 2461
 err3:
    if (!save_err)
        save_err = virSaveLastError();
2462
    ignore_value(virNetDevSetOnline(obj->def->bridge, 0));
2463

2464 2465 2466
 err2:
    if (!save_err)
        save_err = virSaveLastError();
2467 2468
    if (obj->def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(obj->def);
2469 2470

 err1:
2471 2472 2473
    if (!save_err)
        save_err = virSaveLastError();

H
Hu Tao 已提交
2474
    if (macTapIfName) {
2475
        VIR_FORCE_CLOSE(tapfd);
2476
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2477 2478
        VIR_FREE(macTapIfName);
    }
M
Michal Privoznik 已提交
2479
    VIR_FREE(macMapFile);
2480 2481

 err0:
2482 2483
    if (!save_err)
        save_err = virSaveLastError();
2484
    ignore_value(virNetDevBridgeDelete(obj->def->bridge));
2485

2486 2487 2488 2489
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
2490
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2491 2492 2493
    return -1;
}

2494

2495 2496
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2497
                              virNetworkObjPtr obj)
2498
{
2499 2500 2501
    pid_t radvdPid;
    pid_t dnsmasqPid;

2502 2503
    if (obj->def->bandwidth)
        virNetDevBandwidthClear(obj->def->bridge);
2504

2505
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2506

2507 2508
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2509 2510
        char *radvdpidbase;

2511
        kill(radvdPid, SIGTERM);
2512
        /* attempt to delete the pidfile we created */
2513
        if ((radvdpidbase = networkRadvdPidfileBasename(obj->def->name))) {
2514
            virPidFileDelete(driver->pidDir, radvdpidbase);
2515 2516 2517 2518
            VIR_FREE(radvdpidbase);
        }
    }

2519 2520 2521
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2522

2523 2524
    if (obj->def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(obj->def->bridge);
2525
        if (macTapIfName) {
2526
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2527 2528 2529 2530
            VIR_FREE(macTapIfName);
        }
    }

2531
    ignore_value(virNetDevSetOnline(obj->def->bridge, 0));
2532

2533 2534
    if (obj->def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(obj->def);
2535

2536
    ignore_value(virNetDevBridgeDelete(obj->def->bridge));
2537

2538
    /* See if its still alive and really really kill it */
2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549
    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);
2550

2551 2552 2553
    return 0;
}

2554

2555
static int
2556
networkStartNetworkBridge(virNetworkObjPtr obj)
2557 2558 2559 2560 2561
{
    /* 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.
     */
2562
    return networkStartHandleMACTableManagerMode(obj, NULL);
2563 2564
}

2565

2566
static int
2567
networkShutdownNetworkBridge(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2568 2569 2570 2571 2572 2573 2574 2575 2576
{
    /* 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;
}


2577 2578 2579 2580 2581 2582 2583 2584 2585
/* 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;
2586
    unsigned int maxVirtFns = 0;
2587 2588 2589 2590 2591 2592
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2593 2594 2595
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2596 2597
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 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
        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:
2644
        case VIR_NETWORK_FORWARD_OPEN:
2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 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
        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;
}


2685
static int
2686
networkStartNetworkExternal(virNetworkObjPtr obj)
2687 2688
{
    /* put anything here that needs to be done each time a network of
2689
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2690 2691 2692
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2693
    return networkCreateInterfacePool(obj->def);
2694 2695
}

2696 2697

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

2708

2709
static int
2710
networkStartNetwork(virNetworkDriverStatePtr driver,
2711
                    virNetworkObjPtr obj)
2712
{
2713 2714
    int ret = -1;

2715
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2716

2717
    if (virNetworkObjIsActive(obj)) {
2718 2719
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2720
        return ret;
2721 2722
    }

2723 2724 2725
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2726
    if (virNetworkObjSetDefTransient(obj, true) < 0)
2727
        goto cleanup;
2728

2729 2730
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2731
    if (networkRunHook(obj, NULL, NULL,
2732 2733 2734 2735
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2736
    switch (obj->def->forward.type) {
2737 2738 2739 2740

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2741
    case VIR_NETWORK_FORWARD_OPEN:
2742
        if (networkStartNetworkVirtual(driver, obj) < 0)
2743
            goto cleanup;
2744 2745 2746
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2747 2748
        if (obj->def->bridge) {
            if (networkStartNetworkBridge(obj) < 0)
2749 2750 2751 2752 2753 2754 2755
                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).
         */
2756 2757
        ATTRIBUTE_FALLTHROUGH;

2758 2759 2760
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2761
    case VIR_NETWORK_FORWARD_HOSTDEV:
2762
        if (networkStartNetworkExternal(obj) < 0)
2763
            goto cleanup;
2764 2765 2766
        break;
    }

2767
    /* finally we can call the 'started' hook script if any */
2768
    if (networkRunHook(obj, NULL, NULL,
2769 2770 2771 2772
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2773 2774 2775
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2776
    VIR_DEBUG("Writing network status to disk");
2777
    if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0)
2778
        goto cleanup;
2779

2780 2781
    obj->active = 1;
    VIR_INFO("Network '%s' started up", obj->def->name);
2782
    ret = 0;
2783

2784
 cleanup:
2785
    if (ret < 0) {
2786
        virNetworkObjUnsetDefTransient(obj);
2787 2788
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
2789
        networkShutdownNetwork(driver, obj);
2790 2791 2792 2793 2794 2795 2796
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2797

2798 2799
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
2800
                       virNetworkObjPtr obj)
2801 2802 2803 2804
{
    int ret = 0;
    char *stateFile;

2805
    VIR_INFO("Shutting down network '%s'", obj->def->name);
2806

2807
    if (!virNetworkObjIsActive(obj))
2808 2809
        return 0;

2810
    stateFile = virNetworkConfigFile(driver->stateDir,
2811
                                     obj->def->name);
2812 2813 2814 2815 2816 2817
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2818
    switch (obj->def->forward.type) {
2819 2820 2821 2822

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2823
    case VIR_NETWORK_FORWARD_OPEN:
2824
        ret = networkShutdownNetworkVirtual(driver, obj);
2825 2826 2827
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2828 2829
        if (obj->def->bridge) {
            ret = networkShutdownNetworkBridge(obj);
2830 2831 2832 2833 2834 2835
            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).
         */
2836 2837
        ATTRIBUTE_FALLTHROUGH;

2838 2839 2840
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2841
    case VIR_NETWORK_FORWARD_HOSTDEV:
2842
        ret = networkShutdownNetworkExternal(obj);
2843 2844 2845
        break;
    }

2846
    /* now that we know it's stopped call the hook if present */
2847
    networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2848 2849
                   VIR_HOOK_SUBOP_END);

2850 2851
    obj->active = 0;
    virNetworkObjUnsetDefTransient(obj);
2852
    return ret;
2853 2854 2855
}


2856 2857 2858
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
2859
{
2860
    virNetworkDriverStatePtr driver = networkGetDriver();
2861 2862
    virNetworkObjPtr obj;
    virNetworkPtr net = NULL;
2863

2864 2865
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
2866 2867
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
2868
        virReportError(VIR_ERR_NO_NETWORK,
2869 2870
                       _("no network with matching uuid '%s'"),
                       uuidstr);
2871
        goto cleanup;
2872 2873
    }

2874
    if (virNetworkLookupByUUIDEnsureACL(conn, obj->def) < 0)
2875 2876
        goto cleanup;

2877
    net = virGetNetwork(conn, obj->def->name, obj->def->uuid);
2878

2879
 cleanup:
2880 2881
    virNetworkObjEndAPI(&obj);
    return net;
2882 2883
}

2884 2885 2886 2887

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
2888
{
2889
    virNetworkDriverStatePtr driver = networkGetDriver();
2890 2891
    virNetworkObjPtr obj;
    virNetworkPtr net = NULL;
2892

2893 2894
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
2895 2896
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
2897
        goto cleanup;
2898 2899
    }

2900
    if (virNetworkLookupByNameEnsureACL(conn, obj->def) < 0)
2901 2902
        goto cleanup;

2903
    net = virGetNetwork(conn, obj->def->name, obj->def->uuid);
2904

2905
 cleanup:
2906 2907
    virNetworkObjEndAPI(&obj);
    return net;
2908 2909
}

2910 2911 2912

static int
networkConnectNumOfNetworks(virConnectPtr conn)
2913
{
2914
    virNetworkDriverStatePtr driver = networkGetDriver();
2915
    int nactive;
2916

2917 2918 2919
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

2920 2921 2922 2923
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
2924

2925 2926 2927
    return nactive;
}

2928 2929 2930 2931 2932

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
                           int nnames)
2933 2934
{
    virNetworkDriverStatePtr driver = networkGetDriver();
2935
    int got = 0;
2936

2937 2938 2939
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

2940 2941 2942 2943
    got = virNetworkObjListGetNames(driver->networks,
                                    true, names, nnames,
                                    virConnectListNetworksCheckACL,
                                    conn);
2944

2945 2946 2947
    return got;
}

2948 2949 2950

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
2951
{
2952
    virNetworkDriverStatePtr driver = networkGetDriver();
2953
    int ninactive = 0;
2954

2955 2956 2957
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2958 2959 2960 2961
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
2962

2963 2964 2965
    return ninactive;
}

2966 2967 2968 2969 2970

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
                                  int nnames)
2971 2972
{
    virNetworkDriverStatePtr driver = networkGetDriver();
2973
    int got = 0;
2974

2975 2976 2977
    if (virConnectListDefinedNetworksEnsureACL(conn) < 0)
        return -1;

2978 2979 2980 2981
    got = virNetworkObjListGetNames(driver->networks,
                                    false, names, nnames,
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
2982 2983 2984
    return got;
}

2985

2986
static int
2987 2988 2989
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
2990
{
2991
    virNetworkDriverStatePtr driver = networkGetDriver();
2992 2993 2994 2995
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

2996 2997 2998
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

2999
    ret = virNetworkObjListExport(conn, driver->networks, nets,
3000 3001
                                  virConnectListAllNetworksCheckACL,
                                  flags);
3002

3003
 cleanup:
3004 3005
    return ret;
}
3006

3007

3008 3009 3010 3011 3012 3013 3014 3015
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3016
    virNetworkDriverStatePtr driver = networkGetDriver();
3017 3018 3019 3020 3021 3022
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3023
                                       net, eventID, callback,
3024 3025 3026
                                       opaque, freecb, &ret) < 0)
        ret = -1;

3027
 cleanup:
3028 3029 3030
    return ret;
}

3031

3032 3033 3034 3035
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3036
    virNetworkDriverStatePtr driver = networkGetDriver();
3037 3038 3039 3040 3041
    int ret = -1;

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

3042 3043
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3044
                                        callbackID, true) < 0)
3045 3046 3047
        goto cleanup;

    ret = 0;
3048

3049
 cleanup:
3050 3051 3052
    return ret;
}

3053 3054 3055

static int
networkIsActive(virNetworkPtr net)
3056 3057 3058 3059
{
    virNetworkObjPtr obj;
    int ret = -1;

3060 3061
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3062 3063 3064 3065

    if (virNetworkIsActiveEnsureACL(net->conn, obj->def) < 0)
        goto cleanup;

3066 3067
    ret = virNetworkObjIsActive(obj);

3068
 cleanup:
3069
    virNetworkObjEndAPI(&obj);
3070 3071 3072
    return ret;
}

3073 3074 3075

static int
networkIsPersistent(virNetworkPtr net)
3076 3077 3078 3079
{
    virNetworkObjPtr obj;
    int ret = -1;

3080 3081
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3082 3083 3084 3085

    if (virNetworkIsPersistentEnsureACL(net->conn, obj->def) < 0)
        goto cleanup;

3086 3087
    ret = obj->persistent;

3088
 cleanup:
3089
    virNetworkObjEndAPI(&obj);
3090 3091 3092 3093
    return ret;
}


3094 3095
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
3096 3097 3098
 * 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.
3099 3100 3101 3102 3103 3104 3105 3106
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{

    int ret = -1, id = 0;
    char *newname = NULL;
3107 3108 3109 3110 3111
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3112
        p && p[1] == 'd')
3113
        templ = def->bridge;
3114 3115 3116 3117

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3118 3119 3120 3121 3122
        /* 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).
         */
3123
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3124
              virNetDevExists(newname) == 1)) {
3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157
            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")) {
3158
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175
            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;
}


3176
static int
3177
networkValidate(virNetworkDriverStatePtr driver,
3178
                virNetworkDefPtr def)
3179
{
3180
    size_t i, j;
3181 3182
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3183
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3184
    bool ipv4def = false, ipv6def = false;
3185
    bool bandwidthAllowed = true;
3186
    bool usesInterface = false, usesAddress = false;
3187

3188 3189 3190
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3191 3192 3193
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3194 3195
    if (def->forward.type == VIR_NETWORK_FORWARD_NONE ||
        def->forward.type == VIR_NETWORK_FORWARD_NAT ||
3196 3197
        def->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
        def->forward.type == VIR_NETWORK_FORWARD_OPEN) {
3198

3199 3200 3201 3202
        /* 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)
3203 3204 3205
            return -1;

        virNetworkSetBridgeMacAddr(def);
3206 3207
    } else {
        /* They are also the only types that currently support setting
3208 3209
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
3210
         */
3211 3212 3213 3214 3215 3216 3217 3218
        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;
        }
3219
        if (virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0)) {
3220 3221 3222 3223
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3224
                           virNetworkForwardTypeToString(def->forward.type));
3225 3226
            return -1;
        }
3227
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
3228 3229 3230 3231
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3232
                           virNetworkForwardTypeToString(def->forward.type));
3233 3234 3235 3236 3237 3238 3239
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3240
                           virNetworkForwardTypeToString(def->forward.type));
3241 3242
            return -1;
        }
3243 3244 3245 3246 3247 3248 3249 3250
        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;
        }
3251
        bandwidthAllowed = false;
3252 3253
    }

3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266
    /* 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++) {
3267 3268 3269 3270
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

        switch ((virNetworkForwardHostdevDeviceType) iface->type) {
3271 3272
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283

            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;
            }
3284
            break;
3285 3286

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3287
            usesAddress = true;
3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312

            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);
3313
            break;
3314 3315
        }

3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328
        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 已提交
3329 3330 3331
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
3332
    for (i = 0;
3333
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
3334
         i++) {
G
Gene Czarcinski 已提交
3335 3336 3337 3338 3339
        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 -- "
3340 3341
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358
                    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;
                }
3359 3360 3361
            }
        }
    }
3362 3363 3364 3365 3366 3367

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

3368 3369 3370
    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 已提交
3371 3372
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3373
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3374 3375

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

    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;
            }
        }
    }
3451 3452 3453
    return 0;
}

3454 3455 3456 3457

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3458
{
3459
    virNetworkDriverStatePtr driver = networkGetDriver();
3460
    virNetworkDefPtr def;
3461 3462
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3463
    virObjectEventPtr event = NULL;
3464

3465
    if (!(def = virNetworkDefParseString(xml)))
3466
        goto cleanup;
3467

3468 3469 3470
    if (virNetworkCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3471
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3472
        goto cleanup;
3473

3474 3475 3476
    /* 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.
3477
     */
3478 3479 3480
    if (!(obj = virNetworkObjAssignDef(driver->networks, def,
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3481 3482
        goto cleanup;
    def = NULL;
3483

3484 3485
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3486
        goto cleanup;
3487 3488
    }

3489 3490
    event = virNetworkEventLifecycleNew(obj->def->name,
                                        obj->def->uuid,
3491 3492
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3493

3494 3495
    VIR_INFO("Creating network '%s'", obj->def->name);
    net = virGetNetwork(conn, obj->def->name, obj->def->uuid);
3496

3497
 cleanup:
3498
    virNetworkDefFree(def);
3499 3500
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3501 3502
    virNetworkObjEndAPI(&obj);
    return net;
3503 3504
}

3505 3506 3507 3508

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3509
{
3510
    virNetworkDriverStatePtr driver = networkGetDriver();
3511
    virNetworkDefPtr def = NULL;
3512
    bool freeDef = true;
3513 3514
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3515
    virObjectEventPtr event = NULL;
3516

3517
    if (!(def = virNetworkDefParseString(xml)))
3518
        goto cleanup;
3519

3520 3521 3522
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3523
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3524
        goto cleanup;
3525

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

3529
    /* def was assigned to network object */
3530
    freeDef = false;
3531 3532

    if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
3533 3534
        if (!virNetworkObjIsActive(obj)) {
            virNetworkObjRemoveInactive(driver->networks, obj);
3535 3536
            goto cleanup;
        }
3537 3538 3539 3540
        /* if network was active already, just undo new persistent
         * definition by making it transient.
         * XXX - this isn't necessarily the correct thing to do.
         */
3541
        virNetworkObjUpdateAssignDef(obj, NULL, false);
3542 3543 3544
        goto cleanup;
    }

3545
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3546 3547
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3548

3549
    VIR_INFO("Defining network '%s'", def->name);
3550
    net = virGetNetwork(conn, def->name, def->uuid);
3551

3552
 cleanup:
3553 3554
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3555
    if (freeDef)
J
Ján Tomko 已提交
3556
        virNetworkDefFree(def);
3557 3558
    virNetworkObjEndAPI(&obj);
    return net;
3559 3560
}

3561

3562
static int
3563 3564
networkUndefine(virNetworkPtr net)
{
3565
    virNetworkDriverStatePtr driver = networkGetDriver();
3566
    virNetworkObjPtr obj;
3567
    int ret = -1;
3568
    bool active = false;
3569
    virObjectEventPtr event = NULL;
3570

3571
    if (!(obj = networkObjFromNetwork(net)))
3572
        goto cleanup;
3573

3574
    if (virNetworkUndefineEnsureACL(net->conn, obj->def) < 0)
3575 3576
        goto cleanup;

3577
    if (virNetworkObjIsActive(obj))
3578
        active = true;
3579

3580
    if (!obj->persistent) {
3581 3582 3583 3584 3585
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3586
    /* remove autostart link */
3587 3588
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3589
                                  obj) < 0)
3590
        goto cleanup;
3591

3592 3593
    event = virNetworkEventLifecycleNew(obj->def->name,
                                        obj->def->uuid,
3594 3595
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3596

3597
    VIR_INFO("Undefining network '%s'", obj->def->name);
3598
    if (!active) {
3599
        if (networkRemoveInactive(driver, obj) < 0)
3600
            goto cleanup;
3601 3602 3603 3604 3605
    } else {

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

3609
    ret = 0;
3610

3611
 cleanup:
3612 3613
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3614
    virNetworkObjEndAPI(&obj);
3615
    return ret;
3616 3617
}

3618

3619 3620 3621 3622 3623 3624 3625 3626
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3627
    virNetworkDriverStatePtr driver = networkGetDriver();
3628
    virNetworkObjPtr obj = NULL;
3629 3630
    int isActive, ret = -1;
    size_t i;
3631
    virNetworkIPDefPtr ipdef;
3632
    bool oldDhcpActive = false;
3633
    bool needFirewallRefresh = false;
3634

3635 3636 3637 3638 3639

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3640
    if (!(obj = networkObjFromNetwork(net)))
3641 3642
        goto cleanup;

3643
    if (virNetworkUpdateEnsureACL(net->conn, obj->def, flags) < 0)
3644 3645
        goto cleanup;

3646
    /* see if we are listening for dhcp pre-modification */
3647
    for (i = 0;
3648
         (ipdef = virNetworkDefGetIPByIndex(obj->def, AF_INET, i));
3649
         i++) {
3650 3651 3652 3653 3654 3655
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3656 3657
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3658
     */
3659
    isActive = virNetworkObjIsActive(obj);
3660 3661
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3662 3663 3664 3665 3666 3667 3668
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3669 3670 3671 3672
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
3673 3674 3675
        if (obj->def->forward.type == VIR_NETWORK_FORWARD_NONE ||
            obj->def->forward.type == VIR_NETWORK_FORWARD_NAT ||
            obj->def->forward.type == VIR_NETWORK_FORWARD_ROUTE) {
3676 3677 3678 3679 3680 3681 3682 3683 3684 3685
            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).
                 */
3686 3687
                if (obj->def->forward.type != VIR_NETWORK_FORWARD_OPEN) {
                    networkRemoveFirewallRules(obj->def);
3688 3689
                    needFirewallRefresh = true;
                }
3690 3691 3692 3693 3694 3695 3696
                break;
            default:
                break;
            }
        }
    }

3697
    /* update the network config in memory/on disk */
3698
    if (virNetworkObjUpdate(obj, command, section, parentIndex, xml, flags) < 0) {
3699
        if (needFirewallRefresh)
3700
            ignore_value(networkAddFirewallRules(obj->def));
3701 3702 3703
        goto cleanup;
    }

3704
    if (needFirewallRefresh && networkAddFirewallRules(obj->def) < 0)
3705 3706 3707 3708 3709
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
3710
                                 virNetworkObjGetPersistentDef(obj)) < 0) {
3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723
            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 ||
3724 3725 3726 3727 3728 3729 3730 3731
            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)
3732
             */
3733
            if (networkRestartDhcpDaemon(driver, obj) < 0)
3734 3735
                goto cleanup;

3736 3737 3738 3739 3740 3741 3742 3743
        } 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;

3744
            for (i = 0;
3745
                 (ipdef = virNetworkDefGetIPByIndex(obj->def, AF_INET, i));
3746
                 i++) {
3747 3748 3749 3750 3751 3752 3753
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3754 3755
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
3756 3757 3758
                goto cleanup;
            }

3759 3760 3761 3762
        } 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.
3763
             */
3764
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
3765 3766 3767 3768 3769 3770 3771 3772
                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.
             */
3773
            if (networkRefreshRadvd(driver, obj) < 0)
3774 3775 3776 3777
                goto cleanup;
        }

        /* save current network state to disk */
3778
        if ((ret = virNetworkObjSaveStatus(driver->stateDir, obj)) < 0)
3779 3780
            goto cleanup;
    }
3781 3782

    /* call the 'updated' network hook script */
3783
    if (networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_UPDATED,
3784 3785 3786
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

3787
    ret = 0;
3788
 cleanup:
3789
    virNetworkObjEndAPI(&obj);
3790 3791 3792
    return ret;
}

3793 3794 3795

static int
networkCreate(virNetworkPtr net)
3796
{
3797
    virNetworkDriverStatePtr driver = networkGetDriver();
3798
    virNetworkObjPtr obj;
3799
    int ret = -1;
3800
    virObjectEventPtr event = NULL;
3801

3802
    if (!(obj = networkObjFromNetwork(net)))
3803
        goto cleanup;
3804

3805
    if (virNetworkCreateEnsureACL(net->conn, obj->def) < 0)
3806 3807
        goto cleanup;

3808
    if ((ret = networkStartNetwork(driver, obj)) < 0)
3809
        goto cleanup;
3810

3811 3812
    event = virNetworkEventLifecycleNew(obj->def->name,
                                        obj->def->uuid,
3813 3814
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3815

3816
 cleanup:
3817 3818
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3819
    virNetworkObjEndAPI(&obj);
3820
    return ret;
3821 3822
}

3823 3824 3825

static int
networkDestroy(virNetworkPtr net)
3826
{
3827
    virNetworkDriverStatePtr driver = networkGetDriver();
3828
    virNetworkObjPtr obj;
3829
    int ret = -1;
3830
    virObjectEventPtr event = NULL;
3831

3832
    if (!(obj = networkObjFromNetwork(net)))
3833
        goto cleanup;
3834

3835
    if (virNetworkDestroyEnsureACL(net->conn, obj->def) < 0)
3836 3837
        goto cleanup;

3838
    if (!virNetworkObjIsActive(obj)) {
3839
        virReportError(VIR_ERR_OPERATION_INVALID,
3840
                       _("network '%s' is not active"),
3841
                       obj->def->name);
3842 3843 3844
        goto cleanup;
    }

3845
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
3846 3847
        goto cleanup;

3848 3849
    event = virNetworkEventLifecycleNew(obj->def->name,
                                        obj->def->uuid,
3850 3851
                                        VIR_NETWORK_EVENT_STOPPED,
                                        0);
3852

3853
    if (!obj->persistent && networkRemoveInactive(driver, obj) < 0) {
3854 3855
        ret = -1;
        goto cleanup;
3856
    }
3857

3858
 cleanup:
3859 3860
    if (event)
        virObjectEventStateQueue(driver->networkEventState, event);
3861
    virNetworkObjEndAPI(&obj);
3862 3863 3864
    return ret;
}

3865 3866 3867 3868

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
3869
{
3870
    virNetworkObjPtr obj;
3871
    virNetworkDefPtr def;
3872
    char *ret = NULL;
3873

3874
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
3875

3876
    if (!(obj = networkObjFromNetwork(net)))
3877
        return ret;
3878

3879
    if (virNetworkGetXMLDescEnsureACL(net->conn, obj->def) < 0)
3880 3881
        goto cleanup;

3882 3883
    if ((flags & VIR_NETWORK_XML_INACTIVE) && obj->newDef)
        def = obj->newDef;
3884
    else
3885
        def = obj->def;
3886 3887

    ret = virNetworkDefFormat(def, flags);
3888

3889
 cleanup:
3890
    virNetworkObjEndAPI(&obj);
3891
    return ret;
3892 3893
}

3894 3895 3896 3897

static char *
networkGetBridgeName(virNetworkPtr net)
{
3898
    virNetworkObjPtr obj;
3899 3900
    char *bridge = NULL;

3901
    if (!(obj = networkObjFromNetwork(net)))
3902
        return bridge;
3903

3904
    if (virNetworkGetBridgeNameEnsureACL(net->conn, obj->def) < 0)
3905 3906
        goto cleanup;

3907
    if (!(obj->def->bridge)) {
3908 3909
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
3910
                       obj->def->name);
3911 3912 3913
        goto cleanup;
    }

3914
    ignore_value(VIR_STRDUP(bridge, obj->def->bridge));
3915

3916
 cleanup:
3917
    virNetworkObjEndAPI(&obj);
3918 3919 3920
    return bridge;
}

3921 3922 3923 3924

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
3925
{
3926
    virNetworkObjPtr obj;
3927
    int ret = -1;
3928

3929
    if (!(obj = networkObjFromNetwork(net)))
3930
        return ret;
3931

3932
    if (virNetworkGetAutostartEnsureACL(net->conn, obj->def) < 0)
3933 3934
        goto cleanup;

3935
    *autostart = obj->autostart;
3936
    ret = 0;
3937

3938
 cleanup:
3939
    virNetworkObjEndAPI(&obj);
3940
    return ret;
3941 3942
}

3943 3944 3945 3946

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
3947
{
3948
    virNetworkDriverStatePtr driver = networkGetDriver();
3949
    virNetworkObjPtr obj;
3950
    char *configFile = NULL, *autostartLink = NULL;
3951
    int ret = -1;
3952

3953

3954
    if (!(obj = networkObjFromNetwork(net)))
3955
        goto cleanup;
3956

3957
    if (virNetworkSetAutostartEnsureACL(net->conn, obj->def) < 0)
3958 3959
        goto cleanup;

3960
    if (!obj->persistent) {
3961 3962
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
3963 3964 3965
        goto cleanup;
    }

3966 3967
    autostart = (autostart != 0);

3968 3969
    if (obj->autostart != autostart) {
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir, obj->def->name)) == NULL)
3970
            goto cleanup;
3971
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir, obj->def->name)) == NULL)
3972 3973
            goto cleanup;

3974
        if (autostart) {
3975
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
3976
                virReportSystemError(errno,
3977 3978
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
3979 3980
                goto cleanup;
            }
3981

3982
            if (symlink(configFile, autostartLink) < 0) {
3983
                virReportSystemError(errno,
3984
                                     _("Failed to create symlink '%s' to '%s'"),
3985
                                     autostartLink, configFile);
3986 3987 3988
                goto cleanup;
            }
        } else {
3989
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
3990
                virReportSystemError(errno,
3991
                                     _("Failed to delete symlink '%s'"),
3992
                                     autostartLink);
3993 3994
                goto cleanup;
            }
3995 3996
        }

3997
        obj->autostart = autostart;
3998
    }
3999
    ret = 0;
4000

4001
 cleanup:
4002 4003
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4004
    virNetworkObjEndAPI(&obj);
4005
    return ret;
4006 4007
}

4008

4009
static int
4010
networkGetDHCPLeases(virNetworkPtr net,
4011 4012 4013
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
4014
{
4015
    virNetworkDriverStatePtr driver = networkGetDriver();
4016 4017 4018
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
4019
    ssize_t size = 0;
4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030
    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;
4031
    virNetworkIPDefPtr ipdef_tmp = NULL;
4032 4033
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
4034
    virNetworkObjPtr obj;
4035
    virMacAddr mac_addr;
4036 4037 4038

    virCheckFlags(0, -1);

4039 4040 4041 4042 4043 4044
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4045
    if (!(obj = networkObjFromNetwork(net)))
4046 4047
        return -1;

4048
    if (virNetworkGetDHCPLeasesEnsureACL(net->conn, obj->def) < 0)
4049
        goto cleanup;
4050 4051

    /* Retrieve custom leases file location */
4052
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, obj->def->bridge);
4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095

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

4096
        if (mac && virMacAddrCompare(mac, mac_tmp))
4097 4098 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
            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 */
            for (j = 0; j < obj->def->nips; j++) {
                ipdef_tmp = &obj->def->ips[j];

                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)) {
4138
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4139 4140 4141 4142 4143 4144 4145 4146
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
4147
                (VIR_STRDUP(lease->iface, obj->def->bridge) < 0))
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 4174 4175 4176 4177 4178 4179
                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);
4180
    VIR_FREE(lease_entries);
4181 4182
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4183

4184
    virNetworkObjEndAPI(&obj);
4185

4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196
    return rv;

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

4197 4198

static virNetworkDriver networkDriver = {
4199
    .name = "bridge",
4200 4201 4202 4203 4204
    .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 */
4205 4206
    .connectNetworkEventRegisterAny = networkConnectNetworkEventRegisterAny, /* 1.2.1 */
    .connectNetworkEventDeregisterAny = networkConnectNetworkEventDeregisterAny, /* 1.2.1 */
4207 4208
    .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
    .networkLookupByName = networkLookupByName, /* 0.2.0 */
4209 4210
    .networkCreateXML = networkCreateXML, /* 0.2.0 */
    .networkDefineXML = networkDefineXML, /* 0.2.0 */
4211
    .networkUndefine = networkUndefine, /* 0.2.0 */
4212
    .networkUpdate = networkUpdate, /* 0.10.2 */
4213
    .networkCreate = networkCreate, /* 0.2.0 */
4214 4215 4216 4217 4218 4219 4220
    .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 */
4221
    .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.2.6 */
4222 4223 4224
};

static virStateDriver networkStateDriver = {
4225
    .name = "bridge",
4226
    .stateInitialize  = networkStateInitialize,
4227
    .stateAutoStart  = networkStateAutoStart,
4228 4229
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
4230 4231
};

4232 4233
int
networkRegister(void)
4234
{
4235
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
4236
        return -1;
4237 4238
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
4239 4240
    return 0;
}
4241

4242

4243 4244
/********************************************************/

4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279
/* 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);
        }
    }
}

4280

4281 4282 4283 4284 4285 4286 4287 4288 4289
/* 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:
4290
 * @dom: domain definition that @iface belongs to
4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301
 * @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
4302 4303
networkAllocateActualDevice(virDomainDefPtr dom,
                            virDomainNetDefPtr iface)
4304
{
4305
    virNetworkDriverStatePtr driver = networkGetDriver();
4306
    virDomainNetType actualType = iface->type;
4307
    virNetworkObjPtr obj = NULL;
4308
    virNetworkDefPtr netdef = NULL;
4309
    virNetDevBandwidthPtr bandwidth = NULL;
4310 4311 4312
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
4313
    virNetworkForwardIfDefPtr dev = NULL;
4314
    size_t i;
4315 4316 4317
    int ret = -1;

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4318
        goto validate;
4319 4320 4321 4322

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

4323 4324
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4325 4326 4327
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4328
        goto error;
4329
    }
4330
    netdef = obj->def;
4331

4332
    if (!virNetworkObjIsActive(obj)) {
4333 4334 4335 4336 4337 4338
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4339 4340 4341
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

4342 4343 4344
    /* 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 已提交
4345
     */
4346 4347 4348 4349 4350 4351
    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.
     */
4352 4353 4354 4355 4356 4357

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

4358 4359
    if (bandwidth && virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
                                            bandwidth) < 0)
4360
        goto error;
4361

4362 4363 4364 4365 4366 4367 4368 4369
    /* 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;

4370 4371
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
4372

4373 4374 4375 4376 4377 4378 4379 4380 4381 4382
    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;

4383 4384
    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
4385 4386
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
4387
        /* for these forward types, the actual net type really *is*
4388
         * NETWORK; we just keep the info from the portgroup in
4389
         * iface->data.network.actual
J
Ján Tomko 已提交
4390
         */
4391
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
4392

4393
        /* we also store the bridge device and macTableManager settings
4394 4395 4396 4397 4398 4399 4400
         * 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;
4401 4402
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4403

4404
        if (networkPlugBandwidth(obj, iface) < 0)
4405 4406
            goto error;

4407
    } else if ((netdef->forward.type == VIR_NETWORK_FORWARD_BRIDGE) &&
4408
               netdef->bridge) {
4409 4410 4411 4412 4413

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

4414
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_BRIDGE;
4415 4416
        if (VIR_STRDUP(iface->data.network.actual->data.bridge.brname,
                       netdef->bridge) < 0)
4417
            goto error;
4418 4419
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4420

4421 4422 4423 4424 4425 4426 4427 4428
        /* 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) {
4429
            goto error;
4430 4431 4432 4433 4434 4435 4436 4437 4438 4439
        }
        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);
4440
                goto error;
4441 4442 4443
            }
        }

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

4446
        virDomainHostdevSubsysPCIBackendType backend;
4447

4448
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
4449
        if (networkCreateInterfacePool(netdef) < 0)
4450 4451 4452
            goto error;

        /* pick first dev with 0 connections */
4453 4454 4455
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469
                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;
4470
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
4471
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
4472
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
4473

E
Eric Blake 已提交
4474
        switch (netdef->forward.driverName) {
4475
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
4476
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4477 4478
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
4479
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
4480 4481
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
4482
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493
            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;

4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518
        /* 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;
            }
        }

4519 4520 4521 4522
    } 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)) {
4523 4524 4525 4526 4527 4528

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

        /* Set type=direct and appropriate <source mode='xxx'/> */
4529
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
4530
        switch (netdef->forward.type) {
4531
        case VIR_NETWORK_FORWARD_BRIDGE:
4532
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_BRIDGE;
4533 4534
            break;
        case VIR_NETWORK_FORWARD_PRIVATE:
4535
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PRIVATE;
4536 4537
            break;
        case VIR_NETWORK_FORWARD_VEPA:
4538
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_VEPA;
4539 4540
            break;
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
4541
            iface->data.network.actual->data.direct.mode = VIR_NETDEV_MACVLAN_MODE_PASSTHRU;
4542 4543 4544
            break;
        }

4545 4546 4547 4548 4549 4550 4551 4552
        /* 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) {
4553
            goto error;
4554
        }
4555
        virtport = iface->data.network.actual->virtPortProfile;
4556
        if (virtport) {
4557 4558 4559 4560 4561 4562 4563 4564
            /* 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);
4565
                goto error;
4566 4567
            }
        }
4568

4569 4570 4571
        /* 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).
         */
4572
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4573 4574 4575 4576
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4577
            goto error;
4578 4579 4580
        } else {
            /* pick an interface from the pool */

4581
            if (networkCreateInterfacePool(netdef) < 0)
4582 4583
                goto error;

4584 4585 4586 4587 4588
            /* 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.
4589
             */
4590 4591
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4592 4593 4594
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4595

4596
                /* pick first dev with 0 connections */
4597 4598 4599
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4600 4601 4602 4603 4604
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4605
                dev = &netdef->forward.ifs[0];
4606 4607 4608
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4609 4610 4611 4612
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4613 4614 4615 4616
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4617
                goto error;
4618
            }
4619 4620
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
4621
                goto error;
4622 4623 4624
        }
    }

4625 4626
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
                               dom->name, &iface->mac) < 0)
M
Michal Privoznik 已提交
4627 4628
        goto error;

4629
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
4630
        goto error;
4631

4632
 validate:
4633 4634 4635 4636 4637
    /* 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.
     */

4638
    if (virDomainNetGetActualVlan(iface)) {
4639 4640 4641 4642
        /* 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
4643 4644
         */
        if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
4645 4646 4647
              (actualType == VIR_DOMAIN_NET_TYPE_DIRECT &&
               virDomainNetGetActualDirectMode(iface)
               == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) ||
4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666
              (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;
        }
    }
4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677
    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;
        }
    }
4678 4679 4680

    if (netdef) {
        netdef->connections++;
4681
        if (dev)
4682 4683
            dev->connections++;
        /* finally we can call the 'plugged' hook script if any */
4684
        if (networkRunHook(obj, dom, iface,
4685 4686 4687
                           VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
                           VIR_HOOK_SUBOP_BEGIN) < 0) {
            /* adjust for failure */
4688
            netdef->connections--;
4689 4690 4691 4692
            if (dev)
                dev->connections--;
            goto error;
        }
4693
        networkLogAllocation(netdef, actualType, dev, iface, true);
4694 4695
    }

4696
    ret = 0;
4697

4698
 cleanup:
4699
    virNetworkObjEndAPI(&obj);
4700 4701
    return ret;

4702
 error:
4703
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4704 4705 4706
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4707
    goto cleanup;
4708 4709
}

4710

4711
/* networkNotifyActualDevice:
4712
 * @dom: domain definition that @iface belongs to
4713 4714 4715 4716 4717
 * @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
4718 4719
 * order, or re-attach the interface's tap device to the network's
 * bridge.
4720
 *
4721
 * No return value (but does log any failures)
4722
 */
4723
void
4724 4725
networkNotifyActualDevice(virDomainDefPtr dom,
                          virDomainNetDefPtr iface)
4726
{
4727
    virNetworkDriverStatePtr driver = networkGetDriver();
4728
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4729
    virNetworkObjPtr obj;
4730
    virNetworkDefPtr netdef;
4731
    virNetworkForwardIfDefPtr dev = NULL;
4732
    size_t i;
4733
    char *master = NULL;
4734 4735

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4736
        return;
4737

4738 4739
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4740 4741 4742
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4743 4744
        goto error;
    }
4745
    netdef = obj->def;
4746

4747
    if (!virNetworkObjIsActive(obj)) {
4748 4749 4750 4751 4752 4753
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764
    /* 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;

4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789
    /* 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;
            }
        }
    }

4790
    if (!iface->data.network.actual ||
4791 4792
        (actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
4793 4794
        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
        goto success;
4795 4796
    }

4797
    if (networkCreateInterfacePool(netdef) < 0)
4798
        goto error;
4799

4800
    if (netdef->forward.nifs == 0) {
4801
        virReportError(VIR_ERR_INTERNAL_ERROR,
4802 4803
                       _("network '%s' uses a direct or hostdev mode, "
                         "but has no forward dev and no interface pool"),
4804
                       netdef->name);
4805
        goto error;
4806
    }
4807

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

4811 4812 4813 4814 4815 4816 4817 4818 4819
        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 */
4820 4821
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4822
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4823 4824
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4825 4826 4827 4828 4829
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4830
            virReportError(VIR_ERR_INTERNAL_ERROR,
4831 4832
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4833
                           netdef->name, actualDev);
4834
            goto error;
4835 4836
        }

4837
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4838 4839
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4840
         */
4841
        if ((dev->connections > 0) &&
4842 4843
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4844 4845
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
4846
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
4847
            virReportError(VIR_ERR_INTERNAL_ERROR,
4848 4849
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
4850
                           netdef->name, actualDev);
4851
            goto error;
4852
        }
4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864
    }  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 */
4865 4866
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4867
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
4868
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
4869 4870
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
4871 4872 4873 4874 4875 4876 4877 4878 4879
                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,
4880 4881 4882 4883
                           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 已提交
4884
            goto error;
4885 4886 4887 4888 4889 4890 4891
        }

        /* 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) &&
4892
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
4893 4894 4895 4896 4897 4898 4899 4900 4901
            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;
        }
4902 4903
    }

4904
 success:
4905
    netdef->connections++;
4906 4907
    if (dev)
        dev->connections++;
4908
    /* finally we can call the 'plugged' hook script if any */
4909
    if (networkRunHook(obj, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
4910 4911 4912 4913 4914 4915 4916
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
        goto error;
    }
4917
    networkLogAllocation(netdef, actualType, dev, iface, true);
4918

4919
 cleanup:
4920
    virNetworkObjEndAPI(&obj);
4921
    VIR_FREE(master);
4922
    return;
4923

4924
 error:
4925
    goto cleanup;
4926 4927 4928 4929
}


/* networkReleaseActualDevice:
4930
 * @dom: domain definition that @iface belongs to
4931 4932 4933 4934 4935 4936 4937 4938 4939 4940
 * @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
4941 4942
networkReleaseActualDevice(virDomainDefPtr dom,
                           virDomainNetDefPtr iface)
4943
{
4944
    virNetworkDriverStatePtr driver = networkGetDriver();
4945
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4946
    virNetworkObjPtr obj;
4947
    virNetworkDefPtr netdef;
4948
    virNetworkForwardIfDefPtr dev = NULL;
4949 4950
    size_t i;
    int ret = -1;
4951 4952

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

4955 4956
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4957 4958 4959
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4960 4961
        goto error;
    }
4962
    netdef = obj->def;
4963

4964 4965
    if (iface->data.network.actual &&
        (netdef->forward.type == VIR_NETWORK_FORWARD_NONE ||
4966
         netdef->forward.type == VIR_NETWORK_FORWARD_NAT ||
4967 4968
         netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE ||
         netdef->forward.type == VIR_NETWORK_FORWARD_OPEN) &&
4969
        networkUnplugBandwidth(obj, iface) < 0)
4970 4971
        goto error;

4972 4973 4974
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
4975 4976
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
4977 4978
    }

4979
    if (netdef->forward.nifs == 0) {
4980
        virReportError(VIR_ERR_INTERNAL_ERROR,
4981
                       _("network '%s' uses a direct/hostdev mode, but "
4982 4983
                         "has no forward dev and no interface pool"),
                       netdef->name);
4984
        goto error;
4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996
    }

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

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

5007
        if (!dev) {
5008
            virReportError(VIR_ERR_INTERNAL_ERROR,
5009 5010
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5011
                           netdef->name, actualDev);
5012
            goto error;
5013
        }
5014 5015 5016 5017 5018 5019 5020 5021 5022 5023
    } 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;
        }

5024 5025
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5026
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5027
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
5028 5029
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5030 5031 5032 5033 5034 5035 5036 5037 5038
                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,
5039 5040 5041 5042
                           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 已提交
5043
            goto error;
5044
        }
J
Ján Tomko 已提交
5045
    }
5046

5047
 success:
5048
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, dom->name, &iface->mac);
M
Michal Privoznik 已提交
5049

5050
    if (iface->data.network.actual) {
5051
        netdef->connections--;
5052 5053
        if (dev)
            dev->connections--;
5054
        /* finally we can call the 'unplugged' hook script if any */
5055
        networkRunHook(obj, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
5056
                       VIR_HOOK_SUBOP_BEGIN);
5057
        networkLogAllocation(netdef, actualType, dev, iface, false);
5058
    }
5059
    ret = 0;
5060
 cleanup:
5061
    virNetworkObjEndAPI(&obj);
5062 5063 5064 5065
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
5066
    return ret;
5067

5068
 error:
5069
    goto cleanup;
5070
}
5071

5072

5073 5074 5075 5076 5077
/*
 * networkGetNetworkAddress:
 * @netname: the name of a network
 * @netaddr: string representation of IP address for that network.
 *
5078
 * Attempt to return an IP address associated with the named
5079 5080 5081 5082
 * 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.
 *
5083
 * Note: This function returns the first IP address it finds. It might
5084 5085 5086 5087 5088 5089 5090 5091 5092
 * 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
5093 5094
networkGetNetworkAddress(const char *netname,
                         char **netaddr)
5095
{
5096
    virNetworkDriverStatePtr driver = networkGetDriver();
5097
    int ret = -1;
5098
    virNetworkObjPtr obj;
5099
    virNetworkDefPtr netdef;
5100
    virNetworkIPDefPtr ipdef;
5101 5102
    virSocketAddr addr;
    virSocketAddrPtr addrptr = NULL;
5103
    char *dev_name = NULL;
5104 5105

    *netaddr = NULL;
5106 5107
    obj = virNetworkObjFindByName(driver->networks, netname);
    if (!obj) {
5108 5109 5110
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       netname);
5111
        goto cleanup;
5112
    }
5113
    netdef = obj->def;
5114

5115
    switch (netdef->forward.type) {
5116 5117 5118
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
5119
    case VIR_NETWORK_FORWARD_OPEN:
5120
        ipdef = virNetworkDefGetIPByIndex(netdef, AF_UNSPEC, 0);
5121
        if (!ipdef) {
5122
            virReportError(VIR_ERR_INTERNAL_ERROR,
5123
                           _("network '%s' doesn't have an IP address"),
5124
                           netdef->name);
5125
            goto cleanup;
5126 5127 5128 5129 5130
        }
        addrptr = &ipdef->address;
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
5131
        if ((dev_name = netdef->bridge))
5132 5133
            break;
        /*
5134 5135
         * fall through if netdef->bridge wasn't set, since that is
         * macvtap bridge mode network.
5136
         */
5137 5138
        ATTRIBUTE_FALLTHROUGH;

5139 5140 5141
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
5142 5143
        if ((netdef->forward.nifs > 0) && netdef->forward.ifs)
            dev_name = netdef->forward.ifs[0].device.dev;
5144

5145
        if (!dev_name) {
5146 5147 5148
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' has no associated interface or bridge"),
                           netdef->name);
5149
            goto cleanup;
5150 5151 5152 5153
        }
        break;
    }

5154
    if (dev_name) {
5155
        if (virNetDevIPAddrGet(dev_name, &addr) < 0)
5156
            goto cleanup;
5157
        addrptr = &addr;
5158 5159
    }

5160 5161
    if (!(addrptr &&
          (*netaddr = virSocketAddrFormat(addrptr)))) {
5162
        goto cleanup;
5163 5164
    }

5165
    ret = 0;
5166
 cleanup:
5167
    virNetworkObjEndAPI(&obj);
5168 5169
    return ret;
}
5170

5171

5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184
/* 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();
5185
    virNetworkObjPtr obj = NULL;
5186 5187 5188 5189 5190 5191 5192 5193 5194
    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;

5195 5196
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5197 5198 5199 5200 5201
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return -1;
    }
5202
    netdef = obj->def;
5203 5204 5205

    if ((netdef->forward.type == VIR_NETWORK_FORWARD_NONE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_NAT) ||
5206 5207
        (netdef->forward.type == VIR_NETWORK_FORWARD_ROUTE) ||
        (netdef->forward.type == VIR_NETWORK_FORWARD_OPEN)) {
5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239
        /* 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;

    }

5240
    virNetworkObjEndAPI(&obj);
5241 5242 5243 5244
    return ret;
}


5245 5246 5247
/**
 * networkCheckBandwidth:
 * @net: network QoS
5248
 * @ifaceBand: interface QoS (may be NULL if no QoS)
5249
 * @oldBandwidth: new interface QoS (may be NULL if no QoS)
5250
 * @ifaceMac: interface MAC (used in error messages for identification)
5251 5252
 * @new_rate: new rate for non guaranteed class
 *
5253 5254 5255 5256 5257 5258 5259 5260
 * 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.
 *
5261 5262 5263 5264 5265
 * 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
5266
networkCheckBandwidth(virNetworkObjPtr obj,
5267
                      virNetDevBandwidthPtr ifaceBand,
5268
                      virNetDevBandwidthPtr oldBandwidth,
5269
                      virMacAddr ifaceMac,
5270 5271 5272
                      unsigned long long *new_rate)
{
    int ret = -1;
5273 5274
    virNetDevBandwidthPtr netBand = obj->def->bandwidth;
    unsigned long long tmp_floor_sum = obj->floor_sum;
5275 5276 5277
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

5278
    virMacAddrFormat(&ifaceMac, ifmac);
5279 5280 5281 5282 5283 5284

    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"),
5285
                       ifmac, obj->def->name);
5286 5287 5288
        return -1;
    }

5289 5290
    if (((!ifaceBand || !ifaceBand->in || !ifaceBand->in->floor) &&
         (!oldBandwidth || !oldBandwidth->in || !oldBandwidth->in->floor)) ||
5291 5292
        !netBand || !netBand->in) {
        /* no QoS required, claim success */
5293
        return 1;
5294
    }
5295 5296

    tmp_new_rate = netBand->in->average;
5297 5298 5299 5300
    if (oldBandwidth && oldBandwidth->in)
        tmp_floor_sum -= oldBandwidth->in->floor;
    if (ifaceBand && ifaceBand->in)
        tmp_floor_sum += ifaceBand->in->floor;
5301 5302 5303 5304 5305 5306 5307 5308 5309

    /* 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,
5310 5311
                           obj->def->bridge,
                           obj->def->name);
5312 5313 5314 5315 5316 5317 5318 5319 5320
            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,
5321 5322
                       obj->def->bridge,
                       obj->def->name);
5323 5324 5325
        goto cleanup;
    }

5326 5327
    if (new_rate)
        *new_rate = tmp_new_rate;
5328 5329
    ret = 0;

5330
 cleanup:
5331 5332 5333
    return ret;
}

5334

5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345
/**
 * 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
5346
networkNextClassID(virNetworkObjPtr obj)
5347
{
5348
    ssize_t ret = 0;
5349
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5350

5351
    ret = virBitmapNextClearBit(classIdMap, -1);
5352

5353
    if (ret < 0 || virBitmapSetBit(classIdMap, ret) < 0)
5354 5355 5356 5357 5358
        return -1;

    return ret;
}

5359

5360
static int
5361
networkPlugBandwidthImpl(virNetworkObjPtr obj,
5362 5363 5364
                         virDomainNetDefPtr iface,
                         virNetDevBandwidthPtr ifaceBand,
                         unsigned long long new_rate)
5365
{
5366
    virNetworkDriverStatePtr driver = networkGetDriver();
5367
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5368
    ssize_t class_id = 0;
5369 5370
    int plug_ret;
    int ret = -1;
5371 5372

    /* generate new class_id */
5373
    if ((class_id = networkNextClassID(obj)) < 0) {
5374 5375 5376 5377 5378
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not generate next class ID"));
        goto cleanup;
    }

5379
    plug_ret = virNetDevBandwidthPlug(obj->def->bridge, obj->def->bandwidth,
5380
                                      &iface->mac, ifaceBand, class_id);
5381
    if (plug_ret < 0) {
5382
        ignore_value(virNetDevBandwidthUnplug(obj->def->bridge, class_id));
5383 5384 5385 5386 5387 5388
        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 */
5389
    obj->floor_sum += ifaceBand->in->floor;
5390
    /* update status file */
5391
    if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5392
        ignore_value(virBitmapClearBit(classIdMap, class_id));
5393
        obj->floor_sum -= ifaceBand->in->floor;
5394
        iface->data.network.actual->class_id = 0;
5395
        ignore_value(virNetDevBandwidthUnplug(obj->def->bridge, class_id));
5396 5397
        goto cleanup;
    }
5398
    /* update rate for non guaranteed NICs */
5399 5400 5401
    new_rate -= obj->floor_sum;
    if (virNetDevBandwidthUpdateRate(obj->def->bridge, 2,
                                     obj->def->bandwidth, new_rate) < 0)
5402
        VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5403
                 obj->def->bridge);
5404 5405

    ret = 0;
5406 5407 5408 5409 5410 5411
 cleanup:
    return ret;
}


static int
5412
networkPlugBandwidth(virNetworkObjPtr obj,
5413 5414 5415 5416 5417 5418 5419 5420
                     virDomainNetDefPtr iface)
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);

5421
    if ((plug_ret = networkCheckBandwidth(obj, ifaceBand, NULL,
5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441
                                          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;
    }

5442
    if (networkPlugBandwidthImpl(obj, iface, ifaceBand, new_rate) < 0)
5443 5444 5445
        goto cleanup;

    ret = 0;
5446

5447
 cleanup:
5448 5449 5450
    return ret;
}

5451

5452
static int
5453
networkUnplugBandwidth(virNetworkObjPtr obj,
5454 5455
                       virDomainNetDefPtr iface)
{
5456
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5457
    virNetworkDriverStatePtr driver = networkGetDriver();
5458 5459
    int ret = 0;
    unsigned long long new_rate;
5460
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
5461 5462 5463

    if (iface->data.network.actual &&
        iface->data.network.actual->class_id) {
5464
        if (!obj->def->bandwidth || !obj->def->bandwidth->in) {
5465
            VIR_WARN("Network %s has no bandwidth but unplug requested",
5466
                     obj->def->name);
5467 5468
            goto cleanup;
        }
5469
        /* we must remove class from bridge */
5470
        new_rate = obj->def->bandwidth->in->average;
5471

5472 5473
        if (obj->def->bandwidth->in->peak > 0)
            new_rate = obj->def->bandwidth->in->peak;
5474

5475
        ret = virNetDevBandwidthUnplug(obj->def->bridge,
5476 5477 5478 5479
                                       iface->data.network.actual->class_id);
        if (ret < 0)
            goto cleanup;
        /* update sum of 'floor'-s of attached NICs */
5480
        obj->floor_sum -= ifaceBand->in->floor;
5481
        /* return class ID */
5482
        ignore_value(virBitmapClearBit(classIdMap,
5483 5484
                                       iface->data.network.actual->class_id));
        /* update status file */
5485 5486
        if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
            obj->floor_sum += ifaceBand->in->floor;
5487
            ignore_value(virBitmapSetBit(classIdMap,
5488 5489 5490
                                         iface->data.network.actual->class_id));
            goto cleanup;
        }
5491
        /* update rate for non guaranteed NICs */
5492 5493 5494
        new_rate -= obj->floor_sum;
        if (virNetDevBandwidthUpdateRate(obj->def->bridge, 2,
                                         obj->def->bandwidth, new_rate) < 0)
5495
            VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5496
                     obj->def->bridge);
5497 5498 5499 5500
        /* no class is associated any longer */
        iface->data.network.actual->class_id = 0;
    }

5501
 cleanup:
5502 5503
    return ret;
}
5504

5505

5506
static void
5507
networkNetworkObjTaint(virNetworkObjPtr obj,
5508
                       virNetworkTaintFlags taint)
5509
{
5510
    if (virNetworkObjTaint(obj, taint)) {
5511
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5512
        virUUIDFormat(obj->def->uuid, uuidstr);
5513 5514

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5515
                 obj->def->name,
5516 5517 5518 5519
                 uuidstr,
                 virNetworkTaintTypeToString(taint));
    }
}
5520 5521 5522 5523 5524 5525


static bool
networkBandwidthGenericChecks(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
5526
    virNetDevBandwidthPtr ifaceBand;
5527 5528 5529 5530 5531 5532 5533 5534
    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;
    }

5535
    ifaceBand = virDomainNetGetActualBandwidth(iface);
5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551
    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();
5552
    virNetworkObjPtr obj = NULL;
5553 5554 5555 5556 5557 5558
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    bool ret = false;

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

5559 5560
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5561 5562 5563 5564 5565 5566
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return false;
    }

5567
    if (networkCheckBandwidth(obj, newBandwidth, ifaceBand, iface->mac, NULL) < 0)
5568 5569 5570 5571 5572
        goto cleanup;

    ret = true;

 cleanup:
5573
    virNetworkObjEndAPI(&obj);
5574 5575
    return ret;
}
5576 5577 5578 5579 5580 5581 5582


int
networkBandwidthUpdate(virDomainNetDefPtr iface,
                       virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5583
    virNetworkObjPtr obj = NULL;
5584 5585 5586 5587 5588 5589 5590 5591
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    unsigned long long new_rate = 0;
    int plug_ret;
    int ret = -1;

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

5592 5593
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5594 5595 5596 5597 5598 5599
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return ret;
    }

5600
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, ifaceBand,
5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613
                                          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: */

5614
    if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
5615
        newBandwidth->in && newBandwidth->in->floor) {
5616 5617
        /* Either we just need to update @floor .. */

5618
        if (virNetDevBandwidthUpdateRate(obj->def->bridge,
5619
                                         iface->data.network.actual->class_id,
5620
                                         obj->def->bandwidth,
5621 5622 5623
                                         newBandwidth->in->floor) < 0)
            goto cleanup;

5624 5625 5626
        obj->floor_sum -= ifaceBand->in->floor;
        obj->floor_sum += newBandwidth->in->floor;
        new_rate -= obj->floor_sum;
5627

5628 5629 5630
        if (virNetDevBandwidthUpdateRate(obj->def->bridge, 2,
                                         obj->def->bandwidth, new_rate) < 0 ||
            virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5631
            /* Ouch, rollback */
5632 5633
            obj->floor_sum -= newBandwidth->in->floor;
            obj->floor_sum += ifaceBand->in->floor;
5634

5635
            ignore_value(virNetDevBandwidthUpdateRate(obj->def->bridge,
5636
                                                      iface->data.network.actual->class_id,
5637
                                                      obj->def->bandwidth,
5638 5639 5640 5641 5642 5643
                                                      ifaceBand->in->floor));
            goto cleanup;
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5644
        if (networkPlugBandwidthImpl(obj, iface, newBandwidth, new_rate) < 0)
5645 5646 5647 5648
            goto cleanup;
    } else {
        /* .. or unplug old. */

5649
        if (networkUnplugBandwidth(obj, iface) < 0)
5650 5651 5652 5653 5654
            goto cleanup;
    }

    ret = 0;
 cleanup:
5655
    virNetworkObjEndAPI(&obj);
5656 5657
    return ret;
}