lxc_driver.c 82.3 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"
52
#include "files.h"
53
#include "fdstream.h"
54
#include "domain_nwfilter.h"
D
Daniel Veillard 已提交
55

56 57
#define VIR_FROM_THIS VIR_FROM_LXC

58 59
#define START_POSTFIX ": starting up\n"

60 61
#define LXC_NB_MEM_PARAM  3

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


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

/* Functions */

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

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


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

110

D
Daniel Veillard 已提交
111 112 113 114 115
static virDrvOpenStatus lxcOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                int flags ATTRIBUTE_UNUSED)
{
    /* Verify uri was specified */
116
    if (conn->uri == NULL) {
117 118
        if (lxc_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
119

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

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

151
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
152 153 154 155 156 157

    return VIR_DRV_OPEN_SUCCESS;
}

static int lxcClose(virConnectPtr conn)
{
158 159 160
    lxc_driver_t *driver = conn->privateData;

    lxcDriverLock(driver);
161 162
    virDomainEventCallbackListRemoveConn(conn,
                                         driver->domainEventState->callbacks);
163 164
    lxcDriverUnlock(driver);

165 166
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
167 168
}

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183

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


184 185 186 187 188 189
static char *lxcGetCapabilities(virConnectPtr conn) {
    lxc_driver_t *driver = conn->privateData;
    char *xml;

    lxcDriverLock(driver);
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
190
        virReportOOMError();
191 192 193 194 195 196
    lxcDriverUnlock(driver);

    return xml;
}


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

204
    lxcDriverLock(driver);
205
    vm = virDomainFindByID(&driver->domains, id);
206 207
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
208
    if (!vm) {
209 210
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching id %d"), id);
211
        goto cleanup;
D
Daniel Veillard 已提交
212 213 214
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
215
    if (dom)
D
Daniel Veillard 已提交
216 217
        dom->id = vm->def->id;

218
cleanup:
219 220
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
221 222 223 224 225 226
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
227 228 229
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
230

231
    lxcDriverLock(driver);
232
    vm = virDomainFindByUUID(&driver->domains, uuid);
233 234
    lxcDriverUnlock(driver);

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

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
244
    if (dom)
D
Daniel Veillard 已提交
245 246
        dom->id = vm->def->id;

247
cleanup:
248 249
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
250 251 252 253 254 255
    return dom;
}

static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
                                          const char *name)
{
256 257 258
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
259

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

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
270
    if (dom)
D
Daniel Veillard 已提交
271 272
        dom->id = vm->def->id;

273
cleanup:
274 275
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
276 277 278
    return dom;
}

279 280 281 282 283 284 285 286 287 288 289

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

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

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
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;
}
352

353
static int lxcListDomains(virConnectPtr conn, int *ids, int nids) {
354
    lxc_driver_t *driver = conn->privateData;
355
    int n;
356

357
    lxcDriverLock(driver);
358
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
359
    lxcDriverUnlock(driver);
360

361
    return n;
D
Daniel Veillard 已提交
362
}
363

364
static int lxcNumDomains(virConnectPtr conn) {
365
    lxc_driver_t *driver = conn->privateData;
366
    int n;
367

368
    lxcDriverLock(driver);
369
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
370
    lxcDriverUnlock(driver);
371

372
    return n;
D
Daniel Veillard 已提交
373 374 375
}

static int lxcListDefinedDomains(virConnectPtr conn,
376
                                 char **const names, int nnames) {
377
    lxc_driver_t *driver = conn->privateData;
378
    int n;
379

380
    lxcDriverLock(driver);
381
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
382
    lxcDriverUnlock(driver);
383

384
    return n;
D
Daniel Veillard 已提交
385 386 387
}


388
static int lxcNumDefinedDomains(virConnectPtr conn) {
389
    lxc_driver_t *driver = conn->privateData;
390
    int n;
391

392
    lxcDriverLock(driver);
393
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
394
    lxcDriverUnlock(driver);
395

396
    return n;
D
Daniel Veillard 已提交
397 398
}

399 400


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

410
    lxcDriverLock(driver);
411
    if (!(def = virDomainDefParseString(driver->caps, xml,
412
                                        VIR_DOMAIN_XML_INACTIVE)))
413
        goto cleanup;
D
Daniel Veillard 已提交
414

415 416
   if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
417

418
    if ((def->nets != NULL) && !(driver->have_netns)) {
419
        lxcError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
420
                 "%s", _("System lacks NETNS support"));
421
        goto cleanup;
422 423
    }

424
    if (!(vm = virDomainAssignDef(driver->caps,
425
                                  &driver->domains, def, false)))
426 427
        goto cleanup;
    def = NULL;
428
    vm->persistent = 1;
D
Daniel Veillard 已提交
429

430
    if (virDomainSaveConfig(driver->configDir,
431
                            vm->newDef ? vm->newDef : vm->def) < 0) {
432
        virDomainRemoveInactive(&driver->domains, vm);
433
        vm = NULL;
434
        goto cleanup;
D
Daniel Veillard 已提交
435 436
    }

437 438
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
439
                                     !dupVM ?
440 441 442
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

D
Daniel Veillard 已提交
443
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
444
    if (dom)
D
Daniel Veillard 已提交
445 446
        dom->id = vm->def->id;

447 448
cleanup:
    virDomainDefFree(def);
449 450
    if (vm)
        virDomainObjUnlock(vm);
451 452
    if (event)
        lxcDomainEventQueue(driver, event);
453
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
454 455 456 457 458
    return dom;
}

static int lxcDomainUndefine(virDomainPtr dom)
{
459 460
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
461
    virDomainEventPtr event = NULL;
462
    int ret = -1;
D
Daniel Veillard 已提交
463

464
    lxcDriverLock(driver);
465
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
466
    if (!vm) {
467 468 469 470
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
471
        goto cleanup;
D
Daniel Veillard 已提交
472 473
    }

D
Daniel P. Berrange 已提交
474
    if (virDomainObjIsActive(vm)) {
475
        lxcError(VIR_ERR_OPERATION_INVALID,
476
                 "%s", _("Cannot delete active domain"));
477
        goto cleanup;
D
Daniel Veillard 已提交
478 479
    }

480
    if (!vm->persistent) {
481
        lxcError(VIR_ERR_OPERATION_INVALID,
482
                 "%s", _("Cannot undefine transient domain"));
483
        goto cleanup;
484
    }
D
Daniel Veillard 已提交
485

486
    if (virDomainDeleteConfig(driver->configDir,
487
                              driver->autostartDir,
488 489
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
490

491 492 493 494
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

495
    virDomainRemoveInactive(&driver->domains, vm);
496
    vm = NULL;
497
    ret = 0;
D
Daniel Veillard 已提交
498

499
cleanup:
500 501
    if (vm)
        virDomainObjUnlock(vm);
502 503
    if (event)
        lxcDomainEventQueue(driver, event);
504
    lxcDriverUnlock(driver);
505
    return ret;
D
Daniel Veillard 已提交
506 507 508 509 510
}

static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
511 512
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
513
    virCgroupPtr cgroup = NULL;
514
    int ret = -1, rc;
D
Daniel Veillard 已提交
515

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

D
Daniel Veillard 已提交
519
    if (!vm) {
520 521 522 523
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
524
        goto cleanup;
D
Daniel Veillard 已提交
525 526
    }

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

D
Daniel P. Berrange 已提交
529
    if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) {
D
Daniel Veillard 已提交
530
        info->cpuTime = 0;
531
        info->memory = vm->def->mem.cur_balloon;
D
Daniel Veillard 已提交
532
    } else {
533
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
534
            lxcError(VIR_ERR_INTERNAL_ERROR,
535
                     _("Unable to get cgroup for %s"), vm->def->name);
536 537 538 539
            goto cleanup;
        }

        if (virCgroupGetCpuacctUsage(cgroup, &(info->cpuTime)) < 0) {
540
            lxcError(VIR_ERR_OPERATION_FAILED,
541
                     "%s", _("Cannot read cputime for domain"));
R
Ryota Ozaki 已提交
542 543
            goto cleanup;
        }
544
        if ((rc = virCgroupGetMemoryUsage(cgroup, &(info->memory))) < 0) {
545
            lxcError(VIR_ERR_OPERATION_FAILED,
546
                     "%s", _("Cannot read memory usage for domain"));
547 548 549 550 551 552
            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;
553
        }
D
Daniel Veillard 已提交
554 555
    }

