123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- package ebpf
- import (
- "bytes"
- "errors"
- "fmt"
- "github.com/cilium/ebpf/asm"
- "github.com/cilium/ebpf/internal"
- "github.com/cilium/ebpf/internal/sys"
- "github.com/cilium/ebpf/internal/unix"
- )
- // invalidBPFObjNameChar returns true if char may not appear in
- // a BPF object name.
- func invalidBPFObjNameChar(char rune) bool {
- dotAllowed := objNameAllowsDot() == nil
- switch {
- case char >= 'A' && char <= 'Z':
- return false
- case char >= 'a' && char <= 'z':
- return false
- case char >= '0' && char <= '9':
- return false
- case dotAllowed && char == '.':
- return false
- case char == '_':
- return false
- default:
- return true
- }
- }
- func progLoad(insns asm.Instructions, typ ProgramType, license string) (*sys.FD, error) {
- buf := bytes.NewBuffer(make([]byte, 0, insns.Size()))
- if err := insns.Marshal(buf, internal.NativeEndian); err != nil {
- return nil, err
- }
- bytecode := buf.Bytes()
- return sys.ProgLoad(&sys.ProgLoadAttr{
- ProgType: sys.ProgType(typ),
- License: sys.NewStringPointer(license),
- Insns: sys.NewSlicePointer(bytecode),
- InsnCnt: uint32(len(bytecode) / asm.InstructionSize),
- })
- }
- var haveNestedMaps = internal.FeatureTest("nested maps", "4.12", func() error {
- _, err := sys.MapCreate(&sys.MapCreateAttr{
- MapType: sys.MapType(ArrayOfMaps),
- KeySize: 4,
- ValueSize: 4,
- MaxEntries: 1,
- // Invalid file descriptor.
- InnerMapFd: ^uint32(0),
- })
- if errors.Is(err, unix.EINVAL) {
- return internal.ErrNotSupported
- }
- if errors.Is(err, unix.EBADF) {
- return nil
- }
- return err
- })
- var haveMapMutabilityModifiers = internal.FeatureTest("read- and write-only maps", "5.2", func() error {
- // This checks BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG. Since
- // BPF_MAP_FREEZE appeared in 5.2 as well we don't do a separate check.
- m, err := sys.MapCreate(&sys.MapCreateAttr{
- MapType: sys.MapType(Array),
- KeySize: 4,
- ValueSize: 4,
- MaxEntries: 1,
- MapFlags: unix.BPF_F_RDONLY_PROG,
- })
- if err != nil {
- return internal.ErrNotSupported
- }
- _ = m.Close()
- return nil
- })
- var haveMmapableMaps = internal.FeatureTest("mmapable maps", "5.5", func() error {
- // This checks BPF_F_MMAPABLE, which appeared in 5.5 for array maps.
- m, err := sys.MapCreate(&sys.MapCreateAttr{
- MapType: sys.MapType(Array),
- KeySize: 4,
- ValueSize: 4,
- MaxEntries: 1,
- MapFlags: unix.BPF_F_MMAPABLE,
- })
- if err != nil {
- return internal.ErrNotSupported
- }
- _ = m.Close()
- return nil
- })
- var haveInnerMaps = internal.FeatureTest("inner maps", "5.10", func() error {
- // This checks BPF_F_INNER_MAP, which appeared in 5.10.
- m, err := sys.MapCreate(&sys.MapCreateAttr{
- MapType: sys.MapType(Array),
- KeySize: 4,
- ValueSize: 4,
- MaxEntries: 1,
- MapFlags: unix.BPF_F_INNER_MAP,
- })
- if err != nil {
- return internal.ErrNotSupported
- }
- _ = m.Close()
- return nil
- })
- var haveNoPreallocMaps = internal.FeatureTest("prealloc maps", "4.6", func() error {
- // This checks BPF_F_NO_PREALLOC, which appeared in 4.6.
- m, err := sys.MapCreate(&sys.MapCreateAttr{
- MapType: sys.MapType(Hash),
- KeySize: 4,
- ValueSize: 4,
- MaxEntries: 1,
- MapFlags: unix.BPF_F_NO_PREALLOC,
- })
- if err != nil {
- return internal.ErrNotSupported
- }
- _ = m.Close()
- return nil
- })
- func wrapMapError(err error) error {
- if err == nil {
- return nil
- }
- if errors.Is(err, unix.ENOENT) {
- return sys.Error(ErrKeyNotExist, unix.ENOENT)
- }
- if errors.Is(err, unix.EEXIST) {
- return sys.Error(ErrKeyExist, unix.EEXIST)
- }
- if errors.Is(err, unix.ENOTSUPP) {
- return sys.Error(ErrNotSupported, unix.ENOTSUPP)
- }
- if errors.Is(err, unix.E2BIG) {
- return fmt.Errorf("key too big for map: %w", err)
- }
- return err
- }
- var haveObjName = internal.FeatureTest("object names", "4.15", func() error {
- attr := sys.MapCreateAttr{
- MapType: sys.MapType(Array),
- KeySize: 4,
- ValueSize: 4,
- MaxEntries: 1,
- MapName: sys.NewObjName("feature_test"),
- }
- fd, err := sys.MapCreate(&attr)
- if err != nil {
- return internal.ErrNotSupported
- }
- _ = fd.Close()
- return nil
- })
- var objNameAllowsDot = internal.FeatureTest("dot in object names", "5.2", func() error {
- if err := haveObjName(); err != nil {
- return err
- }
- attr := sys.MapCreateAttr{
- MapType: sys.MapType(Array),
- KeySize: 4,
- ValueSize: 4,
- MaxEntries: 1,
- MapName: sys.NewObjName(".test"),
- }
- fd, err := sys.MapCreate(&attr)
- if err != nil {
- return internal.ErrNotSupported
- }
- _ = fd.Close()
- return nil
- })
- var haveBatchAPI = internal.FeatureTest("map batch api", "5.6", func() error {
- var maxEntries uint32 = 2
- attr := sys.MapCreateAttr{
- MapType: sys.MapType(Hash),
- KeySize: 4,
- ValueSize: 4,
- MaxEntries: maxEntries,
- }
- fd, err := sys.MapCreate(&attr)
- if err != nil {
- return internal.ErrNotSupported
- }
- defer fd.Close()
- keys := []uint32{1, 2}
- values := []uint32{3, 4}
- kp, _ := marshalPtr(keys, 8)
- vp, _ := marshalPtr(values, 8)
- err = sys.MapUpdateBatch(&sys.MapUpdateBatchAttr{
- MapFd: fd.Uint(),
- Keys: kp,
- Values: vp,
- Count: maxEntries,
- })
- if err != nil {
- return internal.ErrNotSupported
- }
- return nil
- })
- var haveProbeReadKernel = internal.FeatureTest("bpf_probe_read_kernel", "5.5", func() error {
- insns := asm.Instructions{
- asm.Mov.Reg(asm.R1, asm.R10),
- asm.Add.Imm(asm.R1, -8),
- asm.Mov.Imm(asm.R2, 8),
- asm.Mov.Imm(asm.R3, 0),
- asm.FnProbeReadKernel.Call(),
- asm.Return(),
- }
- fd, err := progLoad(insns, Kprobe, "GPL")
- if err != nil {
- return internal.ErrNotSupported
- }
- _ = fd.Close()
- return nil
- })
- var haveBPFToBPFCalls = internal.FeatureTest("bpf2bpf calls", "4.16", func() error {
- insns := asm.Instructions{
- asm.Call.Label("prog2").WithSymbol("prog1"),
- asm.Return(),
- asm.Mov.Imm(asm.R0, 0).WithSymbol("prog2"),
- asm.Return(),
- }
- fd, err := progLoad(insns, SocketFilter, "MIT")
- if errors.Is(err, unix.EINVAL) {
- return internal.ErrNotSupported
- }
- if err != nil {
- return err
- }
- _ = fd.Close()
- return nil
- })
|