lxc_driver.c 38.3 KB
Newer Older
D
Daniel Veillard 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * Copyright IBM Corp. 2008
 *
 * lxc_driver.c: linux container driver functions
 *
 * Authors:
 *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <config.h>

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

38
#include "virterror_internal.h"
39
#include "logging.h"
40
#include "datatypes.h"
D
Daniel Veillard 已提交
41
#include "lxc_conf.h"
42
#include "lxc_container.h"
D
Daniel Veillard 已提交
43
#include "lxc_driver.h"
44
#include "memory.h"
45
#include "util.h"
46 47
#include "bridge.h"
#include "veth.h"
48
#include "event.h"
D
Dan Smith 已提交
49
#include "cgroup.h"
50

D
Daniel Veillard 已提交
51

52 53
#define VIR_FROM_THIS VIR_FROM_LXC

54 55
static int lxcStartup(void);
static int lxcShutdown(void);
56
static lxc_driver_t *lxc_driver = NULL;
D
Daniel Veillard 已提交
57 58 59

/* Functions */

60 61
static void lxcDriverLock(lxc_driver_t *driver)
{
62
    virMutexLock(&driver->lock);
63 64 65
}
static void lxcDriverUnlock(lxc_driver_t *driver)
{
66
    virMutexUnlock(&driver->lock);
67 68 69
}


70
static int lxcProbe(void)
D
Daniel Veillard 已提交
71
{
72 73 74
    if (getuid() != 0 ||
        lxcContainerAvailable(0) < 0)
        return 0;
75

76
    return 1;
D
Daniel Veillard 已提交
77 78 79 80 81 82
}

static virDrvOpenStatus lxcOpen(virConnectPtr conn,
                                virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                int flags ATTRIBUTE_UNUSED)
{
83 84 85
    if (lxc_driver == NULL)
        goto declineConnection;

D
Daniel Veillard 已提交
86
    /* Verify uri was specified */
87
    if (conn->uri == NULL) {
88 89 90
        if (!lxcProbe())
            goto declineConnection;

91 92
        conn->uri = xmlParseURI("lxc:///");
        if (!conn->uri) {
93
            virReportOOMError(conn);
94 95 96 97
            return VIR_DRV_OPEN_ERROR;
        }
    } else if (conn->uri->scheme == NULL ||
               STRNEQ(conn->uri->scheme, "lxc")) {
D
Daniel Veillard 已提交
98
        goto declineConnection;
99 100
    } else if (!lxcProbe()) {
        goto declineConnection;
D
Daniel Veillard 已提交
101 102
    }

103

104
    conn->privateData = lxc_driver;
D
Daniel Veillard 已提交
105 106 107 108 109 110 111 112 113

    return VIR_DRV_OPEN_SUCCESS;

declineConnection:
    return VIR_DRV_OPEN_DECLINED;
}

static int lxcClose(virConnectPtr conn)
{
114 115
    conn->privateData = NULL;
    return 0;
D
Daniel Veillard 已提交
116 117 118 119 120
}

