[libvirt] [PATCH libvirt 0/9] domain/qemu enhancements

Hi, I have sent those patches before 0.12, and updated them according to comments (hopefully you don't mind I send them all revised in the same thread) They bring: - domain audio <codec> selection, for ICH6 devices - domain port <forward>, for user-mode networking - storage <preallocation> mode for QCOW2 images Marc-André Lureau (9): qemu: test CAPS_HDA_MICRO domain: add <codec> sound sub-element qemu: honour sound <codec> sub-elements tests: add qemu-1.1-rc0 data tests: add ich6 codec type test to qemuxml2argv-sound-device storage: add preallocation element storage: learn to create qcow2 with preallocation domain: add <forward> element for user mode networking qemu: implement user mode port <forward> docs/formatdomain.html.in | 40 +++ docs/formatstorage.html.in | 6 + docs/schemas/domaincommon.rng | 58 +++- docs/schemas/storagevol.rng | 18 ++ src/conf/domain_conf.c | 286 +++++++++++++++++++- src/conf/domain_conf.h | 45 +++ src/conf/storage_conf.c | 26 ++ src/conf/storage_conf.h | 1 + src/libvirt_private.syms | 3 + src/qemu/qemu_capabilities.c | 3 + src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 213 +++++++++++++-- src/storage/storage_backend.c | 70 ++++- src/util/storage_file.c | 4 + src/util/storage_file.h | 10 + tests/qemuhelpdata/qemu-1.1 | 266 ++++++++++++++++++ tests/qemuhelpdata/qemu-1.1-device | 95 +++++++ tests/qemuhelptest.c | 70 +++++ tests/qemuxml2argvdata/qemuxml2argv-net-user.args | 5 +- tests/qemuxml2argvdata/qemuxml2argv-net-user.xml | 2 + .../qemuxml2argv-sound-device.args | 7 +- .../qemuxml2argvdata/qemuxml2argv-sound-device.xml | 7 + tests/qemuxml2argvtest.c | 3 +- tests/qemuxml2xmltest.c | 1 + tests/storagevolxml2xmlin/vol-qcow2.xml | 1 + tests/storagevolxml2xmlout/vol-qcow2.xml | 1 + 26 files changed, 1201 insertions(+), 41 deletions(-) create mode 100644 tests/qemuhelpdata/qemu-1.1 create mode 100644 tests/qemuhelpdata/qemu-1.1-device -- 1.7.10.1

--- src/qemu/qemu_capabilities.c | 3 +++ src/qemu/qemu_capabilities.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 6e5165b..869c55f 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -161,6 +161,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "block-job-async", "scsi-cd", "ide-cd", + "hda-micro" ); struct qemu_feature_flags { @@ -1394,6 +1395,8 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags) /* Which devices exist. */ if (strstr(str, "name \"hda-duplex\"")) qemuCapsSet(flags, QEMU_CAPS_HDA_DUPLEX); + if (strstr(str, "name \"hda-micro\"")) + qemuCapsSet(flags, QEMU_CAPS_HDA_MICRO); if (strstr(str, "name \"ccid-card-emulated\"")) qemuCapsSet(flags, QEMU_CAPS_CCID_EMULATED); if (strstr(str, "name \"ccid-card-passthru\"")) diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 7a6c5a0..3492eb8 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -129,6 +129,7 @@ enum qemuCapsFlags { QEMU_CAPS_BLOCKJOB_ASYNC = 91, /* qemu 1.1 block-job-cancel */ QEMU_CAPS_SCSI_CD = 92, /* -device scsi-cd */ QEMU_CAPS_IDE_CD = 93, /* -device ide-cd */ + QEMU_CAPS_HDA_MICRO = 94, /* -device hda-micro */ QEMU_CAPS_LAST, /* this must always be the last item */ }; -- 1.7.10.1

Allow specifying sound device codecs. See formatdomain.html for more details. --- docs/formatdomain.html.in | 19 +++++++ docs/schemas/domaincommon.rng | 29 +++++++--- src/conf/domain_conf.c | 119 ++++++++++++++++++++++++++++++++++++++++- src/conf/domain_conf.h | 20 +++++++ 4 files changed, 179 insertions(+), 8 deletions(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index da61312..3875167 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -3617,6 +3617,25 @@ qemu-kvm -net nic,model=? /dev/null </dl> <p> + <span class="since">Since 0.9.13</span>, a sound element + with <code>ich6</code> model can have optional + sub-elements <code><codec></code> to attach various audio + codecs to the audio device. If not specified, a default codec + will be attached to allow playback and recording. Valid values + are 'duplex' (advertise a line-in and a line-out) and 'micro' + (advertise a speaker and a microphone). + </p> + +<pre> + ... + <devices> + <sound model='ich6'> + <codec type='micro'/> + <sound/> + </devices> + ...</pre> + + <p> Each <code>sound</code> element has an optional sub-element <code><address></code> which can tie the device to a particular PCI diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 4c4fa6a..34f63c3 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2250,6 +2250,16 @@ </choice> </element> </define> + <define name="codec"> + <element name="codec"> + <attribute name="type"> + <choice> + <value>duplex</value> + <value>micro</value> + </choice> + </attribute> + </element> + </define> <define name="sound"> <element name="sound"> <attribute name="model"> @@ -2261,12 +2271,19 @@ <value>ich6</value> </choice> </attribute> - <optional> - <ref name="alias"/> - </optional> - <optional> - <ref name="address"/> - </optional> + <interleave> + <optional> + <ref name="alias"/> + </optional> + <optional> + <ref name="address"/> + </optional> + <zeroOrMore> + <choice> + <ref name="codec"/> + </choice> + </zeroOrMore> + </interleave> </element> </define> <define name="watchdog"> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 54ac1db..4698c39 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -354,6 +354,10 @@ VIR_ENUM_IMPL(virDomainSmartcard, VIR_DOMAIN_SMARTCARD_TYPE_LAST, "host-certificates", "passthrough") +VIR_ENUM_IMPL(virDomainSoundCodec, VIR_DOMAIN_SOUND_CODEC_TYPE_LAST, + "duplex", + "micro") + VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST, "sb16", "es1370", @@ -1304,6 +1308,14 @@ void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def) VIR_FREE(def); } +void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def); +} + void virDomainSoundDefFree(virDomainSoundDefPtr def) { if (!def) @@ -1311,6 +1323,11 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def) virDomainDeviceInfoClear(&def->info); + int i; + for (i = 0 ; i < def->ncodecs ; i++) + virDomainSoundCodecDefFree(def->codecs[i]); + VIR_FREE(def->codecs); + VIR_FREE(def); } @@ -6345,18 +6362,52 @@ error: } +static virDomainSoundCodecDefPtr +virDomainSoundCodecDefParseXML(const xmlNodePtr node) +{ + char *type; + virDomainSoundCodecDefPtr def; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + type = virXMLPropString(node, "type"); + if ((def->type = virDomainSoundCodecTypeFromString(type)) < 0) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown codec type '%s'"), type); + goto error; + } + +cleanup: + VIR_FREE(type); + + return def; + +error: + virDomainSoundCodecDefFree(def); + def = NULL; + goto cleanup; +} + + static virDomainSoundDefPtr virDomainSoundDefParseXML(const xmlNodePtr node, + xmlXPathContextPtr ctxt, unsigned int flags) { char *model; virDomainSoundDefPtr def; + xmlNodePtr save = ctxt->node; if (VIR_ALLOC(def) < 0) { virReportOOMError(); return NULL; } + ctxt->node = node; + model = virXMLPropString(node, "model"); if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -6364,12 +6415,42 @@ virDomainSoundDefParseXML(const xmlNodePtr node, goto error; } + if (def->model == VIR_DOMAIN_SOUND_MODEL_ICH6) { + int ncodecs; + xmlNodePtr *codecNodes = NULL; + + /* parse the <codec> subelements for sound models that support it */ + ncodecs = virXPathNodeSet("./codec", ctxt, &codecNodes); + if (ncodecs < 0) + goto error; + + if (ncodecs > 0) { + int ii; + + if (VIR_ALLOC_N(def->codecs, ncodecs) < 0) { + virReportOOMError(); + goto error; + } + + for (ii = 0; ii < ncodecs; ii++) { + virDomainSoundCodecDefPtr codec = virDomainSoundCodecDefParseXML(codecNodes[ii]); + if (codec == NULL) + goto error; + + codec->cad = def->ncodecs; /* that will do for now */ + def->codecs[def->ncodecs++] = codec; + } + VIR_FREE(codecNodes); + } + } + if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0) goto error; cleanup: VIR_FREE(model); + ctxt->node = save; return def; error: @@ -6922,7 +7003,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps, goto error; } else if (xmlStrEqual(node->name, BAD_CAST "sound")) { dev->type = VIR_DOMAIN_DEVICE_SOUND; - if (!(dev->data.sound = virDomainSoundDefParseXML(node, flags))) + if (!(dev->data.sound = virDomainSoundDefParseXML(node, ctxt, flags))) goto error; } else if (xmlStrEqual(node->name, BAD_CAST "watchdog")) { dev->type = VIR_DOMAIN_DEVICE_WATCHDOG; @@ -8789,6 +8870,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps, goto no_memory; for (i = 0 ; i < n ; i++) { virDomainSoundDefPtr sound = virDomainSoundDefParseXML(nodes[i], + ctxt, flags); if (!sound) goto error; @@ -11754,11 +11836,30 @@ virDomainSmartcardDefFormat(virBufferPtr buf, } static int +virDomainSoundCodecDefFormat(virBufferPtr buf, + virDomainSoundCodecDefPtr def) +{ + const char *type = virDomainSoundCodecTypeToString(def->type); + + if (!type) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected codec type %d"), def->type); + return -1; + } + + virBufferAsprintf(buf, " <codec type='%s'/>\n", type); + + return 0; +} + +static int virDomainSoundDefFormat(virBufferPtr buf, virDomainSoundDefPtr def, unsigned int flags) { const char *model = virDomainSoundModelTypeToString(def->model); + int children = 0; + int i; if (!model) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -11768,10 +11869,24 @@ virDomainSoundDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " <sound model='%s'", model); + for (i = 0; i < def->ncodecs; i++) { + if (!children) { + virBufferAddLit(buf, ">\n"); + children = 1; + } + virDomainSoundCodecDefFormat(buf, def->codecs[i]); + } + if (virDomainDeviceInfoIsSet(&def->info, flags)) { - virBufferAddLit(buf, ">\n"); + if (!children) { + virBufferAddLit(buf, ">\n"); + children = 1; + } if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0) return -1; + } + + if (children) { virBufferAddLit(buf, " </sound>\n"); } else { virBufferAddLit(buf, "/>\n"); diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 6648a17..70129fe 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -65,6 +65,9 @@ typedef virDomainNetDef *virDomainNetDefPtr; typedef struct _virDomainInputDef virDomainInputDef; typedef virDomainInputDef *virDomainInputDefPtr; +typedef struct _virDomainSoundCodecDef virDomainSoundCodecDef; +typedef virDomainSoundCodecDef *virDomainSoundCodecDefPtr; + typedef struct _virDomainSoundDef virDomainSoundDef; typedef virDomainSoundDef *virDomainSoundDefPtr; @@ -992,6 +995,13 @@ struct _virDomainInputDef { virDomainDeviceInfo info; }; +enum virDomainSoundCodecType { + VIR_DOMAIN_SOUND_CODEC_TYPE_DUPLEX, + VIR_DOMAIN_SOUND_CODEC_TYPE_MICRO, + + VIR_DOMAIN_SOUND_CODEC_TYPE_LAST +}; + enum virDomainSoundModel { VIR_DOMAIN_SOUND_MODEL_SB16, VIR_DOMAIN_SOUND_MODEL_ES1370, @@ -1002,9 +1012,17 @@ enum virDomainSoundModel { VIR_DOMAIN_SOUND_MODEL_LAST }; +struct _virDomainSoundCodecDef { + int type; + int cad; +}; + struct _virDomainSoundDef { int model; virDomainDeviceInfo info; + + int ncodecs; + virDomainSoundCodecDefPtr *codecs; }; enum virDomainWatchdogModel { @@ -1844,6 +1862,7 @@ void virDomainChrDefFree(virDomainChrDefPtr def); void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def); int virDomainChrSourceDefCopy(virDomainChrSourceDefPtr src, virDomainChrSourceDefPtr dest); +void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def); void virDomainSoundDefFree(virDomainSoundDefPtr def); void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def); void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def); @@ -2160,6 +2179,7 @@ VIR_ENUM_DECL(virDomainSmartcard) VIR_ENUM_DECL(virDomainChr) VIR_ENUM_DECL(virDomainChrTcpProtocol) VIR_ENUM_DECL(virDomainChrSpicevmc) +VIR_ENUM_DECL(virDomainSoundCodec) VIR_ENUM_DECL(virDomainSoundModel) VIR_ENUM_DECL(virDomainMemballoonModel) VIR_ENUM_DECL(virDomainSmbiosMode) -- 1.7.10.1

