lxc_driver.c 79.2 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
E
Eric Blake 已提交
2
 * Copyright (C) 2010-2012 Red Hat, Inc.
D
Daniel Veillard 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * 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
O
Osier Yang 已提交
21 22
 * License along with this library;  If not, see
 * <http://www.gnu.org/licenses/>.
D
Daniel Veillard 已提交
23 24 25 26
 */

#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"
43
#include "lxc_domain.h"
D
Daniel Veillard 已提交
44
#include "lxc_driver.h"
45
#include "lxc_process.h"
46
#include "memory.h"
47
#include "util.h"
48
#include "virnetdevbridge.h"
49
#include "virnetdevveth.h"
50
#include "nodeinfo.h"
51
#include "uuid.h"
52
#include "stats_linux.h"
53
#include "hooks.h"
E
Eric Blake 已提交
54
#include "virfile.h"
55
#include "virpidfile.h"
56
#include "fdstream.h"
57
#include "domain_audit.h"
58
#include "domain_nwfilter.h"
59
#include "network/bridge_driver.h"
60
#include "virnetdev.h"
A
Ansis Atteka 已提交
61
#include "virnetdevtap.h"
62
#include "virnodesuspend.h"
63
#include "virtime.h"
64
#include "virtypedparam.h"
M
Martin Kletzander 已提交
65
#include "viruri.h"
66
#include "virdomainlist.h"
D
Daniel Veillard 已提交
67

68 69
#define VIR_FROM_THIS VIR_FROM_LXC

70

71 72
#define LXC_NB_MEM_PARAM  3

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

/* Functions */

static virDrvOpenStatus lxcOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
81
                                unsigned int flags)
D
Daniel Veillard 已提交
82
{
E
Eric Blake 已提交
83 84
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

D
Daniel Veillard 已提交
85
    /* Verify uri was specified */
86
    if (conn->uri == NULL) {
87 88
        if (lxc_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;
89

90
        if (!(conn->uri = virURIParse("lxc:///")))
91
            return VIR_DRV_OPEN_ERROR;
92 93 94 95 96 97 98 99 100 101
    } 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 */
102 103
        if (conn->uri->path != NULL &&
            STRNEQ(conn->uri->path, "/")) {
104 105 106
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unexpected LXC URI path '%s', try lxc:///"),
                           conn->uri->path);
107 108
            return VIR_DRV_OPEN_ERROR;
        }
D
Daniel Veillard 已提交
109

110 111
        /* URI was good, but driver isn't active */
        if (lxc_driver == NULL) {
112 113
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("lxc state driver is not active"));
114 115 116
            return VIR_DRV_OPEN_ERROR;
        }
    }
117

118
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
119 120 121 122 123 124

    return VIR_DRV_OPEN_SUCCESS;
}

static int lxcClose(virConnectPtr conn)
{
125
    virLXCDriverPtr driver = conn->privateData;
126 127

    lxcDriverLock(driver);
128
    virLXCProcessAutoDestroyRun(driver, conn);
129 130
    lxcDriverUnlock(driver);

131 132
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
133 134
}

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

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


150 151 152 153 154 155
static int lxcIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}


156
static char *lxcGetCapabilities(virConnectPtr conn) {
157
    virLXCDriverPtr driver = conn->privateData;
158 159 160 161
    char *xml;

    lxcDriverLock(driver);
    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
162
        virReportOOMError();
163 164 165 166 167 168
    lxcDriverUnlock(driver);

    return xml;
}


D
Daniel Veillard 已提交
169 170 171
static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
                                        int id)
{
172
    virLXCDriverPtr driver = conn->privateData;
173 174
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
175

176
    lxcDriverLock(driver);
177
    vm = virDomainFindByID(&driver->domains, id);
178 179
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
180
    if (!vm) {
181 182
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching id %d"), id);
183
        goto cleanup;
D
Daniel Veillard 已提交
184 185 186
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
187
    if (dom)
D
Daniel Veillard 已提交
188 189
        dom->id = vm->def->id;

190
cleanup:
191 192
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
193 194 195 196 197 198
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
199
    virLXCDriverPtr driver = conn->privateData;
200 201
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
202

203
    lxcDriverLock(driver);
204
    vm = virDomainFindByUUID(&driver->domains, uuid);
205 206
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
207
    if (!vm) {
208 209
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
210 211
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
212
        goto cleanup;
D
Daniel Veillard 已提交
213 214 215
    }

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

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

static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
                                          const char *name)
{
228
    virLXCDriverPtr driver = conn->privateData;
229 230
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
231

232
    lxcDriverLock(driver);
233
    vm = virDomainFindByName(&driver->domains, name);
234
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
235
    if (!vm) {
236 237
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching name '%s'"), name);
238
        goto cleanup;
D
Daniel Veillard 已提交
239 240 241
    }

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

245
cleanup:
246 247
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
248 249 250
    return dom;
}

251 252 253

static int lxcDomainIsActive(virDomainPtr dom)
{
254
    virLXCDriverPtr driver = dom->conn->privateData;
255 256 257 258 259 260 261
    virDomainObjPtr obj;
    int ret = -1;

    lxcDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!obj) {
262 263
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
264 265
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
266 267 268 269 270 271 272 273 274 275 276 277 278
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

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


static int lxcDomainIsPersistent(virDomainPtr dom)
{
279
    virLXCDriverPtr driver = dom->conn->privateData;
280 281 282 283 284 285 286
    virDomainObjPtr obj;
    int ret = -1;

    lxcDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    lxcDriverUnlock(driver);
    if (!obj) {
287 288
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
289 290
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
291 292 293 294 295 296 297 298 299 300
        goto cleanup;
    }
    ret = obj->persistent;

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

301 302
static int lxcDomainIsUpdated(virDomainPtr dom)
{
303
    virLXCDriverPtr driver = dom->conn->privateData;
304 305 306 307 308 309 310 311 312
    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);
313 314
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
315 316 317 318 319 320 321 322 323
        goto cleanup;
    }
    ret = obj->updated;

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

325
static int lxcListDomains(virConnectPtr conn, int *ids, int nids) {
326
    virLXCDriverPtr driver = conn->privateData;
327
    int n;
328

329
    lxcDriverLock(driver);
330
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
331
    lxcDriverUnlock(driver);
332

333
    return n;
D
Daniel Veillard 已提交
334
}
335

336
static int lxcNumDomains(virConnectPtr conn) {
337
    virLXCDriverPtr driver = conn->privateData;
338
    int n;
339

340
    lxcDriverLock(driver);
341
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
342
    lxcDriverUnlock(driver);
343

344
    return n;
D
Daniel Veillard 已提交
345 346 347
}

static int lxcListDefinedDomains(virConnectPtr conn,
348
                                 char **const names, int nnames) {
349
    virLXCDriverPtr driver = conn->privateData;
350
    int n;
351

352
    lxcDriverLock(driver);
353
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
354
    lxcDriverUnlock(driver);
355

356
    return n;
D
Daniel Veillard 已提交
357 358 359
}


360
static int lxcNumDefinedDomains(virConnectPtr conn) {
361
    virLXCDriverPtr driver = conn->privateData;
362
    int n;
363

364
    lxcDriverLock(driver);
365
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
366
    lxcDriverUnlock(driver);
367

368
    return n;
D
Daniel Veillard 已提交
369 370
}

371 372


D
Daniel Veillard 已提交
373 374
static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml)
{
375
    virLXCDriverPtr driver = conn->privateData;
376
    virDomainDefPtr def = NULL;
377
    virDomainObjPtr vm = NULL;
378
    virDomainPtr dom = NULL;
379
    virDomainEventPtr event = NULL;
380
    int dupVM;
D
Daniel Veillard 已提交
381

382
    lxcDriverLock(driver);
383
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
384
                                        1 << VIR_DOMAIN_VIRT_LXC,
385
                                        VIR_DOMAIN_XML_INACTIVE)))
