Skip to content

Commit

Permalink
link/perfEvent: split perf event attachment modes
Browse files Browse the repository at this point in the history
Signed-off-by: Mattia Meleleo <mattia.meleleo@elastic.co>
  • Loading branch information
mmat11 committed Feb 21, 2022
1 parent b2d7f64 commit ec60821
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 146 deletions.
59 changes: 25 additions & 34 deletions link/kprobe.go
Expand Up @@ -99,13 +99,7 @@ func Kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, error
return nil, err
}

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

return k, nil
return attachPerfEvent(k, prog)
}

// Kretprobe attaches the given eBPF program to a perf event that fires right
Expand All @@ -123,18 +117,12 @@ func Kretprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions) (Link, er
return nil, err
}

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

return k, nil
return attachPerfEvent(k, prog)
}

// 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, opts *KprobeOptions, ret bool) (*perfEvent, error) {
func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (Link, error) {
if symbol == "" {
return nil, fmt.Errorf("symbol name cannot be empty: %w", errInvalidInput)
}
Expand Down Expand Up @@ -187,7 +175,7 @@ func kprobe(symbol string, prog *ebpf.Program, opts *KprobeOptions, ret bool) (*

// pmuKprobe opens a perf event based on the kprobe PMU.
// Returns os.ErrNotExist if the given symbol does not exist in the kernel.
func pmuKprobe(args probeArgs) (*perfEvent, error) {
func pmuKprobe(args probeArgs) (Link, error) {
return pmuProbe(kprobeType, args)
}

Expand All @@ -198,7 +186,7 @@ func pmuKprobe(args probeArgs) (*perfEvent, error) {
// 33ea4b24277b "perf/core: Implement the 'perf_uprobe' PMU"
//
// Returns ErrNotSupported if the kernel doesn't support perf_[k,u]probe PMU
func pmuProbe(typ probeType, args probeArgs) (*perfEvent, error) {
func pmuProbe(typ probeType, args probeArgs) (Link, error) {
// Getting the PMU type will fail if the kernel doesn't support
// the perf_[k,u]probe PMU.
et, err := getPMUEventType(typ)
Expand Down Expand Up @@ -281,17 +269,19 @@ 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),
cookie: args.cookie,
}, nil
return newPerfEvent(
typ.PerfEventType(args.ret), // typ
"", // group
args.symbol, // name
et, // pmuID
0, // tracefsID
args.cookie, // cookie
fd, // fd
), nil
}

// tracefsKprobe creates a Kprobe tracefs entry.
func tracefsKprobe(args probeArgs) (*perfEvent, error) {
func tracefsKprobe(args probeArgs) (Link, error) {
return tracefsProbe(kprobeType, args)
}

Expand All @@ -301,7 +291,7 @@ func tracefsKprobe(args probeArgs) (*perfEvent, error) {
// Path and offset are only set in the case of uprobe(s) and are used to set
// the executable/library path on the filesystem and the offset where the probe is inserted.
// A perf event is then opened on the newly-created trace event and returned to the caller.
func tracefsProbe(typ probeType, args probeArgs) (*perfEvent, error) {
func tracefsProbe(typ probeType, args probeArgs) (Link, 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.
Expand Down Expand Up @@ -340,14 +330,15 @@ func tracefsProbe(typ probeType, args probeArgs) (*perfEvent, error) {
return nil, err
}

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

// createTraceFSProbeEvent creates a new ephemeral trace event by writing to
Expand Down
28 changes: 17 additions & 11 deletions link/kprobe_test.go
Expand Up @@ -78,17 +78,19 @@ func TestKprobeCreatePMU(t *testing.T) {
c := qt.New(t)

// kprobe happy path. printk is always present.
pk, err := pmuKprobe(probeArgs{symbol: ksym})
l, err := pmuKprobe(probeArgs{symbol: ksym})
c.Assert(err, qt.IsNil)
defer pk.Close()
defer l.Close()

pk := perfEventFromLink(t, l)
c.Assert(pk.typ, qt.Equals, kprobeEvent)

// kretprobe happy path.
pr, err := pmuKprobe(probeArgs{symbol: ksym, ret: true})
l, err = pmuKprobe(probeArgs{symbol: ksym, ret: true})
c.Assert(err, qt.IsNil)
defer pr.Close()
defer l.Close()

pr := perfEventFromLink(t, l)
c.Assert(pr.typ, qt.Equals, kretprobeEvent)

// Expect os.ErrNotExist when specifying a non-existent kernel symbol
Expand Down Expand Up @@ -134,25 +136,29 @@ func TestKprobeTraceFS(t *testing.T) {
c := qt.New(t)

// Open and close tracefs k(ret)probes, checking all errors.
kp, err := tracefsKprobe(probeArgs{symbol: ksym})
l, err := tracefsKprobe(probeArgs{symbol: ksym})
c.Assert(err, qt.IsNil)
c.Assert(kp.Close(), qt.IsNil)
c.Assert(l.Close(), qt.IsNil)
kp := perfEventFromLink(t, l)
c.Assert(kp.typ, qt.Equals, kprobeEvent)

kp, err = tracefsKprobe(probeArgs{symbol: ksym, ret: true})
l, err = tracefsKprobe(probeArgs{symbol: ksym, ret: true})
kp = perfEventFromLink(t, l)
c.Assert(err, qt.IsNil)
c.Assert(kp.Close(), qt.IsNil)
c.Assert(kp.typ, qt.Equals, kretprobeEvent)

// Create two identical trace events, ensure their IDs differ.
k1, err := tracefsKprobe(probeArgs{symbol: ksym})
l, err = tracefsKprobe(probeArgs{symbol: ksym})
c.Assert(err, qt.IsNil)
defer k1.Close()
defer l.Close()
k1 := perfEventFromLink(t, l)
c.Assert(k1.tracefsID, qt.Not(qt.Equals), 0)

k2, err := tracefsKprobe(probeArgs{symbol: ksym})
l, err = tracefsKprobe(probeArgs{symbol: ksym})
c.Assert(err, qt.IsNil)
defer k2.Close()
defer l.Close()
k2 := perfEventFromLink(t, l)
c.Assert(k2.tracefsID, qt.Not(qt.Equals), 0)

// Compare the kprobes' tracefs IDs.
Expand Down
6 changes: 5 additions & 1 deletion link/link.go
Expand Up @@ -77,6 +77,8 @@ func wrapRawLink(raw *RawLink) (Link, error) {
return &Iter{*raw}, nil
case NetNsType:
return &NetNsLink{*raw}, nil
case PerfEventType:
return &perfEventLink{raw: raw}, nil
default:
return raw, nil
}
Expand Down Expand Up @@ -325,11 +327,13 @@ func (l *RawLink) Info() (*Info, error) {
extra = &TracingInfo{}
case XDPType:
extra = &XDPInfo{}
case PerfEventType:
// not supported
default:
return nil, fmt.Errorf("unknown link info type: %d", info.Type)
}

if info.Type != RawTracepointType && info.Type != IterType {
if info.Type != RawTracepointType && info.Type != IterType && info.Type != PerfEventType {
buf := bytes.NewReader(info.Extra[:])
err := binary.Read(buf, internal.NativeEndian, extra)
if err != nil {
Expand Down

0 comments on commit ec60821

Please sign in to comment.