协议栈是如何调用xdp程序处理报文的

函数调用栈

以xdp SKB模式为例,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
--> bpf_prog_run_generic_xdp
--> --> bpf_prog_run_xdp
--> --> --> u32 act = __bpf_prog_run(prog, xdp, BPF_DISPATCHER_FUNC(xdp));
展开BPF_DISPATCHER_FUNC(xdp), 相当于
u32 act = __bpf_prog_run(prog, xdp, bpf_dispatcher_xdp_func));
--> --> --> --> ret = dfunc(ctx, prog->insnsi, prog->bpf_func);
这里的dfun是`__bpf_prog_run`的第三个参数,因此相当于
ret = bpf_dispatcher_xdp_func(ctx, prog->insnsi, prog->bpf_func); <== 这里的第三个函数就是我们之前提到的,当bpf程序被加载时候,在bpf_prog结构体保存的bpf_func。
--> --> --> --> --> return __BPF_DISPATCHER_CALL(name); <== 根据bpf_dispatcher_xdp_func的定义
展开__BPF_DISPATCHER_CALL,相当于
bpf_func(ctx, insnsi) <=== **这里很有意思**,bpf_fun, ctx, insnsi分别代表bpf_dispatcher_xdp_func的三个函数入口参数,
根据顺序依次为 第三个,第一个,第二个,按照这个顺序展开
prog->bpf_func(ctx, prog->insnsi); <== 至此,就把我们上面一节里总结的`prog->bpf_func`这个函数指针用上了。
最终这个函数根据不同stacksize入口函数的包装,调用到
--> --> --> --> --> --> ___bpf_prog_run(ctx, prog->insnsi)

XDP 函数入口调用顺序

BPF_DISPATCHER_FUNC

BPF_DISPATCHER_FUNC(xdp)相当于:bpf_dispatcher_xdp_func

1
1270 #define BPF_DISPATCHER_FUNC(name) bpf_dispatcher_##name##_func

bpf_dispatcher_xdp_func的定义

bpf_dispatcher_xdp_func这个函数直接用grep命令是找不到函数定义的。
这个函数的定义是通过宏DEFINE_BPF_DISPATCHER实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
1519 DEFINE_BPF_DISPATCHER(xdp)
1250 #define DEFINE_BPF_DISPATCHER(name) \
1251 __BPF_DISPATCHER_SC(name); \
1252 noinline __nocfi unsigned int bpf_dispatcher_##name##_func( \ <== 此函数相当于bpf_dispatcher_xdp(ctx, prog->insnsi, prog->bpf_func)
1253 const void *ctx, \
1254 const struct bpf_insn *insnsi, \
1255 bpf_func_t bpf_func) \
1256 { \
1257 return __BPF_DISPATCHER_CALL(name); \ <== 此处相当于 prog->bpf_func, 参数只在static call场景下有用(ctx, prog->insnsi)
1258 } \
1259 EXPORT_SYMBOL(bpf_dispatcher_##name##_func); \
1260 struct bpf_dispatcher bpf_dispatcher_##name = \
1261 BPF_DISPATCHER_INIT(bpf_dispatcher_##name);

__BPF_DISPATCHER_CALL

为了便于理解,我们使用非static call的场景

1
1232 #define __BPF_DISPATCHER_CALL(name)             bpf_func(ctx, insnsi)

至于static call场景,目前没有遇到,看起来跟xdp管理不大,暂时先不分析了 :(

1
2
1223 #define __BPF_DISPATCHER_CALL(name)                             \
1224 static_call(bpf_dispatcher_##name##_call)(ctx, insnsi, bpf_func)