[Libvir] [PATCH] Enable USB device setting information handling on virsh.

Hi When domHVM started by virsh create, the information of USB setting is not saved by vish dumpxml. The reason is that USB setting is defined by Xen itself, not virsh. This patch enables USB device setting information handling on virsh create/virsh dumpxml. Signed-off-by: Masayuki Sunou <fj1826dm@aa.jp.fujitsu.com> Thanks, Masayuki Sunou Index: libvirt/src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.99 diff -u -p -r1.99 xend_internal.c --- libvirt/src/xend_internal.c 6 Mar 2007 21:55:44 -0000 1.99 +++ libvirt/src/xend_internal.c 7 Mar 2007 08:28:55 -0000 @@ -1666,6 +1666,13 @@ xend_parse_sexp_desc(virConnectPtr conn, free(tty); } + tmp = sexpr_node(root, "domain/image/hvm/usbdevice"); + if ((tmp != NULL) && (tmp[0] != 0)) { + virBufferVSprintf(&buf, " <usb usbdevice='%s'/>\n", tmp); + } else if (sexpr_int(root, "domain/image/hvm/usb")) { + virBufferAdd(&buf, " <usb/>\n", 11 ); + } + virBufferAdd(&buf, " </devices>\n", 13); virBufferAdd(&buf, "</domain>\n", 10); Index: libvirt/src/xml.c =================================================================== RCS file: /data/cvs/libvirt/src/xml.c,v retrieving revision 1.62 diff -u -p -r1.62 xml.c --- libvirt/src/xml.c 6 Mar 2007 20:00:17 -0000 1.62 +++ libvirt/src/xml.c 7 Mar 2007 08:28:55 -0000 @@ -524,6 +524,20 @@ virDomainParseXMLOSDescHVM(virConnectPtr } xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "/domain/devices/usb", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { + virBufferAdd(buf, "(usb 1)", 7); + xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/@usbdevice)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, "(usbdevice '%s')", obj->stringval); + } + } + if (obj) + xmlXPathFreeObject(obj); + virBufferAdd(buf, "))", 2); if (boot_dev)

On Thu, Mar 08, 2007 at 04:52:43PM +0900, Masayuki Sunou wrote:
Hi
When domHVM started by virsh create, the information of USB setting is not saved by vish dumpxml. The reason is that USB setting is defined by Xen itself, not virsh.
This patch enables USB device setting information handling on virsh create/virsh dumpxml.
I've been wondering about how we'll represent USB devices in the libvirt XML. The 'usbdevice' attribute in teh XenD SEXPR is just a straight pass-through to QEMU's -usbdevice command line arg. This arg can accept values of the form: - 'mouse' - 'tablet' - 'disk:file' eg 'disk:/var/lib/xen/images/usbdrive.img' - 'host:bus.addr' eg 'host:01.02' for BUS 01, device 02 - 'host:vendor:product' eg 'host:0324:01a4' http://fabrice.bellard.free.fr/qemu/qemu-doc.html#SEC34 The patch you've got just puts all this into a single 'usbdevice' attribute on a <usb> element. I see there is also a single empty <usb> tag to identify whether the virtual USB bus is enabled at all. So we have <usb/> <usb usbdevice='mouse'/> <usb usbdevice='tablet/> <usb usbdevice='disk:/var/lib/xen/images/usbdrive.img'/> <usb usbdevice='host:01.02'/> <usb usbdevice='host:0324:01a4'/> I'm wondering if we'd be better offnormalizing the attributes somewhat. <usb bus='1'/> <usb hid='mouse'/> (hid is USB speak for Human Input Device) <usb hid='tablet'/> <usb disk='/var/lib/xen/images/usbdrive.img'/> <usb bus='01' addr='02'/> <usb vendor='0324' product='01a4'/> Or alternatively, multiplex off a 'type' attribute <usb type='bus'/> <usb type='mouse'/> <usb type='tablet'/> <usb type='disk' path='/var/lib/xen/images/usbdrive.img'/> <usb type='host' bus='01' addr='02'/> <usb type='host' vendor='0324' product='01a4'> What do people think ? Regards, Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Thu, Mar 08, 2007 at 12:59:30PM +0000, Daniel P. Berrange wrote:
On Thu, Mar 08, 2007 at 04:52:43PM +0900, Masayuki Sunou wrote:
Hi
When domHVM started by virsh create, the information of USB setting is not saved by vish dumpxml. The reason is that USB setting is defined by Xen itself, not virsh.
This patch enables USB device setting information handling on virsh create/virsh dumpxml.
I've been wondering about how we'll represent USB devices in the libvirt XML. The 'usbdevice' attribute in teh XenD SEXPR is just a straight pass-through to QEMU's -usbdevice command line arg. This arg can accept values of the form:
- 'mouse' - 'tablet' - 'disk:file' eg 'disk:/var/lib/xen/images/usbdrive.img' - 'host:bus.addr' eg 'host:01.02' for BUS 01, device 02 - 'host:vendor:product' eg 'host:0324:01a4'
http://fabrice.bellard.free.fr/qemu/qemu-doc.html#SEC34
The patch you've got just puts all this into a single 'usbdevice' attribute on a <usb> element. I see there is also a single empty <usb> tag to identify whether the virtual USB bus is enabled at all. So we have
<usb/> <usb usbdevice='mouse'/> <usb usbdevice='tablet/> <usb usbdevice='disk:/var/lib/xen/images/usbdrive.img'/> <usb usbdevice='host:01.02'/> <usb usbdevice='host:0324:01a4'/>
I'm wondering if we'd be better offnormalizing the attributes somewhat.
<usb bus='1'/> <usb hid='mouse'/> (hid is USB speak for Human Input Device) <usb hid='tablet'/> <usb disk='/var/lib/xen/images/usbdrive.img'/> <usb bus='01' addr='02'/> <usb vendor='0324' product='01a4'/>
Or alternatively, multiplex off a 'type' attribute
<usb type='bus'/> <usb type='mouse'/> <usb type='tablet'/> <usb type='disk' path='/var/lib/xen/images/usbdrive.img'/> <usb type='host' bus='01' addr='02'/> <usb type='host' vendor='0324' product='01a4'>
What do people think ?
That I prefer we first discuss a bit more the format before applying such a patch. I assume the usb description need to go in the <devices> block, right ? I prefer the last version of the 3, you just check for a first attribute and if found derive the processing code according to the value. It's IMHO better than the second structurally speaking, and I really dislike the first because it keeps the structure outside of XML which requires additional parsing and makes things harder. Now thinking out loud a bit, would <usb> need to be a structure, physically it is structured around busses, do we need to reflect that, do we need to make provision for this. Also in what respect is USB specific, I mean <devices> <disk path="..." /> </devices> and <devices> <usb> <disk path="..." /> </usb> </devices> Can we just share parsing or is the fact that a disk hooked on USB bus such a real difference ? Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

