Skip to content

Commit 093495d

Browse files
committed
nettrace: kfree_skb function call strack backtrace support
Add the new argument '--drop-stack' to print the call stack of kfree_skb(). Signed-off-by: Menglong Dong <imagedong@tencent.com>
1 parent 32e544d commit 093495d

12 files changed

Lines changed: 139 additions & 9 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ Usage:
153153
--diag-keep don't quit when abnormal packet found
154154
--hooks print netfilter hooks if dropping by netfilter
155155
--drop skb drop monitor mode, for replace of 'droptrace'
156+
--drop-stack print the kernel function call stack of kfree_skb
156157
157158
-v show log information
158159
--debug show debug information
@@ -171,6 +172,7 @@ Usage:
171172
- `diag-keep`:持续跟踪。`diag`模式下,默认在跟踪到异常报文后会停止跟踪,使用该参数后,会持续跟踪下去。
172173
- `hooks`:结合netfilter做的适配,详见下文
173174
- `drop`:进行系统丢包监控,取代原先的`droptrace`
175+
- `drop-stack`: 打印kfree_skb内核函数的调用堆栈
174176
175177
下面我们首先来看一下默认模式下的工具使用方法。
176178

script/bash-completion.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
complete -W '-s --saddr --saddr6 -d --daddr --daddr6 --addr --addr6 -p -D --dport -S --sport -P --port --pid -t --trace -v --detail --debug --ret --basic --diag --diag-quiet --diag-keep --date --drop --hooks -h --help' nettrace
1+
complete -W '-s --saddr --saddr6 -d --daddr --daddr6 --addr --addr6 -p -D --dport -S --sport -P --port --pid -t --trace -v --detail --debug --ret --basic --diag --diag-quiet --diag-keep --date --drop --drop-stack --hooks -h --help' nettrace
22
complete -W '-h -s -d --addr -p --dport --sport --port -t -v --detail --stack --stack-tracer --timeline -c --ret --skb-mode --force-stack --tcp-flags -o --output' nettrace-legacy

