lxc_driver.c 89.8 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
2
 * Copyright (C) 2010-2011 Red Hat, Inc.
D
Daniel Veillard 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 * Copyright IBM Corp. 2008
 *
 * lxc_driver.c: linux container driver functions
 *
 * Authors:
 *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
 *
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <config.h>

27
#include <fcntl.h>
D
Daniel Veillard 已提交
28 29 30 31
#include <sched.h>
#include <sys/utsname.h>
#include <string.h>
#include <sys/types.h>
32 33 34
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/poll.h>
D
Daniel Veillard 已提交
35 36 37
#include <unistd.h>
#include <wait.h>

38
#include "virterror_internal.h"
39
#include "logging.h"
40
#include "datatypes.h"
D
Daniel Veillard 已提交
41
#include "lxc_conf.h"
42
#include "lxc_container.h"
D
Daniel Veillard 已提交
43
#include "lxc_driver.h"
44
#include "memory.h"
45
#include "util.h"
46
#include "virnetdevbridge.h"
47
#include "virnetdevveth.h"
48
#include "nodeinfo.h"
49
#include "uuid.h"
50
#include "stats_linux.h"
51
#include "hooks.h"
E
Eric Blake 已提交
52
#include "virfile.h"
53
#include "virpidfile.h"
54
#include "fdstream.h"
55
#include "domain_audit.h"
56
#include "domain_nwfilter.h"
57
#include "network/bridge_driver.h"
58
#include "virnetdev.h"
D
Daniel Veillard 已提交
59

60 61
#define VIR_FROM_THIS VIR_FROM_LXC

62 63
#define START_POSTFIX ": starting up\n"

64 65
#define LXC_NB_MEM_PARAM  3

66 67 68 69 70 71 72 73
typedef struct _lxcDomainObjPrivate lxcDomainObjPrivate;
typedef lxcDomainObjPrivate *lxcDomainObjPrivatePtr;
struct _lxcDomainObjPrivate {
    int monitor;
    int monitorWatch;
};


74
static int lxcStartup(int privileged);
75
static int lxcShutdown(void);
76
static lxc_driver_t *lxc_driver = NULL;
D
Daniel Veillard 已提交
77 78 79

/* Functions */

80 81
static void lxcDriverLock(lxc_driver_t *driver)
{
82
    virMutexLock(&driver->lock);
83 84 85
}
static void lxcDriverUnlock(lxc_driver_t *driver)
{
86
    virMutexUnlock(&driver->lock);
87 88
}

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
static void *lxcDomainObjPrivateAlloc(void)
{
    lxcDomainObjPrivatePtr priv;

    if (VIR_ALLOC(priv) < 0)
        return NULL;

    priv->monitor = -1;
    priv->monitorWatch = -1;

    return priv;
}

static void lxcDomainObjPrivateFree(void *data)
{
    lxcDomainObjPrivatePtr priv = data;

    VIR_FREE(priv);
}


110 111 112 113
static void lxcDomainEventFlush(int timer, void *opaque);
static void lxcDomainEventQueue(lxc_driver_t *driver,
                                virDomainEventPtr event);

114 115 116 117 118 119 120 121 122 123 124 125 126
static int lxcVmTerminate(lxc_driver_t *driver,
                          virDomainObjPtr vm,
                          virDomainShutoffReason reason);
static int lxcProcessAutoDestroyInit(lxc_driver_t *driver);
static void lxcProcessAutoDestroyRun(lxc_driver_t *driver,
                                     virConnectPtr conn);
static void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver);
static int lxcProcessAutoDestroyAdd(lxc_driver_t *driver,
                                    virDomainObjPtr vm,
                                    virConnectPtr conn);
static int lxcProcessAutoDestroyRemove(lxc_driver_t *driver,
                                       virDomainObjPtr vm);

127

D
Daniel Veillard 已提交
128 129
static virDrvOpenStatus lxcOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
130
                                unsigned int flags)
D
Daniel Veillard 已提交
131
{
E
Eric Blake 已提交
132 133
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

D
Daniel Veillard 已提交
134
    /* Verify uri was specified */
135
    if (conn->uri == NULL) {
136 137
        if (lxc_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
138

139 140
        conn->uri = xmlParseURI("lxc:///");
        if (!conn->uri) {
141
            virReportOOMError();
142 143
            return VIR_DRV_OPEN_ERROR;
        }
144 145 146 147 148 149 150 151 152 153
    } else {
        if (conn->uri->scheme == NULL ||
            STRNEQ(conn->uri->scheme, "lxc"))
            return VIR_DRV_OPEN_DECLINED;

        /* Leave for remote driver */
        if (conn->uri->server != NULL)
            return VIR_DRV_OPEN_DECLINED;

        /* If path isn't '/' then they typoed, tell them correct path */
154 155
        if (conn->uri->path != NULL &&
            STRNEQ(conn->uri->path, "/")) {
156
            lxcError(VIR_ERR_INTERNAL_ERROR,
157
                     _("Unexpected LXC URI path '%s', try lxc:///"),
158 159 160
                     conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
        }
D
Daniel Veillard 已提交
161

162 163
        /* URI was good, but driver isn't active */
        if (lxc_driver == NULL) {
164
            lxcError(VIR_ERR_INTERNAL_ERROR,
165
                     "%s", _("lxc state driver is not active"));
166 167 168
            return VIR_DRV_OPEN_ERROR;
        }
    }
169

170
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
171 172 173 174 175 176

    return VIR_DRV_OPEN_SUCCESS;
}

static int lxcClose(virConnectPtr conn)
{
177 178 179
    lxc_driver_t *driver = conn->privateData;

    lxcDriverLock(driver);
180 181
    virDomainEventCallbackListRemoveConn(conn,
                                         driver->domainEventState->callbacks);
182
    lxcProcessAutoDestroyRun(driver, conn);
183 184
    lxcDriverUnlock(driver);

185 186
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
187 188
}

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203

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


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


204 205 206 207 208 209
static char *lxcGetCapabilities(virConnectPtr conn) {
    lxc_driver_t *driver = conn->privateData;
    char *xml;

    lxcDriverLock(driver);
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
210
        virReportOOMError();
211 212 213 214 215 216
    lxcDriverUnlock(driver);

    return xml;
}


D
Daniel Veillard 已提交
217 218 219
static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
                                        int id)
{
220 221 222
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
223

224
    lxcDriverLock(driver);
225
    vm = virDomainFindByID(&driver->domains, id);
226 227
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
228
    if (!vm) {
229 230
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching id %d"), id);
231
        goto cleanup;
D
Daniel Veillard 已提交
232 233 234
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
235
    if (dom)
D
Daniel Veillard 已提交
236 237
        dom->id = vm->def->id;

238
cleanup:
239 240
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
241 242 243 244 245 246
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
247 248 249
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
250

251
    lxcDriverLock(driver);
252
    vm = virDomainFindByUUID(&driver->domains, uuid);
253 254
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
255
    if (!vm) {
256 257 258 259
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
260
        goto cleanup;
D
Daniel Veillard 已提交
261 262 263
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
264
    if (dom)
D
Daniel Veillard 已提交
265 266
        dom->id = vm->def->id;

267
cleanup:
268 269
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
270 271 272 273 274 275
    return dom;
}

static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
                                          const char *name)
{
276 277 278
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
279

280
    lxcDriverLock(driver);
281
    vm = virDomainFindByName(&driver->domains, name);
282
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
283
    if (!vm) {
284 285
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching name '%s'"), name);
286
        goto cleanup;
D
Daniel Veillard 已提交
287 288 289
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
290
    if (dom)
D
Daniel Veillard 已提交
291 292
        dom->id = vm->def->id;

293
cleanup:
294 295
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
296 297 298
    return dom;
}

299 300 301 302 303 304 305 306 307 308 309

static int lxcDomainIsActive(virDomainPtr dom)
{
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    lxcDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!obj) {
310 311 312 313
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}


static int lxcDomainIsPersistent(virDomainPtr dom)
{
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    lxcDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!obj) {
335 336 337 338
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
339 340 341 342 343 344 345 346 347 348
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
static int lxcDomainIsUpdated(virDomainPtr dom)
{
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    lxcDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!obj) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }
    ret = obj->updated;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}
372

373
static int lxcListDomains(virConnectPtr conn, int *ids, int nids) {
374
    lxc_driver_t *driver = conn->privateData;
375
    int n;
376

377
    lxcDriverLock(driver);
378
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
379
    lxcDriverUnlock(driver);
380

381
    return n;
D
Daniel Veillard 已提交
382
}
383

384
static int lxcNumDomains(virConnectPtr conn) {
385
    lxc_driver_t *driver = conn->privateData;
386
    int n;
387

388
    lxcDriverLock(driver);
389
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
390
    lxcDriverUnlock(driver);
391

392
    return n;
D
Daniel Veillard 已提交
393 394 395
}

static int lxcListDefinedDomains(virConnectPtr conn,
396
                                 char **const names, int nnames) {
397
    lxc_driver_t *driver = conn->privateData;
398
    int n;
399

400
    lxcDriverLock(driver);
401
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
402
    lxcDriverUnlock(driver);
403

404
    return n;
D
Daniel Veillard 已提交
405 406 407
}


408
static int lxcNumDefinedDomains(virConnectPtr conn) {
409
    lxc_driver_t *driver = conn->privateData;
410
    int n;
411

412
    lxcDriverLock(driver);
413
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
414
    lxcDriverUnlock(driver);
415

416
    return n;
D
Daniel Veillard 已提交
417 418
}

419 420


D
Daniel Veillard 已提交
421 422
static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml)
{
423 424
    lxc_driver_t *driver = conn->privateData;
    virDomainDefPtr def = NULL;
425
    virDomainObjPtr vm = NULL;
426
    virDomainPtr dom = NULL;
427
    virDomainEventPtr event = NULL;
428
    int dupVM;
D
Daniel Veillard 已提交
429

430
    lxcDriverLock(driver);
431
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
432
                                        1 << VIR_DOMAIN_VIRT_LXC,
433
                                        VIR_DOMAIN_XML_INACTIVE)))
434
        goto cleanup;
D
Daniel Veillard 已提交
435

M
Matthias Bolte 已提交
436
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
437
        goto cleanup;
438

439
    if ((def->nets != NULL) && !(driver->have_netns)) {
440
        lxcError(VIR_ERR_OPERATION_INVALID,
J
Jim Meyering 已提交
441
                 "%s", _("System lacks NETNS support"));
442
        goto cleanup;
443 444
    }

445
    if (!(vm = virDomainAssignDef(driver->caps,
446
                                  &driver->domains, def, false)))
447 448
        goto cleanup;
    def = NULL;
449
    vm->persistent = 1;
D
Daniel Veillard 已提交
450

451
    if (virDomainSaveConfig(driver->configDir,
452
                            vm->newDef ? vm->newDef : vm->def) < 0) {
453
        virDomainRemoveInactive(&driver->domains, vm);
454
        vm = NULL;
455
        goto cleanup;
D
Daniel Veillard 已提交
456 457
    }

458 459
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
460
                                     !dupVM ?
461 462 463
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

D
Daniel Veillard 已提交
464
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
465
    if (dom)
