On Wed, Nov 04, 2009 at 04:22:01PM +0000, Matthew Booth wrote:
> This patch allows the following to be specified in a qemu domain:
> 
> <channel type='pipe'>
>   <source path='/tmp/guestfwd'/>
>   <target type='guestfwd' address='10.0.2.1' port='4600'/>
> </channel>
> 
> This will output the following on the qemu command line:
> 
> -chardev pipe,id=channel0,path=/tmp/guestfwd \
> -net user,guestfwd=tcp:10.0.2.1:4600-chardev:channel0
> 
> * docs/schemas/domain.rng: Add <channel> and <guestfwd> elements
> * proxy/Makefile.am: add network.c as dep of domain_conf.c
> * src/conf/domain_conf.[ch]: Add xml parsing/formatting for channel and 
> guestfwd
> * src/qemu/qemu_conf.c: Add argument output for guestfwd
> * tests/qemuxml2(argv|xml)test.c: Add test for guestfwd domain syntax
> ---
>  docs/schemas/domain.rng                            |   89 ++++++----
>  proxy/Makefile.am                                  |    1 +
>  src/conf/domain_conf.c                             |  189 
> ++++++++++++++++++--
>  src/conf/domain_conf.h                             |    6 +
>  src/qemu/qemu_conf.c                               |   64 +++++++
>  .../qemuxml2argv-channel-guestfwd.args             |    1 +
>  .../qemuxml2argv-channel-guestfwd.xml              |   26 +++
>  tests/qemuxml2argvtest.c                           |    4 +-
>  tests/qemuxml2xmltest.c                            |    1 +
>  9 files changed, 332 insertions(+), 49 deletions(-)
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.args
>  create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.xml
> 
> diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
> index 0a6ab61..b75f17e 100644
> --- a/docs/schemas/domain.rng
> +++ b/docs/schemas/domain.rng
> @@ -930,6 +930,19 @@
>        definition doesn't fully specify the constraints on this node.
>      -->
>    <define name="qemucdev">
> +    <ref name="qemucdevSrcType"/>
> +    <interleave>
> +      <ref name="qemucdevSrcDef"/>
> +      <optional>
> +        <element name="target">
> +          <optional>
> +            <attribute name="port"/>
> +          </optional>
> +        </element>
> +      </optional>
> +    </interleave>
> +  </define>
> +  <define name="qemucdevSrcType">
>      <attribute name="type">
>        <choice>
>          <value>dev</value>
> @@ -944,43 +957,36 @@
>          <value>pty</value>
>        </choice>
>      </attribute>
> -    <interleave>
> -      <optional>
> -        <oneOrMore>
> -          <element name="source">
> -            <optional>
> -              <attribute name="mode"/>
> -            </optional>
> -            <optional>
> -              <attribute name="path"/>
> -            </optional>
> -            <optional>
> -              <attribute name="host"/>
> -            </optional>
> -            <optional>
> -              <attribute name="service"/>
> -            </optional>
> -            <optional>
> -              <attribute name="wiremode"/>
> -            </optional>
> -          </element>
> -        </oneOrMore>
> -      </optional>
> -      <optional>
> -        <element name="protocol">
> +  </define>
> +  <define name="qemucdevSrcDef">
> +    <optional>
> +      <oneOrMore>
> +        <element name="source">
>            <optional>
> -            <attribute name="type"/>
> +            <attribute name="mode"/>
>            </optional>
> -        </element>
> -      </optional>
> -      <optional>
> -        <element name="target">
>            <optional>
> -            <attribute name="port"/>
> +            <attribute name="path"/>
> +          </optional>
> +          <optional>
> +            <attribute name="host"/>
> +          </optional>
> +          <optional>
> +            <attribute name="service"/>
> +          </optional>
> +          <optional>
> +            <attribute name="wiremode"/>
>            </optional>
>          </element>
> -      </optional>
> -    </interleave>
> +      </oneOrMore>
> +    </optional>
> +    <optional>
> +      <element name="protocol">
> +        <optional>
> +          <attribute name="type"/>
> +        </optional>
> +      </element>
> +    </optional>
>    </define>
>    <!--
>        The description for a console
> @@ -1044,6 +1050,24 @@
>        <ref name="qemucdev"/>
>      </element>
>    </define>
> +  <define name="guestfwdTarget">
> +    <element name="target">
> +        <attribute name="type">
> +            <value>guestfwd</value>
> +        </attribute>
> +        <attribute name="address"/>
> +        <attribute name="port"/>
> +    </element>
> +  </define>
> +  <define name="channel">
> +    <element name="channel">
> +      <ref name="qemucdevSrcType"/>
> +      <interleave>
> +        <ref name="qemucdevSrcDef"/>
> +        <ref name="guestfwdTarget"/>
> +      </interleave>
> +    </element>
> +  </define>
>    <define name="input">
>      <element name="input">
>        <attribute name="type">
> @@ -1158,6 +1182,7 @@
>              <ref name="console"/>
>              <ref name="parallel"/>
>              <ref name="serial"/>
> +            <ref name="channel"/>
>            </choice>
>          </zeroOrMore>
>          <optional>
> diff --git a/proxy/Makefile.am b/proxy/Makefile.am
> index 3e0050b..42f6a81 100644
> --- a/proxy/Makefile.am
> +++ b/proxy/Makefile.am
> @@ -17,6 +17,7 @@ libvirt_proxy_SOURCES = libvirt_proxy.c \
>              @top_srcdir@/src/util/buf.c \
>           @top_srcdir@/src/util/logging.c \
>              @top_srcdir@/src/util/memory.c \
> +            @top_srcdir@/src/util/network.c \
>           @top_srcdir@/src/util/threads.c  \
>              @top_srcdir@/src/util/util.c \
>           @top_srcdir@/src/util/uuid.c \
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index fc70cfd..94bce1e 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -40,6 +40,7 @@
>  #include "buf.h"
>  #include "c-ctype.h"
>  #include "logging.h"
> +#include "network.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_DOMAIN
>  
> @@ -132,7 +133,8 @@ VIR_ENUM_IMPL(virDomainChrTarget, 
> VIR_DOMAIN_CHR_TARGET_TYPE_LAST,
>                "monitor",
>                "parallel",
>                "serial",
> -              "console")
> +              "console",
> +              "guestfwd")
>  
>  VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
>                "null",
> @@ -412,6 +414,12 @@ void virDomainChrDefFree(virDomainChrDefPtr def)
>      if (!def)
>          return;
>  
> +    switch (def->targetType) {
> +    case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
> +        VIR_FREE(def->target.addr);
> +        break;
> +    }
> +
>      switch (def->type) {
>      case VIR_DOMAIN_CHR_TYPE_PTY:
>      case VIR_DOMAIN_CHR_TYPE_DEV:
> @@ -541,6 +549,7 @@ void virDomainDefFree(virDomainDefPtr def)
>      for (i = 0 ; i < def->nnets ; i++)
>          virDomainNetDefFree(def->nets[i]);
>      VIR_FREE(def->nets);
> +
>      for (i = 0 ; i < def->nserials ; i++)
>          virDomainChrDefFree(def->serials[i]);
>      VIR_FREE(def->serials);
> @@ -549,6 +558,10 @@ void virDomainDefFree(virDomainDefPtr def)
>          virDomainChrDefFree(def->parallels[i]);
>      VIR_FREE(def->parallels);
>  
> +    for (i = 0 ; i < def->nchannels ; i++)
> +        virDomainChrDefFree(def->channels[i]);
> +    VIR_FREE(def->channels);
> +
>      virDomainChrDefFree(def->console);
>  
>      for (i = 0 ; i < def->nsounds ; i++)
> @@ -1332,7 +1345,10 @@ virDomainChrDefParseXML(virConnectPtr conn,
>      char *path = NULL;
>      char *mode = NULL;
>      char *protocol = NULL;
> +    const char *nodeName;
>      const char *targetType = NULL;
> +    const char *addrStr = NULL;
> +    const char *portStr = NULL;
>      virDomainChrDefPtr def;
>  
>      if (VIR_ALLOC(def) < 0) {
> @@ -1346,18 +1362,15 @@ virDomainChrDefParseXML(virConnectPtr conn,
>      else if ((def->type = virDomainChrTypeFromString(type)) < 0)
>          def->type = VIR_DOMAIN_CHR_TYPE_NULL;
>  
> -    targetType = (const char *) node->name;
> -    if (targetType == NULL) {
> -        /* Shouldn't be possible */
> -        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
> -                             "node->name is NULL at %s:%i",
> -                             __FILE__, __LINE__);
> -        return NULL;
> -    }
> -    if ((def->targetType = virDomainChrTargetTypeFromString(targetType)) < 
> 0) {
> -        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
> -                             _("unknown target type for character device: 
> %s"),
> -                             targetType);
> +    nodeName = (const char *) node->name;
> +    if ((def->targetType = virDomainChrTargetTypeFromString(nodeName)) < 0) {
> +        /* channel is handled below */
> +        if(STRNEQ(nodeName, "channel")) {
> +            virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN,
> +                              _("unknown target type for character device: 
> %s"),
> +                                 nodeName);
> +            return NULL;
> +        }
>          def->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_NULL;
>      }
>  
> @@ -1406,6 +1419,89 @@ virDomainChrDefParseXML(virConnectPtr conn,
>              } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
>                  if (protocol == NULL)
>                      protocol = virXMLPropString(cur, "type");
> +            } else if (xmlStrEqual(cur->name, BAD_CAST "target")) {
> +                /* If target type isn't set yet, expect it to be set here */
> +                if(def->targetType == VIR_DOMAIN_CHR_TARGET_TYPE_NULL) {
> +                    targetType = virXMLPropString(cur, "type");
> +                    if(targetType == NULL) {
> +                        virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN, 
> "%s",
> +                                             _("character device target does 
> "
> +                                               "not define a type"));
> +                        goto error;
> +                    }
> +                    if ((def->targetType =
> +                        virDomainChrTargetTypeFromString(targetType)) < 0)
> +                    {
> +                        virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN,
> +                                             _("unknown target type for "
> +                                               "character device: %s"),
> +                                             targetType);
> +                        goto error;
> +                    }
> +                }
> +
> +                unsigned int port;
> +                switch (def->targetType) {
> +                case VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL:
> +                case VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL:
> +                case VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE:
> +                    portStr = virXMLPropString(cur, "port");
> +                    if(portStr == NULL) {
> +                        /* Not required. It will be assigned automatically
> +                         * later */
> +                        break;
> +                    }
> +
> +                    if(virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
> +                        virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN,
> +                                             _("Invalid port number: %s"),
> +                                             portStr);
> +                        goto error;
> +                    }
> +                    break;
> +
> +                case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
> +                    addrStr = virXMLPropString(cur, "address");
> +                    portStr = virXMLPropString(cur, "port");
> +
> +                    if(addrStr == NULL) {
> +                        virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN, 
> "%s",
> +                                             _("guestfwd channel does not "
> +                                               "define a target address"));
> +                        goto error;
> +                    }
> +                    if(VIR_ALLOC(def->target.addr) < 0) {
> +                        virReportOOMError(conn);
> +                        goto error;
> +                    }
> +                    if(virSocketParseAddr(addrStr, def->target.addr, 0) < 0)
> +                    {
> +                        virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN,
> +                                             _("%s is not a valid address"),
> +                                             addrStr);
> +                        goto error;
> +                    }
> +
> +                    if(portStr == NULL) {
> +                        virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN, 
> "%s",
> +                                             _("guestfwd channel does "
> +                                               "not define a target port"));
> +                        goto error;
> +                    }
> +                    if(virStrToLong_ui(portStr, NULL, 10, &port) < 0) {
> +                        virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN,
> +                                             _("Invalid port number: %s"),
> +                                             portStr);
> +                        goto error;
> +                    }
> +                    virSocketSetPort(def->target.addr, port);
> +                    break;
> +
> +                default:
> +                    virDomainReportError(conn, VIR_ERR_INVALID_DOMAIN,
> +                                         _("unexpected target type type %u"),
> +                                         def->targetType);
> +                }
>              }
>          }
>          cur = cur->next;
> @@ -1535,6 +1631,9 @@ cleanup:
>      VIR_FREE(connectHost);
>      VIR_FREE(connectService);
>      VIR_FREE(path);
> +    VIR_FREE(targetType);
> +    VIR_FREE(addrStr);
> +    VIR_FREE(portStr);
>  
>      return def;
>  
> @@ -3007,6 +3106,25 @@ static virDomainDefPtr 
> virDomainDefParseXML(virConnectPtr conn,
>          }
>      }
>  
> +    if ((n = virXPathNodeSet(conn, "./devices/channel", ctxt, &nodes)) < 0) {
> +        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
> +                             "%s", _("cannot extract channel devices"));
> +        goto error;
> +    }
> +    if (n && VIR_ALLOC_N(def->channels, n) < 0)
> +        goto no_memory;
> +
> +    for (i = 0 ; i < n ; i++) {
> +        virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
> +                                                         nodes[i],
> +                                                         flags);
> +        if (!chr)
> +            goto error;
> +
> +        def->channels[def->nchannels++] = chr;
> +    }
> +    VIR_FREE(nodes);
> +
>  
>      /* analysis of the input devices */
>      if ((n = virXPathNodeSet(conn, "./devices/input", ctxt, &nodes)) < 0) {
> @@ -3992,13 +4110,26 @@ virDomainChrDefFormat(virConnectPtr conn,
>  {
>      const char *type = virDomainChrTypeToString(def->type);
>      const char *targetName = virDomainChrTargetTypeToString(def->targetType);
> +    const char *elementName;
> +
> +    const char *addr = NULL;
> +    int ret = 0;
> +
> +    switch (def->targetType) {
> +    /* channel types are in a common channel element */
> +    case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
> +        elementName = "channel";
> +        break;
>  
> -    const char *elementName = targetName; /* Currently always the same */
> +    default:
> +        elementName = targetName;
> +    }
>  
>      if (!type) {
>          virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
>                               _("unexpected char type %d"), def->type);
> -        return -1;
> +        ret = -1;
> +        goto cleanup;
>      }
>  
>      /* Compat with legacy  <console tty='/dev/pts/5'/> syntax */
> @@ -4080,6 +4211,25 @@ virDomainChrDefFormat(virConnectPtr conn,
>      }
>  
>      switch (def->targetType) {
> +    case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
> +        addr = virSocketFormatAddr(def->target.addr);
> +        if (addr == NULL) {
> +            virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
> +                                 _("Unable to format guestfwd address"));
> +            ret = -1;
> +            goto cleanup;
> +        }
> +        int port = virSocketGetPort(def->target.addr);
> +        if (port < 0) {
> +            virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
> +                                 _("Unable to format guestfwd port"));
> +            ret = -1;
> +            goto cleanup;
> +        }
> +        virBufferVSprintf(buf, "      <target type='guestfwd' address='%s' 
> port='%d'/>\n",
> +                          addr, port);
> +        break;
> +
>      case VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL:
>      case VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL:
>      case VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE:
> @@ -4097,7 +4247,10 @@ virDomainChrDefFormat(virConnectPtr conn,
>      virBufferVSprintf(buf, "    </%s>\n",
>                        elementName);
>  
> -    return 0;
> +cleanup:
> +    VIR_FREE(addr);
> +
> +    return ret;
>  }
>  
>  static int
> @@ -4563,6 +4716,10 @@ char *virDomainDefFormat(virConnectPtr conn,
>              goto cleanup;
>      }
>  
> +    for (n = 0 ; n < def->nchannels ; n++)
> +        if (virDomainChrDefFormat(conn, &buf, def->channels[n], flags) < 0)
> +            goto cleanup;
> +
>      for (n = 0 ; n < def->ninputs ; n++)
>          if (def->inputs[n]->bus == VIR_DOMAIN_INPUT_BUS_USB &&
>              virDomainInputDefFormat(conn, &buf, def->inputs[n]) < 0)
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 7bd8c63..e826cc7 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -34,6 +34,7 @@
>  #include "util.h"
>  #include "threads.h"
>  #include "hash.h"
> +#include "network.h"
>  
>  /* Private component of virDomainXMLFlags */
>  typedef enum {
> @@ -217,6 +218,7 @@ enum virDomainChrTargetType {
>      VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL,
>      VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL,
>      VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE,
> +    VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD,
>  
>      VIR_DOMAIN_CHR_TARGET_TYPE_LAST
>  };
> @@ -249,6 +251,7 @@ struct _virDomainChrDef {
>      int targetType;
>      union {
>          int port; /* parallel, serial, console */
> +        virSocketAddrPtr addr; /* guestfwd */
>      } target;
>  
>      int type;
> @@ -623,6 +626,9 @@ struct _virDomainDef {
>      int nparallels;
>      virDomainChrDefPtr *parallels;
>  
> +    int nchannels;
> +    virDomainChrDefPtr *channels;
> +
>      /* Only 1 */
>      virDomainChrDefPtr console;
>      virSecurityLabelDef seclabel;
> diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
> index a9f6885..b83df33 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -51,6 +51,7 @@
>  #include "xml.h"
>  #include "nodeinfo.h"
>  #include "logging.h"
> +#include "network.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_QEMU
>  
> @@ -1478,6 +1479,29 @@ static void 
> qemudBuildCommandLineChrDevChardevStr(virDomainChrDefPtr dev,
>      }
>  }
>  
> +static int qemudBuildCommandLineChrDevTargetStr(virDomainChrDefPtr dev,
> +                                                const char *const id,
> +                                                virBufferPtr buf)
> +{
> +    int ret = 0;
> +    const char *addr = NULL;
> +
> +    int port;
> +    switch (dev->targetType) {
> +    case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
> +        addr = virSocketFormatAddr(dev->target.addr);
> +        port = virSocketGetPort(dev->target.addr);
> +
> +        virBufferVSprintf(buf, "user,guestfwd=tcp:%s:%i-chardev:%s",
> +                          addr, port, id);
> +
> +        VIR_FREE(addr);
> +        break;
> +    }
> +
> +    return ret;
> +}
> +
>  /* This function outputs an all-in-one character device command line option 
> */
>  static int qemudBuildCommandLineChrDevStr(virDomainChrDefPtr dev,
>                                            char *buf,
> @@ -2156,6 +2180,46 @@ int qemudBuildCommandLine(virConnectPtr conn,
>          }
>      }
>  
> +    for (i = 0 ; i < def->nchannels ; i++) {
> +        virBuffer buf = VIR_BUFFER_INITIALIZER;
> +        const char *argStr;
> +        char id[16];
> +
> +        virDomainChrDefPtr channel = def->channels[i];
> +
> +        if (snprintf(id, sizeof(id), "channel%i", i) > sizeof(id))
> +            goto error;
> +
> +        switch(channel->targetType) {
> +        case VIR_DOMAIN_CHR_TARGET_TYPE_GUESTFWD:
> +            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV)) {
> +                qemudReportError(conn, NULL, NULL, VIR_ERR_NO_SUPPORT,
> +                     "%s", _("guestfwd requires QEMU to support -chardev"));
> +                goto error;
> +            }
> +
> +            qemudBuildCommandLineChrDevChardevStr(channel, id, &buf);
> +            argStr = virBufferContentAndReset(&buf);
> +            if (argStr == NULL)
> +                goto error;
> +
> +            ADD_ARG_LIT("-chardev");
> +            ADD_ARG_LIT(argStr);
> +
> +            VIR_FREE(argStr);
> +
> +            qemudBuildCommandLineChrDevTargetStr(channel, id, &buf);
> +            argStr = virBufferContentAndReset(&buf);
> +            if (argStr == NULL)
> +                goto error;
> +
> +            ADD_ARG_LIT("-net");
> +            ADD_ARG_LIT(argStr);
> +
> +            VIR_FREE(argStr);
> +        }
> +    }
> +
>      ADD_ARG_LIT("-usb");
>      for (i = 0 ; i < def->ninputs ; i++) {
>          virDomainInputDefPtr input = def->inputs[i];
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.args 
> b/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.args
> new file mode 100644
> index 0000000..b5bb46d
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.args
> @@ -0,0 +1 @@
> +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 none -serial none -parallel 
> none -chardev pipe,id=channel0,path=/tmp/guestfwd -net 
> user,guestfwd=tcp:10.0.2.1:4600-chardev:channel0 -usb
> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.xml 
> b/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.xml
> new file mode 100644
> index 0000000..51a0c1e
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/qemuxml2argv-channel-guestfwd.xml
> @@ -0,0 +1,26 @@
> +<domain type='qemu'>
> +  <name>QEMUGuest1</name>
> +  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
> +  <memory>219200</memory>
> +  <currentMemory>219200</currentMemory>
> +  <vcpu cpuset='1-4,8-20,525'>1</vcpu>
> +  <os>
> +    <type arch='i686' machine='pc'>hvm</type>
> +    <boot dev='hd'/>
> +  </os>
> +  <clock offset='utc'/>
> +  <on_poweroff>destroy</on_poweroff>
> +  <on_reboot>restart</on_reboot>
> +  <on_crash>destroy</on_crash>
> +  <devices>
> +    <emulator>/usr/bin/qemu</emulator>
> +    <disk type='block' device='disk'>
> +      <source dev='/dev/HostVG/QEMUGuest1'/>
> +      <target dev='hda' bus='ide'/>
> +    </disk>
> +    <channel type='pipe'>
> +      <source path='/tmp/guestfwd'/>
> +      <target type='guestfwd' address='10.0.2.1' port='4600'/>
> +    </channel>
> +  </devices>
> +</domain>
> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
> index 3255146..c948379 100644
> --- a/tests/qemuxml2argvtest.c
> +++ b/tests/qemuxml2argvtest.c
> @@ -268,11 +268,13 @@ mymain(int argc, char **argv)
>      DO_TEST("serial-many", 0);
>      DO_TEST("parallel-tcp", 0);
>      DO_TEST("console-compat", 0);
> +
> +    DO_TEST("channel-guestfwd", QEMUD_CMD_FLAG_CHARDEV);
> +
>      DO_TEST("sound", 0);
>  
>      DO_TEST("hostdev-usb-product", 0);
>      DO_TEST("hostdev-usb-address", 0);
> -
>      DO_TEST("hostdev-pci-address", QEMUD_CMD_FLAG_PCIDEVICE);
>  
>      DO_TEST_FULL("restore-v1", QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO, "stdio");
> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
> index 2cba47b..25ef2ce 100644
> --- a/tests/qemuxml2xmltest.c
> +++ b/tests/qemuxml2xmltest.c
> @@ -129,6 +129,7 @@ mymain(int argc, char **argv)
>      DO_TEST("serial-many");
>      DO_TEST("parallel-tcp");
>      DO_TEST("console-compat");
> +    DO_TEST("channel-guestfwd");
>  
>      DO_TEST("hostdev-usb-product");
>      DO_TEST("hostdev-usb-address");
> -- 

ACK

Daniel
-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to