[PATCH v3 0/2] Enable SEV SNP support in ch driver

This version introduces virStringFormatHex method and uses this method while sending host_data to cloud-hypervisor. Praveen K Paladugu (2): util: Introduce virStringFormatHex ch: Enable SEV SNP support src/ch/ch_monitor.c | 65 ++++++++++++++++++++++++++++++++-------- src/libvirt_private.syms | 1 + src/util/virstring.c | 19 ++++++++++++ src/util/virstring.h | 1 + 4 files changed, 74 insertions(+), 12 deletions(-) -- 2.47.0

virStringFormatHex converts an input byte array into hex string and returns it. Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/libvirt_private.syms | 1 + src/util/virstring.c | 19 +++++++++++++++++++ src/util/virstring.h | 1 + 3 files changed, 21 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6888f6b599..df2f425ef6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3460,6 +3460,7 @@ virSkipToDigit; virStrcpy; virStringBufferIsPrintable; virStringFilterChars; +virStringFormatHex; virStringHasCaseSuffix; virStringHasChars; virStringHasControlChars; diff --git a/src/util/virstring.c b/src/util/virstring.c index 15c3f7bdd1..49b52ce018 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -1092,3 +1092,22 @@ virStringListRemoveDuplicates(char ***list) g_free(*list); *list = g_renew(char *, unique, n + 1); } + +/** + * virStringFormatHex: + * @buf: buffer to format + * @len: length of the buffer + * + * Format a byte array into a hexadecimal string and return it. + */ +char * +virStringFormatHex(uint8_t *buf, size_t len) +{ + char *hex = g_new0(char, len * 2 + 1); + size_t i; + + for (i = 0; i < len; i++) + g_snprintf(hex + i * 2, 3, "%02x", buf[i]); + + return g_steal_pointer(&hex); +} diff --git a/src/util/virstring.h b/src/util/virstring.h index 31a404e106..f5dfbf5387 100644 --- a/src/util/virstring.h +++ b/src/util/virstring.h @@ -140,3 +140,4 @@ int virStringParseVersion(unsigned long long *version, bool allowMissing); void virStringListRemoveDuplicates(char ***list); +char *virStringFormatHex(uint8_t *buf, size_t len); -- 2.47.0

On 2/11/25 20:18, Praveen K Paladugu wrote:
virStringFormatHex converts an input byte array into hex string and returns it.
Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/libvirt_private.syms | 1 + src/util/virstring.c | 19 +++++++++++++++++++ src/util/virstring.h | 1 + 3 files changed, 21 insertions(+)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6888f6b599..df2f425ef6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3460,6 +3460,7 @@ virSkipToDigit; virStrcpy; virStringBufferIsPrintable; virStringFilterChars; +virStringFormatHex; virStringHasCaseSuffix; virStringHasChars; virStringHasControlChars; diff --git a/src/util/virstring.c b/src/util/virstring.c index 15c3f7bdd1..49b52ce018 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -1092,3 +1092,22 @@ virStringListRemoveDuplicates(char ***list) g_free(*list); *list = g_renew(char *, unique, n + 1); } + +/** + * virStringFormatHex: + * @buf: buffer to format + * @len: length of the buffer + * + * Format a byte array into a hexadecimal string and return it.
Since you're documenting behavior, I'd also mention it's callers responsibility to free returned string.
+ */ +char * +virStringFormatHex(uint8_t *buf, size_t len)
s/uint8_t/const unsigned char/
+{ + char *hex = g_new0(char, len * 2 + 1); + size_t i; + + for (i = 0; i < len; i++) + g_snprintf(hex + i * 2, 3, "%02x", buf[i]); + + return g_steal_pointer(&hex); +} diff --git a/src/util/virstring.h b/src/util/virstring.h index 31a404e106..f5dfbf5387 100644 --- a/src/util/virstring.h +++ b/src/util/virstring.h @@ -140,3 +140,4 @@ int virStringParseVersion(unsigned long long *version, bool allowMissing);
void virStringListRemoveDuplicates(char ***list); +char *virStringFormatHex(uint8_t *buf, size_t len);
Michal