D
Daniel Veillard 已提交
466 467
        dom->id = vm->def->id;

468 469
cleanup:
    virDomainDefFree(def);
470 471
    if (vm)
        virDomainObjUnlock(vm);
472 473
    if (event)
        lxcDomainEventQueue(driver, event);
474
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
475 476 477
    return dom;
}

478 479
static int lxcDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
D
Daniel Veillard 已提交
480
{
481 482
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
483
    virDomainEventPtr event = NULL;
484
    int ret = -1;
D
Daniel Veillard 已提交
485

486 487
    virCheckFlags(0, -1);

488
    lxcDriverLock(driver);
489
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
490
    if (!vm) {
491 492 493 494
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
495
        goto cleanup;
D
Daniel Veillard 已提交
496 497
    }

498
    if (!vm->persistent) {
499
        lxcError(VIR_ERR_OPERATION_INVALID,
500
                 "%s", _("Cannot undefine transient domain"));
501
        goto cleanup;
502
    }
D
Daniel Veillard 已提交
503

504
    if (virDomainDeleteConfig(driver->configDir,
505
                              driver->autostartDir,
506 507
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
508

509 510 511 512
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

513 514 515 516 517 518 519
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }

520
    ret = 0;
D
Daniel Veillard 已提交
521

522
cleanup:
523 524
    if (vm)
        virDomainObjUnlock(vm);
525 526
    if (event)
        lxcDomainEventQueue(driver, event);
527
    lxcDriverUnlock(driver);
528
    return ret;
D
Daniel Veillard 已提交
529 530
}

531 532 533 534 535
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
536 537 538
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
539 540
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
541
    virCgroupPtr cgroup = NULL;
542
    int ret = -1, rc;
D
Daniel Veillard 已提交
543

544
    lxcDriverLock(driver);
545
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
546

D
Daniel Veillard 已提交
547
    if (!vm) {
548 549 550 551
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
552
        goto cleanup;
D
Daniel Veillard 已提交
553 554
    }

J
Jiri Denemark 已提交
555
    info->state = virDomainObjGetState(vm, NULL);
D
Daniel Veillard 已提交
556

D
Daniel P. Berrange 已提交
557
    if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) {
D
Daniel Veillard 已提交
558
        info->cpuTime = 0;
559
        info->memory = vm->def->mem.cur_balloon;
D
Daniel Veillard 已提交
560
    } else {
561
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
562
            lxcError(VIR_ERR_INTERNAL_ERROR,
563
                     _("Unable to get cgroup for %s"), vm->def->name);
564 565 566 567
            goto cleanup;
        }

        if (virCgroupGetCpuacctUsage(cgroup, &(info->cpuTime)) < 0) {
568
            lxcError(VIR_ERR_OPERATION_FAILED,
569
                     "%s", _("Cannot read cputime for domain"));
R
Ryota Ozaki 已提交
570 571
            goto cleanup;
        }
572
        if ((rc = virCgroupGetMemoryUsage(cgroup, &(info->memory))) < 0) {
573
            lxcError(VIR_ERR_OPERATION_FAILED,
574
                     "%s", _("Cannot read memory usage for domain"));
575 576 577 578 579 580
            if (rc == -ENOENT) {
                /* Don't fail if we can't read memory usage due to a lack of
                 * kernel support */
                info->memory = 0;
            } else
                goto cleanup;
581
        }
D
Daniel Veillard 已提交
582 583
    }

584
    info->maxMem = vm->def->mem.max_balloon;
D
Daniel Veillard 已提交
585
    info->nrVirtCpu = 1;
586
    ret = 0;
D
Daniel Veillard 已提交
587

588
cleanup:
589
    lxcDriverUnlock(driver);
590 591
    if (cgroup)
        virCgroupFree(&cgroup);
592 593
    if (vm)
        virDomainObjUnlock(vm);
594
    return ret;
D
Daniel Veillard 已提交
595 596
}

597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

J
Jiri Denemark 已提交
621
    *state = virDomainObjGetState(vm, reason);
622 623 624 625 626 627 628 629
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

630
static char *lxcGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
631
{
632 633 634
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
635

636
    lxcDriverLock(driver);
637
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
638 639
    lxcDriverUnlock(driver);

640
    if (!vm) {
641 642 643 644
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
645
        goto cleanup;
646 647
    }

648 649
    ret = strdup(vm->def->os.type);

650
    if (ret == NULL)
651
        virReportOOMError();
652

653
cleanup:
654 655
    if (vm)
        virDomainObjUnlock(vm);
656
    return ret;
D
Daniel Veillard 已提交
657 658
}

R
Ryota Ozaki 已提交
659 660 661 662 663 664 665 666 667 668 669 670 671
/* Returns max memory in kb, 0 if error */
static unsigned long lxcDomainGetMaxMemory(virDomainPtr dom) {
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    unsigned long ret = 0;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
672
        lxcError(VIR_ERR_NO_DOMAIN,
673
                         _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
674 675 676
        goto cleanup;
    }

677
    ret = vm->def->mem.max_balloon;
R
Ryota Ozaki 已提交
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
697
        lxcError(VIR_ERR_NO_DOMAIN,
698
                         _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
699 700 701
        goto cleanup;
    }

702
    if (newmax < vm->def->mem.cur_balloon) {
703
        lxcError(VIR_ERR_INVALID_ARG,
704
                         "%s", _("Cannot set max memory lower than current memory"));
R
Ryota Ozaki 已提交
705 706 707
        goto cleanup;
    }

708
    vm->def->mem.max_balloon = newmax;
R
Ryota Ozaki 已提交
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virCgroupPtr cgroup = NULL;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
729
        lxcError(VIR_ERR_NO_DOMAIN,
730
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
731 732 733
        goto cleanup;
    }

734
    if (newmem > vm->def->mem.max_balloon) {
735
        lxcError(VIR_ERR_INVALID_ARG,
736
                 "%s", _("Cannot set memory higher than max memory"));
R
Ryota Ozaki 已提交
737 738 739
        goto cleanup;
    }

740 741 742 743 744
    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is not running"));
        goto cleanup;
    }
745

746
    if (driver->cgroup == NULL) {
747
        lxcError(VIR_ERR_OPERATION_INVALID,
748 749 750
                 "%s", _("cgroups must be configured on the host"));
        goto cleanup;
    }
R
Ryota Ozaki 已提交
751

752 753 754 755
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("Unable to get cgroup for %s"), vm->def->name);
        goto cleanup;
R
Ryota Ozaki 已提交
756
    }
757 758 759 760 761 762 763

    if (virCgroupSetMemory(cgroup, newmem) < 0) {
        lxcError(VIR_ERR_OPERATION_FAILED,
                 "%s", _("Failed to set memory for domain"));
        goto cleanup;
    }

R
Ryota Ozaki 已提交
764 765 766 767 768 769 770 771 772 773
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    if (cgroup)
        virCgroupFree(&cgroup);
    return ret;
}

774
static int lxcDomainSetMemoryParameters(virDomainPtr dom,
775
                                        virTypedParameterPtr params,
776
                                        int nparams,
E
Eric Blake 已提交
777
                                        unsigned int flags)
778 779 780 781 782 783 784
{
    lxc_driver_t *driver = dom->conn->privateData;
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

E
Eric Blake 已提交
785 786
    virCheckFlags(0, -1);

787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("cannot find cgroup for domain %s"), vm->def->name);
        goto cleanup;
    }

    ret = 0;
    for (i = 0; i < nparams; i++) {
806
        virTypedParameterPtr param = &params[i];
807 808 809

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            int rc;
810
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
811 812 813 814 815 816 817 818 819 820 821 822 823 824
                lxcError(VIR_ERR_INVALID_ARG, "%s",
                         _("invalid type for memory hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

            rc = virCgroupSetMemoryHardLimit(cgroup, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory hard_limit tunable"));
                ret = -1;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
            int rc;
825
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
826 827 828 829 830 831 832 833 834 835 836 837
                lxcError(VIR_ERR_INVALID_ARG, "%s",
                         _("invalid type for memory soft_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

            rc = virCgroupSetMemorySoftLimit(cgroup, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory soft_limit tunable"));
                ret = -1;
            }
838
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
839
            int rc;
840
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
841 842 843 844 845 846
                lxcError(VIR_ERR_INVALID_ARG, "%s",
                         _("invalid type for swap_hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

847
            rc = virCgroupSetMemSwapHardLimit(cgroup, params[i].value.ul);
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set swap_hard_limit tunable"));
                ret = -1;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
            lxcError(VIR_ERR_INVALID_ARG,
                     _("Memory tunable `%s' not implemented"), param->field);
            ret = -1;
        } else {
            lxcError(VIR_ERR_INVALID_ARG,
                     _("Parameter `%s' not supported"), param->field);
            ret = -1;
        }
    }

cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

873
static int lxcDomainGetMemoryParameters(virDomainPtr dom,
874
                                        virTypedParameterPtr params,
875
                                        int *nparams,
E
Eric Blake 已提交
876
                                        unsigned int flags)
877 878 879 880 881
{
    lxc_driver_t *driver = dom->conn->privateData;
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
882
    unsigned long long val;
883 884 885
    int ret = -1;
    int rc;

E
Eric Blake 已提交
886 887
    virCheckFlags(0, -1);

888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = LXC_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("Unable to get cgroup for %s"), vm->def->name);
        goto cleanup;
    }

912
    for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
913
        virTypedParameterPtr param = &params[i];
914 915
        val = 0;
        param->value.ul = 0;
916
        param->type = VIR_TYPED_PARAM_ULLONG;
917 918 919 920 921 922 923

        switch(i) {
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(cgroup, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
924
                goto cleanup;
925 926 927 928
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) {
                lxcError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field memory hard limit too long for destination"));
929
                goto cleanup;
930 931 932 933 934 935 936 937 938
            }
            param->value.ul = val;
            break;

        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(cgroup, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
939
                goto cleanup;
940 941 942 943
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) {
                lxcError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field memory soft limit too long for destination"));
944
                goto cleanup;
945 946 947 948 949
            }
            param->value.ul = val;
            break;

        case 2: /* fill swap hard limit here */
950
            rc = virCgroupGetMemSwapHardLimit(cgroup, &val);
951 952 953
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
954
                goto cleanup;
955
            }
956
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT) == NULL) {
957 958
                lxcError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field swap hard limit too long for destination"));
959
                goto cleanup;
960 961 962 963 964 965 966 967 968 969
            }
            param->value.ul = val;
            break;

        default:
            break;
            /* should not hit here */
        }
    }

970 971
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
972 973
    ret = 0;

974 975 976 977 978 979 980 981 982
cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

983
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
984
                                 unsigned int flags)
D
Daniel Veillard 已提交
985
{
986 987 988
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
989

990 991
    /* Flags checked by virDomainDefFormat */

992
    lxcDriverLock(driver);
993
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
994 995
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
996
    if (!vm) {
997 998 999 1000
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
1001
        goto cleanup;
D
Daniel Veillard 已提交
1002 1003
    }

1004
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
1005 1006 1007 1008
                             vm->newDef ? vm->newDef : vm->def,
                             flags);