static virDomainPtr lxcDomainLookupByID(virConnectPtr conn,
                                        int id)
{
121 122 123
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
124

125
    lxcDriverLock(driver);
126
    vm = virDomainFindByID(&driver->domains, id);
127 128
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
129 130
    if (!vm) {
        lxcError(conn, NULL, VIR_ERR_NO_DOMAIN, NULL);
131
        goto cleanup;
D
Daniel Veillard 已提交
132 133 134
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
135
    if (dom)
D
Daniel Veillard 已提交
136 137
        dom->id = vm->def->id;

138
cleanup:
139 140
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
141 142 143 144 145 146
    return dom;
}

static virDomainPtr lxcDomainLookupByUUID(virConnectPtr conn,
                                          const unsigned char *uuid)
{
147 148 149
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
150

151
    lxcDriverLock(driver);
152
    vm = virDomainFindByUUID(&driver->domains, uuid);
153 154
    lxcDriverUnlock(driver);

D
Daniel Veillard 已提交
155 156
    if (!vm) {
        lxcError(conn, NULL, VIR_ERR_NO_DOMAIN, NULL);
157
        goto cleanup;
D
Daniel Veillard 已提交
158 159 160
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
161
    if (dom)
D
Daniel Veillard 已提交
162 163
        dom->id = vm->def->id;

164
cleanup:
165 166
    if (vm)
        virDomainObjUnlock(vm);
D
Daniel Veillard 已提交
167 168 169 170 171 172
    return dom;
}

static virDomainPtr lxcDomainLookupByName(virConnectPtr conn,
                                          const char *name)
{
173 174 175
    lxc_driver_t *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
176

177
    lxcDriverLock(driver);
178
    vm = virDomainFindByName(&driver->domains, name);
179
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
180 181
    if (!vm) {
        lxcError(conn, NULL, VIR_ERR_NO_DOMAIN, NULL);
182
        goto cleanup;
D
Daniel Veillard 已提交
183 184 185
    }

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

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

195
static int lxcListDomains(virConnectPtr conn, int *ids, int nids) {
196
    lxc_driver_t *driver = conn->privateData;
197 198
    int got = 0, i;

199 200 201
    lxcDriverLock(driver);
    for (i = 0 ; i < driver->domains.count && got < nids ; i++) {
        virDomainObjLock(driver->domains.objs[i]);
202 203
        if (virDomainIsActive(driver->domains.objs[i]))
            ids[got++] = driver->domains.objs[i]->def->id;
204 205 206
        virDomainObjUnlock(driver->domains.objs[i]);
    }
    lxcDriverUnlock(driver);
207

208
    return got;
D
Daniel Veillard 已提交
209
}
210

211
static int lxcNumDomains(virConnectPtr conn) {
212
    lxc_driver_t *driver = conn->privateData;
213 214
    int n = 0, i;

215 216 217
    lxcDriverLock(driver);
    for (i = 0 ; i < driver->domains.count ; i++) {
        virDomainObjLock(driver->domains.objs[i]);
218
        if (virDomainIsActive(driver->domains.objs[i]))
219
            n++;
220 221 222
        virDomainObjUnlock(driver->domains.objs[i]);
    }
    lxcDriverUnlock(driver);
223

224
    return n;
D
Daniel Veillard 已提交
225 226 227
}

static int lxcListDefinedDomains(virConnectPtr conn,
228
                                 char **const names, int nnames) {
229
    lxc_driver_t *driver = conn->privateData;
230
    int got = 0, i;
231

232
    lxcDriverLock(driver);
233
    for (i = 0 ; i < driver->domains.count && got < nnames ; i++) {
234
        virDomainObjLock(driver->domains.objs[i]);
235 236
        if (!virDomainIsActive(driver->domains.objs[i])) {
            if (!(names[got++] = strdup(driver->domains.objs[i]->def->name))) {
237
                virReportOOMError(conn);
238
                virDomainObjUnlock(driver->domains.objs[i]);
D
Daniel Veillard 已提交
239 240 241
                goto cleanup;
            }
        }
242
        virDomainObjUnlock(driver->domains.objs[i]);
D
Daniel Veillard 已提交
243
    }
244
    lxcDriverUnlock(driver);
245

246
    return got;
D
Daniel Veillard 已提交
247 248

 cleanup:
249
    for (i = 0 ; i < got ; i++)
250
        VIR_FREE(names[i]);
251
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
252 253 254 255
    return -1;
}


256
static int lxcNumDefinedDomains(virConnectPtr conn) {
257
    lxc_driver_t *driver = conn->privateData;
258 259
    int n = 0, i;

260 261 262
    lxcDriverLock(driver);
    for (i = 0 ; i < driver->domains.count ; i++) {
        virDomainObjLock(driver->domains.objs[i]);
263
        if (!virDomainIsActive(driver->domains.objs[i]))
264
            n++;
265 266 267
        virDomainObjUnlock(driver->domains.objs[i]);
    }
    lxcDriverUnlock(driver);
268

269
    return n;
D
Daniel Veillard 已提交
270 271
}

272 273


D
Daniel Veillard 已提交
274 275
static virDomainPtr lxcDomainDefine(virConnectPtr conn, const char *xml)
{
276 277
    lxc_driver_t *driver = conn->privateData;
    virDomainDefPtr def = NULL;
278
    virDomainObjPtr vm = NULL;
279
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
280

281
    lxcDriverLock(driver);
282 283
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE)))
284
        goto cleanup;
D
Daniel Veillard 已提交
285

286 287
    if ((def->nets != NULL) && !(driver->have_netns)) {
        lxcError(conn, NULL, VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
288
                 "%s", _("System lacks NETNS support"));
289
        goto cleanup;
290 291
    }

292 293 294
    if (!(vm = virDomainAssignDef(conn, &driver->domains, def)))
        goto cleanup;
    def = NULL;
295
    vm->persistent = 1;
D
Daniel Veillard 已提交
296

297 298
    if (virDomainSaveConfig(conn,
                            driver->configDir,
299
                            vm->newDef ? vm->newDef : vm->def) < 0) {
300
        virDomainRemoveInactive(&driver->domains, vm);
301
        vm = NULL;
302
        goto cleanup;
D
Daniel Veillard 已提交
303 304 305
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
306
    if (dom)
D
Daniel Veillard 已提交
307 308
        dom->id = vm->def->id;

309 310
cleanup:
    virDomainDefFree(def);
311 312 313
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
D
Daniel Veillard 已提交
314 315 316 317 318
    return dom;
}

static int lxcDomainUndefine(virDomainPtr dom)
{
319 320 321
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
D
Daniel Veillard 已提交
322

323
    lxcDriverLock(driver);
324
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
325 326
    if (!vm) {
        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
327
                 "%s", _("no domain with matching uuid"));
328
        goto cleanup;
D
Daniel Veillard 已提交
329 330
    }

331
    if (virDomainIsActive(vm)) {
D
Daniel Veillard 已提交
332
        lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
333
                 "%s", _("cannot delete active domain"));
334
        goto cleanup;
D
Daniel Veillard 已提交
335 336
    }

337 338 339
    if (!vm->persistent) {
        lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
                 "%s", _("cannot undefine transient domain"));
340
        goto cleanup;
341
    }
D
Daniel Veillard 已提交
342

343 344 345
    if (virDomainDeleteConfig(dom->conn,
                              driver->configDir,
                              driver->autostartDir,
346 347
                              vm) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
348

349
    virDomainRemoveInactive(&driver->domains, vm);
350
    vm = NULL;
351
    ret = 0;
D
Daniel Veillard 已提交
352

353
cleanup:
354 355 356
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
357
    return ret;
D
Daniel Veillard 已提交
358 359 360 361 362
}

static int lxcDomainGetInfo(virDomainPtr dom,
                            virDomainInfoPtr info)
{
363 364 365
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
D
Daniel Veillard 已提交
366

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

D
Daniel Veillard 已提交
371 372
    if (!vm) {
        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
373
                 "%s", _("no domain with matching uuid"));
374
        goto cleanup;
D
Daniel Veillard 已提交
375 376 377 378
    }

    info->state = vm->state;

379
    if (!virDomainIsActive(vm)) {
D
Daniel Veillard 已提交
380 381 382 383 384
        info->cpuTime = 0;
    } else {
        info->cpuTime = 0;
    }

385 386
    info->maxMem = vm->def->maxmem;
    info->memory = vm->def->memory;
D
Daniel Veillard 已提交
387
    info->nrVirtCpu = 1;
388
    ret = 0;
D
Daniel Veillard 已提交
389

390
cleanup:
391 392
    if (vm)
        virDomainObjUnlock(vm);
393
    return ret;
D
Daniel Veillard 已提交
394 395
}