386
        goto cleanup;
D
Daniel Veillard 已提交
387

388 389 390
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

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

394
    if ((def->nets != NULL) && !(driver->have_netns)) {
395 396
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
397
        goto cleanup;
398 399
    }

400
    if (!(vm = virDomainAssignDef(driver->caps,
401
                                  &driver->domains, def, false)))
402 403
        goto cleanup;
    def = NULL;
404
    vm->persistent = 1;
D
Daniel Veillard 已提交
405

406
    if (virDomainSaveConfig(driver->configDir,
407
                            vm->newDef ? vm->newDef : vm->def) < 0) {
408
        virDomainRemoveInactive(&driver->domains, vm);
409
        vm = NULL;
410
        goto cleanup;
D
Daniel Veillard 已提交
411 412
    }

413 414
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
415
                                     !dupVM ?
416 417 418
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

D
Daniel Veillard 已提交
419
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
420
    if (dom)
D
Daniel Veillard 已提交
421 422
        dom->id = vm->def->id;

423 424
cleanup:
    virDomainDefFree(def);
425 426
    if (vm)
        virDomainObjUnlock(vm);
427
    if (event)
428
        virDomainEventStateQueue(driver->domainEventState, event);
429
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
430 431 432
    return dom;
}

433 434
static int lxcDomainUndefineFlags(virDomainPtr dom,
                                  unsigned int flags)
D
Daniel Veillard 已提交
435
{
436
    virLXCDriverPtr driver = dom->conn->privateData;
437
    virDomainObjPtr vm;
438
    virDomainEventPtr event = NULL;
439
    int ret = -1;
D
Daniel Veillard 已提交
440

441 442
    virCheckFlags(0, -1);

443
    lxcDriverLock(driver);
444
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
445
    if (!vm) {
446 447
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
448 449
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
450
        goto cleanup;
D
Daniel Veillard 已提交
451 452
    }

453
    if (!vm->persistent) {
454 455
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot undefine transient domain"));
456
        goto cleanup;
457
    }
D
Daniel Veillard 已提交
458

459
    if (virDomainDeleteConfig(driver->configDir,
460
                              driver->autostartDir,
461 462
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
463

464 465 466 467
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

468 469 470 471 472 473 474
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }

475
    ret = 0;
D
Daniel Veillard 已提交
476

477
cleanup:
478 479
    if (vm)
        virDomainObjUnlock(vm);
480
    if (event)
481
        virDomainEventStateQueue(driver->domainEventState, event);
482
    lxcDriverUnlock(driver);
483
    return ret;
D
Daniel Veillard 已提交
484 485
}

486 487 488 489 490
static int lxcDomainUndefine(virDomainPtr dom)
{
    return lxcDomainUndefineFlags(dom, 0);
}

D
Daniel Veillard 已提交
491 492 493
static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
494
    virLXCDriverPtr driver = dom->conn->privateData;
495
    virDomainObjPtr vm;
496
    virCgroupPtr cgroup = NULL;
497
    int ret = -1, rc;
D
Daniel Veillard 已提交
498

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

D
Daniel Veillard 已提交
502
    if (!vm) {
503 504
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
505 506
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
507
        goto cleanup;
D
Daniel Veillard 已提交
508 509
    }

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

D
Daniel P. Berrange 已提交
512
    if (!virDomainObjIsActive(vm) || driver->cgroup == NULL) {
D
Daniel Veillard 已提交
513
        info->cpuTime = 0;
514
        info->memory = vm->def->mem.cur_balloon;
D
Daniel Veillard 已提交
515
    } else {
516
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
517 518
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to get cgroup for %s"), vm->def->name);
519 520 521 522
            goto cleanup;
        }

        if (virCgroupGetCpuacctUsage(cgroup, &(info->cpuTime)) < 0) {
523 524
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Cannot read cputime for domain"));
R
Ryota Ozaki 已提交
525 526
            goto cleanup;
        }
527
        if ((rc = virCgroupGetMemoryUsage(cgroup, &(info->memory))) < 0) {
528 529
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Cannot read memory usage for domain"));
530 531 532 533 534 535
            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;
536
        }
D
Daniel Veillard 已提交
537 538
    }

539
    info->maxMem = vm->def->mem.max_balloon;
540
    info->nrVirtCpu = vm->def->vcpus;
541
    ret = 0;
D
Daniel Veillard 已提交
542

543
cleanup:
544
    lxcDriverUnlock(driver);
545 546
    if (cgroup)
        virCgroupFree(&cgroup);
547 548
    if (vm)
        virDomainObjUnlock(vm);
549
    return ret;
D
Daniel Veillard 已提交
550 551
}

552 553 554 555 556 557
static int
lxcDomainGetState(virDomainPtr dom,
                  int *state,
                  int *reason,
                  unsigned int flags)
{
558
    virLXCDriverPtr driver = dom->conn->privateData;
559 560 561 562 563 564 565 566 567 568 569 570
    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);
571 572
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
573 574 575
        goto cleanup;
    }

J
Jiri Denemark 已提交
576
    *state = virDomainObjGetState(vm, reason);
577 578 579 580 581 582 583 584
    ret = 0;

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

585
static char *lxcGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
586
{
587
    virLXCDriverPtr driver = dom->conn->privateData;
588 589
    virDomainObjPtr vm;
    char *ret = NULL;
590

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

595
    if (!vm) {
596 597
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
598 599
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
600
        goto cleanup;
601 602
    }

603 604
    ret = strdup(vm->def->os.type);

605
    if (ret == NULL)
606
        virReportOOMError();
607

608
cleanup:
609 610
    if (vm)
        virDomainObjUnlock(vm);
611
    return ret;
D
Daniel Veillard 已提交
612 613
}

R
Ryota Ozaki 已提交
614
/* Returns max memory in kb, 0 if error */
615 616 617
static unsigned long long
lxcDomainGetMaxMemory(virDomainPtr dom)
{
618
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
619
    virDomainObjPtr vm;
620
    unsigned long long ret = 0;
R
Ryota Ozaki 已提交
621 622 623 624 625 626 627 628

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

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
629 630
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
631 632 633
        goto cleanup;
    }

634
    ret = vm->def->mem.max_balloon;
R
Ryota Ozaki 已提交
635 636 637 638 639 640 641 642

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

static int lxcDomainSetMaxMemory(virDomainPtr dom, unsigned long newmax) {
643
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
644 645 646 647 648 649 650 651 652 653
    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);
654 655
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
656 657 658
        goto cleanup;
    }

659
    if (newmax < vm->def->mem.cur_balloon) {
660 661
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("Cannot set max memory lower than current memory"));
R
Ryota Ozaki 已提交
662 663 664
        goto cleanup;
    }

665
    vm->def->mem.max_balloon = newmax;
R
Ryota Ozaki 已提交
666 667 668 669 670 671 672 673 674
    ret = 0;

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

static int lxcDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
675
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
676 677 678 679 680 681 682 683 684 685
    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);
686 687
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
688 689 690
        goto cleanup;
    }

691
    if (newmem > vm->def->mem.max_balloon) {
692 693
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("Cannot set memory higher than max memory"));
R
Ryota Ozaki 已提交
694 695 696
        goto cleanup;
    }

