This patch:* Adds virConnectGetCapabilities which returns an XML description of the capabilities of the driver or hypervisor under this connection (see below for more about the XML format).
* Adds virsh capabilities command. * Checks the Python binding works. Caveats:* Xen implementation (in xen_internal.c) is not tested because I don't have a working Xen machine right now. QEMU, test and remote work however.
Example:
$ virsh -c test:///default capabilities | tidy -xml -i -q
<capabilities>
<domain>
<type>test</type>
</domain>
<host_features></host_features>
<guest_architectures>
<guest_architecture>
<model>i686</model>
<bits>32</bits>
<guest_features>
<accelerated />
<pae />
</guest_features>
</guest_architecture>
</guest_architectures>
</capabilities>
$ virsh -c qemu:///session capabilities | tidy -xml -i -q
<capabilities>
<domain>
<type>qemu</type>
</domain>
<guest_architectures>
<guest_architecture>
<model>i686</model>
<bits>32</bits>
<features>
<emulated />
</features>
</guest_architecture>
<guest_architecture>
<model>x86_64</model>
<bits>64</bits>
<features>
<emulated />
</features>
</guest_architecture>
[... other archs deleted ...]
</guest_architectures>
</capabilities>
XML format:
The <capabilities> node contains information about the host and a list
of supported architectures for guests. About the host we return:
<domain>
<type> The default type acceptable when creating a domain.
<host_features>
<hvm> Does the host CPU support HVM?
<type> Type of HVM (eg. "vmx")
<bios_setting> "enabled" or "disabled"
About the guest architectures we can return:
<guest_architecture>
<model> The (virtualised) CPU
<bits> Bits
<domain>
<type> If different from the default type (eg. for kqemu)
<features>
<hvm> Full virt guest?
<accelerated> Accelerated (eg. Xen or kqemu)
<emulated> Emulated (eg. qemu or bochs)
(and a few other esoteric flags here)
Rich.
--
Emerging Technologies, Red Hat http://et.redhat.com/~rjones/
64 Baker Street, London, W1U 7DF Mobile: +44 7866 314 421
"[Negative numbers] darken the very whole doctrines of the equations
and make dark of the things which are in their nature excessively
obvious and simple" (Francis Maseres FRS, mathematician, 1759)
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/configure.in libvirt-caps-tmp/configure.in
--- libvirt-cvs/configure.in 2007-03-06 12:00:03.000000000 +0000
+++ libvirt-caps-tmp/configure.in 2007-03-09 13:08:57.000000000 +0000
@@ -43,6 +43,8 @@
AC_PATH_PROG(XMLLINT, xmllint, /usr/bin/xmllint)
AC_PATH_PROG(XSLTPROC, xsltproc, /usr/bin/xsltproc)
+dnl Availability of various common functions.
+AC_CHECK_FUNCS([regexec])
dnl Make sure we have an ANSI compiler
AM_C_PROTOTYPES
@@ -50,6 +52,8 @@
AM_PROG_LIBTOOL
+AM_PROG_CC_C_O
+
LIBVIRT_COMPILE_WARNINGS(maximum)
dnl Specific dir for HTML output ?
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/.cvsignore libvirt-caps-tmp/.cvsignore
--- libvirt-cvs/.cvsignore 2007-02-16 17:06:38.000000000 +0000
+++ libvirt-caps-tmp/.cvsignore 2007-03-09 13:08:57.000000000 +0000
@@ -1,3 +1,4 @@
+.git
Makefile
aclocal.m4
autom4te.cache
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/include/libvirt/libvirt.h.in libvirt-caps-tmp/include/libvirt/libvirt.h.in
--- libvirt-cvs/include/libvirt/libvirt.h.in 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/include/libvirt/libvirt.h.in 2007-03-09 13:08:57.000000000 +0000
@@ -231,10 +231,15 @@
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
unsigned long *hvVer);
-int virConnectGetMaxVcpus (virConnectPtr conn,
+/*
+ * Capabilities of the connection / driver.
+ */
+
+int virConnectGetMaxVcpus (virConnectPtr conn,
const char *type);
int virNodeGetInfo (virConnectPtr conn,
virNodeInfoPtr info);
+char * virConnectGetCapabilities (virConnectPtr conn);
/*
* Gather list of running domains
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/include/libvirt/virterror.h libvirt-caps-tmp/include/libvirt/virterror.h
--- libvirt-cvs/include/libvirt/virterror.h 2007-02-14 15:40:54.000000000 +0000
+++ libvirt-caps-tmp/include/libvirt/virterror.h 2007-03-09 13:08:57.000000000 +0000
@@ -119,6 +119,7 @@
VIR_ERR_XML_DETAIL, /* detail of an XML error */
VIR_ERR_INVALID_NETWORK, /* invalid network object */
VIR_ERR_NETWORK_EXIST, /* the network already exist */
+ VIR_ERR_SYSTEM_ERROR, /* general system call failure */
} virErrorNumber;
/**
@@ -133,7 +134,7 @@
/*
* Errors can be handled as asynchronous callbacks or after the routine
* failed. They can also be handled globally at the library level, or
- * at the connection level (which then has priority
+ * at the connection level (which then has priority).
*/
virErrorPtr virGetLastError (void);
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/proxy/libvirt_proxy.c libvirt-caps-tmp/proxy/libvirt_proxy.c
--- libvirt-cvs/proxy/libvirt_proxy.c 2007-03-02 11:05:16.000000000 +0000
+++ libvirt-caps-tmp/proxy/libvirt_proxy.c 2007-03-09 13:08:57.000000000 +0000
@@ -786,3 +786,17 @@
proxyCloseUnixSocket();
exit(0);
}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/proxy/Makefile.am libvirt-caps-tmp/proxy/Makefile.am
--- libvirt-cvs/proxy/Makefile.am 2007-03-02 11:05:16.000000000 +0000
+++ libvirt-caps-tmp/proxy/Makefile.am 2007-03-09 13:08:57.000000000 +0000
@@ -10,7 +10,8 @@
libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xend_internal.c \
@top_srcdir@/src/xen_internal.c @top_srcdir@/src/virterror.c \
@top_srcdir@/src/sexpr.c @top_srcdir@/src/xml.c \
- @top_srcdir@/src/xs_internal.c
+ @top_srcdir@/src/xs_internal.c \
+ @top_srcdir@/src/lib.c @top_srcdir@/src/lib.h
libvirt_proxy_LDFLAGS =
libvirt_proxy_DEPENDENCIES =
libvirt_proxy_LDADD =
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/conf.c libvirt-caps-tmp/qemud/conf.c
--- libvirt-cvs/qemud/conf.c 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/qemud/conf.c 2007-03-09 13:08:57.000000000 +0000
@@ -122,8 +122,13 @@
return 0;
}
+/* NB: I've stored "bits" here but in future it may be that the
+ * qemu-system-* binaries are able to emulate machines with different
+ * register sizes. That doesn't happen at present though.
+ */
struct qemu_arch_info {
const char *arch;
+ int bits;
const char **machines;
const char *binary;
};
@@ -145,12 +150,12 @@
/* The archicture tables for supported QEMU archs */
static struct qemu_arch_info archs[] = {
- { "i686", arch_info_x86_machines, "qemu" },
- { "x86_64", arch_info_x86_machines, "qemu-system-x86_64" },
- { "mips", arch_info_mips_machines, "qemu-system-mips" },
- { "mipsel", arch_info_mips_machines, "qemu-system-mipsel" },
- { "sparc", arch_info_sparc_machines, "qemu-system-sparc" },
- { "ppc", arch_info_ppc_machines, "qemu-system-ppc" },
+ { "i686", 32, arch_info_x86_machines, "qemu" },
+ { "x86_64", 64, arch_info_x86_machines, "qemu-system-x86_64" },
+ { "mips", 32, arch_info_mips_machines, "qemu-system-mips" },
+ { "mipsel", 32, arch_info_mips_machines, "qemu-system-mipsel" },
+ { "sparc", 32, arch_info_sparc_machines, "qemu-system-sparc" },
+ { "ppc", 32, arch_info_ppc_machines, "qemu-system-ppc" },
};
/* Return the default architecture if none is explicitly requested*/
@@ -211,6 +216,24 @@
return path;
}
+/* Return the list of architectures. Useful for getCapabilities. */
+int
+qemudGetGuestArchitectures (struct qemud_guest_arch **archs_rtn)
+{
+ const int n = sizeof archs / sizeof archs[0];
+ int i;
+
+ *archs_rtn = malloc (sizeof (struct qemud_guest_arch) * n);
+ if (!*archs_rtn) return -1;
+
+ for (i = 0; i < n; ++i) {
+ (*archs_rtn)[i].model = archs[i].arch;
+ (*archs_rtn)[i].bits = archs[i].bits;
+ }
+
+ return n;
+}
+
static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) {
pid_t child;
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/conf.h libvirt-caps-tmp/qemud/conf.h
--- libvirt-cvs/qemud/conf.h 2007-02-23 17:15:18.000000000 +0000
+++ libvirt-caps-tmp/qemud/conf.h 2007-03-09 13:08:57.000000000 +0000
@@ -78,6 +78,13 @@
struct qemud_network *network,
struct qemud_network_def *def);
+struct qemud_guest_arch {
+ const char *model;
+ int bits;
+};
+
+int qemudGetGuestArchitectures (struct qemud_guest_arch **archs);
+
#endif
/*
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/dispatch.c libvirt-caps-tmp/qemud/dispatch.c
--- libvirt-cvs/qemud/dispatch.c 2007-02-23 09:03:25.000000000 +0000
+++ libvirt-caps-tmp/qemud/dispatch.c 2007-03-09 13:08:57.000000000 +0000
@@ -23,6 +23,7 @@
#include <config.h>
+#include <unistd.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
@@ -33,6 +34,8 @@
#include "internal.h"
#include "driver.h"
#include "dispatch.h"
+#include "conf.h"
+#include "lib.h"
static int qemudDispatchFailure(struct qemud_server *server ATTRIBUTE_UNUSED,
@@ -100,6 +103,149 @@
return 0;
}
+static int
+qemudDispatchGetCapabilities (struct qemud_server *server,
+ struct qemud_client *client,
+ struct qemud_packet *in,
+ struct qemud_packet *out)
+{
+ char *xml, *xml_guest_archs;
+ int len;
+ struct utsname utsname;
+ struct qemud_guest_arch *guest_archs;
+ int nr_guest_archs, i;
+ int have_kqemu = 0;
+ int have_kvm = 0;
+
+ if (in->header.dataSize != 0) return -1;
+
+ have_kqemu = access ("/dev/kqemu", F_OK) == 0;
+ have_kvm = access ("/dev/kvm", F_OK) == 0;
+
+ /* Construct the XML. */
+ /* First the guest architectures for basic <domain type='qemu'>,
+ * all emulated (even x86 on x86).
+ */
+ xml_guest_archs = NULL;
+ nr_guest_archs = qemudGetGuestArchitectures (&guest_archs);
+ for (i = 0; i < nr_guest_archs; ++i) {
+ char bits[16];
+ snprintf (bits, sizeof bits, "%d", guest_archs[i].bits);
+
+ char *old_xml = xml_guest_archs;
+ xml_guest_archs = strjoin
+ ("\n",
+ xml_guest_archs,
+ "<guest_architecture>",
+ "<model>", guest_archs[i].model, "</model>",
+ "<bits>", bits, "</bits>",
+ "<features>",
+ "<emulated/>",
+ "</features>",
+ "</guest_architecture>",
+ NULL);
+ free (old_xml);
+ if (!xml_guest_archs) {
+ qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+ qemudDispatchFailure (server, client, out);
+ free (guest_archs);
+ free (xml_guest_archs);
+ return 0;
+ }
+ }
+ free (guest_archs);
+
+ /* Really, this never fails - look at the man-page. */
+ uname (&utsname);
+
+ /* 32 or 64 bit host? */
+ const char *bits = strstr (utsname.machine, "64") != NULL ? "64" : "32";
+
+ /* If we have kqemu, then there is a <domain type='kqemu'>,
+ * accelerated, but the model is limited to host == guest.
+ */
+ if (have_kqemu) {
+ char *old_xml = xml_guest_archs;
+ xml_guest_archs = strjoin
+ ("\n",
+ xml_guest_archs,
+ "<guest_architecture>",
+ "<domain><type>kqemu</type></domain>",
+ "<model>", utsname.machine, "</model>",
+ "<bits>", bits, "</bits>",
+ "<features>",
+ "<accelerated/>",
+ /* XXX There is no mention of PAE in the qemu docs. */
+ "</features>",
+ "</guest_architecture>",
+ NULL);
+ free (old_xml);
+ if (!xml_guest_archs) {
+ qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+ qemudDispatchFailure (server, client, out);
+ free (xml_guest_archs);
+ return 0;
+ }
+ }
+
+ /* If we have kvm, then there is a <domain type='kvm'>,
+ * accelerated, HVM, but the model is limited to host == guest.
+ */
+ if (have_kvm) {
+ char *old_xml = xml_guest_archs;
+ xml_guest_archs = strjoin
+ ("\n",
+ xml_guest_archs,
+ "<guest_architecture>",
+ "<domain><type>kvm</type></domain>",
+ "<model>", utsname.machine, "</model>",
+ "<bits>", bits, "</bits>",
+ "<features>",
+ "<hvm/>",
+ "<accelerated/>",
+ /* XXX Does KVM support PAE inside the guest? */
+ "</features>",
+ "</guest_architecture>",
+ NULL);
+ free (old_xml);
+ if (!xml_guest_archs) {
+ qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+ qemudDispatchFailure (server, client, out);
+ free (xml_guest_archs);
+ return 0;
+ }
+ }
+
+ /* Finally build the full capabilities. */
+ xml = strjoin
+ ("\n",
+ "<capabilities>",
+ "<domain><type>qemu</type></domain>",
+ "<guest_architectures>",
+ xml_guest_archs,
+ "</guest_architectures>",
+ "</capabilities>",
+ NULL);
+ free (xml_guest_archs);
+ if (!xml) {
+ qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+ qemudDispatchFailure (server, client, out);
+ return 0;
+ }
+
+ /* Copy the XML into the outgoing packet, assuming it's not too large. */
+ len = strlen (xml);
+ if (len > QEMUD_MAX_XML_LEN) {
+ qemudReportError (server, VIR_ERR_XML_ERROR, NULL);
+ qemudDispatchFailure (server, client, out);
+ return -1;
+ }
+ out->header.type = QEMUD_PKT_GET_CAPABILITIES;
+ out->header.dataSize = len;
+ strcpy (out->data.getCapabilitiesReply.xml, xml);
+ return 0;
+}
+
static int qemudDispatchListDomains(struct qemud_server *server, struct qemud_client *client,
struct qemud_packet *in, struct qemud_packet *out) {
int i, ndomains, domains[QEMUD_MAX_NUM_DOMAINS];
@@ -854,6 +1000,7 @@
qemudDispatchDomainSetAutostart,
qemudDispatchNetworkGetAutostart,
qemudDispatchNetworkSetAutostart,
+ qemudDispatchGetCapabilities,
};
clientFunc funcsTransmitRO[QEMUD_PKT_MAX] = {
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/Makefile.am libvirt-caps-tmp/qemud/Makefile.am
--- libvirt-cvs/qemud/Makefile.am 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/qemud/Makefile.am 2007-03-09 13:08:57.000000000 +0000
@@ -10,10 +10,12 @@
conf.c conf.h \
bridge.c bridge.h \
iptables.c iptables.h \
- uuid.c uuid.h
+ uuid.c uuid.h \
+ @top_srcdir@/src/lib.c @top_srcdir@/src/lib.h
#-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=1 -D_POSIX_C_SOURCE=199506L
libvirt_qemud_CFLAGS = \
- -I$(top_srcdir)/include -I$(top_builddir)/include $(LIBXML_CFLAGS) \
+ -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src \
+ $(LIBXML_CFLAGS) \
$(WARN_CFLAGS) -DLOCAL_STATE_DIR="\"$(localstatedir)\"" \
-DSYSCONF_DIR="\"$(sysconfdir)\""
libvirt_qemud_LDFLAGS = $(LIBXML_LIBS) $(SYSFS_LIBS)
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/qemud/protocol.h libvirt-caps-tmp/qemud/protocol.h
--- libvirt-cvs/qemud/protocol.h 2007-02-23 09:03:25.000000000 +0000
+++ libvirt-caps-tmp/qemud/protocol.h 2007-03-09 13:08:57.000000000 +0000
@@ -68,6 +68,7 @@
QEMUD_PKT_DOMAIN_SET_AUTOSTART,
QEMUD_PKT_NETWORK_GET_AUTOSTART,
QEMUD_PKT_NETWORK_SET_AUTOSTART,
+ QEMUD_PKT_GET_CAPABILITIES,
QEMUD_PKT_MAX,
} qemud_packet_type;
@@ -125,6 +126,9 @@
uint32_t threads;
} getNodeInfoReply;
struct {
+ char xml[QEMUD_MAX_XML_LEN];
+ } getCapabilitiesReply;
+ struct {
int32_t numDomains;
int32_t domains[QEMUD_MAX_NUM_DOMAINS];
} listDomainsReply;
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/driver.h libvirt-caps-tmp/src/driver.h
--- libvirt-cvs/src/driver.h 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/src/driver.h 2007-03-09 13:08:57.000000000 +0000
@@ -48,6 +48,8 @@
typedef int
(*virDrvNodeGetInfo) (virConnectPtr conn,
virNodeInfoPtr info);
+typedef char *
+ (*virDrvGetCapabilities) (virConnectPtr conn);
typedef int
(*virDrvListDomains) (virConnectPtr conn,
int *ids,
@@ -164,6 +166,7 @@
virDrvGetVersion version;
virDrvGetMaxVcpus getMaxVcpus;
virDrvNodeGetInfo nodeGetInfo;
+ virDrvGetCapabilities getCapabilities;
virDrvListDomains listDomains;
virDrvNumOfDomains numOfDomains;
virDrvDomainCreateLinux domainCreateLinux;
@@ -283,3 +286,17 @@
}
#endif /* __cplusplus */
#endif /* __VIR_DRIVER_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/internal.h libvirt-caps-tmp/src/internal.h
--- libvirt-cvs/src/internal.h 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/src/internal.h 2007-03-09 13:08:57.000000000 +0000
@@ -239,3 +239,17 @@
}
#endif /* __cplusplus */
#endif /* __VIR_INTERNAL_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/lib.c libvirt-caps-tmp/src/lib.c
--- libvirt-cvs/src/lib.c 1970-01-01 01:00:00.000000000 +0100
+++ libvirt-caps-tmp/src/lib.c 2007-03-09 13:08:57.000000000 +0000
@@ -0,0 +1,84 @@
+/*
+ * lib.c: some private library functions shared between libvirt source
+ * files
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Note: The linker script ensures that these functions are not exported
+ * from libvirt, even though they are not static.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "lib.h"
+
+/**
+ * strjoin:
+ * @sep: Separator string
+ * @str1: First string to join
+ *
+ * Join a list of strings, placing @sep between each
+ * string. The list of strings begins at @str1 and finishes
+ * with a NULL.
+ *
+ * If @str1 is NULL, it is treated as the empty string.
+ *
+ * Returns the joined string, or NULL if memory could not be
+ * allocated.
+ */
+char *
+strjoin (const char *sep, const char *str1, ...)
+{
+ int len, seplen;
+ char *str, *rtn, *tmp;
+ va_list v1, v2;
+
+ va_start (v1, str1);
+ va_copy (v2, v1);
+
+ /* Find out how much memory to allocate. */
+ len = str1 ? strlen (str1) : 0;
+ seplen = strlen (sep);
+ while ((str = va_arg (v1, char *)) != 0)
+ len += seplen + strlen (str);
+ len++; /* for the \0-terminator */
+
+ va_end (v1);
+
+ /* Copy the strings. */
+ tmp = rtn = malloc (len);
+ if (!rtn) goto done;
+
+ if (str1) {
+ strcpy (tmp, str1);
+ tmp += strlen (str1);
+ }
+ while ((str = va_arg (v2, char *)) != 0) {
+ strcpy (tmp, sep);
+ tmp += seplen;
+ strcpy (tmp, str);
+ tmp += strlen (str);
+ }
+
+ done:
+ va_end (v2);
+ return rtn;
+}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/lib.h libvirt-caps-tmp/src/lib.h
--- libvirt-cvs/src/lib.h 1970-01-01 01:00:00.000000000 +0100
+++ libvirt-caps-tmp/src/lib.h 2007-03-09 13:08:57.000000000 +0000
@@ -0,0 +1,29 @@
+/*
+ * lib.c: some private library functions shared between libvirt source
+ * files
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ */
+
+#ifndef __VIR_LIB_H__
+#define __VIR_LIB_H__
+
+char *strjoin (const char *sep, const char *str1, ...);
+
+#endif /* __VIR_LIB_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/libvirt.c libvirt-caps-tmp/src/libvirt.c
--- libvirt-cvs/src/libvirt.c 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/src/libvirt.c 2007-03-09 13:08:57.000000000 +0000
@@ -1701,6 +1701,37 @@
return(0);
}
+/**
+ * virConnectGetCapabilities:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Return capabilities of the hypervisor / driver.
+ *
+ * Returns NULL in case of error, or a pointer to an opaque
+ * virCapabilities structure (virCapabilitiesPtr).
+ *
+ * The client must free the returned string after use.
+ */
+char *
+virConnectGetCapabilities (virConnectPtr conn)
+{
+ int i;
+
+ if (!VIR_IS_CONNECT (conn)) {
+ virLibConnError (conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return NULL;
+ }
+
+ for (i = 0; i < conn->nb_drivers; i++) {
+ if (conn->drivers[i] && conn->drivers[i]->getCapabilities) {
+ return conn->drivers[i]->getCapabilities (conn);
+ }
+ }
+
+ virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__);
+ return NULL;
+}
+
/************************************************************************
* *
* Handling of defined but not running domains *
@@ -2961,3 +2992,17 @@
virLibConnError(network->conn, VIR_ERR_CALL_FAILED, __FUNCTION__);
return (-1);
}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/libvirt_sym.version libvirt-caps-tmp/src/libvirt_sym.version
--- libvirt-cvs/src/libvirt_sym.version 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/src/libvirt_sym.version 2007-03-09 13:08:57.000000000 +0000
@@ -53,6 +53,7 @@
virConnResetLastError;
virDefaultErrorFunc;
virNodeGetInfo;
+ virConnectGetCapabilities;
virDomainSetVcpus;
virDomainPinVcpu;
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/Makefile.am libvirt-caps-tmp/src/Makefile.am
--- libvirt-cvs/src/Makefile.am 2007-03-02 11:05:16.000000000 +0000
+++ libvirt-caps-tmp/src/Makefile.am 2007-03-09 13:08:57.000000000 +0000
@@ -18,6 +18,7 @@
libvirt_la_CFLAGS = $(COVERAGE_CFLAGS)
libvirt_la_SOURCES = \
libvirt.c internal.h \
+ lib.c lib.h \
hash.c hash.h \
test.c test.h \
xml.c xml.h \
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/proxy_internal.c libvirt-caps-tmp/src/proxy_internal.c
--- libvirt-cvs/src/proxy_internal.c 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/src/proxy_internal.c 2007-03-09 13:08:57.000000000 +0000
@@ -52,6 +52,7 @@
xenProxyGetVersion, /* version */
NULL, /* getMaxVcpus */
xenProxyNodeGetInfo, /* nodeGetInfo */
+ NULL, /* getCapabilities */
xenProxyListDomains, /* listDomains */
xenProxyNumOfDomains, /* numOfDomains */
NULL, /* domainCreateLinux */
@@ -1044,3 +1045,17 @@
return(ostype);
}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/proxy_internal.h libvirt-caps-tmp/src/proxy_internal.h
--- libvirt-cvs/src/proxy_internal.h 2006-11-07 16:28:16.000000000 +0000
+++ libvirt-caps-tmp/src/proxy_internal.h 2007-03-09 13:08:57.000000000 +0000
@@ -78,8 +78,8 @@
union {
char str[4080]; /* extra char array */
int arg[1020]; /* extra int array */
- virDomainInfo dinfo; /* domain information */
- virNodeInfo ninfo; /* node information */
+ virDomainInfo dinfo; /* domain information */
+ virNodeInfo ninfo; /* node information */
} extra;
};
typedef struct _virProxyFullPacket virProxyFullPacket;
@@ -93,3 +93,17 @@
}
#endif /* __cplusplus */
#endif /* __LIBVIR_PROXY_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/qemu_internal.c libvirt-caps-tmp/src/qemu_internal.c
--- libvirt-cvs/src/qemu_internal.c 2007-03-09 12:23:50.000000000 +0000
+++ libvirt-caps-tmp/src/qemu_internal.c 2007-03-09 13:08:57.000000000 +0000
@@ -451,6 +451,31 @@
}
+static char *
+qemuGetCapabilities (virConnectPtr conn)
+{
+ struct qemud_packet req, reply;
+ char *xml;
+
+ /* Punt the request across to the daemon, because the daemon
+ * has tables describing available architectures.
+ */
+ req.header.type = QEMUD_PKT_GET_CAPABILITIES;
+ req.header.dataSize = 0;
+
+ if (qemuProcessRequest(conn, NULL, &req, &reply) < 0) {
+ return NULL;
+ }
+
+ xml = strdup (reply.data.getCapabilitiesReply.xml);
+ if (!xml) {
+ qemuError (conn, NULL, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ return xml;
+}
+
static int qemuNumOfDomains(virConnectPtr conn) {
struct qemud_packet req, reply;
@@ -1171,6 +1196,7 @@
qemuGetVersion, /* version */
NULL, /* getMaxVcpus */
qemuNodeGetInfo, /* nodeGetInfo */
+ qemuGetCapabilities, /* getCapabilities */
qemuListDomains, /* listDomains */
qemuNumOfDomains, /* numOfDomains */
qemuDomainCreateLinux, /* domainCreateLinux */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/test.c libvirt-caps-tmp/src/test.c
--- libvirt-cvs/src/test.c 2007-03-09 12:23:51.000000000 +0000
+++ libvirt-caps-tmp/src/test.c 2007-03-09 13:08:57.000000000 +0000
@@ -43,6 +43,7 @@
unsigned long *hvVer);
int testNodeGetInfo(virConnectPtr conn,
virNodeInfoPtr info);
+char *testGetCapabilities (virConnectPtr conn);
int testNumOfDomains(virConnectPtr conn);
int testListDomains(virConnectPtr conn,
int *ids,
@@ -96,6 +97,7 @@
testGetVersion, /* version */
NULL, /* getMaxVcpus */
testNodeGetInfo, /* nodeGetInfo */
+ testGetCapabilities, /* getCapabilities */
testListDomains, /* listDomains */
testNumOfDomains, /* numOfDomains */
testDomainCreateLinux, /* domainCreateLinux */
@@ -178,8 +180,11 @@
static testNode *node = NULL;
static int nextDomID = 1;
+#define TEST_MODEL "i686"
+#define TEST_MODEL_BITS "32"
+
static const virNodeInfo defaultNodeInfo = {
- "i686",
+ TEST_MODEL,
1024*1024*3, /* 3 GB */
16,
1400,
@@ -808,6 +813,35 @@
return (0);
}
+char *
+testGetCapabilities (virConnectPtr conn)
+{
+ static char caps[] = "\
+<capabilities>\n\
+ <domain><type>test</type></domain>\n\
+ <host_features>\n\
+ </host_features>\n\
+ <guest_architectures>\n\
+ <guest_architecture>\n\
+ <model>" TEST_MODEL "</model>\n\
+ <bits>" TEST_MODEL_BITS "</bits>\n\
+ <guest_features>\n\
+ <accelerated/>\n\
+ <pae/>\n\
+ </guest_features>\n\
+ </guest_architecture>\n\
+ </guest_architectures>\n\
+</capabilities>\n\
+";
+
+ char *caps_copy = strdup (caps);
+ if (!caps_copy) {
+ testError(conn, NULL, VIR_ERR_NO_MEMORY, __FUNCTION__);
+ return NULL;
+ }
+ return caps_copy;
+}
+
int testNumOfDomains(virConnectPtr conn)
{
int numActive = 0, i;
@@ -1377,6 +1411,11 @@
}
/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
* Local variables:
* indent-tabs-mode: nil
* c-indent-level: 4
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/virsh.c libvirt-caps-tmp/src/virsh.c
--- libvirt-cvs/src/virsh.c 2007-03-09 14:39:48.000000000 +0000
+++ libvirt-caps-tmp/src/virsh.c 2007-03-09 14:39:59.000000000 +0000
@@ -1545,6 +1545,33 @@
}
/*
+ * "capabilities" command
+ */
+static vshCmdInfo info_capabilities[] = {
+ {"syntax", "capabilities"},
+ {"help", gettext_noop("capabilities")},
+ {"desc", gettext_noop("Returns capabilities of hypervisor/driver.")},
+ {NULL, NULL}
+};
+
+static int
+cmdCapabilities (vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char *caps;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if ((caps = virConnectGetCapabilities (ctl->conn)) == NULL) {
+ vshError(ctl, FALSE, _("failed to get capabilities"));
+ return FALSE;
+ }
+ vshPrint (ctl, "%s\n", caps);
+
+ return TRUE;
+}
+
+/*
* "dumpxml" command
*/
static vshCmdInfo info_dumpxml[] = {
@@ -2375,6 +2402,7 @@
*/
static vshCmdDef commands[] = {
{"autostart", cmdAutostart, opts_autostart, info_autostart},
+ {"capabilities", cmdCapabilities, NULL, info_capabilities},
{"connect", cmdConnect, opts_connect, info_connect},
{"console", cmdConsole, opts_console, info_console},
{"create", cmdCreate, opts_create, info_create},
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/virterror.c libvirt-caps-tmp/src/virterror.c
--- libvirt-cvs/src/virterror.c 2007-02-14 15:40:54.000000000 +0000
+++ libvirt-caps-tmp/src/virterror.c 2007-03-09 13:10:41.000000000 +0000
@@ -604,6 +604,26 @@
else
errmsg = _("network %s exists already");
break;
+ case VIR_ERR_SYSTEM_ERROR:
+ if (info == NULL)
+ errmsg = _("system call error");
+ else
+ errmsg = "%s";
+ break;
}
return (errmsg);
}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xend_internal.c libvirt-caps-tmp/src/xend_internal.c
--- libvirt-cvs/src/xend_internal.c 2007-03-09 12:23:51.000000000 +0000
+++ libvirt-caps-tmp/src/xend_internal.c 2007-03-09 13:12:25.000000000 +0000
@@ -68,6 +68,7 @@
xenDaemonGetVersion, /* version */
NULL, /* getMaxVcpus */
xenDaemonNodeGetInfo, /* nodeGetInfo */
+ NULL, /* getCapabilities */
xenDaemonListDomains, /* listDomains */
xenDaemonNumOfDomains, /* numOfDomains */
xenDaemonCreateLinux, /* domainCreateLinux */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xen_internal.c libvirt-caps-tmp/src/xen_internal.c
--- libvirt-cvs/src/xen_internal.c 2007-03-09 12:23:51.000000000 +0000
+++ libvirt-caps-tmp/src/xen_internal.c 2007-03-09 13:12:25.000000000 +0000
@@ -20,6 +20,8 @@
#include <sys/ioctl.h>
#include <limits.h>
#include <stdint.h>
+#include <regex.h>
+#include <errno.h>
/* required for dom0_getdomaininfo_t */
#include <xen/dom0_ops.h>
@@ -30,6 +32,8 @@
/* required for shutdown flags */
#include <xen/sched.h>
+#include "lib.h"
+
/* #define DEBUG */
/*
* so far there is 2 versions of the structures usable for doing
@@ -70,6 +74,15 @@
static int dom_interface_version = -1;
static int kb_per_pages = 0;
+/* Regular expressions used by xenHypervisorGetCapabilities, and
+ * compiled once by xenHypervisorInit. Note that these are POSIX.2
+ * extended regular expressions (regex(7)).
+ */
+static const char *flags_hvm_re = "^flags[[:blank:]]+:.* (vmx|svm)[[:space:]]";
+static regex_t flags_hvm_rec;
+static const char *xen_cap_re = "(xen|hvm)-[[:digit:]]+\\.[[:digit:]]+-(x86_32|x86_64|ia64)(p|be)?";
+static regex_t xen_cap_rec;
+
/*
* The content of the structures for a getdomaininfolist system hypercall
*/
@@ -430,6 +443,7 @@
xenHypervisorGetVersion, /* version */
xenHypervisorNumOfMaxVcpus, /* getMaxVcpus */
NULL, /* nodeGetInfo */
+ xenHypervisorGetCapabilities, /* getCapabilities */
xenHypervisorListDomains, /* listDomains */
xenHypervisorNumOfDomains, /* numOfDomains */
NULL, /* domainCreateLinux */
@@ -468,9 +482,9 @@
/**
* virXenError:
- * @conn: the connection if available
* @error: the error number
* @info: extra information string
+ * @value: extra information number
*
* Handle an error at the xend daemon interface
*/
@@ -484,7 +498,31 @@
errmsg = __virErrorMsg(error, info);
__virRaiseError(NULL, NULL, NULL, VIR_FROM_XEN, error, VIR_ERR_ERROR,
- errmsg, info, NULL, value, 0, errmsg, info, value);
+ errmsg, info, NULL, value, 0, errmsg, info);
+}
+
+/**
+ * virXenPerror:
+ * @conn: the connection (if available)
+ * @msg: name of system call or file (as in perror(3))
+ *
+ * Raise error from a failed system call, using errno as the source.
+ */
+static void
+virXenPerror (virConnectPtr conn, const char *msg)
+{
+ char *msg_s;
+
+ msg_s = malloc (strlen (msg) + 10);
+ if (msg_s) {
+ strcpy (msg_s, msg);
+ strcat (msg_s, ": %s");
+ }
+
+ __virRaiseError (conn, NULL, NULL,
+ VIR_FROM_XEN, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
+ msg, NULL, NULL, errno, 0,
+ msg_s ? msg_s : msg, strerror (errno));
}
/**
@@ -1137,7 +1175,7 @@
static int
xenHypervisorInit(void)
{
- int fd, ret, cmd;
+ int fd, ret, cmd, errcode;
hypercall_t hc;
v0_hypercall_t v0_hc;
xen_getdomaininfo info;
@@ -1150,6 +1188,31 @@
initialized = 1;
in_init = 1;
+ /* Compile regular expressions used by xenHypervisorGetCapabilities.
+ * Note that errors here are really internal errors since these
+ * regexps should never fail to compile.
+ */
+ errcode = regcomp (&flags_hvm_rec, flags_hvm_re, REG_EXTENDED);
+ if (errcode != 0) {
+ char error[100];
+ regerror (errcode, &flags_hvm_rec, error, sizeof error);
+ regfree (&flags_hvm_rec);
+ virXenError (VIR_ERR_INTERNAL_ERROR, error, 0);
+ in_init = 0;
+ return -1;
+ }
+ errcode = regcomp (&xen_cap_rec, xen_cap_re, REG_EXTENDED);
+ if (errcode != 0) {
+ char error[100];
+ regerror (errcode, &xen_cap_rec, error, sizeof error);
+ regfree (&xen_cap_rec);
+ regfree (&flags_hvm_rec);
+ virXenError (VIR_ERR_INTERNAL_ERROR, error, 0);
+ in_init = 0;
+ return -1;
+ }
+
+ /* Xen hypervisor version detection begins. */
ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
if (ret < 0) {
hypervisor_version = -1;
@@ -1359,6 +1422,207 @@
}
/**
+ * xenHypervisorGetCapabilities:
+ * @conn: pointer to the connection block
+ *
+ * Return the capabilities of this hypervisor.
+ */
+char *
+xenHypervisorGetCapabilities (virConnectPtr conn)
+{
+ char line[1024], *str, *token;
+ regmatch_t subs[3];
+ char *saveptr;
+ FILE *fp;
+ int i;
+
+ char hvm_type[4] = ""; /* "vmx" or "svm" (or "" if not in CPU). */
+ int hvm_enabled_in_bios = 0;
+ const int max_guest_archs = 32;
+ struct {
+ const char *model;
+ const char *bits;
+ int hvm;
+ int pae;
+ int ia64_be;
+ } guest_archs[max_guest_archs];
+ int nr_guest_archs = 0;
+
+ char *xml, *xml_host_features, *xml_guest_archs;
+
+ /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
+ * It's not clear if this will work on IA64, let alone other
+ * architectures and non-Linux. (XXX)
+ */
+ fp = fopen ("/proc/cpuinfo", "r");
+ if (fp == NULL) {
+ if (errno == ENOENT)
+ goto nocpuinfo;
+ virXenPerror (conn, "/proc/cpuinfo");
+ return NULL;
+ }
+
+ while (fgets (line, sizeof line, fp)) {
+ if (regexec (&flags_hvm_rec, line, 1, subs, 0) == 0
+ && subs[0].rm_so != -1)
+ strncpy (hvm_type,
+ &line[subs[0].rm_so], subs[0].rm_eo-subs[0].rm_so+1);
+ }
+
+ fclose (fp);
+
+ nocpuinfo:
+ /* Most of the useful info is in /sys/hypervisor/properties/capabilities
+ * which is documented in the code in xen-unstable.hg/xen/arch/.../setup.c.
+ *
+ * It is a space-separated list of supported guest architectures.
+ *
+ * For x86:
+ * TYP-VER-ARCH[p]
+ * ^ ^ ^ ^
+ * | | | +-- PAE supported
+ * | | +------- x86_32 or x86_64
+ * | +----------- the version of Xen, eg. "3.0"
+ * +--------------- "xen" or "hvm" for para or full virt respectively
+ *
+ * For PPC this file appears to be always empty (?)
+ *
+ * For IA64:
+ * TYP-VER-ARCH[be]
+ * ^ ^ ^ ^
+ * | | | +-- Big-endian supported
+ * | | +------- always "ia64"
+ * | +----------- the version of Xen, eg. "3.0"
+ * +--------------- "xen" or "hvm" for para or full virt respectively
+ */
+ fp = fopen ("/sys/hypervisor/properties/capabilities", "r");
+ if (fp == NULL) {
+ if (errno == ENOENT)
+ goto noxencaps;
+ virXenPerror (conn, "/sys/hypervisor/properties/capabilities");
+ return NULL;
+ }
+
+ /* Expecting one line in this file - ignore any more. */
+ if (!fgets (line, sizeof line, fp)) {
+ fclose (fp);
+ goto noxencaps;
+ }
+
+ fclose (fp);
+
+ /* Split the line into tokens. strtok_r is OK here because we "own"
+ * this buffer. Parse out the features from each token.
+ */
+ for (str = line, nr_guest_archs = 0;
+ nr_guest_archs < max_guest_archs
+ && (token = strtok_r (str, " ", &saveptr)) != NULL;
+ str = NULL) {
+ if (regexec (&xen_cap_rec, token, 3, subs, 0) == 0) {
+ guest_archs[nr_guest_archs].hvm =
+ strncmp (&token[subs[0].rm_so], "hvm", 3) == 0;
+ if (strncmp (&token[subs[1].rm_so], "x86_32", 6) == 0) {
+ guest_archs[nr_guest_archs].model = "i686";
+ guest_archs[nr_guest_archs].bits = "32";
+ }
+ else if (strncmp (&token[subs[1].rm_so], "x86_64", 6) == 0) {
+ guest_archs[nr_guest_archs].model = "x86_64";
+ guest_archs[nr_guest_archs].bits = "64";
+ }
+ else if (strncmp (&token[subs[1].rm_so], "ia64", 4) == 0) {
+ guest_archs[nr_guest_archs].model = "ia64";
+ guest_archs[nr_guest_archs].bits = "64";
+ }
+ else
+ guest_archs[nr_guest_archs].model = ""; /* can never happen */
+ guest_archs[nr_guest_archs].pae =
+ guest_archs[nr_guest_archs].ia64_be = 0;
+ if (subs[2].rm_so != -1) {
+ if (strncmp (&token[subs[2].rm_so], "p", 1) == 0)
+ guest_archs[nr_guest_archs].pae = 1;
+ else if (strncmp (&token[subs[2].rm_so], "be", 2) == 0)
+ guest_archs[nr_guest_archs].ia64_be = 1;
+ }
+ nr_guest_archs++;
+ }
+ }
+
+ noxencaps:
+ /* If HVM in CPU, is it enabled also in the BIOS? */
+ if (strcmp (hvm_type, "") != 0) {
+ for (i = 0; i < nr_guest_archs; ++i)
+ if (guest_archs[i].hvm) {
+ hvm_enabled_in_bios = 1;
+ break;
+ }
+ }
+
+ /* Construct the final XML. */
+ if (strcmp (hvm_type, "") == 0)
+ xml_host_features = strdup ("");
+ else
+ xml_host_features = strjoin
+ ("\n"
+ "<hvm>",
+ "<type>", hvm_type, "</type>",
+ "<bios_setting>",
+ hvm_enabled_in_bios ? "enabled" : "disabled",
+ "</bios_setting>",
+ "</hvm>",
+ NULL);
+ if (!xml_host_features) {
+ virXenError (VIR_ERR_NO_MEMORY, __FUNCTION__, 0);
+ return NULL;
+ }
+
+ xml_guest_archs = NULL;
+ for (i = 0; i < nr_guest_archs; ++i) {
+ char *old_xml = xml_guest_archs;
+ xml_guest_archs = strjoin
+ ("\n",
+ xml_guest_archs,
+ "<guest_architecture>",
+ "<model>", guest_archs[i].model, "</model>",
+ "<bits>", guest_archs[i].bits, "</bits>",
+ "<guest_features>",
+ guest_archs[i].hvm ? "<hvm/>" : "",
+ guest_archs[i].pae ? "<pae/>" : "",
+ guest_archs[i].ia64_be ? "<ia64_be/>" : "",
+ "<accelerated/>",
+ "</guest_features>",
+ "</guest_architecture>",
+ NULL);
+ free (old_xml);
+ if (!xml_guest_archs) {
+ virXenError (VIR_ERR_NO_MEMORY, __FUNCTION__, 0);
+ free (xml_host_features);
+ return NULL;
+ }
+ }
+
+ xml = strjoin
+ ("\n",
+ "<capabilities>",
+ "<domain><type>xen</type></domain>",
+ "<host_features>",
+ xml_host_features,
+ "</host_features>",
+ "<guest_architectures>",
+ xml_guest_archs,
+ "</guest_architectures>",
+ "</capabilities>\n",
+ NULL);
+ free (xml_host_features);
+ free (xml_guest_archs);
+ if (!xml) {
+ virXenError (VIR_ERR_NO_MEMORY, __FUNCTION__, 0);
+ return NULL;
+ }
+
+ return xml;
+}
+
+/**
* xenHypervisorNumOfDomains:
* @conn: pointer to the connection block
*
@@ -1881,6 +2145,11 @@
}
/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
* Local variables:
* indent-tabs-mode: nil
* c-indent-level: 4
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xen_internal.h libvirt-caps-tmp/src/xen_internal.h
--- libvirt-cvs/src/xen_internal.h 2007-03-09 12:23:51.000000000 +0000
+++ libvirt-caps-tmp/src/xen_internal.h 2007-03-09 13:12:25.000000000 +0000
@@ -25,6 +25,8 @@
int xenHypervisorClose (virConnectPtr conn);
int xenHypervisorGetVersion (virConnectPtr conn,
unsigned long *hvVer);
+char *
+ xenHypervisorGetCapabilities (virConnectPtr conn);
unsigned long
xenHypervisorGetDomMaxMemory (virConnectPtr conn,
int id);
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xm_internal.c libvirt-caps-tmp/src/xm_internal.c
--- libvirt-cvs/src/xm_internal.c 2007-03-09 12:23:51.000000000 +0000
+++ libvirt-caps-tmp/src/xm_internal.c 2007-03-09 13:12:25.000000000 +0000
@@ -77,6 +77,7 @@
NULL, /* version */
NULL, /* getMaxVcpus */
NULL, /* nodeGetInfo */
+ NULL, /* getCapabilities */
NULL, /* listDomains */
NULL, /* numOfDomains */
NULL, /* domainCreateLinux */
diff -urN --exclude=CVS --exclude=.git --exclude='*.pem' --exclude=demoCA --exclude=.gitignore --exclude='*.orig' --exclude='*.bak' libvirt-cvs/src/xs_internal.c libvirt-caps-tmp/src/xs_internal.c
--- libvirt-cvs/src/xs_internal.c 2007-03-09 12:23:51.000000000 +0000
+++ libvirt-caps-tmp/src/xs_internal.c 2007-03-09 13:12:25.000000000 +0000
@@ -46,6 +46,7 @@
NULL, /* version */
NULL, /* getMaxVcpus */
NULL, /* nodeGetInfo */
+ NULL, /* getCapabilities */
xenStoreListDomains, /* listDomains */
NULL, /* numOfDomains */
NULL, /* domainCreateLinux */
smime.p7s
Description: S/MIME Cryptographic Signature
-- Libvir-list mailing list [email protected] https://www.redhat.com/mailman/listinfo/libvir-list