396
static char *lxcGetOSType(virDomainPtr dom)
D
Daniel Veillard 已提交
397
{
398 399 400
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
401

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

406 407
    if (!vm) {
        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
408
                 "%s", _("no domain with matching uuid"));
409
        goto cleanup;
410 411
    }

412 413 414
    ret = strdup(vm->def->os.type);

cleanup:
415 416
    if (vm)
        virDomainObjUnlock(vm);
417
    return ret;
D
Daniel Veillard 已提交
418 419 420
}

static char *lxcDomainDumpXML(virDomainPtr dom,
421
                              int flags)
D
Daniel Veillard 已提交
422
{
423 424 425
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
D
Daniel Veillard 已提交
426

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

D
Daniel Veillard 已提交
431 432
    if (!vm) {
        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
J
Jim Meyering 已提交
433
                 "%s", _("no domain with matching uuid"));
434
        goto cleanup;
D
Daniel Veillard 已提交
435 436
    }

437 438 439 440 441 442
    ret = virDomainDefFormat(dom->conn,
                             (flags & VIR_DOMAIN_XML_INACTIVE) &&
                             vm->newDef ? vm->newDef : vm->def,
                             flags);

cleanup:
443 444
    if (vm)
        virDomainObjUnlock(vm);
445
    return ret;
D
Daniel Veillard 已提交
446 447
}

448 449 450 451 452 453 454 455 456 457 458 459 460

/**
 * lxcVmCleanup:
 * @vm: Ptr to VM to clean up
 *
 * waitpid() on the container process.  kill and wait the tty process
 * This is called by both lxcDomainDestroy and lxcSigHandler when a
 * container exits.
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcVMCleanup(virConnectPtr conn,
                        lxc_driver_t *driver,
461
                        virDomainObjPtr  vm)
462 463 464 465
{
    int rc = -1;
    int waitRc;
    int childStatus = -1;
D
Dan Smith 已提交
466
    virCgroupPtr cgroup;
467
    int i;
468 469 470 471 472 473

    while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) &&
           errno == EINTR)
        ; /* empty */

    if ((waitRc != vm->pid) && (errno != ECHILD)) {
474 475 476
        virReportSystemError(conn, errno,
                             _("waitpid failed to wait for container %d: %d"),
                             vm->pid, waitRc);
477 478 479 480 481 482 483 484 485
    }

    rc = 0;

    if (WIFEXITED(childStatus)) {
        rc = WEXITSTATUS(childStatus);
        DEBUG("container exited with rc: %d", rc);
    }

486
    virEventRemoveHandle(vm->monitorWatch);
487 488 489
    close(vm->monitor);

    virFileDeletePid(driver->stateDir, vm->def->name);
490
    virDomainDeleteConfig(conn, driver->stateDir, NULL, vm);
491 492 493 494 495 496

    vm->state = VIR_DOMAIN_SHUTOFF;
    vm->pid = -1;
    vm->def->id = -1;
    vm->monitor = -1;

497 498 499
    for (i = 0 ; i < vm->def->nnets ; i++) {
        vethInterfaceUpOrDown(vm->def->nets[i]->ifname, 0);
        vethDelete(vm->def->nets[i]->ifname);
500 501
    }

D
Dan Smith 已提交
502 503 504 505 506
    if (virCgroupForDomain(vm->def, "lxc", &cgroup) == 0) {
        virCgroupRemove(cgroup);
        virCgroupFree(&cgroup);
    }

507 508 509
    return rc;
}

