[libvirt] [PATCH 4/4 v3] qemu_hostdev: Add support to install port profile and mac address on hostdevs

Laine Stump laine at laine.org
Tue Mar 6 10:38:04 UTC 2012


On 03/05/2012 08:12 PM, Roopa Prabhu wrote:
> From: Roopa Prabhu <roprabhu at cisco.com>
>
> 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 at cisco.com>
> ---
>  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).




More information about the libvir-list mailing list