With ICH6 audio device, allow to specify codecs. By default, for compatibility reasons, if no codec is specified, "hda-duplex" will be used. --- src/qemu/qemu_command.c | 74 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 0a85d19..842b0fd 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -89,6 +89,12 @@ VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST, "", /* don't support vbox */ "qxl"); +VIR_ENUM_DECL(qemuSoundCodec) + +VIR_ENUM_IMPL(qemuSoundCodec, VIR_DOMAIN_SOUND_CODEC_TYPE_LAST, + "hda-duplex", + "hda-micro"); + VIR_ENUM_DECL(qemuControllerModelUSB) VIR_ENUM_IMPL(qemuControllerModelUSB, VIR_DOMAIN_CONTROLLER_MODEL_USB_LAST, @@ -2967,21 +2973,43 @@ error: return NULL; } + +static int +qemuSoundCodecTypeToCaps(int type) +{ + switch (type) { + case VIR_DOMAIN_SOUND_CODEC_TYPE_DUPLEX: + return QEMU_CAPS_HDA_DUPLEX; + case VIR_DOMAIN_SOUND_CODEC_TYPE_MICRO: + return QEMU_CAPS_HDA_MICRO; + default: + return -1; + } +} + + static char * qemuBuildSoundCodecStr(virDomainSoundDefPtr sound, - const char *codec) + virDomainSoundCodecDefPtr codec, + virBitmapPtr qemuCaps) { virBuffer buf = VIR_BUFFER_INITIALIZER; - int cad = 0; + const char *stype; + int type, caps; - virBufferAsprintf(&buf, "%s,id=%s-codec%d,bus=%s.0,cad=%d", - codec, sound->info.alias, cad, sound->info.alias, cad); + type = codec->type; + stype = qemuSoundCodecTypeToString(type); + caps = qemuSoundCodecTypeToCaps(type); - if (virBufferError(&buf)) { - virReportOOMError(); + if (caps == -1 || !qemuCapsGet(qemuCaps, caps)) { + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("%s not supported in this QEMU binary"), stype); goto error; } + virBufferAsprintf(&buf, "%s,id=%s-codec%d,bus=%s.0,cad=%d", + stype, sound->info.alias, codec->cad, sound->info.alias, codec->cad); + return virBufferContentAndReset(&buf); error: @@ -5743,20 +5771,30 @@ qemuBuildCommandLine(virConnectPtr conn, if (sound->model == VIR_DOMAIN_SOUND_MODEL_ICH6) { char *codecstr = NULL; - if (!qemuCapsGet(qemuCaps, QEMU_CAPS_HDA_DUPLEX)) { - qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("this QEMU binary lacks hda support")); - goto error; - } + int ii; - virCommandAddArg(cmd, "-device"); - if (!(codecstr = qemuBuildSoundCodecStr(sound, - "hda-duplex"))) { - goto error; - } + for (ii = 0 ; ii < sound->ncodecs ; ii++) { + virCommandAddArg(cmd, "-device"); + if (!(codecstr = qemuBuildSoundCodecStr(sound, sound->codecs[ii], qemuCaps))) { + goto error; - virCommandAddArg(cmd, codecstr); - VIR_FREE(codecstr); + } + virCommandAddArg(cmd, codecstr); + VIR_FREE(codecstr); + } + if (ii == 0) { + virDomainSoundCodecDef codec = { + VIR_DOMAIN_SOUND_CODEC_TYPE_DUPLEX, + 0 + }; + virCommandAddArg(cmd, "-device"); + if (!(codecstr = qemuBuildSoundCodecStr(sound, &codec, qemuCaps))) { + goto error; + + } + virCommandAddArg(cmd, codecstr); + VIR_FREE(codecstr); + } } VIR_FREE(str); -- 1.7.10.1

Generated with qemu-system-x86_64 -device ? -device virtio-blk-pci,? -device virtio-net-pci,? 2> tests/qemuhelpdata/qemu-1.1-device With QEMU v1.1-rc0 --- tests/qemuhelpdata/qemu-1.1 | 266 ++++++++++++++++++++++++++++++++++++ tests/qemuhelpdata/qemu-1.1-device | 95 +++++++++++++ tests/qemuhelptest.c | 70 ++++++++++ 3 files changed, 431 insertions(+) create mode 100644 tests/qemuhelpdata/qemu-1.1 create mode 100644 tests/qemuhelpdata/qemu-1.1-device diff --git a/tests/qemuhelpdata/qemu-1.1 b/tests/qemuhelpdata/qemu-1.1 new file mode 100644 index 0000000..acce237 --- /dev/null +++ b/tests/qemuhelpdata/qemu-1.1 @@ -0,0 +1,266 @@ +QEMU emulator version 1.0.90, Copyright (c) 2003-2008 Fabrice Bellard +usage: qemu-system-x86_64 [options] [disk_image] + +'disk_image' is a raw hard disk image for IDE hard disk 0 + +Standard options: +-h or -help display this help and exit +-version display version information and exit +-machine [type=]name[,prop[=value][,...]] + selects emulated machine (-machine ? for list) + property accel=accel1[:accel2[:...]] selects accelerator + supported accelerators are kvm, xen, tcg (default: tcg) + kernel_irqchip=on|off controls accelerated irqchip support + kvm_shadow_mem=size of KVM shadow MMU +-cpu cpu select CPU (-cpu ? for list) +-smp n[,maxcpus=cpus][,cores=cores][,threads=threads][,sockets=sockets] + set the number of CPUs to 'n' [default=1] + maxcpus= maximum number of total cpus, including + offline CPUs for hotplug, etc + cores= number of CPU cores on one socket + threads= number of threads on one CPU core + sockets= number of discrete sockets in the system +-numa node[,mem=size][,cpus=cpu[-cpu]][,nodeid=node] +-fda/-fdb file use 'file' as floppy disk 0/1 image +-hda/-hdb file use 'file' as IDE hard disk 0/1 image +-hdc/-hdd file use 'file' as IDE hard disk 2/3 image +-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master) +-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i] + [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off] + [,cache=writethrough|writeback|none|directsync|unsafe][,format=f] + [,serial=s][,addr=A][,id=name][,aio=threads|native] + [,readonly=on|off][,copy-on-read=on|off] + [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]][[,iops=i]|[[,iops_rd=r][,iops_wr=w]] + use 'file' as a drive image +-set group.id.arg=value + set <arg> parameter for item <id> of type <group> + i.e. -set drive.$id.file=/path/to/image +-global driver.prop=value + set a global default for a driver property +-mtdblock file use 'file' as on-board Flash memory image +-sd file use 'file' as SecureDigital card image +-pflash file use 'file' as a parallel flash image +-boot [order=drives][,once=drives][,menu=on|off] + [,splash=sp_name][,splash-time=sp_time] + 'drives': floppy (a), hard disk (c), CD-ROM (d), network (n) + 'sp_name': the file's name that would be passed to bios as logo picture, if menu=on + 'sp_time': the period that splash picture last if menu=on, unit is ms +-snapshot write to temporary files instead of disk image files +-m megs set virtual RAM size to megs MB [default=128] +-mem-path FILE provide backing storage for guest RAM +-mem-prealloc preallocate guest memory (use with -mem-path) +-k language use keyboard layout (for example 'fr' for French) +-audio-help print list of audio drivers and their options +-soundhw c1,... enable audio support + and only specified sound cards (comma separated list) + use -soundhw ? to get the list of supported cards + use -soundhw all to enable all of them +-balloon none disable balloon device +-balloon virtio[,addr=str] + enable virtio balloon device (default) +-usb enable the USB driver (will be the default soon) +-usbdevice name add the host or guest USB device 'name' +-device driver[,prop[=value][,...]] + add device (based on driver) + prop=value,... sets driver properties + use -device ? to print all possible drivers + use -device driver,? to print all possible properties + +File system options: +-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}] + [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd] + +Virtual File system pass-through options: +-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none] + [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd] +-virtfs_synth Create synthetic file system image + +-name string1[,process=string2] + set the name of the guest + string1 sets the window title and string2 the process name (on Linux) +-uuid %08x-%04x-%04x-%04x-%012x + specify machine UUID + +Display options: +-display sdl[,frame=on|off][,alt_grab=on|off][,ctrl_grab=on|off] + [,window_close=on|off]|curses|none| + vnc=<display>[,<optargs>] + select display type +-nographic disable graphical output and redirect serial I/Os to console +-curses use a curses/ncurses interface instead of SDL +-no-frame open SDL window without a frame and window decorations +-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt) +-ctrl-grab use Right-Ctrl to grab mouse (instead of Ctrl-Alt) +-no-quit disable SDL window close capability +-sdl enable SDL +-spice <args> enable spice +-portrait rotate graphical output 90 deg left (only PXA LCD) +-rotate <deg> rotate graphical output some deg left (only PXA LCD) +-vga [std|cirrus|vmware|qxl|xenfb|none] + select video card type +-full-screen start in full screen +-vnc display start a VNC server on display + +i386 target only: +-win2k-hack use it when installing Windows 2000 to avoid a disk full bug +-no-fd-bootchk disable boot signature checking for floppy disks +-no-acpi disable ACPI +-no-hpet disable HPET +-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,{data|file}=file1[:file2]...] + ACPI table description +-smbios file=binary + load SMBIOS entry from binary file +-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d] + specify SMBIOS type 0 fields +-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str] + [,uuid=uuid][,sku=str][,family=str] + specify SMBIOS type 1 fields + +Network options: +-net nic[,vlan=n][,macaddr=mac][,model=type][,name=str][,addr=str][,vectors=v] + create a new Network Interface Card and connect it to VLAN 'n' +-net user[,vlan=n][,name=str][,net=addr[/mask]][,host=addr][,restrict=on|off] + [,hostname=host][,dhcpstart=addr][,dns=addr][,tftp=dir][,bootfile=f] + [,hostfwd=rule][,guestfwd=rule][,smb=dir[,smbserver=addr]] + connect the user mode network stack to VLAN 'n', configure its + DHCP server and enabled optional services +-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off] + connect the host TAP network interface to VLAN 'n' + use network scripts 'file' (default=/etc/qemu-ifup) + to configure it and 'dfile' (default=/etc/qemu-ifdown) + to deconfigure it + use '[down]script=no' to disable script execution + use network helper 'helper' (default=/usr/local/stow/qemu/libexec/qemu-bridge-helper) to + configure it + use 'fd=h' to connect to an already opened TAP interface + use 'sndbuf=nbytes' to limit the size of the send buffer (the + default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576') + use vnet_hdr=off to avoid enabling the IFF_VNET_HDR tap flag + use vnet_hdr=on to make the lack of IFF_VNET_HDR support an error condition + use vhost=on to enable experimental in kernel accelerator + (only has effect for virtio guests which use MSIX) + use vhostforce=on to force vhost on for non-MSIX virtio guests + use 'vhostfd=h' to connect to an already opened vhost net device +-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper] + connects a host TAP network interface to a host bridge device 'br' + (default=br0) using the program 'helper' + (default=/usr/local/stow/qemu/libexec/qemu-bridge-helper) +-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port] + connect the vlan 'n' to another VLAN using a socket connection +-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port[,localaddr=addr]] + connect the vlan 'n' to multicast maddr and port + use 'localaddr=addr' to specify the host address to send packets from +-net socket[,vlan=n][,name=str][,fd=h][,udp=host:port][,localaddr=host:port] + connect the vlan 'n' to another VLAN using an UDP tunnel +-net dump[,vlan=n][,file=f][,len=n] + dump traffic on vlan 'n' to file 'f' (max n bytes per packet) +-net none use it alone to have zero network devices. If no -net option + is provided, the default is '-net nic -net user' +-netdev [user|tap|bridge|socket],id=str[,option][,option][,...] + +Character device options: +-chardev null,id=id[,mux=on|off] +-chardev socket,id=id[,host=host],port=host[,to=to][,ipv4][,ipv6][,nodelay] + [,server][,nowait][,telnet][,mux=on|off] (tcp) +-chardev socket,id=id,path=path[,server][,nowait][,telnet],[mux=on|off] (unix) +-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr] + [,localport=localport][,ipv4][,ipv6][,mux=on|off] +-chardev msmouse,id=id[,mux=on|off] +-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]] + [,mux=on|off] +-chardev file,id=id,path=path[,mux=on|off] +-chardev pipe,id=id,path=path[,mux=on|off] +-chardev pty,id=id[,mux=on|off] +-chardev stdio,id=id[,mux=on|off][,signal=on|off] +-chardev tty,id=id,path=path[,mux=on|off] +-chardev parport,id=id,path=path[,mux=on|off] +-chardev spicevmc,id=id,name=name[,debug=debug] + +-iscsi [user=user][,password=password] + [,header-digest=CRC32C|CR32C-NONE|NONE-CRC32C|NONE + [,initiator-name=iqn] + iSCSI session parameters +Bluetooth(R) options: +-bt hci,null dumb bluetooth HCI - doesn't respond to commands +-bt hci,host[:id] + use host's HCI with the given name +-bt hci[,vlan=n] + emulate a standard HCI in virtual scatternet 'n' +-bt vhci[,vlan=n] + add host computer to virtual scatternet 'n' using VHCI +-bt device:dev[,vlan=n] + emulate a bluetooth device 'dev' in scatternet 'n' + +Linux/Multiboot boot specific: +-kernel bzImage use 'bzImage' as kernel image +-append cmdline use 'cmdline' as kernel command line +-initrd file use 'file' as initial ram disk +-dtb file use 'file' as device tree image + +Debug/Expert options: +-serial dev redirect the serial port to char device 'dev' +-parallel dev redirect the parallel port to char device 'dev' +-monitor dev redirect the monitor to char device 'dev' +-qmp dev like -monitor but opens in 'control' mode +-mon chardev=[name][,mode=readline|control][,default] +-debugcon dev redirect the debug console to char device 'dev' +-pidfile file write PID to 'file' +-singlestep always run in singlestep mode +-S freeze CPU at startup (use 'c' to start execution) +-gdb dev wait for gdb connection on 'dev' +-s shorthand for -gdb tcp::1234 +-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items) +-D logfile output log to logfile (instead of the default /tmp/qemu.log) +-hdachs c,h,s[,t] + force hard disk 0 physical geometry and the optional BIOS + translation (t=none or lba) (usually qemu can guess them) +-L path set the directory for the BIOS, VGA BIOS and keymaps +-bios file set the filename for the BIOS +-enable-kvm enable KVM full virtualization support +-xen-domid id specify xen guest domain id +-xen-create create domain using xen hypercalls, bypassing xend + warning: should not be used when xend is in use +-xen-attach attach to existing xen domain + xend will use this when starting qemu +-no-reboot exit instead of rebooting +-no-shutdown stop before shutdown +-loadvm [tag|id] + start right away with a saved state (loadvm in monitor) +-daemonize daemonize QEMU after initializing +-option-rom rom load a file, rom, into the option ROM space +-clock force the use of the given methods for timer alarm. + To see what timers are available use -clock ? +-rtc [base=utc|localtime|date][,clock=host|rt|vm][,driftfix=none|slew] + set the RTC base and clock, enable drift fix for clock ticks (x86 only) +-icount [N|auto] + enable virtual instruction counter with 2^N clock ticks per + instruction +-watchdog i6300esb|ib700 + enable virtual hardware watchdog [default=none] +-watchdog-action reset|shutdown|poweroff|pause|debug|none + action when watchdog fires [default=reset] +-echr chr set terminal escape character instead of ctrl-a +-virtioconsole c + set virtio console +-show-cursor show cursor +-tb-size n set TB size +-incoming p prepare for incoming migration, listen on port p +-nodefaults don't create default devices +-chroot dir chroot to dir just before starting the VM +-runas user change to user id user just before starting the VM +-readconfig <file> +-writeconfig <file> + read/write config file +-nodefconfig + do not load default config files at startup +-trace [events=<file>][,file=<file>] + specify tracing options +-qtest CHR specify tracing options +-qtest-log LOG specify tracing options + +During emulation, the following keys are useful: +ctrl-alt-f toggle full screen +ctrl-alt-n switch to virtual console 'n' +ctrl-alt toggle mouse and keyboard grab + +When using -nographic, press 'ctrl-a h' to get some help. diff --git a/tests/qemuhelpdata/qemu-1.1-device b/tests/qemuhelpdata/qemu-1.1-device new file mode 100644 index 0000000..bac32c9 --- /dev/null +++ b/tests/qemuhelpdata/qemu-1.1-device @@ -0,0 +1,95 @@ +name "usb-storage", bus USB +name "VGA", bus PCI +name "scsi-hd", bus SCSI, desc "virtual SCSI disk" +name "i82559a", bus PCI, desc "Intel i82559A Ethernet" +name "i82559b", bus PCI, desc "Intel i82559B Ethernet" +name "i82559c", bus PCI, desc "Intel i82559C Ethernet" +name "sysbus-ohci", bus System, desc "OHCI USB Controller" +name "virtio-blk-pci", bus PCI, alias "virtio-blk" +name "qxl-vga", bus PCI, desc "Spice QXL GPU (primary, vga compatible)" +name "x3130-upstream", bus PCI, desc "TI X3130 Upstream Port of PCI Express Switch" +name "ide-drive", bus IDE, desc "virtual IDE disk or CD-ROM (legacy)" +name "cirrus-vga", bus PCI, desc "Cirrus CLGD 54xx VGA" +name "ide-hd", bus IDE, desc "virtual IDE disk" +name "ES1370", bus PCI, desc "ENSONIQ AudioPCI ES1370" +name "ioh3420", bus PCI, desc "Intel IOH device id 3420 PCIE Root Port" +name "sga", bus ISA, desc "Serial Graphics Adapter" +name "scsi-block", bus SCSI, desc "SCSI block device passthrough" +name "usb-serial", bus USB +name "pc-sysfw", bus System, desc "PC System Firmware" +name "usb-mouse", bus USB +name "usb-hub", bus USB +name "usb-net", bus USB +name "ccid-card-emulated", bus ccid-bus, desc "emulated smartcard" +name "ne2k_isa", bus ISA +name "scsi-generic", bus SCSI, desc "pass through generic scsi device (/dev/sg*)" +name "pcnet", bus PCI +name "lsi53c895a", bus PCI, alias "lsi" +name "scsi-disk", bus SCSI, desc "virtual SCSI disk or CD-ROM (legacy)" +name "hda-micro", bus HDA, desc "HDA Audio Codec, duplex (speaker, microphone)" +name "xio3130-downstream", bus PCI, desc "TI X3130 Downstream Port of PCI Express Switch" +name "virtserialport", bus virtio-serial-bus +name "nec-usb-xhci", bus PCI +name "pci-ohci", bus PCI, desc "Apple USB Controller" +name "usb-redir", bus USB +name "usb-braille", bus USB +name "scsi-cd", bus SCSI, desc "virtual SCSI CD-ROM" +name "usb-wacom-tablet", bus USB, desc "QEMU PenPartner Tablet" +name "isa-serial", bus ISA +name "i82550", bus PCI, desc "Intel i82550 Ethernet" +name "i82551", bus PCI, desc "Intel i82551 Ethernet" +name "isa-debugcon", bus ISA +name "ide-cd", bus IDE, desc "virtual IDE CD-ROM" +name "SUNW,fdtwo", bus System +name "ich9-usb-uhci1", bus PCI +name "ich9-usb-uhci2", bus PCI +name "ich9-usb-uhci3", bus PCI +name "isa-parallel", bus ISA +name "virtconsole", bus virtio-serial-bus +name "ne2k_pci", bus PCI +name "virtio-serial-pci", bus PCI, alias "virtio-serial" +name "hda-duplex", bus HDA, desc "HDA Audio Codec, duplex (line-out, line-in)" +name "intel-hda", bus PCI, desc "Intel HD Audio Controller" +name "i82559er", bus PCI, desc "Intel i82559ER Ethernet" +name "hda-output", bus HDA, desc "HDA Audio Codec, output-only (line-out)" +name "i82562", bus PCI, desc "Intel i82562 Ethernet" +name "sysbus-ahci", bus System +name "usb-ccid", bus USB, desc "CCID Rev 1.1 smartcard reader" +name "ivshmem", bus PCI +name "AC97", bus PCI, desc "Intel 82801AA AC97 Audio" +name "e1000", bus PCI, desc "Intel Gigabit Ethernet" +name "sysbus-fdc", bus System +name "usb-bt-dongle", bus USB +name "usb-tablet", bus USB +name "isa-vga", bus ISA +name "usb-kbd", bus USB +name "isa-applesmc", bus ISA +name "rtl8139", bus PCI +name "qxl", bus PCI, desc "Spice QXL GPU (secondary)" +name "i82557a", bus PCI, desc "Intel i82557A Ethernet" +name "i82557c", bus PCI, desc "Intel i82557C Ethernet" +name "usb-audio", bus USB +name "piix3-usb-uhci", bus PCI +name "i82557b", bus PCI, desc "Intel i82557B Ethernet" +name "ccid-card-passthru", bus ccid-bus, desc "passthrough smartcard" +name "ib700", bus ISA +name "i82801", bus PCI, desc "Intel i82801 Ethernet" +name "smbus-eeprom", bus I2C +name "vmware-svga", bus PCI +name "isa-cirrus-vga", bus ISA +name "piix4-usb-uhci", bus PCI +name "sb16", bus ISA, desc "Creative Sound Blaster 16" +name "pci-bridge", bus PCI, desc "Standard PCI Bridge" +name "usb-ehci", bus PCI +name "i82558a", bus PCI, desc "Intel i82558A Ethernet" +name "i82558b", bus PCI, desc "Intel i82558B Ethernet" +name "virtio-net-pci", bus PCI, alias "virtio-net" +name "virtio-balloon-pci", bus PCI, alias "virtio-balloon" +name "ich9-usb-ehci1", bus PCI +name "isa-ide", bus ISA +name "i6300esb", bus PCI +name "ich9-ahci", bus PCI, alias "ahci" +name "usb-host", bus USB +name "vt82c686b-usb-uhci", bus PCI +name "virtio-scsi-pci", bus PCI +virtio-blk-pci.class=hex32 diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c index d23b35a..c79c4e1 100644 --- a/tests/qemuhelptest.c +++ b/tests/qemuhelptest.c @@ -679,6 +679,76 @@ mymain(void) QEMU_CAPS_SCSI_CD, QEMU_CAPS_IDE_CD); + DO_TEST("qemu-1.1", 1000090, 0, 0, + QEMU_CAPS_VNC_COLON, + QEMU_CAPS_NO_REBOOT, + QEMU_CAPS_DRIVE, + QEMU_CAPS_NAME, + QEMU_CAPS_UUID, + QEMU_CAPS_MIGRATE_QEMU_TCP, + QEMU_CAPS_MIGRATE_QEMU_EXEC, + QEMU_CAPS_DRIVE_CACHE_V2, + QEMU_CAPS_DRIVE_CACHE_UNSAFE, + QEMU_CAPS_DRIVE_FORMAT, + QEMU_CAPS_DRIVE_SERIAL, + QEMU_CAPS_XEN_DOMID, + QEMU_CAPS_DRIVE_READONLY, + QEMU_CAPS_VGA, + QEMU_CAPS_0_10, + QEMU_CAPS_MEM_PATH, + QEMU_CAPS_SDL, + QEMU_CAPS_MIGRATE_QEMU_UNIX, + QEMU_CAPS_CHARDEV, + QEMU_CAPS_ENABLE_KVM, + QEMU_CAPS_MONITOR_JSON, + QEMU_CAPS_BALLOON, + QEMU_CAPS_DEVICE, + QEMU_CAPS_SMP_TOPOLOGY, + QEMU_CAPS_NETDEV, + QEMU_CAPS_RTC, + QEMU_CAPS_VHOST_NET, + QEMU_CAPS_NO_HPET, + QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_BOOT_MENU, + QEMU_CAPS_FSDEV, + QEMU_CAPS_NAME_PROCESS, + QEMU_CAPS_SMBIOS_TYPE, + QEMU_CAPS_VGA_QXL, + QEMU_CAPS_SPICE, + QEMU_CAPS_VGA_NONE, + QEMU_CAPS_MIGRATE_QEMU_FD, + QEMU_CAPS_HDA_DUPLEX, + QEMU_CAPS_HDA_MICRO, + QEMU_CAPS_DRIVE_AIO, + QEMU_CAPS_CCID_EMULATED, + QEMU_CAPS_CCID_PASSTHRU, + QEMU_CAPS_CHARDEV_SPICEVMC, + QEMU_CAPS_DEVICE_QXL_VGA, + QEMU_CAPS_PCI_MULTIFUNCTION, + QEMU_CAPS_SGA, + QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC, + QEMU_CAPS_PIIX3_USB_UHCI, + QEMU_CAPS_PIIX4_USB_UHCI, + QEMU_CAPS_USB_EHCI, + QEMU_CAPS_ICH9_USB_EHCI1, + QEMU_CAPS_VT82C686B_USB_UHCI, + QEMU_CAPS_PCI_OHCI, + QEMU_CAPS_USB_HUB, + QEMU_CAPS_USB_REDIR, + QEMU_CAPS_NO_SHUTDOWN, + QEMU_CAPS_PCI_ROMBAR, + QEMU_CAPS_ICH9_AHCI, + QEMU_CAPS_NO_ACPI, + QEMU_CAPS_FSDEV_READONLY, + QEMU_CAPS_VIRTIO_BLK_SG_IO, + QEMU_CAPS_DRIVE_COPY_ON_READ, + QEMU_CAPS_CPU_HOST, + QEMU_CAPS_FSDEV_WRITEOUT, + QEMU_CAPS_DRIVE_IOTUNE, + QEMU_CAPS_SCSI_BLOCK, + QEMU_CAPS_SCSI_CD, + QEMU_CAPS_IDE_CD); + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -- 1.7.10.1

