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

#include <config.h>

#include <sys/types.h>
#include <sys/poll.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <pwd.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
42
#include <net/if.h>
43
#include <dirent.h>
44 45 46
#if HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
47

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

79
#define VIR_FROM_THIS VIR_FROM_NETWORK
80
#define MAX_BRIDGE_ID 256
81

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

89 90
#define SYSCTL_PATH "/proc/sys"

91 92
VIR_LOG_INIT("network.bridge_driver");

93
static virNetworkDriverStatePtr network_driver;
94

95

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

105 106 107

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


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

119

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

130

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

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

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

146

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

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

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

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

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

166
static int
167
networkStartNetworkExternal(virNetworkObjPtr obj);
168

169
static int
170
networkShutdownNetworkExternal(virNetworkObjPtr obj);
171

172 173
static void
networkReloadFirewallRules(virNetworkDriverStatePtr driver);
174

175 176
static void
networkRefreshDaemons(virNetworkDriverStatePtr driver);
177

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

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

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

190

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

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

206
    return obj;
207 208
}

209

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

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

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

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

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

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

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

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

268

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

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

280

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

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

292

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

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

304

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

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

315

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

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

327

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

    int ret = -1;

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

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

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;

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

405

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

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

430

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

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

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

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

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

465 466
        virNetworkObjSetMacMap(obj, macmap);

467
        break;
468

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

485 486 487
    case VIR_NETWORK_FORWARD_HOSTDEV:
        /* so far no extra checks */
        break;
488 489 490 491 492

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

495
    /* Try and read dnsmasq/radvd pids of active networks */
496
    if (virNetworkObjIsActive(obj) && def->ips && (def->nips > 0)) {
497 498
        pid_t radvdPid;
        pid_t dnsmasqPid;
499
        char *radvdpidbase;
500

501
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
502
                                           def->name,
503
                                           &dnsmasqPid,
504
                                           dnsmasqCapsGetBinaryPath(dnsmasq_caps)));
505
        virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
M
Michal Privoznik 已提交
506

507
        radvdpidbase = networkRadvdPidfileBasename(def->name);
508 509
        if (!radvdpidbase)
            goto cleanup;
510

511 512
        ignore_value(virPidFileReadIfAlive(driver->pidDir,
                                           radvdpidbase,
513 514
                                           &radvdPid, RADVD));
        virNetworkObjSetRadvdPid(obj, radvdPid);
515
        VIR_FREE(radvdpidbase);
516
    }
517

518 519
    ret = 0;
 cleanup:
520
    virObjectUnlock(obj);
521
    virObjectUnref(dnsmasq_caps);
522
    VIR_FREE(macMapFile);
523 524
    return ret;
}
525

526

527
static int
528
networkAutostartConfig(virNetworkObjPtr obj,
529
                       void *opaque)
530
{
531
    virNetworkDriverStatePtr driver = opaque;
532
    int ret = -1;
533

534
    virObjectLock(obj);
535
    if (virNetworkObjIsAutostart(obj) &&
536 537
        !virNetworkObjIsActive(obj) &&
        networkStartNetwork(driver, obj) < 0)
538 539 540 541
        goto cleanup;

    ret = 0;
 cleanup:
542
    virObjectUnlock(obj);
543
    return ret;
544 545
}

546

547 548 549
#if HAVE_FIREWALLD
static DBusHandlerResult
firewalld_dbus_filter_bridge(DBusConnection *connection ATTRIBUTE_UNUSED,
550 551
                             DBusMessage *message,
                             void *user_data)
552
{
553 554
    virNetworkDriverStatePtr driver = user_data;

555 556 557 558 559 560
    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.");
561
        networkReloadFirewallRules(driver);
562 563 564 565 566 567
    }

    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
#endif

568

569
static int
570
networkMigrateStateFiles(virNetworkDriverStatePtr driver)
571 572 573 574 575 576 577 578 579 580 581 582 583
{
    /* 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;
584
    int direrr;
585 586 587
    struct dirent *entry;
    char *oldPath = NULL, *newPath = NULL;
    char *contents = NULL;
J
Ján Tomko 已提交
588
    int rc;
589

J
Ján Tomko 已提交
590 591
    if ((rc = virDirOpenIfExists(&dir, oldStateDir)) <= 0)
        return rc;
592 593 594 595 596 597 598

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

599
    while ((direrr = virDirRead(dir, &entry, oldStateDir)) > 0) {
600 601 602
        if (entry->d_type != DT_UNKNOWN &&
            entry->d_type != DT_REG)
            continue;
603 604 605

        if (virAsprintf(&oldPath, "%s/%s",
                        oldStateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
606
            goto cleanup;
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623

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

624
        if (virFileReadAll(oldPath, 1024*1024, &contents) < 0)
J
Ján Tomko 已提交
625
            goto cleanup;
626 627 628

        if (virAsprintf(&newPath, "%s/%s",
                        driver->stateDir, entry->d_name) < 0)
J
Ján Tomko 已提交
629
            goto cleanup;
630 631 632 633 634 635 636 637 638 639 640 641
        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);
    }
642
    if (direrr < 0)
J
Ján Tomko 已提交
643
        goto cleanup;
644 645 646

    ret = 0;
 cleanup:
J
Ján Tomko 已提交
647
    VIR_DIR_CLOSE(dir);
648 649 650 651 652 653
    VIR_FREE(oldPath);
    VIR_FREE(newPath);
    VIR_FREE(contents);
    return ret;
}

654

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

672
    if (VIR_ALLOC(network_driver) < 0)
673
        goto error;
674

675 676
    if (virMutexInit(&network_driver->lock) < 0) {
        VIR_FREE(network_driver);
677 678
        goto error;
    }
679

680 681
    network_driver->privileged = privileged;

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

        /* migration from old to new location is only applicable for
         * privileged mode - unprivileged mode directories haven't
         * changed location.
         */
705
        if (networkMigrateStateFiles(network_driver) < 0)
706
            goto error;
707
    } else {
708 709 710
        configdir = virGetUserConfigDirectory();
        rundir = virGetUserRuntimeDirectory();
        if (!(configdir && rundir))
711
            goto error;
712

713
        if ((virAsprintf(&network_driver->networkConfigDir,
714
                         "%s/qemu/networks", configdir) < 0) ||
715
            (virAsprintf(&network_driver->networkAutostartDir,
716
                         "%s/qemu/networks/autostart", configdir) < 0) ||
717
            (virAsprintf(&network_driver->stateDir,
718
                         "%s/network/lib", rundir) < 0) ||
719
            (virAsprintf(&network_driver->pidDir,
720
                         "%s/network/run", rundir) < 0) ||
721
            (virAsprintf(&network_driver->dnsmasqStateDir,
722
                         "%s/dnsmasq/lib", rundir) < 0) ||
723
            (virAsprintf(&network_driver->radvdStateDir,
724
                         "%s/radvd/lib", rundir) < 0)) {
725
            goto error;
726
        }
727 728
    }

729
    if (virFileMakePath(network_driver->stateDir) < 0) {
730 731
        virReportSystemError(errno,
                             _("cannot create directory %s"),
732
                             network_driver->stateDir);
733 734 735
        goto error;
    }

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

739
    if (!(network_driver->networks = virNetworkObjListNew()))
740 741
        goto error;

742 743
    if (virNetworkObjLoadAllState(network_driver->networks,
                                  network_driver->stateDir) < 0)
744 745
        goto error;

746 747 748
    if (virNetworkObjLoadAllConfigs(network_driver->networks,
                                    network_driver->networkConfigDir,
                                    network_driver->networkAutostartDir) < 0)
749 750
        goto error;

751 752 753 754
    /* 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). */
755
    virNetworkObjListForEach(network_driver->networks,
756
                             networkUpdateState,
757 758
                             network_driver);
    virNetworkObjListPrune(network_driver->networks,
759 760
                           VIR_CONNECT_LIST_NETWORKS_INACTIVE |
                           VIR_CONNECT_LIST_NETWORKS_TRANSIENT);
761 762
    networkReloadFirewallRules(network_driver);
    networkRefreshDaemons(network_driver);
763

764
    network_driver->networkEventState = virObjectEventStateNew();
765

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

791
    ret = 0;
792
 cleanup:
793 794 795
    VIR_FREE(configdir);
    VIR_FREE(rundir);
    return ret;
796

797
 error:
798
    networkStateCleanup();
799
    goto cleanup;
800 801
}

802

803 804 805 806 807 808 809 810
/**
 * networkStateAutoStart:
 *
 * Function to AutoStart the bridge configs
 */
static void
networkStateAutoStart(void)
{
811
    if (!network_driver)
812 813
        return;

814
    virNetworkObjListForEach(network_driver->networks,
815
                             networkAutostartConfig,
816
                             network_driver);
817 818
}

819

820
/**
821
 * networkStateReload:
822
 *
J
Ján Tomko 已提交
823
 * Function to restart the QEMU daemon, it will recheck the configuration
824 825 826
 * files and update its state and the networking
 */
static int
827 828
networkStateReload(void)
{
829
    if (!network_driver)
830 831
        return 0;

832 833 834 835 836
    virNetworkObjLoadAllState(network_driver->networks,
                              network_driver->stateDir);
    virNetworkObjLoadAllConfigs(network_driver->networks,
                                network_driver->networkConfigDir,
                                network_driver->networkAutostartDir);
837 838 839
    networkReloadFirewallRules(network_driver);
    networkRefreshDaemons(network_driver);
    virNetworkObjListForEach(network_driver->networks,
840
                             networkAutostartConfig,
841
                             network_driver);
842 843 844 845 846
    return 0;
}


/**
847
 * networkStateCleanup:
848
 *
J
Ján Tomko 已提交
849
 * Shutdown the QEMU daemon, it will stop all active domains and networks
850 851
 */
static int
852 853
networkStateCleanup(void)
{
854
    if (!network_driver)
855 856
        return -1;

857
    virObjectUnref(network_driver->networkEventState);
858

859
    /* free inactive networks */
860
    virObjectUnref(network_driver->networks);
861

862 863 864 865 866 867
    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);
868

869
    virObjectUnref(network_driver->dnsmasqCaps);
870

871
    virMutexDestroy(&network_driver->lock);
872

873
    VIR_FREE(network_driver);
874 875 876 877 878

    return 0;
}


879 880 881 882 883 884 885 886
static virDrvOpenStatus
networkConnectOpen(virConnectPtr conn,
                   virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                   virConfPtr conf ATTRIBUTE_UNUSED,
                   unsigned int flags)
{
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

887 888 889 890 891 892 893 894 895 896 897
    if (network_driver == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("network state driver is not active"));
        return VIR_DRV_OPEN_ERROR;
    }

    if (network_driver->privileged) {
        if (STRNEQ(conn->uri->path, "/system")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected network URI path '%s', try network:///system"),
                           conn->uri->path);
898 899
            return VIR_DRV_OPEN_ERROR;
        }
900 901 902 903 904 905
    } else {
        if (STRNEQ(conn->uri->path, "/session")) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected network URI path '%s', try network:///session"),
                           conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
        }
    }

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

    return VIR_DRV_OPEN_SUCCESS;
}

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


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


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


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


941 942 943 944 945
/* networkKillDaemon:
 *
 * kill the specified pid/name, and wait a bit to make sure it's dead.
 */
static int
946 947 948
networkKillDaemon(pid_t pid,
                  const char *daemonName,
                  const char *networkName)
949
{
950 951
    size_t i;
    int ret = -1;
952 953 954 955 956 957 958
    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.
     */
959
    for (i = 0; i < 25; i++) {
960
        int signum = 0;
961
        if (i == 0) {
962
            signum = SIGTERM;
963
        } else if (i == 15) {
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
            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);
999
 cleanup:
1000 1001 1002
    return ret;
}

1003

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

G
Gene Czarcinski 已提交
1014 1015
    if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
        ipv6 = true;
1016 1017
    for (i = 0; i < ipdef->nhosts; i++) {
        virNetworkDHCPHostDefPtr host = &(ipdef->hosts[i]);
G
Gene Czarcinski 已提交
1018
        if (VIR_SOCKET_ADDR_VALID(&host->ip))
1019 1020
            if (dnsmasqAddDhcpHost(dctx, host->mac, &host->ip,
                                   host->name, host->id, ipv6) < 0)
1021
                return -1;
1022
    }
1023

G
Gene Czarcinski 已提交
1024 1025 1026
    return 0;
}

1027

G
Gene Czarcinski 已提交
1028 1029 1030 1031
static int
networkBuildDnsmasqHostsList(dnsmasqContext *dctx,
                             virNetworkDNSDefPtr dnsdef)
{
1032
    size_t i, j;
G
Gene Czarcinski 已提交
1033

1034 1035
    if (dnsdef) {
        for (i = 0; i < dnsdef->nhosts; i++) {
1036
            virNetworkDNSHostDefPtr host = &(dnsdef->hosts[i]);
1037
            if (VIR_SOCKET_ADDR_VALID(&host->ip)) {
1038
                for (j = 0; j < host->nnames; j++)
1039 1040
                    if (dnsmasqAddHost(dctx, &host->ip, host->names[j]) < 0)
                        return -1;
1041 1042
            }
        }
1043 1044
    }

1045
    return 0;
1046 1047 1048
}


1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085
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;
}


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

1104 1105
    *configstr = NULL;

1106
    /*
1107 1108 1109
     * All dnsmasq parameters are put into a configuration file, except the
     * command line --conf-file=parameter which specifies the location of
     * configuration file.
1110
     *
1111 1112
     * All dnsmasq conf-file parameters must be specified as "foo=bar"
     * as oppose to "--foo bar" which was acceptable on the command line.
1113
     */
1114 1115 1116 1117 1118 1119

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

1120
    /* create dnsmasq config file appropriate for this network */
1121 1122

    /* Don't forget to update networkxml2conftest :-) */
1123
    virBufferAsprintf(&configbuf,
1124 1125 1126 1127 1128 1129 1130
                      "##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"
1131
                      "strict-order\n",
1132
                      def->name);
1133

1134 1135 1136 1137 1138 1139
    /* if dns is disabled, set its listening port to 0, which
     * tells dnsmasq to not listen
     */
    if (!wantDNS)
        virBufferAddLit(&configbuf, "port=0\n");

1140
    if (wantDNS && def->dns.forwarders) {
1141 1142 1143 1144 1145 1146 1147 1148 1149
        /* 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;

1150 1151
        for (i = 0; i < def->dns.nfwds; i++) {
            virNetworkDNSForwarderPtr fwd = &def->dns.forwarders[i];
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161

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

1174 1175
    if (def->domain) {
        if (def->domainLocalOnly == VIR_TRISTATE_BOOL_YES) {
1176 1177
            virBufferAsprintf(&configbuf,
                              "local=/%s/\n",
1178
                              def->domain);
1179
        }
1180
        virBufferAsprintf(&configbuf,
1181 1182
                          "domain=%s\n"
                          "expand-hosts\n",
1183
                          def->domain);
1184
    }
1185

1186
    if (wantDNS &&
1187
        networkDnsmasqConfLocalPTRs(&configbuf, def) < 0)
1188 1189
        goto cleanup;

1190
    if (wantDNS && def->dns.forwardPlainNames == VIR_TRISTATE_BOOL_NO) {
1191 1192 1193 1194
        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)
1195
         */
1196
        virBufferAddLit(&configbuf, "local=//\n");
1197
    }
1198

1199
    if (pidfile)
1200
        virBufferAsprintf(&configbuf, "pid-file=%s\n", pidfile);
1201

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

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

            if (!ipaddr)
                goto cleanup;
1239

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

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

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