cleanup:
1009 1010
    if (vm)
        virDomainObjUnlock(vm);
1011
    return ret;
D
Daniel Veillard 已提交
1012 1013
}

1014

1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
static int lxcProcessAutoDestroyInit(lxc_driver_t *driver)
{
    if (!(driver->autodestroy = virHashCreate(5, NULL)))
        return -1;

    return 0;
}

struct lxcProcessAutoDestroyData {
    lxc_driver_t *driver;
    virConnectPtr conn;
};

static void lxcProcessAutoDestroyDom(void *payload,
                                     const void *name,
                                     void *opaque)
{
    struct lxcProcessAutoDestroyData *data = opaque;
    virConnectPtr conn = payload;
    const char *uuidstr = name;
    unsigned char uuid[VIR_UUID_BUFLEN];
    virDomainObjPtr dom;
    virDomainEventPtr event = NULL;

    VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn);

    if (data->conn != conn)
        return;

    if (virUUIDParse(uuidstr, uuid) < 0) {
        VIR_WARN("Failed to parse %s", uuidstr);
        return;
    }

    if (!(dom = virDomainFindByUUID(&data->driver->domains,
                                    uuid))) {
        VIR_DEBUG("No domain object to kill");
        return;
    }

    VIR_DEBUG("Killing domain");
    lxcVmTerminate(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED);
    virDomainAuditStop(dom, "destroyed");
    event = virDomainEventNewFromObj(dom,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

    if (dom && !dom->persistent)
        virDomainRemoveInactive(&data->driver->domains, dom);

    if (dom)
        virDomainObjUnlock(dom);
    if (event)
        lxcDomainEventQueue(data->driver, event);
    virHashRemoveEntry(data->driver->autodestroy, uuidstr);
}

/*
 * Precondition: driver is locked
 */
static void lxcProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn)
{
    struct lxcProcessAutoDestroyData data = {
        driver, conn
    };
    VIR_DEBUG("conn=%p", conn);
    virHashForEach(driver->autodestroy, lxcProcessAutoDestroyDom, &data);
}

static void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver)
{
    virHashFree(driver->autodestroy);
}

static int lxcProcessAutoDestroyAdd(lxc_driver_t *driver,
                                    virDomainObjPtr vm,
                                    virConnectPtr conn)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virUUIDFormat(vm->def->uuid, uuidstr);
    VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn);
    if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0)
        return -1;
    return 0;
}

static int lxcProcessAutoDestroyRemove(lxc_driver_t *driver,
                                       virDomainObjPtr vm)
{
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virUUIDFormat(vm->def->uuid, uuidstr);
    VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr);
    if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0)
        return -1;
    return 0;
}


1113 1114
/**
 * lxcVmCleanup:
1115 1116
 * @driver: pointer to driver structure
 * @vm: pointer to VM to clean up
J
Jiri Denemark 已提交
1117
 * @reason: reason for switching the VM to shutoff state
1118
 *
1119
 * Cleanout resources associated with the now dead VM
1120 1121
 *
 */
1122
static void lxcVmCleanup(lxc_driver_t *driver,
J
Jiri Denemark 已提交
1123 1124
                         virDomainObjPtr vm,
                         virDomainShutoffReason reason)
1125
{
D
Dan Smith 已提交
1126
    virCgroupPtr cgroup;
1127
    int i;
1128
    lxcDomainObjPrivatePtr priv = vm->privateData;
1129

1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
    /* now that we know it's stopped call the hook if present */
    if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
        char *xml = virDomainDefFormat(vm->def, 0);

        /* we can't stop the operation even if the script raised an error */
        virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name,
                    VIR_HOOK_LXC_OP_STOPPED, VIR_HOOK_SUBOP_END, NULL, xml);
        VIR_FREE(xml);
    }

1140 1141 1142
    /* Stop autodestroy in case guest is restarted */
    lxcProcessAutoDestroyRemove(driver, vm);

1143
    virEventRemoveHandle(priv->monitorWatch);
1144
    VIR_FORCE_CLOSE(priv->monitor);
1145

1146
    virPidFileDelete(driver->stateDir, vm->def->name);
1147
    virDomainDeleteConfig(driver->stateDir, NULL, vm);
1148

J
Jiri Denemark 已提交
1149
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
1150 1151
    vm->pid = -1;
    vm->def->id = -1;
1152 1153
    priv->monitor = -1;
    priv->monitorWatch = -1;
1154

1155
    for (i = 0 ; i < vm->def->nnets ; i++) {
1156 1157
        ignore_value(virNetDevSetOnline(vm->def->nets[i]->ifname, false));
        ignore_value(virNetDevVethDelete(vm->def->nets[i]->ifname));
1158 1159

        networkReleaseActualDevice(vm->def->nets[i]);
1160 1161
    }

1162 1163
    virDomainConfVMNWFilterTeardown(vm);

1164 1165
    if (driver->cgroup &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) {
D
Dan Smith 已提交
1166 1167 1168 1169
        virCgroupRemove(cgroup);
        virCgroupFree(&cgroup);
    }

1170 1171 1172 1173 1174 1175
    if (vm->newDef) {
        virDomainDefFree(vm->def);
        vm->def = vm->newDef;
        vm->def->id = -1;
        vm->newDef = NULL;
    }
1176 1177
}

1178 1179
/**
 * lxcSetupInterfaces:
1180
 * @conn: pointer to connection
1181
 * @def: pointer to virtual machine structure
1182 1183
 * @nveths: number of interfaces
 * @veths: interface names
1184 1185 1186 1187 1188 1189 1190 1191
 *
 * Sets up the container interfaces by creating the veth device pairs and
 * attaching the parent end to the appropriate bridge.  The container end
 * will moved into the container namespace later after clone has been called.
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcSetupInterfaces(virConnectPtr conn,
1192
                              virDomainDefPtr def,
1193 1194
                              unsigned int *nveths,
                              char ***veths)
1195
{
1196
    int rc = -1, i;
1197
    char *bridge = NULL;
1198

1199
    for (i = 0 ; i < def->nnets ; i++) {
1200 1201
        char *parentVeth;
        char *containerVeth = NULL;
1202

1203 1204 1205 1206 1207 1208 1209 1210
        /* If appropriate, grab a physical device from the configured
         * network's pool of devices, or resolve bridge device name
         * to the one defined in the network definition.
         */
        if (networkAllocateActualDevice(def->nets[i]) < 0)
            goto error_exit;

        switch (virDomainNetGetActualType(def->nets[i])) {
1211 1212
        case VIR_DOMAIN_NET_TYPE_NETWORK:
        {
1213 1214 1215 1216
            virNetworkPtr network;

            network = virNetworkLookupByName(conn,
                                             def->nets[i]->data.network.name);
1217 1218 1219 1220 1221 1222 1223
            if (!network) {
                goto error_exit;
            }

            bridge = virNetworkGetBridgeName(network);

            virNetworkFree(network);
1224 1225 1226
            break;
        }
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
1227
            bridge = virDomainNetGetActualBridgeName(def->nets[i]);
1228
            break;
S
Stefan Berger 已提交
1229 1230 1231 1232 1233 1234 1235 1236 1237 1238

        case VIR_DOMAIN_NET_TYPE_USER:
        case VIR_DOMAIN_NET_TYPE_ETHERNET:
        case VIR_DOMAIN_NET_TYPE_SERVER:
        case VIR_DOMAIN_NET_TYPE_CLIENT:
        case VIR_DOMAIN_NET_TYPE_MCAST:
        case VIR_DOMAIN_NET_TYPE_INTERNAL:
        case VIR_DOMAIN_NET_TYPE_DIRECT:
        case VIR_DOMAIN_NET_TYPE_LAST:
            break;
1239 1240
        }

1241
        VIR_DEBUG("bridge: %s", bridge);
1242
        if (NULL == bridge) {
1243
            lxcError(VIR_ERR_INTERNAL_ERROR,
1244
                     "%s", _("Failed to get bridge for interface"));
1245 1246 1247
            goto error_exit;
        }

1248
        VIR_DEBUG("calling vethCreate()");
1249
        parentVeth = def->nets[i]->ifname;
1250
        if (virNetDevVethCreate(&parentVeth, &containerVeth) < 0)
1251
            goto error_exit;
1252
        VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth);
1253

1254
        if (NULL == def->nets[i]->ifname) {
1255
            def->nets[i]->ifname = parentVeth;
1256
        }
1257

1258
        if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) {
1259
            virReportOOMError();
1260
            VIR_FREE(containerVeth);
1261
            goto error_exit;
1262
        }
1263
        (*veths)[(*nveths)] = containerVeth;
1264
        (*nveths)++;
1265

1266 1267
        if (virNetDevSetMAC(containerVeth, def->nets[i]->mac) < 0)
            goto error_exit;
1268

1269
        if (virNetDevBridgeAddPort(bridge, parentVeth) < 0)
1270 1271
            goto error_exit;

1272
        if (virNetDevSetOnline(parentVeth, true) < 0)
1273
            goto error_exit;
1274

1275 1276
        if (virNetDevBandwidthSet(def->nets[i]->ifname,
                                  virDomainNetGetActualBandwidth(def->nets[i])) < 0) {
1277 1278 1279 1280 1281 1282
            lxcError(VIR_ERR_INTERNAL_ERROR,
                     _("cannot set bandwidth limits on %s"),
                     def->nets[i]->ifname);
            goto error_exit;
        }

1283 1284 1285
        if (def->nets[i]->filter &&
            virDomainConfNWFilterInstantiate(conn, def->nets[i]) < 0)
            goto error_exit;
1286 1287 1288 1289 1290
    }

    rc = 0;

error_exit:
1291 1292 1293 1294
    if (rc != 0) {
        for (i = 0 ; i < def->nnets ; i++)
            networkReleaseActualDevice(def->nets[i]);
    }
1295 1296 1297
    return rc;
}

1298

1299
static int lxcMonitorClient(lxc_driver_t * driver,
1300
                            virDomainObjPtr vm)
1301
{
1302 1303 1304
    char *sockpath = NULL;
    int fd;
    struct sockaddr_un addr;
1305

1306 1307
    if (virAsprintf(&sockpath, "%s/%s.sock",
                    driver->stateDir, vm->def->name) < 0) {
1308
        virReportOOMError();
1309 1310 1311 1312
        return -1;
    }

    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
1313
        virReportSystemError(errno, "%s",
1314
                             _("Failed to create client socket"));
1315
        goto error;
1316 1317
    }

1318 1319
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
C
Chris Lalancette 已提交
1320
    if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) {
1321
        lxcError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
1322 1323 1324
                 _("Socket path %s too big for destination"), sockpath);
        goto error;
    }
1325 1326

    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1327
        virReportSystemError(errno, "%s",
1328
                             _("Failed to connect to client socket"));
1329
        goto error;
1330 1331
    }

1332 1333
    VIR_FREE(sockpath);
    return fd;
1334

1335 1336
error:
    VIR_FREE(sockpath);
1337
    VIR_FORCE_CLOSE(fd);
1338 1339 1340 1341
    return -1;
}


1342
static int lxcVmTerminate(lxc_driver_t *driver,
J
Jiri Denemark 已提交
1343 1344
                          virDomainObjPtr vm,
                          virDomainShutoffReason reason)