697
    if (!virDomainObjIsActive(vm)) {
698 699
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
700 701
        goto cleanup;
    }
702

703
    if (driver->cgroup == NULL) {
704 705
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroups must be configured on the host"));
706 707
        goto cleanup;
    }
R
Ryota Ozaki 已提交
708

709
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
710 711
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to get cgroup for %s"), vm->def->name);
712
        goto cleanup;
R
Ryota Ozaki 已提交
713
    }
714 715

    if (virCgroupSetMemory(cgroup, newmem) < 0) {
716 717
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("Failed to set memory for domain"));
718 719 720
        goto cleanup;
    }

R
Ryota Ozaki 已提交
721 722 723 724 725 726 727 728 729 730
    ret = 0;

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

731 732 733 734 735
static int
lxcDomainSetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
736
{
737
    virLXCDriverPtr driver = dom->conn->privateData;
738 739 740 741
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
742
    int rc;
743

E
Eric Blake 已提交
744
    virCheckFlags(0, -1);
745 746 747 748 749 750 751 752 753
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       NULL) < 0)
        return -1;
E
Eric Blake 已提交
754

755 756 757 758 759 760
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

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

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) != 0) {
767 768
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
769 770 771 772 773
        goto cleanup;
    }

    ret = 0;
    for (i = 0; i < nparams; i++) {
774
        virTypedParameterPtr param = &params[i];
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            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)) {
            rc = virCgroupSetMemorySoftLimit(cgroup, params[i].value.ul);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set memory soft_limit tunable"));
                ret = -1;
            }
790
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
791
            rc = virCgroupSetMemSwapHardLimit(cgroup, params[i].value.ul);
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to set swap_hard_limit tunable"));
                ret = -1;
            }
        }
    }

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

809 810 811 812 813
static int
lxcDomainGetMemoryParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
814
{
815
    virLXCDriverPtr driver = dom->conn->privateData;
816 817 818
    int i;
    virCgroupPtr cgroup = NULL;
    virDomainObjPtr vm = NULL;
819
    unsigned long long val;
820 821 822
    int ret = -1;
    int rc;

E
Eric Blake 已提交
823 824
    virCheckFlags(0, -1);

825 826 827 828 829 830
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
831 832
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
833 834 835 836 837 838 839 840 841 842 843
        goto cleanup;
    }

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

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

849
    for (i = 0; i < LXC_NB_MEM_PARAM && i < *nparams; i++) {
850
        virTypedParameterPtr param = &params[i];
851 852 853 854 855 856 857 858
        val = 0;

        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"));
859
                goto cleanup;
860
            }
861 862
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
863
                goto cleanup;
864 865 866 867 868 869
            break;
        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(cgroup, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
870
                goto cleanup;
871
            }
872 873
            if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
874
                goto cleanup;
875 876
            break;
        case 2: /* fill swap hard limit here */
877
            rc = virCgroupGetMemSwapHardLimit(cgroup, &val);
878 879 880
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
881
                goto cleanup;
882
            }
883 884 885
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
886
                goto cleanup;
887 888 889 890 891 892 893 894
            break;

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

895 896
    if (*nparams > LXC_NB_MEM_PARAM)
        *nparams = LXC_NB_MEM_PARAM;
897 898
    ret = 0;

899 900 901 902 903 904 905 906 907
cleanup:
    if (cgroup)
        virCgroupFree(&cgroup);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

908
static char *lxcDomainGetXMLDesc(virDomainPtr dom,
909
                                 unsigned int flags)
D
Daniel Veillard 已提交
910
{
911
    virLXCDriverPtr driver = dom->conn->privateData;
912 913
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
914

915 916
    /* Flags checked by virDomainDefFormat */

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

D
Daniel Veillard 已提交
921
    if (!vm) {
922 923
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
924 925
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
926
        goto cleanup;
D
Daniel Veillard 已提交
927 928
    }

929
    ret = virDomainDefFormat((flags & VIR_DOMAIN_XML_INACTIVE) &&
930 931 932 933
                             vm->newDef ? vm->newDef : vm->def,
                             flags);

cleanup:
934 935
    if (vm)
        virDomainObjUnlock(vm);
936
    return ret;
D
Daniel Veillard 已提交
937 938
}

939

940
/**
941
 * lxcDomainStartWithFlags:
942
 * @dom: domain to start
943
 * @flags: Must be 0 for now
944 945 946 947 948
 *
 * Looks up domain and starts it.
 *
 * Returns 0 on success or -1 in case of error
 */
949
static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
950
{
951
    virLXCDriverPtr driver = dom->conn->privateData;
952
    virDomainObjPtr vm;
953
    virDomainEventPtr event = NULL;
954
    int ret = -1;
955

956
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
957

958
    lxcDriverLock(driver);
959
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
960
    if (!vm) {
961 962
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
963 964
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
965 966 967
        goto cleanup;
    }

968
    if ((vm->def->nets != NULL) && !(driver->have_netns)) {
969 970
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("System lacks NETNS support"));
971 972 973
        goto cleanup;
    }

974
    if (virDomainObjIsActive(vm)) {
975 976
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
977 978 979
        goto cleanup;
    }

980 981 982
    ret = virLXCProcessStart(dom->conn, driver, vm,
                             (flags & VIR_DOMAIN_START_AUTODESTROY),
                             VIR_DOMAIN_RUNNING_BOOTED);
983

984
    if (ret == 0) {
985 986 987
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STARTED,
                                         VIR_DOMAIN_EVENT_STARTED_BOOTED);
988 989 990 991
        virDomainAuditStart(vm, "booted", true);
    } else {
        virDomainAuditStart(vm, "booted", false);
    }
992

993
cleanup:
994 995
    if (vm)
        virDomainObjUnlock(vm);
996
    if (event)
997
        virDomainEventStateQueue(driver->domainEventState, event);
998
    lxcDriverUnlock(driver);
999
    return ret;
1000 1001
}

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

1015 1016 1017 1018
/**
 * lxcDomainCreateAndStart:
 * @conn: pointer to connection
 * @xml: XML definition of domain
1019
 * @flags: Must be 0 for now
1020 1021 1022 1023 1024 1025 1026 1027
 *
 * 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,
1028
                        unsigned int flags) {
1029
    virLXCDriverPtr driver = conn->privateData;
1030
    virDomainObjPtr vm = NULL;
1031
    virDomainDefPtr def;
1032
    virDomainPtr dom = NULL;
1033
    virDomainEventPtr event = NULL;
1034

1035
    virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
1036

1037
    lxcDriverLock(driver);
1038
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1039
                                        1 << VIR_DOMAIN_VIRT_LXC,
1040
                                        VIR_DOMAIN_XML_INACTIVE)))
1041
        goto cleanup;
1042

1043 1044 1045
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
        goto cleanup;

1046 1047
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
1048

1049
    if ((def->nets != NULL) && !(driver->have_netns)) {
1050 1051
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("System lacks NETNS support"));
1052
        goto cleanup;
1053 1054
    }

1055

1056
    if (!(vm = virDomainAssignDef(driver->caps,
1057
                                  &driver->domains, def, false)))
1058 1059
        goto cleanup;
    def = NULL;
1060

1061 1062 1063
    if (virLXCProcessStart(conn, driver, vm,
                           (flags & VIR_DOMAIN_START_AUTODESTROY),
                           VIR_DOMAIN_RUNNING_BOOTED) < 0) {
1064
        virDomainAuditStart(vm, "booted", false);
1065
        virDomainRemoveInactive(&driver->domains, vm);
1066
        vm = NULL;
1067
        goto cleanup;
1068 1069
    }

1070 1071 1072
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1073
    virDomainAuditStart(vm, "booted", true);
1074

1075
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1076
    if (dom)
1077 1078
        dom->id = vm->def->id;

1079 1080
cleanup:
    virDomainDefFree(def);
1081 1082
    if (vm)
        virDomainObjUnlock(vm);
1083
    if (event)
1084
        virDomainEventStateQueue(driver->domainEventState, event);
1085
    lxcDriverUnlock(driver);
1086 1087 1088
    return dom;
}

1089

1090 1091
static int lxcDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
1092
    virLXCDriverPtr driver = dom->conn->privateData;
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
    virDomainObjPtr vm;
    int ret = -1;

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

    memset(seclabel, 0, sizeof(*seclabel));

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1104 1105
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1106 1107 1108 1109
        goto cleanup;
    }

    if (!virDomainVirtTypeToString(vm->def->virtType)) {
1110 1111 1112
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
        goto cleanup;
    }

    /*
     * Theoretically, the pid can be replaced during this operation and
     * return the label of a different process.  If atomicity is needed,
     * further validation will be required.
     *
     * Comment from Dan Berrange:
     *
     *   Well the PID as stored in the virDomainObjPtr can't be changed
     *   because you've got a locked object.  The OS level PID could have
     *   exited, though and in extreme circumstances have cycled through all
     *   PIDs back to ours. We could sanity check that our PID still exists
     *   after reading the label, by checking that our FD connecting to the
     *   LXC monitor hasn't seen SIGHUP/ERR on poll().
     */
    if (virDomainObjIsActive(vm)) {
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
                                              vm->def, vm->pid, seclabel) < 0) {
1133 1134
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
            goto cleanup;
        }
    }

    ret = 0;

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