1288 1289 1290 1291 1292
    if (wantDNS) {
        for (i = 0; i < dns->ntxts; i++) {
            virBufferAsprintf(&configbuf, "txt-record=%s,%s\n",
                              dns->txts[i].name,
                              dns->txts[i].value);
1293
        }
1294

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

1319 1320 1321 1322 1323 1324 1325
            /* 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.
1326
             */
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
            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");
1347
        }
1348 1349
    }

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

    ipdef = ipv4def ? ipv4def : ipv6def;

    while (ipdef) {
1408 1409
        int prefix;

1410
        prefix = virNetworkIPDefPrefix(ipdef);
1411 1412 1413
        if (prefix < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("bridge '%s' has an invalid prefix"),
1414
                           def->bridge);
1415 1416
            goto cleanup;
        }
1417
        for (r = 0; r < ipdef->nranges; r++) {
1418 1419
            int thisRange;

1420 1421
            if (!(saddr = virSocketAddrFormat(&ipdef->ranges[r].start)) ||
                !(eaddr = virSocketAddrFormat(&ipdef->ranges[r].end)))
1422
                goto cleanup;
1423

1424
            virBufferAsprintf(&configbuf, "dhcp-range=%s,%s",
1425
                              saddr, eaddr);
1426
            if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
1427
                virBufferAsprintf(&configbuf, ",%d", prefix);
1428 1429
            virBufferAddLit(&configbuf, "\n");

1430
            VIR_FREE(saddr);
1431
            VIR_FREE(eaddr);
1432
            thisRange = virSocketAddrGetRange(&ipdef->ranges[r].start,
1433 1434
                                              &ipdef->ranges[r].end,
                                              &ipdef->address,
1435
                                              virNetworkIPDefPrefix(ipdef));
1436 1437 1438
            if (thisRange < 0)
                goto cleanup;
            nbleases += thisRange;
1439
        }
1440

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

G
Gene Czarcinski 已提交
1459 1460
        if (networkBuildDnsmasqDhcpHostsList(dctx, ipdef) < 0)
            goto cleanup;
1461

G
Gene Czarcinski 已提交
1462 1463
        /* Note: the following is IPv4 only */
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET)) {
1464
            if (ipdef->nranges || ipdef->nhosts) {
1465
                virBufferAddLit(&configbuf, "dhcp-no-override\n");
1466 1467
                virBufferAddLit(&configbuf, "dhcp-authoritative\n");
            }
1468

G
Gene Czarcinski 已提交
1469
            if (ipdef->tftproot) {
1470 1471
                virBufferAddLit(&configbuf, "enable-tftp\n");
                virBufferAsprintf(&configbuf, "tftp-root=%s\n", ipdef->tftproot);
G
Gene Czarcinski 已提交
1472
            }
1473

G
Gene Czarcinski 已提交
1474 1475 1476
            if (ipdef->bootfile) {
                if (VIR_SOCKET_ADDR_VALID(&ipdef->bootserver)) {
                    char *bootserver = virSocketAddrFormat(&ipdef->bootserver);
1477

1478
                    if (!bootserver)
G
Gene Czarcinski 已提交
1479
                        goto cleanup;
1480
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s%s%s\n",
1481
                                      ipdef->bootfile, ",,", bootserver);
G
Gene Czarcinski 已提交
1482 1483
                    VIR_FREE(bootserver);
                } else {
1484
                    virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
G
Gene Czarcinski 已提交
1485 1486 1487 1488 1489
                }
            }
        }
        ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
    }
1490

1491
    if (nbleases > 0)
1492
        virBufferAsprintf(&configbuf, "dhcp-lease-max=%d\n", nbleases);
1493

G
Gene Czarcinski 已提交
1494 1495
    /* this is done once per interface */
    if (networkBuildDnsmasqHostsList(dctx, dns) < 0)
1496
        goto cleanup;
G
Gene Czarcinski 已提交
1497 1498 1499 1500 1501 1502

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

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

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

1534 1535 1536
    if (!(*configstr = virBufferContentAndReset(&configbuf)))
        goto cleanup;

1537
    ret = 0;
G
Gene Czarcinski 已提交
1538

1539
 cleanup:
1540 1541
    VIR_FREE(saddr);
    VIR_FREE(eaddr);
1542
    virBufferFreeAndReset(&configbuf);
1543
    return ret;
1544 1545
}

1546

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

1563
    virNetworkObjSetDnsmasqPid(obj, -1);
1564

1565
    if (networkDnsmasqConfContents(obj, pidfile, &configstr,
1566
                                   dctx, dnsmasq_caps) < 0)
1567 1568 1569 1570 1571
        goto cleanup;
    if (!configstr)
        goto cleanup;

    /* construct the filename */
1572
    if (!(configfile = networkDnsmasqConfigFileName(driver, def->name)))
1573 1574 1575 1576 1577
        goto cleanup;

    /* Write the file */
    if (virFileWriteStr(configfile, configstr, 0600) < 0) {
        virReportSystemError(errno,
J
Ján Tomko 已提交
1578 1579
                             _("couldn't write dnsmasq config file '%s'"),
                             configfile);
1580 1581 1582
        goto cleanup;
    }

1583 1584
    /* This helper is used to create custom leases file for libvirt */
    if (!(leaseshelper_path = virFileFindResource("libvirt_leaseshelper",
1585
                                                  abs_topbuilddir "/src",
1586 1587 1588
                                                  LIBEXECDIR)))
        goto cleanup;

1589
    cmd = virCommandNew(dnsmasqCapsGetBinaryPath(dnsmasq_caps));
1590
    virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
1591 1592
    /* Libvirt gains full control of leases database */
    virCommandAddArgFormat(cmd, "--leasefile-ro");
1593
    virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
1594
    virCommandAddEnvPair(cmd, "VIR_BRIDGE_NAME", def->bridge);
1595

1596
    *cmdout = cmd;
1597
    ret = 0;
1598
 cleanup:
1599
    virObjectUnref(dnsmasq_caps);
1600 1601
    VIR_FREE(configfile);
    VIR_FREE(configstr);
1602
    VIR_FREE(leaseshelper_path);
1603 1604 1605
    return ret;
}

1606

1607
static int
1608
networkStartDhcpDaemon(virNetworkDriverStatePtr driver,
1609
                       virNetworkObjPtr obj)
1610
{
1611
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1612 1613 1614
    virNetworkIPDefPtr ipdef;
    size_t i;
    bool needDnsmasq = false;
1615 1616
    virCommandPtr cmd = NULL;
    char *pidfile = NULL;
1617
    pid_t dnsmasqPid;
1618
    int ret = -1;
1619
    dnsmasqContext *dctx = NULL;
1620

1621
    /* see if there are any IP addresses that need a dhcp server */
1622
    i = 0;
1623
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i))) {
1624
        i++;
1625 1626 1627 1628
        if (ipdef->nranges || ipdef->nhosts)
            needDnsmasq = true;
    }

1629 1630 1631 1632 1633 1634
    if (i == 0) {
        /* no IP addresses at all, so we don't need to run */
        ret = 0;
        goto cleanup;
    }

1635
    if (!needDnsmasq && def->dns.enable == VIR_TRISTATE_BOOL_NO) {
1636
        /* no DHCP services needed, and user disabled DNS service */
1637 1638 1639 1640
        ret = 0;
        goto cleanup;
    }

1641
    if (virFileMakePath(driver->pidDir) < 0) {
1642
        virReportSystemError(errno,
1643
                             _("cannot create directory %s"),
1644
                             driver->pidDir);
1645
        goto cleanup;
1646 1647
    }

1648
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, def->name)))
1649
        goto cleanup;
1650

1651
    if (virFileMakePath(driver->dnsmasqStateDir) < 0) {
1652
        virReportSystemError(errno,
1653
                             _("cannot create directory %s"),
1654
                             driver->dnsmasqStateDir);
1655 1656 1657
        goto cleanup;
    }

1658
    dctx = dnsmasqContextNew(def->name, driver->dnsmasqStateDir);
1659 1660 1661
    if (dctx == NULL)
        goto cleanup;

1662
    if (networkDnsmasqCapsRefresh(driver) < 0)
1663
        goto cleanup;
1664

1665
    ret = networkBuildDhcpDaemonCommandLine(driver, obj, &cmd, pidfile, dctx);
1666 1667 1668 1669 1670
    if (ret < 0)
        goto cleanup;

    ret = dnsmasqSave(dctx);
    if (ret < 0)
1671
        goto cleanup;
1672

G
Guido Günther 已提交
1673
    ret = virCommandRun(cmd, NULL);
1674
    if (ret < 0)
1675 1676 1677
        goto cleanup;

    /*
1678 1679 1680 1681 1682
     * 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
1683 1684
     */

1685
    ret = virPidFileRead(driver->pidDir, def->name, &dnsmasqPid);
1686
    if (ret < 0)
1687
        goto cleanup;
1688
    virNetworkObjSetDnsmasqPid(obj, dnsmasqPid);
1689

1690
    ret = 0;
1691
 cleanup:
1692
    VIR_FREE(pidfile);
1693
    virCommandFree(cmd);
1694
    dnsmasqContextFree(dctx);
1695 1696 1697
    return ret;
}

1698

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

G
Gene Czarcinski 已提交
1717
    /* if no IP addresses specified, nothing to do */
1718
    if (!virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0))
G
Gene Czarcinski 已提交
1719 1720
        return 0;

1721
    /* if there's no running dnsmasq, just start it */
1722 1723
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid <= 0 || (kill(dnsmasqPid, 0) < 0))
1724
        return networkStartDhcpDaemon(driver, obj);
1725

1726 1727
    VIR_INFO("Refreshing dnsmasq for network %s", def->bridge);
    if (!(dctx = dnsmasqContextNew(def->name,
1728
                                   driver->dnsmasqStateDir))) {
G
Gene Czarcinski 已提交
1729
        goto cleanup;
1730
    }
G
Gene Czarcinski 已提交
1731 1732 1733 1734 1735 1736

    /* 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;
1737
    for (i = 0;
1738
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
1739
         i++) {
G
Gene Czarcinski 已提交
1740 1741
        if (!ipv4def && (ipdef->nranges || ipdef->nhosts))
            ipv4def = ipdef;
1742 1743
    }

G
Gene Czarcinski 已提交
1744
    ipv6def = NULL;
1745
    for (i = 0;
1746
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i));
1747
         i++) {
G
Gene Czarcinski 已提交
1748 1749
        if (!ipv6def && (ipdef->nranges || ipdef->nhosts))
            ipv6def = ipdef;
1750 1751
    }

G
Gene Czarcinski 已提交
1752
    if (ipv4def && (networkBuildDnsmasqDhcpHostsList(dctx, ipv4def) < 0))
J
Ján Tomko 已提交
1753
        goto cleanup;
G
Gene Czarcinski 已提交
1754 1755

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

1758
    if (networkBuildDnsmasqHostsList(dctx, &def->dns) < 0)
J
Ján Tomko 已提交
1759
        goto cleanup;
1760 1761

    if ((ret = dnsmasqSave(dctx)) < 0)
1762
        goto cleanup;
1763

1764 1765
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    ret = kill(dnsmasqPid, SIGHUP);
1766
 cleanup:
1767 1768 1769 1770
    dnsmasqContextFree(dctx);
    return ret;
}

1771

1772 1773 1774 1775 1776 1777 1778 1779
/* 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
1780
networkRestartDhcpDaemon(virNetworkDriverStatePtr driver,
1781
                         virNetworkObjPtr obj)
1782
{
1783
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1784 1785
    pid_t dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);

1786
    /* if there is a running dnsmasq, kill it */
1787
    if (dnsmasqPid > 0) {
1788
        networkKillDaemon(dnsmasqPid, "dnsmasq", def->name);
1789
        virNetworkObjSetDnsmasqPid(obj, -1);
1790
    }
1791
    /* now start dnsmasq if it should be started */
1792
    return networkStartDhcpDaemon(driver, obj);
1793 1794
}

1795

G
Gene Czarcinski 已提交
1796 1797 1798 1799 1800 1801
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";

1802
static int
1803
networkRadvdConfContents(virNetworkObjPtr obj,
1804
                         char **configstr)
1805
{
1806
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
E
Eric Blake 已提交
1807
    virBuffer configbuf = VIR_BUFFER_INITIALIZER;
1808 1809
    int ret = -1;
    size_t i;
1810
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
1811
    bool v6present = false, dhcp6 = false;
1812 1813

    *configstr = NULL;
1814

G
Gene Czarcinski 已提交
1815
    /* Check if DHCPv6 is needed */
1816
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
G
Gene Czarcinski 已提交
1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
        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;
    }

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

    /* add a section for each IPv6 address in the config */
1844
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, i)); i++) {
1845 1846 1847
        int prefix;
        char *netaddr;

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

1865
    virBufferAddLit(&configbuf, "};\n");
1866

1867
    if (virBufferCheckError(&configbuf) < 0)
1868
        goto cleanup;
1869

1870 1871
    *configstr = virBufferContentAndReset(&configbuf);

1872
    ret = 0;
1873
 cleanup:
1874 1875 1876 1877
    virBufferFreeAndReset(&configbuf);
    return ret;
}

1878

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

    if (!configFile)
        configFile = &myConfigFile;

    *configFile = NULL;

1895
    if (networkRadvdConfContents(obj, &configStr) < 0)
1896 1897 1898 1899
        goto cleanup;

    if (!configStr) {
        ret = 0;
1900 1901 1902 1903
        goto cleanup;
    }

    /* construct the filename */
1904
    if (!(*configFile = networkRadvdConfigFileName(driver, def->name)))
1905 1906
        goto cleanup;
    /* write the file */
1907
    if (virFileWriteStr(*configFile, configStr, 0600) < 0) {
1908 1909
        virReportSystemError(errno,
                             _("couldn't write radvd config file '%s'"),
1910 1911 1912 1913 1914
                             *configFile);
        goto cleanup;
    }

    ret = 0;
1915
 cleanup:
1916 1917 1918 1919 1920
    VIR_FREE(configStr);
    VIR_FREE(myConfigFile);
    return ret;
}

1921

1922
static int
1923
networkStartRadvd(virNetworkDriverStatePtr driver,
1924
                  virNetworkObjPtr obj)
1925
{
1926
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
1927
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
1928
    pid_t radvdPid;
1929 1930 1931 1932 1933 1934
    char *pidfile = NULL;
    char *radvdpidbase = NULL;
    char *configfile = NULL;
    virCommandPtr cmd = NULL;
    int ret = -1;

1935
    virNetworkObjSetRadvdPid(obj, -1);
1936

G
Gene Czarcinski 已提交
1937
    /* Is dnsmasq handling RA? */
1938
    if (DNSMASQ_RA_SUPPORT(dnsmasq_caps)) {
G
Gene Czarcinski 已提交
1939 1940 1941 1942
        ret = 0;
        goto cleanup;
    }

1943
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
1944 1945 1946 1947 1948 1949 1950 1951 1952 1953
        /* 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);
1954 1955 1956
        goto cleanup;
    }

1957
    if (virFileMakePath(driver->pidDir) < 0) {
1958 1959
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1960
                             driver->pidDir);
1961 1962
        goto cleanup;
    }
1963
    if (virFileMakePath(driver->radvdStateDir) < 0) {
1964 1965
        virReportSystemError(errno,
                             _("cannot create directory %s"),
1966
                             driver->radvdStateDir);
1967 1968 1969 1970
        goto cleanup;
    }

    /* construct pidfile name */
1971
    if (!(radvdpidbase = networkRadvdPidfileBasename(def->name)))
1972
        goto cleanup;
1973
    if (!(pidfile = virPidFileBuildPath(driver->pidDir, radvdpidbase)))
1974 1975
        goto cleanup;

1976
    if (networkRadvdConfWrite(driver, obj, &configfile) < 0)
1977 1978
        goto cleanup;

1979 1980 1981 1982
    /* 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
1983
     * virPidFileRead() below will fail if we use them).
1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998
     * 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;

1999
    if (virPidFileRead(driver->pidDir, radvdpidbase, &radvdPid) < 0)
2000
        goto cleanup;
2001
    virNetworkObjSetRadvdPid(obj, radvdPid);
2002 2003

    ret = 0;
2004
 cleanup:
2005
    virObjectUnref(dnsmasq_caps);
2006 2007 2008 2009 2010 2011 2012
    virCommandFree(cmd);
    VIR_FREE(configfile);
    VIR_FREE(radvdpidbase);
    VIR_FREE(pidfile);
    return ret;
}

2013

2014
static int
2015
networkRefreshRadvd(virNetworkDriverStatePtr driver,
2016
                    virNetworkObjPtr obj)
2017
{
2018
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2019
    dnsmasqCapsPtr dnsmasq_caps = networkGetDnsmasqCaps(driver);
G
Gene Czarcinski 已提交
2020
    char *radvdpidbase;
2021
    pid_t radvdPid;
G
Gene Czarcinski 已提交
2022 2023

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

2041
    /* if there's no running radvd, just start it */
2042 2043
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid <= 0 || (kill(radvdPid, 0) < 0))
2044
        return networkStartRadvd(driver, obj);