shared/bpf/skb_shared.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,9 @@ typedef struct {
7979

8080
#define CONFIG_MAP_SIZE 1024
8181

82+
#ifndef PERF_MAX_STACK_DEPTH
83+
#define PERF_MAX_STACK_DEPTH 127
84+
#endif
85+
typedef __u64 stack_trace_t[PERF_MAX_STACK_DEPTH];
86+
8287
#endif

src/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ kprobe_gen_cmd = @make BPF_CFLAGS="$(BPF_CFLAGS) $(1)" \
2525
mv progs/kprobe.skel.h progs/$(2).skel.h
2626

2727
ifndef COMPAT
28+
CFLAGS += -DSTACK_TRACE
2829
$(bpf_progs_ext):
2930
rm -rf progs/kprobe*.skel.h
3031
$(call kprobe_gen_cmd,-DCORE_FULL,kprobe_core)
3132
make progs/kprobe.skel.h
3233
else
34+
ifneq ($(shell grep -c get_stackid $(HEADERS)/include/uapi/linux/bpf.h),0)
35+
CFLAGS += -DSTACK_TRACE
36+
endif
3337
$(bpf_progs_ext): %: %.skel.h
3438
@:
3539
endif

src/analysis.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,14 @@ static void analy_entry_handle(analy_entry_t *entry)
142142
{
143143
packet_t *pkt = &entry->event->pkt;
144144
static char buf[1024], tinfo[128];
145+
event_t *e = entry->event;
145146
rule_t *rule;
146147
trace_t *t;
147148

148149
t = get_trace_from_analy_entry(entry);
149150
pr_debug("output entry(%llx)\n", PTR2X(entry));
150151
if (trace_ctx.detail) {
151-
detail_event_t *detail = (void *)entry->event;
152+
detail_event_t *detail = (void *)e;
152153
static char ifbuf[IF_NAMESIZE];
153154
char *ifname = detail->ifname;
154155

@@ -195,6 +196,8 @@ static void analy_entry_handle(analy_entry_t *entry)
195196
}
196197
out:
197198
pr_info("%s\n", buf);
199+
if (trace_is_stack(t))
200+
trace_ctx.ops->print_stack(e->stack_id);
198201
}
199202

200203
static void analy_ctx_free(analy_ctx_t *ctx)

src/gen_trace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def gen_group_init(group, name):
4949

5050
global_status = {}
5151
global_names = {}
52-
global_status['trace_index'] = 0
52+
global_status['trace_index'] = 1
5353

5454
rule_levels = {
5555
'info': 'RULE_INFO',

src/nettrace.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ static void do_parse_args(int argc, char *argv[])
7878
.type = OPTION_BOOL,
7979
.desc = "skb drop monitor mode, for replace of 'droptrace'",
8080
},
81+
#ifdef STACK_TRACE
82+
{
83+
.lname = "drop-stack", .dest = &trace_args->drop_stack,
84+
.type = OPTION_BOOL,
85+
.desc = "print the kernel function call stack of kfree_skb",
86+
},
87+
#endif
8188
{ .type = OPTION_BLANK },
8289
{
8390
.sname = 'v', .dest = &show_log,

src/progs/kprobe.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ struct {
1919
__uint(max_entries, TRACE_MAX);
2020
} m_ret SEC(".maps");
2121

22+
#ifdef STACK_TRACE
23+
struct {
24+
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
25+
__uint(max_entries, 16384);
26+
__uint(key_size, sizeof(__u32));
27+
__uint(value_size, sizeof(stack_trace_t));
28+
} m_stack SEC(".maps");
29+
#endif
30+
2231
#ifdef KERN_VER
2332
__u32 kern_ver SEC("version") = KERN_VER;
2433
#endif
@@ -64,8 +73,38 @@ static try_inline int put_ret(int func)
6473
return 0;
6574
}
6675

67-
static try_inline int handle_entry(void *regs, struct sk_buff *skb, event_t *e,
68-
int size, int func)
76+
#ifdef STACK_TRACE
77+
static try_inline void try_trace_stack(void *regs, bpf_args_t *bpf_args,
78+
event_t *e, int func)
79+
{
80+
int i = 0, key;
81+
u16 *funcs;
82+
83+
if (!ARGS_GET(stack))
84+
return;
85+
86+
funcs = ARGS_GET(stack_funs);
87+
88+
#pragma unroll
89+
for (; i < MAX_FUNC_STACK; i++) {
90+
if (!funcs[i])
91+
break;
92+
if (funcs[i] == func)
93+
goto do_stack;
94+
}
95+
return;
96+
97+
do_stack:
98+
key = bpf_get_stackid(regs, &m_stack, 0);
99+
e->stack_id = key;
100+
}
101+
#else
102+
static try_inline void try_trace_stack(void *regs, bpf_args_t *bpf_args,
103+
event_t *e, int func) { }
104+
#endif
105+
106+
static try_inline int handle_entry(void *regs, struct sk_buff *skb,
107+
event_t *e, int size, int func)
69108
{
70109
packet_t *pkt = &e->pkt;
71110
bool *matched;
@@ -111,6 +150,7 @@ static try_inline int handle_entry(void *regs, struct sk_buff *skb, event_t *e,
111150
}
112151

113152
out:
153+
try_trace_stack(regs, bpf_args, e, func);
114154
pkt->ts = bpf_ktime_get_ns();
115155
e->key = (u64)(void *)skb;
116156

@@ -129,8 +169,8 @@ static try_inline int handle_destroy(struct sk_buff *skb)
129169
}
130170

131171
static try_inline int default_handle_entry(struct pt_regs *ctx,
132-
struct sk_buff *skb,
133-
int func)
172+
struct sk_buff *skb,
173+
int func)
134174
{
135175
if (ARGS_GET_CONFIG(detail)) {
136176
detail_event_t e = { .func = func };

src/progs/shared.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef _H_PROGS_SHARED
22
#define _H_PROGS_SHARED
33

4+
#define MAX_FUNC_STACK 16
5+
46
#define DEFINE_BPF_ARGS() \
57
u32 trace_mode; \
68
u32 pid; \
@@ -10,14 +12,19 @@
1012
bool detail; \
1113
bool hooks; \
1214
bool ready; \
13-
bool nft_high;
15+
bool nft_high; \
16+
bool stack; \
17+
u16 stack_funs[MAX_FUNC_STACK];
1418

1519
#include <skb_shared.h>
1620

1721
typedef struct __attribute__((__packed__)) {
1822
packet_t pkt;
1923
u64 key;
2024
u32 func;
25+
#ifdef STACK_TRACE
26+
u32 stack_id;
27+
#endif
2128
} event_t;
2229

2330
typedef struct __attribute__((__packed__)) {

src/trace.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ static int trace_prepare_args()
198198
if (args->drop) {
199199
trace_ctx.mode = TRACE_MODE_DROP;
200200
traces = "kfree_skb";
201+
} else if (args->drop_stack) {
202+
pr_err("--drop should be set!\n");
203+
goto err;
201204
}
202205

203206
if (!traces) {
@@ -244,11 +247,17 @@ static int trace_prepare_args()
244247
trace_group_enable("life");
245248
break;
246249
case TRACE_MODE_BASIC:
247-
case TRACE_MODE_DROP:
250+
case TRACE_MODE_DROP: {
251+
trace_t *drop_trace = search_trace_enabled(traces);
252+
248253
if (!trace_ctx.drop_reason)
249254
pr_warn("skb drop reason is not support by your kernel"
250255
", drop reason will not be printed\n");
256+
257+
if (args->drop_stack && trace_set_stack(drop_trace))
258+
goto err;
251259
break;
260+
}
252261
default:
253262
goto err;
254263
}

0 commit comments

Comments
 (0)