| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package isolated_device
- import (
- "fmt"
- "io/ioutil"
- "path"
- "strings"
- "yunion.io/x/jsonutils"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/onecloud/pkg/apis/compute"
- "yunion.io/x/onecloud/pkg/hostman/guestman/desc"
- "yunion.io/x/onecloud/pkg/util/fileutils2"
- )
- type sNVIDIAVgpuDevice struct {
- pfDev *PCIDevice
- cloudId string
- hostId string
- guestId string
- devType string
- mdevId string
- model string
- profile map[string]string
- }
- func (dev *sNVIDIAVgpuDevice) String() string {
- return jsonutils.Marshal(dev).String()
- }
- func (dev *sNVIDIAVgpuDevice) IsInfinibandNic() bool {
- return false
- }
- func (dev *sNVIDIAVgpuDevice) GetCloudId() string {
- return dev.cloudId
- }
- func (dev *sNVIDIAVgpuDevice) GetHostId() string {
- return dev.hostId
- }
- func (dev *sNVIDIAVgpuDevice) SetHostId(hId string) {
- dev.hostId = hId
- }
- func (dev *sNVIDIAVgpuDevice) GetGuestId() string {
- return dev.guestId
- }
- func (dev *sNVIDIAVgpuDevice) GetWireId() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetOvsOffloadInterfaceName() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetVendorDeviceId() string {
- return dev.pfDev.GetVendorDeviceId()
- }
- func (dev *sNVIDIAVgpuDevice) GetAddr() string {
- return dev.pfDev.Addr
- }
- func (dev *sNVIDIAVgpuDevice) GetDeviceType() string {
- return dev.devType
- }
- func (dev *sNVIDIAVgpuDevice) GetModelName() string {
- modelName := dev.pfDev.ModelName
- if dev.pfDev.ModelName == "" {
- modelName = dev.pfDev.DeviceName
- }
- return modelName + "-" + dev.model
- }
- func (dev *sNVIDIAVgpuDevice) CustomProbe(idx int) error {
- return nil
- }
- func (dev *sNVIDIAVgpuDevice) GetDevicePath() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetNvidiaMpsMemoryLimit() int {
- return -1
- }
- func (dev *sNVIDIAVgpuDevice) GetNvidiaMpsMemoryTotal() int {
- return -1
- }
- func (dev *sNVIDIAVgpuDevice) GetNvidiaMpsThreadPercentage() int {
- return -1
- }
- func (dev *sNVIDIAVgpuDevice) GetCardPath() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetRenderPath() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetIndex() int {
- return -1
- }
- func (dev *sNVIDIAVgpuDevice) GetDeviceMinor() int {
- return -1
- }
- func (dev *sNVIDIAVgpuDevice) SetDeviceInfo(info CloudDeviceInfo) {
- if len(info.Id) != 0 {
- dev.cloudId = info.Id
- }
- if len(info.GuestId) != 0 {
- dev.guestId = info.GuestId
- }
- if len(info.HostId) != 0 {
- dev.hostId = info.HostId
- }
- if len(info.DevType) != 0 {
- dev.devType = info.DevType
- }
- }
- func (dev *sNVIDIAVgpuDevice) GetNVIDIAVgpuProfile() map[string]string {
- return dev.profile
- }
- func (dev *sNVIDIAVgpuDevice) GetMdevId() string {
- return dev.mdevId
- }
- func (dev *sNVIDIAVgpuDevice) DetectByAddr() error {
- return nil
- }
- func (dev *sNVIDIAVgpuDevice) GetPassthroughOptions() map[string]string {
- return nil
- }
- func (dev *sNVIDIAVgpuDevice) GetPassthroughCmd(index int) string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetIOMMUGroupDeviceCmd() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetIOMMUGroupRestAddrs() []string {
- return nil
- }
- func (dev *sNVIDIAVgpuDevice) GetPfName() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetVirtfn() int {
- return -1
- }
- func (dev *sNVIDIAVgpuDevice) GetNVMESizeMB() int {
- return -1
- }
- func (dev *sNVIDIAVgpuDevice) GetVGACmd() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetCPUCmd() string {
- return ""
- }
- func (dev *sNVIDIAVgpuDevice) GetQemuId() string {
- return "dev_" + dev.mdevId
- }
- func (dev *sNVIDIAVgpuDevice) GetNumaNode() (int, error) {
- numaNodePath := fmt.Sprintf("/sys/bus/pci/devices/0000:%s/numa_node", dev.GetAddr())
- numaNode, err := fileutils2.FileGetIntContent(numaNodePath)
- if err != nil {
- return -1, errors.Wrap(err, "get device numa node")
- }
- return numaNode, nil
- }
- func (dev *sNVIDIAVgpuDevice) GetHotPlugOptions(isolatedDev *desc.SGuestIsolatedDevice, guestDesc *desc.SGuestDesc) ([]*HotPlugOption, error) {
- ret := make([]*HotPlugOption, 0)
- var masterDevOpt *HotPlugOption
- for i := 0; i < len(isolatedDev.VfioDevs); i++ {
- sysfsdev := path.Join("/sys/bus/mdev/devices", isolatedDev.MdevId)
- opts := map[string]string{
- "sysfsdev": sysfsdev,
- "bus": isolatedDev.VfioDevs[i].BusStr(),
- "addr": isolatedDev.VfioDevs[i].SlotFunc(),
- "id": isolatedDev.VfioDevs[i].Id,
- }
- if isolatedDev.VfioDevs[i].Multi != nil {
- if *isolatedDev.VfioDevs[i].Multi {
- opts["multifunction"] = "on"
- } else {
- opts["multifunction"] = "off"
- }
- }
- devOpt := &HotPlugOption{
- Device: isolatedDev.VfioDevs[i].DevType,
- Options: opts,
- }
- if isolatedDev.VfioDevs[i].Function == 0 {
- masterDevOpt = devOpt
- } else {
- ret = append(ret, devOpt)
- }
- }
- // if PCI slot function 0 already assigned, qemu will reject hotplug function
- // so put function 0 at the enda
- if masterDevOpt == nil {
- return nil, errors.Errorf("GPU Device no function 0 found")
- }
- ret = append(ret, masterDevOpt)
- return ret, nil
- }
- func (dev *sNVIDIAVgpuDevice) GetHotUnplugOptions(isolatedDev *desc.SGuestIsolatedDevice) ([]*HotUnplugOption, error) {
- if len(isolatedDev.VfioDevs) == 0 {
- return nil, errors.Errorf("device %s no pci ids", isolatedDev.Id)
- }
- return []*HotUnplugOption{
- {
- Id: isolatedDev.VfioDevs[0].Id,
- },
- }, nil
- }
- // GetPCIEInfo implements IDevice.
- func (dev *sNVIDIAVgpuDevice) GetPCIEInfo() *compute.IsolatedDevicePCIEInfo {
- return dev.pfDev.PCIEInfo
- }
- func NewNvidiaVgpuDevice(dev *PCIDevice, devType, mdevId, model string, profile map[string]string) *sNVIDIAVgpuDevice {
- return &sNVIDIAVgpuDevice{
- pfDev: dev,
- devType: devType,
- mdevId: mdevId,
- model: model,
- profile: profile,
- }
- }
- func getNvidiaVGpus(gpuPF string) ([]*sNVIDIAVgpuDevice, error) {
- mdevDeviceDir := fmt.Sprintf("/sys/class/mdev_bus/0000:%s", gpuPF)
- if !fileutils2.Exists(mdevDeviceDir) {
- return nil, errors.Errorf("unknown device %s", gpuPF)
- }
- pfDev, err := detectPCIDevByAddrWithoutIOMMUGroup(gpuPF)
- if err != nil {
- return nil, errors.Wrap(err, "detect pf device")
- }
- // regutils.MatchUUID(self.HostId)
- files, err := ioutil.ReadDir(mdevDeviceDir)
- if err != nil {
- return nil, errors.Wrap(err, "read mdev device path")
- }
- nvidiaVgpus := make([]*sNVIDIAVgpuDevice, 0)
- for i := range files {
- if !regutils.MatchUUID(files[i].Name()) {
- continue
- }
- mdevPath := path.Join(mdevDeviceDir, files[i].Name())
- model, err := fileutils2.FileGetContents(path.Join(mdevPath, "mdev_type", "name"))
- if err != nil {
- return nil, errors.Wrap(err, "read file mdev_type/name")
- }
- model = strings.TrimSpace(model)
- // eg: num_heads=4, frl_config=60, framebuffer=1024M, max_resolution=5120x2880, max_instance=24
- vgpuProfile, err := fileutils2.FileGetContents(path.Join(mdevPath, "mdev_type", "description"))
- if err != nil {
- return nil, errors.Wrap(err, "read file mdev_type/description")
- }
- keys := []string{"num_heads", "frl_config", "framebuffer", "max_resolution", "max_instance"}
- profile := make(map[string]string)
- for _, key := range keys {
- keyWithValue := key + "="
- if strings.Contains(vgpuProfile, keyWithValue) {
- startIndex := strings.Index(vgpuProfile, keyWithValue)
- endIndex := startIndex + len(keyWithValue)
- value := strings.Split(vgpuProfile[endIndex:], ",")[0]
- profile[key] = strings.TrimSpace(value)
- }
- }
- mdev := NewNvidiaVgpuDevice(pfDev, compute.LEGACY_VGPU_TYPE, files[i].Name(), model, profile)
- nvidiaVgpus = append(nvidiaVgpus, mdev)
- }
- return nvidiaVgpus, nil
- }
|