510 511
/**
 * lxcSetupInterfaces:
512
 * @def: pointer to virtual machine structure
513 514 515 516 517 518 519 520
 *
 * Sets up the container interfaces by creating the veth device pairs and
 * attaching the parent end to the appropriate bridge.  The container end
 * will moved into the container namespace later after clone has been called.
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcSetupInterfaces(virConnectPtr conn,
521
                              virDomainDefPtr def,
522 523
                              unsigned int *nveths,
                              char ***veths)
524
{
525
    int rc = -1, i;
526
    char *bridge = NULL;
527 528
    char parentVeth[PATH_MAX] = "";
    char containerVeth[PATH_MAX] = "";
529
    brControl *brctl = NULL;
530

531
    if (brInit(&brctl) != 0)
532 533
        return -1;

534 535
    for (i = 0 ; i < def->nnets ; i++) {
        switch (def->nets[i]->type) {
536 537 538
        case VIR_DOMAIN_NET_TYPE_NETWORK:
        {
            virNetworkPtr network = virNetworkLookupByName(conn,
539
                                                           def->nets[i]->data.network.name);
540 541 542 543 544 545 546
            if (!network) {
                goto error_exit;
            }

            bridge = virNetworkGetBridgeName(network);

            virNetworkFree(network);
547 548 549
            break;
        }
        case VIR_DOMAIN_NET_TYPE_BRIDGE:
550
            bridge = def->nets[i]->data.bridge.brname;
551
            break;
552 553 554 555 556
        }

        DEBUG("bridge: %s", bridge);
        if (NULL == bridge) {
            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
557
                     "%s", _("failed to get bridge for interface"));
558 559 560 561
            goto error_exit;
        }

        DEBUG0("calling vethCreate()");
562 563
        if (NULL != def->nets[i]->ifname) {
            strcpy(parentVeth, def->nets[i]->ifname);
564 565 566 567 568 569 570
        }
        DEBUG("parentVeth: %s, containerVeth: %s", parentVeth, containerVeth);
        if (0 != (rc = vethCreate(parentVeth, PATH_MAX, containerVeth, PATH_MAX))) {
            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
                     _("failed to create veth device pair: %d"), rc);
            goto error_exit;
        }
571 572
        if (NULL == def->nets[i]->ifname) {
            def->nets[i]->ifname = strdup(parentVeth);
573
        }
574 575 576
        if (VIR_REALLOC_N(*veths, (*nveths)+1) < 0)
            goto error_exit;
        if (((*veths)[(*nveths)++] = strdup(containerVeth)) == NULL)
577 578
            goto error_exit;

579
        if (NULL == def->nets[i]->ifname) {
580
            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
581
                     "%s", _("failed to allocate veth names"));
582 583 584
            goto error_exit;
        }

585
        if (0 != (rc = brAddInterface(brctl, bridge, parentVeth))) {
586 587 588
            virReportSystemError(conn, rc,
                                 _("failed to add %s device to %s"),
                                 parentVeth, bridge);
589 590 591 592
            goto error_exit;
        }

        if (0 != (rc = vethInterfaceUpOrDown(parentVeth, 1))) {
593 594
            virReportSystemError(conn, rc, "%s",
                                 _("failed to enable parent ns veth device"));
595 596 597 598 599 600 601 602
            goto error_exit;
        }

    }

    rc = 0;

error_exit:
603
    brShutdown(brctl);
604 605 606
    return rc;
}

607

608 609
static int lxcMonitorClient(virConnectPtr conn,
                            lxc_driver_t * driver,
610
                            virDomainObjPtr vm)
611
{
612 613 614
    char *sockpath = NULL;
    int fd;
    struct sockaddr_un addr;
615

616 617
    if (virAsprintf(&sockpath, "%s/%s.sock",
                    driver->stateDir, vm->def->name) < 0) {
618
        virReportOOMError(conn);
619 620 621 622
        return -1;
    }

    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
623 624
        virReportSystemError(conn, errno, "%s",
                             _("failed to create client socket"));
625
        goto error;
626 627
    }

628 629 630 631 632
    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));

    if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
633 634
        virReportSystemError(conn, errno, "%s",
                             _("failed to connect to client socket"));
635
        goto error;
636 637
    }

638 639
    VIR_FREE(sockpath);
    return fd;
640

641 642 643 644 645 646 647 648 649 650
error:
    VIR_FREE(sockpath);
    if (fd != -1)
        close(fd);
    return -1;
}


static int lxcVmTerminate(virConnectPtr conn,
                          lxc_driver_t *driver,
651
                          virDomainObjPtr vm,
652 653 654 655
                          int signum)
{
    if (signum == 0)
        signum = SIGINT;
656

657 658 659 660 661 662
    if (vm->pid <= 0) {
        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
                 _("invalid PID %d for container"), vm->pid);
        return -1;
    }

663 664
    if (kill(vm->pid, signum) < 0) {
        if (errno != ESRCH) {
665 666 667
            virReportSystemError(conn, errno,
                                 _("failed to kill pid %d"),
                                 vm->pid);
668
            return -1;
669
        }
670 671
    }

672
    vm->state = VIR_DOMAIN_SHUTDOWN;
673

674 675
    return lxcVMCleanup(conn, driver, vm);
}
676

677 678
static void lxcMonitorEvent(int watch,
                            int fd,
679 680 681 682
                            int events ATTRIBUTE_UNUSED,
                            void *data)
{
    lxc_driver_t *driver = data;
683 684
    virDomainObjPtr vm = NULL;
    unsigned int i;
685

686
    lxcDriverLock(driver);
687
    for (i = 0 ; i < driver->domains.count ; i++) {
688 689 690 691
        virDomainObjPtr tmpvm = driver->domains.objs[i];
        virDomainObjLock(tmpvm);
        if (tmpvm->monitorWatch == watch) {
            vm = tmpvm;
692
            break;
693
        }
694
        virDomainObjUnlock(tmpvm);
695 696
    }
    if (!vm) {
697
        virEventRemoveHandle(watch);
698
        goto cleanup;
699 700 701 702
    }

    if (vm->monitor != fd) {
        virEventRemoveHandle(watch);
703
        goto cleanup;
704 705
    }

706
    if (lxcVmTerminate(NULL, driver, vm, SIGINT) < 0)
707
        virEventRemoveHandle(watch);
708 709 710 711 712

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
713 714 715
}


716 717 718 719 720 721 722 723 724 725 726 727 728 729
static int lxcControllerStart(virConnectPtr conn,
                              virDomainObjPtr vm,
                              int nveths,
                              char **veths,
                              int appPty,
                              int logfd)
{
    int i;
    int rc;
    int ret = -1;
    int largc = 0, larga = 0;
    const char **largv = NULL;
    pid_t child;
    int status;
730 731
    fd_set keepfd;
    char appPtyStr[30];
732 733
    const char *emulator;
    lxc_driver_t *driver = conn->privateData;
734 735

    FD_ZERO(&keepfd);
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758

#define ADD_ARG_SPACE                                                   \
    do { \
        if (largc == larga) {                                           \
            larga += 10;                                                \
            if (VIR_REALLOC_N(largv, larga) < 0)                        \
                goto no_memory;                                         \
        }                                                               \
    } while (0)

#define ADD_ARG(thisarg)                                                \
    do {                                                                \
        ADD_ARG_SPACE;                                                  \
        largv[largc++] = thisarg;                                       \
    } while (0)

#define ADD_ARG_LIT(thisarg)                                            \
    do {                                                                \
        ADD_ARG_SPACE;                                                  \
        if ((largv[largc++] = strdup(thisarg)) == NULL)                 \
            goto no_memory;                                             \
    } while (0)

759 760
    snprintf(appPtyStr, sizeof(appPtyStr), "%d", appPty);

761 762 763 764 765 766 767
    emulator = vm->def->emulator;
    if (!emulator)
        emulator = virDomainDefDefaultEmulator(conn, vm->def, driver->caps);
    if (!emulator)
        return -1;

    ADD_ARG_LIT(emulator);
768 769 770
    ADD_ARG_LIT("--name");
    ADD_ARG_LIT(vm->def->name);
    ADD_ARG_LIT("--console");
771
    ADD_ARG_LIT(appPtyStr);
772 773 774 775 776 777 778 779 780
    ADD_ARG_LIT("--background");

    for (i = 0 ; i < nveths ; i++) {
        ADD_ARG_LIT("--veth");
        ADD_ARG_LIT(veths[i]);
    }

    ADD_ARG(NULL);

781 782 783
    FD_SET(appPty, &keepfd);

    if (virExec(conn, largv, NULL, &keepfd, &child,
784
                -1, &logfd, &logfd,
785 786 787 788 789 790 791 792 793
                VIR_EXEC_NONE) < 0)
        goto cleanup;

    /* We now wait for the process to exit - the controller
     * will fork() itself into the background - waiting for
     * it to exit thus guarentees it has written its pidfile
     */
    while ((rc = waitpid(child, &status, 0) == -1) && errno == EINTR);
    if (rc == -1) {
794 795 796
        virReportSystemError(conn, errno,
                             _("cannot wait for '%s'"),
                             largv[0]);
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
        goto cleanup;
    }

    if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
                 _("container '%s' unexpectedly shutdown during startup"),
                 largv[0]);
        goto cleanup;
    }