1345
{
1346 1347
    virCgroupPtr group = NULL;
    int rc;
1348

1349
    if (vm->pid <= 0) {
1350
        lxcError(VIR_ERR_INTERNAL_ERROR,
1351
                 _("Invalid PID %d for container"), vm->pid);
1352 1353 1354
        return -1;
    }

1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) == 0) {
        rc = virCgroupKillPainfully(group);
        if (rc < 0) {
            virReportSystemError(-rc, "%s",
                                 _("Failed to kill container PIDs"));
            rc = -1;
            goto cleanup;
        }
        if (rc == 1) {
            lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
                     _("Some container PIDs refused to die"));
            rc = -1;
            goto cleanup;
        }
    } else {
        /* If cgroup doesn't exist, the VM pids must have already
         * died and so we're just cleaning up stale state
         */
1373
    }
1374

J
Jiri Denemark 已提交
1375
    lxcVmCleanup(driver, vm, reason);
1376

1377
    rc = 0;
1378

1379 1380 1381
cleanup:
    virCgroupFree(&group);
    return rc;
1382
}
1383

1384 1385
static void lxcMonitorEvent(int watch,
                            int fd,
1386 1387 1388
                            int events ATTRIBUTE_UNUSED,
                            void *data)
{
1389 1390
    lxc_driver_t *driver = lxc_driver;
    virDomainObjPtr vm = data;
1391
    virDomainEventPtr event = NULL;
1392
    lxcDomainObjPrivatePtr priv;
1393

1394
    lxcDriverLock(driver);
1395 1396
    virDomainObjLock(vm);
    lxcDriverUnlock(driver);
1397

1398 1399 1400
    priv = vm->privateData;

    if (priv->monitor != fd || priv->monitorWatch != watch) {
1401
        virEventRemoveHandle(watch);
1402
        goto cleanup;
1403 1404
    }

J
Jiri Denemark 已提交
1405
    if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) {
1406
        virEventRemoveHandle(watch);
1407 1408 1409 1410
    } else {
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
1411
        virDomainAuditStop(vm, "shutdown");
1412
    }
1413 1414 1415 1416
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1417 1418

cleanup:
1419 1420
    if (vm)
        virDomainObjUnlock(vm);
1421 1422
    if (event) {
        lxcDriverLock(driver);
1423
        lxcDomainEventQueue(driver, event);
1424 1425
        lxcDriverUnlock(driver);
    }
1426 1427 1428
}


1429 1430 1431 1432 1433
static virCommandPtr
lxcBuildControllerCmd(lxc_driver_t *driver,
                      virDomainObjPtr vm,
                      int nveths,
                      char **veths,
1434 1435
                      int *ttyFDs,
                      size_t nttyFDs,
1436
                      int handshakefd)
1437
{
1438
    size_t i;
A
Amy Griffis 已提交
1439 1440
    char *filterstr;
    char *outputstr;
1441 1442 1443 1444 1445 1446 1447 1448 1449
    virCommandPtr cmd;

    cmd = virCommandNew(vm->def->emulator);

    /* The controller may call ip command, so we have to retain PATH. */
    virCommandAddEnvPass(cmd, "PATH");

    virCommandAddEnvFormat(cmd, "LIBVIRT_DEBUG=%d",
                           virLogGetDefaultPriority());
A
Amy Griffis 已提交
1450 1451 1452

    if (virLogGetNbFilters() > 0) {
        filterstr = virLogGetFilters();
1453 1454 1455 1456 1457 1458
        if (!filterstr) {
            virReportOOMError();
            goto cleanup;
        }

        virCommandAddEnvPair(cmd, "LIBVIRT_LOG_FILTERS", filterstr);
A
Amy Griffis 已提交
1459 1460 1461
        VIR_FREE(filterstr);
    }

A
Amy Griffis 已提交
1462 1463 1464
    if (driver->log_libvirtd) {
        if (virLogGetNbOutputs() > 0) {
            outputstr = virLogGetOutputs();
1465 1466 1467 1468 1469 1470
            if (!outputstr) {
                virReportOOMError();
                goto cleanup;
            }

            virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr);
A
Amy Griffis 已提交
1471 1472 1473
            VIR_FREE(outputstr);
        }
    } else {
1474 1475 1476
        virCommandAddEnvFormat(cmd,
                               "LIBVIRT_LOG_OUTPUTS=%d:stderr",
                               virLogGetDefaultPriority());
A
Amy Griffis 已提交
1477 1478
    }

1479 1480 1481 1482 1483 1484
    virCommandAddArgList(cmd, "--name", vm->def->name, NULL);
    for (i = 0 ; i < nttyFDs ; i++) {
        virCommandAddArg(cmd, "--console");
        virCommandAddArgFormat(cmd, "%d", ttyFDs[i]);
        virCommandPreserveFD(cmd, ttyFDs[i]);
    }
1485 1486
    virCommandAddArg(cmd, "--handshake");
    virCommandAddArgFormat(cmd, "%d", handshakefd);
1487
    virCommandAddArg(cmd, "--background");
1488 1489

    for (i = 0 ; i < nveths ; i++) {
1490
        virCommandAddArgList(cmd, "--veth", veths[i], NULL);
1491 1492
    }

1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
    /* now that we know it is about to start call the hook if present */
    if (virHookPresent(VIR_HOOK_DRIVER_LXC)) {
        char *xml = virDomainDefFormat(vm->def, 0);
        int hookret;

        hookret = virHookCall(VIR_HOOK_DRIVER_LXC, vm->def->name,
                    VIR_HOOK_LXC_OP_START, VIR_HOOK_SUBOP_BEGIN, NULL, xml);
        VIR_FREE(xml);

        /*
         * If the script raised an error abort the launch
         */
        if (hookret < 0)
            goto cleanup;
    }

1509
    virCommandPreserveFD(cmd, handshakefd);
1510

1511
    return cmd;
A
Amy Griffis 已提交
1512
cleanup:
1513
    virCommandFree(cmd);
1514
    return NULL;
1515 1516
}

1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
static int
lxcReadLogOutput(virDomainObjPtr vm,
                 char *logfile,
                 off_t pos,
                 char *buf,
                 size_t buflen)
{
    int fd;
    off_t off;
    int whence;
    int got = 0, ret = -1;
    int retries = 10;

    if ((fd = open(logfile, O_RDONLY)) < 0) {
        virReportSystemError(errno, _("failed to open logfile %s"),
                             logfile);
        goto cleanup;
    }

    if (pos < 0) {
        off = 0;
        whence = SEEK_END;
    } else {
        off = pos;
        whence = SEEK_SET;
    }

    if (lseek(fd, off, whence) < 0) {
        if (whence == SEEK_END)
            virReportSystemError(errno,
                                 _("unable to seek to end of log for %s"),
                                 logfile);
        else
            virReportSystemError(errno,
                                 _("unable to seek to %lld from start for %s"),
                                 (long long)off, logfile);
        goto cleanup;
    }

    while (retries) {
        ssize_t bytes;
        int isdead = 0;

        if (kill(vm->pid, 0) == -1 && errno == ESRCH)
            isdead = 1;

        /* Any failures should be detected before we read the log, so we
         * always have something useful to report on failure. */
        bytes = saferead(fd, buf+got, buflen-got-1);
        if (bytes < 0) {
            virReportSystemError(errno, "%s",
                                 _("Failure while reading guest log output"));
            goto cleanup;
        }

        got += bytes;
        buf[got] = '\0';

        if ((got == buflen-1) || isdead) {
            break;
        }

        usleep(100*1000);
        retries--;
    }


    ret = got;
cleanup:
    VIR_FORCE_CLOSE(fd);
    return ret;
}
1589

1590 1591 1592 1593 1594
/**
 * lxcVmStart:
 * @conn: pointer to connection
 * @driver: pointer to driver structure
 * @vm: pointer to virtual machine structure
1595
 * @autoDestroy: mark the domain for auto destruction
J
Jiri Denemark 已提交
1596
 * @reason: reason for switching vm to running state
1597 1598 1599 1600 1601 1602 1603
 *
 * Starts a vm
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcVmStart(virConnectPtr conn,
                      lxc_driver_t * driver,
J
Jiri Denemark 已提交
1604
                      virDomainObjPtr vm,
1605
                      bool autoDestroy,
J
Jiri Denemark 已提交
1606
                      virDomainRunningReason reason)
1607
{
1608
    int rc = -1, r;
1609 1610 1611
    size_t nttyFDs = 0;
    int *ttyFDs = NULL;
    size_t i;
1612 1613 1614 1615
    char *logfile = NULL;
    int logfd = -1;
    unsigned int nveths = 0;
    char **veths = NULL;
1616
    int handshakefds[2] = { -1, -1 };
1617 1618 1619 1620
    off_t pos = -1;
    char ebuf[1024];
    char *timestamp;
    virCommandPtr cmd = NULL;
1621
    lxcDomainObjPrivatePtr priv = vm->privateData;
1622
    virErrorPtr err = NULL;
1623

1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
    if (!lxc_driver->cgroup) {
        lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
                 _("The 'cpuacct', 'devices' & 'memory' cgroups controllers must be mounted"));
        return -1;
    }

    if (!virCgroupMounted(lxc_driver->cgroup,
                          VIR_CGROUP_CONTROLLER_CPUACCT)) {
        lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
                 _("Unable to find 'cpuacct' cgroups controller mount"));
        return -1;
    }
    if (!virCgroupMounted(lxc_driver->cgroup,
                          VIR_CGROUP_CONTROLLER_DEVICES)) {
        lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
                 _("Unable to find 'devices' cgroups controller mount"));
        return -1;
    }
    if (!virCgroupMounted(lxc_driver->cgroup,
                          VIR_CGROUP_CONTROLLER_MEMORY)) {
        lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
                 _("Unable to find 'memory' cgroups controller mount"));
        return -1;
    }

1649 1650
    if (virFileMakePath(driver->logDir) < 0) {
        virReportSystemError(errno,
1651
                             _("Cannot create log directory '%s'"),
1652
                             driver->logDir);
1653 1654
        return -1;
    }
1655

1656 1657
    if (virAsprintf(&logfile, "%s/%s.log",
                    driver->logDir, vm->def->name) < 0) {
1658
        virReportOOMError();
1659
        return -1;
1660 1661
    }

1662 1663 1664 1665 1666 1667 1668 1669
    /* Do this up front, so any part of the startup process can add
     * runtime state to vm->def that won't be persisted. This let's us
     * report implicit runtime defaults in the XML, like vnc listen/socket
     */
    VIR_DEBUG("Setting current domain def as transient");
    if (virDomainObjSetDefTransient(driver->caps, vm, true) < 0)
        goto cleanup;

1670 1671 1672 1673 1674 1675 1676
    /* Here we open all the PTYs we need on the host OS side.
     * The LXC controller will open the guest OS side PTYs
     * and forward I/O between them.
     */
    nttyFDs = vm->def->nconsoles;
    if (VIR_ALLOC_N(ttyFDs, nttyFDs) < 0) {
        virReportOOMError();
1677 1678
        goto cleanup;
    }
