]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
* src/Makefile.am src/lxc_conf.c src/lxc_conf.h src/lxc_container.c
authorDaniel Veillard <veillard@redhat.com>
Thu, 10 Apr 2008 07:30:52 +0000 (07:30 +0000)
committerDaniel Veillard <veillard@redhat.com>
Thu, 10 Apr 2008 07:30:52 +0000 (07:30 +0000)
  src/lxc_container.h src/lxc_driver.c: Applied second set of
  linux container patches from Dave Leskovec adding start/stop
  of domains
Daniel

ChangeLog
src/Makefile.am
src/lxc_conf.c
src/lxc_conf.h
src/lxc_container.c [new file with mode: 0644]
src/lxc_container.h [new file with mode: 0644]
src/lxc_driver.c

index 2c94b1fed335633690e5089c149a411da712fd5f..67e7f3ea22046b95c40839a0e32de74f4813cbee 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Thu Apr 10 09:28:31 CEST 2008 Daniel Veillard <daniel@veillard.com>
+
+       * src/Makefile.am src/lxc_conf.c src/lxc_conf.h src/lxc_container.c
+         src/lxc_container.h src/lxc_driver.c: Applied second set of
+         linux container patches from Dave Leskovec adding start/stop
+         of domains
+
 Wed Apr  9 16:08:00 BST 2008 Richard W.M. Jones <rjones@redhat.com>
 
        Add virsh.pod to EXTRA_DIST
index 9bcc936c07e0592e4a79937bade671d2e71d1478..35b0cece1bfcd283ed72899fec224beea74fa886 100644 (file)
@@ -61,6 +61,7 @@ CLIENT_SOURCES =                                              \
                openvz_driver.c openvz_driver.h                 \
                lxc_driver.c lxc_driver.h                       \
                lxc_conf.c lxc_conf.h                           \
+               lxc_container.c lxc_container.h                         \
                 nodeinfo.h nodeinfo.c                           \
                storage_conf.h storage_conf.c                   \
                storage_driver.h storage_driver.c               \
index 8c6f5096eebb97d9c0061fb2aad93bb2002082bf..325a1bf090d29b36bc554bd555fc6f21c3354337 100644 (file)
@@ -819,6 +819,7 @@ void lxcFreeVMs(lxc_vm_t *vms)
 void lxcFreeVM(lxc_vm_t *vm)
 {
     lxcFreeVMDef(vm->def);
+    free(vm->containerTty);
     free(vm);
 }
 
