[PATCH 2/7] conf: support crypto device

Michal Prívozník mprivozn at redhat.com
Fri Jan 6 11:37:38 UTC 2023


On 1/4/23 04:29, zhenwei pi wrote:
> Support a new device type 'crypto'.
> 
> Signed-off-by: zhenwei pi <pizhenwei at bytedance.com>
> ---
>  src/conf/domain_conf.c         | 191 +++++++++++++++++++++++++++++++++
>  src/conf/domain_conf.h         |  40 +++++++
>  src/conf/domain_postparse.c    |   1 +
>  src/conf/domain_validate.c     |  18 ++++
>  src/conf/virconftypes.h        |   2 +
>  src/libvirt_private.syms       |   1 +
>  src/qemu/qemu_command.c        |   1 +
>  src/qemu/qemu_domain.c         |   3 +
>  src/qemu/qemu_domain_address.c |  26 +++++
>  src/qemu/qemu_driver.c         |   5 +
>  src/qemu/qemu_hotplug.c        |   3 +
>  src/qemu/qemu_validate.c       |  22 ++++
>  12 files changed, 313 insertions(+)

What I'm missing here is qemuxml2xmltest test case. We surely want to
test whether parsing and formatting of the new XML works.

> 
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 6c088ff295..74448fe627 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -332,6 +332,7 @@ VIR_ENUM_IMPL(virDomainDevice,
>                "iommu",
>                "vsock",
>                "audio",
> +              "crypto",
>  );
>  
>  VIR_ENUM_IMPL(virDomainDiskDevice,
> @@ -1314,6 +1315,22 @@ VIR_ENUM_IMPL(virDomainVsockModel,
>                "virtio-non-transitional",
>  );
>  
> +VIR_ENUM_IMPL(virDomainCryptoModel,
> +              VIR_DOMAIN_CRYPTO_MODEL_LAST,
> +              "virtio",
> +);
> +
> +VIR_ENUM_IMPL(virDomainCryptoType,
> +              VIR_DOMAIN_CRYPTO_TYPE_LAST,
> +              "qemu",
> +);
> +
> +VIR_ENUM_IMPL(virDomainCryptoBackend,
> +              VIR_DOMAIN_CRYPTO_BACKEND_LAST,
> +              "builtin",
> +              "lkcf",
> +);
> +
>  VIR_ENUM_IMPL(virDomainDiskDiscard,
>                VIR_DOMAIN_DISK_DISCARD_LAST,
>                "default",
> @@ -3464,6 +3481,9 @@ void virDomainDeviceDefFree(virDomainDeviceDef *def)
>      case VIR_DOMAIN_DEVICE_AUDIO:
>          virDomainAudioDefFree(def->data.audio);
>          break;
> +    case VIR_DOMAIN_DEVICE_CRYPTO:
> +        virDomainCryptoDefFree(def->data.crypto);
> +        break;
>      case VIR_DOMAIN_DEVICE_LAST:
>      case VIR_DOMAIN_DEVICE_NONE:
>          break;
> @@ -3807,6 +3827,10 @@ void virDomainDefFree(virDomainDef *def)
>          virDomainPanicDefFree(def->panics[i]);
>      g_free(def->panics);
>  
> +    for (i = 0; i < def->ncryptos; i++)
> +        virDomainCryptoDefFree(def->cryptos[i]);
> +    g_free(def->cryptos);
> +
>      virDomainIOMMUDefFree(def->iommu);
>  
>      g_free(def->idmap.uidmap);
> @@ -4360,6 +4384,8 @@ virDomainDeviceGetInfo(const virDomainDeviceDef *device)
>          return &device->data.iommu->info;
>      case VIR_DOMAIN_DEVICE_VSOCK:
>          return &device->data.vsock->info;
> +    case VIR_DOMAIN_DEVICE_CRYPTO:
> +        return &device->data.crypto->info;
>  
>      /* The following devices do not contain virDomainDeviceInfo */
>      case VIR_DOMAIN_DEVICE_LEASE:
> @@ -4462,6 +4488,9 @@ virDomainDeviceSetData(virDomainDeviceDef *device,
>      case VIR_DOMAIN_DEVICE_AUDIO:
>          device->data.audio = devicedata;
>          break;
> +    case VIR_DOMAIN_DEVICE_CRYPTO:
> +        device->data.crypto = devicedata;
> +        break;
>      case VIR_DOMAIN_DEVICE_NONE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          break;
> @@ -4673,6 +4702,13 @@ virDomainDeviceInfoIterateFlags(virDomainDef *def,
>              return rc;
>      }
>  
> +    device.type = VIR_DOMAIN_DEVICE_CRYPTO;
> +    for (i = 0; i < def->ncryptos; i++) {
> +        device.data.crypto = def->cryptos[i];
> +        if ((rc = cb(def, &device, &def->cryptos[i]->info, opaque)) != 0)
> +            return rc;
> +    }
> +
>      /* If the flag below is set, make sure @cb can handle @info being NULL */
>      if (iteratorFlags & DOMAIN_DEVICE_ITERATE_MISSING_INFO) {
>          device.type = VIR_DOMAIN_DEVICE_GRAPHICS;
> @@ -4731,6 +4767,7 @@ virDomainDeviceInfoIterateFlags(virDomainDef *def,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
> +    case VIR_DOMAIN_DEVICE_CRYPTO:
>          break;
>      }
>  #endif
> @@ -13417,6 +13454,94 @@ virDomainVsockDefParseXML(virDomainXMLOption *xmlopt,
>      return g_steal_pointer(&vsock);
>  }
>  
> +
> +static virDomainCryptoDef *
> +virDomainCryptoDefParseXML(virDomainXMLOption *xmlopt,
> +                           xmlNodePtr node,
> +                           xmlXPathContextPtr ctxt,
> +                           unsigned int flags)
> +{
> +    virDomainCryptoDef *def;
> +    VIR_XPATH_NODE_AUTORESTORE(ctxt)
> +    int nbackends;
> +    g_autofree xmlNodePtr *backends = NULL;
> +    g_autofree char *model = NULL;
> +    g_autofree char *backend = NULL;
> +    g_autofree char *type = NULL;
> +
> +    def = g_new0(virDomainCryptoDef, 1);
> +
> +    if (!(model = virXMLPropString(node, "model"))) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s", _("missing crypto device model"));
> +        goto error;
> +    }
> +
> +    if ((def->model = virDomainCryptoModelTypeFromString(model)) < 0) {

Problem with this is that compiler may decide that def->model is
unsigned (because it's declared as: virDomainCryptoModel model.
Now, if virXXXTypeFromString() fails and returns -1, this is then
typecased into unsigned int (or whatever unsigned type compiler decided
on) and < 0 check is never true.

Fortunately, we have a conencient function for getting attribute values
and translating them into enums: virXMLPropEnum().

> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unknown crypto model '%s'"), model);
> +        goto error;
> +    }
> +
> +    if (!(type = virXMLPropString(node, "type"))) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s", _("missing crypto device type"));
> +        goto error;
> +    }
> +
> +    if ((def->type = virDomainCryptoTypeTypeFromString(type)) < 0) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unknown crypto type '%s'"), model);
> +        goto error;
> +    }
> +
> +    ctxt->node = node;
> +
> +    if ((nbackends = virXPathNodeSet("./backend", ctxt, &backends)) < 0)
> +        goto error;
> +
> +    if (nbackends != 1) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("only one crypto backend is supported"));
> +        goto error;
> +    }
> +
> +    if (!(backend = virXMLPropString(backends[0], "model"))) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("missing crypto device backend model"));
> +        goto error;
> +    }
> +
> +    if ((def->backend = virDomainCryptoBackendTypeFromString(backend)) < 0) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("unknown crypto backend model '%s'"), backend);
> +        goto error;
> +    }
> +
> +    if (virXMLPropUInt(backends[0], "queues", 10, VIR_XML_PROP_NONE, &def->queues) < 0) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("parsing crypto device queues failed"));

