Skip to content

Commit d932b39

Browse files
committed
fix: Combine two perf-events to one
It should use one perf-event to handle all tracing events to avoid concurrent issue. Signed-off-by: Leon Hwang <hffilwlqm@gmail.com>
1 parent a913db0 commit d932b39

File tree

11 files changed

+56
-176
lines changed

11 files changed

+56
-176
lines changed

bpf/vista.c

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ enum event_source {
139139
EVENT_SOURCE_SK = 1,
140140
EVENT_SOURCE_IPTABLES = 2,
141141
EVENT_SOURCE_TCP = 3,
142+
EVENT_SOURCE_PCAP = 4,
142143
};
143144

144145
struct event_t {
@@ -184,16 +185,9 @@ get_event(void) {
184185
return event;
185186
}
186187

187-
#define MAX_QUEUE_ENTRIES 10000
188-
struct {
189-
__uint(type, BPF_MAP_TYPE_QUEUE);
190-
__type(value, struct event_t);
191-
__uint(max_entries, MAX_QUEUE_ENTRIES);
192-
} events SEC(".maps");
193-
194188
struct {
195189
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
196-
} pcap_events SEC(".maps");
190+
} events SEC(".maps");
197191

198192
#define MAX_TRACK_SIZE 1024
199193
struct {
@@ -482,7 +476,7 @@ kprobe_skb(struct sk_buff *skb, struct pt_regs *ctx, bool has_get_func_ip,
482476
event->addr = has_get_func_ip ? bpf_get_func_ip(ctx) : PT_REGS_IP(ctx);
483477
event->type = EVENT_TYPE_KPROBE;
484478
event->source = EVENT_SOURCE_SKB;
485-
bpf_map_push_elem(&events, event, BPF_EXIST);
479+
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event));
486480

487481
return BPF_OK;
488482
}
@@ -571,12 +565,11 @@ set_skb_pcap_meta(struct sk_buff *skb, struct pcap_meta *pcap, int action, bool
571565

572566
static __always_inline void
573567
output_skb_pcap_event(struct sk_buff *skb, struct event_t *event, int action, bool is_fexit) {
574-
u64 flags;
575-
568+
event->source = EVENT_SOURCE_PCAP;
576569
set_skb_pcap_meta(skb, &event->pcap, action, is_fexit);
577570

578-
flags = (((u64) event->pcap.cap_len) << 32) | BPF_F_CURRENT_CPU;
579-
bpf_skb_output(skb, &pcap_events, flags, event, __sizeof_pcap_event);
571+
u64 flags = (((u64) event->pcap.cap_len) << 32) | BPF_F_CURRENT_CPU;
572+
bpf_skb_output(skb, &events, flags, event, __sizeof_pcap_event);
580573
}
581574

582575
static __noinline void
@@ -594,7 +587,7 @@ handle_tc_skb(struct sk_buff *skb, void *ctx, int action, bool is_fexit, const b
594587
event->source = EVENT_SOURCE_SKB;
595588

596589
if (!cfg->output_pcap) {
597-
bpf_map_push_elem(&events, event, BPF_EXIST);
590+
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event));
598591
return;
599592
}
600593

@@ -731,10 +724,11 @@ set_xdp_pcap_meta(struct xdp_buff *xdp, struct pcap_meta *pcap, u32 len, int act
731724

732725
static __always_inline void
733726
output_xdp_pcap_event(struct xdp_buff *xdp, struct event_t *event, u32 len, int action, bool is_fexit) {
727+
event->source = EVENT_SOURCE_PCAP;
734728
set_xdp_pcap_meta(xdp, &event->pcap, len, action, is_fexit);
735729

736730
u64 flags = (((u64) event->pcap.cap_len) << 32) | BPF_F_CURRENT_CPU;
737-
bpf_xdp_output(xdp, &pcap_events, flags, event, __sizeof_pcap_event);
731+
bpf_xdp_output(xdp, &events, flags, event, __sizeof_pcap_event);
738732
}
739733

740734
static __noinline void
@@ -759,7 +753,7 @@ handle_xdp_buff(struct xdp_buff *xdp, void *ctx, int verdict, bool is_fexit, con
759753
event->source = EVENT_SOURCE_SKB;
760754

761755
if (!cfg->output_pcap) {
762-
bpf_map_push_elem(&events, event, BPF_EXIST);
756+
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event));
763757
return;
764758
}
765759