static int lxcNodeGetSecurityModel(virConnectPtr conn,
                                   virSecurityModelPtr secmodel)
{
1151
    virLXCDriverPtr driver = conn->privateData;
1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
    int ret = 0;

    lxcDriverLock(driver);
    memset(secmodel, 0, sizeof(*secmodel));

    /* NULL indicates no driver, which we treat as
     * success, but simply return no data in *secmodel */
    if (driver->caps->host.secModel.model == NULL)
        goto cleanup;

    if (!virStrcpy(secmodel->model, driver->caps->host.secModel.model,
                   VIR_SECURITY_MODEL_BUFLEN)) {
1164 1165 1166
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN - 1);
1167 1168 1169 1170 1171 1172
        ret = -1;
        goto cleanup;
    }

    if (!virStrcpy(secmodel->doi, driver->caps->host.secModel.doi,
                   VIR_SECURITY_DOI_BUFLEN)) {
1173 1174 1175
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185
        ret = -1;
        goto cleanup;
    }

cleanup:
    lxcDriverUnlock(driver);
    return ret;
}


1186
static int
1187 1188 1189 1190
lxcDomainEventRegister(virConnectPtr conn,
                       virConnectDomainEventCallback callback,
                       void *opaque,
                       virFreeCallback freecb)
1191
{
1192
    virLXCDriverPtr driver = conn->privateData;
1193 1194 1195
    int ret;

    lxcDriverLock(driver);
1196 1197 1198
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
1199
    lxcDriverUnlock(driver);
1200

1201
    return ret;
1202 1203
}

1204

1205
static int
1206 1207
lxcDomainEventDeregister(virConnectPtr conn,
                         virConnectDomainEventCallback callback)
1208
{
1209
    virLXCDriverPtr driver = conn->privateData;
1210 1211 1212
    int ret;

    lxcDriverLock(driver);
1213 1214 1215
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
1216 1217 1218 1219 1220
    lxcDriverUnlock(driver);

    return ret;
}

1221 1222 1223 1224 1225 1226 1227 1228 1229

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

    lxcDriverLock(driver);
1234 1235 1236 1237
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
1238
        ret = -1;
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
    lxcDriverUnlock(driver);

    return ret;
}


static int
lxcDomainEventDeregisterAny(virConnectPtr conn,
                            int callbackID)
{
1249
    virLXCDriverPtr driver = conn->privateData;
1250 1251 1252
    int ret;

    lxcDriverLock(driver);
1253 1254 1255
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
1256 1257 1258 1259 1260 1261
    lxcDriverUnlock(driver);

    return ret;
}


1262
/**
1263
 * lxcDomainDestroyFlags:
1264
 * @dom: pointer to domain to destroy
1265
 * @flags: an OR'ed set of virDomainDestroyFlags
1266 1267 1268 1269 1270
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
1271 1272 1273
static int
lxcDomainDestroyFlags(virDomainPtr dom,
                      unsigned int flags)
1274
{
1275
    virLXCDriverPtr driver = dom->conn->privateData;
1276
    virDomainObjPtr vm;
1277
    virDomainEventPtr event = NULL;
1278
    int ret = -1;
1279
    virLXCDomainObjPrivatePtr priv;
1280

1281 1282
    virCheckFlags(0, -1);

1283
    lxcDriverLock(driver);
1284
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1285
    if (!vm) {
1286 1287
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1288 1289
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
1290
        goto cleanup;
1291 1292
    }

1293
    if (!virDomainObjIsActive(vm)) {
1294 1295
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
1296 1297 1298
        goto cleanup;
    }

1299
    priv = vm->privateData;
1300
    ret = virLXCProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
1301 1302 1303
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
1304
    priv->doneStopEvent = true;
1305
    virDomainAuditStop(vm, "destroyed");
1306 1307 1308 1309
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1310 1311

cleanup:
1312 1313
    if (vm)
        virDomainObjUnlock(vm);
1314
    if (event)
1315
        virDomainEventStateQueue(driver->domainEventState, event);
1316
    lxcDriverUnlock(driver);
1317
    return ret;
1318
}
1319

1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
/**
 * lxcDomainDestroy:
 * @dom: pointer to domain to destroy
 *
 * Sends SIGKILL to container root process to terminate the container
 *
 * Returns 0 on success or -1 in case of error
 */
static int
lxcDomainDestroy(virDomainPtr dom)
{
    return lxcDomainDestroyFlags(dom, 0);
}

1334 1335 1336 1337 1338
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1339
    if (virRun(argv, &ip_rc) < 0 ||
1340 1341
        !(WIFEXITED(ip_rc) && (WEXITSTATUS(ip_rc) != 255)))
        return 0;
1342

1343 1344
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
1345

1346
    return 1;
1347 1348
}

1349

1350
static int
1351
lxcSecurityInit(virLXCDriverPtr driver)
1352
{
1353
    VIR_INFO("lxcSecurityInit %s", driver->securityDriverName);
1354
    virSecurityManagerPtr mgr = virSecurityManagerNew(driver->securityDriverName,
1355
                                                      LXC_DRIVER_NAME,
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
                                                      false,
                                                      driver->securityDefaultConfined,
                                                      driver->securityRequireConfined);
    if (!mgr)
        goto error;

    driver->securityManager = mgr;

    return 0;

error:
    VIR_ERROR(_("Failed to initialize security drivers"));
    virSecurityManagerFree(mgr);
    return -1;
}


