lxc_driver.c 84.0 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 47
#include "bridge.h"
#include "veth.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"
D
Daniel Veillard 已提交
57

58 59
#define VIR_FROM_THIS VIR_FROM_LXC

60 61
#define START_POSTFIX ": starting up\n"

62 63
#define LXC_NB_MEM_PARAM  3

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


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

/* Functions */

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

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
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);
}


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

112

D
Daniel Veillard 已提交
113 114
static virDrvOpenStatus lxcOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
115
                                unsigned int flags)
D
Daniel Veillard 已提交
116
{
E
Eric Blake 已提交
117 118
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

D
Daniel Veillard 已提交
119
    /* Verify uri was specified */
120
    if (conn->uri == NULL) {
121 122
        if (lxc_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
123

124 125
        conn->uri = xmlParseURI("lxc:///");
        if (!conn->uri) {
126
            virReportOOMError();
127 128
            return VIR_DRV_OPEN_ERROR;
        }
129 130 131 132 133 134 135 136 137 138
    } 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 */
139 140
        if (conn->uri->path != NULL &&
            STRNEQ(conn->uri->path, "/")) {
141
            lxcError(VIR_ERR_INTERNAL_ERROR,
142
                     _("Unexpected LXC URI path '%s', try lxc:///"),
143 144 145
                     conn->uri->path);
            return VIR_DRV_OPEN_ERROR;
        }
D
Daniel Veillard 已提交
146

147 148
        /* URI was good, but driver isn't active */
        if (lxc_driver == NULL) {
149
            lxcError(VIR_ERR_INTERNAL_ERROR,
150
                     "%s", _("lxc state driver is not active"));
151 152 153
            return VIR_DRV_OPEN_ERROR;
        }
    }
154

155
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
156 157 158 159 160 161

    return VIR_DRV_OPEN_SUCCESS;
}

static int lxcClose(virConnectPtr conn)
{
162 163 164
    lxc_driver_t *driver = conn->privateData;

    lxcDriverLock(driver);
165 166
    virDomainEventCallbackListRemoveConn(conn,
                                         driver->domainEventState->callbacks);
167 168
    lxcDriverUnlock(driver);

169 170
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
171 172
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

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


188 189 190 191 192 193
static char *lxcGetCapabilities(virConnectPtr conn) {
    lxc_driver_t *driver = conn->privateData;
    char *xml;

    lxcDriverLock(driver);
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
194
        virReportOOMError();
195 196 197 198 199 200
    lxcDriverUnlock(driver);

    return xml;
}


D
Daniel Veillard 已提交
201 202 203
static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
                                        int id)
{
204 205 206
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
207

208
    lxcDriverLock(driver);
209
    vm = virDomainFindByID(&driver->domains, id);
210 211
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
212
    if (!vm) {
213 214
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching id %d"), id);
215
        goto cleanup;
D
Daniel Veillard 已提交
216 217 218
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
219
    if (dom)
D
Daniel Veillard 已提交
220 221
        dom->id = vm->def->id;

222
cleanup:
223 224
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
225 226 227 228 229 230
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
231 232 233
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
234

235
    lxcDriverLock(driver);
236
    vm = virDomainFindByUUID(&driver->domains, uuid);
237 238
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
239
    if (!vm) {
240 241 242 243
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
244
        goto cleanup;
D
Daniel Veillard 已提交
245 246 247
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
248
    if (dom)
D
Daniel Veillard 已提交
249 250
        dom->id = vm->def->id;

251
cleanup:
252 253
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
254 255 256 257 258 259
    return dom;
}

static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
                                          const char *name)
{
260 261 262
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
263

264
    lxcDriverLock(driver);
265
    vm = virDomainFindByName(&driver->domains, name);
266
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
267
    if (!vm) {
268 269
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching name '%s'"), name);
270
        goto cleanup;
D
Daniel Veillard 已提交
271 272 273
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
274
    if (dom)
D
Daniel Veillard 已提交
275 276
        dom->id = vm->def->id;

277
cleanup:
278 279
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
280 281 282
    return dom;
}

283 284 285 286 287 288 289 290 291 292 293

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) {
294 295 296 297
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
        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) {
319 320 321 322
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
323 324 325 326 327 328 329 330 331 332
        goto cleanup;
    }
    ret = obj->persistent;

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

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
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;
}
356

357
static int lxcListDomains(virConnectPtr conn, int *ids, int nids) {
358
    lxc_driver_t *driver = conn->privateData;
359
    int n;
360

361
    lxcDriverLock(driver);
362
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
363
    lxcDriverUnlock(driver);
364

365
    return n;
D
Daniel Veillard 已提交
366
}
367

368
static int lxcNumDomains(virConnectPtr conn) {
369
    lxc_driver_t *driver = conn->privateData;
370
    int n;
371

372
    lxcDriverLock(driver);
373
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
374
    lxcDriverUnlock(driver);
375

376
    return n;
D
Daniel Veillard 已提交
377 378 379
}

static int lxcListDefinedDomains(virConnectPtr conn,
380
                                 char **const names, int nnames) {
381
    lxc_driver_t *driver = conn->privateData;
382
    int n;
383

384
    lxcDriverLock(driver);
385
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
386
    lxcDriverUnlock(driver);
387

388
    return n;
D
Daniel Veillard 已提交
389 390 391
}


392
static int lxcNumDefinedDomains(virConnectPtr conn) {
393
    lxc_driver_t *driver = conn->privateData;
394
    int n;
395

396
    lxcDriverLock(driver);
397
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
398
    lxcDriverUnlock(driver);
399

400
    return n;
D
Daniel Veillard 已提交
401 402
}

403 404


D
Daniel Veillard 已提交
405 406
static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml)
{
407 408
    lxc_driver_t *driver = conn->privateData;
    virDomainDefPtr def = NULL;
409
    virDomainObjPtr vm = NULL;
410
    virDomainPtr dom = NULL;
411
    virDomainEventPtr event = NULL;
412
    int dupVM;
D
Daniel Veillard 已提交
413

414
    lxcDriverLock(driver);
415
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
416
                                        1 << VIR_DOMAIN_VIRT_LXC,
417
                                        VIR_DOMAIN_XML_INACTIVE)))
418
        goto cleanup;
D
Daniel Veillard 已提交
419

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

423
    if ((def->nets != NULL) && !(driver->have_netns)) {
424
        lxcError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
425
                 "%s", _("System lacks NETNS support"));
426
        goto cleanup;
427 428
    }

429
    if (!(vm = virDomainAssignDef(driver->caps,
430
                                  &driver->domains, def, false)))
431 432
        goto cleanup;
    def = NULL;
433
    vm->persistent = 1;
D
Daniel Veillard 已提交
434

435
    if (virDomainSaveConfig(driver->configDir,
436
                            vm->newDef ? vm->newDef : vm->def) < 0) {
437
        virDomainRemoveInactive(&driver->domains, vm);
438
        vm = NULL;
439
        goto cleanup;
D
Daniel Veillard 已提交
440 441
    }

442 443
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
444
                                     !dupVM ?
445 446 447
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

D
Daniel Veillard 已提交
448
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
449
    if (dom)
D
Daniel Veillard 已提交
450 451
        dom->id = vm->def->id;

452 453
cleanup:
    virDomainDefFree(def);
454 455
    if (vm)
        virDomainObjUnlock(vm);
456 457
    if (event)
        lxcDomainEventQueue(driver, event);
458
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
459 460 461
    return dom;
}