@@ -854,7 +848,7 @@ ipt_do_table_exit(struct pt_regs *ctx, uint verdict) {
854848
event->addr = PT_REGS_IP(ctx);
855849
event->type = EVENT_TYPE_KPROBE;
856850
event->source = EVENT_SOURCE_IPTABLES;
857-
bpf_map_push_elem(&events, event, BPF_EXIST);
851+
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event));
858852

859853
return BPF_OK;
860854
}
@@ -1021,7 +1015,7 @@ kprobe_sk(struct sock *sk, struct pt_regs *ctx, const bool has_get_func_ip) {
10211015
event->addr = has_get_func_ip ? bpf_get_func_ip(ctx) : PT_REGS_IP(ctx);
10221016
event->type = EVENT_TYPE_KPROBE;
10231017
event->source = EVENT_SOURCE_SK;
1024-
bpf_map_push_elem(&events, event, BPF_EXIST);
1018+
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event));
10251019

10261020
return BPF_OK;
10271021
}
@@ -1117,7 +1111,7 @@ output_tcp(void *ctx, struct sock *sk, struct event_t *event) {
11171111
event->skb_addr = (u64) sk;
11181112
event->type = EVENT_TYPE_KPROBE;
11191113
event->source = EVENT_SOURCE_TCP;
1120-
bpf_map_push_elem(&events, event, BPF_EXIST);
1114+
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, event, sizeof(*event));
11211115
}
11221116

11231117
SEC("kprobe/tcp_connect")

internal/build/build.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33

44
package build
55

6+
//go:generate sh -c "echo Generating for $TARGET_GOARCH"
7+
68
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -no-global-types -target $TARGET_GOARCH -cc clang -no-strip VistaFeatures ../../bpf/features.c -- -I../../bpf/headers -Wno-address-of-packed-member
79

8-
//go:generate sh -c "echo Generating for $TARGET_GOARCH"
910
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -no-global-types -target $TARGET_GOARCH -cc clang -no-strip KProbeVista ../../bpf/vista.c -- -DOUTPUT_SKB -I../../bpf/headers -Wno-address-of-packed-member
1011
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -no-global-types -target $TARGET_GOARCH -cc clang -no-strip KProbeMultiVista ../../bpf/vista.c -- -DOUTPUT_SKB -DHAS_KPROBE_MULTI -I../../bpf/headers -Wno-address-of-packed-member
1112
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -no-global-types -target $TARGET_GOARCH -cc clang -no-strip KProbeVistaWithoutOutputSKB ../../bpf/vista.c -- -I../../bpf/headers -Wno-address-of-packed-member

internal/vista/flags.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ type Flags struct {
7777
ReadyFile string
7878

7979
KprobeBackend string
80+
81+
PerCPUBuffer uint
8082
}
8183

