Files
kata-containers/virtcontainers/device/manager/utils.go
Liu Xiaodong 3696318436 devices: filter vhost-user-blk/scsi device
Reserved number of Linux device number 241 and 242
are used to identify vhost-user-blk and vhost-user-scsi
devices.
for example, after command:
mknod <Vhost-User-Dir>/block/devices/vhost-dev0 b 241 0
this node will be recognized as vhost-user-blk device.

Fixes: #2380

Signed-off-by: Liu Xiaodong <xiaodong.liu@intel.com>
2020-03-12 03:41:55 -04:00

145 lines
4.1 KiB
Go

// Copyright (c) 2017-2018 Intel Corporation
// Copyright (c) 2018 Huawei Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package manager
import (
"fmt"
"io/ioutil"
"path/filepath"
"strconv"
"strings"
"github.com/sirupsen/logrus"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/device/drivers"
)
const (
vfioPath = "/dev/vfio/"
)
// isVFIO checks if the device provided is a vfio group.
func isVFIO(hostPath string) bool {
// Ignore /dev/vfio/vfio character device
if strings.HasPrefix(hostPath, filepath.Join(vfioPath, "vfio")) {
return false
}
if strings.HasPrefix(hostPath, vfioPath) && len(hostPath) > len(vfioPath) {
return true
}
return false
}
// isBlock checks if the device is a block device.
func isBlock(devInfo config.DeviceInfo) bool {
return devInfo.DevType == "b"
}
// IsVFIOLargeBarSpaceDevice checks if the device is a large bar space device.
func IsVFIOLargeBarSpaceDevice(hostPath string) (bool, error) {
if !isVFIO(hostPath) {
return false, nil
}
iommuDevicesPath := filepath.Join(config.SysIOMMUPath, filepath.Base(hostPath), "devices")
deviceFiles, err := ioutil.ReadDir(iommuDevicesPath)
if err != nil {
return false, err
}
// Pass all devices in iommu group
for _, deviceFile := range deviceFiles {
vfioDeviceType := drivers.GetVFIODeviceType(deviceFile.Name())
var isLarge bool
switch vfioDeviceType {
case config.VFIODeviceNormalType:
sysfsResource := filepath.Join(iommuDevicesPath, deviceFile.Name(), "resource")
if isLarge, err = isLargeBarSpace(sysfsResource); err != nil {
return false, err
}
deviceLogger().WithFields(logrus.Fields{
"device-file": deviceFile.Name(),
"device-type": vfioDeviceType,
"resource": sysfsResource,
"large-bar-space": isLarge,
}).Info("Detect large bar space device")
return isLarge, nil
case config.VFIODeviceMediatedType:
//TODO: support VFIODeviceMediatedType
deviceLogger().WithFields(logrus.Fields{
"device-file": deviceFile.Name(),
"device-type": vfioDeviceType,
}).Warn("Detect large bar space device is not yet supported for VFIODeviceMediatedType")
default:
deviceLogger().WithFields(logrus.Fields{
"device-file": deviceFile.Name(),
"device-type": vfioDeviceType,
}).Warn("Incorrect token found when detecting large bar space devices")
}
}
return false, nil
}
func isLargeBarSpace(resourcePath string) (bool, error) {
buf, err := ioutil.ReadFile(resourcePath)
if err != nil {
return false, fmt.Errorf("failed to read sysfs resource: %v", err)
}
// The resource file contains host addresses of PCI resources:
// For example:
// $ cat /sys/bus/pci/devices/0000:04:00.0/resource
// 0x00000000c6000000 0x00000000c6ffffff 0x0000000000040200
// 0x0000383800000000 0x0000383bffffffff 0x000000000014220c
// Refer:
// resource format: https://github.com/torvalds/linux/blob/63623fd44972d1ed2bfb6e0fb631dfcf547fd1e7/drivers/pci/pci-sysfs.c#L145
// calculate size : https://github.com/pciutils/pciutils/blob/61ecc14a327de030336f1ff3fea9c7e7e55a90ca/lspci.c#L388
suffix := []string{"", "K", "M", "G", "T"}
for rIdx, line := range strings.Split(string(buf), "\n") {
cols := strings.Fields(line)
start, _ := strconv.ParseUint(cols[0], 0, 64)
end, _ := strconv.ParseUint(cols[1], 0, 64)
size := end - start + 1
sIdx := 0
for i := range suffix {
if size/1024 < 1 {
break
}
size /= 1024
sIdx = i + 1
}
deviceLogger().WithFields(logrus.Fields{
"resource": resourcePath,
"region": rIdx,
"start": cols[0],
"end": cols[1],
"size": size,
"suffix": suffix[sIdx],
}).Debug("Check large bar space device")
//size is large than 4G
if (sIdx == 3 && size > 4) || sIdx > 3 {
return true, nil
}
}
return false, nil
}
// isVhostUserBlk checks if the device is a VhostUserBlk device.
func isVhostUserBlk(devInfo config.DeviceInfo) bool {
return devInfo.Major == config.VhostUserBlkMajor
}
// isVhostUserSCSI checks if the device is a VhostUserSCSI device.
func isVhostUserSCSI(devInfo config.DeviceInfo) bool {
return devInfo.Major == config.VhostUserSCSIMajor
}