462 463
static int lxcDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
D
Daniel Veillard 已提交
464
{
465 466
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
467
    virDomainEventPtr event = NULL;
468
    int ret = -1;
D
Daniel Veillard 已提交
469

470 471
    virCheckFlags(0, -1);

472
    lxcDriverLock(driver);
473
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
474
    if (!vm) {
475 476 477 478
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
479
        goto cleanup;
D
Daniel Veillard 已提交
480 481
    }

D
Daniel P. Berrange 已提交
482
    if (virDomainObjIsActive(vm)) {
483
        lxcError(VIR_ERR_OPERATION_INVALID,
484
                 "%s", _("Cannot delete active domain"));
485
        goto cleanup;
D
Daniel Veillard 已提交
486 487
    }

488
    if (!vm->persistent) {
489
        lxcError(VIR_ERR_OPERATION_INVALID,
490
                 "%s", _("Cannot undefine transient domain"));
491
        goto cleanup;
492
    }
D
Daniel Veillard 已提交
493

494
    if (virDomainDeleteConfig(driver->configDir,
495
                              driver->autostartDir,
496 497
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
498

499 500 501 502
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

503
    virDomainRemoveInactive(&driver->domains, vm);
504
    vm = NULL;
505
    ret = 0;
D
Daniel Veillard 已提交
506

507
cleanup:
508 509
    if (vm)
        virDomainObjUnlock(vm);
510 511
    if (event)
        lxcDomainEventQueue(driver, event);
512
    lxcDriverUnlock(driver);
513
    return ret;
D
Daniel Veillard 已提交
514 515
}

516 517 518 519 520
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
521 522 523
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
524 525
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
526
    virCgroupPtr cgroup = NULL;
527
    int ret = -1, rc;
D
Daniel Veillard 已提交
528

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

D
Daniel Veillard 已提交
532
    if (!vm) {
533 534 535 536
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
537
        goto cleanup;
D
Daniel Veillard 已提交
538 539
    }

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

D
Daniel P. Berrange 已提交
542
    if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) {
D
Daniel Veillard 已提交
543
        info->cpuTime = 0;
544
        info->memory = vm->def->mem.cur_balloon;
D
Daniel Veillard 已提交
545
    } else {
546
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
547
            lxcError(VIR_ERR_INTERNAL_ERROR,
548
                     _("Unable to get cgroup for %s"), vm->def->name);
549 550 551 552
            goto cleanup;
        }

        if (virCgroupGetCpuacctUsage(cgroup, &(info->cpuTime)) < 0) {
553
            lxcError(VIR_ERR_OPERATION_FAILED,
554
                     "%s", _("Cannot read cputime for domain"));
R
Ryota Ozaki 已提交
555 556
            goto cleanup;
        }
557
        if ((rc = virCgroupGetMemoryUsage(cgroup, &(info->memory))) < 0) {
558
            lxcError(VIR_ERR_OPERATION_FAILED,
559
                     "%s", _("Cannot read memory usage for domain"));
560 561 562 563 564 565
            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;
566
        }
D
Daniel Veillard 已提交
567 568
    }

569
    info->maxMem = vm->def->mem.max_balloon;
D
Daniel Veillard 已提交
570
    info->nrVirtCpu = 1;
571
    ret = 0;
D
Daniel Veillard 已提交
572

573
cleanup:
574
    lxcDriverUnlock(driver);
575 576
    if (cgroup)
        virCgroupFree(&cgroup);
577 578
    if (vm)
        virDomainObjUnlock(vm);
579
    return ret;
D
Daniel Veillard 已提交
580 581
}

582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
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 已提交
606
    *state = virDomainObjGetState(vm, reason);
607 608 609 610 611 612 613 614
    ret = 0;

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

615
static char *lxcGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
616
{
617 618 619
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
620

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

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

633 634
    ret = strdup(vm->def->os.type);

635
    if (ret == NULL)
636
        virReportOOMError();
637

638
cleanup:
639 640
    if (vm)
        virDomainObjUnlock(vm);
641
    return ret;
D
Daniel Veillard 已提交
642 643
}

R
Ryota Ozaki 已提交
644 645 646 647 648 649 650 651 652 653 654 655 656
/* 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);
657
        lxcError(VIR_ERR_NO_DOMAIN,
658
                         _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
659 660 661
        goto cleanup;
    }

662
    ret = vm->def->mem.max_balloon;
R
Ryota Ozaki 已提交
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681

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);
682
        lxcError(VIR_ERR_NO_DOMAIN,
683
                         _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
684 685 686
        goto cleanup;
    }

687
    if (newmax < vm->def->mem.cur_balloon) {
688
        lxcError(VIR_ERR_INVALID_ARG,
689
                         "%s", _("Cannot set max memory lower than current memory"));
R
Ryota Ozaki 已提交
690 691 692
        goto cleanup;
    }

693
    vm->def->mem.max_balloon = newmax;
R
Ryota Ozaki 已提交
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
    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);
714
        lxcError(VIR_ERR_NO_DOMAIN,
715
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
716 717 718
        goto cleanup;
    }

719
    if (newmem > vm->def->mem.max_balloon) {
720
        lxcError(VIR_ERR_INVALID_ARG,
721
                 "%s", _("Cannot set memory higher than max memory"));
R
Ryota Ozaki 已提交
722 723 724
        goto cleanup;
    }

725 726 727 728 729
    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is not running"));
        goto cleanup;
    }
730

731 732 733 734 735
    if (driver->cgroup == NULL) {
        lxcError(VIR_ERR_NO_SUPPORT,
                 "%s", _("cgroups must be configured on the host"));
        goto cleanup;
    }
R
Ryota Ozaki 已提交
736

737 738 739 740
    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 已提交
741
    }
742 743 744 745 746 747 748

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

R
Ryota Ozaki 已提交
749 750 751 752 753 754 755 756 757 758
    ret = 0;

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

759
static int lxcDomainSetMemoryParameters(virDomainPtr dom,
760
                                        virTypedParameterPtr params,
761
                                        int nparams,
E
Eric Blake 已提交
762
                                        unsigned int flags)
763 764 765 766 767 768 769
{
    lxc_driver_t *driver = dom->conn->privateData;
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

E
Eric Blake 已提交
770 771
    virCheckFlags(0, -1);

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
    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++) {
791
        virTypedParameterPtr param = &params[i];
792 793 794

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            int rc;
795
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
796 797 798 799 800 801 802 803 804 805 806 807 808 809
                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;
810
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
811 812 813 814 815 816 817 818 819 820 821 822
                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;
            }
823
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
824
            int rc;
825
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
826 827 828 829 830 831
                lxcError(VIR_ERR_INVALID_ARG, "%s",
                         _("invalid type for swap_hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

832
            rc = virCgroupSetMemSwapHardLimit(cgroup, params[i].value.ul);
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
            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;
}

858
static int lxcDomainGetMemoryParameters(virDomainPtr dom,
859
                                        virTypedParameterPtr params,
860
                                        int *nparams,
E
Eric Blake 已提交
861
                                        unsigned int flags)
862 863 864 865 866
{
    lxc_driver_t *driver = dom->conn->privateData;
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
867
    unsigned long long val;
868 869 870
    int ret = -1;
    int rc;

E
Eric Blake 已提交
871 872
    virCheckFlags(0, -1);

873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
    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;
    }
890
    if ((*nparams) < LXC_NB_MEM_PARAM) {
891 892 893 894 895 896 897 898 899 900 901
        lxcError(VIR_ERR_INVALID_ARG,
                 "%s", _("Invalid parameter count"));
        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;
    }

902
    for (i = 0; i < LXC_NB_MEM_PARAM; i++) {
903
        virTypedParameterPtr param = &params[i];
904 905
        val = 0;
        param->value.ul = 0;
906
        param->type = VIR_TYPED_PARAM_ULLONG;
907 908 909 910 911 912 913

        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"));
914
                goto cleanup;
915 916 917 918
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) {
                lxcError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field memory hard limit too long for destination"));
919
                goto cleanup;
920 921 922 923 924 925 926 927 928
            }
            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"));
929
                goto cleanup;
930 931 932 933
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) {
                lxcError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field memory soft limit too long for destination"));
934
                goto cleanup;
935 936 937 938 939
            }
            param->value.ul = val;
            break;

        case 2: /* fill swap hard limit here */