556
    info->maxMem = vm->def->mem.max_balloon;
D
Daniel Veillard 已提交
557
    info->nrVirtCpu = 1;
558
    ret = 0;
D
Daniel Veillard 已提交
559

560
cleanup:
561
    lxcDriverUnlock(driver);
562 563
    if (cgroup)
        virCgroupFree(&cgroup);
564 565
    if (vm)
        virDomainObjUnlock(vm);
566
    return ret;
D
Daniel Veillard 已提交
567 568
}

569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
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 已提交
593
    *state = virDomainObjGetState(vm, reason);
594 595 596 597 598 599 600 601
    ret = 0;

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

602
static char *lxcGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
603
{
604 605 606
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
607

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

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

620 621
    ret = strdup(vm->def->os.type);

622
    if (ret == NULL)
623
        virReportOOMError();
624

625
cleanup:
626 627
    if (vm)
        virDomainObjUnlock(vm);
628
    return ret;
D
Daniel Veillard 已提交
629 630
}

R
Ryota Ozaki 已提交
631 632 633 634 635 636 637 638 639 640 641 642 643
/* 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);
644
        lxcError(VIR_ERR_NO_DOMAIN,
645
                         _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
646 647 648
        goto cleanup;
    }

649
    ret = vm->def->mem.max_balloon;
R
Ryota Ozaki 已提交
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668

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);
669
        lxcError(VIR_ERR_NO_DOMAIN,
670
                         _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
671 672 673
        goto cleanup;
    }

674
    if (newmax < vm->def->mem.cur_balloon) {
675
        lxcError(VIR_ERR_INVALID_ARG,
676
                         "%s", _("Cannot set max memory lower than current memory"));
R
Ryota Ozaki 已提交
677 678 679
        goto cleanup;
    }

680
    vm->def->mem.max_balloon = newmax;
R
Ryota Ozaki 已提交
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
    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);
701
        lxcError(VIR_ERR_NO_DOMAIN,
702
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
703 704 705
        goto cleanup;
    }

706
    if (newmem > vm->def->mem.max_balloon) {
707
        lxcError(VIR_ERR_INVALID_ARG,
708
                 "%s", _("Cannot set memory higher than max memory"));
R
Ryota Ozaki 已提交
709 710 711
        goto cleanup;
    }

712 713 714 715 716
    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is not running"));
        goto cleanup;
    }
717

718 719 720 721 722
    if (driver->cgroup == NULL) {
        lxcError(VIR_ERR_NO_SUPPORT,
                 "%s", _("cgroups must be configured on the host"));
        goto cleanup;
    }
R
Ryota Ozaki 已提交
723

724 725 726 727
    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 已提交
728
    }
729 730 731 732 733 734 735

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

R
Ryota Ozaki 已提交
736 737 738 739 740 741 742 743 744 745
    ret = 0;

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

746
static int lxcDomainSetMemoryParameters(virDomainPtr dom,
747
                                        virTypedParameterPtr params,
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
                                        int nparams,
                                        unsigned int flags ATTRIBUTE_UNUSED)
{
    lxc_driver_t *driver = dom->conn->privateData;
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

    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++) {
776
        virTypedParameterPtr param = &params[i];
777 778 779

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            int rc;
780
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
781 782 783 784 785 786 787 788 789 790 791 792 793 794
                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;
795
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
796 797 798 799 800 801 802 803 804 805 806 807
                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;
            }
808
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
809
            int rc;
810
            if (param->type != VIR_TYPED_PARAM_ULLONG) {
811 812 813 814 815 816
                lxcError(VIR_ERR_INVALID_ARG, "%s",
                         _("invalid type for swap_hard_limit tunable, expected a 'ullong'"));
                ret = -1;
                continue;
            }

817
            rc = virCgroupSetMemSwapHardLimit(cgroup, params[i].value.ul);
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
            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;
}

843
static int lxcDomainGetMemoryParameters(virDomainPtr dom,
844
                                        virTypedParameterPtr params,
845 846 847 848 849 850 851
                                        int *nparams,
                                        unsigned int flags ATTRIBUTE_UNUSED)
{
    lxc_driver_t *driver = dom->conn->privateData;
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
852
    unsigned long long val;
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
    int ret = -1;
    int rc;

    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;
    }
873
    if ((*nparams) < LXC_NB_MEM_PARAM) {
874 875 876 877 878 879 880 881 882 883 884
        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;
    }

885
    for (i = 0; i < LXC_NB_MEM_PARAM; i++) {
886
        virTypedParameterPtr param = &params[i];
887 888
        val = 0;
        param->value.ul = 0;
889
        param->type = VIR_TYPED_PARAM_ULLONG;
890 891 892 893 894 895 896

        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"));
897
                goto cleanup;
898 899 900 901
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT) == NULL) {
                lxcError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field memory hard limit too long for destination"));
902
                goto cleanup;
903 904 905 906 907 908 909 910 911
            }
            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"));
912
                goto cleanup;
913 914 915 916
            }
            if (virStrcpyStatic(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT) == NULL) {
                lxcError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("Field memory soft limit too long for destination"));
917
                goto cleanup;
918 919 920 921 922
            }
            param->value.ul = val;
            break;

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

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

943
    *nparams = LXC_NB_MEM_PARAM;
944 945
    ret = 0;

946 947 948 949 950 951 952 953 954
cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

955 956
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
                                 int flags)
D
Daniel Veillard 已提交
957
{
958 959 960
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
961

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

D
Daniel Veillard 已提交
966
    if (!vm) {
967 968 969 970
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
971
        goto cleanup;
D
Daniel Veillard 已提交
972 973
    }

974
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
975 976 977 978
                             vm->newDef ? vm->newDef : vm->def,
                             flags);

cleanup:
979 980
    if (vm)
        virDomainObjUnlock(vm);
981
    return ret;
D
Daniel Veillard 已提交
982 983
}

984 985 986

/**
 * lxcVmCleanup:
987 988
 * @driver: pointer to driver structure
 * @vm: pointer to VM to clean up
J
Jiri Denemark 已提交
989
 * @reason: reason for switching the VM to shutoff state
990
 *
991
 * Cleanout resources associated with the now dead VM
992 993
 *
 */