2045

2046
    if (!virNetworkDefGetIPByIndex(def, AF_INET6, 0)) {
2047 2048 2049 2050
        /* no IPv6 addresses, so we don't need to run radvd */
        return 0;
    }

2051
    if (networkRadvdConfWrite(driver, obj, NULL) < 0)
2052 2053
        return -1;

2054
    return kill(radvdPid, SIGHUP);
2055 2056
}

2057

2058 2059
#if 0
/* currently unused, so it causes a build error unless we #if it out */
2060
static int
2061
networkRestartRadvd(virNetworkObjPtr obj)
2062
{
2063
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2064
    char *radvdpidbase;
2065
    pid_t radvdPid = virNeworkObjGetRadvdPid(obj);
2066 2067

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

2086

2087
static int
2088
networkRefreshDaemonsHelper(virNetworkObjPtr obj,
2089
                            void *opaque)
2090
{
2091
    virNetworkDefPtr def;
2092
    virNetworkDriverStatePtr driver = opaque;
2093

2094
    virObjectLock(obj);
2095
    def = virNetworkObjGetDef(obj);
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123
    if (virNetworkObjIsActive(obj)) {
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
        case VIR_NETWORK_FORWARD_OPEN:
            /* Only the three L3 network types that are configured by
             * libvirt will have a dnsmasq or radvd daemon associated
             * with them.  Here we send a SIGHUP to an existing
             * dnsmasq and/or radvd, or restart them if they've
             * disappeared.
             */
            networkRefreshDhcpDaemon(driver, obj);
            networkRefreshRadvd(driver, obj);
            break;

        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
        case VIR_NETWORK_FORWARD_HOSTDEV:
            break;

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, def->forward.type);
            goto cleanup;
        }
2124
    }
2125 2126

 cleanup:
2127
    virObjectUnlock(obj);
2128 2129 2130
    return 0;
}

2131

2132 2133 2134 2135
/* SIGHUP/restart any dnsmasq or radvd daemons.
 * This should be called when libvirtd is restarted.
 */
static void
2136
networkRefreshDaemons(virNetworkDriverStatePtr driver)
2137 2138
{
    VIR_INFO("Refreshing network daemons");
2139 2140
    virNetworkObjListForEach(driver->networks,
                             networkRefreshDaemonsHelper,
2141
                             driver);
2142
}
2143

2144

2145
static int
2146
networkReloadFirewallRulesHelper(virNetworkObjPtr obj,
2147 2148
                                 void *opaque ATTRIBUTE_UNUSED)
{
2149
    virNetworkDefPtr def;
2150

2151
    virObjectLock(obj);
2152
    def = virNetworkObjGetDef(obj);
2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178
    if (virNetworkObjIsActive(obj)) {
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
            /* Only three of the L3 network types that are configured by
             * libvirt need to have iptables rules reloaded. The 4th L3
             * network type, forward='open', doesn't need this because it
             * has no iptables rules.
             */
            networkRemoveFirewallRules(def);
            ignore_value(networkAddFirewallRules(def));
            break;

        case VIR_NETWORK_FORWARD_OPEN:
        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
        case VIR_NETWORK_FORWARD_HOSTDEV:
            break;

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, def->forward.type);
            goto cleanup;
2179 2180
        }
    }
2181 2182

 cleanup:
2183
    virObjectUnlock(obj);
2184
    return 0;
2185 2186
}

2187

2188
static void
2189
networkReloadFirewallRules(virNetworkDriverStatePtr driver)
2190
{
2191
    VIR_INFO("Reloading iptables rules");
2192 2193 2194
    virNetworkObjListForEach(driver->networks,
                             networkReloadFirewallRulesHelper,
                             NULL);
2195 2196
}

2197

2198
/* Enable IP Forwarding. Return 0 for success, -1 for failure. */
2199
static int
2200 2201
networkEnableIPForwarding(bool enableIPv4,
                          bool enableIPv6)
2202
{
2203
    int ret = 0;
2204 2205 2206 2207
#ifdef HAVE_SYSCTLBYNAME
    int enabled = 1;
    if (enableIPv4)
        ret = sysctlbyname("net.inet.ip.forwarding", NULL, 0,
J
Ján Tomko 已提交
2208
                           &enabled, sizeof(enabled));
2209 2210
    if (enableIPv6 && ret == 0)
        ret = sysctlbyname("net.inet6.ip6.forwarding", NULL, 0,
J
Ján Tomko 已提交
2211
                           &enabled, sizeof(enabled));
2212
#else
2213
    if (enableIPv4)
2214
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv4/ip_forward", "1\n", 0);
2215
    if (enableIPv6 && ret == 0)
2216 2217
        ret = virFileWriteStr(SYSCTL_PATH "/net/ipv6/conf/all/forwarding", "1\n", 0);

2218
#endif
2219
    return ret;
2220 2221
}

2222

2223
static int
2224
networkSetIPv6Sysctls(virNetworkObjPtr obj)
2225
{
2226
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2227 2228
    char *field = NULL;
    int ret = -1;
2229
    bool enableIPv6 = !!virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2230

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

2239 2240
    if (access(field, W_OK) < 0 && errno == ENOENT) {
        if (!enableIPv6)
2241
            VIR_DEBUG("ipv6 appears to already be disabled on %s",
2242
                      def->bridge);
2243 2244 2245
        ret = 0;
        goto cleanup;
    }
2246

2247 2248 2249
    if (virFileWriteStr(field, enableIPv6 ? "0" : "1", 0) < 0) {
        virReportSystemError(errno,
                             _("cannot write to %s to enable/disable IPv6 "
2250
                               "on bridge %s"), field, def->bridge);
2251
        goto cleanup;
2252
    }
2253
    VIR_FREE(field);
2254

2255 2256
    /* The rest of the ipv6 sysctl tunables should always be set the
     * same, whether or not we're using ipv6 on this bridge.
2257 2258 2259 2260 2261 2262
     */

    /* 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",
2263
                    def->bridge) < 0)
2264 2265
        goto cleanup;

2266
    if (virFileWriteStr(field, "0", 0) < 0) {
2267
        virReportSystemError(errno,
2268 2269 2270 2271 2272
                             _("cannot disable %s"), field);
        goto cleanup;
    }
    VIR_FREE(field);

2273 2274 2275 2276
    /* 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",
2277
                    def->bridge) < 0)
2278 2279
        goto cleanup;

2280
    if (virFileWriteStr(field, "0", 0) < 0) {
2281
        virReportSystemError(errno,
2282
                             _("cannot disable %s"), field);
2283 2284 2285 2286
        goto cleanup;
    }

    ret = 0;
2287
 cleanup:
2288 2289 2290 2291
    VIR_FREE(field);
    return ret;
}

2292

2293
/* add an IP address to a bridge */
2294
static int
2295
networkAddAddrToBridge(virNetworkObjPtr obj,
2296
                       virNetworkIPDefPtr ipdef)
2297
{
2298
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2299
    int prefix = virNetworkIPDefPrefix(ipdef);
2300 2301

    if (prefix < 0) {
2302 2303
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("bridge '%s' has an invalid netmask or IP address"),
2304
                       def->bridge);
2305 2306 2307
        return -1;
    }

2308
    if (virNetDevIPAddrAdd(def->bridge, &ipdef->address, NULL, prefix) < 0)
2309 2310 2311 2312 2313
        return -1;

    return 0;
}

2314 2315

static int
2316
networkStartHandleMACTableManagerMode(virNetworkObjPtr obj,
2317 2318
                                      const char *macTapIfName)
{
2319 2320
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    const char *brname = def->bridge;
2321 2322

    if (brname &&
2323
        def->macTableManager == VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT) {
2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336
        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;
}


2337 2338
/* add an IP (static) route to a bridge */
static int
2339
networkAddRouteToBridge(virNetworkObjPtr obj,
2340
                        virNetDevIPRoutePtr routedef)
2341
{
2342
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2343 2344 2345 2346
    int prefix = virNetDevIPRouteGetPrefix(routedef);
    unsigned int metric = virNetDevIPRouteGetMetric(routedef);
    virSocketAddrPtr addr = virNetDevIPRouteGetAddress(routedef);
    virSocketAddrPtr gateway = virNetDevIPRouteGetGateway(routedef);
2347 2348 2349 2350 2351

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

2356
    if (virNetDevIPRouteAdd(def->bridge, addr, prefix, gateway, metric) < 0)
2357
        return -1;
2358

2359 2360 2361
    return 0;
}

2362
static int
2363
networkWaitDadFinish(virNetworkObjPtr obj)
2364
{
2365
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2366
    virNetworkIPDefPtr ipdef;
2367 2368 2369 2370
    virSocketAddrPtr *addrs = NULL, addr = NULL;
    size_t naddrs = 0;
    int ret = -1;

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

2373
    while ((ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, naddrs))) {
2374 2375 2376 2377 2378
        addr = &ipdef->address;
        if (VIR_APPEND_ELEMENT_COPY(addrs, naddrs, addr) < 0)
            goto cleanup;
    }

2379
    ret = (naddrs == 0) ? 0 : virNetDevIPWaitDadFinish(addrs, naddrs);
2380 2381 2382 2383

 cleanup:
    VIR_FREE(addrs);
    VIR_DEBUG("Finished waiting for IPv6 DAD on network %s with status %d",
2384
              def->name, ret);
2385 2386 2387
    return ret;
}

2388

2389
static int
2390
networkStartNetworkVirtual(virNetworkDriverStatePtr driver,
2391
                           virNetworkObjPtr obj)
2392
{
2393
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2394
    size_t i;
2395
    bool v4present = false, v6present = false;
2396
    virErrorPtr save_err = NULL;
2397
    virNetworkIPDefPtr ipdef;
2398
    virNetDevIPRoutePtr routedef;
2399
    char *macTapIfName = NULL;
2400
    virMacMapPtr macmap;
M
Michal Privoznik 已提交
2401
    char *macMapFile = NULL;
2402
    int tapfd = -1;
2403
    pid_t dnsmasqPid;
2404

2405
    /* Check to see if any network IP collides with an existing route */
2406
    if (networkCheckRouteCollision(def) < 0)
2407 2408
        return -1;

2409
    /* Create and configure the bridge device */
2410
    if (!def->bridge) {
2411 2412 2413 2414 2415 2416 2417 2418 2419 2420
        /* 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"),
2421
                       def->name);
2422 2423
        return -1;
    }
2424
    if (virNetDevBridgeCreate(def->bridge) < 0)
2425 2426
        return -1;

2427
    if (def->mac_specified) {
2428 2429 2430 2431 2432 2433
        /* 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.
         */
2434
        macTapIfName = networkBridgeDummyNicName(def->bridge);
2435
        if (!macTapIfName)
2436
            goto err0;
2437
        /* Keep tun fd open and interface up to allow for IPv6 DAD to happen */
2438 2439
        if (virNetDevTapCreateInBridgePort(def->bridge,
                                           &macTapIfName, &def->mac,
2440
                                           NULL, NULL, &tapfd, 1, NULL, NULL,
2441
                                           NULL, def->mtu, NULL,
2442 2443 2444
                                           VIR_NETDEV_TAP_CREATE_USE_MAC_FOR_BRIDGE |
                                           VIR_NETDEV_TAP_CREATE_IFUP |
                                           VIR_NETDEV_TAP_CREATE_PERSIST) < 0) {
2445 2446 2447 2448 2449
            VIR_FREE(macTapIfName);
            goto err0;
        }
    }

2450
    if (!(macMapFile = virMacMapFileName(driver->dnsmasqStateDir,
2451
                                         def->bridge)) ||
2452
        !(macmap = virMacMapNew(macMapFile)))
M
Michal Privoznik 已提交
2453 2454
        goto err1;

2455 2456
    virNetworkObjSetMacMap(obj, macmap);

2457
    /* Set bridge options */
2458 2459 2460 2461

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

2465
    if (virNetDevBridgeSetSTP(def->bridge, def->stp ? true : false) < 0)
2466
        goto err1;
2467

2468 2469 2470
    /* Disable IPv6 on the bridge if there are no IPv6 addresses
     * defined, and set other IPv6 sysctl tunables appropriately.
     */
2471
    if (networkSetIPv6Sysctls(obj) < 0)
2472
        goto err1;
2473

2474
    /* Add "once per network" rules */
2475 2476
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN &&
        networkAddFirewallRules(def) < 0)
2477 2478
        goto err1;

2479
    for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i)); i++) {
2480
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
2481
            v4present = true;
2482
        if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
2483
            v6present = true;
2484

2485
        /* Add the IP address/netmask to the bridge */
2486
        if (networkAddAddrToBridge(obj, ipdef) < 0)
2487
            goto err2;
2488 2489
    }

2490
    if (networkStartHandleMACTableManagerMode(obj, macTapIfName) < 0)
2491 2492
        goto err2;

2493
    /* Bring up the bridge interface */
2494
    if (virNetDevSetOnline(def->bridge, 1) < 0)
2495
        goto err2;
2496

2497
    for (i = 0; i < def->nroutes; i++) {
2498 2499
        virSocketAddrPtr gateway = NULL;

2500
        routedef = def->routes[i];
2501
        gateway = virNetDevIPRouteGetGateway(routedef);
2502

2503 2504 2505
        /* Add the IP route to the bridge */
        /* ignore errors, error msg will be generated */
        /* but libvirt will not know and net-destroy will work. */
2506
        if (VIR_SOCKET_ADDR_VALID(gateway)) {
2507
            if (networkAddRouteToBridge(obj, routedef) < 0) {
2508 2509 2510 2511 2512 2513
                /* an error occurred adding the static route */
                continue; /* for now, do nothing */
            }
        }
    }

2514
    /* If forward.type != NONE, turn on global IP forwarding */
2515
    if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2516
        if (v6present && !virNetDevIPCheckIPv6Forwarding())
2517 2518 2519 2520 2521 2522 2523
            goto err3; /* Precise error message already provided */

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

2526

2527
    /* start dnsmasq if there are any IP addresses (v4 or v6) */
2528
    if ((v4present || v6present) &&
2529
        networkStartDhcpDaemon(driver, obj) < 0)
2530
        goto err3;
2531

2532
    /* start radvd if there are any ipv6 addresses */
2533
    if (v6present && networkStartRadvd(driver, obj) < 0)
2534 2535
        goto err4;