index a0f1737b84f6a359b1cb559d43fcec40db86e05d..92dec390bbe4118a708581a70d7888186585ad20 100644 (file)
@@ -72,6 +72,8 @@ struct __lxc_vm {
     char configFileBase[PATH_MAX];
 
     int parentTty;
+    int containerTtyFd;
+    char *containerTty;
 
     lxc_vm_def_t *def;
 
diff --git a/src/lxc_container.c b/src/lxc_container.c
new file mode 100644 (file)
index 0000000..d02c23b
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * lxc_container.c: file description
+ *
+ * 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>
+
+#ifdef WITH_LXC
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <unistd.h>
+
+#include "lxc_container.h"
+#include "lxc_conf.h"
+#include "util.h"
+
+#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
+#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
+
+/**
+ * lxcExecContainerInit:
+ * @vmDef: Ptr to vm definition structure
+ *
+ * Exec the container init string.  The container init will replace then
+ * be running in the current process
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcExecContainerInit(const lxc_vm_def_t *vmDef)
+{
+    int rc = -1;
+    char* execString;
+    size_t execStringLen = strlen(vmDef->init) + 1 + 5;
+
+    if (NULL == (execString = calloc(execStringLen, sizeof(char)))) {
+       lxcError(NULL, NULL, VIR_ERR_NO_MEMORY,
+                 _("failed to calloc memory for init string: %s"),
+                 strerror(errno));
+        goto error_out;
+    }
+
+    strcpy(execString, "exec ");
+    strcat(execString, vmDef->init);
+
+    execl("/bin/sh", "sh", "-c", execString, (char*)NULL);
+    lxcError(NULL, NULL, VIR_ERR_NO_MEMORY,
+             _("execl failed to exec init: %s"), strerror(errno));
+
+error_out:
+    exit(rc);
+}
+
+/**
+ * lxcSetContainerStdio:
+ * @ttyName: Name of tty to set as the container console
+ *
+ * Sets the given tty as the primary conosole for the container as well as
+ * stdout, stdin and stderr.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSetContainerStdio(const char *ttyName)
+{
+    int rc = -1;
+    int ttyfd;
+
+    if (setsid() < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("setsid failed: %s"), strerror(errno));
+        goto error_out;
+    }
+
+    ttyfd = open(ttyName, O_RDWR|O_NOCTTY);
+    if (ttyfd < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("open(%s) failed: %s"), ttyName, strerror(errno));
+        goto error_out;
+    }
+
+    if (ioctl(ttyfd, TIOCSCTTY, NULL) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("ioctl(TIOCSTTY) failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    close(0); close(1); close(2);
+
+    if (dup2(ttyfd, 0) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("dup2(stdin) failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    if (dup2(ttyfd, 1) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("dup2(stdout) failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    if (dup2(ttyfd, 2) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("dup2(stderr) failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    rc = 0;
+
+cleanup:
+    close(ttyfd);
+
+error_out:
+    return rc;
+}
+
+/**
+ * lxcExecWithTty:
+ * @vm: Ptr to vm structure
+ *
+ * Sets container console and stdio and then execs container init
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcExecWithTty(lxc_vm_t *vm)
+{
+    int rc = -1;
+    lxc_vm_def_t *vmDef = vm->def;
+
+    if(lxcSetContainerStdio(vm->containerTty) < 0) {
+        goto exit_with_error;
+    }
+
+    lxcExecContainerInit(vmDef);
+
+exit_with_error:
+    exit(rc);
+}
+
+/**
+ * lxcChild:
+ * @argv: Pointer to container arguments
+ *
+ * This function is run in the process clone()'d in lxcStartContainer.
+ * Perform a number of container setup tasks:
+ *     Setup container file system
+ *     mount container /proca
+ * Then exec's the container init
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+int lxcChild( void *argv )
+{
+    int rc = -1;
+    lxc_vm_t *vm = (lxc_vm_t *)argv;
+    lxc_vm_def_t *vmDef = vm->def;
+    lxc_mount_t *curMount;
+    int i;
+
+    if (NULL == vmDef) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("lxcChild() passed invalid vm definition"));
+        goto cleanup;
+    }
+
+    /* handle the bind mounts first before doing anything else that may */
+    /* then access those mounted dirs */
+    curMount = vmDef->mounts;
+    for (i = 0; curMount; curMount = curMount->next) {
+        rc = mount(curMount->source,
+                   curMount->target,
+                   NULL,
+                   MS_BIND,
+                   NULL);
+        if (0 != rc) {
+            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                     _("failed to mount %s at %s for container: %s"),
+                     curMount->source, curMount->target, strerror(errno));
+            goto cleanup;
+        }
+    }
+
+    /* mount /proc */
+    rc = mount("lxcproc", "/proc", "proc", 0, NULL);
+    if (0 != rc) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("failed to mount /proc for container: %s"),
+                 strerror(errno));
+        goto cleanup;
+    }
+
+    rc = lxcExecWithTty(vm);
+    /* this function will only return if an error occured */
+
+cleanup:
+    return rc;
+}
+
+#endif /* WITH_LXC */
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
+
diff --git a/src/lxc_container.h b/src/lxc_container.h
new file mode 100644 (file)
index 0000000..d8deecf
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright IBM Corp. 2008
+ *
+ * lxc_container.h: header file for fcns run inside container
+ *
+ * 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
+ */
+
+#ifndef LXC_CONTAINER_H
+#define LXC_CONTAINER_H
+
+#ifdef WITH_LXC
+
+/* Function declarations */
+int lxcChild( void *argv );
+
+#endif /* LXC_DRIVER_H */
+
+#endif /* LXC_CONTAINER_H */
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
+
index a4e77859fa23e0c37bf48aed2e230ba420d6961b..db597e1b5ae6d616fa5a43836515c5ec368600cb 100644 (file)
 
 #ifdef WITH_LXC
 
+#include <fcntl.h>
+#include <poll.h>
 #include <sched.h>
 #include <sys/utsname.h>
 #include <string.h>
 #include <sys/types.h>
+#include <termios.h>
 #include <unistd.h>
 #include <wait.h>
 
 #include "lxc_conf.h"
+#include "lxc_container.h"
 #include "lxc_driver.h"
 #include "driver.h"
 #include "internal.h"
+#include "util.h"
 
 /* debug macros */
 #define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
@@ -375,6 +380,544 @@ static char *lxcDomainDumpXML(virDomainPtr dom,
     return lxcGenerateXML(dom->conn, driver, vm, vm->def);
 }
 
+/**
+ * lxcStartContainer:
+ * @conn: pointer to connection
+ * @driver: pointer to driver structure
+ * @vm: pointer to virtual machine structure
+ *
+ * Starts a container process by calling clone() with the namespace flags
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcStartContainer(virConnectPtr conn,
+                             lxc_driver_t* driver,
+                             lxc_vm_t *vm)
+{
+    int rc = -1;
+    int flags;
+    int stacksize = getpagesize() * 4;
+    void *stack, *stacktop;
+
+    /* allocate a stack for the container */
+    stack = malloc(stacksize);
+    if (!stack) {
+        lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
+                 _("unable to allocate container stack"));
+        goto error_exit;
+    }
+    stacktop = (char*)stack + stacksize;
+
+    flags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWUSER|CLONE_NEWIPC|SIGCHLD;
+
+    vm->def->id = clone(lxcChild, stacktop, flags, (void *)vm);
+
+    DEBUG("clone() returned, %d", vm->def->id);
+
+    if (vm->def->id < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("clone() failed, %s"), strerror(errno));
+        goto error_exit;
+    }
+
+    lxcSaveConfig(NULL, driver, vm, vm->def);
+
+    rc = 0;
+
+error_exit:
+    return rc;
+}
+
+/**
+ * lxcPutTtyInRawMode:
+ * @conn: pointer to connection
+ * @ttyDev: file descriptor for tty
+ *
+ * Sets tty attributes via cfmakeraw()
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcPutTtyInRawMode(virConnectPtr conn, int ttyDev)
+{
+    int rc = -1;
+
+    struct termios ttyAttr;
+
+    if (tcgetattr(ttyDev, &ttyAttr) < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 "tcgetattr() failed: %s", strerror(errno));
+        goto cleanup;
+    }
+
+    cfmakeraw(&ttyAttr);
+
+    if (tcsetattr(ttyDev, TCSADRAIN, &ttyAttr) < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 "tcsetattr failed: %s", strerror(errno));
+        goto cleanup;
+    }
+
+    rc = 0;
+
+cleanup:
+    return rc;
+}
+
+/**
+ * lxcSetupTtyTunnel:
+ * @conn: pointer to connection
+ * @vmDef: pointer to virtual machine definition structure
+ * @ttyDev: pointer to int.  On success will be set to fd for master
+ * end of tty
+ *
+ * Opens and configures the parent side tty
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSetupTtyTunnel(virConnectPtr conn,
+                             lxc_vm_def_t *vmDef,
+                             int* ttyDev)
+{
+    int rc = -1;
+    char *ptsStr;
+
+    if (0 < strlen(vmDef->tty)) {
+        *ttyDev = open(vmDef->tty, O_RDWR|O_NOCTTY|O_NONBLOCK);
+        if (*ttyDev < 0) {
+            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                     "open() tty failed: %s", strerror(errno));
+            goto setup_complete;
+        }
+
+        rc = grantpt(*ttyDev);
+        if (rc < 0) {
+            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                     "grantpt() failed: %s", strerror(errno));
+            goto setup_complete;
+        }
+
+        rc = unlockpt(*ttyDev);
+        if (rc < 0) {
+            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                     "unlockpt() failed: %s", strerror(errno));
+            goto setup_complete;
+        }
+
+        /* get the name and print it to stdout */
+        ptsStr = ptsname(*ttyDev);
+        if (ptsStr == NULL) {
+            lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                     "ptsname() failed");
+            goto setup_complete;
+        }
+        /* This value needs to be stored in the container configuration file */
+        if (STRNEQ(ptsStr, vmDef->tty)) {
+            strcpy(vmDef->tty, ptsStr);
+        }
+
+        /* Enter raw mode, so all characters are passed directly to child */
+        if (lxcPutTtyInRawMode(conn, *ttyDev) < 0) {
+            goto setup_complete;
+        }
+
+    } else {
+        *ttyDev = -1;
+    }
+
+    rc = 0;
+
+setup_complete:
+    if((0 != rc) && (*ttyDev > 0)) {
+        close(*ttyDev);
+    }
+
+    return rc;
+}
+
+/**
+ * lxcSetupContainerTty:
+ * @conn: pointer to connection
+ * @ttymaster: pointer to int.  On success, set to fd for master end
+ * @ttyName: On success, will point to string slave end of tty.  Caller
+ * must free when done (such as in lxcFreeVM).
+ *
+ * Opens and configures container tty.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcSetupContainerTty(virConnectPtr conn,
+                                int *ttymaster,
+                                char **ttyName)
+{
+    int rc = -1;
+    char tempTtyName[PATH_MAX];
+
+    *ttymaster = posix_openpt(O_RDWR|O_NOCTTY);
+    if (*ttymaster < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("posix_openpt failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    if (unlockpt(*ttymaster) < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("unlockpt failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    if (0 != ptsname_r(*ttymaster, tempTtyName, sizeof(tempTtyName))) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("ptsname_r failed: %s"), strerror(errno));
+        goto cleanup;
+    }
+
+    *ttyName = malloc(sizeof(char) * (strlen(tempTtyName) + 1));
+    if (NULL == ttyName) {
+        lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
+                 _("unable to allocate container name string"));
+        goto cleanup;
+    }
+
+    strcpy(*ttyName, tempTtyName);
+
+    rc = 0;
+
+cleanup:
+    if (0 != rc) {
+        if (-1 != *ttymaster) {
+            close(*ttymaster);
+        }
+    }
+
+    return rc;
+}
+
+/**
+ * lxcTtyForward:
+ * @fd1: Open fd
+ * @fd1: Open fd
+ *
+ * Forwards traffic between fds.  Data read from fd1 will be written to fd2
+ * Data read from fd2 will be written to fd1.  This process loops forever.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcTtyForward(int fd1, int fd2)
+{
+    int rc = -1;
+    int i;
+    char buf[2];
+    struct pollfd fds[2];
+    int numFds = 0;
+
+    if (0 <= fd1) {
+        fds[numFds].fd = fd1;
+        fds[numFds].events = POLLIN;
+        ++numFds;
+    }
+
+    if (0 <= fd2) {
+        fds[numFds].fd = fd2;
+        fds[numFds].events = POLLIN;
+        ++numFds;
+    }
+
+    if (0 == numFds) {
+        DEBUG0("No fds to monitor, return");
+        goto cleanup;
+    }
+
+    while (1) {
+        if ((rc = poll(fds, numFds, -1)) <= 0) {
+
+            if ((0 == rc) || (errno == EINTR) || (errno == EAGAIN)) {
+                continue;
+            }
+
+            lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                     _("poll returned error: %s"), strerror(errno));
+            goto cleanup;
+        }
+
+        for (i = 0; i < numFds; ++i) {
+            if (!fds[i].revents) {
+                continue;
+            }
+
+            if (fds[i].revents & POLLIN) {
+                if (1 != (saferead(fds[i].fd, buf, 1))) {
+                    lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("read of fd %d failed: %s"), i,
+                             strerror(errno));
+                    goto cleanup;
+                }
+
+                if (1 < numFds) {
+                    if (1 != (safewrite(fds[i ^ 1].fd, buf, 1))) {
+                        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                                 _("write to fd %d failed: %s"), i,
+                                 strerror(errno));
+                        goto cleanup;
+                    }
+
+                }
+
+            }
+
+        }
+
+    }
+
+    rc = 0;
+
+cleanup:
+    return rc;
+}
+
+/**
+ * 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,
+                      lxc_vm_t * vm)
+{
+    int rc = -1;
+    lxc_vm_def_t *vmDef = vm->def;
+
+    /* open parent tty */
+    if (lxcSetupTtyTunnel(conn, vmDef, &vm->parentTty) < 0) {
+        goto cleanup;
+    }
+
+    /* open container tty */
+    if (lxcSetupContainerTty(conn, &(vm->containerTtyFd), &(vm->containerTty)) < 0) {
+        goto cleanup;
+    }
+
+    /* fork process to handle the tty io forwarding */
+    if ((vm->pid = fork()) < 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("unable to fork tty forwarding process: %s"),
+                 strerror(errno));
+        goto cleanup;
+    }
+
+    if (vm->pid  == 0) {
+        /* child process calls forward routine */
+        lxcTtyForward(vm->parentTty, vm->containerTtyFd);
+    }
+
+    close(vm->parentTty);
+    close(vm->containerTtyFd);
+
+    rc = lxcStartContainer(conn, driver, vm);
+
+    if (rc == 0) {
+        vm->state = VIR_DOMAIN_RUNNING;
+        driver->ninactivevms--;
+        driver->nactivevms++;
+    }
+
+cleanup:
+    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)
+{
+    int rc = -1;
+    virConnectPtr conn = dom->conn;
+    lxc_driver_t *driver = (lxc_driver_t *)(conn->privateData);
+    lxc_vm_t *vm = lxcFindVMByName(driver, dom->name);
+
+    if (!vm) {
+        lxcError(conn, dom, VIR_ERR_INVALID_DOMAIN,
+                 "no domain with uuid");
+        goto cleanup;
+    }
+
+    rc = lxcVmStart(conn, driver, vm);
+
+cleanup:
+    return rc;
+}
+
+/**
+ * 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) {
+    lxc_driver_t *driver = (lxc_driver_t *)conn->privateData;
+    lxc_vm_t *vm;
+    lxc_vm_def_t *def;
+    virDomainPtr dom = NULL;
+
+    if (!(def = lxcParseVMDef(conn, xml, NULL))) {
+        goto return_point;
+    }
+
+    if (!(vm = lxcAssignVMDef(conn, driver, def))) {
+        lxcFreeVMDef(def);
+        goto return_point;
+    }
+
+    if (lxcSaveVMDef(conn, driver, vm, def) < 0) {
+        lxcRemoveInactiveVM(driver, vm);
+        return NULL;
+    }
+
+    if (lxcVmStart(conn, driver, vm) < 0) {
+        lxcRemoveInactiveVM(driver, vm);
+        goto return_point;
+    }
+
+    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
+    if (dom) {
+        dom->id = vm->def->id;
+    }
+
+return_point:
+    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)
+{
+    int rc = -1;
+    lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
+    lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
+
+    if (!vm) {
+        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
+                 _("no domain with id %d"), dom->id);
+        goto error_out;
+    }
+
+    if (0 > (kill(vm->def->id, SIGINT))) {
+        if (ESRCH != errno) {
+            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+                     _("sending SIGTERM failed: %s"), strerror(errno));
+
+            goto error_out;
+        }
+    }
+
+    vm->state = VIR_DOMAIN_SHUTDOWN;
+
+    rc = 0;
+
+error_out:
+    return rc;
+}
+
+/**
+ * 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)
+{
+    int rc = -1;
+    int waitRc;
+    lxc_driver_t *driver = (lxc_driver_t*)dom->conn->privateData;
+    lxc_vm_t *vm = lxcFindVMByID(driver, dom->id);
+    int childStatus;
+
+    if (!vm) {
+        lxcError(dom->conn, dom, VIR_ERR_INVALID_DOMAIN,
+                 _("no domain with id %d"), dom->id);
+        goto error_out;
+    }
+
+    if (0 > (kill(vm->def->id, SIGKILL))) {
+        if (ESRCH != errno) {
+            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+                     _("sending SIGKILL failed: %s"), strerror(errno));
+
+            goto error_out;
+        }
+    }
+
+    vm->state = VIR_DOMAIN_SHUTDOWN;
+
+    while (((waitRc = waitpid(vm->def->id, &childStatus, 0)) == -1) &&
+           errno == EINTR);
+
+    if (waitRc != vm->def->id) {
+        lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+                 _("waitpid failed to wait for container %d: %d %s"),
+                 vm->def->id, waitRc, strerror(errno));
+        goto kill_tty;
+    }
+
+    rc = WEXITSTATUS(childStatus);
+    DEBUG("container exited with rc: %d", rc);
+
+kill_tty:
+    if (0 > (kill(vm->pid, SIGKILL))) {
+        if (ESRCH != errno) {
+            lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+                     _("sending SIGKILL to tty process failed: %s"),
+                     strerror(errno));
+
+            goto tty_error_out;
+        }
+    }
+
+    while (((waitRc = waitpid(vm->pid, &childStatus, 0)) == -1) &&
+           errno == EINTR);
+
+    if (waitRc != vm->pid) {
+        lxcError(dom->conn, dom, VIR_ERR_INTERNAL_ERROR,
+                 _("waitpid failed to wait for tty %d: %d %s"),
+                 vm->pid, waitRc, strerror(errno));
+    }
+
+tty_error_out:
+    vm->state = VIR_DOMAIN_SHUTOFF;
+    vm->pid = -1;
+    vm->def->id = -1;
+    driver->nactivevms--;
+    driver->ninactivevms++;
+
+    rc = 0;
+
+error_out:
+    return rc;
+}
 
 static int lxcStartup(void)
 {
@@ -469,15 +1012,15 @@ static virDriver lxcDriver = {
     NULL, /* getCapabilities */
     lxcListDomains, /* listDomains */
     lxcNumDomains, /* numOfDomains */
