This patch updates the network driver to properly utilize the new attributes/elements that are now in virNetworkDef
Signed-off-by: Shradha Shah <ss...@solarflare.com> --- docs/formatnetwork.html.in | 62 +++++++++++++ src/network/bridge_driver.c | 213 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 240 insertions(+), 35 deletions(-) diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in index 7e8e991..96b9eb2 100644 --- a/docs/formatnetwork.html.in +++ b/docs/formatnetwork.html.in @@ -210,6 +210,37 @@ (usually either a domain start, or a hotplug interface attach to a domain).<span class="since">Since 0.9.4</span> </dd> + <dt><code>hostdev</code></dt> + <dd> + This network facilitates PCI Passthrough of a network device. + A network device is chosen from the interface pool and + 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.1Qbh capable switch using an optionally specified + <code><virtualport></code> element. + 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 <code>< + hostdev></code> device definition and <span class="since"> + Since 0.9.12</span> + + <p>Note that this "intelligent passthrough" of network devices is + very similar to the functionality of a standard <code>< + hostdev></code> device, the difference being that this + method allows specifying a MAC address and <code><virtualport + ></code> 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.12, you should use standard + <code><hostdev></code> to assign the device to the + guest instead of <code><forward mode='hostdev'/></code>. + </p> + </dd> </dl> As mentioned above, a <code><forward></code> element can have multiple <code><interface></code> subelements, each @@ -249,6 +280,37 @@ particular, 'passthrough' mode, and 'private' mode when using 802.1Qbh), libvirt will choose an unused physical interface or, if it can't find an unused interface, fail the operation.</p> + + <span class="since">since 0.9.12</span> and when using forward mode + 'hostdev' we specify the interface pool by using the + <code><address></code> element and <code>< + type></code> <code><domain></code> <code><bus></code> + <code><slot></code> and <code><function></code> + sub-elements. + + <pre> +... + <forward mode='hostdev' managed='yes'> + <address type='pci' domain='0' bus='4' slot='0' function='1'/> + <address type='pci' domain='0' bus='4' slot='0' function='2'/> + <address type='pci' domain='0' bus='4' slot='0' function='3'/> + </forward> +... + </pre> + + Alternatively the interface pool can also be mentioned using a + single physical function <code><pf></code> subelement to + call out the corresponding physical interface associated with + multiple virtual interfaces (similar to the passthrough mode): + + <pre> +... + <forward mode='hostdev' managed='yes'> + <pf dev='eth0'/> + </forward> +... + </pre> + </dd> </dl> <h5><a name="elementQoS">Quality of service</a></h5> diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c index 6ce41b5..35636a8 100644 --- a/src/network/bridge_driver.c +++ b/src/network/bridge_driver.c @@ -1939,7 +1939,7 @@ networkStartNetworkExternal(struct network_driver *driver ATTRIBUTE_UNUSED, virNetworkObjPtr network ATTRIBUTE_UNUSED) { /* put anything here that needs to be done each time a network of - * type BRIDGE, PRIVATE, VEPA, or PASSTHROUGH is started. On + * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is started. On * failure, undo anything you've done, and return -1. On success * return 0. */ @@ -1950,7 +1950,7 @@ static int networkShutdownNetworkExternal(struct network_driver *driver ATTRIBUT virNetworkObjPtr network ATTRIBUTE_UNUSED) { /* put anything here that needs to be done each time a network of - * type BRIDGE, PRIVATE, VEPA, or PASSTHROUGH is shutdown. On + * type BRIDGE, PRIVATE, VEPA, HOSTDEV or PASSTHROUGH is shutdown. On * failure, undo anything you've done, and return -1. On success * return 0. */ @@ -1981,6 +1981,7 @@ networkStartNetwork(struct network_driver *driver, case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: ret = networkStartNetworkExternal(driver, network); break; } @@ -2040,6 +2041,7 @@ static int networkShutdownNetwork(struct network_driver *driver, case VIR_NETWORK_FORWARD_PRIVATE: case VIR_NETWORK_FORWARD_VEPA: case VIR_NETWORK_FORWARD_PASSTHROUGH: + case VIR_NETWORK_FORWARD_HOSTDEV: ret = networkShutdownNetworkExternal(driver, network); break; } @@ -2781,7 +2783,7 @@ networkCreateInterfacePool(virNetworkDefPtr netdef) { goto finish; } } - else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { netdef->forwardIfs[ii].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI; /*Assuming PCI as VF's are PCI devices */ netdef->forwardIfs[ii].device.pci.domain = virt_fns[ii]->domain; netdef->forwardIfs[ii].device.pci.bus = virt_fns[ii]->bus; @@ -2820,6 +2822,8 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) virNetworkObjPtr network; virNetworkDefPtr netdef; virPortGroupDefPtr portgroup; + virNetDevVPortProfilePtr virtport = NULL; + virNetworkForwardIfDefPtr dev = NULL; int ii; int ret = -1; @@ -2872,6 +2876,7 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) */ if (iface->data.network.actual) iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_NETWORK; + } else if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) && netdef->bridge) { @@ -2892,11 +2897,74 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) goto cleanup; } + } else if (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) { + if (!iface->data.network.actual + && (VIR_ALLOC(iface->data.network.actual) < 0)) { + virReportOOMError(); + goto cleanup; + } + + iface->data.network.actual->type = VIR_DOMAIN_NET_TYPE_HOSTDEV; + if ((netdef->nForwardPfs > 0) && (netdef->nForwardIfs <= 0)) { + if(networkCreateInterfacePool(netdef) < 0) { + networkReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not create Interface Pool from PF")); + goto cleanup; + } + } + /* pick first dev with 0 usageCount */ + + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (netdef->forwardIfs[ii].usageCount == 0) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + if (!dev) { + networkReportError(VIR_ERR_INTERNAL_ERROR, + _("network '%s' requires exclusive access to interfaces, but none are available"), + netdef->name); + goto cleanup; + } + iface->data.network.actual->data.hostdev.def.parent.type = VIR_DOMAIN_DEVICE_NET; + iface->data.network.actual->data.hostdev.def.parent.data.net = iface; + iface->data.network.actual->data.hostdev.def.info = &iface->info; + iface->data.network.actual->data.hostdev.def.mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS; + iface->data.network.actual->data.hostdev.def.managed = netdef->managed; + iface->data.network.actual->data.hostdev.def.source.subsys.type = dev->type; + iface->data.network.actual->data.hostdev.def.source.subsys.u.pci = dev->device.pci; + + if (iface->data.network.virtPortProfile) { + virtport = iface->data.network.virtPortProfile; + } else { + if (portgroup) + virtport = portgroup->virtPortProfile; + else + virtport = netdef->virtPortProfile; + } + if (virtport) { + if (VIR_ALLOC(iface->data.network.actual->data.hostdev.virtPortProfile) < 0) { + virReportOOMError(); + goto cleanup; + } + /* There are no pointers in a virtualPortProfile, so a shallow copy + * is sufficient + */ + *iface->data.network.actual->data.direct.virtPortProfile = *virtport; + } + + dev->usageCount++; + VIR_DEBUG("Using physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } else if ((netdef->forwardType == VIR_NETWORK_FORWARD_BRIDGE) || (netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) || (netdef->forwardType == VIR_NETWORK_FORWARD_VEPA) || (netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH)) { - virNetDevVPortProfilePtr virtport = NULL; /* <forward type='bridge|private|vepa|passthrough'> are all * VIR_DOMAIN_NET_TYPE_DIRECT. @@ -2954,7 +3022,6 @@ networkAllocateActualDevice(virDomainNetDefPtr iface) netdef->name); goto cleanup; } else { - virNetworkForwardIfDefPtr dev = NULL; /* pick an interface from the pool */ @@ -3046,14 +3113,16 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network; virNetworkDefPtr netdef; - const char *actualDev; + const char *actualDev = NULL; + virDomainHostdevDefPtr def = NULL; int ret = -1; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) return 0; if (!iface->data.network.actual || - (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT)) { + ((virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT) && + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV))) { VIR_DEBUG("Nothing to claim from network %s", iface->data.network.name); return 0; } @@ -3068,17 +3137,28 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) goto cleanup; } - actualDev = virDomainNetGetActualDirectDev(iface); - if (!actualDev) { - networkReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("the interface uses a direct mode, but has no source dev")); - goto cleanup; + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + actualDev = virDomainNetGetActualDirectDev(iface); + if (!actualDev) { + networkReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a direct mode, but has no source dev")); + goto cleanup; + } + } + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + def = virDomainNetGetActualHostdev(iface); + if (!def) { + networkReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a hostdev mode, but has no hostdev")); + goto cleanup; + } } netdef = network->def; if (netdef->nForwardIfs == 0) { networkReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' uses a direct mode, but has no forward dev and no interface pool"), + _("network '%s' uses a direct/hostdev mode, but has no forward dev and no interface pool"), netdef->name); goto cleanup; } else { @@ -3086,13 +3166,27 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) virNetworkForwardIfDefPtr dev = NULL; /* find the matching interface in the pool and increment its usageCount */ + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + } - for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { - dev = &netdef->forwardIfs[ii]; - break; + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if((def->source.subsys.u.pci.domain == netdef->forwardIfs[ii].device.pci.domain) && + (def->source.subsys.u.pci.bus == netdef->forwardIfs[ii].device.pci.bus) && + (def->source.subsys.u.pci.slot == netdef->forwardIfs[ii].device.pci.slot) && + (def->source.subsys.u.pci.function == netdef->forwardIfs[ii].device.pci.function)) { + dev = &netdef->forwardIfs[ii]; + break; + } } } + /* dev points at the physical device we want to use */ if (!dev) { networkReportError(VIR_ERR_INTERNAL_ERROR, @@ -3107,6 +3201,7 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) */ if ((dev->usageCount > 0) && ((netdef->forwardType == VIR_NETWORK_FORWARD_PASSTHROUGH) || + (netdef->forwardType == VIR_NETWORK_FORWARD_HOSTDEV) || ((netdef->forwardType == VIR_NETWORK_FORWARD_PRIVATE) && iface->data.network.actual->data.direct.virtPortProfile && (iface->data.network.actual->data.direct.virtPortProfile->virtPortType @@ -3118,8 +3213,18 @@ networkNotifyActualDevice(virDomainNetDefPtr iface) } /* we are now assured of success, so mark the allocation */ dev->usageCount++; - VIR_DEBUG("Using physical device %s, usageCount %d", - dev->device.dev, dev->usageCount); + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + VIR_DEBUG("Using physical device %s, usageCount %d", + dev->device.dev, dev->usageCount); + } + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + VIR_DEBUG("Using physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } } ret = 0; @@ -3146,14 +3251,16 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) struct network_driver *driver = driverState; virNetworkObjPtr network = NULL; virNetworkDefPtr netdef; - const char *actualDev; + const char *actualDev = NULL; + virDomainHostdevDefPtr def = NULL; int ret = -1; if (iface->type != VIR_DOMAIN_NET_TYPE_NETWORK) return 0; if (!iface->data.network.actual || - (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT)) { + ((virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_DIRECT) && + (virDomainNetGetActualType(iface) != VIR_DOMAIN_NET_TYPE_HOSTDEV))) { VIR_DEBUG("Nothing to release to network %s", iface->data.network.name); ret = 0; goto cleanup; @@ -3169,29 +3276,55 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) goto cleanup; } - actualDev = virDomainNetGetActualDirectDev(iface); - if (!actualDev) { - networkReportError(VIR_ERR_INTERNAL_ERROR, - "%s", _("the interface uses a direct mode, but has no source dev")); - goto cleanup; + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + actualDev = virDomainNetGetActualDirectDev(iface); + if (!actualDev) { + networkReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a direct mode, but has no source dev")); + goto cleanup; + } + } + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + def = virDomainNetGetActualHostdev(iface); + if (!def) { + networkReportError(VIR_ERR_INTERNAL_ERROR, + "%s", _("the interface uses a hostdev mode, but has no hostdev")); + goto cleanup; + } } netdef = network->def; if (netdef->nForwardIfs == 0) { networkReportError(VIR_ERR_INTERNAL_ERROR, - _("network '%s' uses a direct mode, but has no forward dev and no interface pool"), + _("network '%s' uses a direct/hostdev mode, but has no forward dev and no interface pool"), netdef->name); goto cleanup; } else { int ii; virNetworkForwardIfDefPtr dev = NULL; - - for (ii = 0; ii < netdef->nForwardIfs; ii++) { - if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { - dev = &netdef->forwardIfs[ii]; - break; + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if (STREQ(actualDev, netdef->forwardIfs[ii].device.dev)) { + dev = &netdef->forwardIfs[ii]; + break; + } + } + } + + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + for (ii = 0; ii < netdef->nForwardIfs; ii++) { + if((def->source.subsys.u.pci.domain == netdef->forwardIfs[ii].device.pci.domain) && + (def->source.subsys.u.pci.bus == netdef->forwardIfs[ii].device.pci.bus) && + (def->source.subsys.u.pci.slot == netdef->forwardIfs[ii].device.pci.slot) && + (def->source.subsys.u.pci.function == netdef->forwardIfs[ii].device.pci.function)) { + dev = &netdef->forwardIfs[ii]; + break; + } } } + /* dev points at the physical device we've been using */ if (!dev) { networkReportError(VIR_ERR_INTERNAL_ERROR, @@ -3201,10 +3334,20 @@ networkReleaseActualDevice(virDomainNetDefPtr iface) } dev->usageCount--; - VIR_DEBUG("Releasing physical device %s, usageCount %d", - dev->device.dev, dev->usageCount); + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_DIRECT) { + VIR_DEBUG("Releasing physical device %s, usageCount %d", + dev->device.dev, dev->usageCount); + } + if (virDomainNetGetActualType(iface) == VIR_DOMAIN_NET_TYPE_HOSTDEV) { + VIR_DEBUG("Releasing physical device with domain=%d bus=%d slot=%d function=%d, usageCount %d", + dev->device.pci.domain, + dev->device.pci.bus, + dev->device.pci.slot, + dev->device.pci.function, + dev->usageCount); + } } - + ret = 0; cleanup: if (network) -- 1.7.4.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list