2536 2537 2538
    /* dnsmasq does not wait for DAD to complete before daemonizing,
     * so we need to wait for it ourselves.
     */
2539
    if (v6present && networkWaitDadFinish(obj) < 0)
2540 2541 2542 2543
        goto err4;

    /* DAD has finished, dnsmasq is now bound to the
     * bridge's IPv6 address, so we can set the dummy tun down.
2544 2545 2546 2547 2548 2549 2550
     */
    if (tapfd >= 0) {
        if (virNetDevSetOnline(macTapIfName, false) < 0)
            goto err4;
        VIR_FORCE_CLOSE(tapfd);
    }

2551
    if (virNetDevBandwidthSet(def->bridge, def->bandwidth, true, true) < 0)
2552 2553
        goto err5;

2554
    VIR_FREE(macTapIfName);
M
Michal Privoznik 已提交
2555
    VIR_FREE(macMapFile);
2556 2557 2558

    return 0;

2559
 err5:
2560 2561
    if (def->bandwidth)
       virNetDevBandwidthClear(def->bridge);
2562

2563 2564 2565 2566
 err4:
    if (!save_err)
        save_err = virSaveLastError();

2567 2568 2569 2570
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0) {
        kill(dnsmasqPid, SIGTERM);
        virNetworkObjSetDnsmasqPid(obj, -1);
2571 2572
    }

2573 2574 2575
 err3:
    if (!save_err)
        save_err = virSaveLastError();
2576
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2577

2578 2579 2580
 err2:
    if (!save_err)
        save_err = virSaveLastError();
2581 2582
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2583 2584

 err1:
2585 2586 2587
    if (!save_err)
        save_err = virSaveLastError();

H
Hu Tao 已提交
2588
    if (macTapIfName) {
2589
        VIR_FORCE_CLOSE(tapfd);
2590
        ignore_value(virNetDevTapDelete(macTapIfName, NULL));
H
Hu Tao 已提交
2591 2592
        VIR_FREE(macTapIfName);
    }
M
Michal Privoznik 已提交
2593
    VIR_FREE(macMapFile);
2594 2595

 err0:
2596 2597
    if (!save_err)
        save_err = virSaveLastError();
2598
    ignore_value(virNetDevBridgeDelete(def->bridge));
2599

2600 2601 2602 2603
    if (save_err) {
        virSetError(save_err);
        virFreeError(save_err);
    }
2604
    /* coverity[leaked_handle] - 'tapfd' is not leaked */
2605 2606 2607
    return -1;
}

2608

2609 2610
static int
networkShutdownNetworkVirtual(virNetworkDriverStatePtr driver,
2611
                              virNetworkObjPtr obj)
2612
{
2613
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2614 2615 2616
    pid_t radvdPid;
    pid_t dnsmasqPid;

2617 2618
    if (def->bandwidth)
        virNetDevBandwidthClear(def->bridge);
2619

2620
    virNetworkObjUnrefMacMap(obj);
M
Michal Privoznik 已提交
2621

2622 2623
    radvdPid = virNetworkObjGetRadvdPid(obj);
    if (radvdPid > 0) {
2624 2625
        char *radvdpidbase;

2626
        kill(radvdPid, SIGTERM);
2627
        /* attempt to delete the pidfile we created */
2628
        if ((radvdpidbase = networkRadvdPidfileBasename(def->name))) {
2629
            virPidFileDelete(driver->pidDir, radvdpidbase);
2630 2631 2632 2633
            VIR_FREE(radvdpidbase);
        }
    }

2634 2635 2636
    dnsmasqPid = virNetworkObjGetDnsmasqPid(obj);
    if (dnsmasqPid > 0)
        kill(dnsmasqPid, SIGTERM);
2637

2638 2639
    if (def->mac_specified) {
        char *macTapIfName = networkBridgeDummyNicName(def->bridge);
2640
        if (macTapIfName) {
2641
            ignore_value(virNetDevTapDelete(macTapIfName, NULL));
2642 2643 2644 2645
            VIR_FREE(macTapIfName);
        }
    }

2646
    ignore_value(virNetDevSetOnline(def->bridge, 0));
2647

2648 2649
    if (def->forward.type != VIR_NETWORK_FORWARD_OPEN)
        networkRemoveFirewallRules(def);
2650

2651
    ignore_value(virNetDevBridgeDelete(def->bridge));
2652

2653
    /* See if its still alive and really really kill it */
2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664
    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);
2665

2666 2667 2668
    return 0;
}

2669

2670
static int
2671
networkStartNetworkBridge(virNetworkObjPtr obj)
2672 2673 2674 2675 2676
{
    /* 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.
     */
2677
    return networkStartHandleMACTableManagerMode(obj, NULL);
2678 2679
}

2680

2681
static int
2682
networkShutdownNetworkBridge(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2683 2684 2685 2686 2687 2688 2689 2690 2691
{
    /* 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;
}


2692 2693 2694 2695 2696 2697 2698 2699 2700
/* 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;
2701
    unsigned int maxVirtFns = 0;
2702 2703 2704 2705 2706 2707
    char **vfNames = NULL;
    virPCIDeviceAddressPtr *virtFns;

    int ret = -1;
    size_t i;

2708 2709 2710
    if (netdef->forward.npfs == 0 || netdef->forward.nifs > 0)
       return 0;

2711 2712
    if ((virNetDevGetVirtualFunctions(netdef->forward.pfs->dev, &vfNames,
                                      &virtFns, &numVirtFns, &maxVirtFns)) < 0) {
2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727
        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];

2728
        switch ((virNetworkForwardType) netdef->forward.type) {
2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758
        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:
2759
        case VIR_NETWORK_FORWARD_OPEN:
2760 2761
            /* by definition these will never be encountered here */
            break;
2762 2763 2764 2765 2766

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
            goto cleanup;
2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
        }
    }

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


2804
static int
2805
networkStartNetworkExternal(virNetworkObjPtr obj)
2806 2807
{
    /* put anything here that needs to be done each time a network of
2808
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On
2809 2810 2811
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
2812
    return networkCreateInterfacePool(virNetworkObjGetDef(obj));
2813 2814
}

2815 2816

static int
2817
networkShutdownNetworkExternal(virNetworkObjPtr obj ATTRIBUTE_UNUSED)
2818 2819
{
    /* put anything here that needs to be done each time a network of
2820
     * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On
2821 2822 2823 2824 2825 2826
     * failure, undo anything you've done, and return -1. On success
     * return 0.
     */
    return 0;
}

2827

2828
static int
2829
networkStartNetwork(virNetworkDriverStatePtr driver,
2830
                    virNetworkObjPtr obj)
2831
{
2832
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2833 2834
    int ret = -1;

2835
    VIR_DEBUG("driver=%p, network=%p", driver, obj);
2836

2837
    if (virNetworkObjIsActive(obj)) {
2838 2839
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("network is already active"));
2840
        return ret;
2841 2842
    }

2843 2844 2845
    VIR_DEBUG("Beginning network startup process");

    VIR_DEBUG("Setting current network def as transient");
2846
    if (virNetworkObjSetDefTransient(obj, true) < 0)
2847
        goto cleanup;
2848

2849 2850
    /* Run an early hook to set-up missing devices.
     * If the script raised an error abort the launch. */
2851
    if (networkRunHook(obj, NULL, NULL,
2852 2853 2854 2855
                       VIR_HOOK_NETWORK_OP_START,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2856
    switch ((virNetworkForwardType) def->forward.type) {
2857 2858 2859 2860

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2861
    case VIR_NETWORK_FORWARD_OPEN:
2862
        if (networkStartNetworkVirtual(driver, obj) < 0)
2863
            goto cleanup;
2864 2865 2866
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2867
        if (def->bridge) {
2868
            if (networkStartNetworkBridge(obj) < 0)
2869 2870 2871 2872 2873 2874 2875
                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).
         */
2876 2877
        ATTRIBUTE_FALLTHROUGH;

2878 2879 2880
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2881
    case VIR_NETWORK_FORWARD_HOSTDEV:
2882
        if (networkStartNetworkExternal(obj) < 0)
2883
            goto cleanup;
2884
        break;
2885 2886 2887 2888 2889

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

2892
    /* finally we can call the 'started' hook script if any */
2893
    if (networkRunHook(obj, NULL, NULL,
2894 2895 2896 2897
                       VIR_HOOK_NETWORK_OP_STARTED,
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

2898 2899 2900
    /* Persist the live configuration now that anything autogenerated
     * is setup.
     */
2901
    VIR_DEBUG("Writing network status to disk");
2902
    if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0)
2903
        goto cleanup;
2904

2905
    virNetworkObjSetActive(obj, true);
2906
    VIR_INFO("Network '%s' started up", def->name);
2907
    ret = 0;
2908

2909
 cleanup:
2910
    if (ret < 0) {
2911
        virNetworkObjUnsetDefTransient(obj);
2912 2913
        virErrorPtr save_err = virSaveLastError();
        int save_errno = errno;
2914
        networkShutdownNetwork(driver, obj);
2915 2916 2917 2918 2919 2920 2921
        virSetError(save_err);
        virFreeError(save_err);
        errno = save_errno;
    }
    return ret;
}

2922

2923 2924
static int
networkShutdownNetwork(virNetworkDriverStatePtr driver,
2925
                       virNetworkObjPtr obj)
2926
{
2927
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
2928 2929 2930
    int ret = 0;
    char *stateFile;

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

2933
    if (!virNetworkObjIsActive(obj))
2934 2935
        return 0;

2936
    stateFile = virNetworkConfigFile(driver->stateDir, def->name);
2937 2938 2939 2940 2941 2942
    if (!stateFile)
        return -1;

    unlink(stateFile);
    VIR_FREE(stateFile);

2943
    switch ((virNetworkForwardType) def->forward.type) {
2944 2945 2946 2947

    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
2948
    case VIR_NETWORK_FORWARD_OPEN:
2949
        ret = networkShutdownNetworkVirtual(driver, obj);
2950 2951 2952
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
2953
        if (def->bridge) {
2954
            ret = networkShutdownNetworkBridge(obj);
2955 2956 2957 2958 2959 2960
            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).
         */
2961 2962
        ATTRIBUTE_FALLTHROUGH;

2963 2964 2965
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
2966
    case VIR_NETWORK_FORWARD_HOSTDEV:
2967
        ret = networkShutdownNetworkExternal(obj);
2968
        break;
2969 2970 2971 2972 2973

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

2976
    /* now that we know it's stopped call the hook if present */
2977
    networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_STOPPED,
2978 2979
                   VIR_HOOK_SUBOP_END);

2980
    virNetworkObjSetActive(obj, false);
2981
    virNetworkObjUnsetDefTransient(obj);
2982
    return ret;
2983 2984 2985
}


2986 2987 2988
static virNetworkPtr
networkLookupByUUID(virConnectPtr conn,
                    const unsigned char *uuid)
2989
{
2990
    virNetworkDriverStatePtr driver = networkGetDriver();
2991
    virNetworkObjPtr obj;
2992
    virNetworkDefPtr def;
2993
    virNetworkPtr net = NULL;
2994

2995 2996
    obj = virNetworkObjFindByUUID(driver->networks, uuid);
    if (!obj) {
2997 2998
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
2999
        virReportError(VIR_ERR_NO_NETWORK,
3000 3001
                       _("no network with matching uuid '%s'"),
                       uuidstr);
3002
        goto cleanup;
3003
    }
3004
    def = virNetworkObjGetDef(obj);
3005

3006
    if (virNetworkLookupByUUIDEnsureACL(conn, def) < 0)
3007 3008
        goto cleanup;

3009
    net = virGetNetwork(conn, def->name, def->uuid);
3010

3011
 cleanup:
3012 3013
    virNetworkObjEndAPI(&obj);
    return net;
3014 3015
}

3016 3017 3018 3019

static virNetworkPtr
networkLookupByName(virConnectPtr conn,
                    const char *name)
3020
{
3021
    virNetworkDriverStatePtr driver = networkGetDriver();
3022
    virNetworkObjPtr obj;
3023
    virNetworkDefPtr def;
3024
    virNetworkPtr net = NULL;
3025

3026 3027
    obj = virNetworkObjFindByName(driver->networks, name);
    if (!obj) {
3028 3029
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"), name);
3030
        goto cleanup;
3031
    }
3032
    def = virNetworkObjGetDef(obj);
3033

3034
    if (virNetworkLookupByNameEnsureACL(conn, def) < 0)
3035 3036
        goto cleanup;

3037
    net = virGetNetwork(conn, def->name, def->uuid);
3038

3039
 cleanup:
3040 3041
    virNetworkObjEndAPI(&obj);
    return net;
3042 3043
}

3044 3045 3046

static int
networkConnectNumOfNetworks(virConnectPtr conn)
3047
{
3048
    virNetworkDriverStatePtr driver = networkGetDriver();
3049
    int nactive;
3050

3051 3052 3053
    if (virConnectNumOfNetworksEnsureACL(conn) < 0)
        return -1;

3054 3055 3056 3057
    nactive = virNetworkObjListNumOfNetworks(driver->networks,
                                             true,
                                             virConnectNumOfNetworksCheckACL,
                                             conn);
3058

3059 3060 3061
    return nactive;
}

3062 3063 3064 3065

static int
networkConnectListNetworks(virConnectPtr conn,
                           char **const names,
3066
                           int maxnames)
3067 3068
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3069
    int got = 0;
3070

3071 3072 3073
    if (virConnectListNetworksEnsureACL(conn) < 0)
        return -1;

3074
    got = virNetworkObjListGetNames(driver->networks,
3075
                                    true, names, maxnames,
3076 3077
                                    virConnectListNetworksCheckACL,
                                    conn);
3078

3079 3080 3081
    return got;
}

3082 3083 3084

static int
networkConnectNumOfDefinedNetworks(virConnectPtr conn)
3085
{
3086
    virNetworkDriverStatePtr driver = networkGetDriver();
3087
    int ninactive = 0;
3088

3089 3090 3091
    if (virConnectNumOfDefinedNetworksEnsureACL(conn) < 0)
        return -1;

3092 3093 3094 3095
    ninactive = virNetworkObjListNumOfNetworks(driver->networks,
                                               false,
                                               virConnectNumOfDefinedNetworksCheckACL,
                                               conn);
3096

3097 3098 3099
    return ninactive;
}

3100 3101 3102 3103

static int
networkConnectListDefinedNetworks(virConnectPtr conn,
                                  char **const names,
3104
                                  int maxnames)
3105 3106
{
    virNetworkDriverStatePtr driver = networkGetDriver();
3107
    int got = 0;
3108

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

3112
    got = virNetworkObjListGetNames(driver->networks,
3113
                                    false, names, maxnames,
3114 3115
                                    virConnectListDefinedNetworksCheckACL,
                                    conn);
3116 3117 3118
    return got;
}

3119

3120
static int
3121 3122 3123
networkConnectListAllNetworks(virConnectPtr conn,
                              virNetworkPtr **nets,
                              unsigned int flags)
3124
{
3125
    virNetworkDriverStatePtr driver = networkGetDriver();
3126 3127 3128 3129
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1);

3130 3131 3132
    if (virConnectListAllNetworksEnsureACL(conn) < 0)
        goto cleanup;

3133
    ret = virNetworkObjListExport(conn, driver->networks, nets,
3134 3135
                                  virConnectListAllNetworksCheckACL,
                                  flags);
3136

3137
 cleanup:
3138 3139
    return ret;
}
3140

3141

3142 3143 3144 3145 3146 3147 3148 3149
static int
networkConnectNetworkEventRegisterAny(virConnectPtr conn,
                                      virNetworkPtr net,
                                      int eventID,
                                      virConnectNetworkEventGenericCallback callback,
                                      void *opaque,
                                      virFreeCallback freecb)
{
3150
    virNetworkDriverStatePtr driver = networkGetDriver();
3151 3152 3153 3154 3155 3156
    int ret = -1;

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

    if (virNetworkEventStateRegisterID(conn, driver->networkEventState,
3157
                                       net, eventID, callback,
3158 3159 3160
                                       opaque, freecb, &ret) < 0)
        ret = -1;

3161
 cleanup:
3162 3163 3164
    return ret;
}

3165

3166 3167 3168 3169
static int
networkConnectNetworkEventDeregisterAny(virConnectPtr conn,
                                        int callbackID)
{
3170
    virNetworkDriverStatePtr driver = networkGetDriver();
3171 3172 3173 3174 3175
    int ret = -1;

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

3176 3177
    if (virObjectEventStateDeregisterID(conn,
                                        driver->networkEventState,
3178
                                        callbackID, true) < 0)
3179 3180 3181
        goto cleanup;

    ret = 0;
3182

3183
 cleanup:
3184 3185 3186
    return ret;
}

3187 3188 3189

static int
networkIsActive(virNetworkPtr net)
3190 3191 3192 3193
{
    virNetworkObjPtr obj;
    int ret = -1;

3194 3195
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3196

3197
    if (virNetworkIsActiveEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3198 3199
        goto cleanup;

3200 3201
    ret = virNetworkObjIsActive(obj);

3202
 cleanup:
3203
    virNetworkObjEndAPI(&obj);
3204 3205 3206
    return ret;
}

3207 3208 3209

static int
networkIsPersistent(virNetworkPtr net)
3210 3211 3212 3213
{
    virNetworkObjPtr obj;
    int ret = -1;

3214 3215
    if (!(obj = networkObjFromNetwork(net)))
        return ret;
3216

3217
    if (virNetworkIsPersistentEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
3218 3219
        goto cleanup;

3220
    ret = virNetworkObjIsPersistent(obj);
3221

3222
 cleanup:
3223
    virNetworkObjEndAPI(&obj);
3224 3225 3226 3227
    return ret;
}


3228 3229
/*
 * networkFindUnusedBridgeName() - try to find a bridge name that is
3230 3231 3232
 * 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.
3233 3234 3235 3236 3237 3238 3239 3240
 */
static int
networkFindUnusedBridgeName(virNetworkObjListPtr nets,
                            virNetworkDefPtr def)
{

    int ret = -1, id = 0;
    char *newname = NULL;
3241 3242 3243 3244 3245
    const char *templ = "virbr%d";
    const char *p;

    if (def->bridge &&
        (p = strchr(def->bridge, '%')) == strrchr(def->bridge, '%') &&
3246
        p && p[1] == 'd')
3247
        templ = def->bridge;
3248 3249 3250 3251

    do {
        if (virAsprintf(&newname, templ, id) < 0)
            goto cleanup;
3252 3253 3254 3255 3256
        /* 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).
         */
3257
        if (!(virNetworkObjBridgeInUse(nets, newname, def->name) ||
3258
              virNetDevExists(newname) == 1)) {
3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291
            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")) {
3292
        if (virNetworkObjBridgeInUse(nets, def->bridge, def->name)) {
3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309
            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;
}


3310
static int
3311
networkValidate(virNetworkDriverStatePtr driver,
3312
                virNetworkDefPtr def)
3313
{
3314
    size_t i, j;
3315 3316
    bool vlanUsed, vlanAllowed, badVlanUse = false;
    virPortGroupDefPtr defaultPortGroup = NULL;
3317
    virNetworkIPDefPtr ipdef;
G
Gene Czarcinski 已提交
3318
    bool ipv4def = false, ipv6def = false;
3319
    bool bandwidthAllowed = true;
3320
    bool usesInterface = false, usesAddress = false;
3321

3322 3323 3324
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        return -1;

3325 3326 3327
    /* Only the three L3 network types that are configured by libvirt
     * need to have a bridge device name / mac address provided
     */
3328 3329 3330 3331 3332
    switch ((virNetworkForwardType) def->forward.type) {
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
    case VIR_NETWORK_FORWARD_OPEN:
3333 3334 3335 3336
        /* 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)
3337 3338 3339
            return -1;

        virNetworkSetBridgeMacAddr(def);
3340 3341 3342 3343 3344 3345 3346
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
    case VIR_NETWORK_FORWARD_HOSTDEV:
3347
        /* They are also the only types that currently support setting
3348 3349
         * a MAC or IP address for the host-side device (bridge), DNS
         * configuration, or network-wide bandwidth limits.
3350
         */
3351 3352 3353 3354 3355 3356 3357 3358
        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;
        }
3359
        if (virNetworkDefGetIPByIndex(def, AF_UNSPEC, 0)) {
3360 3361 3362 3363
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <ip> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3364
                           virNetworkForwardTypeToString(def->forward.type));
3365 3366
            return -1;
        }
3367
        if (def->dns.ntxts || def->dns.nhosts || def->dns.nsrvs) {
3368 3369 3370 3371
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <dns> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3372
                           virNetworkForwardTypeToString(def->forward.type));
3373 3374 3375 3376 3377 3378 3379
            return -1;
        }
        if (def->domain) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported <domain> element in network %s "
                             "with forward mode='%s'"),
                           def->name,
3380
                           virNetworkForwardTypeToString(def->forward.type));
3381 3382
            return -1;
        }
3383 3384 3385 3386 3387 3388 3389 3390
        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;
        }
3391
        bandwidthAllowed = false;
3392 3393 3394 3395 3396 3397
        break;

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

3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412
    /* 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++) {
3413 3414 3415
        virNetworkForwardIfDefPtr iface = &def->forward.ifs[i];
        char *sysfs_path = NULL;

3416
        switch ((virNetworkForwardHostdevDeviceType)iface->type) {
3417 3418
        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV:
            usesInterface = true;
3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429

            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;
            }
3430
            break;
3431 3432

        case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI: {
3433
            usesAddress = true;
3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458

            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);
3459
            break;
3460 3461
        }

3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474
        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 已提交
3475 3476 3477
    /* We only support dhcp on one IPv4 address and
     * on one IPv6 address per defined network
     */
3478
    for (i = 0;
3479
         (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
3480
         i++) {
G
Gene Czarcinski 已提交
3481 3482 3483 3484 3485
        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 -- "
3486 3487
                                 "dhcp is supported only for a "
                                 "single IPv4 address on each network"));
G
Gene Czarcinski 已提交
3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504
                    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;
                }