1373
static int lxcStartup(int privileged)
D
Daniel Veillard 已提交
1374
{
1375
    char *ld;
1376
    int rc;
1377 1378 1379 1380 1381 1382

    /* 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");
1383
    if (ld && strstr(ld, "vgpreload")) {
1384
        VIR_INFO("Running under valgrind, disabling driver");
1385 1386
        return 0;
    }
1387

1388
    /* Check that the user is root, silently disable if not */
1389
    if (!privileged) {
1390
        VIR_INFO("Not running privileged, disabling driver");
1391 1392 1393 1394 1395
        return 0;
    }

    /* Check that this is a container enabled kernel */
    if (lxcContainerAvailable(0) < 0) {
1396
        VIR_INFO("LXC support not available in this kernel, disabling driver");
1397
        return 0;
1398 1399
    }

1400
    if (VIR_ALLOC(lxc_driver) < 0) {
1401 1402
        return -1;
    }
1403 1404 1405 1406
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
1407
    lxcDriverLock(lxc_driver);
D
Daniel Veillard 已提交
1408

1409 1410 1411
    if (virDomainObjListInit(&lxc_driver->domains) < 0)
        goto cleanup;

1412
    lxc_driver->domainEventState = virDomainEventStateNew();
1413
    if (!lxc_driver->domainEventState)
1414 1415
        goto cleanup;

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

1419 1420
    rc = virCgroupForDriver("lxc", &lxc_driver->cgroup, privileged, 1);
    if (rc < 0) {
1421
        char buf[1024] ATTRIBUTE_UNUSED;
1422 1423 1424 1425 1426
        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
         */
1427 1428
    }

D
Daniel Veillard 已提交
1429
    /* Call function to load lxc driver configuration information */
1430 1431
    if (lxcLoadDriverConfig(lxc_driver) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
1432

1433 1434 1435 1436
    if (lxcSecurityInit(lxc_driver) < 0)
        goto cleanup;

    if ((lxc_driver->caps = lxcCapsInit(lxc_driver)) == NULL)
1437
        goto cleanup;
D
Daniel Veillard 已提交
1438

1439
    virLXCDomainSetPrivateDataHooks(lxc_driver->caps);
1440

1441
    if (virLXCProcessAutoDestroyInit(lxc_driver) < 0)
1442 1443
        goto cleanup;

O
Osier Yang 已提交
1444 1445 1446 1447 1448
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(lxc_driver->caps,
                                &lxc_driver->domains,
                                lxc_driver->stateDir,
                                NULL,
M
Matthias Bolte 已提交
1449 1450
                                1, 1 << VIR_DOMAIN_VIRT_LXC,
                                NULL, NULL) < 0)
O
Osier Yang 已提交
1451 1452
        goto cleanup;

1453
    virLXCProcessReconnectAll(lxc_driver, &lxc_driver->domains);
O
Osier Yang 已提交
1454 1455

    /* Then inactive persistent configs */
1456
    if (virDomainLoadAllConfigs(lxc_driver->caps,
1457 1458
                                &lxc_driver->domains,
                                lxc_driver->configDir,
1459
                                lxc_driver->autostartDir,
M
Matthias Bolte 已提交
1460 1461
                                0, 1 << VIR_DOMAIN_VIRT_LXC,
                                NULL, NULL) < 0)
1462
        goto cleanup;
1463

1464
    lxcDriverUnlock(lxc_driver);
1465

1466
    virLXCProcessAutostartAll(lxc_driver);
1467

D
Daniel Veillard 已提交
1468 1469
    return 0;

1470 1471 1472 1473
cleanup:
    lxcDriverUnlock(lxc_driver);
    lxcShutdown();
    return -1;
D
Daniel Veillard 已提交
1474 1475
}

1476 1477
static void lxcNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
1478
    virLXCDriverPtr driver = opaque;
1479 1480 1481 1482 1483 1484 1485

    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
1486
            virDomainEventStateQueue(driver->domainEventState, event);
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
    }
}

/**
 * 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);
1502
    virDomainLoadAllConfigs(lxc_driver->caps,
1503 1504 1505
                            &lxc_driver->domains,
                            lxc_driver->configDir,
                            lxc_driver->autostartDir,
M
Matthias Bolte 已提交
1506 1507
                            0, 1 << VIR_DOMAIN_VIRT_LXC,
                            lxcNotifyLoadDomain, lxc_driver);
1508 1509 1510 1511 1512
    lxcDriverUnlock(lxc_driver);

    return 0;
}

1513
static int lxcShutdown(void)
D
Daniel Veillard 已提交
1514
{
1515
    if (lxc_driver == NULL)
1516
        return -1;
1517

1518
    lxcDriverLock(lxc_driver);
1519
    virDomainObjListDeinit(&lxc_driver->domains);
1520
    virDomainEventStateFree(lxc_driver->domainEventState);
1521

1522
    virLXCProcessAutoDestroyShutdown(lxc_driver);
1523

1524
    virCapabilitiesFree(lxc_driver->caps);
1525
    virSecurityManagerFree(lxc_driver->securityManager);
1526 1527 1528 1529 1530
    VIR_FREE(lxc_driver->configDir);
    VIR_FREE(lxc_driver->autostartDir);
    VIR_FREE(lxc_driver->stateDir);
    VIR_FREE(lxc_driver->logDir);
    lxcDriverUnlock(lxc_driver);
1531
    virMutexDestroy(&lxc_driver->lock);
1532
    VIR_FREE(lxc_driver);
1533 1534 1535

    return 0;
}
D
Daniel Veillard 已提交
1536

1537 1538 1539 1540 1541 1542 1543 1544 1545
/**
 * lxcActive:
 *
 * Checks if the LXC daemon is active, i.e. has an active domain
 *
 * Returns 1 if active, 0 otherwise
 */
static int
lxcActive(void) {
1546
    int active;
1547

1548
    if (lxc_driver == NULL)
1549
        return 0;
1550

1551
    lxcDriverLock(lxc_driver);
1552
    active = virDomainObjListNumOfDomains(&lxc_driver->domains, 1);
1553
    lxcDriverUnlock(lxc_driver);
1554

1555
    return active;
D
Daniel Veillard 已提交
1556 1557
}

1558
static int lxcVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
D
Dan Smith 已提交
1559 1560 1561
{
    struct utsname ver;

1562
    uname(&ver);
D
Dan Smith 已提交
1563

1564
    if (virParseVersionString(ver.release, version, true) < 0) {
1565
        virReportError(VIR_ERR_INTERNAL_ERROR, _("Unknown release: %s"), ver.release);
D
Dan Smith 已提交
1566 1567 1568 1569 1570
        return -1;
    }

    return 0;
}
1571

1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605

/*
 * check whether the host supports CFS bandwidth
 *
 * Return 1 when CFS bandwidth is supported, 0 when CFS bandwidth is not
 * supported, -1 on error.
 */
static int lxcGetCpuBWStatus(virCgroupPtr cgroup)
{
    char *cfs_period_path = NULL;
    int ret = -1;

    if (!cgroup)
        return 0;

    if (virCgroupPathOfController(cgroup, VIR_CGROUP_CONTROLLER_CPU,
                                  "cpu.cfs_period_us", &cfs_period_path) < 0) {
        VIR_INFO("cannot get the path of cgroup CPU controller");
        ret = 0;
        goto cleanup;
    }

    if (access(cfs_period_path, F_OK) < 0) {
        ret = 0;
    } else {
        ret = 1;
    }

cleanup:
    VIR_FREE(cfs_period_path);
    return ret;
}


1606
static bool lxcCgroupControllerActive(virLXCDriverPtr driver,
1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
                                      int controller)
{
    if (driver->cgroup == NULL)
        return false;
    if (controller < 0 || controller >= VIR_CGROUP_CONTROLLER_LAST)
        return false;
    if (!virCgroupMounted(driver->cgroup, controller))
        return false;
#if 0
    if (driver->cgroupControllers & (1 << controller))
        return true;
#endif
    return false;
}



static char *lxcGetSchedulerType(virDomainPtr domain,
1625
                                 int *nparams)