8284
func (f *Flags) SetFlags() {
@@ -122,6 +124,8 @@ func (f *Flags) SetFlags() {
122124
flag.StringVar(&f.KprobeBackend, "kprobe-backend", "",
123125
fmt.Sprintf("Tracing backend('%s', '%s'). Will auto-detect if not specified.", BackendKprobe, BackendKprobeMulti))
124126

127+
flag.UintVar(&f.PerCPUBuffer, "output-percpu-buffer", 8192, "specified the buffer size for perf-event")
128+
125129
flag.StringVar(&f.FilterProto, "filter-protocol", "", "filter protocol, tcp, udp, icmp, empty for any")
126130
flag.StringVar(&f.FilterAddr, "filter-addr", "", "filter IP address")
127131
flag.Uint16Var(&f.FilterPort, "filter-port", 0, "filter port")

internal/vista/output.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ const (
2929
eventSourceSk = 1
3030
eventSourceIptables = 2
3131
eventSourceTCP = 3
32+
eventSourcePcap = 4
3233
)
3334

34-
type output struct {
35+
type Output struct {
3536
flags *Flags
3637
lastSeenSkb map[uint64]uint64 // skb addr => last seen TS
3738
printSkbMap *ebpf.Map
@@ -47,7 +48,7 @@ type output struct {
4748

4849
func NewOutput(flags *Flags, printSkbMap *ebpf.Map, printStackMap *ebpf.Map,
4950
addr2Name Addr2Name, kprobeMulti bool, btfSpec *btf.Spec,
50-
) (*output, error) {
51+
) (*Output, error) {
5152
writer := os.Stdout
5253

5354
if flags.OutputFile != "" {
@@ -79,7 +80,7 @@ func NewOutput(flags *Flags, printSkbMap *ebpf.Map, printStackMap *ebpf.Map,
7980
}
8081
}
8182

82-
return &output{
83+
return &Output{
8384
flags: flags,
8485
lastSeenSkb: map[uint64]uint64{},
8586
printSkbMap: printSkbMap,
@@ -94,7 +95,7 @@ func NewOutput(flags *Flags, printSkbMap *ebpf.Map, printStackMap *ebpf.Map,
9495
}, nil
9596
}
9697

97-
func (o *output) Close() {
98+
func (o *Output) Close() {
9899
if o.writer != os.Stdout {
99100
_ = o.writer.Sync()
100101
_ = o.writer.Close()
@@ -105,7 +106,7 @@ func (o *output) Close() {
105106
}
106107
}
107108

108-
func (o *output) PrintHeader() {
109+
func (o *Output) PrintHeader() {
109110
if o.flags.outputTs == outputTimestampAbsolute {
110111
fmt.Fprintf(o.buf, "%12s ", "TIME")
111112
}
@@ -120,7 +121,7 @@ func (o *output) PrintHeader() {
120121
o.buf.Reset()
121122
}
122123

123-
func (o *output) print(event *Event) {
124+
func (o *Output) print(event *Event) {
124125
if o.flags.outputTs == outputTimestampAbsolute {
125126
fmt.Fprintf(o.buf, "%12s ", time.Now().Format(absoluteTS))
126127
}
@@ -193,20 +194,20 @@ func (o *output) print(event *Event) {
193194
}
194195
}
195196

196-
func (o *output) flushBuffer() {
197+
func (o *Output) flushBuffer() {
197198
fmt.Fprintln(o.writer, o.buf.String())
198199

199200
o.buf.Reset()
200201
}
201202

202-
func (o *output) Print(event *Event) {
203-
o.print(event)
203+
func (o *Output) Print(ev OutputEvent) {
204+
o.print(ev.Event)
204205
o.flushBuffer()
205206
}
206207

207-
func (o *output) Pcap(ev OutputEvent) error {
208+
func (o *Output) Pcap(ev OutputEvent) error {
208209
o.print(ev.Event)
209-
fmt.Fprintf(o.buf, "Saving this packet to %s..", o.flags.PcapFile)
210+
fmt.Fprintf(o.buf, "\nSaving this packet to %s..", o.flags.PcapFile)
210211
o.flushBuffer()
211212

212213
iface := o.getIfaceName(ev.Event.Meta.Netns, ev.Event.Meta.Ifindex)

internal/vista/output_event.go

Lines changed: 4 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ package vista
66
import (
77
"fmt"
88
"unsafe"
9-
10-
"golang.org/x/sync/errgroup"
119
)
1210

1311
type OutputEvent struct {
@@ -16,11 +14,14 @@ type OutputEvent struct {
1614
IsPcap bool
1715
}
1816

19-
func NewOutputEvent(raw []byte, isPcap bool) (OutputEvent, error) {
17+
func NewOutputEvent(raw []byte) (OutputEvent, error) {
2018
if len(raw) == 0 {
2119
return OutputEvent{}, fmt.Errorf("empty packet")
2220
}
2321

22+
event := (*Event)(unsafe.Pointer(&raw[0]))
23+
isPcap := event.Source == eventSourcePcap
24+
2425
size := sizeofEvent
2526
if isPcap {
2627
size = sizeofPcapEvent
@@ -30,8 +31,6 @@ func NewOutputEvent(raw []byte, isPcap bool) (OutputEvent, error) {
3031
return OutputEvent{}, fmt.Errorf("record too short: %d < %d", len(raw), size)
3132
}
3233

33-
event := (*Event)(unsafe.Pointer(&raw[0]))
34-
3534
if !isPcap {
3635
return OutputEvent{Event: event}, nil
3736
}
@@ -46,51 +45,3 @@ func NewOutputEvent(raw []byte, isPcap bool) (OutputEvent, error) {
4645

4746
return OutputEvent{Event: event, Packet: data, IsPcap: true}, nil
4847
}
49-
50-
type EventChannels struct {
51-
chs []chan OutputEvent
52-
53-
out chan OutputEvent
54-
}
55-
56-
func NewEventChannels(chs ...chan OutputEvent) *EventChannels {
57-
e := &EventChannels{
58-
chs: chs,
59-
out: make(chan OutputEvent, 100),
60-
}
61-
62-
go e.run()
63-
64-
return e
65-
}
66-
67-
func (e *EventChannels) RecvChan() <-chan OutputEvent {
68-
return e.out
69-
}
70-
71-
func (e *EventChannels) Drain() {
72-
for range e.out {
73-
}
74-
}
75-
76-
func (e *EventChannels) runChan(ch chan OutputEvent) {
77-
for ev := range ch {
78-
e.out <- ev
79-
}
80-
}
81-
82-
func (e *EventChannels) run() {
83-
var errg errgroup.Group
84-
85-
for _, ch := range e.chs {
86-
ch := ch
87-
errg.Go(func() error {
88-
e.runChan(ch)
89-
return nil
90-
})
91-
}
92-
93-
_ = errg.Wait()
94-
95-
close(e.out)
96-
}

internal/vista/output_func.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"runtime"
99
)
1010

11-
func (o *output) getFuncName(event *Event) string {
11+
func (o *Output) getFuncName(event *Event) string {
1212
var outFuncName string
1313

1414
switch event.Source {

internal/vista/output_iface.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ func getIfacesInNetNs(path string) (map[uint32]string, error) {
107107
return ifaces, nil
108108
}
109109

110-
func (o *output) getIfaceName(netnsInode, ifindex uint32) string {
110+
func (o *Output) getIfaceName(netnsInode, ifindex uint32) string {
111111
if ifaces, ok := o.ifaceCache[uint64(netnsInode)]; ok {
112112
if name, ok := ifaces[ifindex]; ok {
113113
return fmt.Sprintf("%d(%s)", ifindex, name)

internal/vista/output_process.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"github.com/tklauser/ps"
1010
)
1111

12-
func (o *output) getProcessExecName(event *Event) string {
12+
func (o *Output) getProcessExecName(event *Event) string {
1313
var execName string
1414
if event.PID != 0 {
1515
if event.Source != eventSourceTCP {

internal/vista/output_tcp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,6 @@ func outputTCP(w io.Writer, tcp *TCPMeta) {
5959
time.Microsecond*time.Duration(tcp.Srtt), tcp.Retrans, tcp.SkMark,
6060
nullStr(tcp.Cong[:]))
6161
if tcp.Reset != 0 {
62-
fmt.Fprintf(w, " reset=%s", tcp.Reset)
62+
fmt.Fprintf(w, " reset=%d", tcp.Reset)
6363
}
6464
}

internal/vista/tracing.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func (t *tracing) traceProg(options *TracingOptions, prog *ebpf.Program, fentryN
169169
func (t *tracing) trace(options *TracingOptions, fentryName, fexitName, fentryPcap, fexitPcap string) error {
170170
progs, err := listBpfProgs(options.progType)
171171
if err != nil {
172-
log.Fatalf("failed to list bpf progs: %w", err)
172+
log.Fatalf("failed to list bpf progs: %v", err)
173173
}
174174
defer func() {
175175
for _, p := range progs {
@@ -197,9 +197,6 @@ func (t *tracing) trace(options *TracingOptions, fentryName, fexitName, fentryPc
197197
if options.OutputSkb {
198198
replacedMaps["print_skb_map"] = options.Coll.Maps["print_skb_map"]
199199
}
200-
if options.Pcap {
201-
replacedMaps["pcap_events"] = options.Coll.Maps["pcap_events"]
202-
}
203200
options.Opts.MapReplacements = replacedMaps
204201

205202
t.links = make([]link.Link, 0, len(progs)*2)

0 commit comments

Comments
 (0)