994
static void lxcVmCleanup(lxc_driver_t *driver,
J
Jiri Denemark 已提交
995 996
                         virDomainObjPtr vm,
                         virDomainShutoffReason reason)
997
{
D
Dan Smith 已提交
998
    virCgroupPtr cgroup;
999
    int i;
1000
    lxcDomainObjPrivatePtr priv = vm->privateData;
1001

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
    /* 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);
    }

1012
    virEventRemoveHandle(priv->monitorWatch);
1013
    VIR_FORCE_CLOSE(priv->monitor);
1014 1015

    virFileDeletePid(driver->stateDir, vm->def->name);
1016
    virDomainDeleteConfig(driver->stateDir, NULL, vm);
1017

J
Jiri Denemark 已提交
1018
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
1019 1020
    vm->pid = -1;
    vm->def->id = -1;
1021 1022
    priv->monitor = -1;
    priv->monitorWatch = -1;
1023

1024 1025 1026
    for (i = 0 ; i < vm->def->nnets ; i++) {
        vethInterfaceUpOrDown(vm->def->nets[i]->ifname, 0);
        vethDelete(vm->def->nets[i]->ifname);
1027 1028
    }

1029 1030
    virDomainConfVMNWFilterTeardown(vm);

1031 1032
    if (driver->cgroup &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0) {
D
Dan Smith 已提交
1033 1034 1035 1036
        virCgroupRemove(cgroup);
        virCgroupFree(&cgroup);
    }

1037 1038 1039 1040 1041 1042
    if (vm->newDef) {
        virDomainDefFree(vm->def);
        vm->def = vm->newDef;
        vm->def->id = -1;
        vm->newDef = NULL;
    }
1043 1044
}

1045 1046
/**
 * lxcSetupInterfaces:
1047
 * @conn: pointer to connection
1048
 * @def: pointer to virtual machine structure
1049 1050
 * @nveths: number of interfaces
 * @veths: interface names
1051 1052 1053 1054 1055 1056 1057 1058
 *
 * 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,
1059
                              virDomainDefPtr def,
1060 1061
                              unsigned int *nveths,
                              char ***veths)
1062
{
1063
    int rc = -1, i;
1064 1065
    char *bridge = NULL;
    brControl *brctl = NULL;
1066
    int ret;
1067

1068 1069 1070
    if ((ret = brInit(&brctl)) != 0) {
        virReportSystemError(ret, "%s",
                             _("Unable to initialize bridging"));
1071
        return -1;
1072
    }
1073

1074
    for (i = 0 ; i < def->nnets ; i++) {
1075 1076
        char *parentVeth;
        char *containerVeth = NULL;
1077

1078
        switch (def->nets[i]->type) {
1079 1080
        case VIR_DOMAIN_NET_TYPE_NETWORK:
        {
1081 1082 1083 1084
            virNetworkPtr network;

            network = virNetworkLookupByName(conn,
                                             def->nets[i]->data.network.name);
1085 1086 1087 1088 1089 1090 1091
            if (!network) {
                goto error_exit;
            }

            bridge = virNetworkGetBridgeName(network);

            virNetworkFree(network);
1092 1093 1094
            break;
        }
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
1095
            bridge = def->nets[i]->data.bridge.brname;
1096
            break;
S
Stefan Berger 已提交
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106

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

1109
        VIR_DEBUG("bridge: %s", bridge);
1110
        if (NULL == bridge) {
1111
            lxcError(VIR_ERR_INTERNAL_ERROR,
1112
                     "%s", _("Failed to get bridge for interface"));
1113 1114 1115
            goto error_exit;
        }

1116
        VIR_DEBUG("calling vethCreate()");
1117 1118
        parentVeth = def->nets[i]->ifname;
        if (vethCreate(&parentVeth, &containerVeth) < 0)
1119
            goto error_exit;
1120
        VIR_DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth);
1121

1122
        if (NULL == def->nets[i]->ifname) {
1123
            def->nets[i]->ifname = parentVeth;
1124
        }
1125

1126
        if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0) {
1127
            virReportOOMError();
1128
            VIR_FREE(containerVeth);
1129
            goto error_exit;
1130
        }
1131
        (*veths)[(*nveths)] = containerVeth;
1132
        (*nveths)++;
1133

1134
        {
1135 1136
            char macaddr[VIR_MAC_STRING_BUFLEN];
            virFormatMacAddr(def->nets[i]->mac, macaddr);
1137
            if (setMacAddr(containerVeth, macaddr) < 0)
1138 1139 1140
                goto error_exit;
        }

1141
        if ((ret = brAddInterface(brctl, bridge, parentVeth)) != 0) {
E
Eric Blake 已提交
1142
            virReportSystemError(ret,
1143
                                 _("Failed to add %s device to %s"),
1144
                                 parentVeth, bridge);
1145 1146 1147
            goto error_exit;
        }

1148
        if (vethInterfaceUpOrDown(parentVeth, 1) < 0)
1149
            goto error_exit;
1150 1151 1152 1153

        if (def->nets[i]->filter &&
            virDomainConfNWFilterInstantiate(conn, def->nets[i]) < 0)
            goto error_exit;
1154 1155 1156 1157 1158
    }

    rc = 0;

error_exit:
1159
    brShutdown(brctl);
1160 1161 1162
    return rc;
}

1163

1164
static int lxcMonitorClient(lxc_driver_t * driver,
1165
                            virDomainObjPtr vm)
1166
{
1167 1168 1169
    char *sockpath = NULL;
    int fd;
    struct sockaddr_un addr;
1170

1171 1172
    if (virAsprintf(&sockpath, "%s/%s.sock",
                    driver->stateDir, vm->def->name) < 0) {
1173
        virReportOOMError();
1174 1175 1176 1177
        return -1;
    }

    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
1178
        virReportSystemError(errno, "%s",
1179
                             _("Failed to create client socket"));
1180
        goto error;
1181 1182
    }

1183 1184
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
C
Chris Lalancette 已提交
1185
    if (virStrcpyStatic(addr.sun_path, sockpath) == NULL) {
1186
        lxcError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
1187 1188 1189
                 _("Socket path %s too big for destination"), sockpath);
        goto error;
    }
1190 1191

    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
1192
        virReportSystemError(errno, "%s",
1193
                             _("Failed to connect to client socket"));
1194
        goto error;
1195 1196
    }

1197 1198
    VIR_FREE(sockpath);
    return fd;
1199

1200 1201
error:
    VIR_FREE(sockpath);
1202
    VIR_FORCE_CLOSE(fd);
1203 1204 1205 1206
    return -1;
}


1207
static int lxcVmTerminate(lxc_driver_t *driver,
J
Jiri Denemark 已提交
1208 1209
                          virDomainObjPtr vm,
                          virDomainShutoffReason reason)
1210
{
1211 1212
    virCgroupPtr group = NULL;
    int rc;
1213

1214
    if (vm->pid <= 0) {
1215
        lxcError(VIR_ERR_INTERNAL_ERROR,
1216
                 _("Invalid PID %d for container"), vm->pid);
1217 1218 1219
        return -1;
    }

1220 1221 1222 1223 1224 1225 1226 1227 1228
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
        return -1;

    rc = virCgroupKillPainfully(group);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("Failed to kill container PIDs"));
        rc = -1;
        goto cleanup;
1229
    }
1230 1231 1232 1233 1234 1235
    if (rc == 1) {
        lxcError(VIR_ERR_INTERNAL_ERROR, "%s",
                 _("Some container PIDs refused to die"));
        rc = -1;
        goto cleanup;
    }
J
Jiri Denemark 已提交
1236
    lxcVmCleanup(driver, vm, reason);
1237

1238
    rc = 0;
1239

1240 1241 1242
cleanup:
    virCgroupFree(&group);
    return rc;
1243
}
1244

1245 1246
static void lxcMonitorEvent(int watch,
                            int fd,
1247 1248 1249
                            int events ATTRIBUTE_UNUSED,
                            void *data)
{
1250 1251
    lxc_driver_t *driver = lxc_driver;
    virDomainObjPtr vm = data;
1252
    virDomainEventPtr event = NULL;
1253
    lxcDomainObjPrivatePtr priv;
1254

1255
    lxcDriverLock(driver);
1256 1257
    virDomainObjLock(vm);
    lxcDriverUnlock(driver);
1258

1259 1260 1261
    priv = vm->privateData;

    if (priv->monitor != fd || priv->monitorWatch != watch) {
1262
        virEventRemoveHandle(watch);
1263
        goto cleanup;
1264 1265
    }

J
Jiri Denemark 已提交
1266
    if (lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_SHUTDOWN) < 0) {
1267
        virEventRemoveHandle(watch);
1268 1269 1270 1271 1272
    } else {
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
    }
1273 1274 1275 1276
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1277 1278

cleanup:
1279 1280
    if (vm)
        virDomainObjUnlock(vm);
1281 1282
    if (event) {
        lxcDriverLock(driver);
1283
        lxcDomainEventQueue(driver, event);
1284 1285
        lxcDriverUnlock(driver);
    }
1286 1287 1288
}


1289 1290 1291 1292 1293 1294
static virCommandPtr
lxcBuildControllerCmd(lxc_driver_t *driver,
                      virDomainObjPtr vm,
                      int nveths,
                      char **veths,
                      int appPty,
1295 1296
                      int logfile,
                      int handshakefd)
1297 1298
{
    int i;
A
Amy Griffis 已提交
1299 1300
    char *filterstr;
    char *outputstr;
1301 1302 1303 1304 1305 1306 1307 1308 1309
    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 已提交
1310 1311 1312

    if (virLogGetNbFilters() > 0) {
        filterstr = virLogGetFilters();
1313 1314 1315 1316 1317 1318
        if (!filterstr) {
            virReportOOMError();
            goto cleanup;
        }

        virCommandAddEnvPair(cmd, "LIBVIRT_LOG_FILTERS", filterstr);
A
Amy Griffis 已提交
1319 1320 1321
        VIR_FREE(filterstr);
    }

A
Amy Griffis 已提交
1322 1323 1324
    if (driver->log_libvirtd) {
        if (virLogGetNbOutputs() > 0) {
            outputstr = virLogGetOutputs();
1325 1326 1327 1328 1329 1330
            if (!outputstr) {
                virReportOOMError();
                goto cleanup;
            }

            virCommandAddEnvPair(cmd, "LIBVIRT_LOG_OUTPUTS", outputstr);
A
Amy Griffis 已提交
1331 1332 1333
            VIR_FREE(outputstr);
        }
    } else {
1334 1335 1336
        virCommandAddEnvFormat(cmd,
                               "LIBVIRT_LOG_OUTPUTS=%d:stderr",
                               virLogGetDefaultPriority());
A
Amy Griffis 已提交
1337 1338
    }

1339 1340
    virCommandAddArgList(cmd, "--name", vm->def->name, "--console", NULL);
    virCommandAddArgFormat(cmd, "%d", appPty);
1341 1342
    virCommandAddArg(cmd, "--handshake");
    virCommandAddArgFormat(cmd, "%d", handshakefd);
1343
    virCommandAddArg(cmd, "--background");
1344 1345

    for (i = 0 ; i < nveths ; i++) {
1346
        virCommandAddArgList(cmd, "--veth", veths[i], NULL);
1347 1348
    }

1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
    /* 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;
    }

1365
    virCommandPreserveFD(cmd, appPty);
1366
    virCommandPreserveFD(cmd, handshakefd);
1367 1368
    virCommandSetOutputFD(cmd, &logfile);
    virCommandSetErrorFD(cmd, &logfile);
1369

1370
    return cmd;
A
Amy Griffis 已提交
1371
cleanup:
1372
    virCommandFree(cmd);
1373
    return NULL;
1374 1375
}

1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 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
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;
}
1448

1449 1450 1451 1452 1453
/**
 * lxcVmStart:
 * @conn: pointer to connection
 * @driver: pointer to driver structure
 * @vm: pointer to virtual machine structure
J
Jiri Denemark 已提交
1454
 * @reason: reason for switching vm to running state
1455 1456 1457 1458 1459 1460 1461
 *
 * 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 已提交
1462 1463
                      virDomainObjPtr vm,
                      virDomainRunningReason reason)
1464
{
1465
    int rc = -1, r;
1466 1467
    unsigned int i;
    int parentTty;
1468
    char *parentTtyPath = NULL;
1469 1470 1471 1472
    char *logfile = NULL;
    int logfd = -1;
    unsigned int nveths = 0;
    char **veths = NULL;
1473
    int handshakefds[2] = { -1, -1 };
1474 1475 1476 1477
    off_t pos = -1;
    char ebuf[1024];
    char *timestamp;
    virCommandPtr cmd = NULL;
1478
    lxcDomainObjPrivatePtr priv = vm->privateData;
1479

1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
    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;
    }

L
Laine Stump 已提交
1505
    if ((r = virFileMakePath(driver->logDir)) != 0) {
1506
        virReportSystemError(r,
1507
                             _("Cannot create log directory '%s'"),
1508
                             driver->logDir);
1509 1510
        return -1;
    }
1511

1512 1513
    if (virAsprintf(&logfile, "%s/%s.log",
                    driver->logDir, vm->def->name) < 0) {
1514
        virReportOOMError();
1515
        return -1;
1516 1517
    }

1518
    /* open parent tty */
1519
    if (virFileOpenTty(&parentTty, &parentTtyPath, 1) < 0) {
1520
        virReportSystemError(errno, "%s",
1521
                             _("Failed to allocate tty"));
1522 1523
        goto cleanup;
    }
1524
    if (vm->def->console &&
1525 1526 1527
        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;
1528 1529 1530
    } else {
        VIR_FREE(parentTtyPath);
    }
1531

1532
    if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0)