1626
{
1627
    virLXCDriverPtr driver = domain->conn->privateData;
1628 1629
    char *ret = NULL;
    int rc;
1630

1631 1632
    lxcDriverLock(driver);
    if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
1633 1634
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
1635 1636
        goto cleanup;
    }
1637

1638 1639 1640 1641 1642 1643 1644 1645 1646
    if (nparams) {
        rc = lxcGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        else if (rc == 0)
            *nparams = 1;
        else
            *nparams = 3;
    }
1647

1648 1649
    ret = strdup("posix");
    if (!ret)
1650
        virReportOOMError();
1651

1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722
cleanup:
    lxcDriverUnlock(driver);
    return ret;
}


static int
lxcGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                 long long *quota)
{
    int rc;

    rc = virCgroupGetCpuCfsPeriod(cgroup, period);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth period tunable"));
        return -1;
    }

    rc = virCgroupGetCpuCfsQuota(cgroup, quota);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth tunable"));
        return -1;
    }

    return 0;
}


static int lxcSetVcpuBWLive(virCgroupPtr cgroup, unsigned long long period,
                            long long quota)
{
    int rc;
    unsigned long long old_period;

    if (period == 0 && quota == 0)
        return 0;

    if (period) {
        /* get old period, and we can rollback if set quota failed */
        rc = virCgroupGetCpuCfsPeriod(cgroup, &old_period);
        if (rc < 0) {
            virReportSystemError(-rc,
                                 "%s", _("Unable to get cpu bandwidth period"));
            return -1;
        }

        rc = virCgroupSetCpuCfsPeriod(cgroup, period);
        if (rc < 0) {
            virReportSystemError(-rc,
                                 "%s", _("Unable to set cpu bandwidth period"));
            return -1;
        }
    }

    if (quota) {
        rc = virCgroupSetCpuCfsQuota(cgroup, quota);
        if (rc < 0) {
            virReportSystemError(-rc,
                                 "%s", _("Unable to set cpu bandwidth quota"));
            goto cleanup;
        }
    }

    return 0;

cleanup:
    if (period) {
        rc = virCgroupSetCpuCfsPeriod(cgroup, old_period);
        if (rc < 0)
1723 1724
            virReportSystemError(-rc, "%s",
                                 _("Unable to rollback cpu bandwidth period"));
1725 1726 1727
    }

    return -1;
1728 1729
}

1730

1731
static int
1732
lxcSetSchedulerParametersFlags(virDomainPtr dom,
1733 1734 1735
                               virTypedParameterPtr params,
                               int nparams,
                               unsigned int flags)
1736
{
1737
    virLXCDriverPtr driver = dom->conn->privateData;
1738
    int i;
1739 1740
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
1741
    virDomainDefPtr vmdef = NULL;
1742
    int ret = -1;
1743
    int rc;
1744

1745 1746
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1747 1748 1749 1750 1751 1752 1753 1754 1755
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                       VIR_TYPED_PARAM_LLONG,
                                       NULL) < 0)
        return -1;
1756 1757

    lxcDriverLock(driver);
1758 1759

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

1761
    if (vm == NULL) {
1762 1763
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
1764
        goto cleanup;
1765 1766
    }

E
Eric Blake 已提交
1767 1768 1769
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &vmdef) < 0)
        goto cleanup;
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
1780 1781
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
1782 1783 1784
            goto cleanup;
        }
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
1785 1786 1787
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
1788 1789 1790
            goto cleanup;
        }
    }
1791 1792

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

1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = virCgroupSetCpuShares(group, params[i].value.ul);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set cpu shares tunable"));
                    goto cleanup;
                }

                vm->def->cputune.shares = params[i].value.ul;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.shares = params[i].value.ul;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = lxcSetVcpuBWLive(group, params[i].value.ul, 0);
                if (rc != 0)
                    goto cleanup;

                if (params[i].value.ul)
                    vm->def->cputune.period = params[i].value.ul;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.period = params[i].value.ul;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                rc = lxcSetVcpuBWLive(group, 0, params[i].value.l);
                if (rc != 0)
                    goto cleanup;

                if (params[i].value.l)
                    vm->def->cputune.quota = params[i].value.l;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                vmdef->cputune.quota = params[i].value.l;
            }
1836
        }
1837
    }
1838

1839 1840
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto cleanup;
1841

1842 1843 1844 1845

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        rc = virDomainSaveConfig(driver->configDir, vmdef);
        if (rc < 0)
1846
            goto cleanup;
1847

1848 1849
        virDomainObjAssignDef(vm, vmdef, false);
        vmdef = NULL;
1850
    }
1851

1852
    ret = 0;
1853

1854
cleanup:
1855
    virDomainDefFree(vmdef);
1856
    virCgroupFree(&group);
1857 1858
    if (vm)
        virDomainObjUnlock(vm);
1859
    lxcDriverUnlock(driver);
1860
    return ret;
1861 1862
}

1863 1864 1865 1866 1867 1868 1869 1870 1871
static int
lxcSetSchedulerParameters(virDomainPtr domain,
                          virTypedParameterPtr params,
                          int nparams)
{
    return lxcSetSchedulerParametersFlags(domain, params, nparams, 0);
}

static int
1872
lxcGetSchedulerParametersFlags(virDomainPtr dom,
1873 1874 1875
                               virTypedParameterPtr params,
                               int *nparams,
                               unsigned int flags)
1876
{
1877
    virLXCDriverPtr driver = dom->conn->privateData;
1878 1879
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
E
Eric Blake 已提交
1880
    virDomainDefPtr persistentDef;
1881 1882 1883
    unsigned long long shares = 0;
    unsigned long long period = 0;
    long long quota = 0;
1884
    int ret = -1;
1885 1886 1887
    int rc;
    bool cpu_bw_status = false;
    int saved_nparams = 0;
1888

1889 1890
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
1891

1892
    lxcDriverLock(driver);
1893 1894 1895 1896 1897 1898 1899 1900 1901

    if (*nparams > 1) {
        rc = lxcGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        cpu_bw_status = !!rc;
    }

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

1903
    if (vm == NULL) {
1904 1905
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
1906 1907 1908
        goto cleanup;
    }

E
Eric Blake 已提交
1909 1910 1911
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
1912 1913

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
1914 1915 1916 1917
        shares = persistentDef->cputune.shares;
        if (*nparams > 1 && cpu_bw_status) {
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
1918 1919 1920 1921 1922
        }
        goto out;
    }

    if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
1923 1924
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
1925
        goto cleanup;
1926 1927
    }

1928
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
1929 1930
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
1931
        goto cleanup;
1932
    }
1933

1934 1935 1936 1937
    rc = virCgroupGetCpuShares(group, &shares);
    if (rc != 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu shares tunable"));
1938
        goto cleanup;
1939 1940 1941 1942 1943 1944 1945 1946
    }

    if (*nparams > 1 && cpu_bw_status) {
        rc = lxcGetVcpuBWLive(group, &period, &quota);
        if (rc != 0)
            goto cleanup;
    }
out:
1947 1948
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
1949
        goto cleanup;
1950 1951 1952 1953
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
1954 1955 1956
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
1957 1958 1959 1960 1961
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
1962 1963 1964
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
1965 1966 1967 1968 1969 1970 1971
                goto cleanup;
            saved_nparams++;
        }
    }

    *nparams = saved_nparams;

1972
    ret = 0;
1973

1974 1975
cleanup:
    virCgroupFree(&group);
1976 1977
    if (vm)
        virDomainObjUnlock(vm);
1978
    lxcDriverUnlock(driver);
