github.com/k8snetworkplumbingwg/sriov-network-operator@v1.2.1-0.20240408194816-2d2e5a45d453/pkg/host/internal/udev/udev.go (about) 1 package udev 2 3 import ( 4 "fmt" 5 "os" 6 "path" 7 "path/filepath" 8 "strings" 9 10 "sigs.k8s.io/controller-runtime/pkg/log" 11 12 "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts" 13 "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/types" 14 "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils" 15 "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars" 16 ) 17 18 type udev struct { 19 utilsHelper utils.CmdInterface 20 } 21 22 func New(utilsHelper utils.CmdInterface) types.UdevInterface { 23 return &udev{utilsHelper: utilsHelper} 24 } 25 26 func (u *udev) PrepareNMUdevRule(supportedVfIds []string) error { 27 log.Log.V(2).Info("PrepareNMUdevRule()") 28 filePath := filepath.Join(vars.FilesystemRoot, consts.HostUdevRulesFolder, "10-nm-unmanaged.rules") 29 30 // remove the old unmanaged rules file 31 if _, err := os.Stat(filePath); err == nil { 32 err = os.Remove(filePath) 33 if err != nil { 34 log.Log.Error(err, "failed to remove the network manager global unmanaged rule", 35 "path", filePath) 36 } 37 } 38 39 // create the pf finder script for udev rules 40 stdout, stderr, err := u.utilsHelper.RunCommand("/bin/bash", filepath.Join(vars.FilesystemRoot, consts.UdevDisableNM)) 41 if err != nil { 42 log.Log.Error(err, "PrepareNMUdevRule(): failed to prepare nmUdevRule", "stderr", stderr) 43 return err 44 } 45 log.Log.V(2).Info("PrepareNMUdevRule()", "stdout", stdout) 46 47 //save the device list to use for udev rules 48 vars.SupportedVfIds = supportedVfIds 49 return nil 50 } 51 52 // PrepareVFRepUdevRule creates a script which helps to configure representor name for the VF 53 func (u *udev) PrepareVFRepUdevRule() error { 54 log.Log.V(2).Info("PrepareVFRepUdevRule()") 55 targetPath := filepath.Join(vars.FilesystemRoot, consts.HostUdevFolder, filepath.Base(consts.UdevRepName)) 56 data, err := os.ReadFile(filepath.Join(vars.FilesystemRoot, consts.UdevRepName)) 57 if err != nil { 58 log.Log.Error(err, "PrepareVFRepUdevRule(): failed to read source for representor name UDEV script") 59 return err 60 } 61 if err := os.WriteFile(targetPath, data, 0755); err != nil { 62 log.Log.Error(err, "PrepareVFRepUdevRule(): failed to write representor name UDEV script") 63 return err 64 } 65 if err := os.Chmod(targetPath, 0755); err != nil { 66 log.Log.Error(err, "PrepareVFRepUdevRule(): failed to set permissions on representor name UDEV script") 67 return err 68 } 69 return nil 70 } 71 72 // AddDisableNMUdevRule adds udev rule that disables NetworkManager for VFs on the concrete PF: 73 func (u *udev) AddDisableNMUdevRule(pfPciAddress string) error { 74 log.Log.V(2).Info("AddDisableNMUdevRule()", "device", pfPciAddress) 75 udevRuleContent := fmt.Sprintf(consts.NMUdevRule, strings.Join(vars.SupportedVfIds, "|"), pfPciAddress) 76 return u.addUdevRule(pfPciAddress, "10-nm-disable", udevRuleContent) 77 } 78 79 // RemoveDisableNMUdevRule removes udev rule that disables NetworkManager for VFs on the concrete PF 80 func (u *udev) RemoveDisableNMUdevRule(pfPciAddress string) error { 81 log.Log.V(2).Info("RemoveDisableNMUdevRule()", "device", pfPciAddress) 82 return u.removeUdevRule(pfPciAddress, "10-nm-disable") 83 } 84 85 // AddPersistPFNameUdevRule add udev rule that preserves PF name after switching to switchdev mode 86 func (u *udev) AddPersistPFNameUdevRule(pfPciAddress, pfName string) error { 87 log.Log.V(2).Info("AddPersistPFNameUdevRule()", "device", pfPciAddress) 88 udevRuleContent := fmt.Sprintf(consts.PFNameUdevRule, pfPciAddress, pfName) 89 return u.addUdevRule(pfPciAddress, "10-pf-name", udevRuleContent) 90 } 91 92 // RemovePersistPFNameUdevRule removes udev rule that preserves PF name after switching to switchdev mode 93 func (u *udev) RemovePersistPFNameUdevRule(pfPciAddress string) error { 94 log.Log.V(2).Info("RemovePersistPFNameUdevRule()", "device", pfPciAddress) 95 return u.removeUdevRule(pfPciAddress, "10-pf-name") 96 } 97 98 // AddVfRepresentorUdevRule adds udev rule that renames VF representors on the concrete PF 99 func (u *udev) AddVfRepresentorUdevRule(pfPciAddress, pfName, pfSwitchID, pfSwitchPort string) error { 100 log.Log.V(2).Info("AddVfRepresentorUdevRule()", 101 "device", pfPciAddress, "name", pfName, "switch", pfSwitchID, "port", pfSwitchPort) 102 udevRuleContent := fmt.Sprintf(consts.SwitchdevUdevRule, pfSwitchID, strings.TrimPrefix(pfSwitchPort, "p"), pfName) 103 return u.addUdevRule(pfPciAddress, "20-switchdev", udevRuleContent) 104 } 105 106 // RemoveVfRepresentorUdevRule removes udev rule that renames VF representors on the concrete PF 107 func (u *udev) RemoveVfRepresentorUdevRule(pfPciAddress string) error { 108 log.Log.V(2).Info("RemoveVfRepresentorUdevRule()", "device", pfPciAddress) 109 return u.removeUdevRule(pfPciAddress, "20-switchdev") 110 } 111 112 // LoadUdevRules triggers udev rules for network subsystem 113 func (u *udev) LoadUdevRules() error { 114 log.Log.V(2).Info("LoadUdevRules()") 115 udevAdmTool := "udevadm" 116 _, stderr, err := u.utilsHelper.RunCommand(udevAdmTool, "control", "--reload-rules") 117 if err != nil { 118 log.Log.Error(err, "LoadUdevRules(): failed to reload rules", "error", stderr) 119 return err 120 } 121 _, stderr, err = u.utilsHelper.RunCommand(udevAdmTool, "trigger", "--action", "add", "--attr-match", "subsystem=net") 122 if err != nil { 123 log.Log.Error(err, "LoadUdevRules(): failed to trigger rules", "error", stderr) 124 return err 125 } 126 return nil 127 } 128 129 func (u *udev) addUdevRule(pfPciAddress, ruleName, ruleContent string) error { 130 log.Log.V(2).Info("addUdevRule()", "device", pfPciAddress, "rule", ruleName) 131 rulePath := u.getRuleFolderPath() 132 err := os.MkdirAll(rulePath, os.ModePerm) 133 if err != nil && !os.IsExist(err) { 134 log.Log.Error(err, "ensureUdevRulePathExist(): failed to create dir", "path", rulePath) 135 return err 136 } 137 filePath := u.getRulePathForPF(ruleName, pfPciAddress) 138 if err := os.WriteFile(filePath, []byte(ruleContent), 0666); err != nil { 139 log.Log.Error(err, "addUdevRule(): fail to write file", "path", filePath) 140 return err 141 } 142 return nil 143 } 144 145 func (u *udev) removeUdevRule(pfPciAddress, ruleName string) error { 146 log.Log.V(2).Info("removeUdevRule()", "device", pfPciAddress, "rule", ruleName) 147 rulePath := u.getRulePathForPF(ruleName, pfPciAddress) 148 err := os.Remove(rulePath) 149 if err != nil && !os.IsNotExist(err) { 150 log.Log.Error(err, "removeUdevRule(): fail to remove rule file", "path", rulePath) 151 return err 152 } 153 return nil 154 } 155 156 func (u *udev) getRuleFolderPath() string { 157 return filepath.Join(vars.FilesystemRoot, consts.UdevRulesFolder) 158 } 159 160 func (u *udev) getRulePathForPF(ruleName, pfPciAddress string) string { 161 return path.Join(u.getRuleFolderPath(), fmt.Sprintf("%s-%s.rules", ruleName, pfPciAddress)) 162 }