940
            rc = virCgroupGetMemSwapHardLimit(cgroup, &val);
941 942 943
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
944
                goto cleanup;
945
            }
946
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT) == NULL) {
947 948
                lxcError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field swap hard limit too long for destination"));
949
                goto cleanup;
950 951 952 953 954 955 956 957 958 959
            }
            param->value.ul = val;
            break;

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

960
    *nparams = LXC_NB_MEM_PARAM;
961 962
    ret = 0;

963 964 965 966 967 968 969 970 971
cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

972
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
973
                                 unsigned int flags)
D
Daniel Veillard 已提交
974
{
975 976 977
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
978

979 980
    /* Flags checked by virDomainDefFormat */

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

D
Daniel Veillard 已提交
985
    if (!vm) {
986 987 988 989
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
990
        goto cleanup;
D
Daniel Veillard 已提交
991 992
    }

993
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
994 995 996 997
                             vm->newDef ? vm->newDef : vm->def,
                             flags);

cleanup:
998 999
    if (vm)
        virDomainObjUnlock(vm);
1000
    return ret;
D
Daniel Veillard 已提交
1001 1002
}

1003 1004 1005

/**
 * lxcVmCleanup:
1006 1007
 * @driver: pointer to driver structure
 * @vm: pointer to VM to clean up
J
Jiri Denemark 已提交
1008
 * @reason: reason for switching the VM to shutoff state
1009
 *
1010
 * Cleanout resources associated with the now dead VM
1011 1012
 *
 */
1013
static void lxcVmCleanup(lxc_driver_t *driver,
J
Jiri Denemark 已提交
1014 1015
                         virDomainObjPtr vm,
                         virDomainShutoffReason reason)
1016
{
D
Dan Smith 已提交
1017
    virCgroupPtr cgroup;
1018
    int i;
1019
    lxcDomainObjPrivatePtr priv = vm->privateData;
1020

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
    /* 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);
    }

1031
    virEventRemoveHandle(priv->monitorWatch);
1032
    VIR_FORCE_CLOSE(priv->monitor);
1033

1034
    virPidFileDelete(driver->stateDir, vm->def->name);
1035
    virDomainDeleteConfig(driver->stateDir, NULL, vm);
1036

J
Jiri Denemark 已提交
1037
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
1038 1039
    vm->pid = -1;
    vm->def->id = -1;
1040 1041
    priv->monitor = -1;
    priv->monitorWatch = -1;
1042

1043 1044 1045
    for (i = 0 ; i < vm->def->nnets ; i++) {
        vethInterfaceUpOrDown(vm->def->nets[i]->ifname, 0);
        vethDelete(vm->def->nets[i]->ifname);
1046 1047
    }

1048 1049
    virDomainConfVMNWFilterTeardown(vm);

1050 1051
    if (driver->cgroup &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) {
D
Dan Smith 已提交
1052 1053 1054 1055
        virCgroupRemove(cgroup);
        virCgroupFree(&cgroup);
    }

1056 1057 1058 1059 1060 1061
    if (vm->newDef) {
        virDomainDefFree(vm->def);
        vm->def = vm->newDef;
        vm->def->id = -1;
        vm->newDef = NULL;
    }
1062 1063
}

1064 1065
/**
 * lxcSetupInterfaces:
1066
 * @conn: pointer to connection
1067
 * @def: pointer to virtual machine structure
1068 1069
 * @nveths: number of interfaces
 * @veths: interface names
1070 1071 1072 1073 1074 1075 1076 1077
 *
 * 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,
1078
                              virDomainDefPtr def,
1079 1080
                              unsigned int *nveths,
                              char ***veths)
1081
{
1082
    int rc = -1, i;
1083 1084
    char *bridge = NULL;
    brControl *brctl = NULL;
1085
    int ret;
1086

1087 1088 1089
    if ((ret = brInit(&brctl)) != 0) {
        virReportSystemError(ret, "%s",
                             _("Unable to initialize bridging"));
1090
        return -1;
1091
    }
1092

1093
    for (i = 0 ; i < def->nnets ; i++) {
1094 1095
        char *parentVeth;
        char *containerVeth = NULL;
1096

1097
        switch (def->nets[i]->type) {
1098 1099
        case VIR_DOMAIN_NET_TYPE_NETWORK:
        {
1100 1101 1102 1103
            virNetworkPtr network;

            network = virNetworkLookupByName(conn,
                                             def->nets[i]->data.network.name);
1104 1105 1106 1107 1108 1109 1110
            if (!network) {
                goto error_exit;
            }

            bridge = virNetworkGetBridgeName(network);

            virNetworkFree(network);
1111 1112 1113
            break;
        }
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
1114
            bridge = def->nets[i]->data.bridge.brname;
1115
            break;
S
Stefan Berger 已提交
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125

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

1128
        VIR_DEBUG("bridge: %s", bridge);
1129
        if (NULL == bridge) {
1130
            lxcError(VIR_ERR_INTERNAL_ERROR,
1131
                     "%s", _("Failed to get bridge for interface"));
1132 1133 1134
            goto error_exit;
        }

1135
        VIR_DEBUG("calling vethCreate()");
1136 1137
        parentVeth = def->nets[i]->ifname;
        if (vethCreate(&parentVeth, &containerVeth) < 0)
1138
            goto error_exit;
1139
        VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth);
1140

1141
        if (NULL == def->nets[i]->ifname) {
1142
            def->nets[i]->ifname = parentVeth;
1143
        }
1144

1145
        if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) {
1146
            virReportOOMError();
1147
            VIR_FREE(containerVeth);
1148
            goto error_exit;
1149
        }
1150
        (*veths)[(*nveths)] = containerVeth;
1151
        (*nveths)++;
1152

1153
        {
1154 1155
            char macaddr[VIR_MAC_STRING_BUFLEN];
            virFormatMacAddr(def->nets[i]->mac, macaddr);
1156
            if (setMacAddr(containerVeth, macaddr) < 0)
1157 1158 1159
                goto error_exit;
        }

1160
        if ((ret = brAddInterface(brctl, bridge, parentVeth)) != 0) {
E
Eric Blake 已提交
1161
            virReportSystemError(ret,
1162
                                 _("Failed to add %s device to %s"),
1163
                                 parentVeth, bridge);
1164 1165 1166
            goto error_exit;
        }

1167
        if (vethInterfaceUpOrDown(parentVeth, 1) < 0)
1168
            goto error_exit;
1169 1170 1171 1172

        if (def->nets[i]->filter &&
            virDomainConfNWFilterInstantiate(conn, def->nets[i]) < 0)
            goto error_exit;
1173 1174 1175 1176 1177
    }

    rc = 0;

error_exit:
1178
    brShutdown(brctl);
1179 1180 1181
    return rc;
}

1182

1183
static int lxcMonitorClient(lxc_driver_t * driver,
1184
                            virDomainObjPtr vm)
1185
{
1186 1187 1188
    char *sockpath = NULL;
    int fd;
    struct sockaddr_un addr;
1189

1190 1191
    if (virAsprintf(&sockpath, "%s/%s.sock",
                    driver->stateDir, vm->def->name) < 0) {
1192
        virReportOOMError();
1193 1194 1195 1196
        return -1;
    }

    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
1197
        virReportSystemError(errno, "%s",
1198
                             _("Failed to create client socket"));
1199
        goto error;
1200 1201
    }

1202 1203
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
C
Chris Lalancette 已提交
1204
    if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) {
1205
        lxcError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
1206 1207 1208
                 _("Socket path %s too big for destination"), sockpath);
        goto error;
    }
1209 1210

    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1211
        virReportSystemError(errno, "%s",
1212
                             _("Failed to connect to client socket"));
1213
        goto error;
1214 1215
    }

1216 1217
    VIR_FREE(sockpath);
    return fd;
1218

1219 1220
error:
    VIR_FREE(sockpath);
1221
    VIR_FORCE_CLOSE(fd);
1222 1223 1224 1225
    return -1;
}


1226
static int lxcVmTerminate(lxc_driver_t *driver,
J
Jiri Denemark 已提交
1227 1228
                          virDomainObjPtr vm,
                          virDomainShutoffReason reason)
1229
{
1230 1231
    virCgroupPtr group = NULL;
    int rc;
1232

1233
    if (vm->pid <= 0) {
1234
        lxcError(VIR_ERR_INTERNAL_ERROR,
1235
                 _("Invalid PID %d for container"), vm->pid);
1236 1237 1238
        return -1;
    }

1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
    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
         */
1257
    }