1979
    return ret;
1980 1981
}

1982 1983 1984 1985 1986 1987 1988 1989
static int
lxcGetSchedulerParameters(virDomainPtr domain,
                          virTypedParameterPtr params,
                          int *nparams)
{
    return lxcGetSchedulerParametersFlags(domain, params, nparams, 0);
}

1990

1991 1992 1993 1994 1995
static int
lxcDomainSetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
1996
{
1997
    virLXCDriverPtr driver = dom->conn->privateData;
1998 1999 2000 2001 2002 2003 2004 2005
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2006 2007 2008 2009 2010 2011
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_BLKIO_WEIGHT,
                                       VIR_TYPED_PARAM_UINT,
                                       NULL) < 0)
        return -1;

2012 2013 2014 2015 2016
    lxcDriverLock(driver);

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

    if (vm == NULL) {
2017 2018
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
2019 2020 2021
        goto cleanup;
    }

E
Eric Blake 已提交
2022 2023 2024
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
2025 2026 2027

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
2028 2029
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2030 2031 2032 2033
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
2034 2035
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
2036 2037 2038 2039 2040 2041 2042 2043 2044 2045
            goto cleanup;
        }

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

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                int rc;

                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
2046 2047
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
E
Eric Blake 已提交
2048
                    goto cleanup;
2049 2050 2051 2052 2053 2054
                }

                rc = virCgroupSetBlkioWeight(group, params[i].value.ui);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set blkio weight tunable"));
E
Eric Blake 已提交
2055
                    goto cleanup;
2056 2057 2058
                }
            }
        }
E
Eric Blake 已提交
2059 2060
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2061 2062 2063 2064 2065 2066 2067 2068
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

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

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
2069 2070
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
E
Eric Blake 已提交
2071
                    goto cleanup;
2072 2073 2074 2075 2076 2077 2078
                }

                persistentDef->blkio.weight = params[i].value.ui;
            }
        }

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
E
Eric Blake 已提交
2079
            goto cleanup;
2080 2081
    }

E
Eric Blake 已提交
2082
    ret = 0;
2083 2084 2085 2086 2087 2088 2089 2090 2091 2092
cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}


#define LXC_NB_BLKIO_PARAM  1
2093 2094 2095 2096 2097
static int
lxcDomainGetBlkioParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
2098
{
2099
    virLXCDriverPtr driver = dom->conn->privateData;
2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    unsigned int val;
    int ret = -1;
    int rc;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
    lxcDriverLock(driver);

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

    if (vm == NULL) {
2115 2116
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
2117 2118 2119 2120 2121 2122 2123 2124 2125 2126
        goto cleanup;
    }

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

E
Eric Blake 已提交
2127 2128 2129
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
2130 2131 2132

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!lxcCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
2133 2134
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
2135 2136 2137 2138
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
2139 2140
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155
            goto cleanup;
        }

        for (i = 0; i < *nparams && i < LXC_NB_BLKIO_PARAM; i++) {
            virTypedParameterPtr param = &params[i];
            val = 0;

            switch (i) {
            case 0: /* fill blkio weight here */
                rc = virCgroupGetBlkioWeight(group, &val);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get blkio weight"));
                    goto cleanup;
                }
2156 2157
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        for (i = 0; i < *nparams && i < LXC_NB_BLKIO_PARAM; i++) {
            virTypedParameterPtr param = &params[i];

            switch (i) {
            case 0: /* fill blkio weight here */
2172 2173 2174
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT,
                                            persistentDef->blkio.weight) < 0)
2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198
                    goto cleanup;
                break;

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

    if (LXC_NB_BLKIO_PARAM < *nparams)
        *nparams = LXC_NB_BLKIO_PARAM;
    ret = 0;

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


2199 2200 2201 2202 2203 2204
#ifdef __linux__
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path,
                        struct _virDomainInterfaceStats *stats)
{
2205
    virLXCDriverPtr driver = dom->conn->privateData;
2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216
    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);
2217 2218
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
2219 2220 2221 2222
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2223 2224
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237
        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)
2238
        ret = linuxDomainInterfaceStats(path, stats);
2239
    else
2240 2241
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Invalid path, '%s' is not a known interface"), path);
2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}
#else
static int
lxcDomainInterfaceStats(virDomainPtr dom,
                        const char *path ATTRIBUTE_UNUSED,
                        struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
A
Alex Jia 已提交
2253
{
2254
    virReportError(VIR_ERR_NO_SUPPORT, "%s", __FUNCTION__);
2255 2256 2257 2258
    return -1;
}
#endif

2259 2260
static int lxcDomainGetAutostart(virDomainPtr dom,
                                   int *autostart) {
2261
    virLXCDriverPtr driver = dom->conn->privateData;
2262 2263 2264 2265 2266 2267 2268 2269 2270 2271
    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);
2272 2273
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
        goto cleanup;
    }

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

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

static int lxcDomainSetAutostart(virDomainPtr dom,
                                   int autostart) {
2288
    virLXCDriverPtr driver = dom->conn->privateData;
2289 2290 2291 2292 2293 2294 2295 2296 2297 2298
    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);
2299 2300
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
2301 2302 2303 2304
        goto cleanup;
    }

    if (!vm->persistent) {
2305 2306
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Cannot set autostart for transient domain"));
2307 2308 2309 2310 2311
        goto cleanup;
    }

    autostart = (autostart != 0);

2312 2313 2314 2315
    if (vm->autostart == autostart) {
        ret = 0;
        goto cleanup;
    }
2316

2317
    configFile = virDomainConfigFile(driver->configDir,
2318 2319 2320
                                     vm->def->name);
    if (configFile == NULL)
        goto cleanup;
2321
    autostartLink = virDomainConfigFile(driver->autostartDir,
2322 2323 2324
                                        vm->def->name);
    if (autostartLink == NULL)
        goto cleanup;
2325

2326
    if (autostart) {
2327 2328
        if (virFileMakePath(driver->autostartDir) < 0) {
            virReportSystemError(errno,
2329 2330 2331
                                 _("Cannot create autostart directory %s"),
                                 driver->autostartDir);
            goto cleanup;
2332 2333
        }

2334
        if (symlink(configFile, autostartLink) < 0) {
2335
            virReportSystemError(errno,
2336 2337 2338 2339 2340 2341
                                 _("Failed to create symlink '%s to '%s'"),
                                 autostartLink, configFile);
            goto cleanup;
        }
    } else {
        if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
2342
            virReportSystemError(errno,
2343 2344 2345 2346
                                 _("Failed to delete symlink '%s'"),
                                 autostartLink);
            goto cleanup;
        }
2347
    }
2348 2349

    vm->autostart = autostart;
2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360
    ret = 0;

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

2361
static int lxcFreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm)
R
Ryota Ozaki 已提交
2362 2363 2364 2365 2366 2367 2368 2369 2370 2371
{
    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 &&
2372
          virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) == 0))
R
Ryota Ozaki 已提交
2373 2374
        return -1;

2375 2376
    /* From here on, we know that cgroup != NULL.  */

R
Ryota Ozaki 已提交
2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397
    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)
2398
            VIR_DEBUG("Writing freezer.state gets EBUSY");
