| package link |
| |
| import ( |
| "errors" |
| |
| "github.com/cilium/ebpf" |
| "github.com/cilium/ebpf/asm" |
| "github.com/cilium/ebpf/internal" |
| "github.com/cilium/ebpf/internal/sys" |
| "github.com/cilium/ebpf/internal/unix" |
| ) |
| |
| // Type is the kind of link. |
| type Type = sys.LinkType |
| |
| // Valid link types. |
| const ( |
| UnspecifiedType = sys.BPF_LINK_TYPE_UNSPEC |
| RawTracepointType = sys.BPF_LINK_TYPE_RAW_TRACEPOINT |
| TracingType = sys.BPF_LINK_TYPE_TRACING |
| CgroupType = sys.BPF_LINK_TYPE_CGROUP |
| IterType = sys.BPF_LINK_TYPE_ITER |
| NetNsType = sys.BPF_LINK_TYPE_NETNS |
| XDPType = sys.BPF_LINK_TYPE_XDP |
| PerfEventType = sys.BPF_LINK_TYPE_PERF_EVENT |
| KprobeMultiType = sys.BPF_LINK_TYPE_KPROBE_MULTI |
| ) |
| |
| var haveProgAttach = internal.NewFeatureTest("BPF_PROG_ATTACH", "4.10", func() error { |
| prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ |
| Type: ebpf.CGroupSKB, |
| License: "MIT", |
| Instructions: asm.Instructions{ |
| asm.Mov.Imm(asm.R0, 0), |
| asm.Return(), |
| }, |
| }) |
| if err != nil { |
| return internal.ErrNotSupported |
| } |
| |
| // BPF_PROG_ATTACH was introduced at the same time as CGgroupSKB, |
| // so being able to load the program is enough to infer that we |
| // have the syscall. |
| prog.Close() |
| return nil |
| }) |
| |
| var haveProgAttachReplace = internal.NewFeatureTest("BPF_PROG_ATTACH atomic replacement of MULTI progs", "5.5", func() error { |
| if err := haveProgAttach(); err != nil { |
| return err |
| } |
| |
| prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ |
| Type: ebpf.CGroupSKB, |
| AttachType: ebpf.AttachCGroupInetIngress, |
| License: "MIT", |
| Instructions: asm.Instructions{ |
| asm.Mov.Imm(asm.R0, 0), |
| asm.Return(), |
| }, |
| }) |
| if err != nil { |
| return internal.ErrNotSupported |
| } |
| defer prog.Close() |
| |
| // We know that we have BPF_PROG_ATTACH since we can load CGroupSKB programs. |
| // If passing BPF_F_REPLACE gives us EINVAL we know that the feature isn't |
| // present. |
| attr := sys.ProgAttachAttr{ |
| // We rely on this being checked after attachFlags. |
| TargetFd: ^uint32(0), |
| AttachBpfFd: uint32(prog.FD()), |
| AttachType: uint32(ebpf.AttachCGroupInetIngress), |
| AttachFlags: uint32(flagReplace), |
| } |
| |
| err = sys.ProgAttach(&attr) |
| if errors.Is(err, unix.EINVAL) { |
| return internal.ErrNotSupported |
| } |
| if errors.Is(err, unix.EBADF) { |
| return nil |
| } |
| return err |
| }) |
| |
| var haveBPFLink = internal.NewFeatureTest("bpf_link", "5.7", func() error { |
| attr := sys.LinkCreateAttr{ |
| // This is a hopefully invalid file descriptor, which triggers EBADF. |
| TargetFd: ^uint32(0), |
| ProgFd: ^uint32(0), |
| AttachType: sys.AttachType(ebpf.AttachCGroupInetIngress), |
| } |
| _, err := sys.LinkCreate(&attr) |
| if errors.Is(err, unix.EINVAL) { |
| return internal.ErrNotSupported |
| } |
| if errors.Is(err, unix.EBADF) { |
| return nil |
| } |
| return err |
| }) |
| |
| var haveProgQuery = internal.NewFeatureTest("BPF_PROG_QUERY", "4.15", func() error { |
| attr := sys.ProgQueryAttr{ |
| // We rely on this being checked during the syscall. |
| // With an otherwise correct payload we expect EBADF here |
| // as an indication that the feature is present. |
| TargetFd: ^uint32(0), |
| AttachType: sys.AttachType(ebpf.AttachCGroupInetIngress), |
| } |
| |
| err := sys.ProgQuery(&attr) |
| if errors.Is(err, unix.EINVAL) { |
| return internal.ErrNotSupported |
| } |
| if errors.Is(err, unix.EBADF) { |
| return nil |
| } |
| return err |
| }) |