1679 1680 1681 1682 1683 1684
    for (i = 0 ; i < vm->def->nconsoles ; i++)
        ttyFDs[i] = -1;

    for (i = 0 ; i < vm->def->nconsoles ; i++) {
        char *ttyPath;
        if (vm->def->consoles[i]->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
1685
            lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1686
                     _("Only PTY console types are supported"));
1687 1688
            goto cleanup;
        }
1689 1690 1691 1692 1693

        if (virFileOpenTty(&ttyFDs[i], &ttyPath, 1) < 0) {
            virReportSystemError(errno, "%s",
                                 _("Failed to allocate tty"));
            goto cleanup;
1694
        }
1695 1696 1697

        VIR_FREE(vm->def->consoles[i]->source.data.file.path);
        vm->def->consoles[i]->source.data.file.path = ttyPath;
1698 1699 1700 1701 1702 1703

        VIR_FREE(vm->def->consoles[i]->info.alias);
        if (virAsprintf(&vm->def->consoles[i]->info.alias, "console%zu", i) < 0) {
            virReportOOMError();
            goto cleanup;
        }
1704
    }
1705

1706
    if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0)
1707
        goto cleanup;
1708

1709
    /* Save the configuration for the controller */
1710
    if (virDomainSaveConfig(driver->stateDir, vm->def) < 0)
1711 1712
        goto cleanup;

1713
    if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT,
1714
             S_IRUSR|S_IWUSR)) < 0) {
1715
        virReportSystemError(errno,
1716
                             _("Failed to open '%s'"),
1717
                             logfile);
1718
        goto cleanup;
1719 1720
    }

1721 1722 1723 1724 1725 1726
    if (pipe(handshakefds) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to create pipe"));
        goto cleanup;
    }

1727 1728 1729
    if (!(cmd = lxcBuildControllerCmd(driver,
                                      vm,
                                      nveths, veths,
1730
                                      ttyFDs, nttyFDs,
E
Eric Blake 已提交
1731
                                      handshakefds[1])))
1732
        goto cleanup;
E
Eric Blake 已提交
1733 1734
    virCommandSetOutputFD(cmd, &logfd);
    virCommandSetErrorFD(cmd, &logfd);
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754

    /* Log timestamp */
    if ((timestamp = virTimestamp()) == NULL) {
        virReportOOMError();
        goto cleanup;
    }
    if (safewrite(logfd, timestamp, strlen(timestamp)) < 0 ||
        safewrite(logfd, START_POSTFIX, strlen(START_POSTFIX)) < 0) {
        VIR_WARN("Unable to write timestamp to logfile: %s",
                 virStrerror(errno, ebuf, sizeof ebuf));
    }
    VIR_FREE(timestamp);

    /* Log generated command line */
    virCommandWriteArgLog(cmd, logfd);
    if ((pos = lseek(logfd, 0, SEEK_END)) < 0)
        VIR_WARN("Unable to seek to end of logfile: %s",
                 virStrerror(errno, ebuf, sizeof ebuf));

    if (virCommandRun(cmd, NULL) < 0)
1755
        goto cleanup;
1756

1757 1758 1759 1760 1761
    if (VIR_CLOSE(handshakefds[1]) < 0) {
        virReportSystemError(errno, "%s", _("could not close handshake fd"));
        goto cleanup;
    }

1762 1763 1764
    /* Connect to the controller as a client *first* because
     * this will block until the child has written their
     * pid file out to disk */
1765
    if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0)
1766 1767
        goto cleanup;

1768
    /* And get its pid */
1769
    if ((r = virPidFileRead(driver->stateDir, vm->def->name, &vm->pid)) < 0) {
1770
        virReportSystemError(-r,
1771 1772
                             _("Failed to read pid file %s/%s.pid"),
                             driver->stateDir, vm->def->name);
1773
        goto cleanup;
1774
    }
1775

1776
    vm->def->id = vm->pid;
J
Jiri Denemark 已提交
1777
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
1778

1779 1780 1781 1782 1783 1784 1785 1786
    if (lxcContainerWaitForContinue(handshakefds[0]) < 0) {
        char out[1024];

        if (!(lxcReadLogOutput(vm, logfile, pos, out, 1024) < 0)) {
            lxcError(VIR_ERR_INTERNAL_ERROR,
                     _("guest failed to start: %s"), out);
        }

1787
        goto error;
1788 1789
    }

1790 1791
    if ((priv->monitorWatch = virEventAddHandle(
             priv->monitor,
1792 1793
             VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
             lxcMonitorEvent,
1794
             vm, NULL)) < 0) {
1795
        goto error;
1796
    }
1797

1798 1799
    if (autoDestroy &&
        lxcProcessAutoDestroyAdd(driver, vm, conn) < 0)
1800
        goto error;
1801

1802 1803 1804 1805 1806
    /*
     * Again, need to save the live configuration, because the function
     * requires vm->def->id != -1 to save tty info surely.
     */
    if (virDomainSaveConfig(driver->stateDir, vm->def) < 0)
1807
        goto error;
1808

1809
    if (virDomainObjSetDefTransient(driver->caps, vm, false) < 0)
1810
        goto error;
1811

O
Osier Yang 已提交
1812 1813
    /* Write domain status to disk. */
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
1814
        goto error;
O
Osier Yang 已提交
1815

1816 1817 1818
    rc = 0;

cleanup:
1819 1820
    if (rc != 0 && !err)
        err = virSaveLastError();
1821
    virCommandFree(cmd);
1822 1823 1824 1825
    if (VIR_CLOSE(logfd) < 0) {
        virReportSystemError(errno, "%s", _("could not close logfile"));
        rc = -1;
    }
1826 1827
    for (i = 0 ; i < nveths ; i++) {
        if (rc != 0)
1828
            ignore_value(virNetDevVethDelete(veths[i]));
1829 1830
        VIR_FREE(veths[i]);
    }
1831
    if (rc != 0) {
1832
        VIR_FORCE_CLOSE(priv->monitor);
1833 1834
        virDomainConfVMNWFilterTeardown(vm);
    }
1835 1836
    for (i = 0 ; i < nttyFDs ; i++)
        VIR_FORCE_CLOSE(ttyFDs[i]);
1837
    VIR_FREE(ttyFDs);
1838 1839
    VIR_FORCE_CLOSE(handshakefds[0]);
    VIR_FORCE_CLOSE(handshakefds[1]);
1840
    VIR_FREE(logfile);
1841 1842 1843

    if (err) {
        virSetError(err);
1844
        virFreeError(err);
1845 1846
    }

1847
    return rc;
1848 1849 1850 1851 1852

error:
    err = virSaveLastError();
    lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
    goto cleanup;
1853 1854 1855
}

/**
1856
 * lxcDomainStartWithFlags:
1857
 * @dom: domain to start
1858
 * @flags: Must be 0 for now
1859 1860 1861 1862 1863
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1864
static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
1865
{
1866 1867
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1868
    virDomainEventPtr event = NULL;
1869
    int ret = -1;
1870

1871
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
1872

1873
    lxcDriverLock(driver);
1874
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1875
    if (!vm) {
1876 1877 1878 1879
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
1880 1881 1882
        goto cleanup;
    }

1883
    if ((vm->def->nets != NULL) && !(driver->have_netns)) {
1884
        lxcError(VIR_ERR_OPERATION_INVALID,
J
Jim Meyering 已提交
1885
                 "%s", _("System lacks NETNS support"));
1886 1887 1888
        goto cleanup;
    }

1889 1890 1891 1892 1893 1894
    if (virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is already running"));
        goto cleanup;
    }

1895 1896 1897
    ret = lxcVmStart(dom->conn, driver, vm,
                     (flags & VIR_DOMAIN_START_AUTODESTROY),
                     VIR_DOMAIN_RUNNING_BOOTED);
1898

1899
    if (ret == 0) {
1900 1901 1902
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
1903 1904 1905 1906
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
1907

1908
cleanup:
1909 1910
    if (vm)
        virDomainObjUnlock(vm);
1911 1912
    if (event)
        lxcDomainEventQueue(driver, event);
1913
    lxcDriverUnlock(driver);
1914
    return ret;
1915 1916
}

1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929
/**
 * lxcDomainStart:
 * @dom: domain to start
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcDomainStart(virDomainPtr dom)
{
    return lxcDomainStartWithFlags(dom, 0);
}

1930 1931 1932 1933
/**
 * lxcDomainCreateAndStart:
 * @conn: pointer to connection
 * @xml: XML definition of domain
1934
 * @flags: Must be 0 for now
1935 1936 1937 1938 1939 1940 1941 1942
 *
 * Creates a domain based on xml and starts it
 *
 * Returns 0 on success or -1 in case of error
 */
static virDomainPtr
lxcDomainCreateAndStart(virConnectPtr conn,
                        const char *xml,
1943
                        unsigned int flags) {
1944
    lxc_driver_t *driver = conn->privateData;
1945
    virDomainObjPtr vm = NULL;
1946
    virDomainDefPtr def;
1947
    virDomainPtr dom = NULL;
1948
    virDomainEventPtr event = NULL;
1949

1950
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
1951

1952
    lxcDriverLock(driver);
1953
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1954
                                        1 << VIR_DOMAIN_VIRT_LXC,
1955
                                        VIR_DOMAIN_XML_INACTIVE)))
1956
        goto cleanup;
1957

1958 1959
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
1960

1961
    if ((def->nets != NULL) && !(driver->have_netns)) {
1962
        lxcError(VIR_ERR_CONFIG_UNSUPPORTED,
J
Jim Meyering 已提交
1963
                 "%s", _("System lacks NETNS support"));
1964
        goto cleanup;
1965 1966
    }

1967

1968
    if (!(vm = virDomainAssignDef(driver->caps,
1969
                                  &driver->domains, def, false)))
1970 1971
        goto cleanup;
    def = NULL;
1972

1973 1974 1975
    if (lxcVmStart(conn, driver, vm,
                   (flags & VIR_DOMAIN_START_AUTODESTROY),
                   VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1976
        virDomainAuditStart(vm, "booted", false);
1977
        virDomainRemoveInactive(&driver->domains, vm);
1978
        vm = NULL;
1979
        goto cleanup;
1980 1981
    }

1982 1983 1984
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1985
    virDomainAuditStart(vm, "booted", true);
1986

1987
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1988
    if (dom)
1989 1990
        dom->id = vm->def->id;

1991 1992
cleanup:
    virDomainDefFree(def);
1993 1994
    if (vm)
        virDomainObjUnlock(vm);
1995 1996
    if (event)
        lxcDomainEventQueue(driver, event);
1997
    lxcDriverUnlock(driver);
1998 1999 2000
    return dom;
}

2001 2002

static int
2003 2004 2005 2006
lxcDomainEventRegister(virConnectPtr conn,
                       virConnectDomainEventCallback callback,
                       void *opaque,
                       virFreeCallback freecb)
2007 2008 2009 2010 2011
{
    lxc_driver_t *driver = conn->privateData;
    int ret;

    lxcDriverLock(driver);
2012 2013
    ret = virDomainEventCallbackListAdd(conn,
                                        driver->domainEventState->callbacks,
2014
                                        callback, opaque, freecb);
2015
    lxcDriverUnlock(driver);
2016

2017
    return ret;
2018 2019
}