#undef ADD_ARG
#undef ADD_ARG_LIT
#undef ADD_ARG_SPACE

    ret = 0;

cleanup:
    for (i = 0 ; i < largc ; i++)
        VIR_FREE(largv[i]);

    return ret;

no_memory:
820
    virReportOOMError(conn);
821 822 823 824
    goto cleanup;
}


825 826 827 828 829 830 831 832 833 834 835 836
/**
 * lxcVmStart:
 * @conn: pointer to connection
 * @driver: pointer to driver structure
 * @vm: pointer to virtual machine structure
 *
 * Starts a vm
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcVmStart(virConnectPtr conn,
                      lxc_driver_t * driver,
837
                      virDomainObjPtr  vm)
838 839
{
    int rc = -1;
840 841
    unsigned int i;
    int parentTty;
842
    char *parentTtyPath = NULL;
843 844 845 846 847
    char *logfile = NULL;
    int logfd = -1;
    unsigned int nveths = 0;
    char **veths = NULL;

848 849 850 851
    if ((rc = virFileMakePath(driver->logDir)) < 0) {
        virReportSystemError(conn, rc,
                             _("cannot create log directory '%s'"),
                             driver->logDir);
852 853
        return -1;
    }
854

855 856
    if (virAsprintf(&logfile, "%s/%s.log",
                    driver->logDir, vm->def->name) < 0) {
857
        virReportOOMError(conn);
858
        return -1;
859 860
    }

861
    /* open parent tty */
862
    if (virFileOpenTty(&parentTty, &parentTtyPath, 1) < 0) {
863 864
        virReportSystemError(conn, errno, "%s",
                             _("failed to allocate tty"));
865 866
        goto cleanup;
    }
867 868 869 870 871 872 873
    if (vm->def->console &&
        vm->def->console->type == VIR_DOMAIN_CHR_TYPE_PTY) {
        VIR_FREE(vm->def->console->data.file.path);
        vm->def->console->data.file.path = parentTtyPath;
    } else {
        VIR_FREE(parentTtyPath);
    }
874

875
    if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0)
876
        goto cleanup;
877

878 879 880 881 882 883
    /* Persist the live configuration now we have veth & tty info */
    if (virDomainSaveConfig(conn, driver->stateDir, vm->def) < 0) {
        rc = -1;
        goto cleanup;
    }

884 885
    if ((logfd = open(logfile, O_WRONLY | O_TRUNC | O_CREAT,
             S_IRUSR|S_IWUSR)) < 0) {
886 887 888
        virReportSystemError(conn, errno,
                             _("failed to open '%s'"),
                             logfile);
889
        goto cleanup;
890 891
    }

892 893 894 895
    if (lxcControllerStart(conn,
                           vm,
                           nveths, veths,
                           parentTty, logfd) < 0)
896
        goto cleanup;
897 898 899 900 901

    /* Connect to the controller as a client *first* because
     * this will block until the child has written their
     * pid file out to disk */
    if ((vm->monitor = lxcMonitorClient(conn, driver, vm)) < 0)
902 903
        goto cleanup;

904 905
    /* And get its pid */
    if ((rc = virFileReadPid(driver->stateDir, vm->def->name, &vm->pid)) != 0) {
906 907 908
        virReportSystemError(conn, rc,
                             _("Failed to read pid file %s/%s.pid"),
                             driver->stateDir, vm->def->name);
909
        rc = -1;
910
        goto cleanup;
911
    }
912

913
    vm->def->id = vm->pid;
914 915
    vm->state = VIR_DOMAIN_RUNNING;

916 917 918 919
    if ((vm->monitorWatch = virEventAddHandle(
             vm->monitor,
             VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP,
             lxcMonitorEvent,
920
             driver, NULL)) < 0) {
921 922 923
        lxcVmTerminate(conn, driver, vm, 0);
        goto cleanup;
    }
924

925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
    rc = 0;

cleanup:
    for (i = 0 ; i < nveths ; i++) {
        if (rc != 0)
            vethDelete(veths[i]);
        VIR_FREE(veths[i]);
    }
    if (rc != 0 && vm->monitor != -1) {
        close(vm->monitor);
        vm->monitor = -1;
    }
    if (parentTty != -1)
        close(parentTty);
    if (logfd != -1)
        close(logfd);
    VIR_FREE(logfile);
942 943 944 945 946 947 948 949 950 951 952 953 954
    return rc;
}