1533
        goto cleanup;
1534

1535
    /* Save the configuration for the controller */
1536
    if (virDomainSaveConfig(driver->stateDir, vm->def) < 0)
1537 1538
        goto cleanup;

1539
    if ((logfd = open(logfile, O_WRONLY | O_APPEND | O_CREAT,
1540
             S_IRUSR|S_IWUSR)) < 0) {
1541
        virReportSystemError(errno,
1542
                             _("Failed to open '%s'"),
1543
                             logfile);
1544
        goto cleanup;
1545 1546
    }

1547 1548 1549 1550 1551 1552
    if (pipe(handshakefds) < 0) {
        virReportSystemError(errno, "%s",
                             _("Unable to create pipe"));
        goto cleanup;
    }

1553 1554 1555
    if (!(cmd = lxcBuildControllerCmd(driver,
                                      vm,
                                      nveths, veths,
1556
                                      parentTty, logfd, handshakefds[1])))
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577
        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)
1578
        goto cleanup;
1579

1580 1581 1582 1583 1584
    if (VIR_CLOSE(handshakefds[1]) < 0) {
        virReportSystemError(errno, "%s", _("could not close handshake fd"));
        goto cleanup;
    }

1585 1586 1587
    /* Connect to the controller as a client *first* because
     * this will block until the child has written their
     * pid file out to disk */