2020

2021
static int
2022 2023
lxcDomainEventDeregister(virConnectPtr conn,
                         virConnectDomainEventCallback callback)
2024 2025 2026 2027 2028
{
    lxc_driver_t *driver = conn->privateData;
    int ret;

    lxcDriverLock(driver);
2029 2030 2031
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
2032 2033 2034 2035 2036
    lxcDriverUnlock(driver);

    return ret;
}

2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050

static int
lxcDomainEventRegisterAny(virConnectPtr conn,
                          virDomainPtr dom,
                          int eventID,
                          virConnectDomainEventGenericCallback callback,
                          void *opaque,
                          virFreeCallback freecb)
{
    lxc_driver_t *driver = conn->privateData;
    int ret;

    lxcDriverLock(driver);
    ret = virDomainEventCallbackListAddID(conn,
2051
                                          driver->domainEventState->callbacks,
2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067
                                          dom, eventID,
                                          callback, opaque, freecb);
    lxcDriverUnlock(driver);

    return ret;
}


static int
lxcDomainEventDeregisterAny(virConnectPtr conn,
                            int callbackID)
{
    lxc_driver_t *driver = conn->privateData;
    int ret;

    lxcDriverLock(driver);
2068 2069 2070
    ret = virDomainEventStateDeregisterAny(conn,
                                           driver->domainEventState,
                                           callbackID);
2071 2072 2073 2074 2075 2076
    lxcDriverUnlock(driver);

    return ret;
}


2077 2078
static void lxcDomainEventDispatchFunc(virConnectPtr conn,
                                       virDomainEventPtr event,
2079
                                       virConnectDomainEventGenericCallback cb,
2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096
                                       void *cbopaque,
                                       void *opaque)
{
    lxc_driver_t *driver = opaque;

    /* Drop the lock whle dispatching, for sake of re-entrancy */
    lxcDriverUnlock(driver);
    virDomainEventDispatchDefaultFunc(conn, event, cb, cbopaque, NULL);
    lxcDriverLock(driver);
}


static void lxcDomainEventFlush(int timer ATTRIBUTE_UNUSED, void *opaque)
{
    lxc_driver_t *driver = opaque;

    lxcDriverLock(driver);
2097 2098 2099
    virDomainEventStateFlush(driver->domainEventState,
                             lxcDomainEventDispatchFunc,
                             driver);
2100 2101 2102 2103 2104 2105 2106 2107
    lxcDriverUnlock(driver);
}


/* driver must be locked before calling */
static void lxcDomainEventQueue(lxc_driver_t *driver,
                                 virDomainEventPtr event)
{
2108
    virDomainEventStateQueue(driver->domainEventState, event);
2109
}
2110 2111

/**
2112
 * lxcDomainDestroyFlags:
2113
 * @dom: pointer to domain to destroy
2114
 * @flags: an OR'ed set of virDomainDestroyFlags
2115 2116 2117 2118 2119
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
2120 2121 2122
static int
lxcDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
2123
{
2124 2125
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2126
    virDomainEventPtr event = NULL;
2127
    int ret = -1;
2128

2129 2130
    virCheckFlags(0, -1);

2131
    lxcDriverLock(driver);
2132
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2133
    if (!vm) {
2134 2135 2136 2137
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
2138
        goto cleanup;
2139 2140
    }

2141 2142 2143 2144 2145 2146
    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is not running"));
        goto cleanup;
    }

J
Jiri Denemark 已提交
2147
    ret = lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
2148 2149 2150
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
2151
    virDomainAuditStop(vm, "destroyed");
2152 2153 2154 2155
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
2156 2157

cleanup:
2158 2159
    if (vm)
        virDomainObjUnlock(vm);
2160 2161
    if (event)
        lxcDomainEventQueue(driver, event);
2162
    lxcDriverUnlock(driver);
2163
    return ret;
2164
}
2165

2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179
/**
 * lxcDomainDestroy:
 * @dom: pointer to domain to destroy
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
static int
lxcDomainDestroy(virDomainPtr dom)
{
    return lxcDomainDestroyFlags(dom, 0);
}

2180 2181 2182 2183 2184
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

2185
    if (virRun(argv, &ip_rc) < 0 ||
2186 2187
        !(WIFEXITED(ip_rc) && (WEXITSTATUS(ip_rc) != 255)))
        return 0;
2188

2189 2190
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
2191

2192
    return 1;
2193 2194
}

2195

2196 2197 2198 2199 2200 2201
struct lxcAutostartData {
    lxc_driver_t *driver;
    virConnectPtr conn;
};

static void
2202
lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
2203 2204 2205 2206 2207 2208
{
    virDomainObjPtr vm = payload;
    const struct lxcAutostartData *data = opaque;

    virDomainObjLock(vm);
    if (vm->autostart &&
D
Daniel P. Berrange 已提交
2209
        !virDomainObjIsActive(vm)) {
2210
        int ret = lxcVmStart(data->conn, data->driver, vm, false,
J
Jiri Denemark 已提交
2211
                             VIR_DOMAIN_RUNNING_BOOTED);
2212
        virDomainAuditStart(vm, "booted", ret >= 0);
2213 2214
        if (ret < 0) {
            virErrorPtr err = virGetLastError();
2215
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229
                      vm->def->name,
                      err ? err->message : "");
        } else {
            virDomainEventPtr event =
                virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
            if (event)
                lxcDomainEventQueue(data->driver, event);
        }
    }
    virDomainObjUnlock(vm);
}

2230 2231 2232 2233 2234 2235 2236 2237 2238 2239
static void
lxcAutostartConfigs(lxc_driver_t *driver) {
    /* XXX: Figure out a better way todo this. The domain
     * startup code needs a connection handle in order
     * to lookup the bridge associated with a virtual
     * network
     */
    virConnectPtr conn = virConnectOpen("lxc:///");
    /* Ignoring NULL conn which is mostly harmless here */

2240 2241
    struct lxcAutostartData data = { driver, conn };

2242
    lxcDriverLock(driver);
2243
    virHashForEach(driver->domains.objs, lxcAutostartDomain, &data);
2244 2245 2246 2247 2248 2249
    lxcDriverUnlock(driver);

    if (conn)
        virConnectClose(conn);
}

2250
static void
2251
lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
2252 2253 2254
{
    virDomainObjPtr vm = payload;
    lxc_driver_t *driver = opaque;
2255
    lxcDomainObjPrivatePtr priv;
2256 2257

    virDomainObjLock(vm);
2258
    VIR_DEBUG("Reconnect %d %d %d\n", vm->def->id, vm->pid, vm->state.state);
2259 2260

    priv = vm->privateData;
2261 2262 2263

    if (vm->pid != 0) {
        vm->def->id = vm->pid;
J
Jiri Denemark 已提交
2264 2265
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNKNOWN);
2266

2267 2268 2269
        if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0)
            goto error;

2270 2271 2272 2273
        if ((priv->monitorWatch = virEventAddHandle(
                 priv->monitor,
                 VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
                 lxcMonitorEvent,
2274 2275
                 vm, NULL)) < 0)
            goto error;
2276 2277
    } else {
        vm->def->id = -1;
2278
        VIR_FORCE_CLOSE(priv->monitor);
2279 2280 2281 2282
    }

cleanup:
    virDomainObjUnlock(vm);
2283 2284 2285 2286 2287 2288
    return;

error:
    lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
    virDomainAuditStop(vm, "failed");
    goto cleanup;
2289 2290
}

2291

2292
static int lxcStartup(int privileged)
D
Daniel Veillard 已提交
2293
{
2294
    char *ld;
2295
    int rc;
2296 2297 2298 2299 2300 2301

    /* Valgrind gets very annoyed when we clone containers, so
     * disable LXC when under valgrind
     * XXX remove this when valgrind is fixed
     */
    ld = getenv("LD_PRELOAD");
2302
    if (ld && strstr(ld, "vgpreload")) {
2303
        VIR_INFO("Running under valgrind, disabling driver");
2304 2305
        return 0;
    }
2306

2307
    /* Check that the user is root, silently disable if not */
2308
    if (!privileged) {
2309
        VIR_INFO("Not running privileged, disabling driver");
2310 2311 2312 2313 2314
        return 0;
    }

    /* Check that this is a container enabled kernel */
    if (lxcContainerAvailable(0) < 0) {
2315
        VIR_INFO("LXC support not available in this kernel, disabling driver");
2316
        return 0;
2317 2318
    }

2319
    if (VIR_ALLOC(lxc_driver) < 0) {
2320 2321
        return -1;
    }
2322 2323 2324 2325
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
2326
    lxcDriverLock(lxc_driver);
D
Daniel Veillard 已提交
2327

2328 2329 2330
    if (virDomainObjListInit(&lxc_driver->domains) < 0)
        goto cleanup;

2331 2332 2333 2334 2335
    lxc_driver->domainEventState = virDomainEventStateNew(lxcDomainEventFlush,
                                                          lxc_driver,
                                                          NULL,
                                                          true);
    if (!lxc_driver->domainEventState)
2336 2337
        goto cleanup;

A
Amy Griffis 已提交
2338
    lxc_driver->log_libvirtd = 0; /* by default log to container logfile */
2339
    lxc_driver->have_netns = lxcCheckNetNsSupport();
D
Daniel Veillard 已提交
2340

2341 2342
    rc = virCgroupForDriver("lxc", &lxc_driver->cgroup, privileged, 1);
    if (rc < 0) {
2343
        char buf[1024] ATTRIBUTE_UNUSED;
2344 2345 2346 2347 2348
        VIR_DEBUG("Unable to create cgroup for LXC driver: %s",
                  virStrerror(-rc, buf, sizeof(buf)));
        /* Don't abort startup. We will explicitly report to
         * the user when they try to start a VM
         */
2349 2350
    }

D
Daniel Veillard 已提交
2351
    /* Call function to load lxc driver configuration information */
2352 2353
    if (lxcLoadDriverConfig(lxc_driver) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
2354

2355 2356
    if ((lxc_driver->caps = lxcCapsInit()) == NULL)
        goto cleanup;
D
Daniel Veillard 已提交
2357

2358 2359 2360
    lxc_driver->caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc;
    lxc_driver->caps->privateDataFreeFunc = lxcDomainObjPrivateFree;

2361 2362 2363
    if (lxcProcessAutoDestroyInit(lxc_driver) < 0)
        goto cleanup;

O
Osier Yang 已提交
2364 2365 2366 2367 2368
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(lxc_driver->caps,
                                &lxc_driver->domains,
                                lxc_driver->stateDir,
                                NULL,
M
Matthias Bolte 已提交
2369 2370
                                1, 1 << VIR_DOMAIN_VIRT_LXC,
                                NULL, NULL) < 0)
O
Osier Yang 已提交
2371 2372 2373 2374 2375
        goto cleanup;

    virHashForEach(lxc_driver->domains.objs, lxcReconnectVM, lxc_driver);

    /* Then inactive persistent configs */
2376
    if (virDomainLoadAllConfigs(lxc_driver->caps,
2377 2378
                                &lxc_driver->domains,
                                lxc_driver->configDir,
2379
                                lxc_driver->autostartDir,
M
Matthias Bolte 已提交
2380 2381
                                0, 1 << VIR_DOMAIN_VIRT_LXC,
                                NULL, NULL) < 0)
2382
        goto cleanup;
2383

2384
    lxcDriverUnlock(lxc_driver);
2385 2386 2387

    lxcAutostartConfigs(lxc_driver);

D
Daniel Veillard 已提交
2388 2389
    return 0;

2390 2391 2392 2393
cleanup:
    lxcDriverUnlock(lxc_driver);
    lxcShutdown();
    return -1;
D
Daniel Veillard 已提交
2394 2395
}