Enable SEV-SNP support for ch guests. Co-Authored-by: Smit Gardhariya <sgardhariya@microsoft.com> Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/ch/ch_monitor.c | 65 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index bedcde2dde..aaec484c35 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -131,28 +131,50 @@ virCHMonitorBuildPayloadJson(virJSONValue *content, virDomainDef *vmdef) { g_autoptr(virJSONValue) payload = virJSONValueNewObject(); - if (vmdef->os.kernel == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Kernel image path in this domain is not defined")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Kernel image path is not defined. With sev_snp=on, pass an igvm path")); return -1; - } else { - if (virJSONValueObjectAppendString(payload, "kernel", vmdef->os.kernel) < 0) - return -1; } - if (vmdef->os.cmdline) { - if (virJSONValueObjectAppendString(payload, "cmdline", vmdef->os.cmdline) < 0) + if (vmdef->sec && + vmdef->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP) { + size_t len; + const size_t host_data_len = 32; + g_autofree unsigned char *buf = NULL; + g_autofree char *host_data = NULL; + + if (virJSONValueObjectAppendString(payload, "igvm", vmdef->os.kernel) < 0) return -1; - } - if (vmdef->os.initrd != NULL) { - if (virJSONValueObjectAppendString(payload, "initramfs", vmdef->os.initrd) < 0) + if (vmdef->sec->data.sev_snp.host_data) { + /* Libvirt provided host_data is base64 encoded and cloud-hypervisor + requires host_data as hex encoded. Base64 decode and hex encode + before sending to cloud-hypervisor.*/ + buf = g_base64_decode(vmdef->sec->data.sev_snp.host_data, &len); + if (len != host_data_len) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid host_data provdied. Expected '%1$ld' bytes"), + host_data_len); + return -1; + } + + host_data = virStringFormatHex(buf, host_data_len); + if (virJSONValueObjectAppendString(payload, "host_data", + host_data) < 0) + return -1; + } + } else { + if (virJSONValueObjectAdd(&payload, + "s:kernel", vmdef->os.kernel, + "S:cmdline", vmdef->os.cmdline, + "S:initramfs", vmdef->os.initrd, + NULL) < 0) return -1; } if (virJSONValueObjectAppend(content, "payload", &payload) < 0) - return -1; + return -1; return 0; } @@ -426,6 +448,23 @@ virCHMonitorBuildDevicesJson(virJSONValue *content, return 0; } +static int +virCHMonitorBuildPlatformJson(virJSONValue *content, virDomainDef *vmdef) +{ + g_autoptr(virJSONValue) platform = virJSONValueNewObject(); + + if (vmdef->sec && + vmdef->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP) { + if (virJSONValueObjectAppendBoolean(platform, "sev_snp", 1) < 0) + return -1; + + if (virJSONValueObjectAppend(content, "platform", &platform) < 0) + return -1; + } + + return 0; +} + static int virCHMonitorBuildVMJson(virCHDriver *driver, virDomainDef *vmdef, char **jsonstr) @@ -454,6 +493,8 @@ virCHMonitorBuildVMJson(virCHDriver *driver, virDomainDef *vmdef, return -1; } + if (virCHMonitorBuildPlatformJson(content, vmdef) < 0) + return -1; if (virCHMonitorBuildDisksJson(content, vmdef) < 0) return -1; -- 2.47.0

On 2/11/25 20:18, Praveen K Paladugu wrote:
Enable SEV-SNP support for ch guests.
Co-Authored-by: Smit Gardhariya <sgardhariya@microsoft.com> Signed-off-by: Praveen K Paladugu <praveenkpaladugu@gmail.com> --- src/ch/ch_monitor.c | 65 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 12 deletions(-)
diff --git a/src/ch/ch_monitor.c b/src/ch/ch_monitor.c index bedcde2dde..aaec484c35 100644 --- a/src/ch/ch_monitor.c +++ b/src/ch/ch_monitor.c @@ -131,28 +131,50 @@ virCHMonitorBuildPayloadJson(virJSONValue *content, virDomainDef *vmdef) { g_autoptr(virJSONValue) payload = virJSONValueNewObject();
- if (vmdef->os.kernel == NULL) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Kernel image path in this domain is not defined")); + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Kernel image path is not defined. With sev_snp=on, pass an igvm path")); return -1; - } else { - if (virJSONValueObjectAppendString(payload, "kernel", vmdef->os.kernel) < 0) - return -1; }
- if (vmdef->os.cmdline) { - if (virJSONValueObjectAppendString(payload, "cmdline", vmdef->os.cmdline) < 0) + if (vmdef->sec && + vmdef->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP) { + size_t len; + const size_t host_data_len = 32; + g_autofree unsigned char *buf = NULL; + g_autofree char *host_data = NULL;
Scope of these variables can be decreased.
+ + if (virJSONValueObjectAppendString(payload, "igvm", vmdef->os.kernel) < 0) return -1; - }
- if (vmdef->os.initrd != NULL) { - if (virJSONValueObjectAppendString(payload, "initramfs", vmdef->os.initrd) < 0) + if (vmdef->sec->data.sev_snp.host_data) { + /* Libvirt provided host_data is base64 encoded and cloud-hypervisor + requires host_data as hex encoded. Base64 decode and hex encode + before sending to cloud-hypervisor.*/ + buf = g_base64_decode(vmdef->sec->data.sev_snp.host_data, &len); + if (len != host_data_len) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid host_data provdied. Expected '%1$ld' bytes"), + host_data_len); + return -1; + } + + host_data = virStringFormatHex(buf, host_data_len); + if (virJSONValueObjectAppendString(payload, "host_data", + host_data) < 0) + return -1; + } + } else { + if (virJSONValueObjectAdd(&payload, + "s:kernel", vmdef->os.kernel, + "S:cmdline", vmdef->os.cmdline, + "S:initramfs", vmdef->os.initrd, + NULL) < 0) return -1; }
if (virJSONValueObjectAppend(content, "payload", &payload) < 0) - return -1; + return -1;
return 0; } @@ -426,6 +448,23 @@ virCHMonitorBuildDevicesJson(virJSONValue *content, return 0; }
+static int +virCHMonitorBuildPlatformJson(virJSONValue *content, virDomainDef *vmdef) +{ + g_autoptr(virJSONValue) platform = virJSONValueNewObject();
And so can be this one.
+ + if (vmdef->sec && + vmdef->sec->sectype == VIR_DOMAIN_LAUNCH_SECURITY_SEV_SNP) { + if (virJSONValueObjectAppendBoolean(platform, "sev_snp", 1) < 0) + return -1; + + if (virJSONValueObjectAppend(content, "platform", &platform) < 0) + return -1; + } + + return 0; +} + static int virCHMonitorBuildVMJson(virCHDriver *driver, virDomainDef *vmdef, char **jsonstr) @@ -454,6 +493,8 @@ virCHMonitorBuildVMJson(virCHDriver *driver, virDomainDef *vmdef, return -1; }
+ if (virCHMonitorBuildPlatformJson(content, vmdef) < 0) + return -1;
if (virCHMonitorBuildDisksJson(content, vmdef) < 0) return -1;
Michal

Bubbling up this patchset for review. On 2/11/2025 1:18 PM, Praveen K Paladugu wrote:
This version introduces virStringFormatHex method and uses this method while sending host_data to cloud-hypervisor.
Praveen K Paladugu (2): util: Introduce virStringFormatHex ch: Enable SEV SNP support
src/ch/ch_monitor.c | 65 ++++++++++++++++++++++++++++++++-------- src/libvirt_private.syms | 1 + src/util/virstring.c | 19 ++++++++++++ src/util/virstring.h | 1 + 4 files changed, 74 insertions(+), 12 deletions(-)
-- Regards, Praveen

On 2/11/25 20:18, Praveen K Paladugu wrote:
This version introduces virStringFormatHex method and uses this method while sending host_data to cloud-hypervisor.
Praveen K Paladugu (2): util: Introduce virStringFormatHex ch: Enable SEV SNP support
src/ch/ch_monitor.c | 65 ++++++++++++++++++++++++++++++++-------- src/libvirt_private.syms | 1 + src/util/virstring.c | 19 ++++++++++++ src/util/virstring.h | 1 + 4 files changed, 74 insertions(+), 12 deletions(-)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> and merged. Michal
participants (2)
-
Michal Prívozník
-
Praveen K Paladugu