3505 3506 3507
            }
        }
    }
3508 3509 3510 3511 3512 3513

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

3514 3515 3516
    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 已提交
3517 3518
                    def->virtPortProfile &&
                    def->virtPortProfile->virtPortType
3519
                    == VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH));
3520 3521

    vlanUsed = def->vlan.nTags > 0;
3522 3523
    for (i = 0; i < def->nPortGroups; i++) {
        if (vlanUsed || def->portGroups[i].vlan.nTags > 0) {
3524 3525 3526 3527 3528
            /* 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.
             */
3529
            if (def->portGroups[i].virtPortProfile) {
3530
                if (def->forward.type != VIR_NETWORK_FORWARD_BRIDGE ||
3531
                    def->portGroups[i].virtPortProfile->virtPortType
3532 3533 3534 3535 3536 3537 3538
                    != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    badVlanUse = true;
                }
            } else if (!vlanAllowed) {
                /* virtualport taken from base network definition */
                badVlanUse = true;
            }
3539
        }
3540
        if (def->portGroups[i].isDefault) {
3541 3542 3543 3544 3545
            if (defaultPortGroup) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("network '%s' has multiple default "
                                 "<portgroup> elements (%s and %s), "
                                 "but only one default is allowed"),
3546
                               def->name, defaultPortGroup->name,
3547
                               def->portGroups[i].name);
3548
                return -1;
3549
            }
3550
            defaultPortGroup = &def->portGroups[i];
3551
        }
3552 3553 3554 3555 3556 3557 3558 3559 3560
        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;
            }
        }
3561 3562 3563 3564 3565 3566 3567 3568
        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;
        }
3569
    }
3570 3571 3572 3573 3574 3575 3576
    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.
         */
3577 3578 3579 3580 3581 3582
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("<vlan> element specified for network %s, "
                         "whose type doesn't support vlan configuration"),
                       def->name);
        return -1;
    }
3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596

    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;
            }
        }
    }
3597 3598 3599
    return 0;
}

3600 3601 3602 3603

static virNetworkPtr
networkCreateXML(virConnectPtr conn,
                 const char *xml)
3604
{
3605
    virNetworkDriverStatePtr driver = networkGetDriver();
3606
    virNetworkDefPtr newDef;
3607
    virNetworkObjPtr obj = NULL;
3608
    virNetworkDefPtr def;
3609
    virNetworkPtr net = NULL;
3610
    virObjectEventPtr event = NULL;
3611

3612
    if (!(newDef = virNetworkDefParseString(xml)))
3613
        goto cleanup;
3614

3615
    if (virNetworkCreateXMLEnsureACL(conn, newDef) < 0)
3616 3617
        goto cleanup;

3618
    if (networkValidate(driver, newDef) < 0)
J
Ján Tomko 已提交
3619
        goto cleanup;
3620

3621 3622 3623
    /* 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.
3624
     */
3625
    if (!(obj = virNetworkObjAssignDef(driver->networks, newDef,
3626 3627
                                       VIR_NETWORK_OBJ_LIST_ADD_LIVE |
                                       VIR_NETWORK_OBJ_LIST_ADD_CHECK_LIVE)))
3628
        goto cleanup;
3629 3630
    newDef = NULL;
    def = virNetworkObjGetDef(obj);
3631

3632 3633
    if (networkStartNetwork(driver, obj) < 0) {
        virNetworkObjRemoveInactive(driver->networks, obj);
3634
        goto cleanup;
3635 3636
    }

3637 3638
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3639 3640
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3641

3642 3643
    VIR_INFO("Creating network '%s'", def->name);
    net = virGetNetwork(conn, def->name, def->uuid);
3644

3645
 cleanup:
3646
    virNetworkDefFree(newDef);
3647
    virObjectEventStateQueue(driver->networkEventState, event);
3648 3649
    virNetworkObjEndAPI(&obj);
    return net;
3650 3651
}

3652 3653 3654 3655

static virNetworkPtr
networkDefineXML(virConnectPtr conn,
                 const char *xml)
3656
{
3657
    virNetworkDriverStatePtr driver = networkGetDriver();
3658
    virNetworkDefPtr def = NULL;
3659
    bool freeDef = true;
3660 3661
    virNetworkObjPtr obj = NULL;
    virNetworkPtr net = NULL;
3662
    virObjectEventPtr event = NULL;
3663

3664
    if (!(def = virNetworkDefParseString(xml)))
3665
        goto cleanup;
3666

3667 3668 3669
    if (virNetworkDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

3670
    if (networkValidate(driver, def) < 0)
J
Ján Tomko 已提交
3671
        goto cleanup;
3672

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

3676
    /* def was assigned to network object */
3677
    freeDef = false;
3678 3679

    if (virNetworkSaveConfig(driver->networkConfigDir, def) < 0) {
3680 3681
        if (!virNetworkObjIsActive(obj)) {
            virNetworkObjRemoveInactive(driver->networks, obj);
3682 3683
            goto cleanup;
        }
3684 3685 3686 3687
        /* if network was active already, just undo new persistent
         * definition by making it transient.
         * XXX - this isn't necessarily the correct thing to do.
         */
3688
        virNetworkObjUpdateAssignDef(obj, NULL, false);
3689 3690 3691
        goto cleanup;
    }

3692
    event = virNetworkEventLifecycleNew(def->name, def->uuid,
3693 3694
                                        VIR_NETWORK_EVENT_DEFINED,
                                        0);
3695

3696
    VIR_INFO("Defining network '%s'", def->name);
3697
    net = virGetNetwork(conn, def->name, def->uuid);
3698

3699
 cleanup:
3700
    virObjectEventStateQueue(driver->networkEventState, event);
3701
    if (freeDef)
J
Ján Tomko 已提交
3702
        virNetworkDefFree(def);
3703 3704
    virNetworkObjEndAPI(&obj);
    return net;
3705 3706
}

3707

3708
static int
3709 3710
networkUndefine(virNetworkPtr net)
{
3711
    virNetworkDriverStatePtr driver = networkGetDriver();
3712
    virNetworkObjPtr obj;
3713
    virNetworkDefPtr def;
3714
    int ret = -1;
3715
    bool active = false;
3716
    virObjectEventPtr event = NULL;
3717

3718
    if (!(obj = networkObjFromNetwork(net)))
3719
        goto cleanup;
3720
    def = virNetworkObjGetDef(obj);
3721

3722
    if (virNetworkUndefineEnsureACL(net->conn, def) < 0)
3723 3724
        goto cleanup;

3725
    if (virNetworkObjIsActive(obj))
3726
        active = true;
3727

3728
    if (!virNetworkObjIsPersistent(obj)) {
3729 3730 3731 3732 3733
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("can't undefine transient network"));
        goto cleanup;
    }

3734
    /* remove autostart link */
3735 3736
    if (virNetworkObjDeleteConfig(driver->networkConfigDir,
                                  driver->networkAutostartDir,
3737
                                  obj) < 0)
3738
        goto cleanup;
3739

3740 3741
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3742 3743
                                        VIR_NETWORK_EVENT_UNDEFINED,
                                        0);
3744

3745
    VIR_INFO("Undefining network '%s'", def->name);
3746
    if (!active) {
3747
        if (networkRemoveInactive(driver, obj) < 0)
3748
            goto cleanup;
3749 3750 3751 3752 3753
    } else {

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

3757
    ret = 0;
3758

3759
 cleanup:
3760
    virObjectEventStateQueue(driver->networkEventState, event);
3761
    virNetworkObjEndAPI(&obj);
3762
    return ret;
3763 3764
}

3765

3766 3767 3768 3769 3770 3771 3772 3773
static int
networkUpdate(virNetworkPtr net,
              unsigned int command,
              unsigned int section,
              int parentIndex,
              const char *xml,
              unsigned int flags)
{
3774
    virNetworkDriverStatePtr driver = networkGetDriver();
3775
    virNetworkObjPtr obj = NULL;
3776
    virNetworkDefPtr def;
3777 3778
    int isActive, ret = -1;
    size_t i;
3779
    virNetworkIPDefPtr ipdef;
3780
    bool oldDhcpActive = false;
3781
    bool needFirewallRefresh = false;
3782

3783 3784 3785 3786 3787

    virCheckFlags(VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG,
                  -1);

3788
    if (!(obj = networkObjFromNetwork(net)))
3789
        goto cleanup;
3790
    def = virNetworkObjGetDef(obj);
3791

3792
    if (virNetworkUpdateEnsureACL(net->conn, def, flags) < 0)
3793 3794
        goto cleanup;

3795
    /* see if we are listening for dhcp pre-modification */
3796
    for (i = 0;
3797
         (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3798
         i++) {
3799 3800 3801 3802 3803 3804
        if (ipdef->nranges || ipdef->nhosts) {
            oldDhcpActive = true;
            break;
        }
    }

3805 3806
    /* VIR_NETWORK_UPDATE_AFFECT_CURRENT means "change LIVE if network
     * is active, else change CONFIG
J
Ján Tomko 已提交
3807
     */
3808
    isActive = virNetworkObjIsActive(obj);
3809 3810
    if ((flags & (VIR_NETWORK_UPDATE_AFFECT_LIVE |
                  VIR_NETWORK_UPDATE_AFFECT_CONFIG)) ==
3811 3812 3813 3814 3815 3816 3817
        VIR_NETWORK_UPDATE_AFFECT_CURRENT) {
        if (isActive)
            flags |= VIR_NETWORK_UPDATE_AFFECT_LIVE;
        else
            flags |= VIR_NETWORK_UPDATE_AFFECT_CONFIG;
    }

3818 3819 3820 3821
    if (isActive && (flags & VIR_NETWORK_UPDATE_AFFECT_LIVE)) {
        /* Take care of anything that must be done before updating the
         * live NetworkDef.
         */
3822 3823 3824 3825
        switch ((virNetworkForwardType) def->forward.type) {
        case VIR_NETWORK_FORWARD_NONE:
        case VIR_NETWORK_FORWARD_NAT:
        case VIR_NETWORK_FORWARD_ROUTE:
3826 3827 3828 3829 3830 3831 3832 3833 3834 3835
            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).
                 */
3836 3837
                networkRemoveFirewallRules(def);
                needFirewallRefresh = true;
3838 3839 3840 3841
                break;
            default:
                break;
            }
3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855
            break;

        case VIR_NETWORK_FORWARD_OPEN:
        case VIR_NETWORK_FORWARD_BRIDGE:
        case VIR_NETWORK_FORWARD_PRIVATE:
        case VIR_NETWORK_FORWARD_VEPA:
        case VIR_NETWORK_FORWARD_PASSTHROUGH:
        case VIR_NETWORK_FORWARD_HOSTDEV:
            break;

        case VIR_NETWORK_FORWARD_LAST:
        default:
            virReportEnumRangeError(virNetworkForwardType, def->forward.type);
            goto cleanup;
3856 3857 3858
        }
    }

