XDP framework
xdp在内核里的有三个关键步骤:
load
: 加载到内核
attach
: 绑定到一个网口
run
:网口收包时候,调用并执行bpf prog
load
加载: 通过ebpf系统调用, 把prog加载到内核
fd = sys_bpf(BPF_PROG_LOAD, attr, size);
- 在内核里创建一个
bfp_prog
结构体用以存储bpf prog。
- 通过
bpf_check
检查prog程序的安全性和合法性。
- 通过
bpf_prog_select_runtime
指定bpf prog对应的执行函数
- 这个函数指针保存在
bpf_func
这个字段里。这里的function最终指向通用的bfp run函数___bpf_prog_run
。
关于___bpf_prog_run
这个具体封装和实现见另外一篇文章。
attach
绑定: 将prog程序绑定到一个特定的网口的struct net_device
上
libpf函数do_attach
将上一步加载在内核里的prog跟一个网口绑定, 具体实现是通过下发netlink命令。
这是个generic类型的netlink命令,最终通过dev_change_xdp_fd
将prog挂载到对应netdev下面。
1 2 3 4 5 6
| 2056 struct net_device { 2057 char name[IFNAMSIZ]; 2058 struct netdev_name_node *name_node; 2059 struct dev_ifalias __rcu *ifalias; ... 2234 struct bpf_prog __rcu *xdp_prog;
|
struct net_device
下的xdp_prog
指向对应的prog
注意这里的加载分skb模式和DRV驱动模式。 驱动模式是加载到网卡驱动里面。以mlx5为例是加载到接收队列rq下面的xdp_prog
run
运行: 当有网络报文从网口进入到协议栈处理时候,调用prog程序并运行
还是以SKB模式为例
网络协议栈在入口函数__netif_receive_skb
时候,通过多层调用,最终会
1 2 3 4 5 6
| --> __netif_receive_skb --> --> __netif_receive_skb_one_core --> --> --> netif_receive_generic_xdp --> --> --> --> bpf_prog_run_generic_xdp --> --> --> --> --> bpf_prog_run_xdp --> --> --> --> --> --> __bpf_prog_run(prog, xdp, BPF_DISPATCHER_FUNC(xdp));
|
核心数据结构
bfp_prog
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 1461 struct bpf_prog { 1462 u16 pages; /* Number of allocated pages */ 1463 u16 jited:1, /* Is our filter JIT'ed? */ 1464 jit_requested:1,/* archs need to JIT the prog */ 1465 gpl_compatible:1, /* Is filter GPL compatible? */ 1466 cb_access:1, /* Is control block accessed? */ 1467 dst_needed:1, /* Do we need dst entry? */ 1468 blinding_requested:1, /* needs constant blinding */ 1469 blinded:1, /* Was blinded */ 1470 is_func:1, /* program is a bpf function */ 1471 kprobe_override:1, /* Do we override a kprobe? */ 1472 has_callchain_buf:1, /* callchain buffer allocated? */ 1473 enforce_expected_attach_type:1, /* Enforce expected_attach_type checking at attach time */ 1474 call_get_stack:1, /* Do we call bpf_get_stack() or bpf_get_stackid() */ 1475 call_get_func_ip:1, /* Do we call get_func_ip() */ 1476 tstamp_type_access:1; /* Accessed __sk_buff->tstamp_type */ 1477 enum bpf_prog_type type; /* Type of BPF program */ 1478 enum bpf_attach_type expected_attach_type; /* For some prog types */ 1479 u32 len; /* Number of filter blocks */ 1480 u32 jited_len; /* Size of jited insns in bytes */ 1481 u8 tag[BPF_TAG_SIZE]; 1482 struct bpf_prog_stats __percpu *stats; 1483 int __percpu *active; 1484 unsigned int (*bpf_func)(const void *ctx, 1485 const struct bpf_insn *insn); 1486 struct bpf_prog_aux *aux; /* Auxiliary fields */ 1487 struct sock_fprog_kern *orig_prog; /* Original BPF program */ 1488 /* Instructions for interpreter */ 1489 union { 1490 DECLARE_FLEX_ARRAY(struct sock_filter, insns); 1491 DECLARE_FLEX_ARRAY(struct bpf_insn, insnsi); 1492 }; 1493 };
|
函数关系汇总图