1588
    if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0)
1589 1590
        goto cleanup;

1591
    /* And get its pid */
1592
    if ((r = virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) != 0) {
1593
        virReportSystemError(r,
1594 1595
                             _("Failed to read pid file %s/%s.pid"),
                             driver->stateDir, vm->def->name);
1596
        goto cleanup;
1597
    }
1598

1599
    vm->def->id = vm->pid;
J
Jiri Denemark 已提交
1600
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, reason);
1601

1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
    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;
    }

1614 1615
    if ((priv->monitorWatch = virEventAddHandle(
             priv->monitor,
1616 1617
             VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
             lxcMonitorEvent,
1618
             vm, NULL)) < 0) {
J
Jiri Denemark 已提交
1619
        lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
1620 1621
        goto cleanup;
    }
1622

1623 1624 1625 1626 1627 1628 1629
    /*
     * 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;

1630
    if (virDomainObjSetDefTransient(driver->caps, vm, false) < 0)
1631 1632
        goto cleanup;

O
Osier Yang 已提交
1633 1634 1635 1636
    /* Write domain status to disk. */
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto cleanup;

1637 1638 1639
    rc = 0;

cleanup:
1640
    virCommandFree(cmd);
1641 1642 1643 1644
    if (VIR_CLOSE(logfd) < 0) {
        virReportSystemError(errno, "%s", _("could not close logfile"));
        rc = -1;
    }
1645 1646 1647 1648 1649
    for (i = 0 ; i < nveths ; i++) {
        if (rc != 0)
            vethDelete(veths[i]);
        VIR_FREE(veths[i]);
    }
1650
    if (rc != 0) {
1651
        VIR_FORCE_CLOSE(priv->monitor);
1652 1653
        virDomainConfVMNWFilterTeardown(vm);
    }
1654
    VIR_FORCE_CLOSE(parentTty);
1655 1656
    VIR_FORCE_CLOSE(handshakefds[0]);
    VIR_FORCE_CLOSE(handshakefds[1]);
1657
    VIR_FREE(logfile);
1658 1659 1660 1661
    return rc;
}

/**
1662
 * lxcDomainStartWithFlags:
1663
 * @dom: domain to start
1664
 * @flags: Must be 0 for now
1665 1666 1667 1668 1669
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
1670
static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
1671
{
1672 1673
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1674
    virDomainEventPtr event = NULL;
1675
    int ret = -1;
1676

1677 1678
    virCheckFlags(0, -1);

1679
    lxcDriverLock(driver);
1680
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1681
    if (!vm) {
1682 1683 1684 1685
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
1686 1687 1688
        goto cleanup;
    }

1689
    if ((vm->def->nets != NULL) && !(driver->have_netns)) {
1690
        lxcError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
1691
                 "%s", _("System lacks NETNS support"));
1692 1693 1694
        goto cleanup;
    }

1695 1696 1697 1698 1699 1700
    if (virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is already running"));
        goto cleanup;
    }

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

1703 1704 1705 1706 1707
    if (ret == 0)
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);

1708
cleanup:
1709 1710
    if (vm)
        virDomainObjUnlock(vm);
1711 1712
    if (event)
        lxcDomainEventQueue(driver, event);
1713
    lxcDriverUnlock(driver);
1714
    return ret;
1715 1716
}

1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729
/**
 * 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);
}

1730 1731 1732 1733
/**
 * lxcDomainCreateAndStart:
 * @conn: pointer to connection
 * @xml: XML definition of domain
1734
 * @flags: Must be 0 for now
1735 1736 1737 1738 1739 1740 1741 1742
 *
 * 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,
1743
                        unsigned int flags) {
1744
    lxc_driver_t *driver = conn->privateData;
1745
    virDomainObjPtr vm = NULL;
1746
    virDomainDefPtr def;
1747
    virDomainPtr dom = NULL;
1748
    virDomainEventPtr event = NULL;
1749

1750 1751
    virCheckFlags(0, NULL);

1752
    lxcDriverLock(driver);
1753
    if (!(def = virDomainDefParseString(driver->caps, xml,
1754
                                        VIR_DOMAIN_XML_INACTIVE)))
1755
        goto cleanup;
1756

1757 1758
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
1759

1760
    if ((def->nets != NULL) && !(driver->have_netns)) {
1761
        lxcError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
1762
                 "%s", _("System lacks NETNS support"));
1763
        goto cleanup;
1764 1765
    }

1766

1767
    if (!(vm = virDomainAssignDef(driver->caps,
1768
                                  &driver->domains, def, false)))
1769 1770
        goto cleanup;
    def = NULL;
1771

J
Jiri Denemark 已提交
1772
    if (lxcVmStart(conn, driver, vm, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1773
        virDomainRemoveInactive(&driver->domains, vm);
1774
        vm = NULL;
1775
        goto cleanup;
1776 1777
    }

1778 1779 1780 1781
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);

1782
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1783
    if (dom)
1784 1785
        dom->id = vm->def->id;

1786 1787
cleanup:
    virDomainDefFree(def);
1788 1789
    if (vm)
        virDomainObjUnlock(vm);
1790 1791
    if (event)
        lxcDomainEventQueue(driver, event);
1792
    lxcDriverUnlock(driver);
1793 1794 1795
    return dom;
}

1796 1797

static int
1798 1799 1800 1801
lxcDomainEventRegister(virConnectPtr conn,
                       virConnectDomainEventCallback callback,
                       void *opaque,
                       virFreeCallback freecb)
1802 1803 1804 1805 1806
{
    lxc_driver_t *driver = conn->privateData;
    int ret;

    lxcDriverLock(driver);
1807 1808
    ret = virDomainEventCallbackListAdd(conn,
                                        driver->domainEventState->callbacks,
1809
                                        callback, opaque, freecb);
1810
    lxcDriverUnlock(driver);
1811

1812
    return ret;
1813 1814
}

1815

1816
static int
1817 1818
lxcDomainEventDeregister(virConnectPtr conn,
                         virConnectDomainEventCallback callback)
1819 1820 1821 1822 1823
{
    lxc_driver_t *driver = conn->privateData;
    int ret;

    lxcDriverLock(driver);
1824 1825 1826
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
1827 1828 1829 1830 1831
    lxcDriverUnlock(driver);

    return ret;
}

1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845

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,
1846
                                          driver->domainEventState->callbacks,
1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
                                          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);
1863 1864 1865
    ret = virDomainEventStateDeregisterAny(conn,
                                           driver->domainEventState,
                                           callbackID);
1866 1867 1868 1869 1870 1871
    lxcDriverUnlock(driver);

    return ret;
}


1872 1873
static void lxcDomainEventDispatchFunc(virConnectPtr conn,
                                       virDomainEventPtr event,
1874
                                       virConnectDomainEventGenericCallback cb,
1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891
                                       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);
1892 1893 1894
    virDomainEventStateFlush(driver->domainEventState,
                             lxcDomainEventDispatchFunc,
                             driver);
1895 1896 1897 1898 1899 1900 1901 1902
    lxcDriverUnlock(driver);
}


/* driver must be locked before calling */
static void lxcDomainEventQueue(lxc_driver_t *driver,
                                 virDomainEventPtr event)
{
1903
    virDomainEventStateQueue(driver->domainEventState, event);
1904
}
1905 1906 1907

