gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/device/drivers/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 drivers
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"path/filepath"
    13  	"strings"
    14  
    15  	"github.com/kata-containers/runtime/virtcontainers/device/api"
    16  	"github.com/kata-containers/runtime/virtcontainers/device/config"
    17  	"github.com/sirupsen/logrus"
    18  )
    19  
    20  const (
    21  	intMax = ^uint(0)
    22  
    23  	PCIDomain   = "0000"
    24  	PCIeKeyword = "PCIe"
    25  )
    26  
    27  type PCISysFsType string
    28  
    29  var (
    30  	PCISysFsDevices PCISysFsType = "devices" // /sys/bus/pci/devices
    31  	PCISysFsSlots   PCISysFsType = "slots"   // /sys/bus/pci/slots
    32  )
    33  
    34  type PCISysFsProperty string
    35  
    36  var (
    37  	PCISysFsDevicesClass     PCISysFsProperty = "class"         // /sys/bus/pci/devices/xxx/class
    38  	PCISysFsSlotsAddress     PCISysFsProperty = "address"       // /sys/bus/pci/slots/xxx/address
    39  	PCISysFsSlotsMaxBusSpeed PCISysFsProperty = "max_bus_speed" // /sys/bus/pci/slots/xxx/max_bus_speed
    40  )
    41  
    42  func deviceLogger() *logrus.Entry {
    43  	return api.DeviceLogger()
    44  }
    45  
    46  /*
    47  Identify PCIe device by /sys/bus/pci/slots/xx/max_bus_speed, sample content "8.0 GT/s PCIe"
    48  The /sys/bus/pci/slots/xx/address contains bdf, sample content "0000:04:00"
    49  bdf format: bus:slot.function
    50  */
    51  func isPCIeDevice(bdf string) bool {
    52  	if len(strings.Split(bdf, ":")) == 2 {
    53  		bdf = PCIDomain + ":" + bdf
    54  	}
    55  	slots, err := ioutil.ReadDir(config.SysBusPciSlotsPath)
    56  	if err != nil {
    57  		deviceLogger().WithError(err).WithField("path", config.SysBusPciSlotsPath).Warn("failed to list pci slots")
    58  		return false
    59  	}
    60  	b := strings.Split(bdf, ".")[0]
    61  	for _, slot := range slots {
    62  		address := getPCISlotProperty(slot.Name(), PCISysFsSlotsAddress)
    63  		if b == address {
    64  			maxBusSpeed := getPCISlotProperty(slot.Name(), PCISysFsSlotsMaxBusSpeed)
    65  			if strings.Contains(maxBusSpeed, PCIeKeyword) {
    66  				return true
    67  			}
    68  		}
    69  	}
    70  	deviceLogger().WithField("dev-bdf", bdf).Debug("can not find slot for bdf of pci device")
    71  	return false
    72  }
    73  
    74  // read from /sys/bus/pci/devices/xxx/property
    75  func getPCIDeviceProperty(bdf string, property PCISysFsProperty) string {
    76  	if len(strings.Split(bdf, ":")) == 2 {
    77  		bdf = PCIDomain + ":" + bdf
    78  	}
    79  	propertyPath := filepath.Join(config.SysBusPciDevicesPath, bdf, string(property))
    80  	rlt, err := readPCIProperty(propertyPath)
    81  	if err != nil {
    82  		deviceLogger().WithError(err).WithField("path", propertyPath).Warn("failed to read pci device property")
    83  		return ""
    84  	}
    85  	return rlt
    86  }
    87  
    88  // read from /sys/bus/pci/slots/xxx/property
    89  func getPCISlotProperty(slot string, property PCISysFsProperty) string {
    90  	propertyPath := filepath.Join(config.SysBusPciSlotsPath, slot, string(property))
    91  	rlt, err := readPCIProperty(propertyPath)
    92  	if err != nil {
    93  		deviceLogger().WithError(err).WithField("path", propertyPath).Warn("failed to read pci slot property")
    94  		return ""
    95  	}
    96  	return rlt
    97  }
    98  
    99  func readPCIProperty(propertyPath string) (string, error) {
   100  	var (
   101  		buf []byte
   102  		err error
   103  	)
   104  	if buf, err = ioutil.ReadFile(propertyPath); err != nil {
   105  		return "", fmt.Errorf("failed to read pci sysfs %v, error:%v", propertyPath, err)
   106  	}
   107  	return strings.Split(string(buf), "\n")[0], nil
   108  }
   109  
   110  func GetVFIODeviceType(deviceFileName string) config.VFIODeviceType {
   111  	//For example, 0000:04:00.0
   112  	tokens := strings.Split(deviceFileName, ":")
   113  	vfioDeviceType := config.VFIODeviceErrorType
   114  	if len(tokens) == 3 {
   115  		vfioDeviceType = config.VFIODeviceNormalType
   116  	} else {
   117  		//For example, 83b8f4f2-509f-382f-3c1e-e6bfe0fa1001
   118  		tokens = strings.Split(deviceFileName, "-")
   119  		if len(tokens) == 5 {
   120  			vfioDeviceType = config.VFIODeviceMediatedType
   121  		}
   122  	}
   123  	return vfioDeviceType
   124  }