Hi Daniel I examined your suggestions, and corrected the patch as follows. ・ only (usb 1) <usb> <bus/> </usb> ・ (usbdevice mouse) <usb> <mouse/> </usb> ・ (usbdevice tablet) <usb> <tablet/> </usb> ・ (usbdevice disk:xxx) <usb> <disk> <source dev='xxx'/> </disk> </usb> ・ (usbdevice host:xxx.yyy) <usb> <host bus='xxx' addr='yyy'/> </usb> ・ (usbdevice host:xxx:yyy) <usb> <host vendor='xxx' product='yyy'/> </usb>
Can we just share parsing or is the fact that a disk hooked on USB bus such a real difference ?
I think that dividing usual disk and disk of USB is necessary. Because USB enables a dynamic detaching of disk though usual disk cannot do it by domHVM. Signed-off-by: Masayuki Sunou <fj1826dm@aa.jp.fujitsu.com> Thanks -------------------------------------------------------------------------------- Index: src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.101 diff -u -p -r1.101 xend_internal.c --- src/xend_internal.c 8 Mar 2007 14:12:06 -0000 1.101 +++ src/xend_internal.c 13 Mar 2007 05:33:33 -0000 @@ -1668,6 +1668,49 @@ xend_parse_sexp_desc(virConnectPtr conn, free(tty); } + tmp = sexpr_node(root, "domain/image/hvm/usbdevice"); + if ((tmp != NULL) && (tmp[0] != 0)) { + char *offset; + virBufferAdd(&buf, " <usb>\n", 10 ); + if (strncmp(tmp, "disk:", 5) == 0) { + offset = strtok((char *)tmp, ":"); + if ((offset = strtok(NULL, ":")) != NULL) { + virBufferAdd(&buf, " <disk>\n", 13 ); + virBufferVSprintf(&buf, " <source dev='%s'/>\n", offset); + virBufferAdd(&buf, " </disk>\n", 14 ); + } + } else if (strncmp(tmp, "host:", 5) == 0) { + if (strrchr(tmp, ':') > (tmp + 4)) { + offset = strtok((char *)tmp, ":"); + if ((offset = strtok(NULL, ":")) != NULL) { + virBufferVSprintf(&buf, " <host vendor='%s'", offset); + if ((offset = strtok(NULL, ":")) != NULL) { + virBufferVSprintf(&buf, " product='%s'", offset); + } + virBufferAdd(&buf, "/>\n", 3 ); + } + } else { + offset = strtok((char *)tmp, ":."); + if ((offset = strtok(NULL, ":.")) != NULL) { + virBufferVSprintf(&buf, " <host bus='%s'", offset); + if ((offset = strtok(NULL, ":.")) != NULL) { + virBufferVSprintf(&buf, " addr='%s'", offset); + } + virBufferAdd(&buf, "/>\n", 3 ); + } + } + } else if (strncmp(tmp, "mouse", 5) == 0) { + virBufferAdd(&buf, " <mouse/>\n", 15 ); + } else if (strncmp(tmp, "tablet", 6) == 0) { + virBufferAdd(&buf, " <tablet/>\n", 16 ); + } + virBufferAdd(&buf, " </usb>\n", 11 ); + } else if (sexpr_int(root, "domain/image/hvm/usb")) { + virBufferAdd(&buf, " <usb>\n", 10 ); + virBufferAdd(&buf, " <bus/>\n", 13 ); + virBufferAdd(&buf, " </usb>\n", 11 ); + } + virBufferAdd(&buf, " </devices>\n", 13); virBufferAdd(&buf, "</domain>\n", 10); Index: src/xml.c =================================================================== RCS file: /data/cvs/libvirt/src/xml.c,v retrieving revision 1.64 diff -u -p -r1.64 xml.c --- src/xml.c 8 Mar 2007 14:12:06 -0000 1.64 +++ src/xml.c 13 Mar 2007 05:33:37 -0000 @@ -524,6 +524,66 @@ virDomainParseXMLOSDescHVM(virConnectPtr } xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "/domain/devices/usb", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { + virBufferAdd(buf, "(usb 1)", 7); + xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/disk/source/@dev)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, "(usbdevice 'disk:%s')", obj->stringval); + } + if (obj) + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/host/@vendor)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, "(usbdevice 'host:%s", obj->stringval); + xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/host/@product)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, ":%s", obj->stringval); + } + virBufferAdd(buf, "')", 2); + } + if (obj) + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/host/@bus)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, "(usbdevice 'host:%s", obj->stringval); + xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/host/@addr)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, ".%s", obj->stringval); + } + virBufferAdd(buf, "')", 2); + } + if (obj) + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "/domain/devices/usb/mouse", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { + virBufferAdd(buf, "(usbdevice 'mouse')", 19); + } + if (obj) + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "/domain/devices/usb/tablet", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { + virBufferAdd(buf, "(usbdevice 'tablet')", 20); + } + } + if (obj) + xmlXPathFreeObject(obj); + virBufferAdd(buf, "))", 2); if (boot_dev) -------------------------------------------------------------------------------- In message <20070308142704.GB26337@redhat.com> "Re: [Libvir] [PATCH] Enable USB device setting information handling on virsh." "Daniel Veillard <veillard@redhat.com>" wrote:
On Thu, Mar 08, 2007 at 12:59:30PM +0000, Daniel P. Berrange wrote:
On Thu, Mar 08, 2007 at 04:52:43PM +0900, Masayuki Sunou wrote:
Hi
When domHVM started by virsh create, the information of USB setting is not saved by vish dumpxml. The reason is that USB setting is defined by Xen itself, not virsh.
This patch enables USB device setting information handling on virsh create/virsh dumpxml.
I've been wondering about how we'll represent USB devices in the libvirt XML. The 'usbdevice' attribute in teh XenD SEXPR is just a straight pass-through to QEMU's -usbdevice command line arg. This arg can accept values of the form:
- 'mouse' - 'tablet' - 'disk:file' eg 'disk:/var/lib/xen/images/usbdrive.img' - 'host:bus.addr' eg 'host:01.02' for BUS 01, device 02 - 'host:vendor:product' eg 'host:0324:01a4'
http://fabrice.bellard.free.fr/qemu/qemu-doc.html#SEC34
The patch you've got just puts all this into a single 'usbdevice' attribute on a <usb> element. I see there is also a single empty <usb> tag to identify whether the virtual USB bus is enabled at all. So we have
<usb/> <usb usbdevice='mouse'/> <usb usbdevice='tablet/> <usb usbdevice='disk:/var/lib/xen/images/usbdrive.img'/> <usb usbdevice='host:01.02'/> <usb usbdevice='host:0324:01a4'/>
I'm wondering if we'd be better offnormalizing the attributes somewhat.
<usb bus='1'/> <usb hid='mouse'/> (hid is USB speak for Human Input Device) <usb hid='tablet'/> <usb disk='/var/lib/xen/images/usbdrive.img'/> <usb bus='01' addr='02'/> <usb vendor='0324' product='01a4'/>
Or alternatively, multiplex off a 'type' attribute
<usb type='bus'/> <usb type='mouse'/> <usb type='tablet'/> <usb type='disk' path='/var/lib/xen/images/usbdrive.img'/> <usb type='host' bus='01' addr='02'/> <usb type='host' vendor='0324' product='01a4'>
What do people think ?
That I prefer we first discuss a bit more the format before applying such a patch. I assume the usb description need to go in the <devices> block, right ? I prefer the last version of the 3, you just check for a first attribute and if found derive the processing code according to the value. It's IMHO better than the second structurally speaking, and I really dislike the first because it keeps the structure outside of XML which requires additional parsing and makes things harder. Now thinking out loud a bit, would <usb> need to be a structure, physically it is structured around busses, do we need to reflect that, do we need to make provision for this. Also in what respect is USB specific, I mean <devices> <disk path="..." /> </devices> and <devices> <usb> <disk path="..." /> </usb> </devices>
Can we just share parsing or is the fact that a disk hooked on USB bus such a real difference ?
Daniel
-- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