/**
 * 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)
{
955 956 957
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
958

959
    lxcDriverLock(driver);
960
    vm = virDomainFindByName(&driver->domains, dom->name);
961
    if (!vm) {
962
        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
963
                 _("no domain named %s"), dom->name);
964 965 966
        goto cleanup;
    }

967
    if ((vm->def->nets != NULL) && !(driver->have_netns)) {
968
        lxcError(dom->conn, NULL, VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
969
                 "%s", _("System lacks NETNS support"));
970 971 972
        goto cleanup;
    }

973
    ret = lxcVmStart(dom->conn, driver, vm);
974 975

cleanup:
976 977 978
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
979
    return ret;
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
}

/**
 * lxcDomainCreateAndStart:
 * @conn: pointer to connection
 * @xml: XML definition of domain
 * @flags: Unused
 *
 * 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,
                        unsigned int flags ATTRIBUTE_UNUSED) {
996
    lxc_driver_t *driver = conn->privateData;
997
    virDomainObjPtr vm = NULL;
998
    virDomainDefPtr def;
999 1000
    virDomainPtr dom = NULL;

1001
    lxcDriverLock(driver);
1002 1003
    if (!(def = virDomainDefParseString(conn, driver->caps, xml,
                                        VIR_DOMAIN_XML_INACTIVE)))
1004
        goto cleanup;
1005

1006 1007
    if ((def->nets != NULL) && !(driver->have_netns)) {
        lxcError(conn, NULL, VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
1008
                 "%s", _("System lacks NETNS support"));
1009
        goto cleanup;
1010 1011
    }

1012

1013 1014 1015
    if (!(vm = virDomainAssignDef(conn, &driver->domains, def)))
        goto cleanup;
    def = NULL;
1016 1017

    if (lxcVmStart(conn, driver, vm) < 0) {
1018
        virDomainRemoveInactive(&driver->domains, vm);
1019
        vm = NULL;
1020
        goto cleanup;
1021 1022 1023
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
1024
    if (dom)
1025 1026
        dom->id = vm->def->id;

1027 1028
cleanup:
    virDomainDefFree(def);
1029 1030 1031
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
    return dom;
}

/**
 * lxcDomainShutdown:
 * @dom: Ptr to domain to shutdown
 *
 * Sends SIGINT to container root process to request it to shutdown
 *
 * Returns 0 on success or -1 in case of error
 */
static int lxcDomainShutdown(virDomainPtr dom)
{
1045 1046 1047
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1048

1049
    lxcDriverLock(driver);
1050
    vm = virDomainFindByID(&driver->domains, dom->id);
1051 1052 1053
    if (!vm) {
        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
                 _("no domain with id %d"), dom->id);
1054
        goto cleanup;
1055 1056
    }

1057
    ret = lxcVmTerminate(dom->conn, driver, vm, 0);
1058 1059 1060 1061
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1062 1063

cleanup:
1064 1065 1066
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
1067
    return ret;
1068 1069
}

1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080

/**
 * lxcDomainDestroy:
 * @dom: Ptr 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)
{
1081 1082 1083
    lxc_driver_t *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1084

1085
    lxcDriverLock(driver);
1086
    vm = virDomainFindByID(&driver->domains, dom->id);
1087 1088 1089
    if (!vm) {
        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
                 _("no domain with id %d"), dom->id);
1090
        goto cleanup;
1091 1092
    }

1093
    ret = lxcVmTerminate(dom->conn, driver, vm, SIGKILL);
1094 1095 1096 1097
    if (!vm->persistent) {
        virDomainRemoveInactive(&driver->domains, vm);
        vm = NULL;
    }
1098 1099

cleanup:
1100 1101 1102
    if (vm)
        virDomainObjUnlock(vm);
    lxcDriverUnlock(driver);
1103
    return ret;
1104
}
1105

1106 1107 1108 1109 1110
static int lxcCheckNetNsSupport(void)
{
    const char *argv[] = {"ip", "link", "set", "lo", "netns", "-1", NULL};
    int ip_rc;

1111 1112 1113
    if (virRun(NULL, argv, &ip_rc) < 0 ||
        !(WIFEXITED(ip_rc) && (WEXITSTATUS(ip_rc) != 255)))
        return 0;
1114

1115 1116
    if (lxcContainerAvailable(LXC_CONTAINER_FEATURE_NET) < 0)
        return 0;
1117

1118
    return 1;
1119 1120
}

1121
static int lxcStartup(void)
D
Daniel Veillard 已提交
1122
{
1123
    uid_t uid = getuid();
1124
    unsigned int i;
1125 1126 1127 1128 1129 1130 1131 1132 1133
    char *ld;

    /* 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");
    if (ld && strstr(ld, "vgpreload"))
        return -1;
1134 1135 1136 1137 1138 1139

    /* Check that the user is root */
    if (0 != uid) {
        return -1;
    }

1140
    if (VIR_ALLOC(lxc_driver) < 0) {
1141 1142
        return -1;
    }
1143 1144 1145 1146
    if (virMutexInit(&lxc_driver->lock) < 0) {
        VIR_FREE(lxc_driver);
        return -1;
    }
1147
    lxcDriverLock(lxc_driver);
D
Daniel Veillard 已提交
1148

1149
    /* Check that this is a container enabled kernel */
1150
    if(lxcContainerAvailable(0) < 0)
1151
        goto cleanup;
D
Daniel Veillard 已提交
1152

1153
    lxc_driver->have_netns = lxcCheckNetNsSupport();
D
Daniel Veillard 已提交
1154 1155

    /* Call function to load lxc driver configuration information */
1156 1157
    if (lxcLoadDriverConfig(lxc_driver) < 0)
        goto cleanup;
D
Daniel Veillard 已提交
1158

1159 1160
    if ((lxc_driver->caps = lxcCapsInit()) == NULL)
        goto cleanup;
D
Daniel Veillard 已提交
1161

1162 1163 1164 1165
    if (virDomainLoadAllConfigs(NULL,
                                lxc_driver->caps,
                                &lxc_driver->domains,
                                lxc_driver->configDir,
1166
                                lxc_driver->autostartDir,
1167 1168
                                NULL, NULL) < 0)
        goto cleanup;
1169