2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    lxc_driver_t *driver = opaque;

    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            lxcDomainEventQueue(driver, event);
    }
}

/**
 * lxcReload:
 *
 * Function to restart the LXC driver, it will recheck the configuration
 * files and perform autostart
 */
static int
lxcReload(void) {
    if (!lxc_driver)
        return 0;

    lxcDriverLock(lxc_driver);
2422
    virDomainLoadAllConfigs(lxc_driver->caps,
2423 2424 2425
                            &lxc_driver->domains,
                            lxc_driver->configDir,
                            lxc_driver->autostartDir,
M
Matthias Bolte 已提交
2426 2427
                            0, 1 << VIR_DOMAIN_VIRT_LXC,
                            lxcNotifyLoadDomain, lxc_driver);
2428 2429 2430 2431 2432 2433 2434
    lxcDriverUnlock(lxc_driver);

    lxcAutostartConfigs(lxc_driver);

    return 0;
}

2435
static int lxcShutdown(void)
D
Daniel Veillard 已提交
2436
{
2437
    if (lxc_driver == NULL)
2438
        return(-1);
2439

2440
    lxcDriverLock(lxc_driver);
2441
    virDomainObjListDeinit(&lxc_driver->domains);
2442
    virDomainEventStateFree(lxc_driver->domainEventState);
2443

2444 2445
    lxcProcessAutoDestroyShutdown(lxc_driver);

2446 2447 2448 2449 2450 2451
    virCapabilitiesFree(lxc_driver->caps);
    VIR_FREE(lxc_driver->configDir);
    VIR_FREE(lxc_driver->autostartDir);
    VIR_FREE(lxc_driver->stateDir);
    VIR_FREE(lxc_driver->logDir);
    lxcDriverUnlock(lxc_driver);
2452
    virMutexDestroy(&lxc_driver->lock);
2453
    VIR_FREE(lxc_driver);
2454 2455 2456

    return 0;
}
D
Daniel Veillard 已提交
2457

2458 2459 2460 2461 2462 2463 2464 2465 2466
/**
 * lxcActive:
 *
 * Checks if the LXC daemon is active, i.e. has an active domain
 *
 * Returns 1 if active, 0 otherwise
 */
static int
lxcActive(void) {
2467
    int active;
2468

2469 2470
    if (lxc_driver == NULL)
        return(0);
2471

2472
    lxcDriverLock(lxc_driver);
2473
    active = virDomainObjListNumOfDomains(&lxc_driver->domains, 1);
2474
    lxcDriverUnlock(lxc_driver);
2475

2476
    return active;
D
Daniel Veillard 已提交
2477 2478
}

2479
static int lxcVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
D
Dan Smith 已提交
2480 2481 2482
{
    struct utsname ver;

2483
    uname(&ver);
D
Dan Smith 已提交
2484

2485
    if (virParseVersionString(ver.release, version, true) < 0) {
2486
        lxcError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
2487 2488 2489 2490 2491
        return -1;
    }

    return 0;
}
2492

2493 2494
static char *lxcGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
                                 int *nparams)
2495
{
2496 2497
    char *schedulerType = NULL;

2498 2499 2500
    if (nparams)
        *nparams = 1;

2501 2502 2503
    schedulerType = strdup("posix");

    if (schedulerType == NULL)
2504
        virReportOOMError();
2505 2506

    return schedulerType;
2507 2508
}

2509 2510 2511 2512 2513
static int
lxcSetSchedulerParametersFlags(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int nparams,
                               unsigned int flags)
2514
{
2515
    lxc_driver_t *driver = domain->conn->privateData;
2516
    int i;
2517 2518 2519
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
2520

2521 2522
    virCheckFlags(0, -1);

2523
    if (driver->cgroup == NULL)
2524 2525 2526 2527
        return -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
2528

2529
    if (vm == NULL) {
2530 2531 2532 2533
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
2534
        goto cleanup;
2535 2536
    }

2537
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
2538
        goto cleanup;
2539 2540

    for (i = 0; i < nparams; i++) {
2541
        virTypedParameterPtr param = &params[i];
2542

2543
        if (STRNEQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
2544 2545 2546 2547 2548
            lxcError(VIR_ERR_INVALID_ARG,
                     _("Invalid parameter `%s'"), param->field);
            goto cleanup;
        }

2549
        if (param->type != VIR_TYPED_PARAM_ULLONG) {
2550
            lxcError(VIR_ERR_INVALID_ARG, "%s",
2551
                 _("Invalid type for cpu_shares tunable, expected a 'ullong'"));
2552 2553
            goto cleanup;
        }
2554

2555 2556 2557 2558
        int rc = virCgroupSetCpuShares(group, params[i].value.ul);
        if (rc != 0) {
            virReportSystemError(-rc, _("failed to set cpu_shares=%llu"),
                                 params[i].value.ul);
2559
            goto cleanup;
2560
        }
2561 2562

        vm->def->cputune.shares = params[i].value.ul;
2563
    }
2564
    ret = 0;
2565

2566
cleanup:
2567
    lxcDriverUnlock(driver);
2568
    virCgroupFree(&group);
2569 2570
    if (vm)
        virDomainObjUnlock(vm);
2571
    return ret;
2572 2573
}

2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586
static int
lxcSetSchedulerParameters(virDomainPtr domain,
                          virTypedParameterPtr params,
                          int nparams)
{
    return lxcSetSchedulerParametersFlags(domain, params, nparams, 0);
}

static int
lxcGetSchedulerParametersFlags(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int *nparams,
                               unsigned int flags)
2587
{
2588
    lxc_driver_t *driver = domain->conn->privateData;
2589 2590
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
2591
    unsigned long long val;
2592
    int ret = -1;
2593

2594 2595
    virCheckFlags(0, -1);

2596
    if (driver->cgroup == NULL)
2597
        return -1;
2598

2599 2600 2601
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);

2602
    if (vm == NULL) {
2603 2604 2605 2606
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
2607
        goto cleanup;
2608 2609
    }

2610
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
2611
        goto cleanup;
2612

2613 2614
    if (virCgroupGetCpuShares(group, &val) != 0)
        goto cleanup;
2615
    params[0].value.ul = val;
2616 2617
    if (virStrcpyStatic(params[0].field,
                        VIR_DOMAIN_SCHEDULER_CPU_SHARES) == NULL) {
2618
        lxcError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
2619 2620 2621
                 "%s", _("Field cpu_shares too big for destination"));
        goto cleanup;
    }
2622
    params[0].type = VIR_TYPED_PARAM_ULLONG;
2623

2624
    *nparams = 1;
2625
    ret = 0;
2626

2627
cleanup:
2628
    lxcDriverUnlock(driver);
2629
    virCgroupFree(&group);
2630 2631
    if (vm)
        virDomainObjUnlock(vm);
2632
    return ret;
2633 2634
}

2635 2636 2637 2638 2639 2640 2641 2642
static int
lxcGetSchedulerParameters(virDomainPtr domain,
                          virTypedParameterPtr params,
                          int *nparams)
{
    return lxcGetSchedulerParametersFlags(domain, params, nparams, 0);
}

2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660
#ifdef __linux__
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path,
                        struct _virDomainInterfaceStats *stats)
{
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int i;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2661
        lxcError(VIR_ERR_NO_DOMAIN,
2662 2663 2664 2665 2666
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2667
        lxcError(VIR_ERR_OPERATION_INVALID,
2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681
                 "%s", _("Domain is not running"));
        goto cleanup;
    }

    /* Check the path is one of the domain's network interfaces. */
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
            STREQ(vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
    }

    if (ret == 0)
2682
        ret = linuxDomainInterfaceStats(path, stats);
2683
    else
2684
        lxcError(VIR_ERR_INVALID_ARG,
2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696
                 _("Invalid path, '%s' is not a known interface"), path);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}
#else
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path ATTRIBUTE_UNUSED,
                        struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
A
Alex Jia 已提交
2697
{
2698
    lxcError(VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__);
2699 2700 2701 2702
    return -1;
}
#endif

2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715
static int lxcDomainGetAutostart(virDomainPtr dom,
                                   int *autostart) {
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2716
        lxcError(VIR_ERR_NO_DOMAIN,
2717
                 _("No domain with matching uuid '%s'"), uuidstr);
2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742
        goto cleanup;
    }

    *autostart = vm->autostart;
    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

static int lxcDomainSetAutostart(virDomainPtr dom,
                                   int autostart) {
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2743
        lxcError(VIR_ERR_NO_DOMAIN,
2744
                 _("No domain with matching uuid '%s'"), uuidstr);
2745 2746 2747 2748
        goto cleanup;
    }

    if (!vm->persistent) {
2749
        lxcError(VIR_ERR_OPERATION_INVALID,
2750
                 "%s", _("Cannot set autostart for transient domain"));
2751 2752 2753 2754 2755
        goto cleanup;
    }

    autostart = (autostart != 0);

2756 2757 2758 2759
    if (vm->autostart == autostart) {
        ret = 0;
        goto cleanup;
    }
2760

2761
    configFile = virDomainConfigFile(driver->configDir,
2762 2763 2764
                                     vm->def->name);
    if (configFile == NULL)
        goto cleanup;
2765
    autostartLink = virDomainConfigFile(driver->autostartDir,
2766 2767 2768
                                        vm->def->name);
    if (autostartLink == NULL)
        goto cleanup;
2769