/**
 * lxcDomainDestroy:
1908
 * @dom: pointer to domain to destroy
1909 1910 1911 1912 1913 1914 1915
 *
 * 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)
{
1916 1917
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
1918
    virDomainEventPtr event = NULL;
1919
    int ret = -1;
1920

1921
    lxcDriverLock(driver);
1922
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1923
    if (!vm) {
1924 1925 1926 1927
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
1928
        goto cleanup;
1929 1930
    }

1931 1932 1933 1934 1935 1936
    if (!virDomainObjIsActive(vm)) {
        lxcError(VIR_ERR_OPERATION_INVALID,
                 "%s", _("Domain is not running"));
        goto cleanup;
    }

J
Jiri Denemark 已提交
1937
    ret = lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1938 1939 1940
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1941 1942 1943 1944
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1945 1946

cleanup:
1947 1948
    if (vm)
        virDomainObjUnlock(vm);
1949 1950
    if (event)
        lxcDomainEventQueue(driver, event);
1951
    lxcDriverUnlock(driver);
1952
    return ret;
1953
}
1954

1955 1956 1957 1958 1959
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1960
    if (virRun(argv, &ip_rc) < 0 ||
1961 1962
        !(WIFEXITED(ip_rc) && (WEXITSTATUS(ip_rc) != 255)))
        return 0;
1963

1964 1965
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
1966

1967
    return 1;
1968 1969
}

1970

1971 1972 1973 1974 1975 1976
struct lxcAutostartData {
    lxc_driver_t *driver;
    virConnectPtr conn;
};

static void
1977
lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
1978 1979 1980 1981 1982 1983
{
    virDomainObjPtr vm = payload;
    const struct lxcAutostartData *data = opaque;

    virDomainObjLock(vm);
    if (vm->autostart &&
D
Daniel P. Berrange 已提交
1984
        !virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
1985 1986
        int ret = lxcVmStart(data->conn, data->driver, vm,
                             VIR_DOMAIN_RUNNING_BOOTED);
1987 1988
        if (ret < 0) {
            virErrorPtr err = virGetLastError();
1989
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003
                      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);
}

2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
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 */

2014 2015
    struct lxcAutostartData data = { driver, conn };

2016
    lxcDriverLock(driver);
2017
    virHashForEach(driver->domains.objs, lxcAutostartDomain, &data);
2018 2019 2020 2021 2022 2023
    lxcDriverUnlock(driver);

    if (conn)
        virConnectClose(conn);
}

2024
static void
2025
lxcReconnectVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
2026 2027 2028
{
    virDomainObjPtr vm = payload;
    lxc_driver_t *driver = opaque;
2029
    lxcDomainObjPrivatePtr priv;
2030 2031

    virDomainObjLock(vm);
2032 2033

    priv = vm->privateData;
2034
    if ((priv->monitor = lxcMonitorClient(driver, vm)) < 0) {
2035 2036 2037 2038 2039
        goto cleanup;
    }

    /* Read pid from controller */
    if ((virFileReadPid(lxc_driver->stateDir, vm->def->name, &vm->pid)) != 0) {
2040
        VIR_FORCE_CLOSE(priv->monitor);
2041 2042 2043 2044 2045
        goto cleanup;
    }

    if (vm->pid != 0) {
        vm->def->id = vm->pid;
J
Jiri Denemark 已提交
2046 2047
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNKNOWN);
2048 2049 2050 2051 2052 2053

        if ((priv->monitorWatch = virEventAddHandle(
                 priv->monitor,
                 VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
                 lxcMonitorEvent,
                 vm, NULL)) < 0) {
J
Jiri Denemark 已提交
2054
            lxcVmTerminate(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED);
2055 2056
            goto cleanup;
        }
2057 2058
    } else {
        vm->def->id = -1;
2059
        VIR_FORCE_CLOSE(priv->monitor);
2060 2061 2062 2063 2064 2065
    }

cleanup:
    virDomainObjUnlock(vm);
}

2066

