github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/feature.go (about)

     1  package btf
     2  
     3  import (
     4  	"errors"
     5  	"math"
     6  
     7  	"github.com/cilium/ebpf/internal"
     8  	"github.com/cilium/ebpf/internal/sys"
     9  	"github.com/cilium/ebpf/internal/unix"
    10  )
    11  
    12  // haveBTF attempts to load a BTF blob containing an Int. It should pass on any
    13  // kernel that supports BPF_BTF_LOAD.
    14  var haveBTF = internal.NewFeatureTest("BTF", "4.18", func() error {
    15  	// 0-length anonymous integer
    16  	err := probeBTF(&Int{})
    17  	if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
    18  		return internal.ErrNotSupported
    19  	}
    20  	return err
    21  })
    22  
    23  // haveMapBTF attempts to load a minimal BTF blob containing a Var. It is
    24  // used as a proxy for .bss, .data and .rodata map support, which generally
    25  // come with a Var and Datasec. These were introduced in Linux 5.2.
    26  var haveMapBTF = internal.NewFeatureTest("Map BTF (Var/Datasec)", "5.2", func() error {
    27  	if err := haveBTF(); err != nil {
    28  		return err
    29  	}
    30  
    31  	v := &Var{
    32  		Name: "a",
    33  		Type: &Pointer{(*Void)(nil)},
    34  	}
    35  
    36  	err := probeBTF(v)
    37  	if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
    38  		// Treat both EINVAL and EPERM as not supported: creating the map may still
    39  		// succeed without Btf* attrs.
    40  		return internal.ErrNotSupported
    41  	}
    42  	return err
    43  })
    44  
    45  // haveProgBTF attempts to load a BTF blob containing a Func and FuncProto. It
    46  // is used as a proxy for ext_info (func_info) support, which depends on
    47  // Func(Proto) by definition.
    48  var haveProgBTF = internal.NewFeatureTest("Program BTF (func/line_info)", "5.0", func() error {
    49  	if err := haveBTF(); err != nil {
    50  		return err
    51  	}
    52  
    53  	fn := &Func{
    54  		Name: "a",
    55  		Type: &FuncProto{Return: (*Void)(nil)},
    56  	}
    57  
    58  	err := probeBTF(fn)
    59  	if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
    60  		return internal.ErrNotSupported
    61  	}
    62  	return err
    63  })
    64  
    65  var haveFuncLinkage = internal.NewFeatureTest("BTF func linkage", "5.6", func() error {
    66  	if err := haveProgBTF(); err != nil {
    67  		return err
    68  	}
    69  
    70  	fn := &Func{
    71  		Name:    "a",
    72  		Type:    &FuncProto{Return: (*Void)(nil)},
    73  		Linkage: GlobalFunc,
    74  	}
    75  
    76  	err := probeBTF(fn)
    77  	if errors.Is(err, unix.EINVAL) {
    78  		return internal.ErrNotSupported
    79  	}
    80  	return err
    81  })
    82  
    83  var haveEnum64 = internal.NewFeatureTest("ENUM64", "6.0", func() error {
    84  	if err := haveBTF(); err != nil {
    85  		return err
    86  	}
    87  
    88  	enum := &Enum{
    89  		Size: 8,
    90  		Values: []EnumValue{
    91  			{"TEST", math.MaxUint32 + 1},
    92  		},
    93  	}
    94  
    95  	err := probeBTF(enum)
    96  	if errors.Is(err, unix.EINVAL) {
    97  		return internal.ErrNotSupported
    98  	}
    99  	return err
   100  })
   101  
   102  func probeBTF(typ Type) error {
   103  	b, err := NewBuilder([]Type{typ})
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	buf, err := b.Marshal(nil, nil)
   109  	if err != nil {
   110  		return err
   111  	}
   112  
   113  	fd, err := sys.BtfLoad(&sys.BtfLoadAttr{
   114  		Btf:     sys.NewSlicePointer(buf),
   115  		BtfSize: uint32(len(buf)),
   116  	})
   117  
   118  	if err == nil {
   119  		fd.Close()
   120  	}
   121  
   122  	return err
   123  }