1258

J
Jiri Denemark 已提交
1259
    lxcVmCleanup(driver, vm, reason);
1260

1261
    rc = 0;
1262

1263 1264 1265
cleanup:
    virCgroupFree(&group);
    return rc;
1266
}
1267

1268 1269
static void lxcMonitorEvent(int watch,
                            int fd,
1270 1271 1272
                            int events ATTRIBUTE_UNUSED,
                            void *data)
{
1273 1274
    lxc_driver_t *driver = lxc_driver;
    virDomainObjPtr vm = data;
1275
    virDomainEventPtr event = NULL;
1276
    lxcDomainObjPrivatePtr priv;
1277

1278
    lxcDriverLock(driver);
1279 1280
    virDomainObjLock(vm);
    lxcDriverUnlock(driver);
1281

1282 1283 1284
    priv = vm->privateData;

    if (priv->monitor != fd || priv->monitorWatch != watch) {
1285
        virEventRemoveHandle(watch);
1286
        goto cleanup;
1287 1288
    }

J
Jiri Denemark 已提交
1289
    if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) {
1290
        virEventRemoveHandle(watch);
1291 1292 1293 1294
    } else {
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
1295
        virDomainAuditStop(vm, "shutdown");
1296
    }
1297 1298 1299 1300
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1301 1302

cleanup:
1303 1304
    if (vm)
        virDomainObjUnlock(vm);
1305 1306
    if (event) {
        lxcDriverLock(driver);
1307
        lxcDomainEventQueue(driver, event);
1308 1309
        lxcDriverUnlock(driver);
    }
1310 1311 1312
}


1313 1314 1315 1316 1317 1318
static virCommandPtr
lxcBuildControllerCmd(lxc_driver_t *driver,
                      virDomainObjPtr vm,
                      int nveths,
                      char **veths,
                      int appPty,
1319 1320
                      int logfile,
                      int handshakefd)
1321 1322
{
    int i;
A
Amy Griffis 已提交
1323 1324
    char *filterstr;
    char *outputstr;
1325 1326 1327 1328 1329 1330 1331 1332 1333
    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 已提交
1334 1335 1336

    if (virLogGetNbFilters() > 0) {
        filterstr = virLogGetFilters();
1337 1338 1339 1340 1341 1342
        if (!filterstr) {
            virReportOOMError();
            goto cleanup;
        }

        virCommandAddEnvPair(cmd, "LIBVIRT_LOG_FILTERS", filterstr);
A
Amy Griffis 已提交
1343 1344 1345
        VIR_FREE(filterstr);
    }

A
Amy Griffis 已提交
1346 1347 1348
    if (driver->log_libvirtd) {
        if (virLogGetNbOutputs() > 0) {
            outputstr = virLogGetOutputs();
1349 1350 1351 1352 1353 1354
            if (!outputstr) {
                virReportOOMError();
                goto cleanup;
            }

            virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr);
A
Amy Griffis 已提交
1355 1356 1357
            VIR_FREE(outputstr);
        }
    } else {
1358 1359 1360
        virCommandAddEnvFormat(cmd,
                               "LIBVIRT_LOG_OUTPUTS=%d:stderr",
                               virLogGetDefaultPriority());
A
Amy Griffis 已提交
1361 1362
    }

1363 1364
    virCommandAddArgList(cmd, "--name", vm->def->name, "--console", NULL);
    virCommandAddArgFormat(cmd, "%d", appPty);
1365 1366
    virCommandAddArg(cmd, "--handshake");
    virCommandAddArgFormat(cmd, "%d", handshakefd);
1367
    virCommandAddArg(cmd, "--background");
1368 1369

    for (i = 0 ; i < nveths ; i++) {
1370
        virCommandAddArgList(cmd, "--veth", veths[i], NULL);
1371 1372
    }

1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
    /* 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;
    }

1389
    virCommandPreserveFD(cmd, appPty);
1390
    virCommandPreserveFD(cmd, handshakefd);
1391 1392
    virCommandSetOutputFD(cmd, &logfile);
    virCommandSetErrorFD(cmd, &logfile);
1393

1394
    return cmd;
A
Amy Griffis 已提交
1395
cleanup:
1396
    virCommandFree(cmd);
1397
    return NULL;
1398 1399
}

1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471
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;
}
1472

1473 1474 1475 1476 1477
/**
 * lxcVmStart:
 * @conn: pointer to connection
 * @driver: pointer to driver structure
 * @vm: pointer to virtual machine structure
J
Jiri Denemark 已提交
1478
 * @reason: reason for switching vm to running state
1479 1480 1481 1482 1483 1484 1485
 *
 * 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 已提交
1486 1487
                      virDomainObjPtr vm,
                      virDomainRunningReason reason)
1488
{
1489
    int rc = -1, r;
1490 1491
    unsigned int i;
    int parentTty;
1492
    char *parentTtyPath = NULL;
1493 1494 1495 1496
    char *logfile = NULL;
    int logfd = -1;
    unsigned int nveths = 0;
    char **veths = NULL;
1497
    int handshakefds[2] = { -1, -1 };
1498 1499 1500 1501
    off_t pos = -1;
    char ebuf[1024];
    char *timestamp;
    virCommandPtr cmd = NULL;
1502
    lxcDomainObjPrivatePtr priv = vm->privateData;
1503

1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
    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;
    }

1529 1530
    if (virFileMakePath(driver->logDir) < 0) {
        virReportSystemError(errno,
1531
                             _("Cannot create log directory '%s'"),
1532
                             driver->logDir);
1533 1534
        return -1;
    }
1535

1536 1537
    if (virAsprintf(&logfile, "%s/%s.log",
                    driver->logDir, vm->def->name) < 0) {
1538
        virReportOOMError();
1539
        return -1;
1540 1541
    }

1542
    /* open parent tty */
