Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

link: support bpf perf event link, add bpf_cookies #565

Merged
merged 7 commits into from Mar 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .semaphore/semaphore.yml
Expand Up @@ -43,7 +43,7 @@ blocks:
- name: TMPDIR
value: /tmp
- name: CI_MAX_KERNEL_VERSION
value: "5.14"
value: "5.15"
jobs:
- name: Build and Lint
commands:
Expand Down
Binary file modified internal/btf/testdata/vmlinux-btf.gz
Binary file not shown.
10 changes: 9 additions & 1 deletion internal/cmd/gentypes/main.go
Expand Up @@ -262,7 +262,7 @@ import (
replace(objName, "prog_name"),
replace(enumTypes["ProgType"], "prog_type"),
replace(enumTypes["AttachType"], "expected_attach_type"),
replace(pointer, "insns", "license", "log_buf", "func_info", "line_info"),
replace(pointer, "insns", "license", "log_buf", "func_info", "line_info", "fd_array"),
},
},
{
Expand Down Expand Up @@ -342,6 +342,14 @@ import (
replace(pointer, "iter_info"),
},
},
{
"LinkCreatePerfEvent", retFd, "link_create", "BPF_LINK_CREATE",
mmat11 marked this conversation as resolved.
Show resolved Hide resolved
[]patch{
chooseNth(4, 2),
replace(enumTypes["AttachType"], "attach_type"),
flattenAnon,
},
},
{
"LinkUpdate", retError, "link_update", "BPF_LINK_UPDATE",
nil,
Expand Down
127 changes: 85 additions & 42 deletions internal/sys/types.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 37 additions & 21 deletions link/kprobe.go
Expand Up @@ -29,10 +29,20 @@ var (
type probeType uint8

type probeArgs struct {
symbol, group, path string
offset, refCtrOffset uint64
pid int
ret bool
symbol, group, path string
offset, refCtrOffset, cookie uint64
pid int
ret bool
}

// KprobeOptions defines additional parameters that will be used
// when loading Kprobes.
type KprobeOptions struct {
// Arbitrary value that can be fetched from an eBPF program
// via `bpf_get_attach_cookie()`.
//
// Needs kernel 5.15+.
Cookie uint64
}

const (
Expand Down Expand Up @@ -78,53 +88,53 @@ func (pt probeType) RetprobeBit() (uint64, error) {
// given kernel symbol starts executing. See /proc/kallsyms for available
// symbols. For example, printk():
//
// kp, err := Kprobe("printk", prog)
// kp, err := Kprobe("printk", prog, nil)
//
// Losing the reference to the resulting Link (kp) will close the Kprobe
// and prevent further execution of prog. The 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)
func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
k, err := kprobe(symbol, prog, opts, false)
if err != nil {
return nil, err
}

err = k.attach(prog)
lnk, err := attachPerfEvent(k, prog)
if err != nil {
k.Close()
return nil, err
}

return k, nil
return lnk, 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():
//
// kp, err := Kretprobe("printk", prog)
// kp, err := Kretprobe("printk", prog, nil)
//
// Losing the reference to the resulting Link (kp) will close the Kretprobe
// and prevent further execution of prog. The 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)
func Kretprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error) {
k, err := kprobe(symbol, prog, opts, true)
if err != nil {
return nil, err
}

err = k.attach(prog)
lnk, err := attachPerfEvent(k, prog)
if err != nil {
k.Close()
return nil, err
}

return k, nil
return lnk, 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) {
func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*perfEvent, error) {
if symbol == "" {
return nil, fmt.Errorf("symbol name cannot be empty: %w", errInvalidInput)
}
Expand All @@ -144,6 +154,10 @@ func kprobe(symbol string, prog *ebpf.Program, ret bool) (*perfEvent, error) {
ret: ret,
}

if opts != nil {
args.cookie = opts.Cookie
}

// Use kprobe PMU if the kernel has it available.
tp, err := pmuKprobe(args)
if errors.Is(err, os.ErrNotExist) {
Expand Down Expand Up @@ -268,10 +282,11 @@ func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {

// Kernel has perf_[k,u]probe PMU available, initialize perf event.
return &perfEvent{
fd: fd,
pmuID: et,
name: args.symbol,
typ: typ.PerfEventType(args.ret),
typ: typ.PerfEventType(args.ret),
name: args.symbol,
pmuID: et,
cookie: args.cookie,
fd: fd,
}, nil
}

Expand Down Expand Up @@ -326,11 +341,12 @@ func tracefsProbe(typ probeType, args probeArgs) (*perfEvent, error) {
}

return &perfEvent{
fd: fd,
typ: typ.PerfEventType(args.ret),
group: group,
name: args.symbol,
tracefsID: tid,
typ: typ.PerfEventType(args.ret),
cookie: args.cookie,
fd: fd,
}, nil
}

Expand Down