3859
    /* update the network config in memory/on disk */
3860
    if (virNetworkObjUpdate(obj, command, section, parentIndex, xml, flags) < 0) {
3861
        if (needFirewallRefresh)
3862
            ignore_value(networkAddFirewallRules(def));
3863 3864 3865
        goto cleanup;
    }

3866 3867 3868 3869
    /* @def is replaced */
    def = virNetworkObjGetDef(obj);

    if (needFirewallRefresh && networkAddFirewallRules(def) < 0)
3870 3871 3872 3873 3874
        goto cleanup;

    if (flags & VIR_NETWORK_UPDATE_AFFECT_CONFIG) {
        /* save updated persistent config to disk */
        if (virNetworkSaveConfig(driver->networkConfigDir,
3875
                                 virNetworkObjGetPersistentDef(obj)) < 0) {
3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888
            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 ||
3889 3890 3891 3892 3893 3894 3895 3896
            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)
3897
             */
3898
            if (networkRestartDhcpDaemon(driver, obj) < 0)
3899 3900
                goto cleanup;

3901 3902 3903 3904 3905 3906 3907 3908
        } 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;

3909
            for (i = 0; (ipdef = virNetworkDefGetIPByIndex(def, AF_INET, i));
3910
                 i++) {
3911 3912 3913 3914 3915 3916 3917
                if (ipdef->nranges || ipdef->nhosts) {
                    newDhcpActive = true;
                    break;
                }
            }

            if ((newDhcpActive != oldDhcpActive &&
3918 3919
                 networkRestartDhcpDaemon(driver, obj) < 0) ||
                networkRefreshDhcpDaemon(driver, obj) < 0) {
3920 3921 3922
                goto cleanup;
            }

3923 3924 3925 3926
        } 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.
3927
             */
3928
            if (networkRefreshDhcpDaemon(driver, obj) < 0)
3929 3930 3931 3932 3933 3934 3935 3936
                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.
             */
3937
            if (networkRefreshRadvd(driver, obj) < 0)
3938 3939 3940 3941
                goto cleanup;
        }

        /* save current network state to disk */
3942
        if ((ret = virNetworkObjSaveStatus(driver->stateDir, obj)) < 0)
3943 3944
            goto cleanup;
    }
3945 3946

    /* call the 'updated' network hook script */
3947
    if (networkRunHook(obj, NULL, NULL, VIR_HOOK_NETWORK_OP_UPDATED,
3948 3949 3950
                       VIR_HOOK_SUBOP_BEGIN) < 0)
        goto cleanup;

3951
    ret = 0;
3952
 cleanup:
3953
    virNetworkObjEndAPI(&obj);
3954 3955 3956
    return ret;
}

3957 3958 3959

static int
networkCreate(virNetworkPtr net)
3960
{
3961
    virNetworkDriverStatePtr driver = networkGetDriver();
3962
    virNetworkObjPtr obj;
3963
    virNetworkDefPtr def;
3964
    int ret = -1;
3965
    virObjectEventPtr event = NULL;
3966

3967
    if (!(obj = networkObjFromNetwork(net)))
3968
        goto cleanup;
3969
    def = virNetworkObjGetDef(obj);
3970

3971
    if (virNetworkCreateEnsureACL(net->conn, def) < 0)
3972 3973
        goto cleanup;

3974
    if ((ret = networkStartNetwork(driver, obj)) < 0)
3975
        goto cleanup;
3976

3977 3978
    event = virNetworkEventLifecycleNew(def->name,
                                        def->uuid,
3979 3980
                                        VIR_NETWORK_EVENT_STARTED,
                                        0);
3981

3982
 cleanup:
3983
    virObjectEventStateQueue(driver->networkEventState, event);
3984
    virNetworkObjEndAPI(&obj);
3985
    return ret;
3986 3987
}

3988 3989 3990

static int
networkDestroy(virNetworkPtr net)
3991
{
3992
    virNetworkDriverStatePtr driver = networkGetDriver();
3993
    virNetworkObjPtr obj;
3994
    virNetworkDefPtr def;
3995
    int ret = -1;
3996
    virObjectEventPtr event = NULL;
3997

3998
    if (!(obj = networkObjFromNetwork(net)))
3999
        goto cleanup;
4000
    def = virNetworkObjGetDef(obj);
4001

4002
    if (virNetworkDestroyEnsureACL(net->conn, def) < 0)
4003 4004
        goto cleanup;

4005
    if (!virNetworkObjIsActive(obj)) {
4006
        virReportError(VIR_ERR_OPERATION_INVALID,
4007
                       _("network '%s' is not active"),
4008
                       def->name);
4009 4010 4011
        goto cleanup;
    }

4012
    if ((ret = networkShutdownNetwork(driver, obj)) < 0)
4013
        goto cleanup;
4014 4015
    /* @def replaced in virNetworkObjUnsetDefTransient*/
    def = virNetworkObjGetDef(obj);
4016

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

4022 4023
    if (!virNetworkObjIsPersistent(obj) &&
        networkRemoveInactive(driver, obj) < 0) {
4024 4025
        ret = -1;
        goto cleanup;
4026
    }
4027

4028
 cleanup:
4029
    virObjectEventStateQueue(driver->networkEventState, event);
4030
    virNetworkObjEndAPI(&obj);
4031 4032 4033
    return ret;
}

4034 4035 4036 4037

static char *
networkGetXMLDesc(virNetworkPtr net,
                  unsigned int flags)
4038
{
4039
    virNetworkObjPtr obj;
4040
    virNetworkDefPtr curDef;
4041
    virNetworkDefPtr def;
4042
    virNetworkDefPtr newDef;
4043
    char *ret = NULL;
4044

4045
    virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL);
4046

4047
    if (!(obj = networkObjFromNetwork(net)))
4048
        return ret;
4049 4050
    def = virNetworkObjGetDef(obj);
    newDef = virNetworkObjGetNewDef(obj);
4051

4052
    if (virNetworkGetXMLDescEnsureACL(net->conn, def) < 0)
4053 4054
        goto cleanup;

4055 4056
    if ((flags & VIR_NETWORK_XML_INACTIVE) && newDef)
        curDef = newDef;
4057
    else
4058
        curDef = def;
4059

4060
    ret = virNetworkDefFormat(curDef, flags);
4061

4062
 cleanup:
4063
    virNetworkObjEndAPI(&obj);
4064
    return ret;
4065 4066
}

4067 4068 4069 4070

static char *
networkGetBridgeName(virNetworkPtr net)
{
4071
    virNetworkObjPtr obj;
4072
    virNetworkDefPtr def;
4073 4074
    char *bridge = NULL;

4075
    if (!(obj = networkObjFromNetwork(net)))
4076
        return bridge;
4077
    def = virNetworkObjGetDef(obj);
4078

4079
    if (virNetworkGetBridgeNameEnsureACL(net->conn, def) < 0)
4080 4081
        goto cleanup;

4082
    if (!(def->bridge)) {
4083 4084
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("network '%s' does not have a bridge name."),
4085
                       def->name);
4086 4087 4088
        goto cleanup;
    }

4089
    ignore_value(VIR_STRDUP(bridge, def->bridge));
4090

4091
 cleanup:
4092
    virNetworkObjEndAPI(&obj);
4093 4094 4095
    return bridge;
}

4096 4097 4098 4099

static int
networkGetAutostart(virNetworkPtr net,
                    int *autostart)
4100
{
4101
    virNetworkObjPtr obj;
4102
    int ret = -1;
4103

4104
    if (!(obj = networkObjFromNetwork(net)))
4105
        return ret;
4106

4107
    if (virNetworkGetAutostartEnsureACL(net->conn, virNetworkObjGetDef(obj)) < 0)
4108 4109
        goto cleanup;

4110
    *autostart = virNetworkObjIsAutostart(obj) ? 1 : 0;
4111
    ret = 0;
4112

4113
 cleanup:
4114
    virNetworkObjEndAPI(&obj);
4115
    return ret;
4116 4117
}

4118 4119 4120 4121

static int
networkSetAutostart(virNetworkPtr net,
                    int autostart)
4122
{
4123
    virNetworkDriverStatePtr driver = networkGetDriver();
4124
    virNetworkObjPtr obj;
4125
    virNetworkDefPtr def;
4126
    char *configFile = NULL, *autostartLink = NULL;
4127 4128
    bool new_autostart;
    bool cur_autostart;
4129
    int ret = -1;
4130

4131
    if (!(obj = networkObjFromNetwork(net)))
4132
        goto cleanup;
4133
    def = virNetworkObjGetDef(obj);
4134

4135
    if (virNetworkSetAutostartEnsureACL(net->conn, def) < 0)
4136 4137
        goto cleanup;

4138
    if (!virNetworkObjIsPersistent(obj)) {
4139 4140
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient network"));
4141 4142 4143
        goto cleanup;
    }

4144 4145 4146
    new_autostart = (autostart != 0);
    cur_autostart = virNetworkObjIsAutostart(obj);
    if (cur_autostart != new_autostart) {
4147 4148
        if ((configFile = virNetworkConfigFile(driver->networkConfigDir,
                                               def->name)) == NULL)
4149
            goto cleanup;
4150 4151
        if ((autostartLink = virNetworkConfigFile(driver->networkAutostartDir,
                                                  def->name)) == NULL)
4152 4153
            goto cleanup;

4154
        if (new_autostart) {
4155
            if (virFileMakePath(driver->networkAutostartDir) < 0) {
4156
                virReportSystemError(errno,
4157 4158
                                     _("cannot create autostart directory '%s'"),
                                     driver->networkAutostartDir);
4159 4160
                goto cleanup;
            }
4161

4162
            if (symlink(configFile, autostartLink) < 0) {
4163
                virReportSystemError(errno,
4164
                                     _("Failed to create symlink '%s' to '%s'"),
4165
                                     autostartLink, configFile);
4166 4167 4168
                goto cleanup;
            }
        } else {
4169
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
4170
                virReportSystemError(errno,
4171
                                     _("Failed to delete symlink '%s'"),
4172
                                     autostartLink);
4173 4174
                goto cleanup;
            }
4175 4176
        }

4177
        virNetworkObjSetAutostart(obj, new_autostart);
4178
    }
4179

4180
    ret = 0;
4181

4182
 cleanup:
4183 4184
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
4185
    virNetworkObjEndAPI(&obj);
4186
    return ret;
4187 4188
}

4189

4190
static int
4191
networkGetDHCPLeases(virNetworkPtr net,
4192 4193 4194
                     const char *mac,
                     virNetworkDHCPLeasePtr **leases,
                     unsigned int flags)
4195
{
4196
    virNetworkDriverStatePtr driver = networkGetDriver();
4197 4198 4199
    size_t i, j;
    size_t nleases = 0;
    int rv = -1;
4200
    size_t size = 0;
4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211
    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;
4212
    virNetworkIPDefPtr ipdef_tmp = NULL;
4213 4214
    virNetworkDHCPLeasePtr lease = NULL;
    virNetworkDHCPLeasePtr *leases_ret = NULL;
4215
    virNetworkObjPtr obj;
4216
    virNetworkDefPtr def;
4217
    virMacAddr mac_addr;
4218 4219 4220

    virCheckFlags(0, -1);

4221 4222 4223 4224 4225 4226
    /* only to check if the MAC is valid */
    if (mac && virMacAddrParse(mac, &mac_addr) < 0) {
        virReportError(VIR_ERR_INVALID_MAC, "%s", mac);
        return -1;
    }

4227
    if (!(obj = networkObjFromNetwork(net)))
4228
        return -1;
4229
    def = virNetworkObjGetDef(obj);
4230

4231
    if (virNetworkGetDHCPLeasesEnsureACL(net->conn, def) < 0)
4232
        goto cleanup;
4233 4234

    /* Retrieve custom leases file location */
4235
    custom_lease_file = networkDnsmasqLeaseFileNameCustom(driver, def->bridge);
4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254

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

4255
        if (!virJSONValueIsArray(leases_array)) {
4256
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4257
                           _("Malformed lease_entries array"));
4258 4259
            goto error;
        }
4260
        size = virJSONValueArraySize(leases_array);
4261 4262
    }

4263
    currtime = (long long)time(NULL);
4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279

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

4280
        if (mac && virMacAddrCompare(mac, mac_tmp))
4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311
            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 */
4312 4313
            for (j = 0; j < def->nips; j++) {
                ipdef_tmp = &def->ips[j];
4314 4315 4316 4317 4318 4319 4320 4321

                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)) {
4322
                    lease->prefix = virSocketAddrGetIPPrefix(&ipdef_tmp->address,
4323 4324 4325 4326 4327 4328 4329 4330
                                                             &ipdef_tmp->netmask,
                                                             ipdef_tmp->prefix);
                    break;
                }
            }

            if ((VIR_STRDUP(lease->mac, mac_tmp) < 0) ||
                (VIR_STRDUP(lease->ipaddr, ip_tmp) < 0) ||
4331
                (VIR_STRDUP(lease->iface, def->bridge) < 0))
4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363
                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);
4364
    VIR_FREE(lease_entries);
4365 4366
    VIR_FREE(custom_lease_file);
    virJSONValueFree(leases_array);
4367

4368
    virNetworkObjEndAPI(&obj);
4369

4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380
    return rv;

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

4381

4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416
/* 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);
        }
    }
}

4417

4418 4419 4420 4421 4422 4423 4424 4425 4426
/* 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:
4427
 * @dom: domain definition that @iface belongs to
4428 4429 4430 4431 4432 4433 4434 4435 4436 4437
 * @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.
 */
4438
static int
4439 4440
networkAllocateActualDevice(virDomainDefPtr dom,
                            virDomainNetDefPtr iface)
4441
{
4442
    virNetworkDriverStatePtr driver = networkGetDriver();
4443
    virDomainNetType actualType = iface->type;
4444
    virNetworkObjPtr obj = NULL;
4445
    virNetworkDefPtr netdef = NULL;
4446
    virNetDevBandwidthPtr bandwidth = NULL;
4447 4448 4449
    virPortGroupDefPtr portgroup = NULL;
    virNetDevVPortProfilePtr virtport = iface->virtPortProfile;
    virNetDevVlanPtr vlan = NULL;
4450
    virNetworkForwardIfDefPtr dev = NULL;
4451
    size_t i;
4452 4453 4454
    int ret = -1;

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4455
        goto validate;
4456 4457 4458 4459

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

4460 4461
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4462 4463 4464
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4465
        goto error;
4466
    }
