runtime: Add IOMMUFD Object Creation for QEMU QMP Commands

The QMP commands sent to QEMU did not properly set up
IOMMUFD objects in the codepath that handles VFIO device
hot-plugging. This is mainly relevant in the Kubernetes
use-case where the VFIO devices are not available when
QEMU is first launched.

Signed-off-by: LandonTClipp <11232769+LandonTClipp@users.noreply.github.com>
This commit is contained in:
LandonTClipp
2025-12-01 13:12:44 -06:00
committed by Fabiano Fidêncio
parent cb8fd2e3b1
commit 09438fd54f
4 changed files with 25 additions and 2 deletions

1
.gitignore vendored
View File

@@ -18,3 +18,4 @@ src/tools/log-parser/kata-log-parser
tools/packaging/static-build/agent/install_libseccomp.sh
.envrc
.direnv
**/.DS_Store

View File

@@ -15,6 +15,7 @@ import (
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
"github.com/go-ini/ini"
"github.com/kata-containers/kata-containers/src/runtime/pkg/device/drivers"
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
"github.com/opencontainers/runtime-spec/specs-go"
"golang.org/x/sys/unix"
@@ -431,6 +432,16 @@ type VFIODev struct {
HostPath string
}
// IOMMUFDID returns the IOMMUFD ID if the VFIO device is backed by IOMMUFD
// otherwise returns an empty string.
func (t VFIODev) IOMMUFDID() string {
if !strings.HasPrefix(t.DevfsDev, drivers.IommufdDevPath) {
return ""
}
basename := filepath.Base(t.DevfsDev)
return strings.TrimPrefix(basename, "vfio")
}
// RNGDev represents a random number generator device
type RNGDev struct {
// ID is used to identify the device in the hypervisor options.

View File

@@ -1160,7 +1160,8 @@ func (q *QMP) ExecutePCIVhostUserDevAdd(ctx context.Context, driver, devID, char
// devID is the id of the device to add. Must be valid QMP identifier.
// bdf is the PCI bus-device-function of the pci device.
// bus is optional. When hot plugging a PCIe device, the bus can be the ID of the pcie-root-port.
func (q *QMP) ExecuteVFIODeviceAdd(ctx context.Context, devID, bdf, bus, romfile string) error {
// iommufdID is the ID of the iommufd object to be created for this device. If empty, no iommufd object will be created.
func (q *QMP) ExecuteVFIODeviceAdd(ctx context.Context, devID, bdf, bus, romfile string, iommufdID string) error {
var driver string
var transport VirtioTransport
@@ -1179,6 +1180,16 @@ func (q *QMP) ExecuteVFIODeviceAdd(ctx context.Context, devID, bdf, bus, romfile
if bus != "" {
args["bus"] = bus
}
if iommufdID != "" {
objectAddArgs := map[string]interface{}{
"qom-type": "iommufd",
"id": iommufdID,
}
if err := q.executeCommand(ctx, "object-add", objectAddArgs, nil); err != nil {
return err
}
args["iommufd"] = iommufdID
}
return q.executeCommand(ctx, "device_add", args, nil)
}

View File

@@ -1876,7 +1876,7 @@ func (q *qemu) executePCIVFIODeviceAdd(device *config.VFIODev, addr string, brid
func (q *qemu) executeVFIODeviceAdd(device *config.VFIODev) error {
switch device.Type {
case config.VFIOPCIDeviceNormalType:
return q.qmpMonitorCh.qmp.ExecuteVFIODeviceAdd(q.qmpMonitorCh.ctx, device.ID, device.BDF, device.Bus, romFile)
return q.qmpMonitorCh.qmp.ExecuteVFIODeviceAdd(q.qmpMonitorCh.ctx, device.ID, device.BDF, device.Bus, romFile, device.IOMMUFDID())
case config.VFIOPCIDeviceMediatedType:
return q.qmpMonitorCh.qmp.ExecutePCIVFIOMediatedDeviceAdd(q.qmpMonitorCh.ctx, device.ID, device.SysfsDev, "", device.Bus, romFile)
case config.VFIOAPDeviceMediatedType: