From f508e5801632f5264528d8c3d6f9493012be9b9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20G=C3=B6gge?= Date: Mon, 15 Apr 2024 22:14:42 +0200 Subject: [PATCH] link: add Info() method to all link types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Robin Gögge --- link/cgroup.go | 19 ++++++++ link/kprobe_multi.go | 19 ++++++++ link/link.go | 113 +++---------------------------------------- link/netfilter.go | 20 ++++++++ link/netkit.go | 18 +++++++ link/netns.go | 19 ++++++++ link/perf_event.go | 32 ++++++++++++ link/tcx.go | 18 +++++++ link/tracing.go | 19 ++++++++ link/xdp.go | 24 ++++++++- 10 files changed, 193 insertions(+), 108 deletions(-) diff --git a/link/cgroup.go b/link/cgroup.go index 79f3d2b7f..f17d34f03 100644 --- a/link/cgroup.go +++ b/link/cgroup.go @@ -6,6 +6,7 @@ import ( "os" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal/sys" ) type cgroupAttachFlags uint32 @@ -187,3 +188,21 @@ func newLinkCgroup(cgroup *os.File, attach ebpf.AttachType, prog *ebpf.Program) return &linkCgroup{*link}, err } + +func (cg *linkCgroup) Info() (*Info, error) { + var info sys.CgroupLinkInfo + if err := sys.ObjInfo(cg.fd, &info); err != nil { + return nil, fmt.Errorf("cgroup link info: %s", err) + } + extra := &CgroupInfo{ + CgroupId: info.CgroupId, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} diff --git a/link/kprobe_multi.go b/link/kprobe_multi.go index 4d364d80e..850c5f8b5 100644 --- a/link/kprobe_multi.go +++ b/link/kprobe_multi.go @@ -138,6 +138,25 @@ func (kml *kprobeMultiLink) Unpin() error { return fmt.Errorf("unpin kprobe_multi: %w", ErrNotSupported) } +func (kml *kprobeMultiLink) Info() (*Info, error) { + var info sys.KprobeMultiLinkInfo + if err := sys.ObjInfo(kml.fd, &info); err != nil { + return nil, fmt.Errorf("kprobe multi link info: %s", err) + } + extra := &KprobeMultiInfo{ + count: info.Count, + flags: info.Flags, + missed: info.Missed, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} + var haveBPFLinkKprobeMulti = internal.NewFeatureTest("bpf_link_kprobe_multi", "5.18", func() error { prog, err := ebpf.NewProgram(&ebpf.ProgramSpec{ Name: "probe_kpm_link", diff --git a/link/link.go b/link/link.go index 81428568f..9e8ca49c6 100644 --- a/link/link.go +++ b/link/link.go @@ -126,6 +126,8 @@ func wrapRawLink(raw *RawLink) (_ Link, err error) { return &netfilterLink{*raw}, nil case NetkitType: return &netkitLink{*raw}, nil + case XDPType: + return &xdpLink{*raw}, nil default: return raw, nil } @@ -438,6 +440,9 @@ func (l *RawLink) UpdateArgs(opts RawLinkUpdateOptions) error { } // Info returns metadata about the link. +// +// Linktype specific metadata is not included and can be retrieved +// via the linktype specific Info() method. func (l *RawLink) Info() (*Info, error) { var info sys.LinkInfo @@ -445,117 +450,11 @@ func (l *RawLink) Info() (*Info, error) { return nil, fmt.Errorf("link info: %s", err) } - var extra interface{} - switch info.Type { - case CgroupType: - var cgroupInfo sys.CgroupLinkInfo - if err := sys.ObjInfo(l.fd, &cgroupInfo); err != nil { - return nil, fmt.Errorf("cgroup link info: %s", err) - } - extra = &CgroupInfo{ - CgroupId: cgroupInfo.CgroupId, - AttachType: cgroupInfo.AttachType, - } - case NetNsType: - var netnsInfo sys.NetNsLinkInfo - if err := sys.ObjInfo(l.fd, &netnsInfo); err != nil { - return nil, fmt.Errorf("netns link info: %s", err) - } - extra = &NetNsInfo{ - NetnsIno: netnsInfo.NetnsIno, - AttachType: netnsInfo.AttachType, - } - case TracingType: - var tracingInfo sys.TracingLinkInfo - if err := sys.ObjInfo(l.fd, &tracingInfo); err != nil { - return nil, fmt.Errorf("tracing link info: %s", err) - } - extra = &TracingInfo{ - TargetObjId: tracingInfo.TargetObjId, - TargetBtfId: tracingInfo.TargetBtfId, - AttachType: tracingInfo.AttachType, - } - case XDPType: - var xdpInfo sys.XDPLinkInfo - if err := sys.ObjInfo(l.fd, &xdpInfo); err != nil { - return nil, fmt.Errorf("xdp link info: %s", err) - } - extra = &XDPInfo{ - Ifindex: xdpInfo.Ifindex, - } - case RawTracepointType, IterType, UprobeMultiType: - // Extra metadata not supported. - case TCXType: - var tcxInfo sys.TcxLinkInfo - if err := sys.ObjInfo(l.fd, &tcxInfo); err != nil { - return nil, fmt.Errorf("tcx link info: %s", err) - } - extra = &TCXInfo{ - Ifindex: tcxInfo.Ifindex, - AttachType: tcxInfo.AttachType, - } - case NetfilterType: - var netfilterInfo sys.NetfilterLinkInfo - if err := sys.ObjInfo(l.fd, &netfilterInfo); err != nil { - return nil, fmt.Errorf("netfilter link info: %s", err) - } - extra = &NetfilterInfo{ - Pf: netfilterInfo.Pf, - Hooknum: netfilterInfo.Hooknum, - Priority: netfilterInfo.Priority, - Flags: netfilterInfo.Flags, - } - case NetkitType: - var netkitInfo sys.NetkitLinkInfo - if err := sys.ObjInfo(l.fd, &netkitInfo); err != nil { - return nil, fmt.Errorf("tcx link info: %s", err) - } - extra = &NetkitInfo{ - Ifindex: netkitInfo.Ifindex, - AttachType: netkitInfo.AttachType, - } - case KprobeMultiType: - var kprobeMultiInfo sys.KprobeMultiLinkInfo - if err := sys.ObjInfo(l.fd, &kprobeMultiInfo); err != nil { - return nil, fmt.Errorf("kprobe multi link info: %s", err) - } - extra = &KprobeMultiInfo{ - count: kprobeMultiInfo.Count, - flags: kprobeMultiInfo.Flags, - missed: kprobeMultiInfo.Missed, - } - case PerfEventType: - var perfEventInfo sys.PerfEventLinkInfo - if err := sys.ObjInfo(l.fd, &perfEventInfo); err != nil { - return nil, fmt.Errorf("perf event link info: %s", err) - } - - var extra2 interface{} - switch perfEventInfo.PerfEventType { - case sys.BPF_PERF_EVENT_KPROBE, sys.BPF_PERF_EVENT_KRETPROBE: - var kprobeInfo sys.KprobeLinkInfo - if err := sys.ObjInfo(l.fd, &kprobeInfo); err != nil { - return nil, fmt.Errorf("kprobe multi link info: %s", err) - } - extra2 = &KprobeInfo{ - address: kprobeInfo.Addr, - missed: kprobeInfo.Missed, - } - } - - extra = &PerfEventInfo{ - Type: perfEventInfo.PerfEventType, - extra: extra2, - } - default: - return nil, fmt.Errorf("unknown link info type: %d", info.Type) - } - return &Info{ info.Type, info.Id, ebpf.ProgramID(info.ProgId), - extra, + nil, }, nil } diff --git a/link/netfilter.go b/link/netfilter.go index 250c87677..34be39085 100644 --- a/link/netfilter.go +++ b/link/netfilter.go @@ -67,4 +67,24 @@ func (*netfilterLink) Update(new *ebpf.Program) error { return fmt.Errorf("netfilter update: %w", ErrNotSupported) } +func (nf *netfilterLink) Info() (*Info, error) { + var info sys.NetfilterLinkInfo + if err := sys.ObjInfo(nf.fd, &info); err != nil { + return nil, fmt.Errorf("netfilter link info: %s", err) + } + extra := &NetfilterInfo{ + Pf: info.Pf, + Hooknum: info.Hooknum, + Priority: info.Priority, + Flags: info.Flags, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} + var _ Link = (*netfilterLink)(nil) diff --git a/link/netkit.go b/link/netkit.go index 36ed72a48..5eee3b023 100644 --- a/link/netkit.go +++ b/link/netkit.go @@ -69,3 +69,21 @@ type netkitLink struct { } var _ Link = (*netkitLink)(nil) + +func (netkit *netkitLink) Info() (*Info, error) { + var info sys.NetkitLinkInfo + if err := sys.ObjInfo(netkit.fd, &info); err != nil { + return nil, fmt.Errorf("netkit link info: %s", err) + } + extra := &NetkitInfo{ + Ifindex: info.Ifindex, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} diff --git a/link/netns.go b/link/netns.go index 344ecced6..b1edd340a 100644 --- a/link/netns.go +++ b/link/netns.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal/sys" ) // NetNsLink is a program attached to a network namespace. @@ -34,3 +35,21 @@ func AttachNetNs(ns int, prog *ebpf.Program) (*NetNsLink, error) { return &NetNsLink{*link}, nil } + +func (ns *NetNsLink) Info() (*Info, error) { + var info sys.NetNsLinkInfo + if err := sys.ObjInfo(ns.fd, &info); err != nil { + return nil, fmt.Errorf("netns link info: %s", err) + } + extra := &NetNsInfo{ + NetnsIno: info.NetnsIno, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} diff --git a/link/perf_event.go b/link/perf_event.go index bb96d4a92..89eab233b 100644 --- a/link/perf_event.go +++ b/link/perf_event.go @@ -144,6 +144,38 @@ func (pl *perfEventLink) PerfEvent() (*os.File, error) { return fd.File("perf-event"), nil } +func (pl *perfEventLink) Info() (*Info, error) { + var info sys.PerfEventLinkInfo + if err := sys.ObjInfo(pl.fd, &info); err != nil { + return nil, fmt.Errorf("perf event link info: %s", err) + } + + var extra2 interface{} + switch info.PerfEventType { + case sys.BPF_PERF_EVENT_KPROBE, sys.BPF_PERF_EVENT_KRETPROBE: + var kprobeInfo sys.KprobeLinkInfo + if err := sys.ObjInfo(pl.fd, &kprobeInfo); err != nil { + return nil, fmt.Errorf("kprobe link info: %s", err) + } + extra2 = &KprobeInfo{ + address: kprobeInfo.Addr, + missed: kprobeInfo.Missed, + } + } + + extra := &PerfEventInfo{ + Type: info.PerfEventType, + extra: extra2, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} + // perfEventIoctl implements Link and handles the perf event lifecycle // via ioctl(). type perfEventIoctl struct { diff --git a/link/tcx.go b/link/tcx.go index 88f2237d2..ac045b71d 100644 --- a/link/tcx.go +++ b/link/tcx.go @@ -69,3 +69,21 @@ type tcxLink struct { } var _ Link = (*tcxLink)(nil) + +func (tcx *tcxLink) Info() (*Info, error) { + var info sys.TcxLinkInfo + if err := sys.ObjInfo(tcx.fd, &info); err != nil { + return nil, fmt.Errorf("tcx link info: %s", err) + } + extra := &TCXInfo{ + Ifindex: info.Ifindex, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} diff --git a/link/tracing.go b/link/tracing.go index 1e1a7834d..9e570afc9 100644 --- a/link/tracing.go +++ b/link/tracing.go @@ -18,6 +18,25 @@ func (f *tracing) Update(new *ebpf.Program) error { return fmt.Errorf("tracing update: %w", ErrNotSupported) } +func (f *tracing) Info() (*Info, error) { + var info sys.TracingLinkInfo + if err := sys.ObjInfo(f.fd, &info); err != nil { + return nil, fmt.Errorf("tracing link info: %s", err) + } + extra := &TracingInfo{ + TargetObjId: info.TargetObjId, + TargetBtfId: info.TargetBtfId, + AttachType: info.AttachType, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil +} + // AttachFreplace attaches the given eBPF program to the function it replaces. // // The program and name can either be provided at link time, or can be provided diff --git a/link/xdp.go b/link/xdp.go index aa8dd3a4c..dbfa52996 100644 --- a/link/xdp.go +++ b/link/xdp.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/cilium/ebpf" + "github.com/cilium/ebpf/internal/sys" ) // XDPAttachFlags represents how XDP program will be attached to interface. @@ -50,5 +51,26 @@ func AttachXDP(opts XDPOptions) (Link, error) { Flags: uint32(opts.Flags), }) - return rawLink, err + return &xdpLink{*rawLink}, err +} + +type xdpLink struct { + RawLink +} + +func (xdp *xdpLink) Info() (*Info, error) { + var info sys.XDPLinkInfo + if err := sys.ObjInfo(xdp.fd, &info); err != nil { + return nil, fmt.Errorf("xdp link info: %s", err) + } + extra := &XDPInfo{ + Ifindex: info.Ifindex, + } + + return &Info{ + info.Type, + info.Id, + ebpf.ProgramID(info.ProgId), + extra, + }, nil }