On Tue, May 15, 2012 at 19:13:37 +0200, Marc-André Lureau wrote:
Generated with qemu-system-x86_64 -device ? -device virtio-blk-pci,? -device virtio-net-pci,? 2> tests/qemuhelpdata/qemu-1.1-device
This command line is actually incomplete. Libvirt uses the following: qemu-system-x86_64 -device ? -device pci-assign,? -device virtio-blk-pci,? -device virtio-net-pci,? -device scsi-disk,? Anyway, as I said -rc0 is not the best source since this command will only produce a single line (IIRC) and I needed the output of 1.1-rc2 for another patch so I used that to fill qemu-1.1{,-device} files. -rc2 is also the first one to fix that annoying -device something,? bug which means libvirt is able to detect everything it cares about. Thus, you can just drop this patch from your series and squash diff --git i/tests/qemuhelptest.c w/tests/qemuhelptest.c index 57d1859..46cc973 100644 --- i/tests/qemuhelptest.c +++ w/tests/qemuhelptest.c @@ -752,7 +752,8 @@ mymain(void) QEMU_CAPS_SCSI_BLOCK, QEMU_CAPS_SCSI_CD, QEMU_CAPS_IDE_CD, - QEMU_CAPS_NO_USER_CONFIG); + QEMU_CAPS_NO_USER_CONFIG, + QEMU_CAPS_HDA_MICRO); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } into 1/9 instead :-) And I will take care of updating the files with 1.1 output once it's released. Jirka

