Revert "Merge pull request 101888 from kolyshkin/update-runc-rc94"
This reverts commitb1b06fe0a4
, reversing changes made to382a33986b
.
This commit is contained in:
171
vendor/github.com/cilium/ebpf/link/cgroup.go
generated
vendored
171
vendor/github.com/cilium/ebpf/link/cgroup.go
generated
vendored
@@ -1,171 +0,0 @@
|
||||
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, opts *ebpf.LoadPinOptions) (Link, error) {
|
||||
link, err := LoadPinnedRawLink(fileName, CgroupType, opts)
|
||||
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)
|
||||
}
|
||||
|
||||
func (cg *progAttachCgroup) Unpin() error {
|
||||
return fmt.Errorf("can't pin cgroup: %w", ErrNotSupported)
|
||||
}
|
||||
|
||||
type linkCgroup struct {
|
||||
RawLink
|
||||
}
|
||||
|
||||
var _ Link = (*linkCgroup)(nil)
|
||||
|
||||
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
|
||||
}
|
2
vendor/github.com/cilium/ebpf/link/doc.go
generated
vendored
2
vendor/github.com/cilium/ebpf/link/doc.go
generated
vendored
@@ -1,2 +0,0 @@
|
||||
// Package link allows attaching eBPF programs to various kernel hooks.
|
||||
package link
|
67
vendor/github.com/cilium/ebpf/link/iter.go
generated
vendored
67
vendor/github.com/cilium/ebpf/link/iter.go
generated
vendored
@@ -1,67 +0,0 @@
|
||||
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, opts *ebpf.LoadPinOptions) (*Iter, error) {
|
||||
link, err := LoadPinnedRawLink(fileName, IterType, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Iter{*link}, err
|
||||
}
|
||||
|
||||
// Iter represents an attached bpf_iter.
|
||||
type Iter struct {
|
||||
RawLink
|
||||
}
|
||||
|
||||
// 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.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
|
||||
}
|
296
vendor/github.com/cilium/ebpf/link/kprobe.go
generated
vendored
296
vendor/github.com/cilium/ebpf/link/kprobe.go
generated
vendored
@@ -1,296 +0,0 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
kprobeEventsPath = filepath.Join(tracefsPath, "kprobe_events")
|
||||
)
|
||||
|
||||
// Kprobe attaches the given eBPF program to a perf event that fires when the
|
||||
// given kernel symbol starts executing. See /proc/kallsyms for available
|
||||
// symbols. For example, printk():
|
||||
//
|
||||
// Kprobe("printk")
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources.
|
||||
func Kprobe(symbol string, prog *ebpf.Program) (Link, error) {
|
||||
k, err := kprobe(symbol, prog, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = k.attach(prog)
|
||||
if err != nil {
|
||||
k.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// Kretprobe attaches the given eBPF program to a perf event that fires right
|
||||
// before the given kernel symbol exits, with the function stack left intact.
|
||||
// See /proc/kallsyms for available symbols. For example, printk():
|
||||
//
|
||||
// Kretprobe("printk")
|
||||
//
|
||||
// The resulting Link must be Closed during program shutdown to avoid leaking
|
||||
// system resources.
|
||||
func Kretprobe(symbol string, prog *ebpf.Program) (Link, error) {
|
||||
k, err := kprobe(symbol, prog, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = k.attach(prog)
|
||||
if err != nil {
|
||||
k.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// kprobe opens a perf event on the given symbol and attaches prog to it.
|
||||
// If ret is true, create a kretprobe.
|
||||
func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
|
||||
if symbol == "" {
|
||||
return nil, fmt.Errorf("symbol name cannot be empty: %w", errInvalidInput)
|
||||
}
|
||||
if prog == nil {
|
||||
return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
|
||||
}
|
||||
if !rgxTraceEvent.MatchString(symbol) {
|
||||
return nil, fmt.Errorf("symbol '%s' must be alphanumeric or underscore: %w", symbol, errInvalidInput)
|
||||
}
|
||||
if prog.Type() != ebpf.Kprobe {
|
||||
return nil, fmt.Errorf("eBPF program type %s is not a Kprobe: %w", prog.Type(), errInvalidInput)
|
||||
}
|
||||
|
||||
// Use kprobe PMU if the kernel has it available.
|
||||
tp, err := pmuKprobe(symbol, ret)
|
||||
if err == nil {
|
||||
return tp, nil
|
||||
}
|
||||
if err != nil && !errors.Is(err, ErrNotSupported) {
|
||||
return nil, fmt.Errorf("creating perf_kprobe PMU: %w", err)
|
||||
}
|
||||
|
||||
// Use tracefs if kprobe PMU is missing.
|
||||
tp, err = tracefsKprobe(symbol, ret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("creating trace event '%s' in tracefs: %w", symbol, err)
|
||||
}
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
// pmuKprobe opens a perf event based on a Performance Monitoring Unit.
|
||||
// Requires at least 4.17 (e12f03d7031a "perf/core: Implement the
|
||||
// 'perf_kprobe' PMU").
|
||||
// Returns ErrNotSupported if the kernel doesn't support perf_kprobe PMU,
|
||||
// or os.ErrNotExist if the given symbol does not exist in the kernel.
|
||||
func pmuKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
|
||||
// Getting the PMU type will fail if the kernel doesn't support
|
||||
// the perf_kprobe PMU.
|
||||
et, err := getPMUEventType("kprobe")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create a pointer to a NUL-terminated string for the kernel.
|
||||
sp, err := unsafeStringPtr(symbol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: Parse the position of the bit from /sys/bus/event_source/devices/%s/format/retprobe.
|
||||
config := 0
|
||||
if ret {
|
||||
config = 1
|
||||
}
|
||||
|
||||
attr := unix.PerfEventAttr{
|
||||
Type: uint32(et), // PMU event type read from sysfs
|
||||
Ext1: uint64(uintptr(sp)), // Kernel symbol to trace
|
||||
Config: uint64(config), // perf_kprobe PMU treats config as flags
|
||||
}
|
||||
|
||||
fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
|
||||
|
||||
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
|
||||
// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
|
||||
// is returned to the caller.
|
||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
||||
return nil, fmt.Errorf("symbol '%s' not found: %w", symbol, os.ErrNotExist)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening perf event: %w", err)
|
||||
}
|
||||
|
||||
// Ensure the string pointer is not collected before PerfEventOpen returns.
|
||||
runtime.KeepAlive(sp)
|
||||
|
||||
// Kernel has perf_kprobe PMU available, initialize perf event.
|
||||
return &perfEvent{
|
||||
fd: internal.NewFD(uint32(fd)),
|
||||
pmuID: et,
|
||||
name: symbol,
|
||||
ret: ret,
|
||||
progType: ebpf.Kprobe,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// tracefsKprobe creates a trace event by writing an entry to <tracefs>/kprobe_events.
|
||||
// A new trace event group name is generated on every call to support creating
|
||||
// multiple trace events for the same kernel symbol. A perf event is then opened
|
||||
// on the newly-created trace event and returned to the caller.
|
||||
func tracefsKprobe(symbol string, ret bool) (*perfEvent, error) {
|
||||
|
||||
// Generate a random string for each trace event we attempt to create.
|
||||
// This value is used as the 'group' token in tracefs to allow creating
|
||||
// multiple kprobe trace events with the same name.
|
||||
group, err := randomGroup("ebpf")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("randomizing group name: %w", err)
|
||||
}
|
||||
|
||||
// Before attempting to create a trace event through tracefs,
|
||||
// check if an event with the same group and name already exists.
|
||||
// Kernels 4.x and earlier don't return os.ErrExist on writing a duplicate
|
||||
// entry, so we need to rely on reads for detecting uniqueness.
|
||||
_, err = getTraceEventID(group, symbol)
|
||||
if err == nil {
|
||||
return nil, fmt.Errorf("trace event already exists: %s/%s", group, symbol)
|
||||
}
|
||||
// The read is expected to fail with ErrNotSupported due to a non-existing event.
|
||||
if err != nil && !errors.Is(err, ErrNotSupported) {
|
||||
return nil, fmt.Errorf("checking trace event %s/%s: %w", group, symbol, err)
|
||||
}
|
||||
|
||||
// Create the kprobe trace event using tracefs.
|
||||
if err := createTraceFSKprobeEvent(group, symbol, ret); err != nil {
|
||||
return nil, fmt.Errorf("creating kprobe event on tracefs: %w", err)
|
||||
}
|
||||
|
||||
// Get the newly-created trace event's id.
|
||||
tid, err := getTraceEventID(group, symbol)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting trace event id: %w", err)
|
||||
}
|
||||
|
||||
// Kprobes are ephemeral tracepoints and share the same perf event type.
|
||||
fd, err := openTracepointPerfEvent(tid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &perfEvent{
|
||||
fd: fd,
|
||||
group: group,
|
||||
name: symbol,
|
||||
ret: ret,
|
||||
tracefsID: tid,
|
||||
progType: ebpf.Kprobe, // kernel only allows attaching kprobe programs to kprobe events
|
||||
}, nil
|
||||
}
|
||||
|
||||
// createTraceFSKprobeEvent creates a new ephemeral trace event by writing to
|
||||
// <tracefs>/kprobe_events. Returns ErrNotSupported if symbol is not a valid
|
||||
// kernel symbol, or if it is not traceable with kprobes.
|
||||
func createTraceFSKprobeEvent(group, symbol string, ret bool) error {
|
||||
// Open the kprobe_events file in tracefs.
|
||||
f, err := os.OpenFile(kprobeEventsPath, os.O_APPEND|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening kprobe_events: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// The kprobe_events syntax is as follows (see Documentation/trace/kprobetrace.txt):
|
||||
// p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe
|
||||
// r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe
|
||||
// -:[GRP/]EVENT : Clear a probe
|
||||
//
|
||||
// Some examples:
|
||||
// r:ebpf_1234/r_my_kretprobe nf_conntrack_destroy
|
||||
// p:ebpf_5678/p_my_kprobe __x64_sys_execve
|
||||
//
|
||||
// Leaving the kretprobe's MAXACTIVE set to 0 (or absent) will make the
|
||||
// kernel default to NR_CPUS. This is desired in most eBPF cases since
|
||||
// subsampling or rate limiting logic can be more accurately implemented in
|
||||
// the eBPF program itself. See Documentation/kprobes.txt for more details.
|
||||
pe := fmt.Sprintf("%s:%s/%s %s", kprobePrefix(ret), group, symbol, symbol)
|
||||
_, err = f.WriteString(pe)
|
||||
// Since commit 97c753e62e6c, ENOENT is correctly returned instead of EINVAL
|
||||
// when trying to create a kretprobe for a missing symbol. Make sure ENOENT
|
||||
// is returned to the caller.
|
||||
if errors.Is(err, os.ErrNotExist) || errors.Is(err, unix.EINVAL) {
|
||||
return fmt.Errorf("kernel symbol %s not found: %w", symbol, os.ErrNotExist)
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("writing '%s' to kprobe_events: %w", pe, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// closeTraceFSKprobeEvent removes the kprobe with the given group, symbol and kind
|
||||
// from <tracefs>/kprobe_events.
|
||||
func closeTraceFSKprobeEvent(group, symbol string) error {
|
||||
f, err := os.OpenFile(kprobeEventsPath, os.O_APPEND|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error opening kprobe_events: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// See kprobe_events syntax above. Kprobe type does not need to be specified
|
||||
// for removals.
|
||||
pe := fmt.Sprintf("-:%s/%s", group, symbol)
|
||||
if _, err = f.WriteString(pe); err != nil {
|
||||
return fmt.Errorf("writing '%s' to kprobe_events: %w", pe, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// randomGroup generates a pseudorandom string for use as a tracefs group name.
|
||||
// Returns an error when the output string would exceed 63 characters (kernel
|
||||
// limitation), when rand.Read() fails or when prefix contains characters not
|
||||
// allowed by rgxTraceEvent.
|
||||
func randomGroup(prefix string) (string, error) {
|
||||
if !rgxTraceEvent.MatchString(prefix) {
|
||||
return "", fmt.Errorf("prefix '%s' must be alphanumeric or underscore: %w", prefix, errInvalidInput)
|
||||
}
|
||||
|
||||
b := make([]byte, 8)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", fmt.Errorf("reading random bytes: %w", err)
|
||||
}
|
||||
|
||||
group := fmt.Sprintf("%s_%x", prefix, b)
|
||||
if len(group) > 63 {
|
||||
return "", fmt.Errorf("group name '%s' cannot be longer than 63 characters: %w", group, errInvalidInput)
|
||||
}
|
||||
|
||||
return group, nil
|
||||
}
|
||||
|
||||
func kprobePrefix(ret bool) string {
|
||||
if ret {
|
||||
return "r"
|
||||
}
|
||||
return "p"
|
||||
}
|
229
vendor/github.com/cilium/ebpf/link/link.go
generated
vendored
229
vendor/github.com/cilium/ebpf/link/link.go
generated
vendored
@@ -1,229 +0,0 @@
|
||||
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
|
||||
|
||||
// Undo a previous call to Pin.
|
||||
//
|
||||
// May return an error wrapping ErrNotSupported.
|
||||
Unpin() 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
|
||||
pinnedPath string
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// Returns an error if the pinned link type doesn't match linkType. Pass
|
||||
// UnspecifiedType to disable this behaviour.
|
||||
func LoadPinnedRawLink(fileName string, linkType Type, opts *ebpf.LoadPinOptions) (*RawLink, error) {
|
||||
fd, err := internal.BPFObjGet(fileName, opts.Marshal())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("load pinned link: %w", err)
|
||||
}
|
||||
|
||||
link := &RawLink{fd, fileName}
|
||||
if linkType == 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 != linkType {
|
||||
link.Close()
|
||||
return nil, fmt.Errorf("link type %v doesn't match %v", info.Type, linkType)
|
||||
}
|
||||
|
||||
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.Pin(l.pinnedPath, fileName, l.fd); err != nil {
|
||||
return err
|
||||
}
|
||||
l.pinnedPath = fileName
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unpin implements the Link interface.
|
||||
func (l *RawLink) Unpin() error {
|
||||
if err := internal.Unpin(l.pinnedPath); err != nil {
|
||||
return err
|
||||
}
|
||||
l.pinnedPath = ""
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update implements the Link interface.
|
||||
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
|
||||
}
|
60
vendor/github.com/cilium/ebpf/link/netns.go
generated
vendored
60
vendor/github.com/cilium/ebpf/link/netns.go
generated
vendored
@@ -1,60 +0,0 @@
|
||||
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, opts *ebpf.LoadPinOptions) (*NetNsLink, error) {
|
||||
link, err := LoadPinnedRawLink(fileName, NetNsType, opts)
|
||||
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
|
||||
}
|
253
vendor/github.com/cilium/ebpf/link/perf_event.go
generated
vendored
253
vendor/github.com/cilium/ebpf/link/perf_event.go
generated
vendored
@@ -1,253 +0,0 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
"github.com/cilium/ebpf/internal"
|
||||
"github.com/cilium/ebpf/internal/unix"
|
||||
)
|
||||
|
||||
// Getting the terminology right is usually the hardest part. For posterity and
|
||||
// for staying sane during implementation:
|
||||
//
|
||||
// - trace event: Representation of a kernel runtime hook. Filesystem entries
|
||||
// under <tracefs>/events. Can be tracepoints (static), kprobes or uprobes.
|
||||
// Can be instantiated into perf events (see below).
|
||||
// - tracepoint: A predetermined hook point in the kernel. Exposed as trace
|
||||
// events in (sub)directories under <tracefs>/events. Cannot be closed or
|
||||
// removed, they are static.
|
||||
// - k(ret)probe: Ephemeral trace events based on entry or exit points of
|
||||
// exported kernel symbols. kprobe-based (tracefs) trace events can be
|
||||
// created system-wide by writing to the <tracefs>/kprobe_events file, or
|
||||
// they can be scoped to the current process by creating PMU perf events.
|
||||
// - perf event: An object instantiated based on an existing trace event or
|
||||
// kernel symbol. Referred to by fd in userspace.
|
||||
// Exactly one eBPF program can be attached to a perf event. Multiple perf
|
||||
// events can be created from a single trace event. Closing a perf event
|
||||
// stops any further invocations of the attached eBPF program.
|
||||
|
||||
var (
|
||||
tracefsPath = "/sys/kernel/debug/tracing"
|
||||
|
||||
// Trace event groups, names and kernel symbols must adhere to this set
|
||||
// of characters. Non-empty, first character must not be a number, all
|
||||
// characters must be alphanumeric or underscore.
|
||||
rgxTraceEvent = regexp.MustCompile("^[a-zA-Z_][0-9a-zA-Z_]*$")
|
||||
|
||||
errInvalidInput = errors.New("invalid input")
|
||||
)
|
||||
|
||||
const (
|
||||
perfAllThreads = -1
|
||||
)
|
||||
|
||||
// A perfEvent represents a perf event kernel object. Exactly one eBPF program
|
||||
// can be attached to it. It is created based on a tracefs trace event or a
|
||||
// Performance Monitoring Unit (PMU).
|
||||
type perfEvent struct {
|
||||
|
||||
// Group and name of the tracepoint/kprobe/uprobe.
|
||||
group string
|
||||
name string
|
||||
|
||||
// PMU event ID read from sysfs. Valid IDs are non-zero.
|
||||
pmuID uint64
|
||||
// ID of the trace event read from tracefs. Valid IDs are non-zero.
|
||||
tracefsID uint64
|
||||
|
||||
// True for kretprobes/uretprobes.
|
||||
ret bool
|
||||
|
||||
fd *internal.FD
|
||||
progType ebpf.ProgramType
|
||||
}
|
||||
|
||||
func (pe *perfEvent) isLink() {}
|
||||
|
||||
func (pe *perfEvent) Pin(string) error {
|
||||
return fmt.Errorf("pin perf event: %w", ErrNotSupported)
|
||||
}
|
||||
|
||||
func (pe *perfEvent) Unpin() error {
|
||||
return fmt.Errorf("unpin perf event: %w", ErrNotSupported)
|
||||
}
|
||||
|
||||
// Since 4.15 (e87c6bc3852b "bpf: permit multiple bpf attachments for a single perf event"),
|
||||
// calling PERF_EVENT_IOC_SET_BPF appends the given program to a prog_array
|
||||
// owned by the perf event, which means multiple programs can be attached
|
||||
// simultaneously.
|
||||
//
|
||||
// Before 4.15, calling PERF_EVENT_IOC_SET_BPF more than once on a perf event
|
||||
// returns EEXIST.
|
||||
//
|
||||
// Detaching a program from a perf event is currently not possible, so a
|
||||
// program replacement mechanism cannot be implemented for perf events.
|
||||
func (pe *perfEvent) Update(prog *ebpf.Program) error {
|
||||
return fmt.Errorf("can't replace eBPF program in perf event: %w", ErrNotSupported)
|
||||
}
|
||||
|
||||
func (pe *perfEvent) Close() error {
|
||||
if pe.fd == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pfd, err := pe.fd.Value()
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting perf event fd: %w", err)
|
||||
}
|
||||
|
||||
err = unix.IoctlSetInt(int(pfd), unix.PERF_EVENT_IOC_DISABLE, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("disabling perf event: %w", err)
|
||||
}
|
||||
|
||||
err = pe.fd.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("closing perf event fd: %w", err)
|
||||
}
|
||||
|
||||
switch t := pe.progType; t {
|
||||
case ebpf.Kprobe:
|
||||
// For kprobes created using tracefs, clean up the <tracefs>/kprobe_events entry.
|
||||
if pe.tracefsID != 0 {
|
||||
return closeTraceFSKprobeEvent(pe.group, pe.name)
|
||||
}
|
||||
case ebpf.TracePoint:
|
||||
// Tracepoint trace events don't hold any extra resources.
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// attach the given eBPF prog to the perf event stored in pe.
|
||||
// pe must contain a valid perf event fd.
|
||||
// prog's type must match the program type stored in pe.
|
||||
func (pe *perfEvent) attach(prog *ebpf.Program) error {
|
||||
if prog == nil {
|
||||
return errors.New("cannot attach a nil program")
|
||||
}
|
||||
if pe.fd == nil {
|
||||
return errors.New("cannot attach to nil perf event")
|
||||
}
|
||||
if t := prog.Type(); t != pe.progType {
|
||||
return fmt.Errorf("invalid program type (expected %s): %s", pe.progType, t)
|
||||
}
|
||||
if prog.FD() < 0 {
|
||||
return fmt.Errorf("invalid program: %w", internal.ErrClosedFd)
|
||||
}
|
||||
|
||||
// The ioctl below will fail when the fd is invalid.
|
||||
kfd, _ := pe.fd.Value()
|
||||
|
||||
// Assign the eBPF program to the perf event.
|
||||
err := unix.IoctlSetInt(int(kfd), unix.PERF_EVENT_IOC_SET_BPF, prog.FD())
|
||||
if err != nil {
|
||||
return fmt.Errorf("setting perf event bpf program: %w", err)
|
||||
}
|
||||
|
||||
// PERF_EVENT_IOC_ENABLE and _DISABLE ignore their given values.
|
||||
if err := unix.IoctlSetInt(int(kfd), unix.PERF_EVENT_IOC_ENABLE, 0); err != nil {
|
||||
return fmt.Errorf("enable perf event: %s", err)
|
||||
}
|
||||
|
||||
// Close the perf event when its reference is lost to avoid leaking system resources.
|
||||
runtime.SetFinalizer(pe, (*perfEvent).Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
// unsafeStringPtr returns an unsafe.Pointer to a NUL-terminated copy of str.
|
||||
func unsafeStringPtr(str string) (unsafe.Pointer, error) {
|
||||
p, err := unix.BytePtrFromString(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return unsafe.Pointer(p), nil
|
||||
}
|
||||
|
||||
// getTraceEventID reads a trace event's ID from tracefs given its group and name.
|
||||
// group and name must be alphanumeric or underscore, as required by the kernel.
|
||||
func getTraceEventID(group, name string) (uint64, error) {
|
||||
tid, err := uint64FromFile(tracefsPath, "events", group, name, "id")
|
||||
if errors.Is(err, ErrNotSupported) {
|
||||
return 0, fmt.Errorf("trace event %s/%s: %w", group, name, ErrNotSupported)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading trace event ID of %s/%s: %w", group, name, err)
|
||||
}
|
||||
|
||||
return tid, nil
|
||||
}
|
||||
|
||||
// getPMUEventType reads a Performance Monitoring Unit's type (numeric identifier)
|
||||
// from /sys/bus/event_source/devices/<pmu>/type.
|
||||
func getPMUEventType(pmu string) (uint64, error) {
|
||||
et, err := uint64FromFile("/sys/bus/event_source/devices", pmu, "type")
|
||||
if errors.Is(err, ErrNotSupported) {
|
||||
return 0, fmt.Errorf("pmu type %s: %w", pmu, ErrNotSupported)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading pmu type %s: %w", pmu, err)
|
||||
}
|
||||
|
||||
return et, nil
|
||||
}
|
||||
|
||||
// openTracepointPerfEvent opens a tracepoint-type perf event. System-wide
|
||||
// kprobes created by writing to <tracefs>/kprobe_events are tracepoints
|
||||
// behind the scenes, and can be attached to using these perf events.
|
||||
func openTracepointPerfEvent(tid uint64) (*internal.FD, error) {
|
||||
attr := unix.PerfEventAttr{
|
||||
Type: unix.PERF_TYPE_TRACEPOINT,
|
||||
Config: tid,
|
||||
Sample_type: unix.PERF_SAMPLE_RAW,
|
||||
Sample: 1,
|
||||
Wakeup: 1,
|
||||
}
|
||||
|
||||
fd, err := unix.PerfEventOpen(&attr, perfAllThreads, 0, -1, unix.PERF_FLAG_FD_CLOEXEC)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("opening tracepoint perf event: %w", err)
|
||||
}
|
||||
|
||||
return internal.NewFD(uint32(fd)), nil
|
||||
}
|
||||
|
||||
// uint64FromFile reads a uint64 from a file. All elements of path are sanitized
|
||||
// and joined onto base. Returns error if base no longer prefixes the path after
|
||||
// joining all components.
|
||||
func uint64FromFile(base string, path ...string) (uint64, error) {
|
||||
|
||||
// Resolve leaf path separately for error feedback. Makes the join onto
|
||||
// base more readable (can't mix with variadic args).
|
||||
l := filepath.Join(path...)
|
||||
|
||||
p := filepath.Join(base, l)
|
||||
if !strings.HasPrefix(p, base) {
|
||||
return 0, fmt.Errorf("path '%s' attempts to escape base path '%s': %w", l, base, errInvalidInput)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(p)
|
||||
if os.IsNotExist(err) {
|
||||
// Only echo leaf path, the base path can be prepended at the call site
|
||||
// if more verbosity is required.
|
||||
return 0, fmt.Errorf("symbol %s: %w", l, ErrNotSupported)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("reading file %s: %w", p, err)
|
||||
}
|
||||
|
||||
et := bytes.TrimSpace(data)
|
||||
return strconv.ParseUint(string(et), 10, 64)
|
||||
}
|
76
vendor/github.com/cilium/ebpf/link/program.go
generated
vendored
76
vendor/github.com/cilium/ebpf/link/program.go
generated
vendored
@@ -1,76 +0,0 @@
|
||||
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
|
||||
}
|
61
vendor/github.com/cilium/ebpf/link/raw_tracepoint.go
generated
vendored
61
vendor/github.com/cilium/ebpf/link/raw_tracepoint.go
generated
vendored
@@ -1,61 +0,0 @@
|
||||
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)
|
||||
}
|
||||
|
||||
func (rt *progAttachRawTracepoint) Unpin() error {
|
||||
return fmt.Errorf("unpin raw_tracepoint: %w", ErrNotSupported)
|
||||
}
|
173
vendor/github.com/cilium/ebpf/link/syscalls.go
generated
vendored
173
vendor/github.com/cilium/ebpf/link/syscalls.go
generated
vendored
@@ -1,173 +0,0 @@
|
||||
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
|
||||
}
|
56
vendor/github.com/cilium/ebpf/link/tracepoint.go
generated
vendored
56
vendor/github.com/cilium/ebpf/link/tracepoint.go
generated
vendored
@@ -1,56 +0,0 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cilium/ebpf"
|
||||
)
|
||||
|
||||
// Tracepoint attaches the given eBPF program to the tracepoint with the given
|
||||
// group and name. See /sys/kernel/debug/tracing/events to find available
|
||||
// tracepoints. The top-level directory is the group, the event's subdirectory
|
||||
// is the name. Example:
|
||||
//
|
||||
// Tracepoint("syscalls", "sys_enter_fork")
|
||||
//
|
||||
// Note that attaching eBPF programs to syscalls (sys_enter_*/sys_exit_*) is
|
||||
// only possible as of kernel 4.14 (commit cf5f5ce).
|
||||
func Tracepoint(group, name string, prog *ebpf.Program) (Link, error) {
|
||||
if group == "" || name == "" {
|
||||
return nil, fmt.Errorf("group and name cannot be empty: %w", errInvalidInput)
|
||||
}
|
||||
if prog == nil {
|
||||
return nil, fmt.Errorf("prog cannot be nil: %w", errInvalidInput)
|
||||
}
|
||||
if !rgxTraceEvent.MatchString(group) || !rgxTraceEvent.MatchString(name) {
|
||||
return nil, fmt.Errorf("group and name '%s/%s' must be alphanumeric or underscore: %w", group, name, errInvalidInput)
|
||||
}
|
||||
if prog.Type() != ebpf.TracePoint {
|
||||
return nil, fmt.Errorf("eBPF program type %s is not a Tracepoint: %w", prog.Type(), errInvalidInput)
|
||||
}
|
||||
|
||||
tid, err := getTraceEventID(group, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fd, err := openTracepointPerfEvent(tid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pe := &perfEvent{
|
||||
fd: fd,
|
||||
tracefsID: tid,
|
||||
group: group,
|
||||
name: name,
|
||||
progType: ebpf.TracePoint,
|
||||
}
|
||||
|
||||
if err := pe.attach(prog); err != nil {
|
||||
pe.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pe, nil
|
||||
}
|
Reference in New Issue
Block a user