2770
    if (autostart) {
2771 2772
        if (virFileMakePath(driver->autostartDir) < 0) {
            virReportSystemError(errno,
2773 2774 2775
                                 _("Cannot create autostart directory %s"),
                                 driver->autostartDir);
            goto cleanup;
2776 2777
        }

2778
        if (symlink(configFile, autostartLink) < 0) {
2779
            virReportSystemError(errno,
2780 2781 2782 2783 2784 2785
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
            goto cleanup;
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2786
            virReportSystemError(errno,
2787 2788 2789 2790
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
            goto cleanup;
        }
2791
    }
2792 2793

    vm->autostart = autostart;
2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804
    ret = 0;

cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

R
Ryota Ozaki 已提交
2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815
static int lxcFreezeContainer(lxc_driver_t *driver, virDomainObjPtr vm)
{
    int timeout = 1000; /* In milliseconds */
    int check_interval = 1; /* In milliseconds */
    int exp = 10;
    int waited_time = 0;
    int ret = -1;
    char *state = NULL;
    virCgroupPtr cgroup = NULL;

    if (!(driver->cgroup &&
2816
          virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0))
R
Ryota Ozaki 已提交
2817 2818
        return -1;

2819 2820
    /* From here on, we know that cgroup != NULL.  */

R
Ryota Ozaki 已提交
2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841
    while (waited_time < timeout) {
        int r;
        /*
         * Writing "FROZEN" to the "freezer.state" freezes the group,
         * i.e., the container, temporarily transiting "FREEZING" state.
         * Once the freezing is completed, the state of the group transits
         * to "FROZEN".
         * (see linux-2.6/Documentation/cgroups/freezer-subsystem.txt)
         */
        r = virCgroupSetFreezerState(cgroup, "FROZEN");

        /*
         * Returning EBUSY explicitly indicates that the group is
         * being freezed but incomplete and other errors are true
         * errors.
         */
        if (r < 0 && r != -EBUSY) {
            VIR_DEBUG("Writing freezer.state failed with errno: %d", r);
            goto error;
        }
        if (r == -EBUSY)
2842
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881

        /*
         * Unfortunately, returning 0 (success) is likely to happen
         * even when the freezing has not been completed. Sometimes
         * the state of the group remains "FREEZING" like when
         * returning -EBUSY and even worse may never transit to
         * "FROZEN" even if writing "FROZEN" again.
         *
         * So we don't trust the return value anyway and always
         * decide that the freezing has been complete only with
         * the state actually transit to "FROZEN".
         */
        usleep(check_interval * 1000);

        r = virCgroupGetFreezerState(cgroup, &state);

        if (r < 0) {
            VIR_DEBUG("Reading freezer.state failed with errno: %d", r);
            goto error;
        }
        VIR_DEBUG("Read freezer.state: %s", state);

        if (STREQ(state, "FROZEN")) {
            ret = 0;
            goto cleanup;
        }

        waited_time += check_interval;
        /*
         * Increasing check_interval exponentially starting with
         * small initial value treats nicely two cases; One is
         * a container is under no load and waiting for long period
         * makes no sense. The other is under heavy load. The container
         * may stay longer time in FREEZING or never transit to FROZEN.
         * In that case, eager polling will just waste CPU time.
         */
        check_interval *= exp;
        VIR_FREE(state);
    }
2882
    VIR_DEBUG("lxcFreezeContainer timeout");
R
Ryota Ozaki 已提交
2883 2884 2885 2886 2887 2888 2889 2890 2891 2892
error:
    /*
     * If timeout or an error on reading the state occurs,
     * activate the group again and return an error.
     * This is likely to fall the group back again gracefully.
     */
    virCgroupSetFreezerState(cgroup, "THAWED");
    ret = -1;

cleanup:
2893
    virCgroupFree(&cgroup);
R
Ryota Ozaki 已提交
2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910
    VIR_FREE(state);
    return ret;
}

static int lxcDomainSuspend(virDomainPtr dom)
{
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainEventPtr event = NULL;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2911
        lxcError(VIR_ERR_NO_DOMAIN,
2912
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2913 2914 2915
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2916
    if (!virDomainObjIsActive(vm)) {
2917
        lxcError(VIR_ERR_OPERATION_INVALID,
2918
                 "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2919 2920 2921
        goto cleanup;
    }

J
Jiri Denemark 已提交
2922
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2923
        if (lxcFreezeContainer(driver, vm) < 0) {
2924
            lxcError(VIR_ERR_OPERATION_FAILED,
2925
                     "%s", _("Suspend operation failed"));
R
Ryota Ozaki 已提交
2926 2927
            goto cleanup;
        }
J
Jiri Denemark 已提交
2928
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
2929 2930 2931 2932 2933 2934

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

2935
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975
        goto cleanup;
    ret = 0;

cleanup:
    if (event)
        lxcDomainEventQueue(driver, event);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

static int lxcUnfreezeContainer(lxc_driver_t *driver, virDomainObjPtr vm)
{
    int ret;
    virCgroupPtr cgroup = NULL;

    if (!(driver->cgroup &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0))
        return -1;

    ret = virCgroupSetFreezerState(cgroup, "THAWED");

    virCgroupFree(&cgroup);
    return ret;
}

static int lxcDomainResume(virDomainPtr dom)
{
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainEventPtr event = NULL;
    int ret = -1;

    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2976
        lxcError(VIR_ERR_NO_DOMAIN,
2977
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2978 2979 2980
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2981
    if (!virDomainObjIsActive(vm)) {
2982
        lxcError(VIR_ERR_OPERATION_INVALID,
2983
                 "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2984 2985 2986
        goto cleanup;
    }

J
Jiri Denemark 已提交
2987
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2988
        if (lxcUnfreezeContainer(driver, vm) < 0) {
2989
            lxcError(VIR_ERR_OPERATION_FAILED,
2990
                     "%s", _("Resume operation failed"));
R
Ryota Ozaki 已提交
2991 2992
            goto cleanup;
        }
J
Jiri Denemark 已提交
2993 2994
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
2995 2996 2997 2998 2999 3000

        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

3001
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013
        goto cleanup;
    ret = 0;

cleanup:
    if (event)
        lxcDomainEventQueue(driver, event);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

3014 3015
static int
lxcDomainOpenConsole(virDomainPtr dom,
3016
                      const char *dev_name,
3017 3018 3019 3020 3021 3022 3023 3024
                      virStreamPtr st,
                      unsigned int flags)
{
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
3025
    size_t i;
3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043

    virCheckFlags(0, -1);

    lxcDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("domain is not running"));
        goto cleanup;
    }

3044
    if (dev_name) {
3045 3046 3047 3048 3049 3050 3051
        for (i = 0 ; i < vm->def->nconsoles ; i++) {
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
3052
    } else {
3053 3054
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
3055 3056 3057 3058 3059
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
3060 3061 3062
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("cannot find console device '%s'"),
                 dev_name ? dev_name : _("default"));
3063 3064 3065
        goto cleanup;
    }

3066
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
3067
        lxcError(VIR_ERR_INTERNAL_ERROR,
3068
                 _("character device %s is not using a PTY"), dev_name);
3069 3070 3071
        goto cleanup;
    }

3072
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
3073
                            0, 0, O_RDWR) < 0)
3074 3075 3076 3077 3078 3079 3080 3081 3082 3083
        goto cleanup;

    ret = 0;
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110
static int
lxcVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
                   virHashIterator iter, void *data)
{
    virHashForEach(lxc_driver->domains.objs, iter, data);

    return 0;
}

static void
lxcVMDriverLock(void)
{
    lxcDriverLock(lxc_driver);
}

static void
lxcVMDriverUnlock(void)
{
    lxcDriverUnlock(lxc_driver);
}

static virNWFilterCallbackDriver lxcCallbackDriver = {
    .name = "LXC",
    .vmFilterRebuild = lxcVMFilterRebuild,
    .vmDriverLock = lxcVMDriverLock,
    .vmDriverUnlock = lxcVMDriverUnlock,
};
R
Ryota Ozaki 已提交
3111

D
Daniel Veillard 已提交
3112 3113
/* Function Tables */
static virDriver lxcDriver = {
3114 3115
    .no = VIR_DRV_LXC,
    .name = "LXC",
3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130
    .open = lxcOpen, /* 0.4.2 */
    .close = lxcClose, /* 0.4.2 */
    .version = lxcVersion, /* 0.4.6 */
    .getHostname = virGetHostname, /* 0.6.3 */
    .nodeGetInfo = nodeGetInfo, /* 0.6.5 */
    .getCapabilities = lxcGetCapabilities, /* 0.6.5 */
    .listDomains = lxcListDomains, /* 0.4.2 */
    .numOfDomains = lxcNumDomains, /* 0.4.2 */
    .domainCreateXML = lxcDomainCreateAndStart, /* 0.4.4 */
    .domainLookupByID = lxcDomainLookupByID, /* 0.4.2 */
    .domainLookupByUUID = lxcDomainLookupByUUID, /* 0.4.2 */
    .domainLookupByName = lxcDomainLookupByName, /* 0.4.2 */
    .domainSuspend = lxcDomainSuspend, /* 0.7.2 */
    .domainResume = lxcDomainResume, /* 0.7.2 */
    .domainDestroy = lxcDomainDestroy, /* 0.4.4 */
3131
    .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146
    .domainGetOSType = lxcGetOSType, /* 0.4.2 */
    .domainGetMaxMemory = lxcDomainGetMaxMemory, /* 0.7.2 */
    .domainSetMaxMemory = lxcDomainSetMaxMemory, /* 0.7.2 */
    .domainSetMemory = lxcDomainSetMemory, /* 0.7.2 */
    .domainSetMemoryParameters = lxcDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = lxcDomainGetMemoryParameters, /* 0.8.5 */
    .domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
    .domainGetState = lxcDomainGetState, /* 0.9.2 */
    .domainGetXMLDesc = lxcDomainGetXMLDesc, /* 0.4.2 */
    .listDefinedDomains = lxcListDefinedDomains, /* 0.4.2 */
    .numOfDefinedDomains = lxcNumDefinedDomains, /* 0.4.2 */
    .domainCreate = lxcDomainStart, /* 0.4.4 */
    .domainCreateWithFlags = lxcDomainStartWithFlags, /* 0.8.2 */
    .domainDefineXML = lxcDomainDefine, /* 0.4.2 */
    .domainUndefine = lxcDomainUndefine, /* 0.4.2 */
3147
    .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
3148 3149 3150 3151
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
    .domainGetSchedulerType = lxcGetSchedulerType, /* 0.5.0 */
    .domainGetSchedulerParameters = lxcGetSchedulerParameters, /* 0.5.0 */
3152
    .domainGetSchedulerParametersFlags = lxcGetSchedulerParametersFlags, /* 0.9.2 */
3153
    .domainSetSchedulerParameters = lxcSetSchedulerParameters, /* 0.5.0 */
3154
    .domainSetSchedulerParametersFlags = lxcSetSchedulerParametersFlags, /* 0.9.2 */
3155
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
3156
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
3157
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169
    .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.6.5 */
    .domainEventRegister = lxcDomainEventRegister, /* 0.7.0 */
    .domainEventDeregister = lxcDomainEventDeregister, /* 0.7.0 */
    .isEncrypted = lxcIsEncrypted, /* 0.7.3 */
    .isSecure = lxcIsSecure, /* 0.7.3 */
    .domainIsActive = lxcDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = lxcDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = lxcDomainIsUpdated, /* 0.8.6 */
    .domainEventRegisterAny = lxcDomainEventRegisterAny, /* 0.8.0 */
    .domainEventDeregisterAny = lxcDomainEventDeregisterAny, /* 0.8.0 */
    .domainOpenConsole = lxcDomainOpenConsole, /* 0.8.6 */
D
Daniel Veillard 已提交
3170 3171
};

3172
static virStateDriver lxcStateDriver = {
3173
    .name = "LXC",
3174 3175 3176
    .initialize = lxcStartup,
    .cleanup = lxcShutdown,
    .active = lxcActive,
3177
    .reload = lxcReload,
3178 3179
};

D
Daniel Veillard 已提交
3180 3181 3182
int lxcRegister(void)
{
    virRegisterDriver(&lxcDriver);
3183
    virRegisterStateDriver(&lxcStateDriver);
3184
    virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
D
Daniel Veillard 已提交
3185 3186
    return 0;
}