2067
static int lxcStartup(int privileged)
D
Daniel Veillard 已提交
2068
{
2069
    char *ld;
2070
    int rc;
2071 2072 2073 2074 2075 2076

    /* 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");
2077
    if (ld && strstr(ld, "vgpreload")) {
2078
        VIR_INFO("Running under valgrind, disabling driver");
2079 2080
        return 0;
    }
2081

2082
    /* Check that the user is root, silently disable if not */
2083
    if (!privileged) {
2084
        VIR_INFO("Not running privileged, disabling driver");
2085 2086 2087 2088 2089
        return 0;
    }

    /* Check that this is a container enabled kernel */
    if (lxcContainerAvailable(0) < 0) {
2090
        VIR_INFO("LXC support not available in this kernel, disabling driver");
2091
        return 0;
2092 2093
    }

2094
    if (VIR_ALLOC(lxc_driver) < 0) {
2095 2096
        return -1;
    }
2097 2098 2099 2100
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
2101
    lxcDriverLock(lxc_driver);
D
Daniel Veillard 已提交
2102

2103 2104 2105
    if (virDomainObjListInit(&lxc_driver->domains) < 0)
        goto cleanup;

2106 2107 2108 2109 2110
    lxc_driver->domainEventState = virDomainEventStateNew(lxcDomainEventFlush,
                                                          lxc_driver,
                                                          NULL,
                                                          true);
    if (!lxc_driver->domainEventState)
2111 2112
        goto cleanup;

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

2116 2117 2118
    rc = virCgroupForDriver("lxc", &lxc_driver->cgroup, privileged, 1);
    if (rc < 0) {
        char buf[1024];
2119 2120 2121 2122 2123
        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
         */
2124 2125
    }

D
Daniel Veillard 已提交
2126
    /* Call function to load lxc driver configuration information */
2127 2128
    if (lxcLoadDriverConfig(lxc_driver) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
2129

2130 2131
    if ((lxc_driver->caps = lxcCapsInit()) == NULL)
        goto cleanup;
D
Daniel Veillard 已提交
2132

2133 2134 2135
    lxc_driver->caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc;
    lxc_driver->caps->privateDataFreeFunc = lxcDomainObjPrivateFree;

O
Osier Yang 已提交
2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(lxc_driver->caps,
                                &lxc_driver->domains,
                                lxc_driver->stateDir,
                                NULL,
                                1, NULL, NULL) < 0)
        goto cleanup;

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

    /* Then inactive persistent configs */
2147
    if (virDomainLoadAllConfigs(lxc_driver->caps,
2148 2149
                                &lxc_driver->domains,
                                lxc_driver->configDir,
2150
                                lxc_driver->autostartDir,
2151
                                0, NULL, NULL) < 0)
2152
        goto cleanup;
2153

2154
    lxcDriverUnlock(lxc_driver);
2155 2156 2157

    lxcAutostartConfigs(lxc_driver);

D
Daniel Veillard 已提交
2158 2159
    return 0;

2160 2161 2162 2163
cleanup:
    lxcDriverUnlock(lxc_driver);
    lxcShutdown();
    return -1;
D
Daniel Veillard 已提交
2164 2165
}

2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191
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);
2192
    virDomainLoadAllConfigs(lxc_driver->caps,
2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203
                            &lxc_driver->domains,
                            lxc_driver->configDir,
                            lxc_driver->autostartDir,
                            0, lxcNotifyLoadDomain, lxc_driver);
    lxcDriverUnlock(lxc_driver);

    lxcAutostartConfigs(lxc_driver);

    return 0;
}

2204
static int lxcShutdown(void)
D
Daniel Veillard 已提交
2205
{
2206
    if (lxc_driver == NULL)
2207
        return(-1);
2208

2209
    lxcDriverLock(lxc_driver);
2210
    virDomainObjListDeinit(&lxc_driver->domains);
2211
    virDomainEventStateFree(lxc_driver->domainEventState);
2212

2213 2214 2215 2216 2217 2218
    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);
2219
    virMutexDestroy(&lxc_driver->lock);
2220
    VIR_FREE(lxc_driver);
2221 2222 2223

    return 0;
}
D
Daniel Veillard 已提交
2224

2225 2226 2227 2228 2229 2230 2231 2232 2233
/**
 * lxcActive:
 *
 * Checks if the LXC daemon is active, i.e. has an active domain
 *
 * Returns 1 if active, 0 otherwise
 */
static int
lxcActive(void) {
2234
    int active;
2235

2236 2237
    if (lxc_driver == NULL)
        return(0);
2238

2239
    lxcDriverLock(lxc_driver);
2240
    active = virDomainObjListNumOfDomains(&lxc_driver->domains, 1);
2241
    lxcDriverUnlock(lxc_driver);
2242

2243
    return active;
D
Daniel Veillard 已提交
2244 2245
}

2246
static int lxcVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
D
Dan Smith 已提交
2247 2248 2249
{
    struct utsname ver;

2250
    uname(&ver);
D
Dan Smith 已提交
2251

2252 2253
    if (virParseVersionString(ver.release, version) < 0) {
        lxcError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
2254 2255 2256 2257 2258
        return -1;
    }

    return 0;
}
2259

2260 2261
static char *lxcGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
                                 int *nparams)
2262
{
2263 2264
    char *schedulerType = NULL;

2265 2266 2267
    if (nparams)
        *nparams = 1;

2268 2269 2270
    schedulerType = strdup("posix");

    if (schedulerType == NULL)
2271
        virReportOOMError();
2272 2273

    return schedulerType;
2274 2275
}

2276 2277 2278 2279 2280
static int
lxcSetSchedulerParametersFlags(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int nparams,
                               unsigned int flags)
2281
{
2282
    lxc_driver_t *driver = domain->conn->privateData;
2283
    int i;
2284 2285 2286
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
2287

2288 2289
    virCheckFlags(0, -1);

2290
    if (driver->cgroup == NULL)
2291 2292 2293 2294
        return -1;

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

2296
    if (vm == NULL) {
2297 2298 2299 2300
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
2301
        goto cleanup;
2302 2303
    }

2304
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
2305
        goto cleanup;
2306 2307

    for (i = 0; i < nparams; i++) {
2308
        virTypedParameterPtr param = &params[i];
2309 2310 2311 2312 2313 2314 2315

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

2316
        if (param->type != VIR_TYPED_PARAM_ULLONG) {
2317
            lxcError(VIR_ERR_INVALID_ARG, "%s",
2318
                 _("Invalid type for cpu_shares tunable, expected a 'ullong'"));
2319 2320
            goto cleanup;
        }
2321

2322 2323 2324 2325
        int rc = virCgroupSetCpuShares(group, params[i].value.ul);
        if (rc != 0) {
            virReportSystemError(-rc, _("failed to set cpu_shares=%llu"),
                                 params[i].value.ul);
2326
            goto cleanup;
2327
        }
2328 2329

        vm->def->cputune.shares = params[i].value.ul;
2330
    }
2331
    ret = 0;
2332

2333
cleanup:
2334
    lxcDriverUnlock(driver);
2335
    virCgroupFree(&group);
2336 2337
    if (vm)
        virDomainObjUnlock(vm);
2338
    return ret;
2339 2340
}

2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353
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)
2354
{
2355
    lxc_driver_t *driver = domain->conn->privateData;
2356 2357
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
2358
    unsigned long long val;
2359
    int ret = -1;
2360

2361 2362
    virCheckFlags(0, -1);

2363
    if (driver->cgroup == NULL)
2364
        return -1;
2365

2366
    if (*nparams < 1) {
2367
        lxcError(VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
2368
                 "%s", _("Invalid parameter count"));
2369
        return -1;
2370 2371
    }

2372 2373 2374
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);

2375
    if (vm == NULL) {
2376 2377 2378 2379
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        lxcError(VIR_ERR_NO_DOMAIN,
                 _("No domain with matching uuid '%s'"), uuidstr);
2380
        goto cleanup;
2381 2382
    }

2383
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0)
2384
        goto cleanup;
2385

2386 2387
    if (virCgroupGetCpuShares(group, &val) != 0)
        goto cleanup;
2388
    params[0].value.ul = val;
C
Chris Lalancette 已提交
2389
    if (virStrcpyStatic(params[0].field, "cpu_shares") == NULL) {
2390
        lxcError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
2391 2392 2393
                 "%s", _("Field cpu_shares too big for destination"));
        goto cleanup;
    }
