[libvirt] save/restore for KVM
by Christian Weyermann
Hello everybody,
I try to save and restore a virtual machine, but I always get this error
message:
~$ virsh save test1 test1.vm
Domain test1 nach test1.vm gespeichert [german for test1 successfully
saved to test1.vm]
~$ virsh restore test1.vm
17:53:10.341: error : this function is not supported by the hypervisor:
STDIO migration is not supported with this QEMU binary
libvir: QEMU error : this function is not supported by the hypervisor:
STDIO migration is not supported with this QEMU binary
17:53:10.341: error : operation failed: failed to start VM
libvir: QEMU error : operation failed: failed to start VM
Fehler: Wiederherstellen der Domain aus test1.vm gescheitert [german:
Restoring test1.vm failed!]
Fehler: operation failed: failed to start VM
I am using libvirt 0.6.3, KVM-84 with qemu 0.9.1.
Does anyone have an idea, how to solve this issue?
Thanks in advance and kind regards,
Christian
15 years, 7 months
[libvirt] libvirt native parameters
by Zvi Dubitzky
can anybody remind me where is the native qemu parameters that result from
libvirt translation of an XML file stored (file path).
thanks
Zvi Dubitzky
Virtualization and System Architecture Email:dubi@il.ibm.com
IBM Haifa Research Laboratory Phone: +972-4-8296182
Haifa, 31905, ISRAEL
15 years, 7 months
[libvirt] error: failed to connect to the hypervisor
by Erkan Unal
Hi,
I installed the libvirt with the following configure options as an
unprivileged user, I am planning to use it just for qemu/kvm:
./configure --without-xen --without-lxc --without-uml --without-openvz
--without-vbox --without-numactl --prefix=/some/nonstandard/dir
make
make install
--without-numactl is added because of a compilation error. I am not sure
whether it is completely necessary or not. If you think it has effect on
the error, please state the reason.
After installation I got the following error when I tried to run the
virsh without any options:
error: failed to connect to the hypervisor
With the following command line error was "Segmentation Fault":
virsh -c qemu:///session.
Qemu executable path: /usr/local/bin/qemu-system-x86_64 and it is
defined on the path. Libvirt daemon is failing with the same error too.
System ---> Scientific Linux SL release 4.7 (Beryllium), Kernel version:
2.6.28.2, libvirt version: 0.6.3
Any ideas?
P.S.: Is there a way to compile static virsh executable? I tried
altering make files, configure options, linker flags and compiler flags
but no luck. "ldd virsh" command should say "not a dynamic executable"
after compilation.
Thanks,
Erkan Unal
15 years, 7 months
[libvirt] SetMaxMemory vs. SetMemory
by Matthias Bolte
Hello,
I just took a look at the driver functions for SetMaxMemory and
SetMemory, as they are not implemented yet for the ESX driver and
Daniel Veillard was a bit surprised that they are missing, as he
expects them to be simple to implement. The problem is that I'm not
sure how the memory model of ESX maps to SetMaxMemory vs. SetMemory.
An ESX virtual machine has a defined memory size. That's the size
reported to the guest OS as the available "physical" memory size.
Beside this ESX allows the user to control how the hypervisor
satisfies this "physical" memory size. You can define a reservation
and an upper limit. The hypervisor will at least use the reserved
amount of real physical memory to satisfy the "physical" memory size,
but will not use more than the upper limit.
How does this map to SetMaxMemory and SetMemory? My first assumption
was, SetMaxMemory defines the "physical" memory size and SetMemory
defines the upper limit of real physical memory to satisfy the
"physical" memory size. This assumption seems to be in sync with the
QEMU driver from just looking at the code. But with Xen it seems to be
different. If I call SetMaxMemory and SetMemory with 2GB than free
inside the domain reports 2GB total memory. After I call SetMemory
with 1GB, free reports 1GB of total memory.
I'm confused. So, what is the intended semantic for SetMaxMemory and SetMemory?
Regards,
Matthias
15 years, 7 months
[libvirt] Re: BUG REPORT: -net tap, fd=X does not work correctly in kvm-86
by Anthony Liguori
Josh Wilsdon wrote:
> We are doing work with libvirt 0.6.3 through which we have started
> virtual machines. Using the same "create" command with the same
> storage, the same everything else this configuration works with both
> kvm-84 and kvm-85. When I built a fresh version of kvm-86 this
> stopped working with an error:
>
> qemu: invalid parameter '15' in 'fd=15,script=,vlan=0,ifname=vnet0'
>
It's a libvirt bug. script and ifname have never been valid parameters
for -net tap. Historically, -net has ignored unknown options but
recently, it now throws an error when encountering an unsupported option.
Regards,
Anthony Liguori
15 years, 7 months
[libvirt] PATCH: Ensure filename/funcname/linenr gets passed to error func
by Daniel P. Berrange
The current virRaiseError() function does not accept any information about
these source location of the error. The various virReportSystemError and
virReportOOMError wrappers all collect this info, but then discard it.
This patch turns virRaiseError into virRaiseErrorFull() and adds params
for linenr, filename & funcname, and then adds a macro providing the
original virRaiseError() API contract, and collecting source location
info. The other wrappers are changed to call virRaiseErrorFull() directly
preserving their source location data. Finally the source location is
passed into the virLogMessage call.
This should address the issue that Mattias mentioned in the VMWare driver
thread.
Regards,
Daniel
diff -r 625ffe1918a4 src/virterror.c
--- a/src/virterror.c Thu May 21 15:56:27 2009 +0100
+++ b/src/virterror.c Thu May 21 16:13:49 2009 +0100
@@ -587,10 +587,11 @@ virSetConnError(virConnectPtr conn)
/**
- * virRaiseError:
+ * virRaiseErrorFull:
* @conn: the connection to the hypervisor if available
- * @dom: the domain if available
- * @net: the network if available
+ * @filename: filename where error was raised
+ * @funcname: function name where error was raised
+ * @linenr: line number where error was raised
* @domain: the virErrorDomain indicating where it's coming from
* @code: the virErrorNumber code for the error
* @level: the virErrorLevel for the error
@@ -606,12 +607,19 @@ virSetConnError(virConnectPtr conn)
* immediately if a callback is found and store it for later handling.
*/
void
-virRaiseError(virConnectPtr conn,
- virDomainPtr dom ATTRIBUTE_UNUSED,
- virNetworkPtr net ATTRIBUTE_UNUSED,
- int domain, int code, virErrorLevel level,
- const char *str1, const char *str2, const char *str3,
- int int1, int int2, const char *msg, ...)
+virRaiseErrorFull(virConnectPtr conn,
+ const char *filename ATTRIBUTE_UNUSED,
+ const char *funcname,
+ size_t linenr,
+ int domain,
+ int code,
+ virErrorLevel level,
+ const char *str1,
+ const char *str2,
+ const char *str3,
+ int int1,
+ int int2,
+ const char *fmt, ...)
{
virErrorPtr to;
void *userData = virUserData;
@@ -647,18 +655,18 @@ virRaiseError(virConnectPtr conn,
/*
* formats the message
*/
- if (msg == NULL) {
+ if (fmt == NULL) {
str = strdup(_("No error message provided"));
} else {
- VIR_GET_VAR_STR(msg, str);
+ VIR_GET_VAR_STR(fmt, str);
}
/*
* Hook up the error or warning to the logging facility
- * TODO: pass function name and lineno
+ * XXXX should we include filename as 'category' instead of domain name ?
*/
virLogMessage(virErrorDomainName(domain), virErrorLevelPriority(level),
- NULL, 0, 1, "%s", str);
+ funcname, linenr, 1, "%s", str);
/*
* Save the information about the error
@@ -1064,10 +1072,12 @@ virErrorMsg(virErrorNumber error, const
* Helper function to do most of the grunt work for individual driver
* ReportError
*/
-void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
- const char *filename ATTRIBUTE_UNUSED,
- const char *funcname ATTRIBUTE_UNUSED,
- size_t linenr ATTRIBUTE_UNUSED,
+void virReportErrorHelper(virConnectPtr conn,
+ int domcode,
+ int errcode,
+ const char *filename,
+ const char *funcname,
+ size_t linenr,
const char *fmt, ...)
{
va_list args;
@@ -1083,8 +1093,10 @@ void virReportErrorHelper(virConnectPtr
}
virerr = virErrorMsg(errcode, (errorMessage[0] ? errorMessage : NULL));
- virRaiseError(conn, NULL, NULL, domcode, errcode, VIR_ERR_ERROR,
- virerr, errorMessage, NULL, -1, -1, virerr, errorMessage);
+ virRaiseErrorFull(conn, filename, funcname, linenr,
+ domcode, errcode, VIR_ERR_ERROR,
+ virerr, errorMessage, NULL,
+ -1, -1, virerr, errorMessage);
}
@@ -1113,9 +1125,9 @@ const char *virStrerror(int theerrno, ch
void virReportSystemErrorFull(virConnectPtr conn,
int domcode,
int theerrno,
- const char *filename ATTRIBUTE_UNUSED,
- const char *funcname ATTRIBUTE_UNUSED,
- size_t linenr ATTRIBUTE_UNUSED,
+ const char *filename,
+ const char *funcname,
+ size_t linenr,
const char *fmt, ...)
{
char strerror_buf[1024];
@@ -1145,19 +1157,21 @@ void virReportSystemErrorFull(virConnect
if (!msgDetail)
msgDetail = errnoDetail;
- virRaiseError(conn, NULL, NULL, domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
- msg, msgDetail, NULL, -1, -1, msg, msgDetail);
+ virRaiseErrorFull(conn, filename, funcname, linenr,
+ domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
+ msg, msgDetail, NULL, -1, -1, msg, msgDetail);
}
void virReportOOMErrorFull(virConnectPtr conn,
int domcode,
- const char *filename ATTRIBUTE_UNUSED,
- const char *funcname ATTRIBUTE_UNUSED,
- size_t linenr ATTRIBUTE_UNUSED)
+ const char *filename,
+ const char *funcname,
+ size_t linenr)
{
const char *virerr;
virerr = virErrorMsg(VIR_ERR_NO_MEMORY, NULL);
- virRaiseError(conn, NULL, NULL, domcode, VIR_ERR_NO_MEMORY, VIR_ERR_ERROR,
- virerr, NULL, NULL, -1, -1, virerr, NULL);
+ virRaiseErrorFull(conn, filename, funcname, linenr,
+ domcode, VIR_ERR_NO_MEMORY, VIR_ERR_ERROR,
+ virerr, NULL, NULL, -1, -1, virerr, NULL);
}
diff -r 625ffe1918a4 src/virterror_internal.h
--- a/src/virterror_internal.h Thu May 21 15:56:27 2009 +0100
+++ b/src/virterror_internal.h Thu May 21 16:13:49 2009 +0100
@@ -33,17 +33,28 @@ extern void *virUserData;
* *
************************************************************************/
int virErrorInitialize(void);
-void virRaiseError(virConnectPtr conn,
- virDomainPtr dom,
- virNetworkPtr net,
- int domain,
- int code,
- virErrorLevel level,
- const char *str1,
- const char *str2,
- const char *str3,
- int int1, int int2, const char *msg, ...)
- ATTRIBUTE_FORMAT(printf, 12, 13);
+void virRaiseErrorFull(virConnectPtr conn,
+ const char *filename,
+ const char *funcname,
+ size_t linenr,
+ int domain,
+ int code,
+ virErrorLevel level,
+ const char *str1,
+ const char *str2,
+ const char *str3,
+ int int1,
+ int int2,
+ const char *fmt, ...)
+ ATTRIBUTE_FORMAT(printf, 13, 14);
+
+/* Includes 'dom' and 'net' for compatbility, but they're ignored */
+#define virRaiseError(conn, dom, net, domain, code, level, \
+ str1, str2, str3, int1, int2, msg, ...) \
+ virRaiseErrorFull(conn, __FILE__, __FUNCTION__, __LINE__, \
+ domain, code, level, str1, str2, str3, int1, int2, \
+ msg, __VA_ARGS__)
+
const char *virErrorMsg(virErrorNumber error, const char *info);
void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
const char *filename ATTRIBUTE_UNUSED,
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
15 years, 7 months
[libvirt] storage: inconsistent in 'format' scheme between document and implementation
by Ryota Ozaki
Hi,
I've found a problem that a 'format' element in storage-{pool,vol} XML
doesn't behave as described in the document.
The document says that a format of {pool,vol} is specified as the value of
a format element, like:
<target>
<path>/var/lib/virt/images/sparse.img</path>
<format>qcow2</format>
<permissions>
However, the implementation doesn't follow this:
if (options->formatFromString) {
char *format = virXPathString(conn,
"string(/volume/target/format/@type)", ctxt);
if (format == NULL)
ret->target.format = options->defaultFormat;
else
ret->target.format = (options->formatFromString)(format);
if (ret->target.format < 0) {
virStorageReportError(conn, VIR_ERR_XML_ERROR,
_("unknown volume format type %s"), format);
VIR_FREE(format);
goto cleanup;
}
VIR_FREE(format);
}
The implementation assumes that a format of {pool,vol} is specified as
the attribute of a format element, like:
<target>
<path>/var/lib/virt/images/sparse.img</path>
<format type='qcow2' />
<permissions>
Thus, we need to fix either the document or the implementation.
(I guess the implementation is correct, right?)
Thanks,
ozaki-r
15 years, 7 months
[libvirt] [PATH 0/5] CORRECTED - Interface Config Public APIs and remote stubs, with MAC addresses in string format
by Laine Stump
MY APOLOGIES! Yesterday I accidentally sent the old patchset rather
than the corrected set. This time it's right.
These patches are based on those I sent last week (the public
virInterface*() API definition, the local plumbing, and the RPC glue),
but with suggestions incorporated:
1) MAC address is always used in null-terminated ASCII string
format. This eliminates any potential problems with extra long
addresses.
2) no comments in libvirt.h
3) flags arguments are all unsigned.
15 years, 7 months
[libvirt] PATCH: Impl python bindings for virInterface
by Daniel P. Berrange
We forgot that adding the virInterface APIs would break the build of the
python bindings. Here is the patch to wire up the code generator for
the new APIs. This is actually surprisingly easy, since we ditched the
raw unsigned char MAC address APIs, no special cases were needed.
Daniel
Index: generator.py
===================================================================
RCS file: /data/cvs/libvirt/python/generator.py,v
retrieving revision 1.42
diff -u -p -r1.42 generator.py
--- generator.py 1 Apr 2009 10:39:12 -0000 1.42
+++ generator.py 20 May 2009 16:43:58 -0000
@@ -246,6 +246,11 @@ py_types = {
'virNetwork *': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
'const virNetwork *': ('O', "virNetwork", "virNetworkPtr", "virNetworkPtr"),
+ 'virInterfacePtr': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
+ 'const virInterfacePtr': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
+ 'virInterface *': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
+ 'const virInterface *': ('O', "virInterface", "virInterfacePtr", "virInterfacePtr"),
+
'virStoragePoolPtr': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
'const virStoragePoolPtr': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
'virStoragePool *': ('O', "virStoragePool", "virStoragePoolPtr", "virStoragePoolPtr"),
@@ -289,6 +294,8 @@ skip_impl = (
'virConnectListDefinedDomains',
'virConnectListNetworks',
'virConnectListDefinedNetworks',
+ 'virConnectListInterfaces',
+ 'virConnectListDefinedInterfaces',
'virConnectListStoragePools',
'virConnectListDefinedStoragePools',
'virConnectListStorageVols',
@@ -608,6 +615,8 @@ classes_type = {
"virDomain *": ("._o", "virDomain(self, _obj=%s)", "virDomain"),
"virNetworkPtr": ("._o", "virNetwork(self, _obj=%s)", "virNetwork"),
"virNetwork *": ("._o", "virNetwork(self, _obj=%s)", "virNetwork"),
+ "virInterfacePtr": ("._o", "virInterface(self, _obj=%s)", "virInterface"),
+ "virInterface *": ("._o", "virInterface(self, _obj=%s)", "virInterface"),
"virStoragePoolPtr": ("._o", "virStoragePool(self, _obj=%s)", "virStoragePool"),
"virStoragePool *": ("._o", "virStoragePool(self, _obj=%s)", "virStoragePool"),
"virStorageVolPtr": ("._o", "virStorageVol(self, _obj=%s)", "virStorageVol"),
@@ -621,7 +630,8 @@ classes_type = {
converter_type = {
}
-primary_classes = ["virDomain", "virNetwork", "virStoragePool", "virStorageVol",
+primary_classes = ["virDomain", "virNetwork", "virInterface",
+ "virStoragePool", "virStorageVol",
"virConnect", "virNodeDevice" ]
classes_ancestor = {
@@ -629,6 +639,7 @@ classes_ancestor = {
classes_destructors = {
"virDomain": "virDomainFree",
"virNetwork": "virNetworkFree",
+ "virInterface": "virInterfaceFree",
"virStoragePool": "virStoragePoolFree",
"virStorageVol": "virStorageVolFree",
"virNodeDevice" : "virNodeDeviceFree"
@@ -638,6 +649,7 @@ functions_noexcept = {
'virDomainGetID': True,
'virDomainGetName': True,
'virNetworkGetName': True,
+ 'virInterfaceGetName': True,
'virStoragePoolGetName': True,
'virStorageVolGetName': True,
'virStorageVolGetkey': True,
@@ -690,6 +702,15 @@ def nameFixup(name, classe, type, file):
elif name[0:16] == "virNetworkLookup":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
+ elif name[0:18] == "virInterfaceDefine":
+ func = name[3:]
+ func = string.lower(func[0:1]) + func[1:]
+ elif name[0:21] == "virInterfaceCreateXML":
+ func = name[3:]
+ func = string.lower(func[0:1]) + func[1:]
+ elif name[0:18] == "virInterfaceLookup":
+ func = name[3:]
+ func = string.lower(func[0:1]) + func[1:]
elif name[0:20] == "virStoragePoolDefine":
func = name[3:]
func = string.lower(func[0:1]) + func[1:]
@@ -717,6 +738,12 @@ def nameFixup(name, classe, type, file):
elif name[0:10] == "virNetwork":
func = name[10:]
func = string.lower(func[0:1]) + func[1:]
+ elif name[0:15] == "virInterfaceGet":
+ func = name[13:]
+ func = string.lower(func[0:1]) + func[1:]
+ elif name[0:12] == "virInterface":
+ func = name[10:]
+ func = string.lower(func[0:1]) + func[1:]
elif name[0:17] == "virStoragePoolGet":
func = name[17:]
func = string.lower(func[0:1]) + func[1:]
@@ -988,7 +1015,7 @@ def buildWrappers():
else:
txt.write("Class %s()\n" % (classname))
classes.write("class %s:\n" % (classname))
- if classname in [ "virDomain", "virNetwork", "virStoragePool", "virStorageVol", "virNodeDevice" ]:
+ if classname in [ "virDomain", "virNetwork", "virInterface", "virStoragePool", "virStorageVol", "virNodeDevice" ]:
classes.write(" def __init__(self, conn, _obj=None):\n")
else:
classes.write(" def __init__(self, _obj=None):\n")
@@ -996,7 +1023,7 @@ def buildWrappers():
list = reference_keepers[classname]
for ref in list:
classes.write(" self.%s = None\n" % ref[1])
- if classname in [ "virDomain", "virNetwork", "virNodeDevice" ]:
+ if classname in [ "virDomain", "virNetwork", "virInterface", "virNodeDevice" ]:
classes.write(" self._conn = conn\n")
elif classname in [ "virStorageVol", "virStoragePool" ]:
classes.write(" self._conn = conn\n" + \
@@ -1097,6 +1124,10 @@ def buildWrappers():
classes.write(
" if ret is None:raise libvirtError('%s() failed', net=self)\n" %
(name))
+ elif classname == "virInterface":
+ classes.write(
+ " if ret is None:raise libvirtError('%s() failed', net=self)\n" %
+ (name))
elif classname == "virStoragePool":
classes.write(
" if ret is None:raise libvirtError('%s() failed', pool=self)\n" %
@@ -1177,6 +1208,10 @@ def buildWrappers():
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', net=self)\n") %
("ret", name))
+ elif classname == "virInterface":
+ classes.write ((" if " + test +
+ ": raise libvirtError ('%s() failed', net=self)\n") %
+ ("ret", name))
elif classname == "virStoragePool":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', pool=self)\n") %
@@ -1215,6 +1250,10 @@ def buildWrappers():
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', net=self)\n") %
("ret", name))
+ elif classname == "virInterface":
+ classes.write ((" if " + test +
+ ": raise libvirtError ('%s() failed', net=self)\n") %
+ ("ret", name))
elif classname == "virStoragePool":
classes.write ((" if " + test +
": raise libvirtError ('%s() failed', pool=self)\n") %
Index: libvirt_wrap.h
===================================================================
RCS file: /data/cvs/libvirt/python/libvirt_wrap.h,v
retrieving revision 1.15
diff -u -p -r1.15 libvirt_wrap.h
--- libvirt_wrap.h 24 Nov 2008 19:28:12 -0000 1.15
+++ libvirt_wrap.h 20 May 2009 16:43:58 -0000
@@ -48,6 +48,15 @@ typedef struct {
} PyvirNetwork_Object;
+#define PyvirInterface_Get(v) (((v) == Py_None) ? NULL : \
+ (((PyvirInterface_Object *)(v))->obj))
+
+typedef struct {
+ PyObject_HEAD
+ virInterfacePtr obj;
+} PyvirInterface_Object;
+
+
#define PyvirStoragePool_Get(v) (((v) == Py_None) ? NULL : \
(((PyvirStoragePool_Object *)(v))->obj))
@@ -118,6 +127,7 @@ PyObject * libvirt_charPtrConstWrap(cons
PyObject * libvirt_virConnectPtrWrap(virConnectPtr node);
PyObject * libvirt_virDomainPtrWrap(virDomainPtr node);
PyObject * libvirt_virNetworkPtrWrap(virNetworkPtr node);
+PyObject * libvirt_virInterfacePtrWrap(virInterfacePtr node);
PyObject * libvirt_virStoragePoolPtrWrap(virStoragePoolPtr node);
PyObject * libvirt_virStorageVolPtrWrap(virStorageVolPtr node);
PyObject * libvirt_virEventHandleCallbackWrap(virEventHandleCallback node);
Index: types.c
===================================================================
RCS file: /data/cvs/libvirt/python/types.c,v
retrieving revision 1.17
diff -u -p -r1.17 types.c
--- types.c 18 Dec 2008 12:25:11 -0000 1.17
+++ types.c 20 May 2009 16:43:58 -0000
@@ -119,6 +119,21 @@ libvirt_virNetworkPtrWrap(virNetworkPtr
}
PyObject *
+libvirt_virInterfacePtrWrap(virInterfacePtr node)
+{
+ PyObject *ret;
+
+ if (node == NULL) {
+ Py_INCREF(Py_None);
+ return (Py_None);
+ }
+ ret =
+ PyCObject_FromVoidPtrAndDesc((void *) node, (char *) "virInterfacePtr",
+ NULL);
+ return (ret);
+}
+
+PyObject *
libvirt_virStoragePoolPtrWrap(virStoragePoolPtr node)
{
PyObject *ret;
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
15 years, 7 months
[libvirt] PATCH: Work in progress suport for video device config
by Daniel P. Berrange
We discussed adding a new XML element for representing video devices a
few weeks back. This is my work in progress patch for the XML parsing
routines supporting
<video>
<model type='vga|cirrus|vmvga|xen' vram='64' heads='1'/>
</video>
For compatability, if an existing guest has a <graphics> tag, but no
<video> tag, then the parser automatically adds a <video> tag for
type=cirrus. Still todo
- Tweak the addition of default <video> tag a little so it uses the
correct type for the type of guest - eg it should use type=xen in
some cases.
- Add RNG XML schemas & website docs
- Make QEMU driver use this info for setting -vga argument
- Make Xen drivers use this info for setting stdvga=1|0 config arg
- Make VirtualBox use this info in whatever way it needs
Daniel
domain_conf.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
domain_conf.h | 26 ++++++++
2 files changed, 194 insertions(+)
diff -r 66fa9bfc797c src/domain_conf.c
--- a/src/domain_conf.c Mon May 18 11:28:46 2009 +0100
+++ b/src/domain_conf.c Mon May 18 11:29:00 2009 +0100
@@ -80,6 +80,7 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAI
"interface",
"input",
"sound",
+ "video",
"hostdev")
VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
@@ -140,6 +141,12 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_D
"pcspk",
"ac97")
+VIR_ENUM_IMPL(virDomainVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
+ "vga",
+ "cirrus",
+ "vmvga",
+ "xen")
+
VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
"mouse",
"tablet")
@@ -372,6 +379,14 @@ void virDomainSoundDefFree(virDomainSoun
VIR_FREE(def);
}
+void virDomainVideoDefFree(virDomainVideoDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def);
+}
+
void virDomainHostdevDefFree(virDomainHostdevDefPtr def)
{
if (!def)
@@ -399,6 +414,9 @@ void virDomainDeviceDefFree(virDomainDev
case VIR_DOMAIN_DEVICE_SOUND:
virDomainSoundDefFree(def->data.sound);
break;
+ case VIR_DOMAIN_DEVICE_VIDEO:
+ virDomainVideoDefFree(def->data.video);
+ break;
case VIR_DOMAIN_DEVICE_HOSTDEV:
virDomainHostdevDefFree(def->data.hostdev);
break;
@@ -456,6 +474,10 @@ void virDomainDefFree(virDomainDefPtr de
virDomainSoundDefFree(def->sounds[i]);
VIR_FREE(def->sounds);
+ for (i = 0 ; i < def->nvideos ; i++)
+ virDomainVideoDefFree(def->videos[i]);
+ VIR_FREE(def->videos);
+
for (i = 0 ; i < def->nhostdevs ; i++)
virDomainHostdevDefFree(def->hostdevs[i]);
VIR_FREE(def->hostdevs);
@@ -1638,6 +1660,84 @@ error:
goto cleanup;
}
+static virDomainVideoDefPtr
+virDomainVideoDefParseXML(virConnectPtr conn,
+ const xmlNodePtr node,
+ int flags ATTRIBUTE_UNUSED) {
+ virDomainVideoDefPtr def;
+ xmlNodePtr cur;
+ char *type = NULL;
+ char *heads = NULL;
+ char *vram = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError(conn);
+ return NULL;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if ((type == NULL) && (vram == NULL) && (heads == NULL) &&
+ xmlStrEqual(cur->name, BAD_CAST "model")) {
+ type = virXMLPropString(cur, "type");
+ vram = virXMLPropString(cur, "vram");
+ heads = virXMLPropString(cur, "heads");
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (type &&
+ (def->type = virDomainVideoTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown video model '%s'"), type);
+ goto error;
+ }
+
+ if (vram &&
+ virStrToLong_ui(vram, NULL, 10, &def->vram) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse video ram '%s'"), vram);
+ goto error;
+ } else {
+ switch (def->type) {
+ /* Wierd, QEMU defaults to 9 MB ??! */
+ case VIR_DOMAIN_VIDEO_TYPE_VGA:
+ case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
+ case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
+ def->vram = 9 * 1024;
+ break;
+ case VIR_DOMAIN_VIDEO_TYPE_XEN:
+ /* Original PVFB hardcoded to 4 MB */
+ def->vram = 4 * 1024;
+ break;
+ }
+ }
+
+ if (heads &&
+ virStrToLong_ui(heads, NULL, 10, &def->heads) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse video heads '%s'"), heads);
+ goto error;
+ } else {
+ def->heads = 1;
+ }
+
+ VIR_FREE(type);
+ VIR_FREE(vram);
+ VIR_FREE(heads);
+
+ return def;
+
+error:
+ virDomainVideoDefFree(def);
+ VIR_FREE(type);
+ VIR_FREE(vram);
+ VIR_FREE(heads);
+ return NULL;
+}
+
static int
virDomainHostdevSubsysUsbDefParseXML(virConnectPtr conn,
const xmlNodePtr node,
@@ -2064,6 +2164,10 @@ virDomainDeviceDefPtr virDomainDeviceDef
dev->type = VIR_DOMAIN_DEVICE_SOUND;
if (!(dev->data.sound = virDomainSoundDefParseXML(conn, node, flags)))
goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "video")) {
+ dev->type = VIR_DOMAIN_DEVICE_VIDEO;
+ if (!(dev->data.video = virDomainVideoDefParseXML(conn, node, flags)))
+ goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "hostdev")) {
dev->type = VIR_DOMAIN_DEVICE_HOSTDEV;
if (!(dev->data.hostdev = virDomainHostdevDefParseXML(conn, node, flags)))
@@ -2584,6 +2688,40 @@ static virDomainDefPtr virDomainDefParse
}
VIR_FREE(nodes);
+ /* analysis of the video devices */
+ if ((n = virXPathNodeSet(conn, "./devices/video", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract video devices"));
+ goto error;
+ }
+ if (n && VIR_ALLOC_N(def->videos, n) < 0)
+ goto no_memory;
+ for (i = 0 ; i < n ; i++) {
+ virDomainVideoDefPtr video = virDomainVideoDefParseXML(conn,
+ nodes[i],
+ flags);
+ if (!video)
+ goto error;
+ def->videos[def->nvideos++] = video;
+ }
+ VIR_FREE(nodes);
+
+ /* For backwards compatability, if no <video> tag is set but there
+ * is a <graphics> tag, then we add a single video tag */
+ if (def->ngraphics && !def->nvideos) {
+ virDomainVideoDefPtr video;
+ if (VIR_ALLOC(video) < 0)
+ goto no_memory;
+ video->type = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
+ video->vram = 9 * 1024;
+ video->heads = 1;
+ if (VIR_ALLOC_N(def->videos, 1) < 0) {
+ virDomainVideoDefFree(video);
+ goto no_memory;
+ }
+ def->videos[def->nvideos++] = video;
+ }
+
/* analysis of the host devices */
if ((n = virXPathNodeSet(conn, "./devices/hostdev", ctxt, &nodes)) < 0) {
virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
@@ -3286,6 +3424,32 @@ virDomainSoundDefFormat(virConnectPtr co
}
static int
+virDomainVideoDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainVideoDefPtr def)
+{
+ const char *model = virDomainVideoTypeToString(def->type);
+
+ if (!model) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected video model %d"), def->type);
+ return -1;
+ }
+
+ virBufferAddLit(buf, " <video>\n");
+ virBufferVSprintf(buf, " <model type='%s'",
+ model);
+ if (def->vram)
+ virBufferVSprintf(buf, " vram='%u'", def->vram);
+ if (def->heads)
+ virBufferVSprintf(buf, " heads='%u'", def->heads);
+ virBufferAddLit(buf, "/>\n");
+ virBufferAddLit(buf, " </video>\n");
+
+ return 0;
+}
+
+static int
virDomainInputDefFormat(virConnectPtr conn,
virBufferPtr buf,
virDomainInputDefPtr def)
@@ -3660,6 +3824,10 @@ char *virDomainDefFormat(virConnectPtr c
if (virDomainSoundDefFormat(conn, &buf, def->sounds[n]) < 0)
goto cleanup;
+ for (n = 0 ; n < def->nvideos ; n++)
+ if (virDomainVideoDefFormat(conn, &buf, def->videos[n]) < 0)
+ goto cleanup;
+
for (n = 0 ; n < def->nhostdevs ; n++)
if (virDomainHostdevDefFormat(conn, &buf, def->hostdevs[n]) < 0)
goto cleanup;
diff -r 66fa9bfc797c src/domain_conf.h
--- a/src/domain_conf.h Mon May 18 11:28:46 2009 +0100
+++ b/src/domain_conf.h Mon May 18 11:29:00 2009 +0100
@@ -264,6 +264,25 @@ struct _virDomainSoundDef {
int model;
};
+
+enum virDomainVideoType {
+ VIR_DOMAIN_VIDEO_TYPE_VGA,
+ VIR_DOMAIN_VIDEO_TYPE_CIRRUS,
+ VIR_DOMAIN_VIDEO_TYPE_VMVGA,
+ VIR_DOMAIN_VIDEO_TYPE_XEN,
+
+ VIR_DOMAIN_VIDEO_TYPE_LAST
+};
+
+
+typedef struct _virDomainVideoDef virDomainVideoDef;
+typedef virDomainVideoDef *virDomainVideoDefPtr;
+struct _virDomainVideoDef {
+ int type;
+ unsigned int vram;
+ unsigned int heads;
+};
+
/* 3 possible graphics console modes */
enum virDomainGraphicsType {
VIR_DOMAIN_GRAPHICS_TYPE_SDL,
@@ -360,6 +379,7 @@ enum virDomainDeviceType {
VIR_DOMAIN_DEVICE_NET,
VIR_DOMAIN_DEVICE_INPUT,
VIR_DOMAIN_DEVICE_SOUND,
+ VIR_DOMAIN_DEVICE_VIDEO,
VIR_DOMAIN_DEVICE_HOSTDEV,
VIR_DOMAIN_DEVICE_LAST,
@@ -375,6 +395,7 @@ struct _virDomainDeviceDef {
virDomainNetDefPtr net;
virDomainInputDefPtr input;
virDomainSoundDefPtr sound;
+ virDomainVideoDefPtr video;
virDomainHostdevDefPtr hostdev;
} data;
};
@@ -491,6 +512,9 @@ struct _virDomainDef {
int nsounds;
virDomainSoundDefPtr *sounds;
+ int nvideos;
+ virDomainVideoDefPtr *videos;
+
int nhostdevs;
virDomainHostdevDefPtr *hostdevs;
@@ -557,6 +581,7 @@ void virDomainFSDefFree(virDomainFSDefPt
void virDomainNetDefFree(virDomainNetDefPtr def);
void virDomainChrDefFree(virDomainChrDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
+void virDomainVideoDefFree(virDomainVideoDefPtr def);
void virDomainHostdevDefFree(virDomainHostdevDefPtr def);
void virDomainDeviceDefFree(virDomainDeviceDefPtr def);
void virDomainDefFree(virDomainDefPtr vm);
@@ -671,6 +696,7 @@ VIR_ENUM_DECL(virDomainFS)
VIR_ENUM_DECL(virDomainNet)
VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainSoundModel)
+VIR_ENUM_DECL(virDomainVideo)
VIR_ENUM_DECL(virDomainHostdevMode)
VIR_ENUM_DECL(virDomainHostdevSubsys)
VIR_ENUM_DECL(virDomainInput)
--
|: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :|
|: http://autobuild.org -o- http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
15 years, 7 months