From 53e95f91ff054789360edc1d11f61428bb122675 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 11 Mar 2024 00:00:28 +0000 Subject: [PATCH] link: Add Info interface support for perf event kprobe link Implementing Info function (Link interface) for perf event kprobe link, it's now possibe to retrieve link's info with: info, err := link.Info() if err != nil { return err } pevent := info.PerfEvent() kp := pevent.Kprobe() At the moment we support/return only Addr and Missed fields. Signed-off-by: Jiri Olsa --- internal/sys/syscall.go | 4 ++++ link/link.go | 50 +++++++++++++++++++++++++++++++++++++++-- link/link_test.go | 10 +++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/internal/sys/syscall.go b/internal/sys/syscall.go index 4dd875270..410ca96df 100644 --- a/internal/sys/syscall.go +++ b/internal/sys/syscall.go @@ -103,6 +103,10 @@ func (i *KprobeMultiLinkInfo) info() (unsafe.Pointer, uint32) { return unsafe.Pointer(i), uint32(unsafe.Sizeof(*i)) } +func (i *KprobeLinkInfo) info() (unsafe.Pointer, uint32) { + return unsafe.Pointer(i), uint32(unsafe.Sizeof(*i)) +} + var _ Info = (*BtfInfo)(nil) func (i *BtfInfo) info() (unsafe.Pointer, uint32) { diff --git a/link/link.go b/link/link.go index 53bf7f5a7..3fcb7cb9e 100644 --- a/link/link.go +++ b/link/link.go @@ -200,6 +200,16 @@ type KprobeMultiInfo struct { Missed uint64 } +type PerfEventInfo struct { + PerfEventType sys.PerfEventType + extra interface{} +} + +type KprobeInfo struct { + Addr uint64 + Missed uint64 +} + // Tracing returns tracing type-specific link info. // // Returns nil if the type-specific link info isn't available. @@ -264,6 +274,19 @@ func (r Info) KprobeMulti() *KprobeMultiInfo { return e } +// PerfEvent returns perf-event type-specific link info. +// +// Returns nil if the type-specific link info isn't available. +func (r Info) PerfEvent() *PerfEventInfo { + e, _ := r.extra.(*PerfEventInfo) + return e +} + +func (r *PerfEventInfo) Kprobe() *KprobeInfo { + e, _ := r.extra.(*KprobeInfo) + return e +} + // RawLink is the low-level API to bpf_link. // // You should consider using the higher level interfaces in this @@ -439,8 +462,7 @@ func (l *RawLink) Info() (*Info, error) { extra = &XDPInfo{ Ifindex: xdpInfo.Ifindex, } - case RawTracepointType, IterType, - PerfEventType, UprobeMultiType: + case RawTracepointType, IterType, UprobeMultiType: // Extra metadata not supported. case TCXType: var tcxInfo sys.TcxLinkInfo @@ -487,6 +509,30 @@ func (l *RawLink) Info() (*Info, error) { Flags: kprobeMultiInfo.Flags, Missed: kprobeMultiInfo.Missed, } + case PerfEventType: + var kprobeInfo sys.KprobeLinkInfo + if err := sys.ObjInfo(l.fd, &kprobeInfo); err != nil { + return nil, fmt.Errorf("kprobe multi link info: %s", err) + } + var extra2 interface{} + + switch kprobeInfo.PerfEventType { + case KprobePerfEventInfoType, KretprobePerfEventInfoType: + // There's a gap between when perf link got introduced and + // when it supported link info interface. We can detect that + // with kprobe specific Addr field being zero. + if kprobeInfo.Addr == 0 { + return nil, fmt.Errorf("perf event link info: %w", ErrNotSupported) + } + extra2 = &KprobeInfo{ + Addr: kprobeInfo.Addr, + Missed: kprobeInfo.Missed, + } + } + extra = &PerfEventInfo{ + PerfEventType: kprobeInfo.PerfEventType, + extra: extra2, + } default: return nil, fmt.Errorf("unknown link info type: %d", info.Type) } diff --git a/link/link_test.go b/link/link_test.go index 61168ff0d..fb52d0066 100644 --- a/link/link_test.go +++ b/link/link_test.go @@ -281,6 +281,16 @@ func testLink(t *testing.T, link Link, prog *ebpf.Program) { if kmulti.Count == 0 { t.Fatalf("Failed to get link KprobeMulti extra info") } + case sys.BPF_LINK_TYPE_PERF_EVENT: + // test default Info data + pevent := info.PerfEvent() + switch pevent.PerfEventType { + case KprobePerfEventInfoType, KretprobePerfEventInfoType: + kp := pevent.Kprobe() + if kp.Addr == 0 { + t.Fatalf("Failed to get link Kprobe extra info") + } + } } })