On 03/05/2012 08:12 PM, Roopa Prabhu wrote: > From: Roopa Prabhu <roprabhu@xxxxxxxxx> > > These changes are applied only if the hostdev has a parent net device. > If the parent netdevice has virtual port information, the original virtualport > associate functions are called (these set and restore both mac and port profile > on an interface). Else, only mac address is set on the device > using other methods depending on if its a sriov device or not. > > Changes also include hotplug pci devices > > Signed-off-by: Roopa Prabhu <roprabhu@xxxxxxxxx> > --- > src/qemu/qemu_hostdev.c | 241 +++++++++++++++++++++++++++++++++++++++++++++-- > src/qemu/qemu_hostdev.h | 8 +- > src/qemu/qemu_hotplug.c | 10 ++ > 3 files changed, 246 insertions(+), 13 deletions(-) > > > diff --git a/src/qemu/qemu_hostdev.c b/src/qemu/qemu_hostdev.c > index b3cad8e..ebcdc52 100644 > --- a/src/qemu/qemu_hostdev.c > +++ b/src/qemu/qemu_hostdev.c > @@ -29,6 +29,13 @@ > #include "memory.h" > #include "pci.h" > #include "hostusb.h" > +#include "virnetdev.h" > + > +VIR_ENUM_IMPL(virNetDevVPort, VIR_NETDEV_VPORT_PROFILE_LAST, > + "none", > + "802.1Qbg", > + "802.1Qbh", > + "openvswitch") > > static pciDeviceList * > qemuGetPciHostDeviceList(virDomainHostdevDefPtr *hostdevs, int nhostdevs) > @@ -156,19 +163,192 @@ int qemuUpdateActivePciHostdevs(struct qemud_driver *driver, > return 0; > } > > +static int > +qemuDomainHostdevPciSysfsPath(virDomainHostdevDefPtr hostdev, char **sysfs_path) > +{ > + struct pci_config_address config_address; > + > + config_address.domain = hostdev->source.subsys.u.pci.domain; > + config_address.bus = hostdev->source.subsys.u.pci.bus; > + config_address.slot = hostdev->source.subsys.u.pci.slot; > + config_address.function = hostdev->source.subsys.u.pci.function; > + > + return pciConfigAddressToSysfsFile(&config_address, sysfs_path); > +} > + > +int > +qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev) > +{ > + char *sysfs_path = NULL; > + int ret = -1; > + > + if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) > + return ret; > + > + ret = pciDeviceIsVirtualFunction(sysfs_path); > + > + VIR_FREE(sysfs_path); > + > + return ret; > +} > + > +static int > +qemuDomainHostdevNetDevice(virDomainHostdevDefPtr hostdev, char **linkdev, > + int *vf) > +{ > + int ret = -1; > + char *sysfs_path = NULL; > + > + if (qemuDomainHostdevPciSysfsPath(hostdev, &sysfs_path) < 0) > + return ret; > + > + if (pciDeviceIsVirtualFunction(sysfs_path) == 1) { > + if (pciDeviceGetVirtualFunctionInfo(sysfs_path, linkdev, > + vf) < 0) > + goto cleanup; > + } else { > + if (pciDeviceNetName(sysfs_path, linkdev) < 0) > + goto cleanup; > + *vf = -1; > + } > + > + ret = 0; > + > +cleanup: > + VIR_FREE(sysfs_path); > + > + return ret; > +} > + > +static int > +qemuDomainHostdevNetConfigVirtPortProfile(const char *linkdev, int vf, > + virNetDevVPortProfilePtr virtPort, > + const unsigned char *macaddr, > + const unsigned char *uuid, > + int associate) > +{ > + int ret = -1; > + > + if (!virtPort) > + return ret; > + > + switch(virtPort->virtPortType) { > + case VIR_NETDEV_VPORT_PROFILE_NONE: > + case VIR_NETDEV_VPORT_PROFILE_OPENVSWITCH: > + case VIR_NETDEV_VPORT_PROFILE_8021QBG: > + case VIR_NETDEV_VPORT_PROFILE_LAST: > + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("virtualport type %s is " > + "currently not supported on interfaces of type " > + "hostdev"), > + virNetDevVPortTypeToString(virtPort->virtPortType)); > + break; > + > + case VIR_NETDEV_VPORT_PROFILE_8021QBH: > + if (associate) > + ret = virNetDevVPortProfileAssociate(NULL, virtPort, macaddr, > + linkdev, vf, uuid, > + VIR_NETDEV_VPORT_PROFILE_OP_CREATE, false); > + else > + ret = virNetDevVPortProfileDisassociate(NULL, virtPort, > + macaddr, linkdev, vf, > + VIR_NETDEV_VPORT_PROFILE_OP_DESTROY); > + break; > + } > + > + return ret; > +} > + > +int > +qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, > + const unsigned char *uuid, > + char *stateDir) > +{ > + char *linkdev = NULL; > + virNetDevVPortProfilePtr virtPort; > + int ret = -1; > + int vf = -1; > + int vlanid = -1; > + int port_profile_associate = 1; > + int isvf; > + > + isvf = qemuDomainHostdevIsVirtualFunction(hostdev); > + if (isvf <= 0) { > + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("Interface type hostdev is currently supported on" > + " sriov Virtual functions only")); I changed the capitalization a bit here: "SR-IOV Virtual Functions". > + return ret; > + } > + > + if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0) > + return ret; > + > + virtPort = virDomainNetGetActualVirtPortProfile( > + hostdev->parent.data.net); > + if (virtPort) > + ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, > + virtPort, hostdev->parent.data.net->mac, uuid, > + port_profile_associate); > + else > + /* Set only mac */ > + ret = virNetDevReplaceNetConfig(linkdev, vf, > + hostdev->parent.data.net->mac, vlanid, > + stateDir); > + VIR_FREE(linkdev); > + > + return ret; > +} > + > +int > +qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, > + char *stateDir) > +{ > + char *linkdev = NULL; > + virNetDevVPortProfilePtr virtPort; > + int ret = -1; > + int vf = -1; > + int port_profile_associate = 0; > + int isvf; > + > + isvf = qemuDomainHostdevIsVirtualFunction(hostdev); > + if (isvf <= 0) { > + qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, > + _("Interface type hostdev is currently supported on" > + " sriov Virtual functions only")); ditto. > + return ret; > + } > + > + if (qemuDomainHostdevNetDevice(hostdev, &linkdev, &vf) < 0) > + return ret; > + > + virtPort = virDomainNetGetActualVirtPortProfile( > + hostdev->parent.data.net); > + if (virtPort) > + ret = qemuDomainHostdevNetConfigVirtPortProfile(linkdev, vf, virtPort, > + hostdev->parent.data.net->mac, NULL, > + port_profile_associate); > + else > + ret = virNetDevRestoreNetConfig(linkdev, vf, stateDir); > + > + VIR_FREE(linkdev); > + > + return ret; > +} > + > int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, > const char *name, > + const unsigned char *uuid, > virDomainHostdevDefPtr *hostdevs, > int nhostdevs) > { > pciDeviceList *pcidevs; > + int last_processed_hostdev_vf = -1; > int i; > int ret = -1; > > if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs))) > return -1; > > - /* We have to use 7 loops here. *All* devices must > + /* We have to use 9 loops here. *All* devices must > * be detached before we reset any of them, because > * in some cases you have to reset the whole PCI, > * which impacts all devices on it. Also, all devices > @@ -225,7 +405,22 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, > goto reattachdevs; > } > > - /* Loop 4: Now mark all the devices as active */ > + /* Loop 4: For SRIOV network devices, Now that we have detached the > + * the network device, set the netdev config */ > + for (i = 0; i < nhostdevs; i++) { > + virDomainHostdevDefPtr hostdev = hostdevs[i]; > + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) > + continue; > + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) > + continue; > + if (hostdev->parent.data.net) While this currently will work, I had figured that (to allow for the possibility of other smart hostdev types) we should check this way: if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && hostdev->parent.data.net) I'm squashing that in to the three places you check for this. > + if (qemuDomainHostdevNetConfigReplace(hostdev, uuid, > + driver->stateDir) < 0) > + goto resetvfnetconfig; > + last_processed_hostdev_vf = i; > + } > + > + /* Loop 5: Now mark all the devices as active */ > for (i = 0; i < pciDeviceListCount(pcidevs); i++) { > pciDevice *dev = pciDeviceListGet(pcidevs, i); > if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) { > @@ -234,13 +429,13 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, > } > } > > - /* Loop 5: Now remove the devices from inactive list. */ > + /* Loop 6: Now remove the devices from inactive list. */ > for (i = 0; i < pciDeviceListCount(pcidevs); i++) { > pciDevice *dev = pciDeviceListGet(pcidevs, i); > pciDeviceListDel(driver->inactivePciHostdevs, dev); > } > > - /* Loop 6: Now set the used_by_domain of the device in > + /* Loop 7: Now set the used_by_domain of the device in > * driver->activePciHostdevs as domain name. > */ > for (i = 0; i < pciDeviceListCount(pcidevs); i++) { > @@ -252,7 +447,7 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, > pciDeviceSetUsedBy(activeDev, name); > } > > - /* Loop 7: Now set the original states for hostdev def */ > + /* Loop 8: Now set the original states for hostdev def */ > for (i = 0; i < nhostdevs; i++) { > pciDevice *dev; > pciDevice *pcidev; > @@ -284,7 +479,7 @@ int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, > pciFreeDevice(dev); > } > > - /* Loop 8: Now steal all the devices from pcidevs */ > + /* Loop 9: Now steal all the devices from pcidevs */ > while (pciDeviceListCount(pcidevs) > 0) { > pciDevice *dev = pciDeviceListGet(pcidevs, 0); > pciDeviceListSteal(pcidevs, dev); > @@ -302,6 +497,13 @@ inactivedevs: > pciDeviceListSteal(driver->activePciHostdevs, dev); > } > > +resetvfnetconfig: > + for (i = 0; i < last_processed_hostdev_vf; i++) { > + virDomainHostdevDefPtr hostdev = hostdevs[i]; > + if (hostdev->parent.data.net) > + qemuDomainHostdevNetConfigRestore(hostdev, driver->stateDir); > + } > + > reattachdevs: > for (i = 0; i < pciDeviceListCount(pcidevs); i++) { > pciDevice *dev = pciDeviceListGet(pcidevs, i); > @@ -317,10 +519,10 @@ static int > qemuPrepareHostPCIDevices(struct qemud_driver *driver, > virDomainDefPtr def) > { > - return qemuPrepareHostdevPCIDevices(driver, def->name, def->hostdevs, def->nhostdevs); > + return qemuPrepareHostdevPCIDevices(driver, def->name, def->uuid, > + def->hostdevs, def->nhostdevs); > } > > - > int > qemuPrepareHostdevUSBDevices(struct qemud_driver *driver, > const char *name, > @@ -494,8 +696,10 @@ void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver, > return; > } > > - /* Again 3 loops; mark all devices as inactive before reset > - * them and reset all the devices before re-attach */ > + /* Again 4 loops; mark all devices as inactive before reset > + * them and reset all the devices before re-attach. > + * Attach mac and port profile parameters to devices > + */ > for (i = 0; i < pciDeviceListCount(pcidevs); i++) { > pciDevice *dev = pciDeviceListGet(pcidevs, i); > pciDevice *activeDev = NULL; > @@ -514,6 +718,20 @@ void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver, > pciDeviceListSteal(driver->activePciHostdevs, dev); > } > > + /* > + * For SRIOV net host devices, unset mac and port profile before > + * reset and reattach device > + */ > + for (i = 0; i < nhostdevs; i++) { > + virDomainHostdevDefPtr hostdev = hostdevs[i]; > + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) > + continue; > + if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) > + continue; > + if (hostdev->parent.data.net) > + qemuDomainHostdevNetConfigRestore(hostdev, driver->stateDir); > + } > + > for (i = 0; i < pciDeviceListCount(pcidevs); i++) { > pciDevice *dev = pciDeviceListGet(pcidevs, i); > if (pciResetDevice(dev, driver->activePciHostdevs, > @@ -540,5 +758,6 @@ void qemuDomainReAttachHostDevices(struct qemud_driver *driver, > if (!def->nhostdevs) > return; > > - qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs, def->nhostdevs); > + qemuDomainReAttachHostdevDevices(driver, def->name, def->hostdevs, > + def->nhostdevs); > } > diff --git a/src/qemu/qemu_hostdev.h b/src/qemu/qemu_hostdev.h > index d852f5b..173e4f4 100644 > --- a/src/qemu/qemu_hostdev.h > +++ b/src/qemu/qemu_hostdev.h > @@ -31,6 +31,7 @@ int qemuUpdateActivePciHostdevs(struct qemud_driver *driver, > virDomainDefPtr def); > int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, > const char *name, > + const unsigned char *uuid, > virDomainHostdevDefPtr *hostdevs, > int nhostdevs); > int qemuPrepareHostdevUSBDevices(struct qemud_driver *driver, > @@ -46,6 +47,11 @@ void qemuDomainReAttachHostdevDevices(struct qemud_driver *driver, > int nhostdevs); > void qemuDomainReAttachHostDevices(struct qemud_driver *driver, > virDomainDefPtr def); > - > +int qemuDomainHostdevIsVirtualFunction(virDomainHostdevDefPtr hostdev); > +int qemuDomainHostdevNetConfigReplace(virDomainHostdevDefPtr hostdev, > + const unsigned char *uuid, > + char *stateDir); > +int qemuDomainHostdevNetConfigRestore(virDomainHostdevDefPtr hostdev, > + char *stateDir); > > #endif /* __QEMU_HOSTDEV_H__ */ > diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c > index 50563c5..c5ed9f7 100644 > --- a/src/qemu/qemu_hotplug.c > +++ b/src/qemu/qemu_hotplug.c > @@ -927,7 +927,8 @@ int qemuDomainAttachHostPciDevice(struct qemud_driver *driver, > return -1; > } > > - if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, &hostdev, 1) < 0) > + if (qemuPrepareHostdevPCIDevices(driver, vm->def->name, vm->def->uuid, > + &hostdev, 1) < 0) > return -1; > > if (qemuCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) { > @@ -1886,6 +1887,13 @@ qemuDomainDetachHostPciDevice(struct qemud_driver *driver, > if (ret < 0) > return -1; > > + /* > + * For SRIOV net host devices, unset mac and port profile before > + * reset and reattach device > + */ > + if (detach->parent.data.net) > + qemuDomainHostdevNetConfigRestore(detach, driver->stateDir); > + > pci = pciGetDevice(subsys->u.pci.domain, subsys->u.pci.bus, > subsys->u.pci.slot, subsys->u.pci.function); > if (pci) { > > It turned out just like I'd hoped it would! ACK with those small nits (which I'm applying before I push). -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list