This is the second version of this patch. I'll just summarise what's
changed below rather than reiterating what it does over again. I
believe this addresses everyone's concerns, _except_ for a rather long
email from Dan to which I'm going to provide a separate reply.
Changes over previous patch:
* strjoin is gone, and replaced by virBuffer* [DV]
** however, in order to do that I had to duplicate the buffer handling
code for qemud (since qemud doesn't link with libvirt and the virBuffer*
code depends on other internals of libvirt).
* <bits> is now optional, and where it's too hard to determine it
reliably, we don't include it in the XML output [DV, danpb]
* <domain><type> -> <domain_type> [markmc]
Rich.
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-12 10:39:29.000000000 +0000
+++ libvirt-caps-tmp/configure.in 2007-03-12 10:42:24.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-03-12 10:39:29.000000000 +0000
+++ libvirt-caps-tmp/.cvsignore 2007-03-12 10:42:23.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-12 10:39:42.000000000 +0000
+++ libvirt-caps-tmp/include/libvirt/libvirt.h.in 2007-03-12 10:45:43.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-03-12 10:39:42.000000000 +0000
+++ libvirt-caps-tmp/include/libvirt/virterror.h 2007-03-12 10:45:45.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-12 10:39:46.000000000 +0000
+++ libvirt-caps-tmp/proxy/libvirt_proxy.c 2007-03-12 10:45:58.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/qemud/conf.c libvirt-caps-tmp/qemud/conf.c
--- libvirt-cvs/qemud/conf.c 2007-03-12 10:39:24.000000000 +0000
+++ libvirt-caps-tmp/qemud/conf.c 2007-03-12 10:42:01.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-03-12 10:39:24.000000000 +0000
+++ libvirt-caps-tmp/qemud/conf.h 2007-03-12 10:42:01.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-03-12 10:39:26.000000000 +0000
+++ libvirt-caps-tmp/qemud/dispatch.c 2007-03-12 13:47:00.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 "qemud_xml.h"
static int qemudDispatchFailure(struct qemud_server *server ATTRIBUTE_UNUSED,
@@ -100,6 +103,137 @@
return 0;
}
+static int
+qemudDispatchGetCapabilities (struct qemud_server *server,
+ struct qemud_client *client,
+ struct qemud_packet *in,
+ struct qemud_packet *out)
+{
+ struct utsname utsname;
+ struct qemud_guest_arch *guest_archs;
+ int nr_guest_archs, i, r;
+ int have_kqemu = 0;
+ int have_kvm = 0;
+ bufferPtr xml;
+ int len;
+
+ 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. */
+ xml = bufferNew (1024);
+ if (!xml) {
+ qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+ qemudDispatchFailure (server, client, out);
+ return 0;
+ }
+
+ r = bufferAdd (xml,
+ "\
+<capabilities>\n\
+ <domain_type>qemu</domain_type>\n\
+ <guest_architectures>\n", -1);
+ if (r == -1) {
+ vir_buffer_failed:
+ bufferFree (xml);
+ qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+ qemudDispatchFailure (server, client, out);
+ return 0;
+ }
+
+ /* First the guest architectures for basic <domain type='qemu'>,
+ * all emulated (even x86 on x86).
+ */
+ nr_guest_archs = qemudGetGuestArchitectures (&guest_archs);
+ if (nr_guest_archs == -1) {
+ bufferFree (xml);
+ qemudReportError (server, VIR_ERR_NO_MEMORY, NULL);
+ qemudDispatchFailure (server, client, out);
+ return 0;
+ }
+ for (i = 0; i < nr_guest_archs; ++i) {
+ r = bufferVSprintf (xml,
+ "\
+ <guest_architecture>\n\
+ <model>%s</model>\n\
+ <bits>%d</bits>\n\
+ <features>\n\
+ <emulated/>\n\
+ </features>\n\
+ </guest_architecture>\n",
+ guest_archs[i].model,
+ guest_archs[i].bits);
+ if (r == -1) {
+ free (guest_archs);
+ goto vir_buffer_failed;
+ }
+ }
+ free (guest_archs);
+
+ /* Really, this never fails - look at the man-page. */
+ uname (&utsname);
+
+ /* If we have kqemu, then there is a <domain type='kqemu'>,
+ * accelerated, but the model is limited to host == guest.
+ */
+ if (have_kqemu) {
+ r = bufferVSprintf (xml,
+ /* XXX There is no mention of PAE in qemu docs */
+ "\
+ <guest_architecture>\n\
+ <domain_type>kqemu</domain_type>\n\
+ <model>%s</model>\n\
+ <features>\n\
+ <accelerated/>\n\
+ </features>\n\
+ </guest_architecture>\n",
+ utsname.machine);
+ if (r == -1) goto vir_buffer_failed;
+ }
+
+ /* If we have kvm, then there is a <domain type='kvm'>,
+ * accelerated, HVM, but the model is limited to host == guest.
+ */
+ if (have_kvm) {
+ r = bufferVSprintf (xml,
+ /* XXX Does KVM support PAE inside the guest? */
+ "\
+ <guest_architecture>\n\
+ <domain_type>kvm</domain_type>\n\
+ <model>%s</model>\n\
+ <features>\n\
+ <hvm/>\n\
+ <accelerated/>\n\
+ </features>\n\
+ </guest_architecture>\n",
+ utsname.machine);
+ if (r == -1) goto vir_buffer_failed;
+ }
+
+ /* Finally build the full capabilities. */
+ r = bufferAdd (xml,
+ "\
+ </guest_architectures>\n\
+</capabilities>\n", -1);
+ if (r == -1) goto vir_buffer_failed;
+
+ /* Copy the XML into the outgoing packet, assuming it's not too large. */
+ len = strlen (xml->content);
+ if (len > QEMUD_MAX_XML_LEN) {
+ bufferFree (xml);
+ qemudReportError (server, VIR_ERR_XML_ERROR, NULL);
+ qemudDispatchFailure (server, client, out);
+ return 0;
+ }
+ out->header.type = QEMUD_PKT_GET_CAPABILITIES;
+ out->header.dataSize = len;
+ strcpy (out->data.getCapabilitiesReply.xml, xml->content);
+ bufferFree (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 +988,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-12 10:39:27.000000000 +0000
+++ libvirt-caps-tmp/qemud/Makefile.am 2007-03-12 14:06:20.000000000 +0000
@@ -10,7 +10,8 @@
conf.c conf.h \
bridge.c bridge.h \
iptables.c iptables.h \
- uuid.c uuid.h
+ uuid.c uuid.h \
+ qemud_xml.c qemud_xml.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) \
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-03-12 10:39:29.000000000 +0000
+++ libvirt-caps-tmp/qemud/protocol.h 2007-03-12 10:42:15.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/qemud/qemud_xml.c libvirt-caps-tmp/qemud/qemud_xml.c
--- libvirt-cvs/qemud/qemud_xml.c 1970-01-01 01:00:00.000000000 +0100
+++ libvirt-caps-tmp/qemud/qemud_xml.c 2007-03-12 13:46:28.000000000 +0000
@@ -0,0 +1,195 @@
+/*
+ * qemud_xml.c: buffers for qemud
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <[EMAIL PROTECTED]>
+ */
+
+#include "libvirt/libvirt.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "qemud_xml.h"
+
+/**
+ * bufferGrow:
+ * @buf: the buffer
+ * @len: the minimum free size to allocate
+ *
+ * Grow the available space of an XML buffer.
+ *
+ * Returns the new available space or -1 in case of error
+ */
+static int
+bufferGrow(bufferPtr buf, unsigned int len)
+{
+ int size;
+ char *newbuf;
+
+ if (buf == NULL)
+ return (-1);
+ if (len + buf->use < buf->size)
+ return (0);
+
+ size = buf->use + len + 1000;
+
+ newbuf = (char *) realloc(buf->content, size);
+ if (newbuf == NULL) return -1;
+ buf->content = newbuf;
+ buf->size = size;
+ return (buf->size - buf->use);
+}
+
+/**
+ * bufferAdd:
+ * @buf: the buffer to dump
+ * @str: the string
+ * @len: the number of bytes to add
+ *
+ * Add a string range to an XML buffer. if len == -1, the length of
+ * str is recomputed to the full string.
+ *
+ * Returns 0 successful, -1 in case of internal or API error.
+ */
+int
+bufferAdd(bufferPtr buf, const char *str, int len)
+{
+ unsigned int needSize;
+
+ if ((str == NULL) || (buf == NULL)) {
+ return -1;
+ }
+ if (len == 0)
+ return 0;
+
+ if (len < 0)
+ len = strlen(str);
+
+ needSize = buf->use + len + 2;
+ if (needSize > buf->size) {
+ if (!bufferGrow(buf, needSize)) {
+ return (-1);
+ }
+ }
+ /* XXX: memmove() is 2x slower than memcpy(), do we really need it? */
+ memmove(&buf->content[buf->use], str, len);
+ buf->use += len;
+ buf->content[buf->use] = 0;
+ return (0);
+}
+
+bufferPtr
+bufferNew(unsigned int size)
+{
+ bufferPtr buf;
+
+ if (!(buf = malloc(sizeof(*buf)))) return NULL;
+ if (size && (buf->content = malloc(size))==NULL) {
+ free(buf);
+ return NULL;
+ }
+ buf->size = size;
+ buf->use = 0;
+
+ return buf;
+}
+
+void
+bufferFree(bufferPtr buf)
+{
+ if (buf) {
+ if (buf->content)
+ free(buf->content);
+ free(buf);
+ }
+}
+
+/**
+ * bufferVSprintf:
+ * @buf: the buffer to dump
+ * @format: the format
+ * @argptr: the variable list of arguments
+ *
+ * Do a formatted print to an XML buffer.
+ *
+ * Returns 0 successful, -1 in case of internal or API error.
+ */
+int
+bufferVSprintf(bufferPtr buf, const char *format, ...)
+{
+ int size, count;
+ va_list locarg, argptr;
+
+ if ((format == NULL) || (buf == NULL)) {
+ return (-1);
+ }
+ size = buf->size - buf->use - 1;
+ va_start(argptr, format);
+ va_copy(locarg, argptr);
+ while (((count = vsnprintf(&buf->content[buf->use], size, format,
+ locarg)) < 0) || (count >= size - 1)) {
+ buf->content[buf->use] = 0;
+ va_end(locarg);
+ if (bufferGrow(buf, 1000) < 0) {
+ return (-1);
+ }
+ size = buf->size - buf->use - 1;
+ va_copy(locarg, argptr);
+ }
+ va_end(locarg);
+ buf->use += count;
+ buf->content[buf->use] = 0;
+ return (0);
+}
+
+/**
+ * bufferStrcat:
+ * @buf: the buffer to dump
+ * @argptr: the variable list of strings, the last argument must be NULL
+ *
+ * Concatenate strings to an XML buffer.
+ *
+ * Returns 0 successful, -1 in case of internal or API error.
+ */
+int
+bufferStrcat(bufferPtr buf, ...)
+{
+ va_list ap;
+ char *str;
+
+ va_start(ap, buf);
+
+ while ((str = va_arg(ap, char *)) != NULL) {
+ unsigned int len = strlen(str);
+ unsigned int needSize = buf->use + len + 2;
+
+ if (needSize > buf->size) {
+ if (!bufferGrow(buf, needSize))
+ return -1;
+ }
+ memcpy(&buf->content[buf->use], str, len);
+ buf->use += len;
+ buf->content[buf->use] = 0;
+ }
+ va_end(ap);
+ return 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/qemud/qemud_xml.h libvirt-caps-tmp/qemud/qemud_xml.h
--- libvirt-cvs/qemud/qemud_xml.h 1970-01-01 01:00:00.000000000 +0100
+++ libvirt-caps-tmp/qemud/qemud_xml.h 2007-03-12 13:44:40.000000000 +0000
@@ -0,0 +1,33 @@
+/*
+ * qemud_xml.h: buffers for qemud
+ *
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * See COPYING.LIB for the License of this software
+ *
+ * Daniel Veillard <[EMAIL PROTECTED]>
+ */
+
+#ifndef __QEMUD_XML_H__
+#define __QEMUD_XML_H__
+
+/**
+ * buffer:
+ *
+ * A buffer structure.
+ */
+typedef struct _buffer buffer;
+typedef buffer *bufferPtr;
+struct _buffer {
+ char *content; /* The buffer content UTF8 */
+ unsigned int use; /* The buffer size used */
+ unsigned int size; /* The buffer size */
+};
+
+bufferPtr bufferNew(unsigned int size);
+void bufferFree(bufferPtr buf);
+int bufferAdd(bufferPtr buf, const char *str, int len);
+int bufferVSprintf(bufferPtr buf, const char *format, ...);
+int bufferStrcat(bufferPtr buf, ...);
+
+#endif /* __QEMUD_XML_H__ */
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-12 10:40:28.000000000 +0000
+++ libvirt-caps-tmp/src/driver.h 2007-03-12 10:48:28.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-12 10:40:32.000000000 +0000
+++ libvirt-caps-tmp/src/internal.h 2007-03-12 10:48:32.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/libvirt.c libvirt-caps-tmp/src/libvirt.c
--- libvirt-cvs/src/libvirt.c 2007-03-12 10:40:26.000000000 +0000
+++ libvirt-caps-tmp/src/libvirt.c 2007-03-12 10:48:22.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-12 11:09:50.000000000 +0000
+++ libvirt-caps-tmp/src/libvirt_sym.version 2007-03-12 14:07:55.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/proxy_internal.c libvirt-caps-tmp/src/proxy_internal.c
--- libvirt-cvs/src/proxy_internal.c 2007-03-12 10:40:33.000000000 +0000
+++ libvirt-caps-tmp/src/proxy_internal.c 2007-03-12 10:50:13.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 2007-03-12 10:40:33.000000000 +0000
+++ libvirt-caps-tmp/src/proxy_internal.h 2007-03-12 10:50:13.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-12 10:40:22.000000000 +0000
+++ libvirt-caps-tmp/src/qemu_internal.c 2007-03-12 10:48:12.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-12 10:40:24.000000000 +0000
+++ libvirt-caps-tmp/src/test.c 2007-03-12 12:47:18.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</domain_type>\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-12 10:40:35.000000000 +0000
+++ libvirt-caps-tmp/src/virsh.c 2007-03-12 10:50:15.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-03-12 10:40:36.000000000 +0000
+++ libvirt-caps-tmp/src/virterror.c 2007-03-12 10:50:16.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-12 10:40:28.000000000 +0000
+++ libvirt-caps-tmp/src/xend_internal.c 2007-03-12 10:48:24.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-12 10:40:20.000000000 +0000
+++ libvirt-caps-tmp/src/xen_internal.c 2007-03-12 13:14:33.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 "xml.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,204 @@
}
/**
+ * 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, r;
+
+ 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;
+ int bits;
+ int hvm;
+ int pae;
+ int ia64_be;
+ } guest_archs[max_guest_archs];
+ int nr_guest_archs = 0;
+
+ virBufferPtr xml;
+ char *xml_str;
+
+ /* /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. */
+ xml = virBufferNew (1024);
+ if (!xml) return NULL;
+ r = virBufferAdd (xml,
+ "\
+<capabilities>\n\
+ <domain_type>xen</domain_type>\n\
+ <host_features>\n", -1);
+ if (r == -1) return NULL;
+
+ if (strcmp (hvm_type, "") != 0) {
+ r = virBufferVSprintf (xml,
+ "\
+ <hvm>\n\
+ <type>%s</type>\n\
+ <bios_setting>%s</bios_setting>\n\
+ </hvm>\n",
+ hvm_type,
+ hvm_enabled_in_bios ? "enabled" : "disabled");
+ if (r == -1) {
+ vir_buffer_failed:
+ virBufferFree (xml);
+ return NULL;
+ }
+ }
+ r = virBufferAdd (xml,
+ "\
+ </host_features>\n\
+ <guest_architectures>\n", -1);
+ if (r == -1) goto vir_buffer_failed;
+
+ for (i = 0; i < nr_guest_archs; ++i) {
+ r = virBufferVSprintf (xml,
+ "\
+ <guest_architecture>\n\
+ <model>%s</model>\n\
+ <bits>%d</bits>\n\
+ <guest_features>%s%s%s<accelerated/></guest_features>\n\
+ </guest_architecture>\n",
+ guest_archs[i].model,
+ guest_archs[i].bits,
+ guest_archs[i].hvm ? "<hvm/> " : "",
+ guest_archs[i].pae ? "<pae/> " : "",
+ guest_archs[i].ia64_be ? "<ia64_be/> " : "");
+ if (r == -1) goto vir_buffer_failed;
+ }
+ r = virBufferAdd (xml,
+ "\
+ </guest_architectures>\n\
+</capabilities>\n", -1);
+ if (r == -1) goto vir_buffer_failed;
+ xml_str = strdup (xml->content);
+ if (!xml_str) {
+ virXenError(VIR_ERR_NO_MEMORY, "strdup", 0);
+ goto vir_buffer_failed;
+ }
+ virBufferFree (xml);
+
+ return xml_str;
+}
+
+/**
* xenHypervisorNumOfDomains:
* @conn: pointer to the connection block
*
@@ -1881,6 +2142,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-12 10:40:28.000000000 +0000
+++ libvirt-caps-tmp/src/xen_internal.h 2007-03-12 10:48:28.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-12 10:40:31.000000000 +0000
+++ libvirt-caps-tmp/src/xm_internal.c 2007-03-12 10:48:31.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/xml.h libvirt-caps-tmp/src/xml.h
--- libvirt-cvs/src/xml.h 2007-03-12 10:40:36.000000000 +0000
+++ libvirt-caps-tmp/src/xml.h 2007-03-12 13:40:11.000000000 +0000
@@ -29,6 +29,7 @@
int virBufferAdd(virBufferPtr buf, const char *str, int len);
int virBufferVSprintf(virBufferPtr buf, const char *format, ...);
int virBufferStrcat(virBufferPtr buf, ...);
+
char *virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, int xendConfigVersion);
unsigned char *virParseUUID(char **ptr, const char *uuid);
char *virParseXMLDevice(virConnectPtr conn, char *xmldesc, int hvm, int xendConfigVersion);
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-12 10:40:21.000000000 +0000
+++ libvirt-caps-tmp/src/xs_internal.c 2007-03-12 10:48:12.000000000 +0000
@@ -46,6 +46,7 @@
NULL, /* version */
NULL, /* getMaxVcpus */
NULL, /* nodeGetInfo */
+ NULL, /* getCapabilities */
xenStoreListDomains, /* listDomains */
NULL, /* numOfDomains */
NULL, /* domainCreateLinux */
--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list