...

Source file src/github.com/cilium/ebpf/internal/version.go

Documentation: github.com/cilium/ebpf/internal

     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  var (
    19  	kernelVersion = struct {
    20  		once    sync.Once
    21  		version Version
    22  		err     error
    23  	}{}
    24  )
    25  
    26  // A Version in the form Major.Minor.Patch.
    27  type Version [3]uint16
    28  
    29  // NewVersion creates a version from a string like "Major.Minor.Patch".
    30  //
    31  // Patch is optional.
    32  func NewVersion(ver string) (Version, error) {
    33  	var major, minor, patch uint16
    34  	n, _ := fmt.Sscanf(ver, "%d.%d.%d", &major, &minor, &patch)
    35  	if n < 2 {
    36  		return Version{}, fmt.Errorf("invalid version: %s", ver)
    37  	}
    38  	return Version{major, minor, patch}, nil
    39  }
    40  
    41  // NewVersionFromCode creates a version from a LINUX_VERSION_CODE.
    42  func NewVersionFromCode(code uint32) Version {
    43  	return Version{
    44  		uint16(uint8(code >> 16)),
    45  		uint16(uint8(code >> 8)),
    46  		uint16(uint8(code)),
    47  	}
    48  }
    49  
    50  func (v Version) String() string {
    51  	if v[2] == 0 {
    52  		return fmt.Sprintf("v%d.%d", v[0], v[1])
    53  	}
    54  	return fmt.Sprintf("v%d.%d.%d", v[0], v[1], v[2])
    55  }
    56  
    57  // Less returns true if the version is less than another version.
    58  func (v Version) Less(other Version) bool {
    59  	for i, a := range v {
    60  		if a == other[i] {
    61  			continue
    62  		}
    63  		return a < other[i]
    64  	}
    65  	return false
    66  }
    67  
    68  // Unspecified returns true if the version is all zero.
    69  func (v Version) Unspecified() bool {
    70  	return v[0] == 0 && v[1] == 0 && v[2] == 0
    71  }
    72  
    73  // Kernel implements the kernel's KERNEL_VERSION macro from linux/version.h.
    74  // It represents the kernel version and patch level as a single value.
    75  func (v Version) Kernel() uint32 {
    76  
    77  	// Kernels 4.4 and 4.9 have their SUBLEVEL clamped to 255 to avoid
    78  	// overflowing into PATCHLEVEL.
    79  	// See kernel commit 9b82f13e7ef3 ("kbuild: clamp SUBLEVEL to 255").
    80  	s := v[2]
    81  	if s > 255 {
    82  		s = 255
    83  	}
    84  
    85  	// Truncate members to uint8 to prevent them from spilling over into
    86  	// each other when overflowing 8 bits.
    87  	return uint32(uint8(v[0]))<<16 | uint32(uint8(v[1]))<<8 | uint32(uint8(s))
    88  }
    89  
    90  // KernelVersion returns the version of the currently running kernel.
    91  func KernelVersion() (Version, error) {
    92  	kernelVersion.once.Do(func() {
    93  		kernelVersion.version, kernelVersion.err = detectKernelVersion()
    94  	})
    95  
    96  	if kernelVersion.err != nil {
    97  		return Version{}, kernelVersion.err
    98  	}
    99  	return kernelVersion.version, nil
   100  }
   101  
   102  // detectKernelVersion returns the version of the running kernel.
   103  func detectKernelVersion() (Version, error) {
   104  	vc, err := vdsoVersion()
   105  	if err != nil {
   106  		return Version{}, err
   107  	}
   108  	return NewVersionFromCode(vc), nil
   109  }
   110  
   111  // KernelRelease returns the release string of the running kernel.
   112  // Its format depends on the Linux distribution and corresponds to directory
   113  // names in /lib/modules by convention. Some examples are 5.15.17-1-lts and
   114  // 4.19.0-16-amd64.
   115  func KernelRelease() (string, error) {
   116  	var uname unix.Utsname
   117  	if err := unix.Uname(&uname); err != nil {
   118  		return "", fmt.Errorf("uname failed: %w", err)
   119  	}
   120  
   121  	return unix.ByteSliceToString(uname.Release[:]), nil
   122  }
   123  

View as plain text