github.com/cilium/cilium@v1.16.2/pkg/datapath/linux/modules/modules_linux.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package modules 5 6 import ( 7 "bufio" 8 "errors" 9 "fmt" 10 "io" 11 "os" 12 "path/filepath" 13 "strings" 14 15 linux "golang.org/x/sys/unix" 16 ) 17 18 const ( 19 loadedModulesFilepath = "/proc/modules" 20 ) 21 22 func moduleLoader() string { 23 return "modprobe" 24 } 25 26 // kernelRelease returns the release string of the running kernel. 27 // Its format depends on the Linux distribution and corresponds to directory 28 // names in /lib/modules by convention. Some examples are 5.15.17-1-lts and 29 // 4.19.0-16-amd64. 30 // Note: copied from /vendor/github.com/cilium/ebpf/internal/version.go 31 func kernelRelease() (string, error) { 32 var uname linux.Utsname 33 if err := linux.Uname(&uname); err != nil { 34 return "", fmt.Errorf("uname failed: %w", err) 35 } 36 37 return linux.ByteSliceToString(uname.Release[:]), nil 38 } 39 40 // parseLoadedModulesFile returns the list of loaded kernel modules names. 41 func parseLoadedModulesFile(r io.Reader) ([]string, error) { 42 var result []string 43 44 scanner := bufio.NewScanner(r) 45 scanner.Split(bufio.ScanLines) 46 47 for scanner.Scan() { 48 moduleInfoRaw := scanner.Text() 49 moduleInfoSeparated := strings.Split(moduleInfoRaw, " ") 50 if len(moduleInfoSeparated) < 6 { 51 return nil, fmt.Errorf( 52 "invalid module info - it has %d fields (less than 6): %s", 53 len(moduleInfoSeparated), moduleInfoRaw) 54 } 55 56 result = append(result, moduleInfoSeparated[0]) 57 } 58 59 if err := scanner.Err(); err != nil { 60 return nil, err 61 } 62 63 return result, nil 64 } 65 66 // parseBuiltinModulesFile returns the list of builtin kernel modules names. 67 func parseBuiltinModulesFile(r io.Reader) ([]string, error) { 68 var result []string 69 70 scanner := bufio.NewScanner(r) 71 scanner.Split(bufio.ScanLines) 72 73 for scanner.Scan() { 74 modulePathRaw := scanner.Text() 75 moduleFileName := filepath.Base(modulePathRaw) 76 moduleFileExt := filepath.Ext(modulePathRaw) 77 moduleName := strings.TrimSuffix(moduleFileName, moduleFileExt) 78 result = append(result, moduleName) 79 } 80 81 if err := scanner.Err(); err != nil { 82 return nil, err 83 } 84 85 return result, nil 86 } 87 88 // listLoadedModules returns the parsed list of loaded kernel modules names. 89 func listLoadedModules() ([]string, error) { 90 fModules, err := os.Open(loadedModulesFilepath) 91 if err != nil { 92 return nil, fmt.Errorf( 93 "failed to open loaded modules information at %s: %w", 94 loadedModulesFilepath, err) 95 } 96 defer fModules.Close() 97 return parseLoadedModulesFile(fModules) 98 } 99 100 // listBuiltinModules returns the parsed list of builtin kernel modules names. 101 func listBuiltinModules() ([]string, error) { 102 var result []string 103 104 locations := []string{ 105 "/lib/modules/%s/modules.builtin", 106 "/usr/lib/modules/%s/modules.builtin", 107 "/usr/lib/debug/lib/modules/%s/modules.builtin", 108 } 109 110 release, err := kernelRelease() 111 if err != nil { 112 return nil, err 113 } 114 115 for _, location := range locations { 116 fModulePath := fmt.Sprintf(location, release) 117 118 fModules, err := os.Open(fModulePath) 119 if errors.Is(err, os.ErrNotExist) { 120 continue 121 } 122 123 if err != nil { 124 return nil, fmt.Errorf( 125 "failed to open builtin modules information at %s: %w", 126 fModulePath, err) 127 } 128 129 defer fModules.Close() 130 131 result, err = parseBuiltinModulesFile(fModules) 132 if err != nil { 133 return nil, err 134 } 135 136 break 137 } 138 139 return result, nil 140 } 141 142 // listModules returns the list of loaded kernel modules names parsed from 143 // /proc/modules and from /lib/modules/<version>/modules.builtin. 144 func listModules() ([]string, error) { 145 loadedModules, err := listLoadedModules() 146 if err != nil { 147 return nil, fmt.Errorf("failed to retrieve loaded modules names: %w", err) 148 } 149 150 builtinModules, err := listBuiltinModules() 151 if err != nil { 152 return nil, fmt.Errorf("failed to retrieve builtin modules names: %w", err) 153 } 154 155 return append(loadedModules, builtinModules...), nil 156 }