4467
    netdef = virNetworkObjGetDef(obj);
4468

4469
    if (!virNetworkObjIsActive(obj)) {
4470 4471 4472 4473 4474 4475
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4476 4477 4478
    if (VIR_ALLOC(iface->data.network.actual) < 0)
        goto error;

4479 4480 4481
    /* 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 已提交
4482
     */
4483 4484 4485 4486 4487 4488
    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.
     */
4489 4490 4491 4492 4493 4494

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

4495 4496
    if (bandwidth && virNetDevBandwidthCopy(&iface->data.network.actual->bandwidth,
                                            bandwidth) < 0)
4497
        goto error;
4498

4499 4500 4501 4502 4503 4504 4505 4506
    /* 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;

4507 4508
    if (vlan && virNetDevVlanCopy(&iface->data.network.actual->vlan, vlan) < 0)
        goto error;
4509

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

4520 4521 4522 4523 4524
    switch ((virNetworkForwardType) netdef->forward.type) {
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
    case VIR_NETWORK_FORWARD_OPEN:
4525
        /* for these forward types, the actual net type really *is*
4526
         * NETWORK; we just keep the info from the portgroup in
4527
         * iface->data.network.actual
J
Ján Tomko 已提交
4528
         */
4529
        iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK;
4530

4531
        /* we also store the bridge device and macTableManager settings
4532 4533 4534 4535 4536 4537 4538
         * 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;
4539 4540
        iface->data.network.actual->data.bridge.macTableManager
           = netdef->macTableManager;
4541

4542
        if (networkPlugBandwidth(obj, iface) < 0)
4543
            goto error;
4544
        break;
4545

4546
    case VIR_NETWORK_FORWARD_HOSTDEV: {
4547
        virDomainHostdevSubsysPCIBackendType backend;
4548

4549
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_HOSTDEV;
4550
        if (networkCreateInterfacePool(netdef) < 0)
4551 4552 4553
            goto error;

        /* pick first dev with 0 connections */
4554 4555 4556
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].connections == 0) {
                dev = &netdef->forward.ifs[i];
4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570
                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;
4571
        iface->data.network.actual->data.hostdev.def.managed = netdef->forward.managed ? 1 : 0;
4572
        iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type;
4573
        iface->data.network.actual->data.hostdev.def.source.subsys.u.pci.addr = dev->device.pci;
4574

E
Eric Blake 已提交
4575
        switch (netdef->forward.driverName) {
4576
        case VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT:
4577
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT;
4578 4579
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_KVM:
4580
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM;
4581 4582
            break;
        case VIR_NETWORK_FORWARD_DRIVER_NAME_VFIO:
4583
            backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO;
4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594
            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;

4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618
        /* 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;
            }
        }
4619 4620
        break;
    }
4621

4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633
    case VIR_NETWORK_FORWARD_BRIDGE:
        if (netdef->bridge) {
            /* <forward type='bridge'/> <bridge name='xxx'/>
             * is VIR_DOMAIN_NET_TYPE_BRIDGE
             */

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

4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667
            /* 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) {
                /* only type='openvswitch' is allowed for bridges */
                if (virtport->virtPortType != VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("<virtualport type='%s'> not supported for network "
                                     "'%s' which uses a bridge device"),
                                   virNetDevVPortTypeToString(virtport->virtPortType),
                                   netdef->name);
                    goto error;
                }
            }
            break;
        }

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

    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
4668 4669 4670 4671 4672
        /* <forward type='bridge|private|vepa|passthrough'> are all
         * VIR_DOMAIN_NET_TYPE_DIRECT.
         */

        /* Set type=direct and appropriate <source mode='xxx'/> */
4673
        iface->data.network.actual->type = actualType = VIR_DOMAIN_NET_TYPE_DIRECT;
4674 4675 4676 4677 4678 4679

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

4681 4682 4683 4684 4685 4686 4687 4688
        /* 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) {
4689
            goto error;
4690
        }
4691
        virtport = iface->data.network.actual->virtPortProfile;
4692
        if (virtport) {
4693 4694 4695 4696 4697 4698 4699 4700
            /* 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);
4701
                goto error;
4702 4703
            }
        }
4704

4705 4706 4707
        /* 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).
         */
4708
        if ((netdef->forward.nifs <= 0) && (netdef->forward.npfs <= 0)) {
4709 4710 4711 4712
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network '%s' uses a direct mode, but "
                             "has no forward dev and no interface pool"),
                           netdef->name);
4713
            goto error;
4714 4715 4716
        } else {
            /* pick an interface from the pool */

4717
            if (networkCreateInterfacePool(netdef) < 0)
4718 4719
                goto error;

4720 4721 4722 4723 4724
            /* 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.
4725
             */
4726 4727
            if ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
                ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
4728 4729 4730
                 iface->data.network.actual->virtPortProfile &&
                 (iface->data.network.actual->virtPortProfile->virtPortType
                  == VIR_NETDEV_VPORT_PROFILE_8021QBH))) {
4731

4732
                /* pick first dev with 0 connections */
4733 4734 4735
                for (i = 0; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections == 0) {
                        dev = &netdef->forward.ifs[i];
4736 4737 4738 4739 4740
                        break;
                    }
                }
            } else {
                /* pick least used dev */
4741
                dev = &netdef->forward.ifs[0];
4742 4743 4744
                for (i = 1; i < netdef->forward.nifs; i++) {
                    if (netdef->forward.ifs[i].connections < dev->connections)
                        dev = &netdef->forward.ifs[i];
4745 4746 4747 4748
                }
            }
            /* dev points at the physical device we want to use */
            if (!dev) {
4749 4750 4751 4752
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("network '%s' requires exclusive access "
                                 "to interfaces, but none are available"),
                               netdef->name);
4753
                goto error;
4754
            }
4755 4756
            if (VIR_STRDUP(iface->data.network.actual->data.direct.linkdev,
                           dev->device.dev) < 0)
4757
                goto error;
4758
        }
4759 4760 4761 4762 4763 4764
        break;

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

4767 4768
    if (virNetworkObjMacMgrAdd(obj, driver->dnsmasqStateDir,
                               dom->name, &iface->mac) < 0)
M
Michal Privoznik 已提交
4769 4770
        goto error;

4771
    if (virNetDevVPortProfileCheckComplete(virtport, true) < 0)
4772
        goto error;
4773

4774
 validate:
4775 4776 4777 4778 4779
    /* 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.
     */

4780
    if (virDomainNetGetActualVlan(iface)) {
4781 4782 4783 4784
        /* 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
4785 4786
         */
        if (!(actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV ||
4787 4788 4789
              (actualType == VIR_DOMAIN_NET_TYPE_DIRECT &&
               virDomainNetGetActualDirectMode(iface)
               == VIR_NETDEV_MACVLAN_MODE_PASSTHRU) ||
4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808
              (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;
        }
    }
4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819
    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;
        }
    }
4820 4821 4822

    if (netdef) {
        netdef->connections++;
4823
        if (dev)
4824 4825
            dev->connections++;
        /* finally we can call the 'plugged' hook script if any */
4826
        if (networkRunHook(obj, dom, iface,
4827 4828 4829
                           VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
                           VIR_HOOK_SUBOP_BEGIN) < 0) {
            /* adjust for failure */
4830
            netdef->connections--;
4831 4832 4833 4834
            if (dev)
                dev->connections--;
            goto error;
        }
4835
        networkLogAllocation(netdef, actualType, dev, iface, true);
4836 4837
    }

4838
    ret = 0;
4839

4840
 cleanup:
4841
    virNetworkObjEndAPI(&obj);
4842 4843
    return ret;

4844
 error:
4845
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4846 4847 4848
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
4849
    goto cleanup;
4850 4851
}

4852

4853
/* networkNotifyActualDevice:
4854
 * @dom: domain definition that @iface belongs to
4855 4856 4857 4858 4859
 * @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
4860 4861
 * order, or re-attach the interface's tap device to the network's
 * bridge.
4862
 *
4863
 * No return value (but does log any failures)
4864
 */
4865
static void
4866 4867
networkNotifyActualDevice(virDomainDefPtr dom,
                          virDomainNetDefPtr iface)
4868
{
4869
    virNetworkDriverStatePtr driver = networkGetDriver();
4870
    virDomainNetType actualType = virDomainNetGetActualType(iface);
4871
    virNetworkObjPtr obj;
4872
    virNetworkDefPtr netdef;
4873
    virNetworkForwardIfDefPtr dev = NULL;
4874
    size_t i;
4875
    char *master = NULL;
4876 4877

    if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
4878
        return;
4879

4880 4881
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
4882 4883 4884
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
4885 4886
        goto error;
    }
4887
    netdef = virNetworkObjGetDef(obj);
4888

4889
    if (!virNetworkObjIsActive(obj)) {
4890 4891 4892 4893 4894 4895
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("network '%s' is not active"),
                       netdef->name);
        goto error;
    }

4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906
    /* 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;

4907 4908
    /* see if we're connected to the correct bridge */
    if (netdef->bridge) {
4909 4910
        bool useOVS = false;

4911 4912 4913
        if (virNetDevGetMaster(iface->ifname, &master) < 0)
            goto error;

4914 4915 4916 4917 4918 4919 4920 4921
        /* IFLA_MASTER for a tap on an OVS switch is always "ovs-system" */
        if (STREQ_NULLABLE(master, "ovs-system")) {
            useOVS = true;
            VIR_FREE(master);
            if (virNetDevOpenvswitchInterfaceGetMaster(iface->ifname, &master) < 0)
                goto error;
        }

4922 4923
        if (STRNEQ_NULLABLE(netdef->bridge, master)) {
            /* disconnect from current (incorrect) bridge */
4924 4925 4926 4927 4928 4929 4930
            if (master) {
                VIR_INFO("Removing %s from %s", iface->ifname, master);
                if (useOVS)
                    ignore_value(virNetDevOpenvswitchRemovePort(master, iface->ifname));
                else
                    ignore_value(virNetDevBridgeRemovePort(master, iface->ifname));
            }
4931 4932 4933 4934 4935 4936

            /* 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())
             */
4937
            VIR_INFO("Attaching %s to %s", iface->ifname, netdef->bridge);
4938 4939 4940 4941 4942 4943 4944 4945 4946 4947
            if (virNetDevTapAttachBridge(iface->ifname, netdef->bridge,
                                         &iface->mac, dom->uuid,
                                         virDomainNetGetActualVirtPortProfile(iface),
                                         virDomainNetGetActualVlan(iface),
                                         iface->mtu, NULL) < 0) {
                goto error;
            }
        }
    }

4948
    if (!iface->data.network.actual ||
4949 4950
        (actualType != VIR_DOMAIN_NET_TYPE_DIRECT &&
         actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
4951 4952
        VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name);
        goto success;
4953 4954
    }

4955
    if (networkCreateInterfacePool(netdef) < 0)
4956
        goto error;
4957

4958
    if (netdef->forward.nifs == 0) {
4959
        virReportError(VIR_ERR_INTERNAL_ERROR,
4960 4961
                       _("network '%s' uses a direct or hostdev mode, "
                         "but has no forward dev and no interface pool"),
4962
                       netdef->name);
4963
        goto error;
4964
    }
4965

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

4969 4970 4971 4972 4973 4974 4975 4976 4977
        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 */
4978 4979
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
4980
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
4981 4982
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
4983 4984 4985 4986 4987
                break;
            }
        }
        /* dev points at the physical device we want to use */
        if (!dev) {
4988
            virReportError(VIR_ERR_INTERNAL_ERROR,
4989 4990
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
4991
                           netdef->name, actualDev);
4992
            goto error;
4993 4994
        }

4995
        /* PASSTHROUGH mode and PRIVATE Mode + 802.1Qbh both require
4996 4997
         * exclusive access to a device, so current connections count
         * must be 0 in those cases.
4998
         */
4999
        if ((dev->connections > 0) &&
5000 5001
            ((netdef->forward.type == VIR_NETWORK_FORWARD_PASSTHROUGH) ||
             ((netdef->forward.type == VIR_NETWORK_FORWARD_PRIVATE) &&
5002 5003
              iface->data.network.actual->virtPortProfile &&
              (iface->data.network.actual->virtPortProfile->virtPortType
5004
               == VIR_NETDEV_VPORT_PROFILE_8021QBH)))) {
5005
            virReportError(VIR_ERR_INTERNAL_ERROR,
5006 5007
                           _("network '%s' claims dev='%s' is already in "
                             "use by a different domain"),
5008
                           netdef->name, actualDev);
5009
            goto error;
5010
        }
5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022
    }  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 */
5023 5024
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5025
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5026
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
5027 5028
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5029 5030 5031 5032 5033 5034 5035 5036 5037
                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,
5038 5039 5040 5041
                           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 已提交
5042
            goto error;
5043 5044 5045 5046 5047 5048 5049
        }

        /* 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) &&
5050
            netdef->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
5051 5052 5053 5054 5055 5056 5057 5058 5059
            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;
        }
5060 5061
    }

5062
 success:
5063
    netdef->connections++;
5064 5065
    if (dev)
        dev->connections++;
5066
    /* finally we can call the 'plugged' hook script if any */
5067
    if (networkRunHook(obj, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_PLUGGED,
5068 5069 5070 5071 5072 5073 5074
                       VIR_HOOK_SUBOP_BEGIN) < 0) {
        /* adjust for failure */
        if (dev)
            dev->connections--;
        netdef->connections--;
        goto error;
    }
5075
    networkLogAllocation(netdef, actualType, dev, iface, true);
5076

5077
 cleanup:
5078
    virNetworkObjEndAPI(&obj);
5079
    VIR_FREE(master);
5080
    return;
5081

5082
 error:
5083
    goto cleanup;
5084 5085 5086 5087
}


/* networkReleaseActualDevice:
5088
 * @dom: domain definition that @iface belongs to
5089 5090 5091 5092 5093 5094 5095 5096 5097
 * @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.
 */
5098
static int
5099 5100
networkReleaseActualDevice(virDomainDefPtr dom,
                           virDomainNetDefPtr iface)
5101
{
5102
    virNetworkDriverStatePtr driver = networkGetDriver();
5103
    virDomainNetType actualType = virDomainNetGetActualType(iface);
5104
    virNetworkObjPtr obj;
5105
    virNetworkDefPtr netdef;
5106
    virNetworkForwardIfDefPtr dev = NULL;
5107 5108
    size_t i;
    int ret = -1;
5109 5110

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

5113 5114
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5115 5116 5117
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
5118 5119
        goto error;
    }
5120
    netdef = virNetworkObjGetDef(obj);
5121

5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140
    switch ((virNetworkForwardType) netdef->forward.type) {
    case VIR_NETWORK_FORWARD_NONE:
    case VIR_NETWORK_FORWARD_NAT:
    case VIR_NETWORK_FORWARD_ROUTE:
    case VIR_NETWORK_FORWARD_OPEN:
        if (iface->data.network.actual && networkUnplugBandwidth(obj, iface) < 0)
            goto error;
        break;

    case VIR_NETWORK_FORWARD_BRIDGE:
    case VIR_NETWORK_FORWARD_PRIVATE:
    case VIR_NETWORK_FORWARD_VEPA:
    case VIR_NETWORK_FORWARD_PASSTHROUGH:
    case VIR_NETWORK_FORWARD_HOSTDEV:
        break;

    case VIR_NETWORK_FORWARD_LAST:
    default:
        virReportEnumRangeError(virNetworkForwardType, netdef->forward.type);
5141
        goto error;
5142
    }