2394
    params[0].type = VIR_TYPED_PARAM_ULLONG;
2395

2396
    *nparams = 1;
2397
    ret = 0;
2398

2399
cleanup:
2400
    lxcDriverUnlock(driver);
2401
    virCgroupFree(&group);
2402 2403
    if (vm)
        virDomainObjUnlock(vm);
2404
    return ret;
2405 2406
}

2407 2408 2409 2410 2411 2412 2413 2414
static int
lxcGetSchedulerParameters(virDomainPtr domain,
                          virTypedParameterPtr params,
                          int *nparams)
{
    return lxcGetSchedulerParametersFlags(domain, params, nparams, 0);
}

2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432
#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);
2433
        lxcError(VIR_ERR_NO_DOMAIN,
2434 2435 2436 2437 2438
                 _("No domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2439
        lxcError(VIR_ERR_OPERATION_INVALID,
2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453
                 "%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)
2454
        ret = linuxDomainInterfaceStats(path, stats);
2455
    else
2456
        lxcError(VIR_ERR_INVALID_ARG,
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
                 _("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)
2469
    lxcError(VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__);
2470 2471 2472 2473
    return -1;
}
#endif

2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486
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);
2487
        lxcError(VIR_ERR_NO_DOMAIN,
2488
                 _("No domain with matching uuid '%s'"), uuidstr);
2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513
        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);
2514
        lxcError(VIR_ERR_NO_DOMAIN,
2515
                 _("No domain with matching uuid '%s'"), uuidstr);
2516 2517 2518 2519
        goto cleanup;
    }

    if (!vm->persistent) {
2520
        lxcError(VIR_ERR_OPERATION_INVALID,
2521
                 "%s", _("Cannot set autostart for transient domain"));
2522 2523 2524 2525 2526
        goto cleanup;
    }

    autostart = (autostart != 0);

2527 2528 2529 2530
    if (vm->autostart == autostart) {
        ret = 0;
        goto cleanup;
    }
2531

2532
    configFile = virDomainConfigFile(driver->configDir,
2533 2534 2535
                                     vm->def->name);
    if (configFile == NULL)
        goto cleanup;
2536
    autostartLink = virDomainConfigFile(driver->autostartDir,
2537 2538 2539
                                        vm->def->name);
    if (autostartLink == NULL)
        goto cleanup;
2540

2541 2542
    if (autostart) {
        int err;
2543

2544
        if ((err = virFileMakePath(driver->autostartDir))) {
2545
            virReportSystemError(err,
2546 2547 2548
                                 _("Cannot create autostart directory %s"),
                                 driver->autostartDir);
            goto cleanup;
2549 2550
        }

2551
        if (symlink(configFile, autostartLink) < 0) {
2552
            virReportSystemError(errno,
2553 2554 2555 2556 2557 2558
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
            goto cleanup;
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2559
            virReportSystemError(errno,
2560 2561 2562 2563
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
            goto cleanup;
        }
2564
    }
2565 2566

    vm->autostart = autostart;
2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
    ret = 0;

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

R
Ryota Ozaki 已提交
2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588
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 &&
2589
          virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0))
R
Ryota Ozaki 已提交
2590 2591
        return -1;

2592 2593
    /* From here on, we know that cgroup != NULL.  */

R
Ryota Ozaki 已提交
2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614
    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)
2615
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654

        /*
         * 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);
    }
2655
    VIR_DEBUG("lxcFreezeContainer timeout");
R
Ryota Ozaki 已提交
2656 2657 2658 2659 2660 2661 2662 2663 2664 2665
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:
2666
    virCgroupFree(&cgroup);
R
Ryota Ozaki 已提交
2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683
    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);
2684
        lxcError(VIR_ERR_NO_DOMAIN,
2685
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2686 2687 2688
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2689
    if (!virDomainObjIsActive(vm)) {
2690
        lxcError(VIR_ERR_OPERATION_INVALID,
2691
                 "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2692 2693 2694
        goto cleanup;
    }

J
Jiri Denemark 已提交
2695
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2696
        if (lxcFreezeContainer(driver, vm) < 0) {
2697
            lxcError(VIR_ERR_OPERATION_FAILED,
2698
                     "%s", _("Suspend operation failed"));
R
Ryota Ozaki 已提交
2699 2700
            goto cleanup;
        }
J
Jiri Denemark 已提交
2701
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
2702 2703 2704 2705 2706 2707

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

2708
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748
        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);
2749
        lxcError(VIR_ERR_NO_DOMAIN,
2750
                 _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2751 2752 2753
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2754
    if (!virDomainObjIsActive(vm)) {
2755
        lxcError(VIR_ERR_OPERATION_INVALID,
2756
                 "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2757 2758 2759
        goto cleanup;
    }

J
Jiri Denemark 已提交
2760
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2761
        if (lxcUnfreezeContainer(driver, vm) < 0) {
2762
            lxcError(VIR_ERR_OPERATION_FAILED,
2763
                     "%s", _("Resume operation failed"));
R
Ryota Ozaki 已提交
2764 2765
            goto cleanup;
        }
J
Jiri Denemark 已提交
2766 2767
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
2768 2769 2770 2771 2772 2773

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

2774
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786
        goto cleanup;
    ret = 0;

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

2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833
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;
    }

2834
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2835 2836 2837 2838 2839
        lxcError(VIR_ERR_INTERNAL_ERROR,
                 _("character device %s is not using a PTY"), devname);
        goto cleanup;
    }

2840 2841
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
                            0, 0, O_RDWR, false) < 0)
2842 2843 2844 2845 2846 2847 2848 2849 2850 2851
        goto cleanup;

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

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
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 已提交
2879

D
Daniel Veillard 已提交
2880 2881
/* Function Tables */
static virDriver lxcDriver = {
2882 2883
    .no = VIR_DRV_LXC,
    .name = "LXC",
2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917
    .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 */
    .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 */
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
    .domainGetSchedulerType = lxcGetSchedulerType, /* 0.5.0 */
    .domainGetSchedulerParameters = lxcGetSchedulerParameters, /* 0.5.0 */
2918
    .domainGetSchedulerParametersFlags = lxcGetSchedulerParametersFlags, /* 0.9.2 */
2919
    .domainSetSchedulerParameters = lxcSetSchedulerParameters, /* 0.5.0 */
2920
    .domainSetSchedulerParametersFlags = lxcSetSchedulerParametersFlags, /* 0.9.2 */
2921
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
2922
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
2923
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935
    .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 已提交
2936 2937
};

2938
static virStateDriver lxcStateDriver = {
2939
    .name = "LXC",
2940 2941 2942
    .initialize = lxcStartup,
    .cleanup = lxcShutdown,
    .active = lxcActive,
2943
    .reload = lxcReload,
2944 2945
};

D
Daniel Veillard 已提交
2946 2947 2948
int lxcRegister(void)
{
    virRegisterDriver(&lxcDriver);
2949
    virRegisterStateDriver(&lxcStateDriver);
2950
    virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
D
Daniel Veillard 已提交
2951 2952
    return 0;
}