github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/device/manager/utils.go (about) 1 // Copyright (c) 2017-2018 Intel Corporation 2 // Copyright (c) 2018 Huawei Corporation 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 package manager 8 9 import ( 10 "fmt" 11 "io/ioutil" 12 "path/filepath" 13 "strconv" 14 "strings" 15 16 "github.com/sirupsen/logrus" 17 18 "github.com/kata-containers/runtime/virtcontainers/device/config" 19 "github.com/kata-containers/runtime/virtcontainers/device/drivers" 20 ) 21 22 const ( 23 vfioPath = "/dev/vfio/" 24 ) 25 26 // isVFIO checks if the device provided is a vfio group. 27 func isVFIO(hostPath string) bool { 28 // Ignore /dev/vfio/vfio character device 29 if strings.HasPrefix(hostPath, filepath.Join(vfioPath, "vfio")) { 30 return false 31 } 32 33 if strings.HasPrefix(hostPath, vfioPath) && len(hostPath) > len(vfioPath) { 34 return true 35 } 36 37 return false 38 } 39 40 // isBlock checks if the device is a block device. 41 func isBlock(devInfo config.DeviceInfo) bool { 42 return devInfo.DevType == "b" 43 } 44 45 // IsVFIOLargeBarSpaceDevice checks if the device is a large bar space device. 46 func IsVFIOLargeBarSpaceDevice(hostPath string) (bool, error) { 47 if !isVFIO(hostPath) { 48 return false, nil 49 } 50 51 iommuDevicesPath := filepath.Join(config.SysIOMMUPath, filepath.Base(hostPath), "devices") 52 deviceFiles, err := ioutil.ReadDir(iommuDevicesPath) 53 if err != nil { 54 return false, err 55 } 56 57 // Pass all devices in iommu group 58 for _, deviceFile := range deviceFiles { 59 vfioDeviceType := drivers.GetVFIODeviceType(deviceFile.Name()) 60 var isLarge bool 61 switch vfioDeviceType { 62 case config.VFIODeviceNormalType: 63 sysfsResource := filepath.Join(iommuDevicesPath, deviceFile.Name(), "resource") 64 if isLarge, err = isLargeBarSpace(sysfsResource); err != nil { 65 return false, err 66 } 67 deviceLogger().WithFields(logrus.Fields{ 68 "device-file": deviceFile.Name(), 69 "device-type": vfioDeviceType, 70 "resource": sysfsResource, 71 "large-bar-space": isLarge, 72 }).Info("Detect large bar space device") 73 return isLarge, nil 74 case config.VFIODeviceMediatedType: 75 //TODO: support VFIODeviceMediatedType 76 deviceLogger().WithFields(logrus.Fields{ 77 "device-file": deviceFile.Name(), 78 "device-type": vfioDeviceType, 79 }).Warn("Detect large bar space device is not yet supported for VFIODeviceMediatedType") 80 default: 81 deviceLogger().WithFields(logrus.Fields{ 82 "device-file": deviceFile.Name(), 83 "device-type": vfioDeviceType, 84 }).Warn("Incorrect token found when detecting large bar space devices") 85 } 86 } 87 88 return false, nil 89 } 90 91 func isLargeBarSpace(resourcePath string) (bool, error) { 92 buf, err := ioutil.ReadFile(resourcePath) 93 if err != nil { 94 return false, fmt.Errorf("failed to read sysfs resource: %v", err) 95 } 96 97 // The resource file contains host addresses of PCI resources: 98 // For example: 99 // $ cat /sys/bus/pci/devices/0000:04:00.0/resource 100 // 0x00000000c6000000 0x00000000c6ffffff 0x0000000000040200 101 // 0x0000383800000000 0x0000383bffffffff 0x000000000014220c 102 // Refer: 103 // resource format: https://github.com/torvalds/linux/blob/63623fd44972d1ed2bfb6e0fb631dfcf547fd1e7/drivers/pci/pci-sysfs.c#L145 104 // calculate size : https://github.com/pciutils/pciutils/blob/61ecc14a327de030336f1ff3fea9c7e7e55a90ca/lspci.c#L388 105 for rIdx, line := range strings.Split(string(buf), "\n") { 106 cols := strings.Fields(line) 107 // start and end columns are required to calculate the size 108 if len(cols) < 2 { 109 deviceLogger().WithField("resource-line", line).Debug("not enough columns to calculate PCI size") 110 continue 111 } 112 start, _ := strconv.ParseUint(cols[0], 0, 64) 113 end, _ := strconv.ParseUint(cols[1], 0, 64) 114 if start > end { 115 deviceLogger().WithFields(logrus.Fields{ 116 "start": start, 117 "end": end, 118 }).Debug("start is greater than end") 119 continue 120 } 121 // Use right shift to convert Bytes to GBytes 122 // This is equivalent to ((end - start + 1) / 1024 / 1024 / 1024) 123 gbSize := (end - start + 1) >> 30 124 deviceLogger().WithFields(logrus.Fields{ 125 "resource": resourcePath, 126 "region": rIdx, 127 "start": cols[0], 128 "end": cols[1], 129 "gb-size": gbSize, 130 }).Debug("Check large bar space device") 131 //size is large than 4G 132 if gbSize > 4 { 133 return true, nil 134 } 135 } 136 137 return false, nil 138 } 139 140 // isVhostUserBlk checks if the device is a VhostUserBlk device. 141 func isVhostUserBlk(devInfo config.DeviceInfo) bool { 142 return devInfo.DevType == "b" && devInfo.Major == config.VhostUserBlkMajor 143 } 144 145 // isVhostUserSCSI checks if the device is a VhostUserSCSI device. 146 func isVhostUserSCSI(devInfo config.DeviceInfo) bool { 147 return devInfo.DevType == "b" && devInfo.Major == config.VhostUserSCSIMajor 148 }