1543
    if (virFileOpenTty(&parentTty, &parentTtyPath, 1) < 0) {
1544
        virReportSystemError(errno, "%s",
1545
                             _("Failed to allocate tty"));
1546 1547
        goto cleanup;
    }
1548
    if (vm->def->console &&
1549 1550 1551
        vm->def->console->source.type == VIR_DOMAIN_CHR_TYPE_PTY) {
        VIR_FREE(vm->def->console->source.data.file.path);
        vm->def->console->source.data.file.path = parentTtyPath;
1552 1553 1554
    } else {
        VIR_FREE(parentTtyPath);
    }
1555

1556
    if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0)
1557
        goto cleanup;
1558

1559
    /* Save the configuration for the controller */
1560
    if (virDomainSaveConfig(driver->stateDir, vm->def) < 0)
1561 1562
        goto cleanup;

1563
    if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT,
1564
             S_IRUSR|S_IWUSR)) < 0) {
1565
        virReportSystemError(errno,
1566
                             _("Failed to open '%s'"),
1567
                             logfile);
1568
        goto cleanup;
1569 1570
    }

1571 1572 1573 1574 1575 1576
    if (pipe(handshakefds) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to create pipe"));
        goto cleanup;
    }

1577 1578 1579
    if (!(cmd = lxcBuildControllerCmd(driver,
                                      vm,
                                      nveths, veths,
1580
                                      parentTty, logfd, handshakefds[1])))
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601
        goto cleanup;

    /* 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)
1602
        goto cleanup;
1603

1604 1605 1606 1607 1608
    if (VIR_CLOSE(handshakefds[1]) < 0) {
        virReportSystemError(errno, "%s", _("could not close handshake fd"));
        goto cleanup;
    }

1609 1610 1611
    /* Connect to the controller as a client *first* because
     * this will block until the child has written their
     * pid file out to disk */
1612
    if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0)
1613 1614
        goto cleanup;

1615
    /* And get its pid */
1616
    if ((r = virPidFileRead(driver->stateDir, vm->def->name, &vm->pid)) < 0) {
1617
        virReportSystemError(-r,
1618 1619
                             _("Failed to read pid file %s/%s.pid"),
                             driver->stateDir, vm->def->name);
1620
        goto cleanup;
1621
    }
1622

1623
    vm->def->id = vm->pid;
J
Jiri Denemark 已提交
1624
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
1625

1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637
    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);
        }

        lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
        goto cleanup;
    }

1638 1639
    if ((priv->monitorWatch = virEventAddHandle(
             priv->monitor,
1640 1641
             VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
             lxcMonitorEvent,
1642
             vm, NULL)) < 0) {
J
Jiri Denemark 已提交
1643
        lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
1644 1645
        goto cleanup;
    }
1646

1647 1648 1649 1650 1651 1652 1653
    /*
     * 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)
        goto cleanup;

1654
    if (virDomainObjSetDefTransient(driver->caps, vm, false) < 0)
1655 1656
        goto cleanup;

O
Osier Yang 已提交
1657 1658 1659 1660
    /* Write domain status to disk. */
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto cleanup;

1661 1662 1663
    rc = 0;

cleanup:
1664
    virCommandFree(cmd);
1665 1666 1667 1668
    if (VIR_CLOSE(logfd) < 0) {
        virReportSystemError(errno, "%s", _("could not close logfile"));
        rc = -1;
    }
1669 1670 1671 1672 1673
    for (i = 0 ; i < nveths ; i++) {
        if (rc != 0)
            vethDelete(veths[i]);
        VIR_FREE(veths[i]);
    }
1674
    if (rc != 0) {
1675
        VIR_FORCE_CLOSE(priv->monitor);
1676 1677
        virDomainConfVMNWFilterTeardown(vm);
    }
1678
    VIR_FORCE_CLOSE(parentTty);
1679 1680
    VIR_FORCE_CLOSE(handshakefds[0]);
    VIR_FORCE_CLOSE(handshakefds[1]);
1681
    VIR_FREE(logfile);
1682 1683 1684 1685
    return rc;
}

/**
1686
 * lxcDomainStartWithFlags:
1687
 * @dom: domain to start
1688
 * @flags: Must be 0 for now
1689 1690 1691 1692 1693
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1694
static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
1695
{
1696 1697
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1698
    virDomainEventPtr event = NULL;
1699
    int ret = -1;
1700

1701 1702
    virCheckFlags(0, -1);

1703
    lxcDriverLock(driver);
1704
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1705
    if (!vm) {
1706 1707 1708 1709
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
1710 1711 1712
        goto cleanup;
    }

1713
    if ((vm->def->nets != NULL) && !(driver->have_netns)) {
1714
        lxcError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
1715
                 "%s", _("System lacks NETNS support"));
1716 1717 1718
        goto cleanup;
    }

1719 1720 1721 1722 1723 1724
    if (virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is already running"));
        goto cleanup;
    }

J
Jiri Denemark 已提交
1725
    ret = lxcVmStart(dom->conn, driver, vm, VIR_DOMAIN_RUNNING_BOOTED);
1726

1727
    if (ret == 0) {
1728 1729 1730
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
1731 1732 1733 1734
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
1735

1736
cleanup:
1737 1738
    if (vm)
        virDomainObjUnlock(vm);
1739 1740
    if (event)
        lxcDomainEventQueue(driver, event);
1741
    lxcDriverUnlock(driver);
1742
    return ret;
1743 1744
}

1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
/**
 * 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);
}

1758 1759 1760 1761
/**
 * lxcDomainCreateAndStart:
 * @conn: pointer to connection
 * @xml: XML definition of domain
1762
 * @flags: Must be 0 for now
1763 1764 1765 1766 1767 1768 1769 1770
 *
 * 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,
1771
                        unsigned int flags) {
1772
    lxc_driver_t *driver = conn->privateData;
1773
    virDomainObjPtr vm = NULL;
1774
    virDomainDefPtr def;
1775
    virDomainPtr dom = NULL;
1776
    virDomainEventPtr event = NULL;
1777

1778 1779
    virCheckFlags(0, NULL);

1780
    lxcDriverLock(driver);
1781
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1782
                                        1 << VIR_DOMAIN_VIRT_LXC,
1783
                                        VIR_DOMAIN_XML_INACTIVE)))
1784
        goto cleanup;
1785

1786 1787
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
1788

1789
    if ((def->nets != NULL) && !(driver->have_netns)) {
1790
        lxcError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
1791
                 "%s", _("System lacks NETNS support"));
1792
        goto cleanup;
1793 1794
    }

1795

1796
    if (!(vm = virDomainAssignDef(driver->caps,
1797
                                  &driver->domains, def, false)))
1798 1799
        goto cleanup;
    def = NULL;
1800

J
Jiri Denemark 已提交
1801
    if (lxcVmStart(conn, driver, vm, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1802
        virDomainAuditStart(vm, "booted", false);
1803
        virDomainRemoveInactive(&driver->domains, vm);
1804
        vm = NULL;
1805
        goto cleanup;
1806 1807
    }

1808 1809 1810
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1811
    virDomainAuditStart(vm, "booted", true);
1812

1813
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1814
    if (dom)
1815 1816
        dom->id = vm->def->id;

1817 1818
cleanup:
    virDomainDefFree(def);
1819 1820
    if (vm)
        virDomainObjUnlock(vm);
1821 1822
    if (event)
        lxcDomainEventQueue(driver, event);
1823
    lxcDriverUnlock(driver);
1824 1825 1826
    return dom;
}

1827 1828

static int
1829 1830 1831 1832
lxcDomainEventRegister(virConnectPtr conn,
                       virConnectDomainEventCallback callback,
                       void *opaque,
                       virFreeCallback freecb)
1833 1834 1835 1836 1837
{
    lxc_driver_t *driver = conn->privateData;
    int ret;

    lxcDriverLock(driver);
1838 1839
    ret = virDomainEventCallbackListAdd(conn,
                                        driver->domainEventState->callbacks,
1840
                                        callback, opaque, freecb);
1841
    lxcDriverUnlock(driver);
1842

1843
    return ret;
1844 1845
}

1846

1847
static int
1848 1849
lxcDomainEventDeregister(virConnectPtr conn,
                         virConnectDomainEventCallback callback)
1850 1851 1852 1853 1854
{
    lxc_driver_t *driver = conn->privateData;
    int ret;

    lxcDriverLock(driver);
1855 1856 1857
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
1858 1859 1860 1861 1862
    lxcDriverUnlock(driver);

    return ret;
}

1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876

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,
1877
                                          driver->domainEventState->callbacks,
1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893
                                          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);
1894 1895 1896
    ret = virDomainEventStateDeregisterAny(conn,
                                           driver->domainEventState,
                                           callbackID);
1897 1898 1899 1900 1901 1902
    lxcDriverUnlock(driver);

    return ret;
}


1903 1904
static void lxcDomainEventDispatchFunc(virConnectPtr conn,
                                       virDomainEventPtr event,
1905
                                       virConnectDomainEventGenericCallback cb,
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922
                                       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);
1923 1924 1925
    virDomainEventStateFlush(driver->domainEventState,
                             lxcDomainEventDispatchFunc,
                             driver);
1926 1927 1928 1929 1930 1931 1932 1933
    lxcDriverUnlock(driver);
}


/* driver must be locked before calling */
static void lxcDomainEventQueue(lxc_driver_t *driver,
                                 virDomainEventPtr event)
{
1934
    virDomainEventStateQueue(driver->domainEventState, event);
1935
}
1936 1937

