...

Source file src/github.com/cilium/ebpf/syscalls.go

Documentation: github.com/cilium/ebpf

     1  package ebpf
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"github.com/cilium/ebpf/asm"
     9  	"github.com/cilium/ebpf/internal"
    10  	"github.com/cilium/ebpf/internal/sys"
    11  	"github.com/cilium/ebpf/internal/unix"
    12  )
    13  
    14  // invalidBPFObjNameChar returns true if char may not appear in
    15  // a BPF object name.
    16  func invalidBPFObjNameChar(char rune) bool {
    17  	dotAllowed := objNameAllowsDot() == nil
    18  
    19  	switch {
    20  	case char >= 'A' && char <= 'Z':
    21  		return false
    22  	case char >= 'a' && char <= 'z':
    23  		return false
    24  	case char >= '0' && char <= '9':
    25  		return false
    26  	case dotAllowed && char == '.':
    27  		return false
    28  	case char == '_':
    29  		return false
    30  	default:
    31  		return true
    32  	}
    33  }
    34  
    35  func progLoad(insns asm.Instructions, typ ProgramType, license string) (*sys.FD, error) {
    36  	buf := bytes.NewBuffer(make([]byte, 0, insns.Size()))
    37  	if err := insns.Marshal(buf, internal.NativeEndian); err != nil {
    38  		return nil, err
    39  	}
    40  	bytecode := buf.Bytes()
    41  
    42  	return sys.ProgLoad(&sys.ProgLoadAttr{
    43  		ProgType: sys.ProgType(typ),
    44  		License:  sys.NewStringPointer(license),
    45  		Insns:    sys.NewSlicePointer(bytecode),
    46  		InsnCnt:  uint32(len(bytecode) / asm.InstructionSize),
    47  	})
    48  }
    49  
    50  var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() error {
    51  	_, err := sys.MapCreate(&sys.MapCreateAttr{
    52  		MapType:    sys.MapType(ArrayOfMaps),
    53  		KeySize:    4,
    54  		ValueSize:  4,
    55  		MaxEntries: 1,
    56  		// Invalid file descriptor.
    57  		InnerMapFd: ^uint32(0),
    58  	})
    59  	if errors.Is(err, unix.EINVAL) {
    60  		return internal.ErrNotSupported
    61  	}
    62  	if errors.Is(err, unix.EBADF) {
    63  		return nil
    64  	}
    65  	return err
    66  })
    67  
    68  var haveMapMutabilityModifiers = internal.FeatureTest("read- and write-only maps", "5.2", func() error {
    69  	// This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since
    70  	// BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check.
    71  	m, err := sys.MapCreate(&sys.MapCreateAttr{
    72  		MapType:    sys.MapType(Array),
    73  		KeySize:    4,
    74  		ValueSize:  4,
    75  		MaxEntries: 1,
    76  		MapFlags:   unix.BPF_F_RDONLY_PROG,
    77  	})
    78  	if err != nil {
    79  		return internal.ErrNotSupported
    80  	}
    81  	_ = m.Close()
    82  	return nil
    83  })
    84  
    85  var haveMmapableMaps = internal.FeatureTest("mmapable maps", "5.5", func() error {
    86  	// This checks BPF_F_MMAPABLE, which appeared in 5.5 for array maps.
    87  	m, err := sys.MapCreate(&sys.MapCreateAttr{
    88  		MapType:    sys.MapType(Array),
    89  		KeySize:    4,
    90  		ValueSize:  4,
    91  		MaxEntries: 1,
    92  		MapFlags:   unix.BPF_F_MMAPABLE,
    93  	})
    94  	if err != nil {
    95  		return internal.ErrNotSupported
    96  	}
    97  	_ = m.Close()
    98  	return nil
    99  })
   100  
   101  var haveInnerMaps = internal.FeatureTest("inner maps", "5.10", func() error {
   102  	// This checks BPF_F_INNER_MAP, which appeared in 5.10.
   103  	m, err := sys.MapCreate(&sys.MapCreateAttr{
   104  		MapType:    sys.MapType(Array),
   105  		KeySize:    4,
   106  		ValueSize:  4,
   107  		MaxEntries: 1,
   108  		MapFlags:   unix.BPF_F_INNER_MAP,
   109  	})
   110  	if err != nil {
   111  		return internal.ErrNotSupported
   112  	}
   113  	_ = m.Close()
   114  	return nil
   115  })
   116  
   117  var haveNoPreallocMaps = internal.FeatureTest("prealloc maps", "4.6", func() error {
   118  	// This checks BPF_F_NO_PREALLOC, which appeared in 4.6.
   119  	m, err := sys.MapCreate(&sys.MapCreateAttr{
   120  		MapType:    sys.MapType(Hash),
   121  		KeySize:    4,
   122  		ValueSize:  4,
   123  		MaxEntries: 1,
   124  		MapFlags:   unix.BPF_F_NO_PREALLOC,
   125  	})
   126  	if err != nil {
   127  		return internal.ErrNotSupported
   128  	}
   129  	_ = m.Close()
   130  	return nil
   131  })
   132  
   133  func wrapMapError(err error) error {
   134  	if err == nil {
   135  		return nil
   136  	}
   137  
   138  	if errors.Is(err, unix.ENOENT) {
   139  		return sys.Error(ErrKeyNotExist, unix.ENOENT)
   140  	}
   141  
   142  	if errors.Is(err, unix.EEXIST) {
   143  		return sys.Error(ErrKeyExist, unix.EEXIST)
   144  	}
   145  
   146  	if errors.Is(err, unix.ENOTSUPP) {
   147  		return sys.Error(ErrNotSupported, unix.ENOTSUPP)
   148  	}
   149  
   150  	if errors.Is(err, unix.E2BIG) {
   151  		return fmt.Errorf("key too big for map: %w", err)
   152  	}
   153  
   154  	return err
   155  }
   156  
   157  var haveObjName = internal.FeatureTest("object names", "4.15", func() error {
   158  	attr := sys.MapCreateAttr{
   159  		MapType:    sys.MapType(Array),
   160  		KeySize:    4,
   161  		ValueSize:  4,
   162  		MaxEntries: 1,
   163  		MapName:    sys.NewObjName("feature_test"),
   164  	}
   165  
   166  	fd, err := sys.MapCreate(&attr)
   167  	if err != nil {
   168  		return internal.ErrNotSupported
   169  	}
   170  
   171  	_ = fd.Close()
   172  	return nil
   173  })
   174  
   175  var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func() error {
   176  	if err := haveObjName(); err != nil {
   177  		return err
   178  	}
   179  
   180  	attr := sys.MapCreateAttr{
   181  		MapType:    sys.MapType(Array),
   182  		KeySize:    4,
   183  		ValueSize:  4,
   184  		MaxEntries: 1,
   185  		MapName:    sys.NewObjName(".test"),
   186  	}
   187  
   188  	fd, err := sys.MapCreate(&attr)
   189  	if err != nil {
   190  		return internal.ErrNotSupported
   191  	}
   192  
   193  	_ = fd.Close()
   194  	return nil
   195  })
   196  
   197  var haveBatchAPI = internal.FeatureTest("map batch api", "5.6", func() error {
   198  	var maxEntries uint32 = 2
   199  	attr := sys.MapCreateAttr{
   200  		MapType:    sys.MapType(Hash),
   201  		KeySize:    4,
   202  		ValueSize:  4,
   203  		MaxEntries: maxEntries,
   204  	}
   205  
   206  	fd, err := sys.MapCreate(&attr)
   207  	if err != nil {
   208  		return internal.ErrNotSupported
   209  	}
   210  	defer fd.Close()
   211  
   212  	keys := []uint32{1, 2}
   213  	values := []uint32{3, 4}
   214  	kp, _ := marshalPtr(keys, 8)
   215  	vp, _ := marshalPtr(values, 8)
   216  
   217  	err = sys.MapUpdateBatch(&sys.MapUpdateBatchAttr{
   218  		MapFd:  fd.Uint(),
   219  		Keys:   kp,
   220  		Values: vp,
   221  		Count:  maxEntries,
   222  	})
   223  	if err != nil {
   224  		return internal.ErrNotSupported
   225  	}
   226  	return nil
   227  })
   228  
   229  var haveProbeReadKernel = internal.FeatureTest("bpf_probe_read_kernel", "5.5", func() error {
   230  	insns := asm.Instructions{
   231  		asm.Mov.Reg(asm.R1, asm.R10),
   232  		asm.Add.Imm(asm.R1, -8),
   233  		asm.Mov.Imm(asm.R2, 8),
   234  		asm.Mov.Imm(asm.R3, 0),
   235  		asm.FnProbeReadKernel.Call(),
   236  		asm.Return(),
   237  	}
   238  
   239  	fd, err := progLoad(insns, Kprobe, "GPL")
   240  	if err != nil {
   241  		return internal.ErrNotSupported
   242  	}
   243  	_ = fd.Close()
   244  	return nil
   245  })
   246  
   247  var haveBPFToBPFCalls = internal.FeatureTest("bpf2bpf calls", "4.16", func() error {
   248  	insns := asm.Instructions{
   249  		asm.Call.Label("prog2").WithSymbol("prog1"),
   250  		asm.Return(),
   251  		asm.Mov.Imm(asm.R0, 0).WithSymbol("prog2"),
   252  		asm.Return(),
   253  	}
   254  
   255  	fd, err := progLoad(insns, SocketFilter, "MIT")
   256  	if errors.Is(err, unix.EINVAL) {
   257  		return internal.ErrNotSupported
   258  	}
   259  	if err != nil {
   260  		return err
   261  	}
   262  	_ = fd.Close()
   263  	return nil
   264  })
   265  

View as plain text