conf: support abstracted interface info in domain interface XML

the domain XML <interface> element is updated in the following ways:

1) <virtualportprofile> can be specified when source type='network'
(previously it was only valid for source type='direct')

2) A new attribute "portgroup" has been added to the <source>
element. When source type='network' (the only time portgroup is
recognized), extra configuration information will be taken from the
<portgroup> element of the given name in the network definition.

3) Each virDomainNetDef now also potentially has a
virDomainActualNetDef which is a private object (never
exported/imported via the public API, and not defined in the RNG) that
is used to maintain information about the physical device that was
actually used for a NetDef of type VIR_DOMAIN_NET_TYPE_NETWORK.

The virDomainActualNetDef will only be parsed/formatted if the
parse/format function is called with the
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET flag set (which is only needed when
saving/loading a running domain's state info to the stateDir).
This commit is contained in:
Laine Stump 2011-06-26 04:09:00 -04:00
parent 524655eea2
commit 07f4136993
8 changed files with 409 additions and 22 deletions

1
cfg.mk
View File

@ -97,6 +97,7 @@ useless_free_options = \
--name=virCommandFree \
--name=virConfFreeList \
--name=virConfFreeValue \
--name=virDomainActualNetDefFree \
--name=virDomainChrDefFree \
--name=virDomainChrSourceDefFree \
--name=virDomainControllerDefFree \

View File

@ -1391,24 +1391,55 @@
<p>
<strong><em>
This is the recommended config for general guest connectivity on
hosts with dynamic / wireless networking configs
hosts with dynamic / wireless networking configs (or multi-host
environments where the host hardware details are described
separately in a <code>&lt;network&gt;</code>
definition <span class="since">Since 0.9.4</span>).
</em></strong>
</p>
<p>
Provides a virtual network using a bridge device in the host.
Depending on the virtual network configuration, the network may be
totally isolated, NAT'ing to an explicit network device, or NAT'ing to
the default route. DHCP and DNS are provided on the virtual network in
all cases and the IP range can be determined by examining the virtual
network config with '<code>virsh net-dumpxml [networkname]</code>'.
There is one virtual network called 'default' setup out
of the box which does NAT'ing to the default route and has an IP range of
<code>192.168.122.0/255.255.255.0</code>. Each guest will have an
associated tun device created with a name of vnetN, which can also be
overridden with the &lt;target&gt; element (see
Provides a connection whose details are described by the named
network definition. Depending on the virtual network's "forward
mode" configuration, the network may be totally isolated
(no <code>&lt;forward&gt;</code> element given), NAT'ing to an
explicit network device or to the default route
(<code>&lt;forward mode='nat'&gt;</code>), routed with no NAT
(<code>&lt;forward mode='route'/&gt;</code>), or connected
directly to one of the host's network interfaces (via macvtap)
or bridge devices ((<code>&lt;forward
mode='bridge|private|vepa|passthrough'/&gt;</code> <span class="since">Since
0.9.4</span>)
</p>
<p>
For networks with a forward mode of bridge, private, vepa, and
passthrough, it is assumed that the host has any necessary DNS
and DHCP services already setup outside the scope of libvirt. In
the case of isolated, nat, and routed networks, DHCP and DNS are
provided on the virtual network by libvirt, and the IP range can
be determined by examining the virtual network config with
'<code>virsh net-dumpxml [networkname]</code>'. There is one
virtual network called 'default' setup out of the box which does
NAT'ing to the default route and has an IP range
of <code>192.168.122.0/255.255.255.0</code>. Each guest will
have an associated tun device created with a name of vnetN,
which can also be overridden with the &lt;target&gt; element
(see
<a href="#elementsNICSTargetOverride">overriding the target element</a>).
</p>
<p>
When the source of an interface is a network,
a <code>portgroup</code> can be specified along with the name of
the network; one network may have multiple portgroups defined,
with each portgroup containing slightly different configuration
information for different classes of network
connections. <span class="since">Since 0.9.4</span>). Also,
similar to <code>direct</code> network connections (described
below), a connection of type <code>network</code> may specify
a <code>virtportprofile</code> element, with configuration data
to be forwarded to a vepa or 802.1Qbh compliant switch.
</p>
<pre>
...
@ -1418,9 +1449,13 @@
&lt;/interface&gt;
...
&lt;interface type='network'&gt;
&lt;source network='default'/&gt;
&lt;source network='default' portgroup='engineering'/&gt;
&lt;target dev='vnet7'/&gt;
&lt;mac address="00:11:22:33:44:55"/&gt;
&lt;virtualport type='802.1Qbg'&gt;
&lt;parameters managerid='11' typeid='1193047' typeidversion='2' instanceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/&gt;
&lt;/virtualport&gt;
&lt;/interface&gt;
&lt;/devices&gt;
...</pre>

View File

@ -1036,8 +1036,16 @@
<attribute name="network">
<ref name="deviceName"/>
</attribute>
<optional>
<attribute name="portgroup">
<ref name="deviceName"/>
</attribute>
</optional>
<empty/>
</element>
<optional>
<ref name="virtualPortProfile"/>
</optional>
<ref name="interface-options"/>
</interleave>
</group>

View File

@ -56,10 +56,11 @@
* verify that it doesn't overflow an unsigned int when shifting */
verify(VIR_DOMAIN_VIRT_LAST <= 32);
/* Private flag used internally by virDomainSaveStatus and
* virDomainObjParseFile. */
/* Private flags used internally by virDomainSaveStatus and
* virDomainLoadStatus. */
typedef enum {
VIR_DOMAIN_XML_INTERNAL_STATUS = (1<<16), /* dump internal domain status information */
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET = (1<<17), /* dump/parse <actual> element */
} virDomainXMLInternalFlags;
VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
@ -734,6 +735,27 @@ void virDomainFSDefFree(virDomainFSDefPtr def)
VIR_FREE(def);
}
void
virDomainActualNetDefFree(virDomainActualNetDefPtr def)
{
if (!def)
return;
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
VIR_FREE(def->data.bridge.brname);
break;
case VIR_DOMAIN_NET_TYPE_DIRECT:
VIR_FREE(def->data.direct.linkdev);
VIR_FREE(def->data.direct.virtPortProfile);
break;
default:
break;
}
VIR_FREE(def);
}
void virDomainNetDefFree(virDomainNetDefPtr def)
{
if (!def)
@ -756,6 +778,9 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
case VIR_DOMAIN_NET_TYPE_NETWORK:
VIR_FREE(def->data.network.name);
VIR_FREE(def->data.network.portgroup);
VIR_FREE(def->data.network.virtPortProfile);
virDomainActualNetDefFree(def->data.network.actual);
break;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
@ -2586,6 +2611,81 @@ cleanup:
goto cleanup;
}
static int
virDomainActualNetDefParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
virDomainActualNetDefPtr *def)
{
virDomainActualNetDefPtr actual = NULL;
int ret = -1;
xmlNodePtr save_ctxt = ctxt->node;
char *type = NULL;
char *mode = NULL;
if (VIR_ALLOC(actual) < 0) {
virReportOOMError();
return -1;
}
ctxt->node = node;
type = virXMLPropString(node, "type");
if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing type attribute in interface's <actual> element"));
goto error;
}
if ((actual->type = virDomainNetTypeFromString(type)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown type '%s' in interface's <actual> element"), type);
goto error;
}
if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
actual->type != VIR_DOMAIN_NET_TYPE_DIRECT) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unsupported type '%s' in interface's <actual> element"),
type);
goto error;
}
if (actual->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
actual->data.bridge.brname = virXPathString("string(./source[1]/@bridge)", ctxt);
} else if (actual->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
xmlNodePtr virtPortNode;
actual->data.direct.linkdev = virXPathString("string(./source[1]/@dev)", ctxt);
mode = virXPathString("string(./source[1]/@mode)", ctxt);
if (mode) {
int m;
if ((m = virMacvtapModeTypeFromString(mode)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("Unkown mode '%s' in interface <actual> element"),
mode);
goto error;
}
actual->data.direct.mode = m;
}
virtPortNode = virXPathNode("./virtualport", ctxt);
if (virtPortNode &&
virVirtualPortProfileParseXML(virtPortNode,
&actual->data.direct.virtPortProfile) < 0) {
goto error;
}
}
*def = actual;
actual = NULL;
ret = 0;
error:
VIR_FREE(type);
VIR_FREE(mode);
virDomainActualNetDefFree(actual);
ctxt->node = save_ctxt;
return ret;
}
/* Parse the XML definition for a network interface
* @param node XML nodeset to parse for net definition
@ -2603,6 +2703,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *macaddr = NULL;
char *type = NULL;
char *network = NULL;
char *portgroup = NULL;
char *bridge = NULL;
char *dev = NULL;
char *ifname = NULL;
@ -2619,6 +2720,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
char *mode = NULL;
virNWFilterHashTablePtr filterparams = NULL;
virVirtualPortProfileParamsPtr virtPort = NULL;
virDomainActualNetDefPtr actual = NULL;
xmlNodePtr oldnode = ctxt->node;
int ret;
@ -2650,6 +2752,7 @@ virDomainNetDefParseXML(virCapsPtr caps,
(def->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
network = virXMLPropString(cur, "network");
portgroup = virXMLPropString(cur, "portgroup");
} else if ((internal == NULL) &&
(def->type == VIR_DOMAIN_NET_TYPE_INTERNAL) &&
(xmlStrEqual(cur->name, BAD_CAST "source"))) {
@ -2665,7 +2768,8 @@ virDomainNetDefParseXML(virCapsPtr caps,
dev = virXMLPropString(cur, "dev");
mode = virXMLPropString(cur, "mode");
} else if ((virtPort == NULL) &&
(def->type == VIR_DOMAIN_NET_TYPE_DIRECT) &&
((def->type == VIR_DOMAIN_NET_TYPE_DIRECT) ||
(def->type == VIR_DOMAIN_NET_TYPE_NETWORK)) &&
xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
if (virVirtualPortProfileParseXML(cur, &virtPort) < 0)
goto error;
@ -2713,6 +2817,12 @@ virDomainNetDefParseXML(virCapsPtr caps,
if (virDomainDeviceBootParseXML(cur, &def->bootIndex,
bootMap))
goto error;
} else if ((actual == NULL) &&
(flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
(def->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
xmlStrEqual(cur->name, BAD_CAST "actual")) {
if (virDomainActualNetDefParseXML(cur, ctxt, &actual) < 0)
goto error;
}
}
cur = cur->next;
@ -2761,6 +2871,12 @@ virDomainNetDefParseXML(virCapsPtr caps,
}
def->data.network.name = network;
network = NULL;
def->data.network.portgroup = portgroup;
portgroup = NULL;
def->data.network.virtPortProfile = virtPort;
virtPort = NULL;
def->data.network.actual = actual;
actual = NULL;
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
@ -2956,11 +3072,13 @@ cleanup:
ctxt->node = oldnode;
VIR_FREE(macaddr);
VIR_FREE(network);
VIR_FREE(portgroup);
VIR_FREE(address);
VIR_FREE(port);
VIR_FREE(ifname);
VIR_FREE(dev);
VIR_FREE(virtPort);
virDomainActualNetDefFree(actual);
VIR_FREE(script);
VIR_FREE(bridge);
VIR_FREE(model);
@ -8536,6 +8654,67 @@ virDomainFSDefFormat(virBufferPtr buf,
return 0;
}
static int
virDomainActualNetDefFormat(virBufferPtr buf,
virDomainActualNetDefPtr def)
{
int ret = -1;
const char *type;
const char *mode;
if (!def)
return 0;
type = virDomainNetTypeToString(def->type);
if (!type) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected net type %d"), def->type);
return ret;
}
if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
def->type != VIR_DOMAIN_NET_TYPE_DIRECT) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected net type %s"), type);
goto error;
}
virBufferAsprintf(buf, " <actual type='%s'>\n", type);
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
if (def->data.bridge.brname) {
virBufferEscapeString(buf, " <source bridge='%s'/>\n",
def->data.bridge.brname);
}
break;
case VIR_DOMAIN_NET_TYPE_DIRECT:
virBufferAddLit(buf, " <source");
if (def->data.direct.linkdev)
virBufferEscapeString(buf, " dev='%s'",
def->data.direct.linkdev);
mode = virMacvtapModeTypeToString(def->data.direct.mode);
if (!mode) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected source mode %d"),
def->data.direct.mode);
return ret;
}
virBufferAsprintf(buf, " mode='%s'/>\n", mode);
virVirtualPortProfileFormat(buf, def->data.direct.virtPortProfile,
" ");
break;
default:
break;
}
virBufferAddLit(buf, " </actual>\n");
ret = 0;
error:
return ret;
}
static int
virDomainNetDefFormat(virBufferPtr buf,
virDomainNetDefPtr def,
@ -8559,8 +8738,18 @@ virDomainNetDefFormat(virBufferPtr buf,
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_NETWORK:
virBufferEscapeString(buf, " <source network='%s'/>\n",
virBufferEscapeString(buf, " <source network='%s'",
def->data.network.name);
if (def->data.network.portgroup) {
virBufferEscapeString(buf, " portgroup='%s'",
def->data.network.portgroup);
}
virBufferAddLit(buf, "/>\n");
virVirtualPortProfileFormat(buf, def->data.network.virtPortProfile,
" ");
if ((flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
(virDomainActualNetDefFormat(buf, def->data.network.actual) < 0))
return -1;
break;
case VIR_DOMAIN_NET_TYPE_ETHERNET:
@ -9445,9 +9634,11 @@ virDomainHostdevDefFormat(virBufferPtr buf,
VIR_DOMAIN_XML_INACTIVE | \
VIR_DOMAIN_XML_UPDATE_CPU)
verify((VIR_DOMAIN_XML_INTERNAL_STATUS & DUMPXML_FLAGS) == 0);
verify(((VIR_DOMAIN_XML_INTERNAL_STATUS |
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET)
& DUMPXML_FLAGS) == 0);
/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_STATUS,
/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_*,
* whereas the public version cannot. */
static char *
virDomainDefFormatInternal(virDomainDefPtr def,
@ -9459,7 +9650,10 @@ virDomainDefFormatInternal(virDomainDefPtr def,
const char *type = NULL;
int n, allones = 1;
virCheckFlags(DUMPXML_FLAGS | VIR_DOMAIN_XML_INTERNAL_STATUS, NULL);
virCheckFlags(DUMPXML_FLAGS |
VIR_DOMAIN_XML_INTERNAL_STATUS |
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET,
NULL);
if (!(type = virDomainVirtTypeToString(def->virtType))) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@ -10024,7 +10218,10 @@ int virDomainSaveStatus(virCapsPtr caps,
const char *statusDir,
virDomainObjPtr obj)
{
unsigned int flags = VIR_DOMAIN_XML_SECURE|VIR_DOMAIN_XML_INTERNAL_STATUS;
unsigned int flags = (VIR_DOMAIN_XML_SECURE |
VIR_DOMAIN_XML_INTERNAL_STATUS |
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET);
int ret = -1;
char *xml;
@ -10115,7 +10312,8 @@ static virDomainObjPtr virDomainLoadStatus(virCapsPtr caps,
goto error;
if (!(obj = virDomainObjParseFile(caps, statusFile, expectedVirtTypes,
VIR_DOMAIN_XML_INTERNAL_STATUS)))
VIR_DOMAIN_XML_INTERNAL_STATUS |
VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET)))
goto error;
virUUIDFormat(obj->def->uuid, uuidstr);
@ -11112,3 +11310,68 @@ virDomainStateReasonFromString(virDomainState state, const char *reason)
return -1;
}
/* Some access functions to gloss over the difference between NetDef
* (<interface>) and ActualNetDef (<actual>). If the NetDef has an
* ActualNetDef, return the requested value from the ActualNetDef,
* otherwise return the value from the NetDef.
*/
int
virDomainNetGetActualType(virDomainNetDefPtr iface)
{
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
return iface->type;
if (!iface->data.network.actual)
return iface->type;
return iface->data.network.actual->type;
}
char *
virDomainNetGetActualBridgeName(virDomainNetDefPtr iface)
{
if (iface->type == VIR_DOMAIN_NET_TYPE_BRIDGE)
return iface->data.bridge.brname;
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
return NULL;
if (!iface->data.network.actual)
return NULL;
return iface->data.network.actual->data.bridge.brname;
}
char *
virDomainNetGetActualDirectDev(virDomainNetDefPtr iface)
{
if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
return iface->data.direct.linkdev;
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
return NULL;
if (!iface->data.network.actual)
return NULL;
return iface->data.network.actual->data.direct.linkdev;
}
int
virDomainNetGetActualDirectMode(virDomainNetDefPtr iface)
{
if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
return iface->data.direct.mode;
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
return 0;
if (!iface->data.network.actual)
return 0;
return iface->data.network.actual->data.direct.mode;
}
virVirtualPortProfileParamsPtr
virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface)
{
if (iface->type == VIR_DOMAIN_NET_TYPE_DIRECT)
return iface->data.direct.virtPortProfile;
if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK)
return NULL;
if (!iface->data.network.actual)
return NULL;
return iface->data.network.actual->data.direct.virtPortProfile;
}