Thus, you can just drop this patch from your series and squash
diff --git i/tests/qemuhelptest.c w/tests/qemuhelptest.c index 57d1859..46cc973 100644 --- i/tests/qemuhelptest.c +++ w/tests/qemuhelptest.c @@ -752,7 +752,8 @@ mymain(void) QEMU_CAPS_SCSI_BLOCK, QEMU_CAPS_SCSI_CD, QEMU_CAPS_IDE_CD, - QEMU_CAPS_NO_USER_CONFIG); + QEMU_CAPS_NO_USER_CONFIG, + QEMU_CAPS_HDA_MICRO);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }
into 1/9 instead :-)
done, will resend -- Marc-André Lureau

Test new codec type element. --- tests/qemuxml2argvdata/qemuxml2argv-sound-device.args | 7 +++++-- tests/qemuxml2argvdata/qemuxml2argv-sound-device.xml | 7 +++++++ tests/qemuxml2argvtest.c | 3 ++- tests/qemuxml2xmltest.c | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/qemuxml2argvdata/qemuxml2argv-sound-device.args b/tests/qemuxml2argvdata/qemuxml2argv-sound-device.args index 0a09c41..4a7129b 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-sound-device.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-sound-device.args @@ -4,5 +4,8 @@ unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \ /dev/HostVG/QEMUGuest1 -usb -soundhw pcspk -device ES1370,id=sound1,bus=pci.0,\ addr=0x3 -device sb16,id=sound2 -device AC97,id=sound3,bus=pci.0,addr=0x4 \ -device intel-hda,id=sound4,bus=pci.0,addr=0x5 -device hda-duplex,\ -id=sound4-codec0,bus=sound4.0,cad=0 -device virtio-balloon-pci,id=balloon0,\ -bus=pci.0,addr=0x6 +id=sound4-codec0,bus=sound4.0,cad=0 \ +-device intel-hda,id=sound5,bus=pci.0,addr=0x6 \ +-device hda-micro,id=sound5-codec0,bus=sound5.0,cad=0 \ +-device hda-duplex,id=sound5-codec1,bus=sound5.0,cad=1 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-sound-device.xml b/tests/qemuxml2argvdata/qemuxml2argv-sound-device.xml index 33ec569..c588a24 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-sound-device.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-sound-device.xml @@ -17,12 +17,19 @@ <disk type='block' device='disk'> <source dev='/dev/HostVG/QEMUGuest1'/> <target dev='hda' bus='ide'/> + <address type='drive' controller='0' bus='0' target='0' unit='0'/> </disk> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> <sound model='pcspk'/> <sound model='es1370'/> <sound model='sb16'/> <sound model='ac97'/> <sound model='ich6'/> + <sound model='ich6'> + <codec type='micro'/> + <codec type='duplex'/> + </sound> <memballoon model='virtio'/> </devices> </domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index c073429..617b178 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -680,7 +680,8 @@ mymain(void) QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG); DO_TEST("sound", false, NONE); DO_TEST("sound-device", false, - QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_HDA_DUPLEX); + QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_HDA_DUPLEX, QEMU_CAPS_HDA_MICRO); DO_TEST("fs9p", false, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_FSDEV, QEMU_CAPS_FSDEV_WRITEOUT); diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 5b6a216..f3eeb66 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -179,6 +179,7 @@ mymain(void) DO_TEST("net-virtio-network-portgroup"); DO_TEST("net-hostdev"); DO_TEST("sound"); + DO_TEST("sound-device"); DO_TEST("net-bandwidth"); DO_TEST("serial-vc"); -- 1.7.10.1