On Tue, Mar 13, 2007 at 05:50:38PM +0900, Masayuki Sunou wrote:
Hi Daniel
I examined your suggestions, and corrected the patch as follows. ・ only (usb 1) <usb> <bus/> </usb>
・ (usbdevice mouse) <usb> <mouse/> </usb>
・ (usbdevice tablet) <usb> <tablet/> </usb>
・ (usbdevice disk:xxx) <usb> <disk> <source dev='xxx'/> </disk> </usb>
・ (usbdevice host:xxx.yyy) <usb> <host bus='xxx' addr='yyy'/> </usb>
・ (usbdevice host:xxx:yyy) <usb> <host vendor='xxx' product='yyy'/> </usb>
okay that looks fine to me
Can we just share parsing or is the fact that a disk hooked on USB bus such a real difference ?
I think that dividing usual disk and disk of USB is necessary. Because USB enables a dynamic detaching of disk though usual disk cannot do it by domHVM.
okay, fair enough.
+ offset = strtok((char *)tmp, ":");
Sorry you can't use strtok there, it's not reentrant, uses a global variable and as a result multiple concurent threads accessing libvirt for different connections may get their data randomly corrupted, this is a big problem. I prefer parsing to be done explicitely computing indexes from the string being parsed (and then you can use strndup() to generate copies if needed).
+ if ((offset = strtok(NULL, ":")) != NULL) { + virBufferAdd(&buf, " <disk>\n", 13 ); + virBufferVSprintf(&buf, " <source dev='%s'/>\n", offset); + virBufferAdd(&buf, " </disk>\n", 14 ); + }
plus offset would not been freed here, so that would be a memory leak too,
+ } else if (strncmp(tmp, "host:", 5) == 0) { + if (strrchr(tmp, ':') > (tmp + 4)) { + offset = strtok((char *)tmp, ":"); + if ((offset = strtok(NULL, ":")) != NULL) { + virBufferVSprintf(&buf, " <host vendor='%s'", offset); + if ((offset = strtok(NULL, ":")) != NULL) { + virBufferVSprintf(&buf, " product='%s'", offset); + } + virBufferAdd(&buf, "/>\n", 3 ); + } + } else { + offset = strtok((char *)tmp, ":."); + if ((offset = strtok(NULL, ":.")) != NULL) { + virBufferVSprintf(&buf, " <host bus='%s'", offset); + if ((offset = strtok(NULL, ":.")) != NULL) { + virBufferVSprintf(&buf, " addr='%s'", offset); + } + virBufferAdd(&buf, "/>\n", 3 ); + } + } + } else if (strncmp(tmp, "mouse", 5) == 0) { + virBufferAdd(&buf, " <mouse/>\n", 15 ); + } else if (strncmp(tmp, "tablet", 6) == 0) { + virBufferAdd(&buf, " <tablet/>\n", 16 ); + } + virBufferAdd(&buf, " </usb>\n", 11 ); + } else if (sexpr_int(root, "domain/image/hvm/usb")) { + virBufferAdd(&buf, " <usb>\n", 10 ); + virBufferAdd(&buf, " <bus/>\n", 13 ); + virBufferAdd(&buf, " </usb>\n", 11 ); + } + virBufferAdd(&buf, " </devices>\n", 13); virBufferAdd(&buf, "</domain>\n", 10);
Index: src/xml.c =================================================================== RCS file: /data/cvs/libvirt/src/xml.c,v retrieving revision 1.64 diff -u -p -r1.64 xml.c
the patch for xml.c looks good to me, but I would rather apply both at the same time. Could you regenerate a patch doing the same but avoiding strtok (I'm not too fond of strtok_r() either). thanks in advance ! Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

On Tue, Mar 13, 2007 at 12:12:56PM -0400, Daniel Veillard wrote:
On Tue, Mar 13, 2007 at 05:50:38PM +0900, Masayuki Sunou wrote:
Hi Daniel
I examined your suggestions, and corrected the patch as follows. ??? only (usb 1) <usb> <bus/> </usb>
??? (usbdevice mouse) <usb> <mouse/> </usb>
??? (usbdevice tablet) <usb> <tablet/> </usb>
??? (usbdevice disk:xxx) <usb> <disk> <source dev='xxx'/> </disk> </usb>
??? (usbdevice host:xxx.yyy) <usb> <host bus='xxx' addr='yyy'/> </usb>
??? (usbdevice host:xxx:yyy) <usb> <host vendor='xxx' product='yyy'/> </usb>
okay that looks fine to me
I'm not so sure about this to be honest. This is very verbose syntax and having the empty <usb> wrapper around every element isn't adding all that much useful info in relation to its verbosity. I've been thinking about how the contents of the <devices> section relates to the way Linux models devices in sysfs. Thus far we have 'interface', 'disk' 'console' and 'graphics'. - The 'disk' element maps onto /sys/block or /sys/class/scsi_disk - The 'interface' element maps onto /sys/class/net - The 'graphics' element maps onto /sys/class/graphics - The 'console' element maps onto /sys/class/misc I tend to think of /sys/block as really being a class too (ie /sys/class/block). With the way we've been thinking about USB in this thread so far though, we're approaching a model that is much more like /sys/bus rather than /sys/class. ie we're grouping everything under a bus type at the top level, rather than the rest of the nodes which are grouped by class (function). Listing again at what things we need to represent here: - Input devices - mouse, tablet - Disk devices - Presence of USB or not (aka whether a bus is emulated) - Pass through of devices from the host bus Now consider a couple of non-USB related things we don't have representations for yet - VMWare mouse type - Summa graphics tablet - a serial device tablet - PS/2 mouse - implicitly represented if we don't ask for any other mouse - PCI device pass through from host - Serial ports - Parallel ports - Sound cards Basically we end up with two sorts of things we need to represent: - Emulation of particular classes of devices grouped by their function - Pass through of real hardware, irrespective of function Based on this observation I think we need to actually treat the Xen USB configs in two different ways according to the above split. So USB disks might look like <disk type='file' device='disk'> <source file='/some/path.img'/> <target dev='usb'/> </disk> NB, I'm using a generic 'usb' tag as the guest device name, since USB devices are fundamentally hotplug oriented it is very unsual to have persistent USB bus IDs and thus you'll never have a persistent device node. Maybe its better to have a separate named attribute instead of re-using the 'dev' attribute in <target>: <disk type='file' device='disk'> <source file='/some/path.img'/> <target bus='usb'/> </disk> Or a separate bus type ? <disk type='file' device='disk'> <source file='/some/path.img'/> <bus type='usb'/> </disk> Anyway, now onto input devices. It would seem like a reasonable idea to have a top level '<input>' device element. So a generic USB mouse could be <input type='usbmouse'/> While a tablet would be <input type='usbtablet'/> Alternatively we could be explicit about the particular type of device / named model being emulated, eg for the USB tablet: <input type='evtouch'/> The downside with the latter is that its probably different device name for every different virt system. If we just kept a generic 'usbmouse' it would represent 'whatever particular usb mouse the virt system supports'. My final thought is that we could have 'typoe' be compulsory representing the type of pointer. And then 'bus' and 'model' could be optional atttributes to give more specific info if needed, eg for tablets these are equivalent: <input type='tablet'/> <input bus='serial' type='tablet'/> <input bus='serial' type='tablet' model='summagraphics'/> <input type='tablet' model='summagraphics'/> And these are equivalent: <input type='tablet' model='evtouch'/> <input bus='usb' type='tablet'/> <input bus='usb' type='tablet' model='evtouch'/> When creating a domain, the caller could leave out 'bus' or 'model' if they don't care about specific details. When asking libvirt for an XML dump of a running domain though, we'd fill in the most specific info we have. Finally, for the mapping of host devices through to the guest. In this case we probably do just want to group stuff under either a bus specific node, eg <usb> <host vendor='0234' model='2342'/> <host vendor='1248' model='4228'/> <host bus='03' device='02'/> </usb> <pci> <host id='0000:00:1f.1'/> </pci> Or a generic bus node <bus type='usb'> <host vendor='0234' model='2342'/> <host vendor='1248' model='4228'/> <host bus='03' device='02'/> </bus> <bus type='pci'> <host id='0000:00:1f.1'/> </bus>
Can we just share parsing or is the fact that a disk hooked on USB bus such a real difference ?
I think that dividing usual disk and disk of USB is necessary. Because USB enables a dynamic detaching of disk though usual disk cannot do it by domHVM.
okay, fair enough.
That's not entirely accurate - we can already do dynamic hotplug add & remove for <disk> devices on paravirt - that Xen cannot currently do it for fully virt is really just an artifact of the particular implementation. If fact if you use paravirt drivers for fully-virt / HVM you *can* do disk & network hotplug. This email was *significantly* longer than I thought it would be. I guess that's good because it shows there's some non-trivial decisions we should make before committing to a particular style of implementation. I want to ask do a little research of the way USB / PCI devices are expressed with VMWare config files, and with the XenAPI XML-RPC format in case there's any useful stuff we can learn from the way they model devices. Regards, Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|

On Wed, Mar 14, 2007 at 03:38:02AM +0000, Daniel P. Berrange wrote:
I'm not so sure about this to be honest. This is very verbose syntax and having the empty <usb> wrapper around every element isn't adding all that much useful info in relation to its verbosity.
I based my review on the structure, this was looking flexible enough to not raise big problem, but I didn't tried to make a global analysis, thanks for doing this !
I've been thinking about how the contents of the <devices> section relates to the way Linux models devices in sysfs. Thus far we have 'interface', 'disk' 'console' and 'graphics'.
- The 'disk' element maps onto /sys/block or /sys/class/scsi_disk - The 'interface' element maps onto /sys/class/net - The 'graphics' element maps onto /sys/class/graphics - The 'console' element maps onto /sys/class/misc
I tend to think of /sys/block as really being a class too (ie /sys/class/block).
With the way we've been thinking about USB in this thread so far though, we're approaching a model that is much more like /sys/bus rather than /sys/class. ie we're grouping everything under a bus type at the top level, rather than the rest of the nodes which are grouped by class (function).
Listing again at what things we need to represent here:
- Input devices - mouse, tablet - Disk devices - Presence of USB or not (aka whether a bus is emulated) - Pass through of devices from the host bus
Now consider a couple of non-USB related things we don't have representations for yet
- VMWare mouse type - Summa graphics tablet - a serial device tablet - PS/2 mouse - implicitly represented if we don't ask for any other mouse - PCI device pass through from host - Serial ports - Parallel ports - Sound cards
Basically we end up with two sorts of things we need to represent:
- Emulation of particular classes of devices grouped by their function - Pass through of real hardware, irrespective of function
Based on this observation I think we need to actually treat the Xen USB configs in two different ways according to the above split.
yes that look nicer in the long term
So USB disks might look like
<disk type='file' device='disk'> <source file='/some/path.img'/> <target dev='usb'/> </disk>
NB, I'm using a generic 'usb' tag as the guest device name, since USB devices are fundamentally hotplug oriented it is very unsual to have persistent USB bus IDs and thus you'll never have a persistent device node. Maybe its better to have a separate named attribute instead of re-using the 'dev' attribute in <target>:
<disk type='file' device='disk'> <source file='/some/path.img'/> <target bus='usb'/> </disk>
Or a separate bus type ?
<disk type='file' device='disk'> <source file='/some/path.img'/> <bus type='usb'/> </disk>
I'm not sure this really adds much over <target dev='usb'/>, we can still add extra attributes if needed onto target in the usb case.
Anyway, now onto input devices. It would seem like a reasonable idea to have a top level '<input>' device element.
Yes, but when you mean top level you really mean as child of <devices>, I see why an input would be any different, right ?
So a generic USB mouse could be
<input type='usbmouse'/>
While a tablet would be
<input type='usbtablet'/>
Alternatively we could be explicit about the particular type of device / named model being emulated, eg for the USB tablet:
<input type='evtouch'/>
The downside with the latter is that its probably different device name for every different virt system. If we just kept a generic 'usbmouse' it would represent 'whatever particular usb mouse the virt system supports'.
My final thought is that we could have 'typoe' be compulsory representing the type of pointer. And then 'bus' and 'model' could be optional atttributes to give more specific info if needed, eg for tablets these are equivalent:
<input type='tablet'/> <input bus='serial' type='tablet'/> <input bus='serial' type='tablet' model='summagraphics'/> <input type='tablet' model='summagraphics'/>
And these are equivalent:
<input type='tablet' model='evtouch'/> <input bus='usb' type='tablet'/> <input bus='usb' type='tablet' model='evtouch'/>
looks good to me
When creating a domain, the caller could leave out 'bus' or 'model' if they don't care about specific details. When asking libvirt for an XML dump of a running domain though, we'd fill in the most specific info we have.
Finally, for the mapping of host devices through to the guest. In this case we probably do just want to group stuff under either a bus specific node, eg
<usb> <host vendor='0234' model='2342'/> <host vendor='1248' model='4228'/> <host bus='03' device='02'/> </usb>
<pci> <host id='0000:00:1f.1'/> </pci>
Or a generic bus node
<bus type='usb'> <host vendor='0234' model='2342'/> <host vendor='1248' model='4228'/> <host bus='03' device='02'/> </bus>
<bus type='pci'> <host id='0000:00:1f.1'/> </bus>
I prefer the later, it's a bit more structured.
This email was *significantly* longer than I thought it would be. I guess that's good because it shows there's some non-trivial decisions we should make before committing to a particular style of implementation. I want to ask do a little research of the way USB / PCI devices are expressed with VMWare config files, and with the XenAPI XML-RPC format in case there's any useful stuff we can learn from the way they model devices.
yes thanks for getting deeper on this ! Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

Hi Daniel I contribute some corrected patches. 1. strtok() --> strtok_r() --> Add tok_buf for strtok_r() 2. Correct the first argument of strtok_r() 3. Add a version of XML --> So that the format of XML may change in the future Signed-off-by: Masayuki Sunou <fj1826dm@aa.jp.fujitsu.com> Thanks ------------------------------------------------------------------------------- Index: libvirt/include/libvirt/libvirt.h =================================================================== RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h,v retrieving revision 1.40 diff -u -p -r1.40 libvirt.h --- libvirt/include/libvirt/libvirt.h 8 Mar 2007 08:31:07 -0000 1.40 +++ libvirt/include/libvirt/libvirt.h 15 Mar 2007 06:09:16 -0000 @@ -221,6 +221,12 @@ int virGetVersion (unsigned long *lib unsigned long *typeVer); /* + * Macro providing the version of the XML + */ +#define XML_VERSION_NUMBER 1 + + +/* * Connection and disconnections to the Hypervisor */ int virInitialize (void); Index: libvirt/src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.102 diff -u -p -r1.102 xend_internal.c --- libvirt/src/xend_internal.c 14 Mar 2007 13:14:51 -0000 1.102 +++ libvirt/src/xend_internal.c 15 Mar 2007 06:09:23 -0000 @@ -1344,7 +1344,7 @@ xend_parse_sexp_desc(virConnectPtr conn, domid = sexpr_int(root, "domain/domid"); else domid = -1; - virBufferVSprintf(&buf, "<domain type='xen' id='%d'>\n", domid); + virBufferVSprintf(&buf, "<domain type='xen' id='%d' version='%d'>\n", domid, XML_VERSION_NUMBER); tmp = sexpr_node(root, "domain/name"); if (tmp == NULL) { @@ -1668,6 +1668,57 @@ xend_parse_sexp_desc(virConnectPtr conn, free(tty); } + tmp = sexpr_node(root, "domain/image/hvm/usbdevice"); + if ((tmp != NULL) && (tmp[0] != 0)) { + char *offset; + char *tmp_buf; + char *tok_buf; + virBufferAdd(&buf, " <usb>\n", 10 ); + if (strncmp(tmp, "disk:", 5) == 0) { + tmp_buf = strdup(tmp); + offset = strtok_r(tmp_buf, ":", &tok_buf); + if ((offset = strtok_r(NULL, ":", &tok_buf)) != NULL) { + virBufferAdd(&buf, " <disk>\n", 13 ); + virBufferVSprintf(&buf, " <source dev='%s'/>\n", offset); + virBufferAdd(&buf, " </disk>\n", 14 ); + } + free(tmp_buf); + } else if (strncmp(tmp, "host:", 5) == 0) { + if (strrchr(tmp, ':') > (tmp + 4)) { + tmp_buf = strdup(tmp); + offset = strtok_r(tmp_buf, ":", &tok_buf); + if ((offset = strtok_r(NULL, ":", &tok_buf)) != NULL) { + virBufferVSprintf(&buf, " <host vendor='%s'", offset); + if ((offset = strtok_r(NULL, ":", &tok_buf)) != NULL) { + virBufferVSprintf(&buf, " product='%s'", offset); + } + virBufferAdd(&buf, "/>\n", 3 ); + } + free(tmp_buf); + } else { + tmp_buf = strdup(tmp); + offset = strtok_r(tmp_buf, ":.", &tok_buf); + if ((offset = strtok_r(NULL, ":.", &tok_buf)) != NULL) { + virBufferVSprintf(&buf, " <host bus='%s'", offset); + if ((offset = strtok_r(NULL, ":.", &tok_buf)) != NULL) { + virBufferVSprintf(&buf, " addr='%s'", offset); + } + virBufferAdd(&buf, "/>\n", 3 ); + } + free(tmp_buf); + } + } else if (strncmp(tmp, "mouse", 5) == 0) { + virBufferAdd(&buf, " <mouse/>\n", 15 ); + } else if (strncmp(tmp, "tablet", 6) == 0) { + virBufferAdd(&buf, " <tablet/>\n", 16 ); + } + virBufferAdd(&buf, " </usb>\n", 11 ); + } else if (sexpr_int(root, "domain/image/hvm/usb")) { + virBufferAdd(&buf, " <usb>\n", 10 ); + virBufferAdd(&buf, " <bus/>\n", 13 ); + virBufferAdd(&buf, " </usb>\n", 11 ); + } + virBufferAdd(&buf, " </devices>\n", 13); virBufferAdd(&buf, "</domain>\n", 10); Index: libvirt/src/xml.c =================================================================== RCS file: /data/cvs/libvirt/src/xml.c,v retrieving revision 1.64 diff -u -p -r1.64 xml.c --- libvirt/src/xml.c 8 Mar 2007 14:12:06 -0000 1.64 +++ libvirt/src/xml.c 15 Mar 2007 06:09:27 -0000 @@ -524,6 +524,66 @@ virDomainParseXMLOSDescHVM(virConnectPtr } xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "/domain/devices/usb", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { + virBufferAdd(buf, "(usb 1)", 7); + xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/disk/source/@dev)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, "(usbdevice 'disk:%s')", obj->stringval); + } + if (obj) + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/host/@vendor)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, "(usbdevice 'host:%s", obj->stringval); + xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/host/@product)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, ":%s", obj->stringval); + } + virBufferAdd(buf, "')", 2); + } + if (obj) + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/host/@bus)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, "(usbdevice 'host:%s", obj->stringval); + xmlXPathFreeObject(obj); + obj = xmlXPathEval(BAD_CAST "string(/domain/devices/usb/host/@addr)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + virBufferVSprintf(buf, ".%s", obj->stringval); + } + virBufferAdd(buf, "')", 2); + } + if (obj) + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "/domain/devices/usb/mouse", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { + virBufferAdd(buf, "(usbdevice 'mouse')", 19); + } + if (obj) + xmlXPathFreeObject(obj); + + obj = xmlXPathEval(BAD_CAST "/domain/devices/usb/tablet", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { + virBufferAdd(buf, "(usbdevice 'tablet')", 20); + } + } + if (obj) + xmlXPathFreeObject(obj); + virBufferAdd(buf, "))", 2); if (boot_dev) ------------------------------------------------------------------------------- In message <20070314155441.GI3127@redhat.com> "Re: [Libvir] [PATCH] Enable USB device setting information handling on virsh." "Daniel Veillard <veillard@redhat.com>" wrote:
On Wed, Mar 14, 2007 at 03:38:02AM +0000, Daniel P. Berrange wrote:
I'm not so sure about this to be honest. This is very verbose syntax and having the empty <usb> wrapper around every element isn't adding all that much useful info in relation to its verbosity.
I based my review on the structure, this was looking flexible enough to not raise big problem, but I didn't tried to make a global analysis, thanks for doing this !
I've been thinking about how the contents of the <devices> section relates to the way Linux models devices in sysfs. Thus far we have 'interface', 'disk' 'console' and 'graphics'.
- The 'disk' element maps onto /sys/block or /sys/class/scsi_disk - The 'interface' element maps onto /sys/class/net - The 'graphics' element maps onto /sys/class/graphics - The 'console' element maps onto /sys/class/misc
I tend to think of /sys/block as really being a class too (ie /sys/class/block).
With the way we've been thinking about USB in this thread so far though, we're approaching a model that is much more like /sys/bus rather than /sys/class. ie we're grouping everything under a bus type at the top level, rather than the rest of the nodes which are grouped by class (function).
Listing again at what things we need to represent here:
- Input devices - mouse, tablet - Disk devices - Presence of USB or not (aka whether a bus is emulated) - Pass through of devices from the host bus
Now consider a couple of non-USB related things we don't have representations for yet
- VMWare mouse type - Summa graphics tablet - a serial device tablet - PS/2 mouse - implicitly represented if we don't ask for any other mouse - PCI device pass through from host - Serial ports - Parallel ports - Sound cards
Basically we end up with two sorts of things we need to represent:
- Emulation of particular classes of devices grouped by their function - Pass through of real hardware, irrespective of function
Based on this observation I think we need to actually treat the Xen USB configs in two different ways according to the above split.
yes that look nicer in the long term
So USB disks might look like
<disk type='file' device='disk'> <source file='/some/path.img'/> <target dev='usb'/> </disk>
NB, I'm using a generic 'usb' tag as the guest device name, since USB devices are fundamentally hotplug oriented it is very unsual to have persistent USB bus IDs and thus you'll never have a persistent device node. Maybe its better to have a separate named attribute instead of re-using the 'dev' attribute in <target>:
<disk type='file' device='disk'> <source file='/some/path.img'/> <target bus='usb'/> </disk>
Or a separate bus type ?
<disk type='file' device='disk'> <source file='/some/path.img'/> <bus type='usb'/> </disk>
I'm not sure this really adds much over <target dev='usb'/>, we can still add extra attributes if needed onto target in the usb case.
Anyway, now onto input devices. It would seem like a reasonable idea to have a top level '<input>' device element.
Yes, but when you mean top level you really mean as child of <devices>, I see why an input would be any different, right ?
So a generic USB mouse could be
<input type='usbmouse'/>
While a tablet would be
<input type='usbtablet'/>
Alternatively we could be explicit about the particular type of device / named model being emulated, eg for the USB tablet:
<input type='evtouch'/>
The downside with the latter is that its probably different device name for every different virt system. If we just kept a generic 'usbmouse' it would represent 'whatever particular usb mouse the virt system supports'.
My final thought is that we could have 'typoe' be compulsory representing the type of pointer. And then 'bus' and 'model' could be optional atttributes to give more specific info if needed, eg for tablets these are equivalent:
<input type='tablet'/> <input bus='serial' type='tablet'/> <input bus='serial' type='tablet' model='summagraphics'/> <input type='tablet' model='summagraphics'/>
And these are equivalent:
<input type='tablet' model='evtouch'/> <input bus='usb' type='tablet'/> <input bus='usb' type='tablet' model='evtouch'/>
looks good to me
When creating a domain, the caller could leave out 'bus' or 'model' if they don't care about specific details. When asking libvirt for an XML dump of a running domain though, we'd fill in the most specific info we have.
Finally, for the mapping of host devices through to the guest. In this case we probably do just want to group stuff under either a bus specific node, eg
<usb> <host vendor='0234' model='2342'/> <host vendor='1248' model='4228'/> <host bus='03' device='02'/> </usb>
<pci> <host id='0000:00:1f.1'/> </pci>
Or a generic bus node
<bus type='usb'> <host vendor='0234' model='2342'/> <host vendor='1248' model='4228'/> <host bus='03' device='02'/> </bus>
<bus type='pci'> <host id='0000:00:1f.1'/> </bus>
I prefer the later, it's a bit more structured.
This email was *significantly* longer than I thought it would be. I guess that's good because it shows there's some non-trivial decisions we should make before committing to a particular style of implementation. I want to ask do a little research of the way USB / PCI devices are expressed with VMWare config files, and with the XenAPI XML-RPC format in case there's any useful stuff we can learn from the way they model devices.
yes thanks for getting deeper on this !
Daniel
-- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

On Thu, Mar 15, 2007 at 05:54:19PM +0900, Masayuki Sunou wrote:
Hi Daniel
I contribute some corrected patches.
1. strtok() --> strtok_r() --> Add tok_buf for strtok_r() 2. Correct the first argument of strtok_r() 3. Add a version of XML --> So that the format of XML may change in the future
Signed-off-by: Masayuki Sunou <fj1826dm@aa.jp.fujitsu.com>
Hi Masayuki, I realized I forgot to answer to that patch. Let's not drop the issue ! The problem is that this new patch still seems to follow the old XML of the initial patch while following Dan Berrange last post it looks better to integrate the USB specific part in other logical blocs. I don't think adding a version number is the right approach, it's better to get the XML set up straight rather than put the burden on long term maintainance and at the user level to decode the different ways to express the same thing. I also don't like strtok_r too much I admit but it's a separate issue :-) Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

Hi, Daniel Thank you for your comments. We never forget this issue. Please give us a time about this. (Since JFY(Japan Finalcial Year) is changed when March 31 to April 1) Thanks Atsushi SAKAI Daniel Veillard <veillard@redhat.com> wrote:
On Thu, Mar 15, 2007 at 05:54:19PM +0900, Masayuki Sunou wrote:
Hi Daniel
I contribute some corrected patches.
1. strtok() --> strtok_r() --> Add tok_buf for strtok_r() 2. Correct the first argument of strtok_r() 3. Add a version of XML --> So that the format of XML may change in the future
Signed-off-by: Masayuki Sunou <fj1826dm@aa.jp.fujitsu.com>
Hi Masayuki,
I realized I forgot to answer to that patch. Let's not drop the issue ! The problem is that this new patch still seems to follow the old XML of the initial patch while following Dan Berrange last post it looks better to integrate the USB specific part in other logical blocs. I don't think adding a version number is the right approach, it's better to get the XML set up straight rather than put the burden on long term maintainance and at the user level to decode the different ways to express the same thing. I also don't like strtok_r too much I admit but it's a separate issue :-)
Daniel
-- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/
-- Libvir-list mailing list Libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Thu, Mar 29, 2007 at 09:03:05PM +0900, Atsushi SAKAI wrote:
Hi, Daniel
Thank you for your comments. We never forget this issue. Please give us a time about this. (Since JFY(Japan Finalcial Year) is changed when March 31 to April 1)
Okay I may look into implementing those, in the next days, then you should be able to check if it works as expected :-) Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/
participants (4)
-
Atsushi SAKAI
-
Daniel P. Berrange
-
Daniel Veillard
-
Masayuki Sunou