/**
1938
 * lxcDomainDestroyFlags:
1939
 * @dom: pointer to domain to destroy
1940
 * @flags: an OR'ed set of virDomainDestroyFlags
1941 1942 1943 1944 1945
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
1946 1947 1948
static int
lxcDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
1949
{
1950 1951
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1952
    virDomainEventPtr event = NULL;
1953
    int ret = -1;
1954

1955 1956
    virCheckFlags(0, -1);

1957
    lxcDriverLock(driver);
1958
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1959
    if (!vm) {
1960 1961 1962 1963
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
1964
        goto cleanup;
1965 1966
    }

1967 1968 1969 1970 1971 1972
    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is not running"));
        goto cleanup;
    }

J
Jiri Denemark 已提交
1973
    ret = lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1974 1975 1976
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1977
    virDomainAuditStop(vm, "destroyed");
1978 1979 1980 1981
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1982 1983

cleanup:
1984 1985
    if (vm)
        virDomainObjUnlock(vm);
1986 1987
    if (event)
        lxcDomainEventQueue(driver, event);
1988
    lxcDriverUnlock(driver);
1989
    return ret;
1990
}
1991

1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005
/**
 * 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);
}

2006 2007 2008 2009 2010
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

2011
    if (virRun(argv, &ip_rc) < 0 ||
2012 2013
        !(WIFEXITED(ip_rc) && (WEXITSTATUS(ip_rc) != 255)))
        return 0;
2014

2015 2016
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
2017

2018
    return 1;
2019 2020
}

2021

2022 2023 2024 2025 2026 2027
struct lxcAutostartData {
    lxc_driver_t *driver;
    virConnectPtr conn;
};

static void
2028
lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
2029 2030 2031 2032 2033 2034
{
    virDomainObjPtr vm = payload;
    const struct lxcAutostartData *data = opaque;

    virDomainObjLock(vm);
    if (vm->autostart &&
D
Daniel P. Berrange 已提交
2035
        !virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
2036 2037
        int ret = lxcVmStart(data->conn, data->driver, vm,
                             VIR_DOMAIN_RUNNING_BOOTED);
2038
        virDomainAuditStart(vm, "booted", ret >= 0);
2039 2040
        if (ret < 0) {
            virErrorPtr err = virGetLastError();
2041
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055
                      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);
}

2056 2057 2058 2059 2060 2061 2062 2063 2064 2065
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 */

2066 2067
    struct lxcAutostartData data = { driver, conn };

2068
    lxcDriverLock(driver);
2069
    virHashForEach(driver->domains.objs, lxcAutostartDomain, &data);
2070 2071 2072 2073 2074 2075
    lxcDriverUnlock(driver);

    if (conn)
        virConnectClose(conn);
}

2076
static void
2077
lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
2078 2079 2080
{
    virDomainObjPtr vm = payload;
    lxc_driver_t *driver = opaque;
2081
    lxcDomainObjPrivatePtr priv;
2082 2083

    virDomainObjLock(vm);
2084
    VIR_DEBUG("Reconnect %d %d %d\n", vm->def->id, vm->pid, vm->state.state);
2085 2086

    priv = vm->privateData;
2087 2088 2089

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

2093 2094 2095
        if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0)
            goto error;

2096 2097 2098 2099
        if ((priv->monitorWatch = virEventAddHandle(
                 priv->monitor,
                 VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
                 lxcMonitorEvent,
2100 2101
                 vm, NULL)) < 0)
            goto error;
2102 2103
    } else {
        vm->def->id = -1;
2104
        VIR_FORCE_CLOSE(priv->monitor);
2105 2106 2107 2108
    }

cleanup:
    virDomainObjUnlock(vm);
2109 2110 2111 2112 2113 2114
    return;

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

2117