Allow to specify preallocation mode for QCOW2 images. If not specified or not available, it's ignored. This change only modify the schema, doc, parsing and tests. --- docs/formatstorage.html.in | 6 ++++++ docs/schemas/storagevol.rng | 18 ++++++++++++++++++ src/conf/storage_conf.c | 26 ++++++++++++++++++++++++++ src/conf/storage_conf.h | 1 + src/util/storage_file.c | 4 ++++ src/util/storage_file.h | 10 ++++++++++ tests/storagevolxml2xmlin/vol-qcow2.xml | 1 + tests/storagevolxml2xmlout/vol-qcow2.xml | 1 + 8 files changed, 67 insertions(+) diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in index d0e4319..8fd2908 100644 --- a/docs/formatstorage.html.in +++ b/docs/formatstorage.html.in @@ -252,6 +252,12 @@ 1,152,921,504,606,846,976 bytes). <span class="since">Since 0.4.1, multi-character <code>unit</code> since 0.9.11</span></dd> + <dt><code>preallocation</code></dt> + <dd>An image with preallocated metadata is initially larger but + can improve performance when the image needs to grow. This is + supported by the QCOW2 image format. + Attribute <code>mode</code> value can be 'off' or 'metadata'. + <span class="since">Since 0.9.13</span></dd> <dt><code>capacity</code></dt> <dd>Providing the logical capacity for the volume. This value is in bytes by default, but a <code>unit</code> attribute can be diff --git a/docs/schemas/storagevol.rng b/docs/schemas/storagevol.rng index 8edb877..b54db13 100644 --- a/docs/schemas/storagevol.rng +++ b/docs/schemas/storagevol.rng @@ -40,6 +40,9 @@ <ref name='scaledInteger'/> </element> </optional> + <optional> + <ref name='preallocation'/> + </optional> </define> <define name='permissions'> @@ -171,6 +174,21 @@ </optional> </define> + <define name='preallocationmode'> + <choice> + <value>off</value> + <value>metadata</value> + </choice> + </define> + + <define name='preallocation'> + <element name='preallocation'> + <attribute name='mode'> + <ref name='preallocationmode'/> + </attribute> + </element> + </define> + <define name='name'> <data type='string'> <param name="pattern">[a-zA-Z0-9_\+\-\.]+</param> diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 188af6d..b775ad2 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -992,6 +992,7 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool, char *allocation = NULL; char *capacity = NULL; char *unit = NULL; + char *preallocation = NULL; xmlNodePtr node; options = virStorageVolOptionsForPoolType(pool->type); @@ -1036,6 +1037,18 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool, ret->allocation = ret->capacity; } + preallocation = virXPathString("string(./preallocation/@mode)", ctxt); + if (preallocation) { + if ((ret->preallocation = virStoragePreallocationModeTypeFromString(preallocation)) < 0) { + virStorageReportError(VIR_ERR_XML_ERROR, + _("unknown preallocation mode %s"), preallocation); + goto cleanup; + } + VIR_FREE(preallocation); + } else { + ret->preallocation = VIR_STORAGE_PREALLOCATION_NONE; + } + ret->target.path = virXPathString("string(./target/path)", ctxt); if (options->formatFromString) { char *format = virXPathString("string(./target/format/@type)", ctxt); @@ -1091,6 +1104,7 @@ virStorageVolDefParseXML(virStoragePoolDefPtr pool, return ret; cleanup: + VIR_FREE(preallocation); VIR_FREE(allocation); VIR_FREE(capacity); VIR_FREE(unit); @@ -1245,6 +1259,18 @@ virStorageVolDefFormat(virStoragePoolDefPtr pool, virBufferAsprintf(&buf," <allocation unit='bytes'>%llu</allocation>\n", def->allocation); + if (def->preallocation != VIR_STORAGE_PREALLOCATION_NONE) { + const char *preallocation; + + preallocation = virStoragePreallocationModeTypeToString(def->preallocation); + if (!preallocation) { + virStorageReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("unexpected preallocation mode")); + goto cleanup; + } + virBufferAsprintf(&buf," <preallocation mode='%s'/>\n", preallocation); + } + if (virStorageVolTargetDefFormat(options, &buf, &def->target, "target") < 0) goto cleanup; diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 9222c4a..c7c7af0 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -98,6 +98,7 @@ struct _virStorageVolDef { virStorageVolSource source; virStorageVolTarget target; virStorageVolTarget backingStore; + int preallocation; /* virStoragePreallocationMode enum */ }; typedef struct _virStorageVolDefList virStorageVolDefList; diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 530071e..63abe65 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -47,6 +47,10 @@ VIR_ENUM_IMPL(virStorageFileFormat, "cloop", "cow", "dmg", "iso", "qcow", "qcow2", "qed", "vmdk", "vpc") +VIR_ENUM_IMPL(virStoragePreallocationMode, + VIR_STORAGE_PREALLOCATION_LAST, + "default", "off", "metadata") + enum lv_endian { LV_LITTLE_ENDIAN = 1, /* 1234 */ LV_BIG_ENDIAN /* 4321 */ diff --git a/src/util/storage_file.h b/src/util/storage_file.h index 13d0e87..dfc8719 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -46,6 +46,16 @@ enum virStorageFileFormat { VIR_ENUM_DECL(virStorageFileFormat); +enum virStoragePreallocationMode { + VIR_STORAGE_PREALLOCATION_NONE, + VIR_STORAGE_PREALLOCATION_OFF, + VIR_STORAGE_PREALLOCATION_METADATA, + + VIR_STORAGE_PREALLOCATION_LAST +}; + +VIR_ENUM_DECL(virStoragePreallocationMode); + typedef struct _virStorageFileMetadata { char *backingStore; int backingStoreFormat; diff --git a/tests/storagevolxml2xmlin/vol-qcow2.xml b/tests/storagevolxml2xmlin/vol-qcow2.xml index b4924de..b4c6522 100644 --- a/tests/storagevolxml2xmlin/vol-qcow2.xml +++ b/tests/storagevolxml2xmlin/vol-qcow2.xml @@ -5,6 +5,7 @@ </source> <capacity unit="G">5</capacity> <allocation>294912</allocation> + <preallocation mode='metadata'/> <target> <path>/var/lib/libvirt/images/OtherDemo.img</path> <format type='qcow2'/> diff --git a/tests/storagevolxml2xmlout/vol-qcow2.xml b/tests/storagevolxml2xmlout/vol-qcow2.xml index 4490931..311c52e 100644 --- a/tests/storagevolxml2xmlout/vol-qcow2.xml +++ b/tests/storagevolxml2xmlout/vol-qcow2.xml @@ -5,6 +5,7 @@ </source> <capacity unit='bytes'>5368709120</capacity> <allocation unit='bytes'>294912</allocation> + <preallocation mode='metadata'/> <target> <path>/var/lib/libvirt/images/OtherDemo.img</path> <format type='qcow2'/> -- 1.7.10.1