R
Ryota Ozaki 已提交
2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437

        /*
         * 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);
    }
2438
    VIR_DEBUG("lxcFreezeContainer timeout");
R
Ryota Ozaki 已提交
2439 2440 2441 2442 2443 2444 2445 2446 2447 2448
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:
2449
    virCgroupFree(&cgroup);
R
Ryota Ozaki 已提交
2450 2451 2452 2453 2454 2455
    VIR_FREE(state);
    return ret;
}

static int lxcDomainSuspend(virDomainPtr dom)
{
2456
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
2457 2458 2459 2460 2461 2462 2463 2464 2465 2466
    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);
2467 2468
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2469 2470 2471
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2472
    if (!virDomainObjIsActive(vm)) {
2473 2474
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2475 2476 2477
        goto cleanup;
    }

J
Jiri Denemark 已提交
2478
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2479
        if (lxcFreezeContainer(driver, vm) < 0) {
2480 2481
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Suspend operation failed"));
R
Ryota Ozaki 已提交
2482 2483
            goto cleanup;
        }
J
Jiri Denemark 已提交
2484
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
R
Ryota Ozaki 已提交
2485 2486 2487 2488 2489 2490

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

2491
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2492 2493 2494 2495 2496
        goto cleanup;
    ret = 0;

cleanup:
    if (event)
2497
        virDomainEventStateQueue(driver->domainEventState, event);
R
Ryota Ozaki 已提交
2498 2499 2500 2501 2502 2503
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

2504
static int lxcUnfreezeContainer(virLXCDriverPtr driver, virDomainObjPtr vm)
R
Ryota Ozaki 已提交
2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520
{
    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)
{
2521
    virLXCDriverPtr driver = dom->conn->privateData;
R
Ryota Ozaki 已提交
2522 2523 2524 2525 2526 2527 2528 2529 2530 2531
    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);
2532 2533
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("No domain with matching uuid '%s'"), uuidstr);
R
Ryota Ozaki 已提交
2534 2535 2536
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
2537
    if (!virDomainObjIsActive(vm)) {
2538 2539
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
R
Ryota Ozaki 已提交
2540 2541 2542
        goto cleanup;
    }

J
Jiri Denemark 已提交
2543
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
R
Ryota Ozaki 已提交
2544
        if (lxcUnfreezeContainer(driver, vm) < 0) {
2545 2546
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Resume operation failed"));
R
Ryota Ozaki 已提交
2547 2548
            goto cleanup;
        }
J
Jiri Denemark 已提交
2549 2550
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
R
Ryota Ozaki 已提交
2551 2552 2553 2554 2555 2556

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

2557
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
R
Ryota Ozaki 已提交
2558 2559 2560 2561 2562
        goto cleanup;
    ret = 0;

cleanup:
    if (event)
2563
        virDomainEventStateQueue(driver->domainEventState, event);
R
Ryota Ozaki 已提交
2564 2565 2566 2567 2568 2569
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
    return ret;
}

2570 2571
static int
lxcDomainOpenConsole(virDomainPtr dom,
2572
                      const char *dev_name,
2573 2574 2575
                      virStreamPtr st,
                      unsigned int flags)
{
2576
    virLXCDriverPtr driver = dom->conn->privateData;
2577 2578 2579 2580
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
2581
    size_t i;
2582 2583 2584 2585 2586 2587 2588

    virCheckFlags(0, -1);

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

    if (!virDomainObjIsActive(vm)) {
2595 2596
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2597 2598 2599
        goto cleanup;
    }

2600
    if (dev_name) {
2601 2602 2603 2604 2605 2606 2607
        for (i = 0 ; i < vm->def->nconsoles ; i++) {
            if (vm->def->consoles[i]->info.alias &&
                STREQ(vm->def->consoles[i]->info.alias, dev_name)) {
                chr = vm->def->consoles[i];
                break;
            }
        }
2608
    } else {
2609 2610
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
2611 2612 2613 2614 2615
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
2616 2617 2618
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find console device '%s'"),
                       dev_name ? dev_name : _("default"));
2619 2620 2621
        goto cleanup;
    }

2622
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
2623 2624
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("character device %s is not using a PTY"), dev_name);
2625 2626 2627
        goto cleanup;
    }

2628
    if (virFDStreamOpenFile(st, chr->source.data.file.path,
E
Eric Blake 已提交
2629
                            0, 0, O_RDWR) < 0)
2630 2631 2632 2633 2634 2635 2636 2637 2638 2639
        goto cleanup;

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

2640 2641 2642 2643 2644
static int
lxcListAllDomains(virConnectPtr conn,
                  virDomainPtr **domains,
                  unsigned int flags)
{
2645
    virLXCDriverPtr driver = conn->privateData;
2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656
    int ret = -1;

    virCheckFlags(VIR_CONNECT_LIST_FILTERS_ALL, -1);

    lxcDriverLock(driver);
    ret = virDomainList(conn, driver->domains.objs, domains, flags);
    lxcDriverUnlock(driver);

    return ret;
}

2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683
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 已提交
2684

D
Daniel Veillard 已提交
2685 2686
/* Function Tables */
static virDriver lxcDriver = {
2687
    .no = VIR_DRV_LXC,
2688
    .name = LXC_DRIVER_NAME,
2689 2690 2691 2692 2693 2694 2695 2696
    .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 */
2697
    .listAllDomains = lxcListAllDomains, /* 0.9.13 */
2698 2699 2700 2701 2702 2703 2704
    .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 */
2705
    .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
2706 2707 2708 2709 2710 2711
    .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 */
2712 2713
    .domainSetBlkioParameters = lxcDomainSetBlkioParameters, /* 0.9.8 */
    .domainGetBlkioParameters = lxcDomainGetBlkioParameters, /* 0.9.8 */
2714 2715
    .domainGetInfo = lxcDomainGetInfo, /* 0.4.2 */
    .domainGetState = lxcDomainGetState, /* 0.9.2 */
2716 2717
    .domainGetSecurityLabel = lxcDomainGetSecurityLabel, /* 0.9.10 */
    .nodeGetSecurityModel = lxcNodeGetSecurityModel, /* 0.9.10 */
2718 2719 2720 2721 2722 2723 2724
    .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 */
2725
    .domainUndefineFlags = lxcDomainUndefineFlags, /* 0.9.4 */
2726 2727 2728 2729
    .domainGetAutostart = lxcDomainGetAutostart, /* 0.7.0 */
    .domainSetAutostart = lxcDomainSetAutostart, /* 0.7.0 */
    .domainGetSchedulerType = lxcGetSchedulerType, /* 0.5.0 */
    .domainGetSchedulerParameters = lxcGetSchedulerParameters, /* 0.5.0 */
2730
    .domainGetSchedulerParametersFlags = lxcGetSchedulerParametersFlags, /* 0.9.2 */
2731
    .domainSetSchedulerParameters = lxcSetSchedulerParameters, /* 0.5.0 */
2732
    .domainSetSchedulerParametersFlags = lxcSetSchedulerParametersFlags, /* 0.9.2 */
2733
    .domainInterfaceStats = lxcDomainInterfaceStats, /* 0.7.3 */
2734
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
2735
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747
    .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 */
2748
    .isAlive = lxcIsAlive, /* 0.9.8 */
2749
    .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
D
Daniel Veillard 已提交
2750 2751
};

2752
static virStateDriver lxcStateDriver = {
2753
    .name = LXC_DRIVER_NAME,
2754 2755 2756
    .initialize = lxcStartup,
    .cleanup = lxcShutdown,
    .active = lxcActive,
2757
    .reload = lxcReload,
2758 2759
};

D
Daniel Veillard 已提交
2760 2761 2762
int lxcRegister(void)
{
    virRegisterDriver(&lxcDriver);
2763
    virRegisterStateDriver(&lxcStateDriver);
2764
    virNWFilterRegisterCallbackDriver(&lxcCallbackDriver);
D
Daniel Veillard 已提交
2765 2766
    return 0;
}