-
Notifications
You must be signed in to change notification settings - Fork 242
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check VBM node type automatically and support csi rund 3.0 protocol #1177
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ import ( | |
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
"sync" | ||
|
@@ -78,6 +79,13 @@ func IsNoSuchDeviceErr(err error) bool { | |
return strings.Contains(strings.ToLower(err.Error()), "no such device") | ||
} | ||
|
||
func IsNoSuchFileErr(err error) bool { | ||
if err == nil { | ||
return false | ||
} | ||
return strings.Contains(strings.ToLower(err.Error()), "no such file or directory") | ||
} | ||
|
||
// IohubSriovBind io hub bind | ||
func IohubSriovBind(bdf string) error { | ||
return ioutil.WriteFile(iohubSriovAction+"bind", []byte(bdf), 0600) | ||
|
@@ -491,6 +499,10 @@ const ( | |
DFBus // 1 | ||
) | ||
|
||
const ( | ||
dfBusDevicePathPattern = "/sys/bus/dragonfly/devices/dfvirtio*/type" | ||
) | ||
|
||
func (_type MachineType) BusName() string { | ||
busNames := [...]string{ | ||
BDFTypeBus, | ||
|
@@ -504,40 +516,89 @@ func (_type MachineType) BusName() string { | |
return busNames[_type] | ||
} | ||
|
||
func (_type MachineType) BusPrefix() string { | ||
busPrefixes := [...]string{ | ||
func (_type MachineType) BusRegex() (*regexp.Regexp, error) { | ||
busRegexes := [...]*regexp.Regexp{ | ||
BDFTypeDevice, | ||
DFBusTypeDevice, | ||
} | ||
|
||
if _type < BDF || _type > DFBus { | ||
return fmt.Sprintf("Unknown(%d)", _type) | ||
return nil, fmt.Errorf("Unknown(%d)", _type) | ||
} | ||
|
||
return busPrefixes[_type] | ||
return busRegexes[_type], nil | ||
} | ||
|
||
type Driver interface { | ||
CurentDriver() (string, error) | ||
UnbindDriver() error | ||
BindDriver(targetDriver string) error | ||
GetDeviceNumber() string | ||
GetPCIDeviceDriverType() string | ||
CheckVFIOUsage() error | ||
} | ||
|
||
func NewDeviceDriver(blockDevice, deviceNumber string, _type MachineType, extras map[string]string) (Driver, error) { | ||
func NewDeviceDriver(volumeId, blockDevice, deviceNumber string, _type MachineType, extras map[string]string) (Driver, error) { | ||
d := &driver{ | ||
blockDevice: blockDevice, | ||
deviceNumber: deviceNumber, | ||
machineType: _type, | ||
extras: extras, | ||
} | ||
if d.deviceNumber == "" { | ||
deviceNumber, err := DefaultDeviceManager.GetDeviceNumberFromBlockDevice(blockDevice, d.machineType.BusPrefix()) | ||
deviceNumberFromDevice := "" | ||
if blockDevice != "" { | ||
klog.Infof("NewDeviceDriver: start to get deviceNumber from device: %s", blockDevice) | ||
busRegex, err := d.machineType.BusRegex() | ||
if err != nil { | ||
klog.Errorf("NewDeviceDriver: get device number from block device err: %v", err) | ||
klog.Errorf("NewDeviceDriver: get bus type: %v", err) | ||
return nil, err | ||
} | ||
d.deviceNumber = deviceNumber | ||
deviceNumberFromDevice, err = DefaultDeviceManager.GetDeviceNumberFromBlockDevice(blockDevice, busRegex) | ||
if err != nil { | ||
klog.Errorf("NewDeviceDriver: get device number from block device err: %v", err) | ||
if deviceNumber == "" { | ||
return nil, err | ||
} | ||
} | ||
} | ||
if deviceNumberFromDevice != "" { | ||
if deviceNumber != "" && deviceNumberFromDevice != deviceNumber { | ||
klog.Warningf("NewDeviceDriver: newGeneratedDeviceNumber: %s is different from the one from exists file: %s, override with new deviceNumber", deviceNumberFromDevice, deviceNumber) | ||
} | ||
d.deviceNumber = deviceNumberFromDevice | ||
} | ||
if d.deviceNumber != "" { | ||
return d, nil | ||
} | ||
if _type == DFBus { | ||
matchesFile, err := filepath.Glob(dfBusDevicePathPattern) | ||
if err != nil { | ||
return nil, fmt.Errorf("Failed to list DFbus type files path. err: %v", err) | ||
} | ||
for _, path := range matchesFile { | ||
body, err := os.ReadFile(path) | ||
if err != nil { | ||
return nil, fmt.Errorf("Dfbus read type file %q failed: %v", path, err) | ||
} | ||
infos := strings.Split(string(body), " ") | ||
if len(infos) != 2 { | ||
return nil, fmt.Errorf("Dfbus type file format error") | ||
} | ||
if infos[0] != "block" { | ||
continue | ||
} | ||
if infos[1] == strings.TrimPrefix(volumeId, "d-") { | ||
DFNumber := filepath.Base(filepath.Dir(path)) | ||
d.deviceNumber = DFNumber | ||
return d, nil | ||
} | ||
} | ||
} else { | ||
output, err := utils.CommandOnNode("xdragon-bdf", "--nvme", "-id=%s", volumeId).CombinedOutput() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: new usage of nsenter. We should try to remove nsenter usage. |
||
if err != nil { | ||
return nil, fmt.Errorf("Failed to excute bdf command: %s, err: %v", volumeId, err) | ||
} | ||
d.deviceNumber = string(output) | ||
} | ||
return d, nil | ||
} | ||
|
@@ -570,5 +631,39 @@ func (d *driver) UnbindDriver() error { | |
} | ||
|
||
func (d *driver) BindDriver(targetDriver string) error { | ||
return utilsio.WriteTrunc(unix.AT_FDCWD, filepath.Join(sysPrefix, "sys/bus", d.machineType.BusName(), "drivers", targetDriver, "bind"), []byte(d.deviceNumber)) | ||
err := utilsio.WriteTrunc(unix.AT_FDCWD, filepath.Join(sysPrefix, "sys/bus", d.machineType.BusName(), "devices", d.deviceNumber, "driver_override"), []byte(targetDriver)) | ||
if err != nil { | ||
return err | ||
} | ||
if d.machineType == BDF { | ||
return utilsio.WriteTrunc(unix.AT_FDCWD, filepath.Join(sysPrefix, "sys/bus", d.machineType.BusName(), "drivers_probe"), []byte(d.deviceNumber)) | ||
} | ||
return nil | ||
} | ||
|
||
func (d *driver) GetPCIDeviceDriverType() string { | ||
output, _ := exec.Command("lspci", "-s", d.deviceNumber, "-n").CombinedOutput() | ||
klog.InfoS("GetDeviceDriverType: get driver type output", "deviceNumber", d.deviceNumber, "output", output) | ||
// #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 | ||
// #define PCI_DEVICE_ID_ALIBABA_NVME 0×5004 | ||
if strings.HasSuffix(strings.TrimSpace(string(output)), "1001") { | ||
return PCITypeVIRTIO | ||
} else { | ||
return PCITypeNVME | ||
} | ||
} | ||
|
||
func (d *driver) CheckVFIOUsage() error { | ||
actualPath, err := filepath.EvalSymlinks(filepath.Join(sysPrefix, "sys/bus", d.machineType.BusName(), "devices", d.deviceNumber, "iommu_group")) | ||
if err != nil { | ||
return err | ||
} | ||
klog.V(5).InfoS("CheckVFIOUsage: eval symlink success", "path", actualPath) | ||
groupNumber := filepath.Base(actualPath) | ||
// the command returns -1 if nothing is returned | ||
output, _ := exec.Command("lsof", filepath.Join("/dev/vfio", groupNumber)).CombinedOutput() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is expensive, I would strongly recommend not using this. Instead, ask the user to lock this file, so that we can use lock to detect usage. Or ask the user to write a PID file, and we can just check if the process is alive. |
||
if strings.TrimSpace(string(output)) != "" { | ||
return errors.Errorf("CheckVFIOUsage: device: %s is still be in used, output: %s", d.deviceNumber, output) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. convert output to string before logging. Or it will output a list of number. |
||
} | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't check error string. It is subject to change. Use errors.Is instead.