View File

@ -343,6 +343,27 @@ enum virDomainNetVirtioTxModeType {
VIR_DOMAIN_NET_VIRTIO_TX_MODE_LAST,
};
/* Config that was actually used to bring up interface, after
* resolving network reference. This is private data, only used within
* libvirt, but still must maintain backward compatibility, because
* different versions of libvirt may read the same data file.
*/
typedef struct _virDomainActualNetDef virDomainActualNetDef;
typedef virDomainActualNetDef *virDomainActualNetDefPtr;
struct _virDomainActualNetDef {
int type; /* enum virDomainNetType */
union {
struct {
char *brname;
} bridge;
struct {
char *linkdev;
int mode; /* enum virMacvtapMode from util/macvtap.h */
virVirtualPortProfileParamsPtr virtPortProfile;
} direct;
} data;
};
/* Stores the virtual network interface configuration */
typedef struct _virDomainNetDef virDomainNetDef;
typedef virDomainNetDef *virDomainNetDefPtr;
@ -369,6 +390,17 @@ struct _virDomainNetDef {
} socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */
struct {
char *name;
char *portgroup;
virVirtualPortProfileParamsPtr virtPortProfile;
/* actual has info about the currently used physical
* device (if the network is of type
* bridge/private/vepa/passthrough). This is saved in the
* domain state, but never written to persistent config,
* since it needs to be re-allocated whenever the domain
* is restarted. It is also never shown to the user, and
* the user cannot specify it in XML documents.
*/
virDomainActualNetDefPtr actual;
} network;
struct {
char *brname;
@ -1340,6 +1372,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def);
void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def);
void virDomainControllerDefFree(virDomainControllerDefPtr def);
void virDomainFSDefFree(virDomainFSDefPtr def);
void virDomainActualNetDefFree(virDomainActualNetDefPtr def);
void virDomainNetDefFree(virDomainNetDefPtr def);
void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def);
void virDomainChrDefFree(virDomainChrDefPtr def);
@ -1450,6 +1483,13 @@ int virDomainNetIndexByMac(virDomainDefPtr def, const unsigned char *mac);
int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net);
int virDomainNetRemoveByMac(virDomainDefPtr def, const unsigned char *mac);
int virDomainNetGetActualType(virDomainNetDefPtr iface);
char *virDomainNetGetActualBridgeName(virDomainNetDefPtr iface);
char *virDomainNetGetActualDirectDev(virDomainNetDefPtr iface);
int virDomainNetGetActualDirectMode(virDomainNetDefPtr iface);
virVirtualPortProfileParamsPtr
virDomainNetGetActualDirectVirtPortProfile(virDomainNetDefPtr iface);
int virDomainControllerInsert(virDomainDefPtr def,
virDomainControllerDefPtr controller);
void virDomainControllerInsertPreAlloced(virDomainDefPtr def,

View File

@ -228,6 +228,7 @@ virDomainAuditVcpu;
# domain_conf.h
virDiskNameToBusDeviceIndex;
virDiskNameToIndex;
virDomainActualNetDefFree;
virDomainAssignDef;
virDomainChrConsoleTargetTypeFromString;
virDomainChrConsoleTargetTypeToString;
@ -334,6 +335,11 @@ virDomainLoadAllConfigs;
virDomainMemballoonModelTypeFromString;
virDomainMemballoonModelTypeToString;
virDomainNetDefFree;
virDomainNetGetActualBridgeName;
virDomainNetGetActualDirectDev;
virDomainNetGetActualDirectMode;
virDomainNetGetActualType;
virDomainNetGetActualDirectVirtPortProfile;
virDomainNetIndexByMac;
virDomainNetInsert;
virDomainNetRemoveByMac;

View File

@ -0,0 +1,33 @@
<domain type='qemu'>
<name>QEMUGuest1</name>
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
<memory>219136</memory>
<currentMemory>219136</currentMemory>
<vcpu>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'/>
<address type='drive' controller='0' bus='0' unit='0'/>
</disk>
<controller type='ide' index='0'/>
<interface type='network'>
<mac address='00:11:22:33:44:55'/>
<source network='rednet' portgroup='bob'/>
<virtualport type='802.1Qbg'>
<parameters managerid='11' typeid='1193047' typeidversion='2' instanceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
</virtualport>
<model type='virtio'/>
</interface>
<memballoon model='virtio'/>
</devices>
</domain>

View File

@ -158,6 +158,7 @@ mymain(void)
DO_TEST("net-virtio-device");
DO_TEST("net-eth");
DO_TEST("net-eth-ifname");
DO_TEST("net-virtio-network-portgroup");
DO_TEST("sound");
DO_TEST("serial-vc");