github.com/k8snetworkplumbingwg/sriov-network-operator@v1.2.1-0.20240408194816-2d2e5a45d453/pkg/host/internal/kernel/kernel.go (about)

     1  package kernel
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"sigs.k8s.io/controller-runtime/pkg/log"
    11  
    12  	sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
    13  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
    14  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal"
    15  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/types"
    16  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
    17  	"github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
    18  )
    19  
    20  type kernel struct {
    21  	utilsHelper utils.CmdInterface
    22  }
    23  
    24  func New(utilsHelper utils.CmdInterface) types.KernelInterface {
    25  	return &kernel{utilsHelper: utilsHelper}
    26  }
    27  
    28  func (k *kernel) LoadKernelModule(name string, args ...string) error {
    29  	log.Log.Info("LoadKernelModule(): try to load kernel module", "name", name, "args", args)
    30  	chrootDefinition := utils.GetChrootExtension()
    31  	cmdArgs := strings.Join(args, " ")
    32  
    33  	// check if the driver is already loaded in to the system
    34  	isLoaded, err := k.IsKernelModuleLoaded(name)
    35  	if err != nil {
    36  		log.Log.Error(err, "LoadKernelModule(): failed to check if kernel module is already loaded", "name", name)
    37  	}
    38  	if isLoaded {
    39  		log.Log.Info("LoadKernelModule(): kernel module already loaded", "name", name)
    40  		return nil
    41  	}
    42  
    43  	_, _, err = k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("%s modprobe %s %s", chrootDefinition, name, cmdArgs))
    44  	if err != nil {
    45  		log.Log.Error(err, "LoadKernelModule(): failed to load kernel module with arguments", "name", name, "args", args)
    46  		return err
    47  	}
    48  	return nil
    49  }
    50  
    51  func (k *kernel) IsKernelModuleLoaded(kernelModuleName string) (bool, error) {
    52  	log.Log.Info("IsKernelModuleLoaded(): check if kernel module is loaded", "name", kernelModuleName)
    53  	chrootDefinition := utils.GetChrootExtension()
    54  
    55  	stdout, stderr, err := k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("%s lsmod | grep \"^%s\"", chrootDefinition, kernelModuleName))
    56  	if err != nil && len(stderr) != 0 {
    57  		log.Log.Error(err, "IsKernelModuleLoaded(): failed to check if kernel module is loaded",
    58  			"name", kernelModuleName, "stderr", stderr)
    59  		return false, err
    60  	}
    61  	log.Log.V(2).Info("IsKernelModuleLoaded():", "stdout", stdout)
    62  	if len(stderr) != 0 {
    63  		log.Log.Error(err, "IsKernelModuleLoaded(): failed to check if kernel module is loaded", "name", kernelModuleName, "stderr", stderr)
    64  		return false, fmt.Errorf(stderr)
    65  	}
    66  
    67  	if len(stdout) != 0 {
    68  		log.Log.Info("IsKernelModuleLoaded(): kernel module already loaded", "name", kernelModuleName)
    69  		return true, nil
    70  	}
    71  
    72  	return false, nil
    73  }
    74  
    75  func (k *kernel) TryEnableTun() {
    76  	if err := k.LoadKernelModule("tun"); err != nil {
    77  		log.Log.Error(err, "tryEnableTun(): TUN kernel module not loaded")
    78  	}
    79  }
    80  
    81  func (k *kernel) TryEnableVhostNet() {
    82  	if err := k.LoadKernelModule("vhost_net"); err != nil {
    83  		log.Log.Error(err, "tryEnableVhostNet(): VHOST_NET kernel module not loaded")
    84  	}
    85  }
    86  
    87  // GetCurrentKernelArgs This retrieves the kernel cmd line arguments
    88  func (k *kernel) GetCurrentKernelArgs() (string, error) {
    89  	path := consts.ProcKernelCmdLine
    90  	if !vars.UsingSystemdMode {
    91  		path = filepath.Join(consts.Host, path)
    92  	}
    93  
    94  	path = filepath.Join(vars.FilesystemRoot, path)
    95  	cmdLine, err := os.ReadFile(path)
    96  	if err != nil {
    97  		return "", fmt.Errorf("GetCurrentKernelArgs(): Error reading %s: %v", path, err)
    98  	}
    99  	return string(cmdLine), nil
   100  }
   101  
   102  // IsKernelArgsSet This checks if the kernel cmd line is set properly. Please note that the same key could be repeated
   103  // several times in the kernel cmd line. We can only ensure that the kernel cmd line has the key/val kernel arg that we set.
   104  func (k *kernel) IsKernelArgsSet(cmdLine string, karg string) bool {
   105  	elements := strings.Fields(cmdLine)
   106  	for _, element := range elements {
   107  		if element == karg {
   108  			return true
   109  		}
   110  	}
   111  	return false
   112  }
   113  
   114  // Unbind unbind driver for one device
   115  func (k *kernel) Unbind(pciAddr string) error {
   116  	log.Log.V(2).Info("Unbind(): unbind device driver for device", "device", pciAddr)
   117  	return k.UnbindDriverByBusAndDevice(consts.BusPci, pciAddr)
   118  }
   119  
   120  // BindDpdkDriver bind dpdk driver for one device
   121  // Bind the device given by "pciAddr" to the driver "driver"
   122  func (k *kernel) BindDpdkDriver(pciAddr, driver string) error {
   123  	log.Log.V(2).Info("BindDpdkDriver(): bind device to driver",
   124  		"device", pciAddr, "driver", driver)
   125  	if err := k.BindDriverByBusAndDevice(consts.BusPci, pciAddr, driver); err != nil {
   126  		_, innerErr := os.Readlink(filepath.Join(vars.FilesystemRoot, consts.SysBusPciDevices, pciAddr, "iommu_group"))
   127  		if innerErr != nil {
   128  			log.Log.Error(err, "Could not read IOMMU group for device", "device", pciAddr)
   129  			return fmt.Errorf(
   130  				"cannot bind driver %s to device %s, make sure IOMMU is enabled in BIOS. %w", driver, pciAddr, innerErr)
   131  		}
   132  		return err
   133  	}
   134  	return nil
   135  }
   136  
   137  // BindDefaultDriver bind driver for one device
   138  // Bind the device given by "pciAddr" to the default driver
   139  func (k *kernel) BindDefaultDriver(pciAddr string) error {
   140  	log.Log.V(2).Info("BindDefaultDriver(): bind device to default driver", "device", pciAddr)
   141  
   142  	curDriver, err := getDriverByBusAndDevice(consts.BusPci, pciAddr)
   143  	if err != nil {
   144  		return err
   145  	}
   146  	if curDriver != "" {
   147  		if !sriovnetworkv1.StringInArray(curDriver, vars.DpdkDrivers) {
   148  			log.Log.V(2).Info("BindDefaultDriver(): device already bound to default driver",
   149  				"device", pciAddr, "driver", curDriver)
   150  			return nil
   151  		}
   152  		if err := k.UnbindDriverByBusAndDevice(consts.BusPci, pciAddr); err != nil {
   153  			return err
   154  		}
   155  	}
   156  	if err := setDriverOverride(consts.BusPci, pciAddr, ""); err != nil {
   157  		return err
   158  	}
   159  	if err := probeDriver(consts.BusPci, pciAddr); err != nil {
   160  		return err
   161  	}
   162  	return nil
   163  }
   164  
   165  // BindDriverByBusAndDevice binds device to the provided driver
   166  // bus - the bus path in the sysfs, e.g. "pci" or "vdpa"
   167  // device - the name of the device on the bus, e.g. 0000:85:1e.5 for PCI or vpda1 for VDPA
   168  // driver - the name of the driver, e.g. vfio-pci or vhost_vdpa.
   169  func (k *kernel) BindDriverByBusAndDevice(bus, device, driver string) error {
   170  	log.Log.V(2).Info("BindDriverByBusAndDevice(): bind device to driver",
   171  		"bus", bus, "device", device, "driver", driver)
   172  
   173  	curDriver, err := getDriverByBusAndDevice(bus, device)
   174  	if err != nil {
   175  		return err
   176  	}
   177  	if curDriver != "" {
   178  		if curDriver == driver {
   179  			log.Log.V(2).Info("BindDriverByBusAndDevice(): device already bound to driver",
   180  				"bus", bus, "device", device, "driver", driver)
   181  			return nil
   182  		}
   183  		if err := k.UnbindDriverByBusAndDevice(bus, device); err != nil {
   184  			return err
   185  		}
   186  	}
   187  	if err := setDriverOverride(bus, device, driver); err != nil {
   188  		return err
   189  	}
   190  	if err := bindDriver(bus, device, driver); err != nil {
   191  		return err
   192  	}
   193  	return setDriverOverride(bus, device, "")
   194  }
   195  
   196  // Workaround function to handle a case where the vf default driver is stuck and not able to create the vf kernel interface.
   197  // This function unbind the VF from the default driver and try to bind it again
   198  // bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2045087
   199  func (k *kernel) RebindVfToDefaultDriver(vfAddr string) error {
   200  	log.Log.Info("RebindVfToDefaultDriver()", "vf", vfAddr)
   201  	if err := k.Unbind(vfAddr); err != nil {
   202  		return err
   203  	}
   204  	if err := k.BindDefaultDriver(vfAddr); err != nil {
   205  		log.Log.Error(err, "RebindVfToDefaultDriver(): fail to bind default driver", "device", vfAddr)
   206  		return err
   207  	}
   208  
   209  	log.Log.Info("RebindVfToDefaultDriver(): workaround implemented", "vf", vfAddr)
   210  	return nil
   211  }
   212  
   213  func (k *kernel) UnbindDriverIfNeeded(vfAddr string, isRdma bool) error {
   214  	if isRdma {
   215  		log.Log.Info("UnbindDriverIfNeeded(): unbinding driver", "device", vfAddr)
   216  		if err := k.Unbind(vfAddr); err != nil {
   217  			return err
   218  		}
   219  		log.Log.Info("UnbindDriverIfNeeded(): unbounded driver", "device", vfAddr)
   220  	}
   221  	return nil
   222  }
   223  
   224  // UnbindDriverByBusAndDevice unbind device identified by bus and device ID from the driver
   225  // bus - the bus path in the sysfs, e.g. "pci" or "vdpa"
   226  // device - the name of the device on the bus, e.g. 0000:85:1e.5 for PCI or vpda1 for VDPA
   227  func (k *kernel) UnbindDriverByBusAndDevice(bus, device string) error {
   228  	log.Log.V(2).Info("UnbindDriverByBusAndDevice(): unbind device driver for device", "bus", bus, "device", device)
   229  	driver, err := getDriverByBusAndDevice(bus, device)
   230  	if err != nil {
   231  		return err
   232  	}
   233  	if driver == "" {
   234  		log.Log.V(2).Info("UnbindDriverByBusAndDevice(): device has no driver", "bus", bus, "device", device)
   235  		return nil
   236  	}
   237  	return unbindDriver(bus, device, driver)
   238  }
   239  
   240  func (k *kernel) HasDriver(pciAddr string) (bool, string) {
   241  	driver, err := getDriverByBusAndDevice(consts.BusPci, pciAddr)
   242  	if err != nil {
   243  		log.Log.V(2).Info("HasDriver(): device driver is empty for device", "device", pciAddr)
   244  		return false, ""
   245  	}
   246  	if driver != "" {
   247  		log.Log.V(2).Info("HasDriver(): device driver for device", "device", pciAddr, "driver", driver)
   248  		return true, driver
   249  	}
   250  	return false, ""
   251  }
   252  
   253  // GetDriverByBusAndDevice returns driver for the device or error.
   254  // returns "", nil if the device has no driver.
   255  // bus - the bus path in the sysfs, e.g. "pci" or "vdpa"
   256  // device - the name of the device on the bus, e.g. 0000:85:1e.5 for PCI or vpda1 for VDPA
   257  func (k *kernel) GetDriverByBusAndDevice(bus, device string) (string, error) {
   258  	log.Log.V(2).Info("GetDriverByBusAndDevice(): get driver for device", "bus", bus, "device", device)
   259  	return getDriverByBusAndDevice(bus, device)
   260  }
   261  
   262  func (k *kernel) TryEnableRdma() (bool, error) {
   263  	log.Log.V(2).Info("tryEnableRdma()")
   264  	chrootDefinition := utils.GetChrootExtension()
   265  
   266  	// check if the driver is already loaded in to the system
   267  	_, stderr, mlx4Err := k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("grep --quiet 'mlx4_en' <(%s lsmod)", chrootDefinition))
   268  	if mlx4Err != nil && len(stderr) != 0 {
   269  		log.Log.Error(mlx4Err, "tryEnableRdma(): failed to check for kernel module 'mlx4_en'", "stderr", stderr)
   270  		return false, fmt.Errorf(stderr)
   271  	}
   272  
   273  	_, stderr, mlx5Err := k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("grep --quiet 'mlx5_core' <(%s lsmod)", chrootDefinition))
   274  	if mlx5Err != nil && len(stderr) != 0 {
   275  		log.Log.Error(mlx5Err, "tryEnableRdma(): failed to check for kernel module 'mlx5_core'", "stderr", stderr)
   276  		return false, fmt.Errorf(stderr)
   277  	}
   278  
   279  	if mlx4Err != nil && mlx5Err != nil {
   280  		log.Log.Error(nil, "tryEnableRdma(): no RDMA capable devices")
   281  		return false, nil
   282  	}
   283  
   284  	isRhelSystem, err := k.IsRHELSystem()
   285  	if err != nil {
   286  		log.Log.Error(err, "tryEnableRdma(): failed to check if the machine is base on RHEL")
   287  		return false, err
   288  	}
   289  
   290  	// RHEL check
   291  	if isRhelSystem {
   292  		return k.EnableRDMAOnRHELMachine()
   293  	}
   294  
   295  	isUbuntuSystem, err := k.IsUbuntuSystem()
   296  	if err != nil {
   297  		log.Log.Error(err, "tryEnableRdma(): failed to check if the machine is base on Ubuntu")
   298  		return false, err
   299  	}
   300  
   301  	if isUbuntuSystem {
   302  		return k.EnableRDMAOnUbuntuMachine()
   303  	}
   304  
   305  	osName, err := k.GetOSPrettyName()
   306  	if err != nil {
   307  		log.Log.Error(err, "tryEnableRdma(): failed to check OS name")
   308  		return false, err
   309  	}
   310  
   311  	log.Log.Error(nil, "tryEnableRdma(): Unsupported OS", "name", osName)
   312  	return false, fmt.Errorf("unable to load RDMA unsupported OS: %s", osName)
   313  }
   314  
   315  func (k *kernel) EnableRDMAOnRHELMachine() (bool, error) {
   316  	log.Log.Info("EnableRDMAOnRHELMachine()")
   317  	isCoreOsSystem, err := k.IsCoreOS()
   318  	if err != nil {
   319  		log.Log.Error(err, "EnableRDMAOnRHELMachine(): failed to check if the machine runs CoreOS")
   320  		return false, err
   321  	}
   322  
   323  	// CoreOS check
   324  	if isCoreOsSystem {
   325  		isRDMALoaded, err := k.RdmaIsLoaded()
   326  		if err != nil {
   327  			log.Log.Error(err, "EnableRDMAOnRHELMachine(): failed to check if RDMA kernel modules are loaded")
   328  			return false, err
   329  		}
   330  
   331  		return isRDMALoaded, nil
   332  	}
   333  
   334  	// RHEL
   335  	log.Log.Info("EnableRDMAOnRHELMachine(): enabling RDMA on RHEL machine")
   336  	isRDMAEnable, err := k.EnableRDMA(internal.RhelRDMAConditionFile, internal.RhelRDMAServiceName, internal.RhelPackageManager)
   337  	if err != nil {
   338  		log.Log.Error(err, "EnableRDMAOnRHELMachine(): failed to enable RDMA on RHEL machine")
   339  		return false, err
   340  	}
   341  
   342  	// check if we need to install rdma-core package
   343  	if isRDMAEnable {
   344  		isRDMALoaded, err := k.RdmaIsLoaded()
   345  		if err != nil {
   346  			log.Log.Error(err, "EnableRDMAOnRHELMachine(): failed to check if RDMA kernel modules are loaded")
   347  			return false, err
   348  		}
   349  
   350  		// if ib kernel module is not loaded trigger a loading
   351  		if isRDMALoaded {
   352  			err = k.TriggerUdevEvent()
   353  			if err != nil {
   354  				log.Log.Error(err, "EnableRDMAOnRHELMachine() failed to trigger udev event")
   355  				return false, err
   356  			}
   357  		}
   358  	}
   359  
   360  	return true, nil
   361  }
   362  
   363  func (k *kernel) EnableRDMAOnUbuntuMachine() (bool, error) {
   364  	log.Log.Info("EnableRDMAOnUbuntuMachine(): enabling RDMA on RHEL machine")
   365  	isRDMAEnable, err := k.EnableRDMA(internal.UbuntuRDMAConditionFile, internal.UbuntuRDMAServiceName, internal.UbuntuPackageManager)
   366  	if err != nil {
   367  		log.Log.Error(err, "EnableRDMAOnUbuntuMachine(): failed to enable RDMA on Ubuntu machine")
   368  		return false, err
   369  	}
   370  
   371  	// check if we need to install rdma-core package
   372  	if isRDMAEnable {
   373  		isRDMALoaded, err := k.RdmaIsLoaded()
   374  		if err != nil {
   375  			log.Log.Error(err, "EnableRDMAOnUbuntuMachine(): failed to check if RDMA kernel modules are loaded")
   376  			return false, err
   377  		}
   378  
   379  		// if ib kernel module is not loaded trigger a loading
   380  		if isRDMALoaded {
   381  			err = k.TriggerUdevEvent()
   382  			if err != nil {
   383  				log.Log.Error(err, "EnableRDMAOnUbuntuMachine() failed to trigger udev event")
   384  				return false, err
   385  			}
   386  		}
   387  	}
   388  
   389  	return true, nil
   390  }
   391  
   392  func (k *kernel) IsRHELSystem() (bool, error) {
   393  	log.Log.Info("IsRHELSystem(): checking for RHEL machine")
   394  	path := internal.RedhatReleaseFile
   395  	if !vars.UsingSystemdMode {
   396  		path = filepath.Join(internal.HostPathFromDaemon, path)
   397  	}
   398  	if _, err := os.Stat(path); err != nil {
   399  		if os.IsNotExist(err) {
   400  			log.Log.V(2).Info("IsRHELSystem() not a RHEL machine")
   401  			return false, nil
   402  		}
   403  
   404  		log.Log.Error(err, "IsRHELSystem() failed to check for os release file", "path", path)
   405  		return false, err
   406  	}
   407  
   408  	return true, nil
   409  }
   410  
   411  func (k *kernel) IsCoreOS() (bool, error) {
   412  	log.Log.Info("IsCoreOS(): checking for CoreOS machine")
   413  	path := internal.RedhatReleaseFile
   414  	if !vars.UsingSystemdMode {
   415  		path = filepath.Join(internal.HostPathFromDaemon, path)
   416  	}
   417  
   418  	data, err := os.ReadFile(path)
   419  	if err != nil {
   420  		log.Log.Error(err, "IsCoreOS(): failed to read RHEL release file on path", "path", path)
   421  		return false, err
   422  	}
   423  
   424  	if strings.Contains(string(data), "CoreOS") {
   425  		return true, nil
   426  	}
   427  
   428  	return false, nil
   429  }
   430  
   431  func (k *kernel) IsUbuntuSystem() (bool, error) {
   432  	log.Log.Info("IsUbuntuSystem(): checking for Ubuntu machine")
   433  	path := internal.GenericOSReleaseFile
   434  	if !vars.UsingSystemdMode {
   435  		path = filepath.Join(internal.HostPathFromDaemon, path)
   436  	}
   437  
   438  	if _, err := os.Stat(path); err != nil {
   439  		if os.IsNotExist(err) {
   440  			log.Log.Error(nil, "IsUbuntuSystem() os-release on path doesn't exist", "path", path)
   441  			return false, err
   442  		}
   443  
   444  		log.Log.Error(err, "IsUbuntuSystem() failed to check for os release file", "path", path)
   445  		return false, err
   446  	}
   447  
   448  	stdout, stderr, err := k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("grep -i --quiet 'ubuntu' %s", path))
   449  	if err != nil && len(stderr) != 0 {
   450  		log.Log.Error(err, "IsUbuntuSystem(): failed to check for ubuntu operating system name in os-releasae file", "stderr", stderr)
   451  		return false, fmt.Errorf(stderr)
   452  	}
   453  
   454  	if len(stdout) > 0 {
   455  		return true, nil
   456  	}
   457  
   458  	return false, nil
   459  }
   460  
   461  func (k *kernel) RdmaIsLoaded() (bool, error) {
   462  	log.Log.V(2).Info("RdmaIsLoaded()")
   463  	chrootDefinition := utils.GetChrootExtension()
   464  
   465  	// check if the driver is already loaded in to the system
   466  	_, stderr, err := k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("grep --quiet '\\(^ib\\|^rdma\\)' <(%s lsmod)", chrootDefinition))
   467  	if err != nil && len(stderr) != 0 {
   468  		log.Log.Error(err, "RdmaIsLoaded(): fail to check if ib and rdma kernel modules are loaded", "stderr", stderr)
   469  		return false, fmt.Errorf(stderr)
   470  	}
   471  
   472  	if err != nil {
   473  		return false, nil
   474  	}
   475  
   476  	return true, nil
   477  }
   478  
   479  func (k *kernel) EnableRDMA(conditionFilePath, serviceName, packageManager string) (bool, error) {
   480  	path := conditionFilePath
   481  	if !vars.UsingSystemdMode {
   482  		path = filepath.Join(internal.HostPathFromDaemon, path)
   483  	}
   484  	log.Log.Info("EnableRDMA(): checking for service file", "path", path)
   485  
   486  	if _, err := os.Stat(path); err != nil {
   487  		if os.IsNotExist(err) {
   488  			log.Log.V(2).Info("EnableRDMA(): RDMA server doesn't exist")
   489  			err = k.InstallRDMA(packageManager)
   490  			if err != nil {
   491  				log.Log.Error(err, "EnableRDMA() failed to install RDMA package")
   492  				return false, err
   493  			}
   494  
   495  			err = k.TriggerUdevEvent()
   496  			if err != nil {
   497  				log.Log.Error(err, "EnableRDMA() failed to trigger udev event")
   498  				return false, err
   499  			}
   500  
   501  			return false, nil
   502  		}
   503  
   504  		log.Log.Error(err, "EnableRDMA() failed to check for os release file", "path", path)
   505  		return false, err
   506  	}
   507  
   508  	log.Log.Info("EnableRDMA(): service installed", "name", serviceName)
   509  	return true, nil
   510  }
   511  
   512  func (k *kernel) InstallRDMA(packageManager string) error {
   513  	log.Log.Info("InstallRDMA(): installing RDMA")
   514  	chrootDefinition := utils.GetChrootExtension()
   515  
   516  	stdout, stderr, err := k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("%s %s install -y rdma-core", chrootDefinition, packageManager))
   517  	if err != nil && len(stderr) != 0 {
   518  		log.Log.Error(err, "InstallRDMA(): failed to install RDMA package", "stdout", stdout, "stderr", stderr)
   519  		return err
   520  	}
   521  
   522  	return nil
   523  }
   524  
   525  func (k *kernel) TriggerUdevEvent() error {
   526  	log.Log.Info("TriggerUdevEvent(): installing RDMA")
   527  
   528  	err := k.ReloadDriver("mlx4_en")
   529  	if err != nil {
   530  		return err
   531  	}
   532  
   533  	err = k.ReloadDriver("mlx5_core")
   534  	if err != nil {
   535  		return err
   536  	}
   537  
   538  	return nil
   539  }
   540  
   541  func (k *kernel) ReloadDriver(driverName string) error {
   542  	log.Log.Info("ReloadDriver(): reload driver", "name", driverName)
   543  	chrootDefinition := utils.GetChrootExtension()
   544  
   545  	_, stderr, err := k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("%s modprobe -r %s && %s modprobe %s", chrootDefinition, driverName, chrootDefinition, driverName))
   546  	if err != nil && len(stderr) != 0 {
   547  		log.Log.Error(err, "ReloadDriver(): failed to reload kernel module",
   548  			"name", driverName, "stderr", stderr)
   549  		return err
   550  	}
   551  
   552  	return nil
   553  }
   554  
   555  func (k *kernel) GetOSPrettyName() (string, error) {
   556  	path := internal.GenericOSReleaseFile
   557  	if !vars.UsingSystemdMode {
   558  		path = filepath.Join(internal.HostPathFromDaemon, path)
   559  	}
   560  
   561  	log.Log.Info("GetOSPrettyName(): getting os name from os-release file")
   562  
   563  	stdout, stderr, err := k.utilsHelper.RunCommand("/bin/sh", "-c", fmt.Sprintf("cat %s | grep PRETTY_NAME | cut -c 13-", path))
   564  	if err != nil && len(stderr) != 0 {
   565  		log.Log.Error(err, "GetOSPrettyName(): failed to check for operating system name in os-release file", "stderr", stderr)
   566  		return "", fmt.Errorf(stderr)
   567  	}
   568  
   569  	if len(stdout) > 0 {
   570  		return stdout, nil
   571  	}
   572  
   573  	return "", fmt.Errorf("failed to find pretty operating system name")
   574  }
   575  
   576  // IsKernelLockdownMode returns true when kernel lockdown mode is enabled
   577  // TODO: change this to return error
   578  func (k *kernel) IsKernelLockdownMode() bool {
   579  	path := utils.GetHostExtension()
   580  	path = filepath.Join(path, "/sys/kernel/security/lockdown")
   581  
   582  	stdout, stderr, err := k.utilsHelper.RunCommand("cat", path)
   583  	log.Log.V(2).Info("IsKernelLockdownMode()", "output", stdout, "error", err)
   584  	if err != nil {
   585  		log.Log.Error(err, "IsKernelLockdownMode(): failed to check for lockdown file", "stderr", stderr)
   586  		return false
   587  	}
   588  	return strings.Contains(stdout, "[integrity]") || strings.Contains(stdout, "[confidentiality]")
   589  }
   590  
   591  // returns driver for device on the bus
   592  func getDriverByBusAndDevice(bus, device string) (string, error) {
   593  	driverLink := filepath.Join(vars.FilesystemRoot, consts.SysBus, bus, "devices", device, "driver")
   594  	driverInfo, err := os.Readlink(driverLink)
   595  	if err != nil {
   596  		if errors.Is(err, os.ErrNotExist) {
   597  			log.Log.V(2).Info("getDriverByBusAndDevice(): driver path for device not exist", "bus", bus, "device", device, "driver", driverInfo)
   598  			return "", nil
   599  		}
   600  		log.Log.Error(err, "getDriverByBusAndDevice(): error getting driver info for device", "bus", bus, "device", device)
   601  		return "", err
   602  	}
   603  	log.Log.V(2).Info("getDriverByBusAndDevice(): driver for device", "bus", bus, "device", device, "driver", driverInfo)
   604  	return filepath.Base(driverInfo), nil
   605  }
   606  
   607  // binds device to the provide driver
   608  func bindDriver(bus, device, driver string) error {
   609  	log.Log.V(2).Info("bindDriver(): bind to driver", "bus", bus, "device", device, "driver", driver)
   610  	bindPath := filepath.Join(vars.FilesystemRoot, consts.SysBus, bus, "drivers", driver, "bind")
   611  	err := os.WriteFile(bindPath, []byte(device), os.ModeAppend)
   612  	if err != nil {
   613  		log.Log.Error(err, "bindDriver(): failed to bind driver", "bus", bus, "device", device, "driver", driver)
   614  		return err
   615  	}
   616  	return nil
   617  }
   618  
   619  // unbind device from the driver
   620  func unbindDriver(bus, device, driver string) error {
   621  	log.Log.V(2).Info("unbindDriver(): unbind from driver", "bus", bus, "device", device, "driver", driver)
   622  	unbindPath := filepath.Join(vars.FilesystemRoot, consts.SysBus, bus, "drivers", driver, "unbind")
   623  	err := os.WriteFile(unbindPath, []byte(device), os.ModeAppend)
   624  	if err != nil {
   625  		log.Log.Error(err, "unbindDriver(): failed to unbind driver", "bus", bus, "device", device, "driver", driver)
   626  		return err
   627  	}
   628  	return nil
   629  }
   630  
   631  // probes driver for device on the bus
   632  func probeDriver(bus, device string) error {
   633  	log.Log.V(2).Info("probeDriver(): drivers probe", "bus", bus, "device", device)
   634  	probePath := filepath.Join(vars.FilesystemRoot, consts.SysBus, bus, "drivers_probe")
   635  	err := os.WriteFile(probePath, []byte(device), os.ModeAppend)
   636  	if err != nil {
   637  		log.Log.Error(err, "probeDriver(): failed to trigger driver probe", "bus", bus, "device", device)
   638  		return err
   639  	}
   640  	return nil
   641  }
   642  
   643  // set driver override for the bus/device,
   644  // resets override if override arg is "",
   645  // if device doesn't support overriding (has no driver_override path), does nothing
   646  func setDriverOverride(bus, device, override string) error {
   647  	driverOverridePath := filepath.Join(vars.FilesystemRoot, consts.SysBus, bus, "devices", device, "driver_override")
   648  	if _, err := os.Stat(driverOverridePath); err != nil {
   649  		if os.IsNotExist(err) {
   650  			log.Log.V(2).Info("setDriverOverride(): device doesn't support driver override, skip", "bus", bus, "device", device)
   651  			return nil
   652  		}
   653  		return err
   654  	}
   655  	var overrideData []byte
   656  	if override != "" {
   657  		log.Log.V(2).Info("setDriverOverride(): configure driver override for device", "bus", bus, "device", device, "driver", override)
   658  		overrideData = []byte(override)
   659  	} else {
   660  		log.Log.V(2).Info("setDriverOverride(): reset driver override for device", "bus", bus, "device", device)
   661  		overrideData = []byte("\x00")
   662  	}
   663  	err := os.WriteFile(driverOverridePath, overrideData, os.ModeAppend)
   664  	if err != nil {
   665  		log.Log.Error(err, "setDriverOverride(): fail to write driver_override for device",
   666  			"bus", bus, "device", device, "driver", override)
   667  		return err
   668  	}
   669  	return nil
   670  }