github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/internal/version.go (about) 1 package internal 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/cilium/ebpf/internal/unix" 8 ) 9 10 const ( 11 // Version constant used in ELF binaries indicating that the loader needs to 12 // substitute the eBPF program's version with the value of the kernel's 13 // KERNEL_VERSION compile-time macro. Used for compatibility with BCC, gobpf 14 // and RedSift. 15 MagicKernelVersion = 0xFFFFFFFE 16 ) 17 18 // A Version in the form Major.Minor.Patch. 19 type Version [3]uint16 20 21 // NewVersion creates a version from a string like "Major.Minor.Patch". 22 // 23 // Patch is optional. 24 func NewVersion(ver string) (Version, error) { 25 var major, minor, patch uint16 26 n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch) 27 if n < 2 { 28 return Version{}, fmt.Errorf("invalid version: %s", ver) 29 } 30 return Version{major, minor, patch}, nil 31 } 32 33 // NewVersionFromCode creates a version from a LINUX_VERSION_CODE. 34 func NewVersionFromCode(code uint32) Version { 35 return Version{ 36 uint16(uint8(code >> 16)), 37 uint16(uint8(code >> 8)), 38 uint16(uint8(code)), 39 } 40 } 41 42 func (v Version) String() string { 43 if v[2] == 0 { 44 return fmt.Sprintf("v%d.%d", v[0], v[1]) 45 } 46 return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2]) 47 } 48 49 // Less returns true if the version is less than another version. 50 func (v Version) Less(other Version) bool { 51 for i, a := range v { 52 if a == other[i] { 53 continue 54 } 55 return a < other[i] 56 } 57 return false 58 } 59 60 // Unspecified returns true if the version is all zero. 61 func (v Version) Unspecified() bool { 62 return v[0] == 0 && v[1] == 0 && v[2] == 0 63 } 64 65 // Kernel implements the kernel's KERNEL_VERSION macro from linux/version.h. 66 // It represents the kernel version and patch level as a single value. 67 func (v Version) Kernel() uint32 { 68 69 // Kernels 4.4 and 4.9 have their SUBLEVEL clamped to 255 to avoid 70 // overflowing into PATCHLEVEL. 71 // See kernel commit 9b82f13e7ef3 ("kbuild: clamp SUBLEVEL to 255"). 72 s := v[2] 73 if s > 255 { 74 s = 255 75 } 76 77 // Truncate members to uint8 to prevent them from spilling over into 78 // each other when overflowing 8 bits. 79 return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s)) 80 } 81 82 // KernelVersion returns the version of the currently running kernel. 83 var KernelVersion = sync.OnceValues(func() (Version, error) { 84 return detectKernelVersion() 85 }) 86 87 // detectKernelVersion returns the version of the running kernel. 88 func detectKernelVersion() (Version, error) { 89 vc, err := vdsoVersion() 90 if err != nil { 91 return Version{}, err 92 } 93 return NewVersionFromCode(vc), nil 94 } 95 96 // KernelRelease returns the release string of the running kernel. 97 // Its format depends on the Linux distribution and corresponds to directory 98 // names in /lib/modules by convention. Some examples are 5.15.17-1-lts and 99 // 4.19.0-16-amd64. 100 func KernelRelease() (string, error) { 101 var uname unix.Utsname 102 if err := unix.Uname(&uname); err != nil { 103 return "", fmt.Errorf("uname failed: %w", err) 104 } 105 106 return unix.ByteSliceToString(uname.Release[:]), nil 107 }