1170 1171
    for (i = 0 ; i < lxc_driver->domains.count ; i++) {
        virDomainObjPtr vm = lxc_driver->domains.objs[i];
1172 1173
        char *config = NULL;
        virDomainDefPtr tmp;
1174
        int rc;
1175 1176 1177 1178

        virDomainObjLock(vm);
        if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) {
            virDomainObjUnlock(vm);
1179
            continue;
1180
        }
1181 1182 1183 1184 1185

        /* Read pid from controller */
        if ((rc = virFileReadPid(lxc_driver->stateDir, vm->def->name, &vm->pid)) != 0) {
            close(vm->monitor);
            vm->monitor = -1;
1186
            virDomainObjUnlock(vm);
1187 1188 1189
            continue;
        }

1190 1191
        if ((config = virDomainConfigFile(NULL,
                                          lxc_driver->stateDir,
1192 1193
                                          vm->def->name)) == NULL) {
            virDomainObjUnlock(vm);
1194
            continue;
1195
        }
1196 1197

        /* Try and load the live config */
1198
        tmp = virDomainDefParseFile(NULL, lxc_driver->caps, config, 0);
1199 1200 1201 1202 1203 1204
        VIR_FREE(config);
        if (tmp) {
            vm->newDef = vm->def;
            vm->def = tmp;
        }

1205 1206 1207 1208 1209 1210 1211 1212
        if (vm->pid != 0) {
            vm->def->id = vm->pid;
            vm->state = VIR_DOMAIN_RUNNING;
        } else {
            vm->def->id = -1;
            close(vm->monitor);
            vm->monitor = -1;
        }
1213
        virDomainObjUnlock(vm);
1214 1215
    }

1216
    lxcDriverUnlock(lxc_driver);
D
Daniel Veillard 已提交
1217 1218
    return 0;

1219 1220 1221 1222
cleanup:
    lxcDriverUnlock(lxc_driver);
    lxcShutdown();
    return -1;
D
Daniel Veillard 已提交
1223 1224
}

1225
static int lxcShutdown(void)
D
Daniel Veillard 已提交
1226
{
1227
    if (lxc_driver == NULL)
1228
        return(-1);
1229

1230
    lxcDriverLock(lxc_driver);
1231
    virDomainObjListFree(&lxc_driver->domains);
1232 1233 1234 1235 1236 1237 1238

    virCapabilitiesFree(lxc_driver->caps);
    VIR_FREE(lxc_driver->configDir);
    VIR_FREE(lxc_driver->autostartDir);
    VIR_FREE(lxc_driver->stateDir);
    VIR_FREE(lxc_driver->logDir);
    lxcDriverUnlock(lxc_driver);
1239
    virMutexDestroy(&lxc_driver->lock);
1240
    VIR_FREE(lxc_driver);
1241
    lxc_driver = NULL;
1242 1243 1244

    return 0;
}
D
Daniel Veillard 已提交
1245

1246 1247 1248 1249 1250 1251 1252 1253 1254
/**
 * lxcActive:
 *
 * Checks if the LXC daemon is active, i.e. has an active domain
 *
 * Returns 1 if active, 0 otherwise
 */
static int
lxcActive(void) {
1255
    unsigned int i;
1256
    int active = 0;
1257

1258 1259
    if (lxc_driver == NULL)
        return(0);
1260

1261 1262 1263
    lxcDriverLock(lxc_driver);
    for (i = 0 ; i < lxc_driver->domains.count ; i++) {
        virDomainObjLock(lxc_driver->domains.objs[i]);
1264
        if (virDomainIsActive(lxc_driver->domains.objs[i]))
1265 1266 1267 1268
            active = 1;
        virDomainObjUnlock(lxc_driver->domains.objs[i]);
    }
    lxcDriverUnlock(lxc_driver);
1269

1270
    return active;
D
Daniel Veillard 已提交
1271 1272
}

D
Dan Smith 已提交
1273 1274 1275 1276 1277 1278 1279
static int lxcVersion(virConnectPtr conn, unsigned long *version)
{
    struct utsname ver;
    int maj;
    int min;
    int rev;

1280
    uname(&ver);
D
Dan Smith 已提交
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291

    if (sscanf(ver.release, "%i.%i.%i", &maj, &min, &rev) != 3) {
        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
                 _("Unknown release: %s"), ver.release);
        return -1;
    }

    *version = (maj * 1000 * 1000) + (min * 1000) + rev;

    return 0;
}
1292

1293 1294
static char *lxcGetSchedulerType(virDomainPtr domain ATTRIBUTE_UNUSED,
                                 int *nparams)
1295 1296 1297 1298 1299 1300 1301
{
    if (nparams)
        *nparams = 1;

    return strdup("posix");
}

1302
static int lxcSetSchedulerParameters(virDomainPtr domain,
1303 1304 1305
                                     virSchedParameterPtr params,
                                     int nparams)
{
1306
    lxc_driver_t *driver = domain->conn->privateData;
1307
    int i;
1308 1309 1310
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
1311 1312

    if (virCgroupHaveSupport() != 0)
1313 1314 1315 1316 1317
        return -1;

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

1319 1320 1321 1322
    if (vm == NULL) {
        lxcError(NULL, domain, VIR_ERR_INTERNAL_ERROR,
                 _("No such domain %s"), domain->uuid);
        goto cleanup;
1323 1324
    }

1325 1326
    if (virCgroupForDomain(vm->def, "lxc", &group) != 0)
        goto cleanup;
1327 1328 1329 1330 1331

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

        if (STREQ(param->field, "cpu_shares")) {
1332 1333
            if (virCgroupSetCpuShares(group, params[i].value.ui) != 0)
                goto cleanup;
1334
        } else {
1335
            lxcError(NULL, domain, VIR_ERR_INVALID_ARG,
1336
                     _("Invalid parameter `%s'"), param->field);
1337
            goto cleanup;
1338 1339
        }
    }
1340
    ret = 0;
1341

1342
cleanup:
1343
    virCgroupFree(&group);