2118
static int lxcStartup(int privileged)
D
Daniel Veillard 已提交
2119
{
2120
    char *ld;
2121
    int rc;
2122 2123 2124 2125 2126 2127

    /* 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");
2128
    if (ld && strstr(ld, "vgpreload")) {
2129
        VIR_INFO("Running under valgrind, disabling driver");
2130 2131
        return 0;
    }
2132

2133
    /* Check that the user is root, silently disable if not */
2134
    if (!privileged) {
2135
        VIR_INFO("Not running privileged, disabling driver");
2136 2137 2138 2139 2140
        return 0;
    }

    /* Check that this is a container enabled kernel */
    if (lxcContainerAvailable(0) < 0) {
2141
        VIR_INFO("LXC support not available in this kernel, disabling driver");
2142
        return 0;
2143 2144
    }

2145
    if (VIR_ALLOC(lxc_driver) < 0) {
2146 2147
        return -1;
    }
2148 2149 2150 2151
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
2152
    lxcDriverLock(lxc_driver);
D
Daniel Veillard 已提交
2153

2154 2155 2156
    if (virDomainObjListInit(&lxc_driver->domains) < 0)
        goto cleanup;

2157 2158 2159 2160 2161
    lxc_driver->domainEventState = virDomainEventStateNew(lxcDomainEventFlush,
                                                          lxc_driver,
                                                          NULL,
                                                          true);
    if (!lxc_driver->domainEventState)
2162 2163
        goto cleanup;

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

2167 2168 2169
    rc = virCgroupForDriver("lxc", &lxc_driver->cgroup, privileged, 1);
    if (rc < 0) {
        char buf[1024];
2170 2171 2172 2173 2174
        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
         */
2175 2176
    }

D
Daniel Veillard 已提交
2177
    /* Call function to load lxc driver configuration information */
2178 2179
    if (lxcLoadDriverConfig(lxc_driver) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
2180

2181 2182
    if ((lxc_driver->caps = lxcCapsInit()) == NULL)
        goto cleanup;
D
Daniel Veillard 已提交
2183

2184 2185 2186
    lxc_driver->caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc;
    lxc_driver->caps->privateDataFreeFunc = lxcDomainObjPrivateFree;

O
Osier Yang 已提交
2187 2188 2189 2190 2191
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(lxc_driver->caps,
                                &lxc_driver->domains,
                                lxc_driver->stateDir,
                                NULL,
M
Matthias Bolte 已提交
2192 2193
                                1, 1 << VIR_DOMAIN_VIRT_LXC,
                                NULL, NULL) < 0)
O
Osier Yang 已提交
2194 2195 2196 2197 2198
        goto cleanup;

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

    /* Then inactive persistent configs */
2199
    if (virDomainLoadAllConfigs(lxc_driver->caps,
2200 2201
                                &lxc_driver->domains,
                                lxc_driver->configDir,
2202
                                lxc_driver->autostartDir,
M
Matthias Bolte 已提交
2203 2204
                                0, 1 << VIR_DOMAIN_VIRT_LXC,
                                NULL, NULL) < 0)
2205
        goto cleanup;
2206

2207
    lxcDriverUnlock(lxc_driver);
2208 2209 2210

    lxcAutostartConfigs(lxc_driver);

D
Daniel Veillard 已提交
2211 2212
    return 0;

2213 2214 2215 2216
cleanup:
    lxcDriverUnlock(lxc_driver);
    lxcShutdown();
    return -1;
D
Daniel Veillard 已提交
2217 2218
}

2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244
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);
2245
    virDomainLoadAllConfigs(lxc_driver->caps,
2246 2247 2248
                            &lxc_driver->domains,
                            lxc_driver->configDir,
                            lxc_driver->autostartDir,
M
Matthias Bolte 已提交
2249 2250
                            0, 1 << VIR_DOMAIN_VIRT_LXC,
                            lxcNotifyLoadDomain, lxc_driver);
2251 2252 2253 2254 2255 2256 2257
    lxcDriverUnlock(lxc_driver);

    lxcAutostartConfigs(lxc_driver);

    return 0;
}

2258
static int lxcShutdown(void)
D
Daniel Veillard 已提交
2259
{
2260
    if (lxc_driver == NULL)
2261
        return(-1);
2262

2263
    lxcDriverLock(lxc_driver);
2264
    virDomainObjListDeinit(&lxc_driver->domains);
2265
    virDomainEventStateFree(lxc_driver->domainEventState);
2266

2267 2268 2269 2270 2271 2272
    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);
2273
    virMutexDestroy(&lxc_driver->lock);
2274
    VIR_FREE(lxc_driver);
2275 2276 2277

    return 0;
}
D
Daniel Veillard 已提交
2278

2279 2280 2281 2282 2283 2284 2285 2286 2287
/**
 * lxcActive:
 *
 * Checks if the LXC daemon is active, i.e. has an active domain
 *
 * Returns 1 if active, 0 otherwise
 */
static int
lxcActive(void) {
2288
    int active;
2289

2290 2291
    if (lxc_driver == NULL)
        return(0);
2292

2293
    lxcDriverLock(lxc_driver);
2294
    active = virDomainObjListNumOfDomains(&lxc_driver->domains, 1);
2295
    lxcDriverUnlock(lxc_driver);
2296

2297
    return active;
D
Daniel Veillard 已提交
2298 2299
}

2300
static int lxcVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
D
Dan Smith 已提交
2301 2302 2303
{
    struct utsname ver;

2304
    uname(&ver);
D
Dan Smith 已提交
2305

2306
    if (virParseVersionString(ver.release, version, true) < 0) {
2307
        lxcError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
2308 2309 2310 2311 2312
        return -1;
    }

    return 0;
}
2313

2314 2315
static char *lxcGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
                                 int *nparams)
2316
{
2317 2318
    char *schedulerType = NULL;

2319 2320 2321
    if (nparams)
        *nparams = 1;

2322 2323 2324
    schedulerType = strdup("posix");

    if (schedulerType == NULL)
2325
        virReportOOMError();
2326 2327

    return schedulerType;
2328 2329
}

2330 2331 2332 2333 2334
static int
lxcSetSchedulerParametersFlags(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int nparams,
                               unsigned int flags)
2335
{
2336
    lxc_driver_t *driver = domain->conn->privateData;
2337
    int i;
2338 2339 2340
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
2341

2342 2343
    virCheckFlags(0, -1);

2344
    if (driver->cgroup == NULL)
2345 2346 2347 2348
        return -1;

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

2350
    if (vm == NULL) {
2351 2352 2353 2354
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
2355
        goto cleanup;
2356 2357
    }

2358
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
2359
        goto cleanup;
2360 2361

    for (i = 0; i < nparams; i++) {
2362
        virTypedParameterPtr param = &params[i];
2363 2364 2365 2366 2367 2368 2369

        if (STRNEQ(param->field, "cpu_shares")) {
            lxcError(VIR_ERR_INVALID_ARG,
                     _("Invalid parameter `%s'"), param->field);
            goto cleanup;
        }

2370
        if (param->type != VIR_TYPED_PARAM_ULLONG) {
2371
            lxcError(VIR_ERR_INVALID_ARG, "%s",
2372
                 _("Invalid type for cpu_shares tunable, expected a 'ullong'"));
2373 2374
            goto cleanup;
        }
2375

2376 2377 2378 2379
        int rc = virCgroupSetCpuShares(group, params[i].value.ul);
        if (rc != 0) {
            virReportSystemError(-rc, _("failed to set cpu_shares=%llu"),
                                 params[i].value.ul);
2380
            goto cleanup;
2381
        }
2382 2383

        vm->def->cputune.shares = params[i].value.ul;
2384
    }
2385
    ret = 0;
2386

2387
cleanup:
2388
    lxcDriverUnlock(driver);
2389
    virCgroupFree(&group);
2390 2391
    if (vm)
        virDomainObjUnlock(vm);
2392
    return ret;
2393 2394
}

2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407
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)
2408
{
2409
    lxc_driver_t *driver = domain->conn->privateData;
2410 2411
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
2412
    unsigned long long val;
2413
    int ret = -1;
2414

2415 2416
    virCheckFlags(0, -1);

2417
    if (driver->cgroup == NULL)
2418
        return -1;
2419

2420
    if (*nparams < 1) {
2421
        lxcError(VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
2422
                 "%s", _("Invalid parameter count"));
2423
        return -1;
2424 2425
    }

2426 2427 2428
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);

2429
    if (vm == NULL) {
2430 2431 2432 2433
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
2434
        goto cleanup;
2435 2436
    }

2437
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
2438
        goto cleanup;
2439

2440 2441
    if (virCgroupGetCpuShares(group, &val) != 0)
        goto cleanup;
2442
    params[0].value.ul = val;
C
Chris Lalancette 已提交
2443
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
2444
        lxcError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
