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