...
</pre>
+
+ <h5><a name="elementsNICSHostdev">PCI Passthrough</a></h5>
+
+ <p>
+ A PCI network device (specified by the <source> element)
+ is directly assigned to the guest using generic device
+ passthrough, after first optionally setting the device's MAC
+ address to the configured value, and associating the device with
+ an 802.1Qgh capable switch using an optionally specified
+ %lt;virtualport%gt; element (see the examples of virtualport
+ given above for type='direct' network devices). Note that - due
+ to limitations in standard single-port PCI ethernet card driver
+ design - only SR-IOV (Single Root I/O Virtualization) virtual
+ function (VF) devices can be assigned in this manner; to assign
+ a standard single-port PCI or PCIe ethernet card to a guest, use
+ the traditional <hostdev> device definition and
+ <span class="since">Since 0.9.11</span>
+ </p>
+
+ <p>
+ Note that this "intelligent passthrough" of network devices is
+ very similar to the functionality of a standard <hostdev>
+ device, the difference being that this method allows specifying
+ a MAC address and <virtualport> for the passed-through
+ device. If these capabilities are not required, if you have a
+ standard single-port PCI, PCIe, or USB network card that doesn't
+ support SR-IOV (and hence would anyway lose the configured MAC
+ address during reset after being assigned to the guest domain),
+ or if you are using a version of libvirt older than 0.9.11, you
+ should use standard <hostdev> to assign the device to the
+ guest instead of <interface type='hostdev'/>.
+ </p>
+
+<pre>
+ ...
+ <devices>
+ <interface type='hostdev'>
+ <source>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
+ </source>
+ <mac address='52:54:00:6d:90:02'>
+ <virtualport type='802.1Qbh'>
+ <parameters profileid='finance'/>
+ </virtualport>
+ </interface>
+ </devices>
+ ...</pre>
+
+
<h5><a name="elementsNICSMulticast">Multicast tunnel</a></h5>
<p>
"network",
"bridge",
"internal",
- "direct")
+ "direct",
+ "hostdev")
VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST,
"default",
VIR_FREE(def->data.direct.linkdev);
VIR_FREE(def->data.direct.virtPortProfile);
break;
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ virDomainHostdevDefClear(&def->data.hostdev.def);
+ VIR_FREE(def->data.hostdev.virtPortProfile);
+ break;
default:
break;
}
VIR_FREE(def->data.direct.virtPortProfile);
break;
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ virDomainHostdevDefClear(&def->data.hostdev.def);
+ VIR_FREE(def->data.hostdev.virtPortProfile);
+ break;
+
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_LAST:
break;
static int
virDomainActualNetDefParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt,
- virDomainActualNetDefPtr *def)
+ virDomainNetDefPtr parent,
+ virDomainActualNetDefPtr *def,
+ unsigned int flags)
{
virDomainActualNetDefPtr actual = NULL;
int ret = -1;
xmlNodePtr bandwidth_node = NULL;
char *type = NULL;
char *mode = NULL;
+ char *addrtype = NULL;
if (VIR_ALLOC(actual) < 0) {
virReportOOMError();
}
if (actual->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
actual->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
+ actual->type != VIR_DOMAIN_NET_TYPE_HOSTDEV &&
actual->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unsupported type '%s' in interface's <actual> element"),
(!(actual->data.direct.virtPortProfile =
virNetDevVPortProfileParse(virtPortNode))))
goto error;
+ } else if (actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
+ xmlNodePtr virtPortNode = virXPathNode("./virtualport", ctxt);
+ virDomainHostdevDefPtr hostdev = &actual->data.hostdev.def;
+
+ hostdev->parent.type = VIR_DOMAIN_DEVICE_NET;
+ hostdev->parent.data.net = parent;
+ hostdev->info = &parent->info;
+ /* The helper function expects type to already be found and
+ * passed in as a string, since it is in a different place in
+ * NetDef vs HostdevDef.
+ */
+ addrtype = virXPathString("string(./source/address/@type)", ctxt);
+ /* if not explicitly stated, source/vendor implies usb device */
+ if ((!addrtype) && virXPathNode("./source/vendor", ctxt) &&
+ ((addrtype = strdup("usb")) == NULL)) {
+ virReportOOMError();
+ goto error;
+ }
+ if (virDomainHostdevPartsParse(node, ctxt, NULL, addrtype,
+ hostdev, flags) < 0) {
+ goto error;
+ }
+
+ if (virtPortNode &&
+ (!(actual->data.hostdev.virtPortProfile =
+ virNetDevVPortProfileParse(virtPortNode)))) {
+ goto error;
+ }
}
bandwidth_node = virXPathNode("./bandwidth", ctxt);
error:
VIR_FREE(type);
VIR_FREE(mode);
+ VIR_FREE(addrtype);
virDomainActualNetDefFree(actual);
ctxt->node = save_ctxt;
unsigned int flags)
{
virDomainNetDefPtr def;
+ virDomainHostdevDefPtr hostdev;
xmlNodePtr cur;
char *macaddr = NULL;
char *type = NULL;
char *devaddr = NULL;
char *mode = NULL;
char *linkstate = NULL;
+ char *addrtype = NULL;
virNWFilterHashTablePtr filterparams = NULL;
virNetDevVPortProfilePtr virtPort = NULL;
virDomainActualNetDefPtr actual = NULL;
} else if ((virtPort == NULL) &&
((def->type == VIR_DOMAIN_NET_TYPE_DIRECT) ||
(def->type == VIR_DOMAIN_NET_TYPE_NETWORK) ||
- (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE)) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)) &&
xmlStrEqual(cur->name, BAD_CAST "virtualport")) {
if (!(virtPort = virNetDevVPortProfileParse(cur)))
goto error;
(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)
+ if (virDomainActualNetDefParseXML(cur, ctxt, def,
+ &actual, flags) < 0) {
goto error;
+ }
} else if (xmlStrEqual(cur->name, BAD_CAST "bandwidth")) {
if (!(def->bandwidth = virNetDevBandwidthParse(cur)))
goto error;
break;
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ hostdev = &def->data.hostdev.def;
+ hostdev->parent.type = VIR_DOMAIN_DEVICE_NET;
+ hostdev->parent.data.net = def;
+ hostdev->info = &def->info;
+ /* The helper function expects type to already be found and
+ * passed in as a string, since it is in a different place in
+ * NetDef vs HostdevDef.
+ */
+ addrtype = virXPathString("string(./source/address/@type)", ctxt);
+ /* if not explicitly stated, source/vendor implies usb device */
+ if ((!addrtype) && virXPathNode("./source/vendor", ctxt) &&
+ ((addrtype = strdup("usb")) == NULL)) {
+ virReportOOMError();
+ goto error;
+ }
+ if (virDomainHostdevPartsParse(node, ctxt, NULL, addrtype,
+ hostdev, flags) < 0) {
+ goto error;
+ }
+ def->data.hostdev.virtPortProfile = virtPort;
+ virtPort = NULL;
+ break;
+
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_LAST:
break;
VIR_FREE(devaddr);
VIR_FREE(mode);
VIR_FREE(linkstate);
+ VIR_FREE(addrtype);
virNWFilterHashTableFree(filterparams);
return def;
static int
virDomainActualNetDefFormat(virBufferPtr buf,
- virDomainActualNetDefPtr def)
+ virDomainActualNetDefPtr def,
+ unsigned int flags)
{
int ret = -1;
const char *type;
return ret;
}
- if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
- def->type != VIR_DOMAIN_NET_TYPE_DIRECT &&
- def->type != VIR_DOMAIN_NET_TYPE_NETWORK) {
- virDomainReportError(VIR_ERR_INTERNAL_ERROR,
- _("unexpected net type %s"), type);
- goto error;
+ virBufferAsprintf(buf, " <actual type='%s'", type);
+ if ((def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) &&
+ def->data.hostdev.def.managed) {
+ virBufferAddLit(buf, " managed='yes'");
}
- virBufferAsprintf(buf, " <actual type='%s'>\n", type);
+ virBufferAddLit(buf, ">\n");
switch (def->type) {
case VIR_DOMAIN_NET_TYPE_BRIDGE:
goto error;
virBufferAdjustIndent(buf, -8);
break;
- default:
+
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ virBufferAdjustIndent(buf, 8);
+ if (virDomainHostdevSourceFormat(buf, &def->data.hostdev.def,
+ flags, true) < 0) {
+ return -1;
+ }
+ if (virNetDevVPortProfileFormat(def->data.hostdev.virtPortProfile,
+ buf) < 0) {
+ return -1;
+ }
+ virBufferAdjustIndent(buf, -8);
break;
+
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ break;
+ default:
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected net type %s"), type);
+ goto error;
}
virBufferAdjustIndent(buf, 8);
return -1;
}
- virBufferAsprintf(buf, " <interface type='%s'>\n", type);
+ virBufferAsprintf(buf, " <interface type='%s'", type);
+ if ((def->type == VIR_DOMAIN_NET_TYPE_HOSTDEV) &&
+ def->data.hostdev.def.managed) {
+ virBufferAddLit(buf, " managed='yes'");
+ }
+ virBufferAddLit(buf, ">\n");
virBufferAsprintf(buf,
" <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
return -1;
virBufferAdjustIndent(buf, -6);
if ((flags & VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET) &&
- (virDomainActualNetDefFormat(buf, def->data.network.actual) < 0))
+ (virDomainActualNetDefFormat(buf, def->data.network.actual, flags) < 0))
return -1;
break;
virBufferAdjustIndent(buf, -6);
break;
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ virBufferAdjustIndent(buf, 6);
+ if (virDomainHostdevSourceFormat(buf, &def->data.hostdev.def,
+ flags, true) < 0) {
+ return -1;
+ }
+ if (virNetDevVPortProfileFormat(def->data.hostdev.virtPortProfile,
+ buf) < 0) {
+ return -1;
+ }
+ virBufferAdjustIndent(buf, -6);
+ break;
+
case VIR_DOMAIN_NET_TYPE_USER:
case VIR_DOMAIN_NET_TYPE_LAST:
break;
return iface->data.network.actual->data.direct.mode;
}
+virDomainHostdevDefPtr
+virDomainNetGetActualHostdev(virDomainNetDefPtr iface)
+{
+ if (iface->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)
+ return &iface->data.hostdev.def;
+ if ((iface->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
+ (iface->data.network.actual->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
+ return &iface->data.network.actual->data.hostdev.def;
+ }
+ return NULL;
+}
+
virNetDevVPortProfilePtr
virDomainNetGetActualVirtPortProfile(virDomainNetDefPtr iface)
{
return iface->data.direct.virtPortProfile;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
return iface->data.bridge.virtPortProfile;
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ return iface->data.hostdev.virtPortProfile;
case VIR_DOMAIN_NET_TYPE_NETWORK:
if (!iface->data.network.actual)
return NULL;
return iface->data.network.actual->data.direct.virtPortProfile;
case VIR_DOMAIN_NET_TYPE_BRIDGE:
return iface->data.network.actual->data.bridge.virtPortProfile;
+ case VIR_DOMAIN_NET_TYPE_HOSTDEV:
+ return iface->data.network.actual->data.hostdev.virtPortProfile;
default:
return NULL;
}