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  }