Use preallocation mode specified in volume XML format when running qemu-img. --- src/storage/storage_backend.c | 70 +++++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index caac2f8..8b31823 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -645,6 +645,38 @@ cleanup: return ret; } +static char * +virStorageQemuImgOptionsStr(virStorageVolDefPtr vol) +{ + virBuffer buf = VIR_BUFFER_INITIALIZER; + bool do_encryption = (vol->target.encryption != NULL); + const char *backingType = vol->backingStore.path ? + virStorageFileFormatTypeToString(vol->backingStore.format) : NULL; + bool comma = false; + const char *preallocation = vol->preallocation != VIR_STORAGE_PREALLOCATION_NONE ? + virStoragePreallocationModeTypeToString(vol->preallocation) : NULL; + + if (backingType) { + virBufferAddLit(&buf, "backing_fmt="); + virBufferAdd(&buf, backingType, -1); + comma = true; + } + + if (do_encryption) { + virBufferAdd(&buf, comma ? "," : "", -1); + virBufferAddLit(&buf, "encryption=on"); + comma = true; + } + + if (preallocation) { + virBufferAdd(&buf, comma ? "," : "", -1); + virBufferAddLit(&buf, "preallocation="); + virBufferAdd(&buf, preallocation, -1); + comma = true; + } + + return virBufferContentAndReset(&buf); +} static int virStorageBackendCreateQemuImg(virConnectPtr conn, @@ -658,7 +690,9 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, int imgformat = -1; virCommandPtr cmd = NULL; bool do_encryption = (vol->target.encryption != NULL); + bool with_preallocation = (vol->preallocation != VIR_STORAGE_PREALLOCATION_NONE); unsigned long long int size_arg; + char *options; virCheckFlags(0, -1); @@ -689,6 +723,12 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, return -1; } + if (vol->target.format != VIR_STORAGE_FILE_QCOW2 && with_preallocation) { + virStorageReportError(VIR_ERR_INTERNAL_ERROR, + _("Preallocation is only available with qcow2")); + return -1; + } + if (vol->backingStore.path) { int accessRetCode = -1; char *absolutePath = NULL; @@ -781,16 +821,22 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, if (imgformat < 0) goto cleanup; + if (imgformat != QEMU_IMG_BACKING_FORMAT_OPTIONS && with_preallocation) + VIR_INFO("Preallocation not supported with this version of qemu-img"); + cmd = virCommandNew(create_tool); if (inputvol) { virCommandAddArgList(cmd, "convert", "-f", inputType, "-O", type, inputPath, vol->target.path, NULL); - if (do_encryption) { - if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS) { - virCommandAddArgList(cmd, "-o", "encryption=on", NULL); - } else { + if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS) { + virCommandAddArg(cmd, "-o"); + options = virStorageQemuImgOptionsStr(vol); + virCommandAddArg(cmd, options); + VIR_FREE(options); + } else { + if (do_encryption) { virCommandAddArg(cmd, "-e"); } } @@ -811,10 +857,11 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, case QEMU_IMG_BACKING_FORMAT_OPTIONS: virCommandAddArg(cmd, "-o"); - virCommandAddArgFormat(cmd, "backing_fmt=%s%s", backingType, - do_encryption ? ",encryption=on" : ""); + options = virStorageQemuImgOptionsStr(vol); + virCommandAddArg(cmd, options); virCommandAddArg(cmd, vol->target.path); virCommandAddArgFormat(cmd, "%lluK", size_arg); + VIR_FREE(options); break; default: @@ -831,10 +878,13 @@ virStorageBackendCreateQemuImg(virConnectPtr conn, vol->target.path, NULL); virCommandAddArgFormat(cmd, "%lluK", size_arg); - if (do_encryption) { - if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS) { - virCommandAddArgList(cmd, "-o", "encryption=on", NULL); - } else { + if (imgformat == QEMU_IMG_BACKING_FORMAT_OPTIONS) { + virCommandAddArg(cmd, "-o"); + options = virStorageQemuImgOptionsStr(vol); + virCommandAddArg(cmd, options); + VIR_FREE(options); + } else { + if (do_encryption) { virCommandAddArg(cmd, "-e"); } } -- 1.7.10.1

Add element <forward> to add TCP or UDP port redirection from host to guest in user mode networking. --- docs/formatdomain.html.in | 21 +++ docs/schemas/domaincommon.rng | 29 ++++ src/conf/domain_conf.c | 167 ++++++++++++++++++++++ src/conf/domain_conf.h | 25 ++++ tests/qemuargv2xmltest.c | 3 +- tests/qemuxml2argvdata/qemuxml2argv-net-user.xml | 2 + 6 files changed, 246 insertions(+), 1 deletion(-) diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 3875167..c030c61 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -2268,6 +2268,27 @@ VMs to have outgoing access. </p> + <p> + <span class="since">Since 0.9.13</span>, port redirections from + host to guest can be added by providing <code>forward</code> + elements that takes the following attributes: + </p> + + <dl> + <dt><code>type</code></dt> + <dd>Either <code>tcp</code> (default) or <code>udp</code>.</dd> + + <dt><code>host_port</code></dt> + <dd>Host port to redirect.</dd> + + <dt><code>guest_port</code></dt> + <dd>Guest port to redirect to.</dd> + + <dt><code>host</code></dt> + <dd>IPv4 address to bound the redirection to a specific host + interface.</dd> + </dl> + <pre> ... <devices> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 34f63c3..740f5af 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1408,6 +1408,35 @@ <value>user</value> </attribute> <interleave> + <zeroOrMore> + <element name="forward"> + <attribute name="host_port"> + <ref name="PortNumber"/> + </attribute> + <attribute name="guest_port"> + <ref name="PortNumber"/> + </attribute> + <optional> + <attribute name="type"> + <choice> + <value>tcp</value> + <value>udp</value> + </choice> + </attribute> + </optional> + <optional> + <attribute name="host"> + <ref name="ipv4Addr"/> + </attribute> + </optional> + <optional> + <attribute name="guest"> + <ref name="ipv4Addr"/> + </attribute> + </optional> + <empty/> + </element> + </zeroOrMore> <ref name="interface-options"/> </interleave> </group> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 4698c39..0f3fa72 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -650,6 +650,11 @@ VIR_ENUM_IMPL(virDomainNumatuneMemPlacementMode, "static", "auto"); + +VIR_ENUM_IMPL(virDomainNetForwardProtocol, VIR_DOMAIN_NET_FORWARD_PROTOCOL_LAST, + "tcp", + "udp") + #define virDomainReportError(code, ...) \ virReportErrorHelper(VIR_FROM_DOMAIN, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) @@ -1019,8 +1024,19 @@ virDomainActualNetDefFree(virDomainActualNetDefPtr def) VIR_FREE(def); } +void +virDomainNetForwardDefFree(virDomainNetForwardDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def); +} + void virDomainNetDefFree(virDomainNetDefPtr def) { + int i; + if (!def) return; @@ -1066,6 +1082,11 @@ void virDomainNetDefFree(virDomainNetDefPtr def) break; case VIR_DOMAIN_NET_TYPE_USER: + for (i = 0; i < def->data.user.nforward; i++) + virDomainNetForwardDefFree(def->data.user.forwards[i]); + VIR_FREE(def->data.user.forwards); + break; + case VIR_DOMAIN_NET_TYPE_LAST: break; } @@ -4351,6 +4372,81 @@ error: return ret; } +static virDomainNetForwardDefPtr +virDomainNetForwardDefParseXML(const xmlNodePtr node) +{ + char *type = NULL; + char *host = NULL; + char *guest = NULL; + char *host_port = NULL; + char *guest_port = NULL; + virDomainNetForwardDefPtr def; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + type = virXMLPropString(node, "type"); + if (type == NULL) { + def->type = VIR_DOMAIN_NET_FORWARD_PROTOCOL_TCP; + } else if ((def->type = virDomainNetForwardProtocolTypeFromString(type)) < 0) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("unknown forward type '%s'"), type); + goto error; + } + + host_port = virXMLPropString(node, "host_port"); + if (!host_port || + virStrToLong_i(host_port, NULL, 10, &def->host_port) < 0) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("Cannot parse <forward> 'host_port' attribute")); + goto error; + } + + guest_port = virXMLPropString(node, "guest_port"); + if (!guest_port || + virStrToLong_i(guest_port, NULL, 10, &def->guest_port) < 0) { + virDomainReportError(VIR_ERR_XML_ERROR, "%s", + _("Cannot parse <forward> 'guest_port' attribute")); + goto error; + } + + host = virXMLPropString(node, "host"); + if (host) { + if (virSocketAddrParse(&def->host_addr, host, AF_INET) < 0) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("Bad host address '%s' for redirection"), host); + goto error; + } + def->has_host_addr = true; + } + + guest = virXMLPropString(node, "guest"); + if (guest) { + if (virSocketAddrParse(&def->guest_addr, guest, AF_INET) < 0) { + virDomainReportError(VIR_ERR_XML_ERROR, + _("Bad guest address '%s' for redirection"), guest); + goto error; + } + def->has_guest_addr = true; + } + +cleanup: + VIR_FREE(type); + VIR_FREE(host); + VIR_FREE(guest); + VIR_FREE(host_port); + VIR_FREE(guest_port); + + return def; + +error: + virDomainNetForwardDefFree(def); + def = NULL; + goto cleanup; +} + #define NET_MODEL_CHARS \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ091234567890_-" @@ -4394,6 +4490,8 @@ virDomainNetDefParseXML(virCapsPtr caps, virDomainActualNetDefPtr actual = NULL; xmlNodePtr oldnode = ctxt->node; int ret; + int nforwards; + xmlNodePtr *forwardNodes = NULL; if (VIR_ALLOC(def) < 0) { virReportOOMError(); @@ -4683,6 +4781,28 @@ virDomainNetDefParseXML(virCapsPtr caps, break; case VIR_DOMAIN_NET_TYPE_USER: + /* parse the <forward> elements */ + nforwards = virXPathNodeSet("./forward", ctxt, &forwardNodes); + if (nforwards < 0) + goto error; + + if (nforwards > 0) { + int i; + if (VIR_ALLOC_N(def->data.user.forwards, nforwards) < 0) { + virReportOOMError(); + goto error; + } + for (i = 0; i < nforwards; i++) { + virDomainNetForwardDefPtr fwd = + virDomainNetForwardDefParseXML(forwardNodes[i]); + if (fwd == NULL) + goto error; + def->data.user.forwards[def->data.user.nforward++] = fwd; + } + VIR_FREE(forwardNodes); + } + break; + case VIR_DOMAIN_NET_TYPE_LAST: break; } @@ -11416,11 +11536,50 @@ error: } static int +virDomainNetForwardDefFormat(virBufferPtr buf, + virDomainNetForwardDefPtr def) +{ + const char *type; + char *ip; + + if (!def) + return 0; + + type = virDomainNetForwardProtocolTypeToString(def->type); + if (!type) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected net type %d"), def->type); + return -1; + } + virBufferAsprintf(buf, "<forward type='%s'", type); + + if (def->has_host_addr) { + ip = virSocketAddrFormat(&def->host_addr); + virBufferAsprintf(buf, " host='%s'", ip); + VIR_FREE(ip); + } + + virBufferAsprintf(buf, " host_port='%d'", def->host_port); + + if (def->has_guest_addr) { + ip = virSocketAddrFormat(&def->guest_addr); + virBufferAsprintf(buf, " guest='%s'", ip); + VIR_FREE(ip); + } + + virBufferAsprintf(buf, " guest_port='%d'", def->guest_port); + + virBufferAddLit(buf, "/>\n"); + return 0; +} + +static int virDomainNetDefFormat(virBufferPtr buf, virDomainNetDefPtr def, unsigned int flags) { const char *type = virDomainNetTypeToString(def->type); + int i; if (!type) { virDomainReportError(VIR_ERR_INTERNAL_ERROR, @@ -11520,6 +11679,14 @@ virDomainNetDefFormat(virBufferPtr buf, break; case VIR_DOMAIN_NET_TYPE_USER: + virBufferAdjustIndent(buf, 6); + for (i = 0; i < def->data.user.nforward; i++) { + if (virDomainNetForwardDefFormat(buf, def->data.user.forwards[i]) < 0) + return -1; + } + virBufferAdjustIndent(buf, -6); + break; + case VIR_DOMAIN_NET_TYPE_LAST: break; } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 70129fe..e93cab9 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -768,6 +768,25 @@ struct _virDomainActualNetDef { virNetDevBandwidthPtr bandwidth; }; +enum virDomainNetForwardProtocol { + VIR_DOMAIN_NET_FORWARD_PROTOCOL_TCP, + VIR_DOMAIN_NET_FORWARD_PROTOCOL_UDP, + + VIR_DOMAIN_NET_FORWARD_PROTOCOL_LAST, +}; + +typedef struct _virDomainNetForwardDef virDomainNetForwardDef; +typedef virDomainNetForwardDef *virDomainNetForwardDefPtr; +struct _virDomainNetForwardDef { + int type; /* enum virDomainNetForwardProtocol */ + bool has_host_addr; + virSocketAddr host_addr; + int host_port; + bool has_guest_addr; + virSocketAddr guest_addr; + int guest_port; +}; + /* Stores the virtual network interface configuration */ struct _virDomainNetDef { enum virDomainNetType type; @@ -821,6 +840,10 @@ struct _virDomainNetDef { virDomainHostdevDef def; virNetDevVPortProfilePtr virtPortProfile; } hostdev; + struct { + int nforward; + virDomainNetForwardDefPtr *forwards; + } user; } data; struct { bool sndbuf_specified; @@ -1856,6 +1879,7 @@ int virDomainDiskFindControllerModel(virDomainDefPtr def, void virDomainControllerDefFree(virDomainControllerDefPtr def); void virDomainFSDefFree(virDomainFSDefPtr def); void virDomainActualNetDefFree(virDomainActualNetDefPtr def); +void virDomainNetForwardDefFree(virDomainNetForwardDefPtr def); void virDomainNetDefFree(virDomainNetDefPtr def); void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def); void virDomainChrDefFree(virDomainChrDefPtr def); @@ -2170,6 +2194,7 @@ VIR_ENUM_DECL(virDomainFSAccessMode) VIR_ENUM_DECL(virDomainFSWrpolicy) VIR_ENUM_DECL(virDomainNet) VIR_ENUM_DECL(virDomainNetBackend) +VIR_ENUM_DECL(virDomainNetForwardProtocol) VIR_ENUM_DECL(virDomainNetVirtioTxMode) VIR_ENUM_DECL(virDomainNetInterfaceLinkState) VIR_ENUM_DECL(virDomainChrDevice) diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 439218e..cf2862b 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -207,7 +207,8 @@ mymain(void) DO_TEST("misc-acpi"); DO_TEST("misc-no-reboot"); DO_TEST("misc-uuid"); - DO_TEST("net-user"); + /* Fixed in following commit */ + /* DO_TEST("net-user"); */ DO_TEST("net-virtio"); DO_TEST("net-eth"); DO_TEST("net-eth-ifname"); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-user.xml b/tests/qemuxml2argvdata/qemuxml2argv-net-user.xml index 37e5edf..ecefdeb 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-net-user.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-user.xml @@ -23,6 +23,8 @@ <controller type='ide' index='0'/> <interface type='user'> <mac address='00:11:22:33:44:55'/> + <forward type='tcp' host_port='2222' guest_port='22'/> + <forward type='udp' host='127.0.0.1' host_port='2242' guest='10.0.2.15' guest_port='42'/> </interface> <memballoon model='virtio'/> </devices> -- 1.7.10.1

Implement port forwarding for user mode networking with QEMU. --- src/libvirt_private.syms | 3 + src/qemu/qemu_command.c | 139 +++++++++++++++++++++ tests/qemuargv2xmltest.c | 3 +- tests/qemuxml2argvdata/qemuxml2argv-net-user.args | 5 +- 4 files changed, 146 insertions(+), 4 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7d09f33..d497bce 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -396,6 +396,9 @@ virDomainNetInsert; virDomainNetRemove; virDomainNetRemoveByMac; virDomainNetTypeToString; +virDomainNetForwardDefFree; +virDomainNetForwardProtocolTypeFromString; +virDomainNetForwardProtocolTypeToString; virDomainNostateReasonTypeFromString; virDomainNostateReasonTypeToString; virDomainNumatuneMemModeTypeFromString; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 842b0fd..4cccc91 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2846,6 +2846,34 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, virBufferAsprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf); } + if (netType == VIR_DOMAIN_NET_TYPE_USER) { + int i; + + for (i = 0; i < net->data.user.nforward; ++i) { + char *host_addr = NULL; + char *guest_addr = NULL; + virDomainNetForwardDefPtr fwd = net->data.user.forwards[i]; + const char *type = virDomainNetForwardProtocolTypeToString(fwd->type); + if (!type) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("Invalid forward type")); + return NULL; + } + + if (fwd->has_host_addr) + host_addr = virSocketAddrFormat(&fwd->host_addr); + if (fwd->has_guest_addr) + guest_addr = virSocketAddrFormat(&fwd->guest_addr); + + virBufferAsprintf(&buf, ",hostfwd=%s:%s:%d-%s:%d", type, + host_addr ? host_addr : "", fwd->host_port, + guest_addr ? guest_addr : "", fwd->guest_port); + + VIR_FREE(host_addr); + VIR_FREE(guest_addr); + } + } + if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); virReportOOMError(); @@ -6713,6 +6741,94 @@ qemuFindNICForVLAN(int nnics, } +static virDomainNetForwardDefPtr +qemuParseNetForward(char *val) +{ + char *type, *host, *guest, *port; + virDomainNetForwardDefPtr def; + + if (VIR_ALLOC(def) < 0) { + virReportOOMError(); + return NULL; + } + + type = val; + host = strchr(type, ':'); + if (!host) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse hostfwd host '%s'"), val); + goto error; + } + *host = '\0'; + host++; + guest = strchr(host, '-'); + if (!guest) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot parse hostfwd guest '%s'"), val); + goto error; + } + *guest = '\0'; + guest++; + + if (STREQ(type, "")) { + def->type = VIR_DOMAIN_NET_FORWARD_PROTOCOL_TCP; + } else if ((def->type = virDomainNetForwardProtocolTypeFromString(type)) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown forward type '%s'"), type); + goto error; + } + + port = strchr(host, ':'); + if (!port) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing host port")); + goto error; + } + *port = '\0'; + port++; + if (!STREQ(host, "")) { + if (virSocketAddrParse(&def->host_addr, host, AF_INET) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("Bad host address '%s' for redirection"), host); + goto error; + } + def->has_host_addr = true; + } + if (virStrToLong_i(port, NULL, 10, &def->host_port) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse host port")); + goto error; + } + + port = strchr(guest, ':'); + if (!port) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing guest port")); + goto error; + } + *port = '\0'; + port++; + if (!STREQ(guest, "")) { + if (virSocketAddrParse(&def->guest_addr, guest, AF_INET) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("Bad guest address '%s' for redirection"), guest); + goto error; + } + def->has_guest_addr = true; + } + if (virStrToLong_i(port, NULL, 10, &def->guest_port) < 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Cannot parse guest port")); + goto error; + } + + return def; + +error: + virDomainNetForwardDefFree(def); + return NULL; +} + /* * Tries to parse a QEMU -net backend argument. Gets given * a list of all known -net frontend arguments to try and @@ -6732,6 +6848,7 @@ qemuParseCommandLineNet(virCapsPtr caps, int wantvlan = 0; const char *tmp; int genmac = 1; + int nforward = 0; int i; tmp = strchr(val, ','); @@ -6778,9 +6895,31 @@ qemuParseCommandLineNet(virCapsPtr caps, STREQ(keywords[i], "ifname")) { def->ifname = values[i]; values[i] = NULL; + } else if (def->type == VIR_DOMAIN_NET_TYPE_USER && + STREQ(keywords[i], "hostfwd")) { + nforward++; } } + if (nforward > 0) { + if (VIR_ALLOC_N(def->data.user.forwards, nforward) < 0) { + virReportOOMError(); + goto cleanup; + } + + for (i = 0 ; i < nkeywords ; i++) { + virDomainNetForwardDefPtr fwd; + if (def->type != VIR_DOMAIN_NET_TYPE_USER || + !STREQ(keywords[i], "hostfwd")) + continue; + + if ((fwd = qemuParseNetForward(values[i])) == NULL) + goto cleanup; + + def->data.user.forwards[def->data.user.nforward] = fwd; + def->data.user.nforward++; + } + } /* Done parsing the nic backend. Now to try and find corresponding * frontend, based off vlan number. NB this assumes a 1-1 mapping diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index cf2862b..439218e 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -207,8 +207,7 @@ mymain(void) DO_TEST("misc-acpi"); DO_TEST("misc-no-reboot"); DO_TEST("misc-uuid"); - /* Fixed in following commit */ - /* DO_TEST("net-user"); */ + DO_TEST("net-user"); DO_TEST("net-virtio"); DO_TEST("net-eth"); DO_TEST("net-eth-ifname"); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-net-user.args b/tests/qemuxml2argvdata/qemuxml2argv-net-user.args index 093ff01..db31e95 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-net-user.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-net-user.args @@ -1,5 +1,6 @@ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \ pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \ -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net nic,\ -macaddr=00:11:22:33:44:55,vlan=0 -net user,vlan=0 -serial none -parallel none \ --usb +macaddr=00:11:22:33:44:55,vlan=0 \ +-net user,vlan=0,hostfwd=tcp::2222-:22,hostfwd=udp:127.0.0.1:2242-10.0.2.15:42 \ +-serial none -parallel none -usb -- 1.7.10.1
participants (2)
-
Jiri Denemark
-
Marc-André Lureau