mirror of
https://github.com/kata-containers/kata-containers.git
synced 2026-07-07 10:45:21 +00:00
runtime: add guest_extension_images cold-plug support for Go runtime
Mirror the Rust runtime's guest_extension_images support in the Go runtime: - hypervisor.go: add GuestExtensionImage struct and GuestExtensionImages field to HypervisorConfig. - config.go: parse [[hypervisor.qemu.guest_extension_images]] TOML sections via toGuestExtensionImages(), validating that every extension has a non-empty name and valid dm-verity parameters. - qemu.go: in buildDevices(), attach each extra image as a virtio-blk drive with ID extension-<name>; in kernelParameters(), append kata.extension.<name>.verity_params=... for each extra image. Signed-off-by: Fabiano Fidêncio <ffidencio@nvidia.com> Assisted-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
Fabiano Fidêncio
parent
e96b6c8b17
commit
968d6e9431
@@ -177,6 +177,13 @@ type hypervisor struct {
|
||||
DisableGuestSeLinux bool `toml:"disable_guest_selinux"`
|
||||
LegacySerial bool `toml:"use_legacy_serial"`
|
||||
ExtraMonitorSocket govmmQemu.MonitorProtocol `toml:"extra_monitor_socket"`
|
||||
GuestExtensionImages []guestExtensionImage `toml:"guest_extension_images"`
|
||||
}
|
||||
|
||||
type guestExtensionImage struct {
|
||||
Name string `toml:"name"`
|
||||
Path string `toml:"path"`
|
||||
VerityParams string `toml:"verity_params"`
|
||||
}
|
||||
|
||||
type runtime struct {
|
||||
@@ -1033,6 +1040,11 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
|
||||
return vc.HypervisorConfig{}, err
|
||||
}
|
||||
|
||||
guestExtensionImages, err := toGuestExtensionImages(h.GuestExtensionImages)
|
||||
if err != nil {
|
||||
return vc.HypervisorConfig{}, err
|
||||
}
|
||||
|
||||
return vc.HypervisorConfig{
|
||||
HypervisorPath: hypervisor,
|
||||
HypervisorPathList: h.HypervisorPathList,
|
||||
@@ -1116,9 +1128,57 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
|
||||
SnpIdAuth: h.SnpIdAuth,
|
||||
SnpGuestPolicy: h.SnpGuestPolicy,
|
||||
MeasurementAlgo: h.GetMeasurementAlgo(),
|
||||
GuestExtensionImages: guestExtensionImages,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// isValidExtensionName reports whether name is safe to embed in the virtio-blk
|
||||
// serial (extension-<name>) and the kata.extension.<name>.verity_params kernel
|
||||
// parameter. A stray space or '=' would corrupt the kernel command line, so the
|
||||
// name is restricted to ASCII alphanumerics, '-' and '_'.
|
||||
func isValidExtensionName(name string) bool {
|
||||
if name == "" {
|
||||
return false
|
||||
}
|
||||
for _, r := range name {
|
||||
switch {
|
||||
case r >= 'a' && r <= 'z':
|
||||
case r >= 'A' && r <= 'Z':
|
||||
case r >= '0' && r <= '9':
|
||||
case r == '-' || r == '_':
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func toGuestExtensionImages(imgs []guestExtensionImage) ([]vc.GuestExtensionImage, error) {
|
||||
if len(imgs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
result := make([]vc.GuestExtensionImage, len(imgs))
|
||||
for i, img := range imgs {
|
||||
if img.Name == "" {
|
||||
return nil, fmt.Errorf("guest_extension_images entry %d is missing required 'name' field", i)
|
||||
}
|
||||
if !isValidExtensionName(img.Name) {
|
||||
return nil, fmt.Errorf("guest_extension_images '%s' has an invalid name: only ASCII alphanumerics, '-' and '_' are allowed (the name is used in the virtio-blk serial and in the kata.extension.<name>.verity_params kernel parameter)", img.Name)
|
||||
}
|
||||
if strings.TrimSpace(img.VerityParams) != "" {
|
||||
if _, err := vc.ParseKernelVerityParams(img.VerityParams); err != nil {
|
||||
return nil, fmt.Errorf("guest_extension_images '%s' has invalid verity_params: %w", img.Name, err)
|
||||
}
|
||||
}
|
||||
result[i] = vc.GuestExtensionImage{
|
||||
Name: img.Name,
|
||||
Path: img.Path,
|
||||
VerityParams: img.VerityParams,
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func newClhHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
|
||||
hypervisor, err := h.path()
|
||||
if err != nil {
|
||||
|
||||
@@ -463,6 +463,22 @@ type Param struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
// GuestExtensionImage represents an additional block device image to attach to the VM
|
||||
// (e.g. CoCo extension, GPU extension).
|
||||
type GuestExtensionImage struct {
|
||||
// Name is a short identifier for this extension (e.g. "coco", "gpu").
|
||||
// Used as the virtio-blk serial so the guest can discover the device
|
||||
// via /dev/disk/by-id/virtio-extension-<name> and match verity params
|
||||
// from kernel cmdline kata.extension.<name>.verity_params=...
|
||||
Name string
|
||||
|
||||
// Path is the host path to the extension image file.
|
||||
Path string
|
||||
|
||||
// VerityParams contains dm-verity parameters for this extension image.
|
||||
VerityParams string
|
||||
}
|
||||
|
||||
// HypervisorConfig is the hypervisor configuration.
|
||||
// nolint: govet
|
||||
type HypervisorConfig struct {
|
||||
@@ -485,6 +501,9 @@ type HypervisorConfig struct {
|
||||
// ImagePath and InitrdPath cannot be set at the same time.
|
||||
InitrdPath string
|
||||
|
||||
// GuestExtensionImages lists additional block device images to attach to the VM.
|
||||
GuestExtensionImages []GuestExtensionImage
|
||||
|
||||
// RootfsType is filesystem type of rootfs.
|
||||
RootfsType string
|
||||
|
||||
|
||||
@@ -214,6 +214,18 @@ func (q *qemu) kernelParameters() string {
|
||||
// params are added here, they will take priority over the defaults.
|
||||
params = append(params, q.config.KernelParams...)
|
||||
|
||||
// Emit one kata.extension.<name>.verity_params entry per configured
|
||||
// extension. This doubles as the guest-side activation signal (the systemd
|
||||
// generator and mount unit key on it), so it is emitted even when
|
||||
// VerityParams is empty (e.g. an unmeasured extension on s390x); the mount
|
||||
// helper then mounts the extension off its raw partition.
|
||||
for _, extra := range q.config.GuestExtensionImages {
|
||||
params = append(params, Param{
|
||||
Key: fmt.Sprintf("kata.extension.%s.verity_params", extra.Name),
|
||||
Value: extra.VerityParams,
|
||||
})
|
||||
}
|
||||
|
||||
paramsStr := SerializeParams(params, "=")
|
||||
|
||||
return strings.Join(paramsStr, " ")
|
||||
@@ -865,6 +877,23 @@ func (q *qemu) buildDevices(ctx context.Context, kernelPath string) ([]govmmQemu
|
||||
kernel.InitrdPath = ""
|
||||
}
|
||||
|
||||
for _, extra := range q.config.GuestExtensionImages {
|
||||
if extra.Path == "" {
|
||||
continue
|
||||
}
|
||||
drive := config.BlockDrive{
|
||||
File: extra.Path,
|
||||
Format: "raw",
|
||||
ID: fmt.Sprintf("extension-%s", extra.Name),
|
||||
ShareRW: true,
|
||||
ReadOnly: true,
|
||||
}
|
||||
devices, err = q.arch.appendBlockDevice(ctx, devices, drive)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if q.config.IOMMU {
|
||||
devices, err = q.arch.appendIOMMU(devices)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user