5143

5144 5145 5146
    if ((!iface->data.network.actual) ||
        ((actualType != VIR_DOMAIN_NET_TYPE_DIRECT) &&
         (actualType != VIR_DOMAIN_NET_TYPE_HOSTDEV))) {
5147 5148
        VIR_DEBUG("Nothing to release to network %s", iface->data.network.name);
        goto success;
5149 5150
    }

5151
    if (netdef->forward.nifs == 0) {
5152
        virReportError(VIR_ERR_INTERNAL_ERROR,
5153
                       _("network '%s' uses a direct/hostdev mode, but "
5154 5155
                         "has no forward dev and no interface pool"),
                       netdef->name);
5156
        goto error;
5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168
    }

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

5170 5171
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5172
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
5173 5174
                STREQ(actualDev, netdef->forward.ifs[i].device.dev)) {
                dev = &netdef->forward.ifs[i];
5175 5176 5177
                break;
            }
        }
5178

5179
        if (!dev) {
5180
            virReportError(VIR_ERR_INTERNAL_ERROR,
5181 5182
                           _("network '%s' doesn't have dev='%s' "
                             "in use by domain"),
5183
                           netdef->name, actualDev);
5184
            goto error;
5185
        }
5186 5187 5188 5189 5190 5191 5192 5193 5194 5195
    } 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;
        }

5196 5197
        for (i = 0; i < netdef->forward.nifs; i++) {
            if (netdef->forward.ifs[i].type
5198
                == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI &&
5199
                virPCIDeviceAddressEqual(&hostdev->source.subsys.u.pci.addr,
5200 5201
                                         &netdef->forward.ifs[i].device.pci)) {
                dev = &netdef->forward.ifs[i];
5202 5203 5204 5205 5206 5207 5208 5209 5210
                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,
5211 5212 5213 5214
                           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 已提交
5215
            goto error;
5216
        }
J
Ján Tomko 已提交
5217
    }
5218

5219
 success:
5220
    virNetworkObjMacMgrDel(obj, driver->dnsmasqStateDir, dom->name, &iface->mac);
M
Michal Privoznik 已提交
5221

5222
    if (iface->data.network.actual) {
5223
        netdef->connections--;
5224 5225
        if (dev)
            dev->connections--;
5226
        /* finally we can call the 'unplugged' hook script if any */
5227
        networkRunHook(obj, dom, iface, VIR_HOOK_NETWORK_OP_IFACE_UNPLUGGED,
5228
                       VIR_HOOK_SUBOP_BEGIN);
5229
        networkLogAllocation(netdef, actualType, dev, iface, false);
5230
    }
5231
    ret = 0;
5232
 cleanup:
5233
    virNetworkObjEndAPI(&obj);
5234 5235 5236 5237
    if (iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
        virDomainActualNetDefFree(iface->data.network.actual);
        iface->data.network.actual = NULL;
    }
5238
    return ret;
5239

5240
 error:
5241
    goto cleanup;
5242
}
5243

5244

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
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
    virNetDevBandwidthPtr netBand = def->bandwidth;
5275
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5276 5277 5278
    unsigned long long tmp_new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];

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

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

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

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

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

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

5331
 cleanup:
5332 5333 5334
    return ret;
}

5335

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

5352 5353
    if ((ret = virBitmapNextClearBit(classIdMap, -1)) < 0)
        ret = virBitmapSize(classIdMap);
5354

5355
    if (virBitmapSetBitExpand(classIdMap, ret) < 0)
5356 5357 5358 5359 5360
        return -1;

    return ret;
}

5361

5362
static int
5363
networkPlugBandwidthImpl(virNetworkObjPtr obj,
5364 5365 5366
                         virDomainNetDefPtr iface,
                         virNetDevBandwidthPtr ifaceBand,
                         unsigned long long new_rate)
5367
{
5368
    virNetworkDriverStatePtr driver = networkGetDriver();
5369
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5370
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5371
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5372
    ssize_t class_id = 0;
5373 5374
    int plug_ret;
    int ret = -1;
5375 5376

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

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

    ret = 0;
5412 5413 5414 5415 5416 5417
 cleanup:
    return ret;
}


static int
5418
networkPlugBandwidth(virNetworkObjPtr obj,
5419 5420 5421 5422 5423 5424 5425 5426
                     virDomainNetDefPtr iface)
{
    int ret = -1;
    int plug_ret;
    unsigned long long new_rate = 0;
    char ifmac[VIR_MAC_STRING_BUFLEN];
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);

5427
    if ((plug_ret = networkCheckBandwidth(obj, ifaceBand, NULL,
5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447
                                          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;
    }

5448
    if (networkPlugBandwidthImpl(obj, iface, ifaceBand, new_rate) < 0)
5449 5450 5451
        goto cleanup;

    ret = 0;
5452

5453
 cleanup:
5454 5455 5456
    return ret;
}

5457

5458
static int
5459
networkUnplugBandwidth(virNetworkObjPtr obj,
5460 5461
                       virDomainNetDefPtr iface)
{
5462
    virNetworkDefPtr def = virNetworkObjGetDef(obj);
5463
    virBitmapPtr classIdMap = virNetworkObjGetClassIdMap(obj);
5464
    unsigned long long tmp_floor_sum = virNetworkObjGetFloorSum(obj);
5465
    virNetworkDriverStatePtr driver = networkGetDriver();
5466 5467
    int ret = 0;
    unsigned long long new_rate;
5468
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
5469 5470 5471

    if (iface->data.network.actual &&
        iface->data.network.actual->class_id) {
5472
        if (!def->bandwidth || !def->bandwidth->in) {
5473
            VIR_WARN("Network %s has no bandwidth but unplug requested",
5474
                     def->name);
5475 5476
            goto cleanup;
        }
5477
        /* we must remove class from bridge */
5478
        new_rate = def->bandwidth->in->average;
5479

5480 5481
        if (def->bandwidth->in->peak > 0)
            new_rate = def->bandwidth->in->peak;
5482

5483
        ret = virNetDevBandwidthUnplug(def->bridge,
5484 5485 5486 5487
                                       iface->data.network.actual->class_id);
        if (ret < 0)
            goto cleanup;
        /* update sum of 'floor'-s of attached NICs */
5488 5489 5490
        tmp_floor_sum -= ifaceBand->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);

5491
        /* return class ID */
5492
        ignore_value(virBitmapClearBit(classIdMap,
5493 5494
                                       iface->data.network.actual->class_id));
        /* update status file */
5495
        if (virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5496 5497
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5498
            ignore_value(virBitmapSetBit(classIdMap,
5499 5500 5501
                                         iface->data.network.actual->class_id));
            goto cleanup;
        }
5502
        /* update rate for non guaranteed NICs */
5503
        new_rate -= tmp_floor_sum;
5504 5505
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0)
5506
            VIR_WARN("Unable to update rate for 1:2 class on %s bridge",
5507
                     def->bridge);
5508 5509 5510 5511
        /* no class is associated any longer */
        iface->data.network.actual->class_id = 0;
    }

5512
 cleanup:
5513 5514
    return ret;
}
5515

5516

5517
static void
5518
networkNetworkObjTaint(virNetworkObjPtr obj,
5519
                       virNetworkTaintFlags taint)
5520
{
5521 5522
    virNetworkDefPtr def = virNetworkObjGetDef(obj);

5523
    if (virNetworkObjTaint(obj, taint)) {
5524
        char uuidstr[VIR_UUID_STRING_BUFLEN];
5525
        virUUIDFormat(def->uuid, uuidstr);
5526 5527

        VIR_WARN("Network name='%s' uuid=%s is tainted: %s",
5528
                 def->name, uuidstr, virNetworkTaintTypeToString(taint));
5529 5530
    }
}
5531 5532 5533 5534 5535 5536


static bool
networkBandwidthGenericChecks(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
5537
    virNetDevBandwidthPtr ifaceBand;
5538 5539 5540 5541 5542 5543 5544 5545
    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;
    }

5546
    ifaceBand = virDomainNetGetActualBandwidth(iface);
5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557
    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;
}


5558
static bool
5559 5560 5561 5562
networkBandwidthChangeAllowed(virDomainNetDefPtr iface,
                              virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5563
    virNetworkObjPtr obj = NULL;
5564 5565 5566 5567 5568 5569
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    bool ret = false;

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

5570 5571
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5572 5573 5574 5575 5576 5577
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return false;
    }

5578
    if (networkCheckBandwidth(obj, newBandwidth, ifaceBand, iface->mac, NULL) < 0)
5579 5580 5581 5582 5583
        goto cleanup;

    ret = true;

 cleanup:
5584
    virNetworkObjEndAPI(&obj);
5585 5586
    return ret;
}
5587 5588


5589
static int
5590 5591 5592 5593
networkBandwidthUpdate(virDomainNetDefPtr iface,
                       virNetDevBandwidthPtr newBandwidth)
{
    virNetworkDriverStatePtr driver = networkGetDriver();
5594
    virNetworkObjPtr obj = NULL;
5595
    virNetworkDefPtr def;
5596
    unsigned long long tmp_floor_sum;
5597 5598 5599 5600 5601 5602 5603 5604
    virNetDevBandwidthPtr ifaceBand = virDomainNetGetActualBandwidth(iface);
    unsigned long long new_rate = 0;
    int plug_ret;
    int ret = -1;

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

5605 5606
    obj = virNetworkObjFindByName(driver->networks, iface->data.network.name);
    if (!obj) {
5607 5608 5609 5610 5611
        virReportError(VIR_ERR_NO_NETWORK,
                       _("no network with matching name '%s'"),
                       iface->data.network.name);
        return ret;
    }
5612
    def = virNetworkObjGetDef(obj);
5613

5614
    if ((plug_ret = networkCheckBandwidth(obj, newBandwidth, ifaceBand,
5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627
                                          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: */

5628
    if (ifaceBand && ifaceBand->in && ifaceBand->in->floor &&
5629
        newBandwidth->in && newBandwidth->in->floor) {
5630 5631
        /* Either we just need to update @floor .. */

5632
        if (virNetDevBandwidthUpdateRate(def->bridge,
5633
                                         iface->data.network.actual->class_id,
5634
                                         def->bandwidth,
5635 5636 5637
                                         newBandwidth->in->floor) < 0)
            goto cleanup;

5638 5639 5640 5641 5642
        tmp_floor_sum = virNetworkObjGetFloorSum(obj);
        tmp_floor_sum -= ifaceBand->in->floor;
        tmp_floor_sum += newBandwidth->in->floor;
        virNetworkObjSetFloorSum(obj, tmp_floor_sum);
        new_rate -= tmp_floor_sum;
5643

5644 5645
        if (virNetDevBandwidthUpdateRate(def->bridge, 2,
                                         def->bandwidth, new_rate) < 0 ||
5646
            virNetworkObjSaveStatus(driver->stateDir, obj) < 0) {
5647
            /* Ouch, rollback */
5648 5649 5650
            tmp_floor_sum -= newBandwidth->in->floor;
            tmp_floor_sum += ifaceBand->in->floor;
            virNetworkObjSetFloorSum(obj, tmp_floor_sum);
5651

5652
            ignore_value(virNetDevBandwidthUpdateRate(def->bridge,
5653
                                                      iface->data.network.actual->class_id,
5654
                                                      def->bandwidth,
5655 5656 5657 5658 5659 5660
                                                      ifaceBand->in->floor));
            goto cleanup;
        }
    } else if (newBandwidth->in && newBandwidth->in->floor) {
        /* .. or we need to plug in new .. */

5661
        if (networkPlugBandwidthImpl(obj, iface, newBandwidth, new_rate) < 0)
5662 5663 5664 5665
            goto cleanup;
    } else {
        /* .. or unplug old. */

5666
        if (networkUnplugBandwidth(obj, iface) < 0)
5667 5668 5669 5670 5671
            goto cleanup;
    }

    ret = 0;
 cleanup:
5672
    virNetworkObjEndAPI(&obj);
5673 5674
    return ret;
}
5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702


static virNetworkDriver networkDriver = {
    .name = "bridge",
    .connectNumOfNetworks = networkConnectNumOfNetworks, /* 0.2.0 */
    .connectListNetworks = networkConnectListNetworks, /* 0.2.0 */
    .connectNumOfDefinedNetworks = networkConnectNumOfDefinedNetworks, /* 0.2.0 */
    .connectListDefinedNetworks = networkConnectListDefinedNetworks, /* 0.2.0 */
    .connectListAllNetworks = networkConnectListAllNetworks, /* 0.10.2 */
    .connectNetworkEventRegisterAny = networkConnectNetworkEventRegisterAny, /* 1.2.1 */
    .connectNetworkEventDeregisterAny = networkConnectNetworkEventDeregisterAny, /* 1.2.1 */
    .networkLookupByUUID = networkLookupByUUID, /* 0.2.0 */
    .networkLookupByName = networkLookupByName, /* 0.2.0 */
    .networkCreateXML = networkCreateXML, /* 0.2.0 */
    .networkDefineXML = networkDefineXML, /* 0.2.0 */
    .networkUndefine = networkUndefine, /* 0.2.0 */
    .networkUpdate = networkUpdate, /* 0.10.2 */
    .networkCreate = networkCreate, /* 0.2.0 */
    .networkDestroy = networkDestroy, /* 0.2.0 */
    .networkGetXMLDesc = networkGetXMLDesc, /* 0.2.0 */
    .networkGetBridgeName = networkGetBridgeName, /* 0.2.0 */
    .networkGetAutostart = networkGetAutostart, /* 0.2.1 */
    .networkSetAutostart = networkSetAutostart, /* 0.2.1 */
    .networkIsActive = networkIsActive, /* 0.7.3 */
    .networkIsPersistent = networkIsPersistent, /* 0.7.3 */
    .networkGetDHCPLeases = networkGetDHCPLeases, /* 1.2.6 */
};

5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714

static virHypervisorDriver networkHypervisorDriver = {
    .name = "network",
    .connectOpen = networkConnectOpen, /* 4.1.0 */
    .connectClose = networkConnectClose, /* 4.1.0 */
    .connectIsEncrypted = networkConnectIsEncrypted, /* 4.1.0 */
    .connectIsSecure = networkConnectIsSecure, /* 4.1.0 */
    .connectIsAlive = networkConnectIsAlive, /* 4.1.0 */
};


static virConnectDriver networkConnectDriver = {
5715
    .localOnly = true,
5716
    .uriSchemes = (const char *[]){ "network", NULL },
5717 5718 5719 5720 5721
    .hypervisorDriver = &networkHypervisorDriver,
    .networkDriver = &networkDriver,
};


5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732
static virStateDriver networkStateDriver = {
    .name = "bridge",
    .stateInitialize  = networkStateInitialize,
    .stateAutoStart  = networkStateAutoStart,
    .stateCleanup = networkStateCleanup,
    .stateReload = networkStateReload,
};

int
networkRegister(void)
{
5733 5734
    if (virRegisterConnectDriver(&networkConnectDriver, false) < 0)
        return -1;
5735 5736 5737 5738
    if (virSetSharedNetworkDriver(&networkDriver) < 0)
        return -1;
    if (virRegisterStateDriver(&networkStateDriver) < 0)
        return -1;
5739 5740 5741 5742

    virDomainNetSetDeviceImpl(
        networkAllocateActualDevice,
        networkNotifyActualDevice,
5743 5744
        networkReleaseActualDevice,
        networkBandwidthChangeAllowed,
5745
        networkBandwidthUpdate);
5746

5747 5748
    return 0;
}