1344 1345
    if (vm)
        virDomainObjUnlock(vm);
1346
    return ret;
1347 1348
}

1349
static int lxcGetSchedulerParameters(virDomainPtr domain,
1350 1351 1352
                                     virSchedParameterPtr params,
                                     int *nparams)
{
1353
    lxc_driver_t *driver = domain->conn->privateData;
1354 1355
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
1356
    unsigned long val;
1357
    int ret = -1;
1358 1359

    if (virCgroupHaveSupport() != 0)
1360
        return -1;
1361 1362

    if ((*nparams) != 1) {
1363
        lxcError(NULL, domain, VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
1364
                 "%s", _("Invalid parameter count"));
1365
        return -1;
1366 1367
    }

1368 1369 1370 1371
    lxcDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    lxcDriverUnlock(driver);

1372 1373 1374 1375
    if (vm == NULL) {
        lxcError(NULL, domain, VIR_ERR_INTERNAL_ERROR,
                 _("No such domain %s"), domain->uuid);
        goto cleanup;
1376 1377
    }

1378 1379
    if (virCgroupForDomain(vm->def, "lxc", &group) != 0)
        goto cleanup;
1380

1381 1382
    if (virCgroupGetCpuShares(group, &val) != 0)
        goto cleanup;
1383
    params[0].value.ul = val;
1384 1385 1386
    strncpy(params[0].field, "cpu_shares", sizeof(params[0].field));
    params[0].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;

1387
    ret = 0;
1388

1389 1390
cleanup:
    virCgroupFree(&group);
1391 1392
    if (vm)
        virDomainObjUnlock(vm);
1393
    return ret;
1394 1395
}

D
Daniel Veillard 已提交
1396 1397 1398 1399 1400 1401 1402 1403
/* Function Tables */
static virDriver lxcDriver = {
    VIR_DRV_LXC, /* the number virDrvNo */
    "LXC", /* the name of the driver */
    lxcOpen, /* open */
    lxcClose, /* close */
    NULL, /* supports_feature */
    NULL, /* type */
D
Dan Smith 已提交
1404
    lxcVersion, /* version */
D
Daniel Veillard 已提交
1405 1406 1407 1408 1409 1410 1411
    NULL, /* getHostname */
    NULL, /* getURI */
    NULL, /* getMaxVcpus */
    NULL, /* nodeGetInfo */
    NULL, /* getCapabilities */
    lxcListDomains, /* listDomains */
    lxcNumDomains, /* numOfDomains */
1412
    lxcDomainCreateAndStart, /* domainCreateXML */
D
Daniel Veillard 已提交
1413 1414 1415 1416 1417
    lxcDomainLookupByID, /* domainLookupByID */
    lxcDomainLookupByUUID, /* domainLookupByUUID */
    lxcDomainLookupByName, /* domainLookupByName */
    NULL, /* domainSuspend */
    NULL, /* domainResume */
1418
    lxcDomainShutdown, /* domainShutdown */
D
Daniel Veillard 已提交
1419
    NULL, /* domainReboot */
1420
    lxcDomainDestroy, /* domainDestroy */
D
Daniel Veillard 已提交
1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
    lxcGetOSType, /* domainGetOSType */
    NULL, /* domainGetMaxMemory */
    NULL, /* domainSetMaxMemory */
    NULL, /* domainSetMemory */
    lxcDomainGetInfo, /* domainGetInfo */
    NULL, /* domainSave */
    NULL, /* domainRestore */
    NULL, /* domainCoreDump */
    NULL, /* domainSetVcpus */
    NULL, /* domainPinVcpu */
    NULL, /* domainGetVcpus */
    NULL, /* domainGetMaxVcpus */
    lxcDomainDumpXML, /* domainDumpXML */
    lxcListDefinedDomains, /* listDefinedDomains */
    lxcNumDefinedDomains, /* numOfDefinedDomains */
1436
    lxcDomainStart, /* domainCreate */
D
Daniel Veillard 已提交
1437 1438 1439 1440 1441 1442
    lxcDomainDefine, /* domainDefineXML */
    lxcDomainUndefine, /* domainUndefine */
    NULL, /* domainAttachDevice */
    NULL, /* domainDetachDevice */
    NULL, /* domainGetAutostart */
    NULL, /* domainSetAutostart */
1443 1444 1445
    lxcGetSchedulerType, /* domainGetSchedulerType */
    lxcGetSchedulerParameters, /* domainGetSchedulerParameters */
    lxcSetSchedulerParameters, /* domainSetSchedulerParameters */
D
Daniel Veillard 已提交
1446 1447 1448 1449 1450
    NULL, /* domainMigratePrepare */
    NULL, /* domainMigratePerform */
    NULL, /* domainMigrateFinish */
    NULL, /* domainBlockStats */
    NULL, /* domainInterfaceStats */
D
Daniel P. Berrange 已提交
1451 1452
    NULL, /* domainBlockPeek */
    NULL, /* domainMemoryPeek */
D
Daniel Veillard 已提交
1453 1454
    NULL, /* nodeGetCellsFreeMemory */
    NULL, /* getFreeMemory */
1455 1456
    NULL, /* domainEventRegister */
    NULL, /* domainEventDeregister */
D
Daniel Veillard 已提交
1457 1458
    NULL, /* domainMigratePrepare2 */
    NULL, /* domainMigrateFinish2 */
D
Daniel Veillard 已提交
1459 1460
};

1461
static virStateDriver lxcStateDriver = {
1462 1463 1464
    .initialize = lxcStartup,
    .cleanup = lxcShutdown,
    .active = lxcActive,
1465 1466
};

D
Daniel Veillard 已提交
1467 1468 1469
int lxcRegister(void)
{
    virRegisterDriver(&lxcDriver);
1470
    virRegisterStateDriver(&lxcStateDriver);
D
Daniel Veillard 已提交
1471 1472
    return 0;
}