1. 查看支持xdp功能的网卡
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c:218: case XDP_SETUP_PROG:
drivers/net/ethernet/cavium/thunder/nicvf_main.c:1848: case XDP_SETUP_PROG:
drivers/net/ethernet/intel/i40e/i40e_main.c:11845: case XDP_SETUP_PROG:
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c:10154: case XDP_SETUP_PROG:
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c:4444: case XDP_SETUP_PROG:
drivers/net/ethernet/mellanox/mlx4/en_netdev.c:2911: case XDP_SETUP_PROG:
drivers/net/ethernet/mellanox/mlx5/core/en_main.c:4308: case XDP_SETUP_PROG:
drivers/net/ethernet/netronome/nfp/nfp_net_common.c:3471: case XDP_SETUP_PROG:
drivers/net/ethernet/netronome/nfp/nfp_net_common.c:3473: case XDP_SETUP_PROG_HW:
drivers/net/ethernet/qlogic/qede/qede_filter.c:1119: case XDP_SETUP_PROG:
drivers/net/netdevsim/bpf.c:207: if (bpf->command == XDP_SETUP_PROG && !ns->bpf_xdpdrv_accept) {
drivers/net/netdevsim/bpf.c:211: if (bpf->command == XDP_SETUP_PROG_HW && !ns->bpf_xdpoffload_accept) {
drivers/net/netdevsim/bpf.c:216: if (bpf->command == XDP_SETUP_PROG_HW) {
drivers/net/netdevsim/bpf.c:558: case XDP_SETUP_PROG:
drivers/net/netdevsim/bpf.c:564: case XDP_SETUP_PROG_HW:
drivers/net/tun.c:1233: case XDP_SETUP_PROG:
drivers/net/veth.c:993: case XDP_SETUP_PROG:
drivers/net/virtio_net.c:2406: case XDP_SETUP_PROG:
2. xdp 函数的Hook点
很显然xdp也是利用了trace类似的机制,通过埋点挂载回调函数实现,所以xdp一定有埋点函数,而且如果要实现双向的数据报文处理,必须有一个收包路径的关键埋点 和 一个发包路径的关键埋点,而且这两个埋点比如在网卡驱动程序中(事实上xdp只在收包路径上 有埋点)。
ixgbe网卡为例,收包路径埋点在ixgbe_clean_rx_irq函数中,埋点函数是ixgbe_run_xdp,函数调用路径为:
ixgbe_run_xdp <--- ixgbe_clean_rx_irq <--- ixgbe_poll(网卡poll)
static struct sk_buff *ixgbe_run_xdp(struct ixgbe_adapter *adapter,
struct ixgbe_ring *rx_ring,
struct xdp_buff *xdp)
{
int err, result = IXGBE_XDP_PASS;
struct bpf_prog *xdp_prog;
struct xdp_frame *xdpf;
u32 act;
rcu_read_lock();
xdp_prog = READ_ONCE(rx_ring->xdp_prog);
if (!xdp_prog)
goto xdp_out;
prefetchw(xdp->data_hard_start); /* xdp_frame write */
act = bpf_prog_run_xdp(xdp_prog, xdp);
switch (act) {
case XDP_PASS:
break;
case XDP_TX:
xdpf = convert_to_xdp_frame(xdp);
if (unlikely(!xdpf)) {
result = IXGBE_XDP_CONSUMED;
break;
}
result = ixgbe_xmit_xdp_ring(adapter, xdpf);
break;
case XDP_REDIRECT:
err = xdp_do_redirect(adapter->netdev, xdp, xdp_prog);
if (!err)
result = IXGBE_XDP_REDIR;
else
result = IXGBE_XDP_CONSUMED;
break;
default:
bpf_warn_invalid_xdp_action(act);
/* fallthrough */
case XDP_ABORTED:
trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
/* fallthrough -- handle aborts by dropping packet */
case XDP_DROP:
result = IXGBE_XDP_CONSUMED;
break;
}
xdp_out:
rcu_read_unlock();
return ERR_PTR(-result);
}
代码片段 act = bpf_prog_run_xdp(xdp_prog, xdp),很明显就是在遍历挂载的回调函数。