mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-11 21:02:34 +00:00
runtime: Add proper IOMMUFD parsing
With newer kernels we have a new backend for VFIO called IOMMUFD this is a departure from VFIO IOMMU Groups since it has only one device associated with an IOMMUFD entry. Signed-off-by: Zvonko Kaiser <zkaiser@nvidia.com>
This commit is contained in:
parent
121ac0c5c0
commit
e82fdee20f
@ -9,9 +9,12 @@ package drivers
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/kata-containers/kata-containers/src/runtime/pkg/device/api"
|
"github.com/kata-containers/kata-containers/src/runtime/pkg/device/api"
|
||||||
"github.com/kata-containers/kata-containers/src/runtime/pkg/device/config"
|
"github.com/kata-containers/kata-containers/src/runtime/pkg/device/config"
|
||||||
@ -157,6 +160,92 @@ func checkIgnorePCIClass(pciClass string, deviceBDF string, bitmask uint64) (boo
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMajorMinorFromDevPath(devPath string) (uint32, uint32, error) {
|
||||||
|
fi, err := os.Stat(devPath)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dev := fi.Sys().(*syscall.Stat_t)
|
||||||
|
return uint32(dev.Rdev >> 8), uint32(dev.Rdev & 0xff), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractIndex(devicePath string) (string, error) {
|
||||||
|
|
||||||
|
base := filepath.Base(devicePath)
|
||||||
|
|
||||||
|
const prefix = "vfio"
|
||||||
|
if !strings.HasPrefix(base, prefix) {
|
||||||
|
return "0", fmt.Errorf("unexpected device name format: %s", base)
|
||||||
|
}
|
||||||
|
return strings.TrimPrefix(base, prefix), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBdfFromVFIODev(major uint32, minor uint32) (string, error) {
|
||||||
|
devPath := fmt.Sprintf("/sys/dev/char/%d:%d", major, minor)
|
||||||
|
realPath, err := filepath.EvalSymlinks(devPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to resolve symlink for %s: %v", devPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bdfRegex := regexp.MustCompile(`([0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-9a-fA-F])`)
|
||||||
|
matches := bdfRegex.FindAllString(realPath, -1)
|
||||||
|
if len(matches) == 0 {
|
||||||
|
return "", fmt.Errorf("No BDF found in resolved path: %s", realPath)
|
||||||
|
}
|
||||||
|
return matches[len(matches)-1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDeviceFromVFIODev return the host device associated with the VFIO device
|
||||||
|
// There is only one device per VFIO device in the case of IOMMUFD
|
||||||
|
func GetDeviceFromVFIODev(device config.DeviceInfo) ([]*config.VFIODev, error) {
|
||||||
|
// The way we get the host BDF is by reading the symlink of the char
|
||||||
|
// device major:minor entries in /sys/chart/major:minor
|
||||||
|
// $ ls -l /dev/vfio/devices/vfio0
|
||||||
|
// crw------- 1 root root 237, 0 Jan 15 16:53 /dev/vfio/devices/vfio0
|
||||||
|
major, minor, err := getMajorMinorFromDevPath(device.HostPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to get major:minor from %s: %v", device.HostPath, err)
|
||||||
|
}
|
||||||
|
// $ ls -l /sys/dev/char/237:0
|
||||||
|
// /sys/dev/char/237:0 -> ../../devices/pci0000:64/0000:64:00.0/0000:65:00.0/vfio-dev/vfio0
|
||||||
|
deviceBDF, err := getBdfFromVFIODev(major, minor)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceSysfsDev := path.Join(config.SysBusPciDevicesPath, deviceBDF)
|
||||||
|
vfioDeviceType, err := GetVFIODeviceType(deviceSysfsDev)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vendorID := getPCIDeviceProperty(deviceBDF, PCISysFsDevicesVendor)
|
||||||
|
deviceID := getPCIDeviceProperty(deviceBDF, PCISysFsDevicesDevice)
|
||||||
|
pciClass := getPCIDeviceProperty(deviceBDF, PCISysFsDevicesClass)
|
||||||
|
|
||||||
|
id, err := extractIndex(device.HostPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
vfio := config.VFIODev{
|
||||||
|
ID: id,
|
||||||
|
Type: vfioDeviceType,
|
||||||
|
BDF: deviceBDF,
|
||||||
|
SysfsDev: deviceSysfsDev,
|
||||||
|
IsPCIe: IsPCIeDevice(deviceBDF),
|
||||||
|
Class: pciClass,
|
||||||
|
VendorID: vendorID,
|
||||||
|
DeviceID: deviceID,
|
||||||
|
Port: device.Port,
|
||||||
|
HostPath: device.HostPath,
|
||||||
|
}
|
||||||
|
vfioDevs := []*config.VFIODev{&vfio}
|
||||||
|
|
||||||
|
return vfioDevs, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetAllVFIODevicesFromIOMMUGroup returns all the VFIO devices in the IOMMU group
|
// GetAllVFIODevicesFromIOMMUGroup returns all the VFIO devices in the IOMMU group
|
||||||
// We can reuse this function at various levels, sandbox, container.
|
// We can reuse this function at various levels, sandbox, container.
|
||||||
func GetAllVFIODevicesFromIOMMUGroup(device config.DeviceInfo) ([]*config.VFIODev, error) {
|
func GetAllVFIODevicesFromIOMMUGroup(device config.DeviceInfo) ([]*config.VFIODev, error) {
|
||||||
|
@ -28,6 +28,7 @@ const (
|
|||||||
iommuGroupPath = "/sys/bus/pci/devices/%s/iommu_group"
|
iommuGroupPath = "/sys/bus/pci/devices/%s/iommu_group"
|
||||||
vfioDevPath = "/dev/vfio/%s"
|
vfioDevPath = "/dev/vfio/%s"
|
||||||
vfioAPSysfsDir = "/sys/devices/vfio_ap"
|
vfioAPSysfsDir = "/sys/devices/vfio_ap"
|
||||||
|
IommufdDevPath = "/dev/vfio/devices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VFIODevice is a vfio device meant to be passed to the hypervisor
|
// VFIODevice is a vfio device meant to be passed to the hypervisor
|
||||||
@ -64,10 +65,19 @@ func (device *VFIODevice) Attach(ctx context.Context, devReceiver api.DeviceRece
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// This work for IOMMUFD enabled kernels > 6.x
|
||||||
|
// In the case of IOMMUFD the device.HostPath will look like
|
||||||
|
// /dev/vfio/devices/vfio0
|
||||||
|
// (1) Check if we have the new IOMMUFD or old container based VFIO
|
||||||
|
if strings.HasPrefix(device.DeviceInfo.HostPath, IommufdDevPath) {
|
||||||
|
device.VfioDevs, err = GetDeviceFromVFIODev(*device.DeviceInfo)
|
||||||
|
} else {
|
||||||
|
// Once we have
|
||||||
device.VfioDevs, err = GetAllVFIODevicesFromIOMMUGroup(*device.DeviceInfo)
|
device.VfioDevs, err = GetAllVFIODevicesFromIOMMUGroup(*device.DeviceInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, vfio := range device.VfioDevs {
|
for _, vfio := range device.VfioDevs {
|
||||||
// If vfio.Port is not set we bail out, users should set
|
// If vfio.Port is not set we bail out, users should set
|
||||||
|
@ -792,11 +792,25 @@ func (q *qemu) createPCIeTopology(qemuConfig *govmmQemu.Config, hypervisorConfig
|
|||||||
return fmt.Errorf("Cannot get host path for device: %v err: %v", dev, err)
|
return fmt.Errorf("Cannot get host path for device: %v err: %v", dev, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
devicesPerIOMMUGroup, err := drivers.GetAllVFIODevicesFromIOMMUGroup(dev)
|
vfioDevices := []*config.VFIODev{}
|
||||||
|
// This works for IOMMUFD enabled kernels > 6.x
|
||||||
|
// In the case of IOMMUFD the device.HostPath will look like
|
||||||
|
// /dev/vfio/devices/vfio0
|
||||||
|
// (1) Check if we have the new IOMMUFD or old container based VFIO
|
||||||
|
if strings.HasPrefix(dev.HostPath, drivers.IommufdDevPath) {
|
||||||
|
q.Logger().Infof("### IOMMUFD Path: %s", dev.HostPath)
|
||||||
|
vfioDevices, err = drivers.GetDeviceFromVFIODev(dev)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Cannot get VFIO device from IOMMUFD with device: %v err: %v", dev, err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vfioDevices, err = drivers.GetAllVFIODevicesFromIOMMUGroup(dev)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Cannot get all VFIO devices from IOMMU group with device: %v err: %v", dev, err)
|
return fmt.Errorf("Cannot get all VFIO devices from IOMMU group with device: %v err: %v", dev, err)
|
||||||
}
|
}
|
||||||
for _, vfioDevice := range devicesPerIOMMUGroup {
|
}
|
||||||
|
|
||||||
|
for _, vfioDevice := range vfioDevices {
|
||||||
if drivers.IsPCIeDevice(vfioDevice.BDF) {
|
if drivers.IsPCIeDevice(vfioDevice.BDF) {
|
||||||
numOfPluggablePorts = numOfPluggablePorts + 1
|
numOfPluggablePorts = numOfPluggablePorts + 1
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user