[RFC] Linux-VServer support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

This is an initial stab at adding Linux-VServer support to libvirt. There are still a couple of things missing, like scheduler support in the XML parsing, and proper network support.

I've got a few questions though. virsh's schedinfo hardcodes the available options, should I be adding new ones there? Would better introspection from getSchedulerType make this a non-issue? How do the network domains interact and associate with the regular domains?

--
Daniel Hokka Zakrisson
diff -Nurp libvirt-0.3.3.orig/configure.in libvirt-0.3.3.vserver/configure.in
--- libvirt-0.3.3.orig/configure.in	2007-09-30 23:02:48.000000000 +0200
+++ libvirt-0.3.3.vserver/configure.in	2007-10-29 23:26:06.000000000 +0100
@@ -84,6 +84,8 @@ AC_ARG_WITH(qemu,
 [  --with-qemu             add QEMU/KVM support (on)],[],[with_qemu=yes])
 AC_ARG_WITH(openvz,
 [  --with-openvz           add OpenVZ support (off)],[],[with_openvz=no])
+AC_ARG_WITH(vserver,
+[  --with-vserver          add Linux-VServer support (off)],[],[with_vserver=no])
 AC_ARG_WITH(test,
 [  --with-test             add test driver support (on)],[],[with_test=yes])
 AC_ARG_WITH(remote,
@@ -189,6 +191,19 @@ fi
 if test "$with_qemu" = "yes" ; then
     LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_QEMU"
 fi
+if test "$with_vserver" = "yes" ; then
+    AC_CHECK_LIB(vserver, [vc_rlimit_stat],, [with_vserver=no])
+    AC_CHECK_HEADER(vserver.h,, [with_vserver=no])
+    AC_MSG_CHECKING([for vserver configuration directory])
+    VSERVER_CONF_DIR=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
+        vserver-info - SYSINFO | awk '$1 == "cfg-Directory:" { print $2 }'`
+    AC_MSG_RESULT([$VSERVER_CONF_DIR])
+    AC_DEFINE_UNQUOTED([VSERVER_CONF_DIR], ["$VSERVER_CONF_DIR"],
+        [The default path to the Linux-VServer configuration files])
+    if test "$with_vserver" = "yes" ; then
+        LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_VSERVER"
+    fi
+fi
 
 if test "$with_test" = "yes" ; then
     LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_TEST"
@@ -530,6 +545,7 @@ AC_MSG_NOTICE([])
 AC_MSG_NOTICE([     Xen: $with_xen])
 AC_MSG_NOTICE([    QEMU: $with_qemu])
 AC_MSG_NOTICE([  OpenVZ: $with_openvz])
+AC_MSG_NOTICE([ VServer: $with_vserver])
 AC_MSG_NOTICE([    Test: $with_test])
 AC_MSG_NOTICE([  Remote: $with_remote])
 AC_MSG_NOTICE([])
diff -Nurp libvirt-0.3.3.orig/include/libvirt/virterror.h libvirt-0.3.3.vserver/include/libvirt/virterror.h
--- libvirt-0.3.3.orig/include/libvirt/virterror.h	2007-07-19 18:07:35.000000000 +0200
+++ libvirt-0.3.3.vserver/include/libvirt/virterror.h	2007-10-29 23:26:06.000000000 +0100
@@ -52,6 +52,7 @@ typedef enum {
     VIR_FROM_TEST,	/* Error from test driver */
     VIR_FROM_REMOTE,	/* Error from remote driver */
     VIR_FROM_OPENVZ,    /* Error from OpenVZ driver */
+    VIR_FROM_VSERVER,	/* Error from Linux-VServer */
 } virErrorDomain;
 
 
diff -Nurp libvirt-0.3.3.orig/python/libvirt.py libvirt-0.3.3.vserver/python/libvirt.py
--- libvirt-0.3.3.orig/python/libvirt.py	2007-09-30 23:43:44.000000000 +0200
+++ libvirt-0.3.3.vserver/python/libvirt.py	2007-10-29 23:26:06.000000000 +0100
@@ -840,6 +840,7 @@ VIR_FROM_NET = 11
 VIR_FROM_TEST = 12
 VIR_FROM_REMOTE = 13
 VIR_FROM_OPENVZ = 14
+VIR_FROM_VSERVER = 15
 
 # virDomainRestart
 VIR_DOMAIN_DESTROY = 1
diff -Nurp libvirt-0.3.3.orig/src/driver.h libvirt-0.3.3.vserver/src/driver.h
--- libvirt-0.3.3.orig/src/driver.h	2007-09-30 12:39:28.000000000 +0200
+++ libvirt-0.3.3.vserver/src/driver.h	2007-10-29 23:26:06.000000000 +0100
@@ -22,6 +22,7 @@ typedef enum {
     VIR_DRV_QEMU = 3,
     VIR_DRV_REMOTE = 4,
     VIR_DRV_OPENVZ = 5,
+    VIR_DRV_VSERVER = 6,
 } virDrvNo;
 
 
diff -Nurp libvirt-0.3.3.orig/src/libvirt.c libvirt-0.3.3.vserver/src/libvirt.c
--- libvirt-0.3.3.orig/src/libvirt.c	2007-09-30 15:17:30.000000000 +0200
+++ libvirt-0.3.3.vserver/src/libvirt.c	2007-10-29 23:26:06.000000000 +0100
@@ -34,6 +34,7 @@
 #ifdef WITH_OPENVZ
 #include "openvz_driver.h"
 #endif
+#include "vserver_driver.h"
 
 /*
  * TODO:
@@ -98,6 +99,9 @@ virInitialize(void)
 #ifdef WITH_OPENVZ
     if (openvzRegister() == -1) return -1;
 #endif
+#ifdef WITH_VSERVER
+    if (vserverRegister() == -1) return -1;
+#endif
 #ifdef WITH_REMOTE
     if (remoteRegister () == -1) return -1;
 #endif
diff -Nurp libvirt-0.3.3.orig/src/Makefile.am libvirt-0.3.3.vserver/src/Makefile.am
--- libvirt-0.3.3.orig/src/Makefile.am	2007-09-21 12:41:27.000000000 +0200
+++ libvirt-0.3.3.vserver/src/Makefile.am	2007-10-29 23:26:06.000000000 +0100
@@ -52,6 +52,7 @@ CLIENT_SOURCES =						\
 		qemu_conf.c qemu_conf.h					\
 		openvz_conf.c openvz_conf.h				\
 		openvz_driver.c openvz_driver.h 		\
+		vserver_driver.c vserver_driver.h		\
                 nodeinfo.h nodeinfo.c                           \
 		util.c util.h
 
diff -Nurp libvirt-0.3.3.orig/src/virterror.c libvirt-0.3.3.vserver/src/virterror.c
--- libvirt-0.3.3.orig/src/virterror.c	2007-09-26 11:09:13.000000000 +0200
+++ libvirt-0.3.3.vserver/src/virterror.c	2007-10-29 23:26:06.000000000 +0100
@@ -280,6 +280,9 @@ virDefaultErrorFunc(virErrorPtr err)
         case VIR_FROM_REMOTE:
             dom = "Remote ";
             break;
+        case VIR_FROM_VSERVER:
+            dom = "VServer ";
+            break;
     }
     if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
         domain = err->dom->name;
diff -Nurp libvirt-0.3.3.orig/src/vserver_driver.c libvirt-0.3.3.vserver/src/vserver_driver.c
--- libvirt-0.3.3.orig/src/vserver_driver.c	1970-01-01 01:00:00.000000000 +0100
+++ libvirt-0.3.3.vserver/src/vserver_driver.c	2007-10-29 23:26:06.000000000 +0100
@@ -0,0 +1,1368 @@
+/*
+ * Core driver for managing Linux-VServer guests
+ *
+ * Copyright (C) 2007 Daniel Hokka Zakrisson
+ *
+ * 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
+ *
+ * Author: Daniel Hokka Zakrisson <daniel@xxxxxxxxx>
+ */
+
+#ifdef WITH_VSERVER
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include <libxml/uri.h>
+#include <libxml/xpath.h>
+#include <libxml/tree.h>
+
+#include <libvirt/virterror.h>
+
+#include "internal.h"
+#include "vserver_driver.h"
+#include "buf.h"
+#include "uuid.h"
+#include "xml.h"
+#include "nodeinfo.h"
+
+typedef unsigned int xid_t;
+typedef unsigned int nid_t;
+typedef unsigned int tag_t;
+#include <vserver.h>
+
+#define PROG_VSERVER "/usr/sbin/vserver"
+
+#define GET_DOMAIN(dom, ret)                                            \
+    struct vserver_driver *driver = (struct vserver_driver *)           \
+                                    (dom)->conn->privateData;           \
+    struct vserver_guest *guest = getGuestByUUID(driver, (dom)->uuid);  \
+                                                                        \
+    if (!guest) {                                                       \
+        vserverError((dom)->conn, (dom), NULL, VIR_ERR_INVALID_ARG,     \
+                     __FUNCTION__);                                     \
+        return (ret);                                                   \
+    }
+
+static inline struct vserver_guest *
+getGuestByID(struct vserver_driver *driver,
+             int id)
+{
+    struct vserver_guest *res;
+    for (res = driver->guests; res; res = res->next) {
+        if (res->xid == id)
+            break;
+    }
+    return res;
+}
+
+static inline struct vserver_guest *
+getGuestByUUID(struct vserver_driver *driver,
+               const unsigned char *uuid)
+{
+    struct vserver_guest *res;
+    for (res = driver->guests; res; res = res->next) {
+        if (memcmp(res->uuid, uuid, VIR_UUID_BUFLEN) == 0)
+            break;
+    }
+    return res;
+}
+
+static inline struct vserver_guest *
+getGuestByName(struct vserver_driver *driver,
+               const char *name)
+{
+    struct vserver_guest *res;
+    for (res = driver->guests; res; res = res->next) {
+        if (STREQ(res->name, name))
+            break;
+    }
+    return res;
+}
+
+static inline void
+vserverError(virConnectPtr con,
+             virDomainPtr dom,
+             virNetworkPtr net,
+             virErrorNumber error,
+             const char *info)
+{
+    const char *errmsg;
+
+    if (error == VIR_ERR_OK)
+        return;
+
+    errmsg = __virErrorMsg(error, info);
+    __virRaiseError(con, dom, net, VIR_FROM_VSERVER, error, VIR_ERR_ERROR,
+                    errmsg, info, NULL, 0, 0, errmsg, info, 0);
+}
+
+/* like execl, but uses /dev/null and handles forking/waiting/etc. */
+static int
+runCommand(const char *cmd, ...)
+{
+    pid_t pid;
+    va_list va;
+    char *argv[10];
+    int i;
+    sighandler_t sigchld;
+    int ret;
+
+    va_start(va, cmd);
+    argv[0] = (char *) cmd;
+    for (i = 1; i < (sizeof(argv) / sizeof(*argv)) - 1; i++) {
+        argv[i] = va_arg(va, char *);
+        if (argv[i] == NULL)
+            break;
+    }
+    if (argv[i] != NULL)
+        return -1;
+
+    va_end(va);
+
+    sigchld = signal(SIGCHLD, SIG_DFL);
+    if ((pid = fork()) == 0) {
+        int fd;
+        if ((fd = open("/dev/null", O_RDWR)) == -1)
+            goto error;
+        if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1)
+            goto error;
+        if (fd > 2 && close(fd) == -1)
+            goto error;
+        execv(cmd, argv);
+    error:
+        _exit(1);
+    }
+    else if (pid == -1) {
+        ret =  -1;
+    }
+    else {
+        int status;
+        if (waitpid(pid, &status, 0) == -1)
+            ret = -1;
+        else if (WEXITSTATUS(status) != 0)
+            ret = 1;
+        else
+            ret = 0;
+    }
+
+    signal(SIGCHLD, sigchld);
+    return ret;
+}
+
+static int
+readStr(char *dst, size_t len, const char *name, const char *setting)
+{
+    char file[strlen(name) + strlen(setting) + 2];
+    int fd;
+    ssize_t bytes;
+    char *p;
+
+    sprintf(file, "%s/%s", name, setting);
+
+    /* a non-existant file is not a failure */
+    *dst = '\0';
+    if ((fd = open(file, O_RDONLY)) == -1)
+        return 1;
+
+    if ((bytes = read(fd, dst, len - 1)) == -1) {
+        close(fd);
+        return -1;
+    }
+    close(fd);
+
+    dst[bytes] = '\0';
+
+    if ((p = strchr(dst, '\n')) != NULL)
+        *p = '\0';
+
+    return 0;
+}
+
+static int
+readLong(void *v_dst, const char *name, const char *setting)
+{
+    char buf[128], *endptr;
+    int ret;
+    long *dst = v_dst;
+
+    ret = readStr(buf, sizeof(buf), name, setting);
+    if (ret)
+        return ret;
+
+    *dst = strtol(buf, &endptr, 0);
+    if (endptr && *endptr != '\0')
+        return -1;
+
+    return 0;
+}
+
+static int
+readInt(void *v_dst, const char *name, const char *setting)
+{
+    long val;
+    int *dst = v_dst;
+    int ret;
+
+    ret = readLong(&val, name, setting);
+    if (ret)
+        return ret;
+
+    *dst = (int) val;
+
+    return 0;
+}
+
+static int
+readBool(char *dst, const char *name, const char *setting)
+{
+    char file[strlen(name) + strlen(setting) + 2];
+
+    sprintf(file, "%s/%s", name, setting);
+
+    *dst = access(file, F_OK) != -1;
+
+    return 0;
+}
+
+static int
+writeToConfig(struct vserver_guest *guest, const char *filename,
+              const char *format, ...)
+{
+    char path[strlen(guest->path) + 1 + strlen(filename) + 1];
+    va_list va;
+    char value[1024];
+    int fd;
+    ssize_t len, off, ret;
+
+    sprintf(path, "%s/%s", guest->path, filename);
+
+    va_start(va, format);
+    if (strcmp(format, "%b") == 0) {
+        /* bool, this is a special case */
+        if (va_arg(va, int)) {
+            *value = '\0';
+            len = 0;
+        }
+        else {
+            if (unlink(path) == -1 && errno != -ENOENT)
+                return -1;
+            else
+                return 0;
+        }
+    }
+    else
+        len = vsnprintf(value, sizeof(value), format, va);
+    va_end(va);
+
+    fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 0644);
+    if (fd == -1)
+        return -1;
+
+    for (off = 0; off < len; off += ret) {
+        ret = write(fd, value + off, len - off);
+        if (ret == -1) {
+            close(fd);
+            return -1;
+        }
+    }
+
+    if (close(fd) == -1)
+        return -1;
+    return 0;
+}
+
+static int
+contextIsRunning(const char *path)
+{
+    return vc_getVserverCtx(path, vcCFG_AUTO, false, 0, vcCTX_XID) != VC_NOCTX;
+}
+
+static virDrvOpenStatus
+vserverInitializeDriver(virConnectPtr conn, struct vserver_driver *driver,
+                        const char *path)
+{
+    struct vserver_guest *guest = NULL;
+    DIR *dp = NULL;
+    struct dirent *de;
+    int cwd;
+    char uuidstr[VIR_UUID_STRING_BUFLEN + 1];
+    char mark[8];
+    const char *conf_dir = (*path ? path : VSERVER_CONF_DIR);
+
+    if (driver->initialized == 1)
+        return VIR_DRV_OPEN_SUCCESS;
+
+    driver->guests = NULL;
+    driver->networks = NULL;
+    driver->inactive_guests = driver->active_guests = 0;
+
+    cwd = open(".", O_RDONLY);
+    if (cwd == -1 ||
+        chdir(conf_dir) == -1 ||
+        (dp = opendir(".")) == NULL) {
+        vserverError(conn, NULL, NULL, VIR_ERR_OPEN_FAILED, conf_dir);
+        goto error;
+    }
+
+    while ((de = readdir(dp)) != NULL) {
+        if (*de->d_name == '.')
+            continue;
+
+        if (driver->guests == NULL)
+            driver->guests = guest = calloc(1, sizeof(struct vserver_guest));
+        else {
+            guest->next = calloc(1, sizeof(struct vserver_guest));
+            guest = guest->next;
+        }
+
+        if (!guest) {
+            vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
+                         "vserver_guest");
+            goto error;
+        }
+
+        snprintf(guest->path, sizeof(guest->path), "%s/%s",
+                 conf_dir, de->d_name);
+
+#define CHECK(x)                                                            \
+    if ((x) == -1) {                                                        \
+        vserverError(conn, NULL, NULL, VIR_ERR_PARSE_FAILED, de->d_name);   \
+        goto error;                                                         \
+    }
+#define DO_SCHED(type, var, file, bit)                                      \
+    do {                                                                    \
+        int ret;                                                            \
+        CHECK(ret = read ## type((var), de->d_name, (file)));               \
+        if (ret == 0)                                                       \
+            guest->sched.set_mask |= (bit);                                 \
+    } while (0)
+        CHECK(readInt(&guest->xid, de->d_name, "context"));
+        CHECK(readStr(guest->name, sizeof(guest->name), de->d_name, "name"));
+        CHECK(readStr(guest->hostname, sizeof(guest->hostname), de->d_name,
+                      "uts/nodename"));
+        CHECK(readStr(uuidstr, sizeof(uuidstr), de->d_name, "uuid"));
+        CHECK(readStr(mark, sizeof(mark), de->d_name, "apps/init/mark"));
+        DO_SCHED(Int, &guest->sched.fill_rate[0], "sched/fill-rate",
+                 VSERVER_SCHED_FILL_RATE1);
+        DO_SCHED(Int, &guest->sched.interval[0],  "sched/interval",
+                 VSERVER_SCHED_INTERVAL1);
+        DO_SCHED(Int, &guest->sched.fill_rate[1], "sched/fill-rate2",
+                 VSERVER_SCHED_FILL_RATE2);
+        DO_SCHED(Int, &guest->sched.interval[1],  "sched/interval2",
+                 VSERVER_SCHED_INTERVAL2);
+        DO_SCHED(Int, &guest->sched.tokens_min,   "sched/tokens-min",
+                 VSERVER_SCHED_TOKENS_MIN);
+        DO_SCHED(Int, &guest->sched.tokens_max,   "sched/tokens-max",
+                 VSERVER_SCHED_TOKENS_MAX);
+        DO_SCHED(Int, &guest->sched.prio_bias,    "sched/priority-bias",
+                 VSERVER_SCHED_PRIO_BIAS);
+        DO_SCHED(Bool, &guest->sched.idle_time,   "sched/idle-time",
+                 VSERVER_SCHED_IDLE_TIME);
+        CHECK(readLong(&guest->rss_hard, de->d_name, "rlimits/rss.hard"));
+
+        CHECK(virUUIDParse(uuidstr, guest->uuid));
+#undef DO_SCHED
+#undef CHECK
+
+        if (STREQ(mark, "default"))
+            guest->autostart = 1;
+        if (contextIsRunning(guest->path)) {
+            guest->status = VIR_DOMAIN_RUNNING;
+            driver->active_guests++;
+        }
+        else {
+            guest->status = VIR_DOMAIN_SHUTOFF;
+            driver->inactive_guests++;
+        }
+    }
+
+    closedir(dp);
+    fchdir(cwd);
+    driver->initialized = 1;
+
+    return VIR_DRV_OPEN_SUCCESS;
+
+error:
+    if (dp)
+        closedir(dp);
+
+    fchdir(cwd);
+    return VIR_DRV_OPEN_ERROR;
+}
+
+static virDrvOpenStatus
+vserverOpen(virConnectPtr conn, const char *name, int flags ATTRIBUTE_UNUSED)
+{
+    xmlURIPtr uri;
+    virDrvOpenStatus ret;
+
+    if (!name)
+        return VIR_DRV_OPEN_DECLINED;
+
+    if (getuid() != 0)
+        return VIR_DRV_OPEN_DECLINED;
+
+    uri = xmlParseURI(name);
+    if (!uri)
+        return VIR_DRV_OPEN_DECLINED;
+
+    if (!uri->scheme || STRNEQ(uri->scheme, "vserver")) {
+        xmlFreeURI(uri);
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    if (uri->server) {
+        xmlFreeURI(uri);
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    /* nothing else supported right now */
+    if (strncmp(uri->path, "/system", 7) != 0) {
+        xmlFreeURI(uri);
+        return VIR_DRV_OPEN_DECLINED;
+    }
+    
+    if (access("/proc/virtual", F_OK) == -1) {
+        xmlFreeURI(uri);
+        return VIR_DRV_OPEN_DECLINED;
+    }
+
+    if (!conn->privateData)
+        conn->privateData = calloc(1, sizeof(struct vserver_driver));
+
+    ret = vserverInitializeDriver(conn, conn->privateData, uri->path + 7);
+
+    xmlFreeURI(uri);
+
+    return ret;
+}
+
+static int
+vserverClose(virConnectPtr conn)
+{
+    struct vserver_driver *driver = conn->privateData;
+    struct vserver_guest *guest, *pguest;
+
+    if (!driver || !driver->initialized)
+        return 0;
+
+    for (guest = driver->guests, pguest = NULL; guest; guest = guest->next) {
+        if (pguest)
+            free(pguest);
+        pguest = guest;
+    }
+    if (pguest)
+        free(pguest);
+
+    free(driver);
+    conn->privateData = NULL;
+
+    return 0;
+}
+
+static const char *
+vserverGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    return "Linux-VServer";
+}
+
+static int
+vserverGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
+{
+    *version = 1;
+    return 0;
+}
+
+static char *
+vserverGetHostname(virConnectPtr conn)
+{
+    char *ret;
+
+    ret = calloc(VSERVER_HOSTNAME_MAX + 1, sizeof(char));
+    if (!ret) {
+        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "gethostname");
+        return NULL;
+    }
+
+    if (gethostname(ret, VSERVER_HOSTNAME_MAX) == -1) {
+        free(ret);
+        vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "gethostname");
+        return NULL;
+    }
+
+    return ret;
+}
+
+static char *
+vserverGetURI(virConnectPtr conn ATTRIBUTE_UNUSED)
+{
+    /* FIXME */
+    return strdup("vserver:///system");
+}
+
+static int
+vserverNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
+{
+    return virNodeInfoPopulate(conn, nodeinfo);
+}
+
+static int
+vserverListDomains(virConnectPtr conn, int *ids, int nids)
+{
+    struct vserver_driver *driver = conn->privateData;
+    struct vserver_guest *guest;
+    int i;
+
+    for (guest = driver->guests, i = 0; guest && i < nids;
+         guest = guest->next) {
+        if (guest->status == VIR_DOMAIN_RUNNING)
+            ids[i++] = guest->xid;
+    }
+
+    return i;
+}
+
+static int
+vserverNumOfDomains(virConnectPtr conn)
+{
+    struct vserver_driver *driver = conn->privateData;
+
+    return driver->active_guests;
+}
+
+static virDomainPtr
+vserverDomainLookupByID(virConnectPtr conn, int id)
+{
+    struct vserver_driver *driver = conn->privateData;
+    struct vserver_guest *guest;
+    virDomainPtr domain;
+
+    if ((guest = getGuestByID(driver, id)) == NULL) {
+        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
+                     _("No domain by that ID found"));
+        return NULL;
+    }
+
+    domain = virGetDomain(conn, guest->name, guest->uuid);
+    if (!domain) {
+        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
+        return NULL;
+    }
+
+    if (guest->status == VIR_DOMAIN_RUNNING)
+        domain->id = guest->xid;
+
+    return domain;
+}
+
+static virDomainPtr
+vserverDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+    struct vserver_driver *driver = conn->privateData;
+    struct vserver_guest *guest;
+    virDomainPtr domain;
+
+    if ((guest = getGuestByUUID(driver, uuid)) == NULL) {
+        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
+                     _("No domain by that UUID found"));
+        return NULL;
+    }
+
+    domain = virGetDomain(conn, guest->name, guest->uuid);
+    if (!domain) {
+        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
+        return NULL;
+    }
+
+    if (guest->status == VIR_DOMAIN_RUNNING)
+        domain->id = guest->xid;
+
+    return domain;
+}
+
+static virDomainPtr
+vserverDomainLookupByName(virConnectPtr conn, const char *name)
+{
+    struct vserver_driver *driver = conn->privateData;
+    struct vserver_guest *guest;
+    virDomainPtr domain;
+
+    if ((guest = getGuestByName(driver, name)) == NULL) {
+        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
+                     _("No domain by that name found"));
+        return NULL;
+    }
+
+    domain = virGetDomain(conn, guest->name, guest->uuid);
+    if (!domain) {
+        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
+        return NULL;
+    }
+
+    if (guest->status == VIR_DOMAIN_RUNNING)
+        domain->id = guest->xid;
+
+    return domain;
+}
+
+static int
+vserverDomainShutdown(virDomainPtr domain)
+{
+    GET_DOMAIN(domain, -1);
+
+    if (runCommand(PROG_VSERVER, guest->path, "stop", NULL) != 0) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
+                     "vserver stop");
+        return -1;
+    }
+
+    driver->active_guests--;
+    guest->status = VIR_DOMAIN_SHUTOFF;
+    driver->inactive_guests++;
+    return 0;
+}
+
+static int
+vserverDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
+{
+    GET_DOMAIN(domain, -1);
+
+    if (runCommand(PROG_VSERVER, guest->path, "restart", NULL) != 0) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
+                     "vserver restart");
+        return -1;
+    }
+
+    guest->status = VIR_DOMAIN_RUNNING;
+    return 0;
+}
+
+static int
+vserverDomainDestroy(virDomainPtr domain)
+{
+    GET_DOMAIN(domain, -1);
+
+    if (vserverDomainShutdown(domain) == -1)
+        return -1;
+
+    virFreeDomain(domain->conn, domain);
+
+    return 0;
+}
+
+static char *
+vserverDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
+{
+    return strdup("Linux");
+}
+
+static unsigned long
+vserverDomainGetMaxMemory(virDomainPtr domain)
+{
+    GET_DOMAIN(domain, (unsigned long) -1);
+
+    return guest->rss_hard;
+}
+
+static int
+vserverDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
+{
+    struct vc_rlimit limit = {
+        .min = 0,
+        .soft = memory,
+        .hard = memory,
+    };
+    GET_DOMAIN(domain, -1);
+
+    guest->rss_hard = memory;
+    if (guest->status == VIR_DOMAIN_RUNNING &&
+        vc_set_rlimit(guest->xid, RLIMIT_RSS, &limit) == -1) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR, "vc_set_rlimit");
+        return -1;
+    }
+
+    if (writeToConfig(guest, "rlimits/rss", "%lu\n", memory) == -1) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR, "writeToConfig");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+vserverDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+    struct vc_sched_info sinfo = { .user_msec = 0, .sys_msec = 0 };
+    struct vc_rlimit_stat rss_stat = { .value = 0 };
+    GET_DOMAIN(domain, -1);
+
+    if (guest->status == VIR_DOMAIN_RUNNING) {
+        if (vc_sched_info(guest->xid, &sinfo) == -1) {
+            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR, "vc_sched_info");
+            return -1;
+        }
+        if (vc_rlimit_stat(guest->xid, RLIMIT_RSS, &rss_stat) == -1) {
+            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR, "vc_rlimit_stat");
+            return -1;
+        }
+    }
+
+    info->state = guest->status;
+    info->maxMem = guest->rss_hard;
+    info->nrVirtCpu = -1;
+    info->memory = rss_stat.value;
+    info->cpuTime = (sinfo.user_msec + sinfo.sys_msec) * 1000000ULL;
+
+    return 0;
+}
+
+static char *
+vserverDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
+{
+    virBufferPtr buf;
+    char uuid[VIR_UUID_STRING_BUFLEN + 1];
+    GET_DOMAIN(domain, NULL);
+
+    buf = virBufferNew(4096);
+    if (!buf)
+        goto no_memory;
+
+    virUUIDFormat(guest->uuid, uuid);
+    if (virBufferVSprintf(buf,
+"<domain type='vserver'>\n"
+"  <xid>%d</xid>\n"
+"  <name>%s</name>\n"
+"  <uuid>%s</uuid>\n"
+"  <memory>%lu</memory>\n"
+                             , guest->xid, guest->name, uuid, guest->rss_hard
+                             ) < 0)
+        goto no_memory;
+
+    if (guest->sched.set_mask) {
+        if (virBufferVSprintf(buf, "  <scheduler>\n") < 0)
+            goto no_memory;
+        if (guest->sched.set_mask & VSERVER_SCHED_FILL_RATE1)
+            if (virBufferVSprintf(buf,
+                                  "    <param name='fill_rate1'>%u</param>\n",
+                                  guest->sched.fill_rate[0]) < 0)
+                goto no_memory;
+        if (guest->sched.set_mask & VSERVER_SCHED_INTERVAL1)
+            if (virBufferVSprintf(buf,
+                                  "    <param name='interval1'>%u</param>\n",
+                                  guest->sched.interval[0]) < 0)
+                goto no_memory;
+        if (guest->sched.set_mask & VSERVER_SCHED_FILL_RATE2)
+            if (virBufferVSprintf(buf,
+                                  "    <param name='fill_rate2'>%u</param>\n",
+                                  guest->sched.fill_rate[1]) < 0)
+                goto no_memory;
+        if (guest->sched.set_mask & VSERVER_SCHED_INTERVAL2)
+            if (virBufferVSprintf(buf,
+                                  "    <param name='interval2'>%u</param>\n",
+                                  guest->sched.interval[1]) < 0)
+                goto no_memory;
+        if (guest->sched.set_mask & VSERVER_SCHED_TOKENS_MIN)
+            if (virBufferVSprintf(buf,
+                                  "    <param name='tokens_min'>%u</param>\n",
+                                  guest->sched.tokens_min) < 0)
+                goto no_memory;
+        if (guest->sched.set_mask & VSERVER_SCHED_TOKENS_MAX)
+            if (virBufferVSprintf(buf,
+                                  "    <param name='tokens_max'>%u</param>\n",
+                                  guest->sched.tokens_max) < 0)
+                goto no_memory;
+        if (guest->sched.set_mask & VSERVER_SCHED_PRIO_BIAS)
+            if (virBufferVSprintf(buf,
+                                  "    <param name='prio_bias'>%d</param>\n",
+                                  guest->sched.prio_bias) < 0)
+                goto no_memory;
+        if (guest->sched.set_mask & VSERVER_SCHED_IDLE_TIME)
+            if (virBufferVSprintf(buf,
+                                  "    <param name='idle_time'>%d</param>\n",
+                                  (int) guest->sched.idle_time) < 0)
+                goto no_memory;
+        if (virBufferVSprintf(buf, "  </scheduler>\n") < 0)
+            goto no_memory;
+    }
+    if (virBufferVSprintf(buf, "</domain>\n") < 0)
+        goto no_memory;
+
+    return virBufferContentAndFree(buf);
+
+no_memory:
+    if (buf)
+        virBufferFree(buf);
+    vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
+                 "xml");
+    return NULL;
+}
+
+static int
+vserverParseXML(struct vserver_guest *guest, xmlDocPtr doc)
+{
+    xmlNodePtr root = NULL;
+    xmlXPathContextPtr xpath = NULL;
+    char *str;
+    long l_tmp;
+
+    root = xmlDocGetRootElement(doc);
+    if (!root || !xmlStrEqual(root->name, BAD_CAST "domain"))
+        goto err;
+
+    xpath = xmlXPathNewContext(doc);
+    if (!xpath)
+        goto err;
+
+    if (virXPathLong("string(/domain/xid[1])", xpath, &l_tmp) != 0)
+        goto err;
+    guest->xid = (int) l_tmp;
+
+    str = virXPathString("string(/domain/name[1])", xpath);
+    if (!str)
+        goto err;
+    strncpy(guest->name, str, VSERVER_NAME_MAX - 1);
+
+    str = virXPathString("string(/domain/uuid[1])", xpath);
+    if (!str)
+        goto err;
+    if (virUUIDParse(str, guest->uuid) < 0)
+        goto err;
+
+    if (virXPathLong("string(/domain/memory[1])", xpath, (long *) &guest->rss_hard) != 0)
+        goto err;
+
+    /* TODO: scheduler */
+
+    xmlXPathFreeContext(xpath);
+    xpath = NULL;
+
+    return 0;
+
+err:
+    if (xpath)
+        xmlXPathFreeContext(xpath);
+    return -1;
+}
+
+static virDomainPtr
+vserverDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+    struct vserver_driver *driver = conn->privateData;
+    struct vserver_guest *guest, *tail;
+    virDomainPtr domain;
+    xmlDocPtr doc;
+
+    if ((guest = calloc(1, sizeof(struct vserver_guest))) == NULL) {
+        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "vserver_guest");
+        return NULL;
+    }
+
+    if ((doc = xmlReadDoc(BAD_CAST xml, "domain.xml", NULL,
+                          XML_PARSE_NOENT | XML_PARSE_NONET |
+                          XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
+        vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
+        free(guest);
+        return NULL;
+    }
+
+    if (vserverParseXML(guest, doc) == -1) {
+        vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
+        xmlFreeDoc(doc);
+        free(guest);
+        return NULL;
+    }
+
+    xmlFreeDoc(doc);
+
+    if (runCommand(PROG_VSERVER, guest->name, "build", "-m",
+                   "skeleton", NULL) == -1) {
+        vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserver build");
+        free(guest);
+        return NULL;
+    }
+
+    /* add it to the list */
+    for (tail = driver->guests; tail && tail->next; tail = tail->next)
+        ;
+    if (!tail)
+        driver->guests = guest;
+    else
+        tail->next = guest;
+
+    driver->inactive_guests++;
+
+    domain = virGetDomain(conn, guest->name, guest->uuid);
+    if (!domain)
+        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
+
+    return domain;
+}
+
+static int
+vserverListDefinedDomains(virConnectPtr conn, char **const names,
+                          int maxnames)
+{
+    struct vserver_driver *driver = conn->privateData;
+    struct vserver_guest *guest;
+    int i = 0;
+
+    for (guest = driver->guests; guest && i < maxnames; guest = guest->next) {
+        if (guest->status == VIR_DOMAIN_SHUTOFF) {
+            if ((names[i++] = strdup(guest->name)) == NULL) {
+                vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "names");
+                return -1;
+            }
+        }
+    }
+
+    return i;
+}
+
+static int
+vserverNumOfDefinedDomains(virConnectPtr conn)
+{
+    struct vserver_driver *driver = conn->privateData;
+
+    return driver->inactive_guests;
+}
+
+static int
+vserverDomainCreate(virDomainPtr domain)
+{
+    GET_DOMAIN(domain, -1);
+
+    if (runCommand(PROG_VSERVER, guest->path, "start", NULL) != 0) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
+                     "vserver start");
+        return -1;
+    }
+
+    driver->inactive_guests--;
+    guest->status = VIR_DOMAIN_RUNNING;
+    driver->active_guests++;
+    return 0;
+}
+
+static virDomainPtr
+vserverDomainCreateLinux(virConnectPtr conn, const char *xml,
+                         unsigned int flags ATTRIBUTE_UNUSED)
+{
+    virDomainPtr domain;
+
+    domain = vserverDomainDefineXML(conn, xml);
+    if (!domain)
+        return NULL;
+
+    if (vserverDomainCreate(domain) == -1)
+        return NULL;
+
+    return domain;
+}
+
+static int
+vserverDomainUndefine(virDomainPtr domain)
+{
+    struct vserver_guest *prev;
+    GET_DOMAIN(domain, -1);
+
+    for (prev = driver->guests; prev; prev = prev->next) {
+        if (prev->next == guest)
+            break;
+    }
+    if (!prev) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
+                     _("Domain not found"));
+        return -1;
+    }
+    if (guest->status == VIR_DOMAIN_RUNNING) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG,
+                     _("Domain is running"));
+        return -1;
+    }
+
+    driver->inactive_guests--;
+    prev->next = guest->next;
+    /* XXX: deletes the domain's contents as well */
+    runCommand(PROG_VSERVER, guest->path, "delete", NULL);
+    free(guest);
+
+    return 0;
+}
+
+static int
+vserverDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+                     unsigned char *cpumap, int maplen)
+{
+    /* TODO: implement this */
+    return -1;
+}
+
+static int
+vserverDomainGetAutostart(virDomainPtr domain, int *autostart)
+{
+    GET_DOMAIN(domain, -1);
+
+    *autostart = guest->autostart;
+    return 0;
+}
+
+static int
+vserverDomainSetAutostart(virDomainPtr domain, int autostart)
+{
+    GET_DOMAIN(domain, -1);
+
+    if (writeToConfig(guest, "apps/init/mark",
+                      (autostart ? "default\n" : "\n")) == -1) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
+                     "writeToConfig");
+        return -1;
+    }
+    guest->autostart = autostart;
+    return 0;
+}
+
+static const struct {
+    enum vserver_scheduler_setting id;
+    const char *field;
+    int type;
+} sched_fields[] = {
+    { VSERVER_SCHED_FILL_RATE1, "fill_rate1",   VIR_DOMAIN_SCHED_FIELD_UINT },
+    { VSERVER_SCHED_INTERVAL1,  "interval1",    VIR_DOMAIN_SCHED_FIELD_UINT },
+    { VSERVER_SCHED_FILL_RATE2, "fill_rate2",   VIR_DOMAIN_SCHED_FIELD_UINT },
+    { VSERVER_SCHED_INTERVAL2,  "interval2",    VIR_DOMAIN_SCHED_FIELD_UINT },
+    { VSERVER_SCHED_TOKENS_MIN, "tokens_min",   VIR_DOMAIN_SCHED_FIELD_UINT },
+    { VSERVER_SCHED_TOKENS_MAX, "tokens_max",   VIR_DOMAIN_SCHED_FIELD_UINT },
+    { VSERVER_SCHED_PRIO_BIAS,  "prio_bias",    VIR_DOMAIN_SCHED_FIELD_INT  },
+    { VSERVER_SCHED_IDLE_TIME,  "idle_time",    VIR_DOMAIN_SCHED_FIELD_BOOLEAN },
+    { 0, NULL, 0 }
+};
+
+static char *
+vserverDomainGetSchedulerType(virDomainPtr domain, int *nparams)
+{
+    char *ret;
+    int i;
+    GET_DOMAIN(domain, NULL);
+
+    ret = strdup(guest->sched.idle_time ? "fair" : "hard");
+    if (!ret) {
+        vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
+                     _("scheduler"));
+        return NULL;
+    }
+
+    *nparams = 0;
+    for (i = 0; sched_fields[i].field != NULL; i++) {
+        if (guest->sched.set_mask & sched_fields[i].id)
+            (*nparams)++;
+    }
+
+    return ret;
+}
+
+static int
+vserverDomainGetSchedulerParams(virDomainPtr domain,
+                                virSchedParameterPtr params,
+                                int *nparams)
+{
+    int i, j;
+    GET_DOMAIN(domain, -1);
+
+    for (i = 0, j = 0; sched_fields[i].field != NULL && i < *nparams; i++) {
+        /* skip unset fields */
+        if (!(guest->sched.set_mask & sched_fields[i].id))
+            continue;
+
+        params[j].type = sched_fields[i].type;
+        strncpy(params[j].field, sched_fields[i].field, sizeof(params[j].field) - 1);
+        switch (sched_fields[i].id) {
+            case VSERVER_SCHED_FILL_RATE1:
+                params[j].value.ui = guest->sched.fill_rate[0];
+                break;
+            case VSERVER_SCHED_INTERVAL1:
+                params[j].value.ui = guest->sched.interval[0];
+                break;
+            case VSERVER_SCHED_FILL_RATE2:
+                params[j].value.ui = guest->sched.fill_rate[1];
+                break;
+            case VSERVER_SCHED_INTERVAL2:
+                params[j].value.ui = guest->sched.interval[1];
+                break;
+            case VSERVER_SCHED_TOKENS_MIN:
+                params[j].value.ui = guest->sched.tokens_min;
+                break;
+            case VSERVER_SCHED_TOKENS_MAX:
+                params[j].value.ui = guest->sched.tokens_max;
+                break;
+            case VSERVER_SCHED_PRIO_BIAS:
+                params[j].value.i = guest->sched.prio_bias;
+                break;
+            case VSERVER_SCHED_IDLE_TIME:
+                params[j].value.b = guest->sched.idle_time;
+                break;
+        }
+        j++;
+    }
+    *nparams = j;
+
+    return 0;
+}
+
+static int
+vserverDomainSetSchedulerParams(virDomainPtr domain,
+                                virSchedParameterPtr params,
+                                int nparams)
+{
+    int i, j, cret;
+    GET_DOMAIN(domain, -1);
+
+    for (i = 0; i < nparams; i++) {
+        for (j = 0; sched_fields[j].field != NULL; j++) {
+            if (STREQ(sched_fields[j].field, params[i].field))
+                break;
+        }
+        if (sched_fields[j].field == NULL) {
+            vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "field");
+            return -1;
+        }
+        if (sched_fields[j].type != params[i].type) {
+            vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "type");
+            return -1;
+        }
+        switch (sched_fields[j].id) {
+            case VSERVER_SCHED_FILL_RATE1:
+                guest->sched.fill_rate[0] = params[i].value.ui;
+                cret = writeToConfig(guest, "sched/fill-rate", "%u\n",
+                                     params[i].value.ui);
+                break;
+            case VSERVER_SCHED_INTERVAL1:
+                guest->sched.interval[0] = params[i].value.ui;
+                cret = writeToConfig(guest, "sched/interval", "%u\n",
+                                     params[i].value.ui);
+                break;
+            case VSERVER_SCHED_FILL_RATE2:
+                guest->sched.fill_rate[1] = params[i].value.ui;
+                cret = writeToConfig(guest, "sched/fill-rate2", "%u\n",
+                                     params[i].value.ui);
+                break;
+            case VSERVER_SCHED_INTERVAL2:
+                guest->sched.interval[1] = params[i].value.ui;
+                cret = writeToConfig(guest, "sched/interval2", "%u\n",
+                                     params[i].value.ui);
+                break;
+            case VSERVER_SCHED_TOKENS_MIN:
+                guest->sched.tokens_min = params[i].value.ui;
+                cret = writeToConfig(guest, "sched/tokens-min", "%u\n",
+                                     params[i].value.ui);
+                break;
+            case VSERVER_SCHED_TOKENS_MAX:
+                guest->sched.tokens_max = params[i].value.ui;
+                cret = writeToConfig(guest, "sched/tokens-max", "%u\n",
+                                     params[i].value.ui);
+                break;
+            case VSERVER_SCHED_PRIO_BIAS:
+                guest->sched.prio_bias = params[i].value.i;
+                cret = writeToConfig(guest, "sched/prio-bias", "%d\n",
+                                     params[i].value.i);
+                break;
+            case VSERVER_SCHED_IDLE_TIME:
+                guest->sched.idle_time = params[i].value.b;
+                cret = writeToConfig(guest, "sched/idle-time", "%b",
+                                     params[i].value.b);
+                break;
+            default:
+                vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
+                             "Unknown scheduler parameter");
+                return -1;
+        }
+        if (cret == -1) {
+            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
+                         "writeToConfig");
+            return -1;
+        }
+        guest->sched.set_mask |= sched_fields[j].id;
+    }
+
+    return 0;
+}
+
+
+/* FIXME: implement some real networking stuff */
+static int
+vserverNumOfNetworks(virConnectPtr conn)
+{
+    struct vserver_driver *driver = conn->privateData;
+
+    return 1;
+}
+
+static int
+vserverListNetworks(virConnectPtr conn, char **const names, int maxnames)
+{
+    struct vserver_driver *driver = conn->privateData;
+
+    if (maxnames < 1) {
+        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_ARG, "maxnames");
+        return -1;
+    }
+
+    if ((names[0] = strdup("Shared")) == NULL) {
+        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "network");
+        return -1;
+    }
+
+    return 1;
+}
+
+static int
+vserverNumOfDefinedNetworks(virConnectPtr conn)
+{
+    struct vserver_driver *driver = conn->privateData;
+
+    return 0;
+}
+
+static int
+vserverListDefinedNetworks(virConnectPtr conn, char **const names, int maxnames)
+{
+    return 0;
+}
+
+static virNetworkPtr
+vserverNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+    struct vserver_driver *driver = conn->privateData;
+
+    return virGetNetwork(conn, "Shared", uuid);
+}
+
+static virNetworkPtr
+vserverNetworkLookupByName(virConnectPtr conn, const char *name)
+{
+    struct vserver_driver *driver = conn->privateData;
+    unsigned char uuid[VIR_UUID_BUFLEN];
+
+    if (strcmp("Shared", name) != 0) {
+        vserverError(conn, NULL, NULL, VIR_ERR_NO_NETWORK, "No such network");
+        return NULL;
+    }
+
+    virUUIDGenerate(uuid);
+    return virGetNetwork(conn, "Shared", uuid);
+}
+
+
+virDriver vserverDriver = {
+    VIR_DRV_VSERVER,
+    "Linux-VServer",
+    LIBVIR_VERSION_NUMBER,
+    vserverOpen,
+    vserverClose,
+    NULL,   /* supports_feature */
+    vserverGetType,
+    vserverGetVersion,
+    vserverGetHostname,
+    vserverGetURI,
+    NULL,   /* getMaxVcpus */
+    vserverNodeGetInfo,
+    NULL,   /* getCapabilties */
+    vserverListDomains,
+    vserverNumOfDomains,
+    vserverDomainCreateLinux,
+    vserverDomainLookupByID,
+    vserverDomainLookupByUUID,
+    vserverDomainLookupByName,
+    NULL,   /* domainSuspend */
+    NULL,   /* domainResume */
+    vserverDomainShutdown,
+    vserverDomainReboot,
+    vserverDomainDestroy,
+    vserverDomainGetOSType,
+    vserverDomainGetMaxMemory,
+    vserverDomainSetMaxMemory,
+    NULL,   /* domainSetMemory */
+    vserverDomainGetInfo,
+    NULL,   /* domainSave */
+    NULL,   /* domainRestore */
+    NULL,   /* domainCoreDump */
+    NULL,   /* domainSetVcpus */
+    vserverDomainPinVcpu,
+    NULL,   /* domainGetVcpus */
+    NULL,   /* domainGetMaxVcpus */
+    vserverDomainDumpXML,
+    vserverListDefinedDomains,
+    vserverNumOfDefinedDomains,
+    vserverDomainCreate,
+    vserverDomainDefineXML,
+    vserverDomainUndefine,
+    NULL,   /* domainAttachDevice */
+    NULL,   /* domainDetachDevice */
+    vserverDomainGetAutostart,
+    vserverDomainSetAutostart,
+    vserverDomainGetSchedulerType,
+    vserverDomainGetSchedulerParams,
+    vserverDomainSetSchedulerParams,
+    NULL,   /* domainMigratePrepare  */
+    NULL,   /* domainMigratePerform */
+    NULL,   /* domainMigrateFinish */
+    NULL,   /* domainBlockStats */
+    NULL,   /* domainInterfaceStats */
+    NULL,   /* nodeGetCellsFreeMemory */
+    NULL,   /* getFreeMemory */
+};
+
+virNetworkDriver vserverNetworkDriver = {
+    "Linux-VServer",
+    vserverOpen,
+    vserverClose,
+    vserverNumOfNetworks,
+    vserverListNetworks,
+    vserverNumOfDefinedNetworks,
+    vserverListDefinedNetworks,
+    vserverNetworkLookupByUUID,
+    vserverNetworkLookupByName,
+    NULL,   /* networkCreateXML */
+    NULL,   /* networkDefineXML */
+    NULL,   /* networkUndefine */
+    NULL,   /* networkCreate */
+    NULL,   /* networkDestroy */
+    NULL,   /* networkDumpXML */
+    NULL,   /* networkGetBridgeName */
+    NULL,   /* networkGetAutostart */
+    NULL,   /* networkSetAutostart */
+};
+
+int vserverRegister(void)
+{
+    if (virRegisterDriver(&vserverDriver) < 0)
+        return -1;
+    if (virRegisterNetworkDriver(&vserverNetworkDriver) < 0)
+        return -1;
+    return 0;
+}
+
+#endif
diff -Nurp libvirt-0.3.3.orig/src/vserver_driver.h libvirt-0.3.3.vserver/src/vserver_driver.h
--- libvirt-0.3.3.orig/src/vserver_driver.h	1970-01-01 01:00:00.000000000 +0100
+++ libvirt-0.3.3.vserver/src/vserver_driver.h	2007-10-29 23:26:06.000000000 +0100
@@ -0,0 +1,96 @@
+/*
+ * Core driver for managing Linux-VServer guests
+ *
+ * Copyright (C) 2007 Daniel Hokka Zakrisson
+ *
+ * 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
+ *
+ * Author: Daniel Hokka Zakrisson <daniel@xxxxxxxxx>
+ */
+
+#ifdef WITH_VSERVER
+
+#define VSERVER_NAME_MAX		64
+#define VSERVER_HOSTNAME_MAX	255
+
+enum vserver_initstyle {
+	VSERVER_INIT_NONE,
+	VSERVER_INIT_SYSV,
+	VSERVER_INIT_PLAIN,
+	VSERVER_INIT_GENTOO,
+	VSERVER_INIT_MINIT,
+};
+
+enum vserver_scheduler_setting {
+	VSERVER_SCHED_FILL_RATE1	= (1 << 0),
+	VSERVER_SCHED_INTERVAL1		= (1 << 1),
+	VSERVER_SCHED_FILL_RATE2	= (1 << 2),
+	VSERVER_SCHED_INTERVAL2		= (1 << 3),
+	VSERVER_SCHED_TOKENS_MIN	= (1 << 5),
+	VSERVER_SCHED_TOKENS_MAX	= (1 << 6),
+	VSERVER_SCHED_PRIO_BIAS		= (1 << 8),
+	VSERVER_SCHED_IDLE_TIME		= (1 << 9),
+};
+
+struct vserver_scheduler {
+	uint32_t set_mask; /* bits of vserver_scheduler_setting */
+	uint32_t fill_rate[2];
+	uint32_t interval[2];
+	uint32_t tokens_min;
+	uint32_t tokens_max;
+	int32_t prio_bias;
+	char idle_time;
+};
+
+struct vserver_guest {
+	int xid;
+	char name[VSERVER_NAME_MAX];
+	unsigned char uuid[VIR_UUID_BUFLEN];
+	char path[PATH_MAX];
+
+	char hostname[VSERVER_HOSTNAME_MAX];
+
+	struct vserver_scheduler sched;
+	unsigned long rss_hard;
+
+	char autostart;
+	enum vserver_initstyle initstyle;
+
+	int status;
+
+	struct vserver_guest *next;
+};
+
+struct vserver_network {
+	char name[VSERVER_NAME_MAX];
+	unsigned char uuid[VIR_UUID_BUFLEN];
+
+	struct vserver_network *next;
+};
+
+struct vserver_driver {
+	struct vserver_guest *guests;
+	struct vserver_network *networks;
+	unsigned int active_guests;
+	unsigned int inactive_guests;
+	unsigned int active_networks;
+	unsigned int inactive_networks;
+	unsigned int initialized : 1;
+};
+
+
+extern int vserverRegister(void);
+
+#endif
--
Libvir-list mailing list
Libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]