2445 2446 2447
                 "%s", _("Field cpu_shares too big for destination"));
        goto cleanup;
    }
2448
    params[0].type = VIR_TYPED_PARAM_ULLONG;
2449

2450
    *nparams = 1;
2451
    ret = 0;
2452

2453
cleanup:
2454
    lxcDriverUnlock(driver);
2455
    virCgroupFree(&group);
2456 2457
    if (vm)
        virDomainObjUnlock(vm);
2458
    return ret;
2459 2460
}

2461 2462 2463 2464 2465 2466 2467 2468
static int
lxcGetSchedulerParameters(virDomainPtr domain,
                          virTypedParameterPtr params,
                          int *nparams)
{
    return lxcGetSchedulerParametersFlags(domain, params, nparams, 0);
}

2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486
#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);
2487
        lxcError(VIR_ERR_NO_DOMAIN,
2488 2489 2490 2491 2492
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2493
        lxcError(VIR_ERR_OPERATION_INVALID,
2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507
                 "%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)
2508
        ret = linuxDomainInterfaceStats(path, stats);
2509
    else
2510
        lxcError(VIR_ERR_INVALID_ARG,
2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522
                 _("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)
2523
    lxcError(VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__);
2524 2525 2526 2527
    return -1;
}
#endif

2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540
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);
2541
        lxcError(VIR_ERR_NO_DOMAIN,
2542
                 _("No domain with matching uuid '%s'"), uuidstr);
2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567
        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);
2568
        lxcError(VIR_ERR_NO_DOMAIN,
2569
                 _("No domain with matching uuid '%s'"), uuidstr);
2570 2571 2572 2573
        goto cleanup;
    }

    if (!vm->persistent) {
2574
        lxcError(VIR_ERR_OPERATION_INVALID,
2575
                 "%s", _("Cannot set autostart for transient domain"));
2576 2577 2578 2579 2580
        goto cleanup;
    }

    autostart = (autostart != 0);

2581 2582 2583 2584
    if (vm->autostart == autostart) {
        ret = 0;
        goto cleanup;
    }
2585

2586
    configFile = virDomainConfigFile(driver->configDir,
2587 2588 2589
                                     vm->def->name);
    if (configFile == NULL)
        goto cleanup;
2590
    autostartLink = virDomainConfigFile(driver->autostartDir,
2591 2592 2593
                                        vm->def->name);
    if (autostartLink == NULL)
        goto cleanup;
2594

2595
    if (autostart) {
2596 2597
        if (virFileMakePath(driver->autostartDir) < 0) {
            virReportSystemError(errno,
2598 2599 2600
                                 _("Cannot create autostart directory %s"),
                                 driver->autostartDir);
            goto cleanup;
2601 2602
        }

2603
        if (symlink(configFile, autostartLink) < 0) {
2604
            virReportSystemError(errno,
2605 2606 2607 2608 2609 2610
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
            goto cleanup;
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2611
            virReportSystemError(errno,
2612 2613 2614 2615
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
            goto cleanup;
        }
2616
    }
2617 2618

    vm->autostart = autostart;
2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629
    ret = 0;

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

R
Ryota Ozaki 已提交
2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640
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 &&
2641
          virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0))
R
Ryota Ozaki 已提交
2642 2643
        return -1;

2644 2645
    /* From here on, we know that cgroup != NULL.  */

R
Ryota Ozaki 已提交
2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666
    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)
2667
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706

        /*
         * 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);
    }
2707
    VIR_DEBUG("lxcFreezeContainer timeout");
R
Ryota Ozaki 已提交
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717
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:
2718
    virCgroupFree(&cgroup);
R
Ryota Ozaki 已提交
2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735
    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);
2736
        lxcError(VIR_ERR_NO_DOMAIN,
2737
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2738 2739 2740
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2741
    if (!virDomainObjIsActive(vm)) {
2742
        lxcError(VIR_ERR_OPERATION_INVALID,
2743
                 "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2744 2745 2746
        goto cleanup;
    }

J
Jiri Denemark 已提交
2747
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2748
        if (lxcFreezeContainer(driver, vm) < 0) {
2749
            lxcError(VIR_ERR_OPERATION_FAILED,
2750
                     "%s", _("Suspend operation failed"));
R
Ryota Ozaki 已提交
2751 2752
            goto cleanup;
        }
J
Jiri Denemark 已提交
2753
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
2754 2755 2756 2757 2758 2759

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

2760
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800
        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);
2801
        lxcError(VIR_ERR_NO_DOMAIN,
2802
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2803 2804 2805
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2806
    if (!virDomainObjIsActive(vm)) {
2807
        lxcError(VIR_ERR_OPERATION_INVALID,
2808
                 "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2809 2810 2811
        goto cleanup;
    }

J
Jiri Denemark 已提交
2812
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2813
        if (lxcUnfreezeContainer(driver, vm) < 0) {
2814
            lxcError(VIR_ERR_OPERATION_FAILED,
2815
                     "%s", _("Resume operation failed"));
R
Ryota Ozaki 已提交
2816 2817
            goto cleanup;
        }
J
Jiri Denemark 已提交
2818 2819
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
2820 2821 2822 2823 2824 2825

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

2826
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838
        goto cleanup;
    ret = 0;

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

2839 2840 2841 2842 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 2882 2883 2884 2885
static int
lxcDomainOpenConsole(virDomainPtr dom,
                      const char *devname,
                      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;

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

    if (devname) {
        /* XXX support device aliases in future */
        lxcError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                 _("Named device aliases are not supported"));
        goto cleanup;
    } else {
        if (vm->def->console)
            chr = vm->def->console;
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
        lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
                 _("cannot find default console device"));
        goto cleanup;
    }

2886
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2887 2888 2889 2890 2891
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("character device %s is not using a PTY"), devname);
        goto cleanup;
    }

2892
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
2893
                            0, 0, O_RDWR) < 0)
2894 2895 2896 2897 2898 2899 2900 2901 2902 2903
        goto cleanup;

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

2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930
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 已提交
2931

D
Daniel Veillard 已提交
2932 2933
/* Function Tables */
static virDriver lxcDriver = {
2934 2935
    .no = VIR_DRV_LXC,
    .name = "LXC",
2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950
    .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 */
2951
    .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966
    .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 */
2967
    .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
2968 2969 2970 2971
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
    .domainGetSchedulerType = lxcGetSchedulerType, /* 0.5.0 */
    .domainGetSchedulerParameters = lxcGetSchedulerParameters, /* 0.5.0 */
2972
    .domainGetSchedulerParametersFlags = lxcGetSchedulerParametersFlags, /* 0.9.2 */
2973
    .domainSetSchedulerParameters = lxcSetSchedulerParameters, /* 0.5.0 */
2974
    .domainSetSchedulerParametersFlags = lxcSetSchedulerParametersFlags, /* 0.9.2 */
2975
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
2976
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
2977
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989
    .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 已提交
2990 2991
};

2992
static virStateDriver lxcStateDriver = {
2993
    .name = "LXC",
2994 2995 2996
    .initialize = lxcStartup,
    .cleanup = lxcShutdown,
    .active = lxcActive,
2997
    .reload = lxcReload,
2998 2999
};

D
Daniel Veillard 已提交
3000 3001 3002
int lxcRegister(void)
{
    virRegisterDriver(&lxcDriver);
3003
    virRegisterStateDriver(&lxcStateDriver);
3004
    virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
D
Daniel Veillard 已提交
3005 3006
    return 0;
}