-    NULL/*lxcDomainCreateLinux*/, /* domainCreateLinux */
+    lxcDomainCreateAndStart, /* domainCreateLinux */
     lxcDomainLookupByID, /* domainLookupByID */
     lxcDomainLookupByUUID, /* domainLookupByUUID */
     lxcDomainLookupByName, /* domainLookupByName */
     NULL, /* domainSuspend */
     NULL, /* domainResume */
-    NULL, /* domainShutdown */
+    lxcDomainShutdown, /* domainShutdown */
     NULL, /* domainReboot */
-    NULL, /* domainDestroy */
+    lxcDomainDestroy, /* domainDestroy */
     lxcGetOSType, /* domainGetOSType */
     NULL, /* domainGetMaxMemory */
     NULL, /* domainSetMaxMemory */
@@ -493,7 +1036,7 @@ static virDriver lxcDriver = {
     lxcDomainDumpXML, /* domainDumpXML */
     lxcListDefinedDomains, /* listDefinedDomains */
     lxcNumDefinedDomains, /* numOfDefinedDomains */
-    NULL, /* domainCreate */
+    lxcDomainStart, /* domainCreate */
     lxcDomainDefine, /* domainDefineXML */
     lxcDomainUndefine, /* domainUndefine */
     NULL, /* domainAttachDevice */