Nope, this overwrites more specific error message reported by
virXMLPropUInt().

> +        goto error;
> +    }
> +
> +    switch ((virDomainCryptoBackend) def->backend) {
> +    case VIR_DOMAIN_CRYPTO_BACKEND_BUILTIN:
> +    case VIR_DOMAIN_CRYPTO_BACKEND_LKCF:
> +    case VIR_DOMAIN_CRYPTO_BACKEND_LAST:
> +        break;
> +    }

What's the purpose of this statement?

> +
> +    if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0)
> +        goto error;
> +
> +    if (virDomainVirtioOptionsParseXML(virXPathNode("./driver", ctxt),
> +                                       &def->virtio) < 0)
> +        goto error;
> +
> +    return def;
> +
> + error:
> +    g_clear_pointer(&def, virDomainCryptoDefFree);

How about declaring @def as g_autoptr() and dropping this label completely?

> +    return NULL;
> +}
> +
> +
>  virDomainDeviceDef *
>  virDomainDeviceDefParse(const char *xmlStr,
>                          const virDomainDef *def,
> @@ -13578,6 +13703,11 @@ virDomainDeviceDefParse(const char *xmlStr,
>                                                            flags)))
>              return NULL;
>          break;
> +    case VIR_DOMAIN_DEVICE_CRYPTO:
> +        if (!(dev->data.crypto = virDomainCryptoDefParseXML(xmlopt, node, ctxt,
> +                                                          flags)))
> +            return NULL;
> +        break;
>      case VIR_DOMAIN_DEVICE_NONE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          break;
> @@ -18670,6 +18800,21 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt,
>      }
>      VIR_FREE(nodes);
>  
> +    /* Parse the crypto devices */
> +    if ((n = virXPathNodeSet("./devices/crypto", ctxt, &nodes)) < 0)
> +        return NULL;
> +    if (n)
> +        def->cryptos = g_new0(virDomainCryptoDef *, n);
> +    for (i = 0; i < n; i++) {
> +        virDomainCryptoDef *crypto = virDomainCryptoDefParseXML(xmlopt, nodes[i],
> +                                                       ctxt, flags);
> +        if (!crypto)
> +            return NULL;
> +
> +        def->cryptos[def->ncryptos++] = crypto;
> +    }
> +    VIR_FREE(nodes);
> +
>      /* Parse the TPM devices */
>      if ((n = virXPathNodeSet("./devices/tpm", ctxt, &nodes)) < 0)
>          return NULL;
> @@ -21210,6 +21355,7 @@ virDomainDefCheckABIStabilityFlags(virDomainDef *src,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
> +    case VIR_DOMAIN_DEVICE_CRYPTO:
>          break;
>      }
>  #endif
> @@ -24562,6 +24708,47 @@ virDomainRNGDefFree(virDomainRNGDef *def)
>  }
>  
>  
> +static int
> +virDomainCryptoDefFormat(virBuffer *buf,
> +                         virDomainCryptoDef *def,
> +                         unsigned int flags)
> +{
> +    const char *model = virDomainCryptoModelTypeToString(def->model);
> +    const char *type = virDomainCryptoTypeTypeToString(def->model);
> +    const char *backend = virDomainCryptoBackendTypeToString(def->backend);
> +    g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER;
> +
> +    virBufferAsprintf(buf, "<crypto model='%s' type='%s'>\n", model, type);
> +    virBufferAdjustIndent(buf, 2);
> +    virBufferAsprintf(buf, "<backend model='%s'", backend);
> +    if (def->queues)
> +        virBufferAsprintf(buf, " queues='%d'", def->queues);
> +    virBufferAddLit(buf, "/>\n");
> +
> +    virDomainVirtioOptionsFormat(&driverAttrBuf, def->virtio);
> +
> +    virXMLFormatElement(buf, "driver", &driverAttrBuf, NULL);
> +
> +    virDomainDeviceInfoFormat(buf, &def->info, flags);
> +
> +    virBufferAdjustIndent(buf, -2);
> +    virBufferAddLit(buf, "</crypto>\n");
> +
> +    return 0;

This is all the function returns. Can this be made void instead?

> +}
> +
> +void
> +virDomainCryptoDefFree(virDomainCryptoDef *def)
> +{
> +    if (!def)
> +        return;
> +
> +    virDomainDeviceInfoClear(&def->info);
> +    g_free(def->virtio);
> +    g_free(def);
> +}
> +
> +
>  static int
>  virDomainMemorySourceDefFormat(virBuffer *buf,
>                                 virDomainMemoryDef *def)
> @@ -27261,6 +27448,10 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def,
>              return -1;
>      }
>  
> +    for (n = 0; n < def->ncryptos; n++) {
> +        if (virDomainCryptoDefFormat(buf, def->cryptos[n], flags))
> +            return -1;
> +    }
>      if (def->iommu)
>          virDomainIOMMUDefFormat(buf, def->iommu);
>  
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 1404c55053..9062250d60 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -86,6 +86,7 @@ typedef enum {
>      VIR_DOMAIN_DEVICE_IOMMU,
>      VIR_DOMAIN_DEVICE_VSOCK,
>      VIR_DOMAIN_DEVICE_AUDIO,
> +    VIR_DOMAIN_DEVICE_CRYPTO,
>  
>      VIR_DOMAIN_DEVICE_LAST
>  } virDomainDeviceType;
> @@ -118,6 +119,7 @@ struct _virDomainDeviceDef {
>          virDomainIOMMUDef *iommu;
>          virDomainVsockDef *vsock;
>          virDomainAudioDef *audio;
> +        virDomainCryptoDef *crypto;
>      } data;
>  };
>  
> @@ -2858,6 +2860,34 @@ struct _virDomainVsockDef {
>      virDomainVirtioOptions *virtio;
>  };
>  
> +typedef enum {
> +    VIR_DOMAIN_CRYPTO_MODEL_VIRTIO,
> +
> +    VIR_DOMAIN_CRYPTO_MODEL_LAST
> +} virDomainCryptoModel;
> +
> +typedef enum {
> +    VIR_DOMAIN_CRYPTO_TYPE_QEMU,
> +
> +    VIR_DOMAIN_CRYPTO_TYPE_LAST
> +} virDomainCryptoType;
> +
> +typedef enum {
> +    VIR_DOMAIN_CRYPTO_BACKEND_BUILTIN,
> +    VIR_DOMAIN_CRYPTO_BACKEND_LKCF,
> +
> +    VIR_DOMAIN_CRYPTO_BACKEND_LAST
> +} virDomainCryptoBackend;
> +
> +struct _virDomainCryptoDef {
> +    virDomainCryptoModel model;
> +    virDomainCryptoType type;
> +    virDomainCryptoBackend backend;
> +    unsigned int queues;
> +    virDomainDeviceInfo info;
> +    virDomainVirtioOptions *virtio;
> +};
> +
>  struct _virDomainVirtioOptions {
>      virTristateSwitch iommu;
>      virTristateSwitch ats;
> @@ -3023,6 +3053,9 @@ struct _virDomainDef {
>      size_t nsysinfo;
>      virSysinfoDef **sysinfo;
>  
> +    size_t ncryptos;
> +    virDomainCryptoDef **cryptos;
> +
>      /* At maximum 2 TPMs on the domain if a TPM Proxy is present. */
>      size_t ntpms;
>      virDomainTPMDef **tpms;
> @@ -3274,6 +3307,7 @@ struct _virDomainXMLPrivateDataCallbacks {
>      virDomainXMLPrivateDataNewFunc    vcpuNew;
>      virDomainXMLPrivateDataNewFunc    chrSourceNew;
>      virDomainXMLPrivateDataNewFunc    vsockNew;
> +    virDomainXMLPrivateDataNewFunc    cryptoNew;
>      virDomainXMLPrivateDataNewFunc    graphicsNew;
>      virDomainXMLPrivateDataNewFunc    networkNew;
>      virDomainXMLPrivateDataNewFunc    videoNew;
> @@ -3440,6 +3474,9 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainIOMMUDef, virDomainIOMMUDefFree);
>  virDomainVsockDef *virDomainVsockDefNew(virDomainXMLOption *xmlopt);
>  void virDomainVsockDefFree(virDomainVsockDef *vsock);
>  G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainVsockDef, virDomainVsockDefFree);
> +virDomainCryptoDef *virDomainCryptoDefNew(virDomainXMLOption *xmlopt);

This function is never defined, only declared here.

> +void virDomainCryptoDefFree(virDomainCryptoDef *crypto);
> +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainCryptoDef, virDomainCryptoDefFree);
>  void virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming);
>  G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetTeamingInfo, virDomainNetTeamingInfoFree);
>  void virDomainNetDefFree(virDomainNetDef *def);

Michal



More information about the libvir-list mailing list