summaryrefslogtreecommitdiff
path: root/vendor/github.com/cilium/ebpf/link
diff options
context:
space:
mode:
authorLibravatar Daniele Sluijters <daenney@users.noreply.github.com>2023-01-17 21:59:04 +0100
committerLibravatar GitHub <noreply@github.com>2023-01-17 20:59:04 +0000
commitacc333c40bcf45fb78a0701596a99e93800fe566 (patch)
treec2e236ce1bb6e9871c97a01dde9b22b26fa28742 /vendor/github.com/cilium/ebpf/link
parent[feature] Tune sqlite pragmas (#1349) (diff)
downloadgotosocial-acc333c40bcf45fb78a0701596a99e93800fe566.tar.xz
[feature] Inherit resource limits from cgroups (#1336)
When GTS is running in a container runtime which has configured CPU or memory limits or under an init system that uses cgroups to impose CPU and memory limits the values the Go runtime sees for GOMAXPROCS and GOMEMLIMIT are still based on the host resources, not the cgroup. At least for the throttling middlewares which use GOMAXPROCS to configure their queue size, this can result in GTS running with values too big compared to the resources that will actuall be available to it. This introduces 2 dependencies which can pick up resource contraints from the current cgroup and tune the Go runtime accordingly. This should result in the different queues being appropriately sized and in general more predictable performance. These dependencies are a no-op on non-Linux systems or if running in a cgroup that doesn't set a limit on CPU or memory. The automatic tuning of GOMEMLIMIT can be disabled by either explicitly setting GOMEMLIMIT yourself or by setting AUTOMEMLIMIT=off. The automatic tuning of GOMAXPROCS can similarly be counteracted by setting GOMAXPROCS yourself.
Diffstat (limited to 'vendor/github.com/cilium/ebpf/link')
-rw-r--r--vendor/github.com/cilium/ebpf/link/cgroup.go169
-rw-r--r--vendor/github.com/cilium/ebpf/link/doc.go2
-rw-r--r--vendor/github.com/cilium/ebpf/link/iter.go91
-rw-r--r--vendor/github.com/cilium/ebpf/link/link.go214
-rw-r--r--vendor/github.com/cilium/ebpf/link/netns.go60
-rw-r--r--vendor/github.com/cilium/ebpf/link/program.go76
-rw-r--r--vendor/github.com/cilium/ebpf/link/raw_tracepoint.go57
-rw-r--r--vendor/github.com/cilium/ebpf/link/syscalls.go173
8 files changed, 842 insertions, 0 deletions
diff --git a/vendor/github.com/cilium/ebpf/link/cgroup.go b/vendor/github.com/cilium/ebpf/link/cgroup.go
new file mode 100644
index 000000000..16a943930
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/link/cgroup.go
@@ -0,0 +1,169 @@
+package link
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "github.com/cilium/ebpf"
+)
+
+type cgroupAttachFlags uint32
+
+// cgroup attach flags
+const (
+ flagAllowOverride cgroupAttachFlags = 1 << iota
+ flagAllowMulti
+ flagReplace
+)
+
+type CgroupOptions struct {
+ // Path to a cgroupv2 folder.
+ Path string
+ // One of the AttachCgroup* constants
+ Attach ebpf.AttachType
+ // Program must be of type CGroup*, and the attach type must match Attach.
+ Program *ebpf.Program
+}
+
+// AttachCgroup links a BPF program to a cgroup.
+func AttachCgroup(opts CgroupOptions) (Link, error) {
+ cgroup, err := os.Open(opts.Path)
+ if err != nil {
+ return nil, fmt.Errorf("can't open cgroup: %s", err)
+ }
+
+ clone, err := opts.Program.Clone()
+ if err != nil {
+ cgroup.Close()
+ return nil, err
+ }
+
+ var cg Link
+ cg, err = newLinkCgroup(cgroup, opts.Attach, clone)
+ if errors.Is(err, ErrNotSupported) {
+ cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowMulti)
+ }
+ if errors.Is(err, ErrNotSupported) {
+ cg, err = newProgAttachCgroup(cgroup, opts.Attach, clone, flagAllowOverride)
+ }
+ if err != nil {
+ cgroup.Close()
+ clone.Close()
+ return nil, err
+ }
+
+ return cg, nil
+}
+
+// LoadPinnedCgroup loads a pinned cgroup from a bpffs.
+func LoadPinnedCgroup(fileName string) (Link, error) {
+ link, err := LoadPinnedRawLink(fileName)
+ if err != nil {
+ return nil, err
+ }
+
+ return &linkCgroup{link}, nil
+}
+
+type progAttachCgroup struct {
+ cgroup *os.File
+ current *ebpf.Program
+ attachType ebpf.AttachType
+ flags cgroupAttachFlags
+}
+
+var _ Link = (*progAttachCgroup)(nil)
+
+func (cg *progAttachCgroup) isLink() {}
+
+func newProgAttachCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program, flags cgroupAttachFlags) (*progAttachCgroup, error) {
+ if flags&flagAllowMulti > 0 {
+ if err := haveProgAttachReplace(); err != nil {
+ return nil, fmt.Errorf("can't support multiple programs: %w", err)
+ }
+ }
+
+ err := RawAttachProgram(RawAttachProgramOptions{
+ Target: int(cgroup.Fd()),
+ Program: prog,
+ Flags: uint32(flags),
+ Attach: attach,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("cgroup: %w", err)
+ }
+
+ return &progAttachCgroup{cgroup, prog, attach, flags}, nil
+}
+
+func (cg *progAttachCgroup) Close() error {
+ defer cg.cgroup.Close()
+ defer cg.current.Close()
+
+ err := RawDetachProgram(RawDetachProgramOptions{
+ Target: int(cg.cgroup.Fd()),
+ Program: cg.current,
+ Attach: cg.attachType,
+ })
+ if err != nil {
+ return fmt.Errorf("close cgroup: %s", err)
+ }
+ return nil
+}
+
+func (cg *progAttachCgroup) Update(prog *ebpf.Program) error {
+ new, err := prog.Clone()
+ if err != nil {
+ return err
+ }
+
+ args := RawAttachProgramOptions{
+ Target: int(cg.cgroup.Fd()),
+ Program: prog,
+ Attach: cg.attachType,
+ Flags: uint32(cg.flags),
+ }
+
+ if cg.flags&flagAllowMulti > 0 {
+ // Atomically replacing multiple programs requires at least
+ // 5.5 (commit 7dd68b3279f17921 "bpf: Support replacing cgroup-bpf
+ // program in MULTI mode")
+ args.Flags |= uint32(flagReplace)
+ args.Replace = cg.current
+ }
+
+ if err := RawAttachProgram(args); err != nil {
+ new.Close()
+ return fmt.Errorf("can't update cgroup: %s", err)
+ }
+
+ cg.current.Close()
+ cg.current = new
+ return nil
+}
+
+func (cg *progAttachCgroup) Pin(string) error {
+ return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
+}
+
+type linkCgroup struct {
+ *RawLink
+}
+
+var _ Link = (*linkCgroup)(nil)
+
+func (cg *linkCgroup) isLink() {}
+
+func newLinkCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program) (*linkCgroup, error) {
+ link, err := AttachRawLink(RawLinkOptions{
+ Target: int(cgroup.Fd()),
+ Program: prog,
+ Attach: attach,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return &linkCgroup{link}, err
+}
diff --git a/vendor/github.com/cilium/ebpf/link/doc.go b/vendor/github.com/cilium/ebpf/link/doc.go
new file mode 100644
index 000000000..2bde35ed7
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/link/doc.go
@@ -0,0 +1,2 @@
+// Package link allows attaching eBPF programs to various kernel hooks.
+package link
diff --git a/vendor/github.com/cilium/ebpf/link/iter.go b/vendor/github.com/cilium/ebpf/link/iter.go
new file mode 100644
index 000000000..2b5f2846a
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/link/iter.go
@@ -0,0 +1,91 @@
+package link
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/cilium/ebpf"
+)
+
+type IterOptions struct {
+ // Program must be of type Tracing with attach type
+ // AttachTraceIter. The kind of iterator to attach to is
+ // determined at load time via the AttachTo field.
+ //
+ // AttachTo requires the kernel to include BTF of itself,
+ // and it to be compiled with a recent pahole (>= 1.16).
+ Program *ebpf.Program
+}
+
+// AttachIter attaches a BPF seq_file iterator.
+func AttachIter(opts IterOptions) (*Iter, error) {
+ link, err := AttachRawLink(RawLinkOptions{
+ Program: opts.Program,
+ Attach: ebpf.AttachTraceIter,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("can't link iterator: %w", err)
+ }
+
+ return &Iter{link}, err
+}
+
+// LoadPinnedIter loads a pinned iterator from a bpffs.
+func LoadPinnedIter(fileName string) (*Iter, error) {
+ link, err := LoadPinnedRawLink(fileName)
+ if err != nil {
+ return nil, err
+ }
+
+ return &Iter{link}, err
+}
+
+// Iter represents an attached bpf_iter.
+type Iter struct {
+ link *RawLink
+}
+
+var _ Link = (*Iter)(nil)
+
+func (it *Iter) isLink() {}
+
+// FD returns the underlying file descriptor.
+func (it *Iter) FD() int {
+ return it.link.FD()
+}
+
+// Close implements Link.
+func (it *Iter) Close() error {
+ return it.link.Close()
+}
+
+// Pin implements Link.
+func (it *Iter) Pin(fileName string) error {
+ return it.link.Pin(fileName)
+}
+
+// Update implements Link.
+func (it *Iter) Update(new *ebpf.Program) error {
+ return it.link.Update(new)
+}
+
+// Open creates a new instance of the iterator.
+//
+// Reading from the returned reader triggers the BPF program.
+func (it *Iter) Open() (io.ReadCloser, error) {
+ linkFd, err := it.link.fd.Value()
+ if err != nil {
+ return nil, err
+ }
+
+ attr := &bpfIterCreateAttr{
+ linkFd: linkFd,
+ }
+
+ fd, err := bpfIterCreate(attr)
+ if err != nil {
+ return nil, fmt.Errorf("can't create iterator: %w", err)
+ }
+
+ return fd.File("bpf_iter"), nil
+}
diff --git a/vendor/github.com/cilium/ebpf/link/link.go b/vendor/github.com/cilium/ebpf/link/link.go
new file mode 100644
index 000000000..48f1a5529
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/link/link.go
@@ -0,0 +1,214 @@
+package link
+
+import (
+ "fmt"
+ "unsafe"
+
+ "github.com/cilium/ebpf"
+ "github.com/cilium/ebpf/internal"
+)
+
+var ErrNotSupported = internal.ErrNotSupported
+
+// Link represents a Program attached to a BPF hook.
+type Link interface {
+ // Replace the current program with a new program.
+ //
+ // Passing a nil program is an error. May return an error wrapping ErrNotSupported.
+ Update(*ebpf.Program) error
+
+ // Persist a link by pinning it into a bpffs.
+ //
+ // May return an error wrapping ErrNotSupported.
+ Pin(string) error
+
+ // Close frees resources.
+ //
+ // The link will be broken unless it has been pinned. A link
+ // may continue past the lifetime of the process if Close is
+ // not called.
+ Close() error
+
+ // Prevent external users from implementing this interface.
+ isLink()
+}
+
+// ID uniquely identifies a BPF link.
+type ID uint32
+
+// RawLinkOptions control the creation of a raw link.
+type RawLinkOptions struct {
+ // File descriptor to attach to. This differs for each attach type.
+ Target int
+ // Program to attach.
+ Program *ebpf.Program
+ // Attach must match the attach type of Program.
+ Attach ebpf.AttachType
+}
+
+// RawLinkInfo contains metadata on a link.
+type RawLinkInfo struct {
+ Type Type
+ ID ID
+ Program ebpf.ProgramID
+}
+
+// RawLink is the low-level API to bpf_link.
+//
+// You should consider using the higher level interfaces in this
+// package instead.
+type RawLink struct {
+ fd *internal.FD
+}
+
+// AttachRawLink creates a raw link.
+func AttachRawLink(opts RawLinkOptions) (*RawLink, error) {
+ if err := haveBPFLink(); err != nil {
+ return nil, err
+ }
+
+ if opts.Target < 0 {
+ return nil, fmt.Errorf("invalid target: %s", internal.ErrClosedFd)
+ }
+
+ progFd := opts.Program.FD()
+ if progFd < 0 {
+ return nil, fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
+ }
+
+ attr := bpfLinkCreateAttr{
+ targetFd: uint32(opts.Target),
+ progFd: uint32(progFd),
+ attachType: opts.Attach,
+ }
+ fd, err := bpfLinkCreate(&attr)
+ if err != nil {
+ return nil, fmt.Errorf("can't create link: %s", err)
+ }
+
+ return &RawLink{fd}, nil
+}
+
+// LoadPinnedRawLink loads a persisted link from a bpffs.
+func LoadPinnedRawLink(fileName string) (*RawLink, error) {
+ return loadPinnedRawLink(fileName, UnspecifiedType)
+}
+
+func loadPinnedRawLink(fileName string, typ Type) (*RawLink, error) {
+ fd, err := internal.BPFObjGet(fileName)
+ if err != nil {
+ return nil, fmt.Errorf("load pinned link: %s", err)
+ }
+
+ link := &RawLink{fd}
+ if typ == UnspecifiedType {
+ return link, nil
+ }
+
+ info, err := link.Info()
+ if err != nil {
+ link.Close()
+ return nil, fmt.Errorf("get pinned link info: %s", err)
+ }
+
+ if info.Type != typ {
+ link.Close()
+ return nil, fmt.Errorf("link type %v doesn't match %v", info.Type, typ)
+ }
+
+ return link, nil
+}
+
+func (l *RawLink) isLink() {}
+
+// FD returns the raw file descriptor.
+func (l *RawLink) FD() int {
+ fd, err := l.fd.Value()
+ if err != nil {
+ return -1
+ }
+ return int(fd)
+}
+
+// Close breaks the link.
+//
+// Use Pin if you want to make the link persistent.
+func (l *RawLink) Close() error {
+ return l.fd.Close()
+}
+
+// Pin persists a link past the lifetime of the process.
+//
+// Calling Close on a pinned Link will not break the link
+// until the pin is removed.
+func (l *RawLink) Pin(fileName string) error {
+ if err := internal.BPFObjPin(fileName, l.fd); err != nil {
+ return fmt.Errorf("can't pin link: %s", err)
+ }
+ return nil
+}
+
+// Update implements Link.
+func (l *RawLink) Update(new *ebpf.Program) error {
+ return l.UpdateArgs(RawLinkUpdateOptions{
+ New: new,
+ })
+}
+
+// RawLinkUpdateOptions control the behaviour of RawLink.UpdateArgs.
+type RawLinkUpdateOptions struct {
+ New *ebpf.Program
+ Old *ebpf.Program
+ Flags uint32
+}
+
+// UpdateArgs updates a link based on args.
+func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error {
+ newFd := opts.New.FD()
+ if newFd < 0 {
+ return fmt.Errorf("invalid program: %s", internal.ErrClosedFd)
+ }
+
+ var oldFd int
+ if opts.Old != nil {
+ oldFd = opts.Old.FD()
+ if oldFd < 0 {
+ return fmt.Errorf("invalid replacement program: %s", internal.ErrClosedFd)
+ }
+ }
+
+ linkFd, err := l.fd.Value()
+ if err != nil {
+ return fmt.Errorf("can't update link: %s", err)
+ }
+
+ attr := bpfLinkUpdateAttr{
+ linkFd: linkFd,
+ newProgFd: uint32(newFd),
+ oldProgFd: uint32(oldFd),
+ flags: opts.Flags,
+ }
+ return bpfLinkUpdate(&attr)
+}
+
+// struct bpf_link_info
+type bpfLinkInfo struct {
+ typ uint32
+ id uint32
+ prog_id uint32
+}
+
+// Info returns metadata about the link.
+func (l *RawLink) Info() (*RawLinkInfo, error) {
+ var info bpfLinkInfo
+ err := internal.BPFObjGetInfoByFD(l.fd, unsafe.Pointer(&info), unsafe.Sizeof(info))
+ if err != nil {
+ return nil, fmt.Errorf("link info: %s", err)
+ }
+
+ return &RawLinkInfo{
+ Type(info.typ),
+ ID(info.id),
+ ebpf.ProgramID(info.prog_id),
+ }, nil
+}
diff --git a/vendor/github.com/cilium/ebpf/link/netns.go b/vendor/github.com/cilium/ebpf/link/netns.go
new file mode 100644
index 000000000..3533ff0fa
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/link/netns.go
@@ -0,0 +1,60 @@
+package link
+
+import (
+ "fmt"
+
+ "github.com/cilium/ebpf"
+)
+
+// NetNsInfo contains metadata about a network namespace link.
+type NetNsInfo struct {
+ RawLinkInfo
+}
+
+// NetNsLink is a program attached to a network namespace.
+type NetNsLink struct {
+ *RawLink
+}
+
+// AttachNetNs attaches a program to a network namespace.
+func AttachNetNs(ns int, prog *ebpf.Program) (*NetNsLink, error) {
+ var attach ebpf.AttachType
+ switch t := prog.Type(); t {
+ case ebpf.FlowDissector:
+ attach = ebpf.AttachFlowDissector
+ case ebpf.SkLookup:
+ attach = ebpf.AttachSkLookup
+ default:
+ return nil, fmt.Errorf("can't attach %v to network namespace", t)
+ }
+
+ link, err := AttachRawLink(RawLinkOptions{
+ Target: ns,
+ Program: prog,
+ Attach: attach,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return &NetNsLink{link}, nil
+}
+
+// LoadPinnedNetNs loads a network namespace link from bpffs.
+func LoadPinnedNetNs(fileName string) (*NetNsLink, error) {
+ link, err := loadPinnedRawLink(fileName, NetNsType)
+ if err != nil {
+ return nil, err
+ }
+
+ return &NetNsLink{link}, nil
+}
+
+// Info returns information about the link.
+func (nns *NetNsLink) Info() (*NetNsInfo, error) {
+ info, err := nns.RawLink.Info()
+ if err != nil {
+ return nil, err
+ }
+ return &NetNsInfo{*info}, nil
+}
diff --git a/vendor/github.com/cilium/ebpf/link/program.go b/vendor/github.com/cilium/ebpf/link/program.go
new file mode 100644
index 000000000..0fe9d37c4
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/link/program.go
@@ -0,0 +1,76 @@
+package link
+
+import (
+ "fmt"
+
+ "github.com/cilium/ebpf"
+ "github.com/cilium/ebpf/internal"
+)
+
+type RawAttachProgramOptions struct {
+ // File descriptor to attach to. This differs for each attach type.
+ Target int
+ // Program to attach.
+ Program *ebpf.Program
+ // Program to replace (cgroups).
+ Replace *ebpf.Program
+ // Attach must match the attach type of Program (and Replace).
+ Attach ebpf.AttachType
+ // Flags control the attach behaviour. This differs for each attach type.
+ Flags uint32
+}
+
+// RawAttachProgram is a low level wrapper around BPF_PROG_ATTACH.
+//
+// You should use one of the higher level abstractions available in this
+// package if possible.
+func RawAttachProgram(opts RawAttachProgramOptions) error {
+ if err := haveProgAttach(); err != nil {
+ return err
+ }
+
+ var replaceFd uint32
+ if opts.Replace != nil {
+ replaceFd = uint32(opts.Replace.FD())
+ }
+
+ attr := internal.BPFProgAttachAttr{
+ TargetFd: uint32(opts.Target),
+ AttachBpfFd: uint32(opts.Program.FD()),
+ ReplaceBpfFd: replaceFd,
+ AttachType: uint32(opts.Attach),
+ AttachFlags: uint32(opts.Flags),
+ }
+
+ if err := internal.BPFProgAttach(&attr); err != nil {
+ return fmt.Errorf("can't attach program: %s", err)
+ }
+ return nil
+}
+
+type RawDetachProgramOptions struct {
+ Target int
+ Program *ebpf.Program
+ Attach ebpf.AttachType
+}
+
+// RawDetachProgram is a low level wrapper around BPF_PROG_DETACH.
+//
+// You should use one of the higher level abstractions available in this
+// package if possible.
+func RawDetachProgram(opts RawDetachProgramOptions) error {
+ if err := haveProgAttach(); err != nil {
+ return err
+ }
+
+ attr := internal.BPFProgDetachAttr{
+ TargetFd: uint32(opts.Target),
+ AttachBpfFd: uint32(opts.Program.FD()),
+ AttachType: uint32(opts.Attach),
+ }
+ if err := internal.BPFProgDetach(&attr); err != nil {
+ return fmt.Errorf("can't detach program: %s", err)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/cilium/ebpf/link/raw_tracepoint.go b/vendor/github.com/cilium/ebpf/link/raw_tracepoint.go
new file mode 100644
index 000000000..65652486f
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/link/raw_tracepoint.go
@@ -0,0 +1,57 @@
+package link
+
+import (
+ "fmt"
+
+ "github.com/cilium/ebpf"
+ "github.com/cilium/ebpf/internal"
+)
+
+type RawTracepointOptions struct {
+ // Tracepoint name.
+ Name string
+ // Program must be of type RawTracepoint*
+ Program *ebpf.Program
+}
+
+// AttachRawTracepoint links a BPF program to a raw_tracepoint.
+//
+// Requires at least Linux 4.17.
+func AttachRawTracepoint(opts RawTracepointOptions) (Link, error) {
+ if t := opts.Program.Type(); t != ebpf.RawTracepoint && t != ebpf.RawTracepointWritable {
+ return nil, fmt.Errorf("invalid program type %s, expected RawTracepoint(Writable)", t)
+ }
+ if opts.Program.FD() < 0 {
+ return nil, fmt.Errorf("invalid program: %w", internal.ErrClosedFd)
+ }
+
+ fd, err := bpfRawTracepointOpen(&bpfRawTracepointOpenAttr{
+ name: internal.NewStringPointer(opts.Name),
+ fd: uint32(opts.Program.FD()),
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return &progAttachRawTracepoint{fd: fd}, nil
+}
+
+type progAttachRawTracepoint struct {
+ fd *internal.FD
+}
+
+var _ Link = (*progAttachRawTracepoint)(nil)
+
+func (rt *progAttachRawTracepoint) isLink() {}
+
+func (rt *progAttachRawTracepoint) Close() error {
+ return rt.fd.Close()
+}
+
+func (rt *progAttachRawTracepoint) Update(_ *ebpf.Program) error {
+ return fmt.Errorf("can't update raw_tracepoint: %w", ErrNotSupported)
+}
+
+func (rt *progAttachRawTracepoint) Pin(_ string) error {
+ return fmt.Errorf("can't pin raw_tracepoint: %w", ErrNotSupported)
+}
diff --git a/vendor/github.com/cilium/ebpf/link/syscalls.go b/vendor/github.com/cilium/ebpf/link/syscalls.go
new file mode 100644
index 000000000..19326c8af
--- /dev/null
+++ b/vendor/github.com/cilium/ebpf/link/syscalls.go
@@ -0,0 +1,173 @@
+package link
+
+import (
+ "errors"
+ "unsafe"
+
+ "github.com/cilium/ebpf"
+ "github.com/cilium/ebpf/asm"
+ "github.com/cilium/ebpf/internal"
+ "github.com/cilium/ebpf/internal/unix"
+)
+
+// Type is the kind of link.
+type Type uint32
+
+// Valid link types.
+//
+// Equivalent to enum bpf_link_type.
+const (
+ UnspecifiedType Type = iota
+ RawTracepointType
+ TracingType
+ CgroupType
+ IterType
+ NetNsType
+ XDPType
+)
+
+var haveProgAttach = internal.FeatureTest("BPF_PROG_ATTACH", "4.10", func() error {
+ 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
+ }
+
+ // 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.FeatureTest("BPF_PROG_ATTACH atomic replacement", "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 := internal.BPFProgAttachAttr{
+ // We rely on this being checked after attachFlags.
+ TargetFd: ^uint32(0),
+ AttachBpfFd: uint32(prog.FD()),
+ AttachType: uint32(ebpf.AttachCGroupInetIngress),
+ AttachFlags: uint32(flagReplace),
+ }
+
+ err = internal.BPFProgAttach(&attr)
+ if errors.Is(err, unix.EINVAL) {
+ return internal.ErrNotSupported
+ }
+ if errors.Is(err, unix.EBADF) {
+ return nil
+ }
+ return err
+})
+
+type bpfLinkCreateAttr struct {
+ progFd uint32
+ targetFd uint32
+ attachType ebpf.AttachType
+ flags uint32
+}
+
+func bpfLinkCreate(attr *bpfLinkCreateAttr) (*internal.FD, error) {
+ ptr, err := internal.BPF(internal.BPF_LINK_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
+ if err != nil {
+ return nil, err
+ }
+ return internal.NewFD(uint32(ptr)), nil
+}
+
+type bpfLinkUpdateAttr struct {
+ linkFd uint32
+ newProgFd uint32
+ flags uint32
+ oldProgFd uint32
+}
+
+func bpfLinkUpdate(attr *bpfLinkUpdateAttr) error {
+ _, err := internal.BPF(internal.BPF_LINK_UPDATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
+ return err
+}
+
+var haveBPFLink = internal.FeatureTest("bpf_link", "5.7", func() error {
+ 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()
+
+ attr := bpfLinkCreateAttr{
+ // This is a hopefully invalid file descriptor, which triggers EBADF.
+ targetFd: ^uint32(0),
+ progFd: uint32(prog.FD()),
+ attachType: ebpf.AttachCGroupInetIngress,
+ }
+ _, err = bpfLinkCreate(&attr)
+ if errors.Is(err, unix.EINVAL) {
+ return internal.ErrNotSupported
+ }
+ if errors.Is(err, unix.EBADF) {
+ return nil
+ }
+ return err
+})
+
+type bpfIterCreateAttr struct {
+ linkFd uint32
+ flags uint32
+}
+
+func bpfIterCreate(attr *bpfIterCreateAttr) (*internal.FD, error) {
+ ptr, err := internal.BPF(internal.BPF_ITER_CREATE, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
+ if err == nil {
+ return internal.NewFD(uint32(ptr)), nil
+ }
+ return nil, err
+}
+
+type bpfRawTracepointOpenAttr struct {
+ name internal.Pointer
+ fd uint32
+ _ uint32
+}
+
+func bpfRawTracepointOpen(attr *bpfRawTracepointOpenAttr) (*internal.FD, error) {
+ ptr, err := internal.BPF(internal.BPF_RAW_TRACEPOINT_OPEN, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
+ if err == nil {
+ return internal.NewFD(uint32(ptr)), nil
+ }
+ return nil, err
+}