19

从Bcc到xdp原理分析

 3 years ago
source link: https://kernel.taobao.org/2019/05/bcc_to_xdp/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Bcc是ebpf的编译工具集合,前端提供python/lua调用,本身通过c语言实现,集成llvm/clang,将ebpf代码注入,提供一些更人性化的函数给用户使用,比如函数的注入等,里面提供了很多xdp的例子,本文将从bcc xdp例子为入口,研究整个xdp的工作流程
附:ebpf框架(map作为用户态和内核态注入代码的通信(目前upstream xdp支持devmap、cpumap、xskmap),通过verfier检查,通过JIT即时翻译,底层有各种静态探针点,比如xdp,tracepoint,perf,也有动态探针点,比如kprobe)

xdp.png#align=left&display=inline&height=254&originHeight=254&originWidth=407&size=0&status=done&width=407

xdp注入流程

以bcc的开源xdp_redirect_map为例讲述整个xdp的流程
https://github.com/iovisor/bcc/blob/b0bf04ac4042a6c004b15dcc5e40e12ae78020f9/examples/networking/xdp/xdp_redirect_map.py

int xdp_redirect_map(struct xdp_md *ctx) {
    void* data_end = (void*)(long)ctx->data_end;
    void* data = (void*)(long)ctx->data;
    struct ethhdr *eth = data;
    uint32_t key = 0;
    long *value;
    uint64_t nh_off;
    nh_off = sizeof(*eth);
    if (data + nh_off  > data_end)
        return XDP_DROP;
    value = rxcnt.lookup(&key);
    if (value)
        *value += 1;
    swap_src_dst_mac(data);
    return tx_port.redirect_map(0, 0);
}
int xdp_dummy(struct xdp_md *ctx) {
    return XDP_PASS;
}
""", cflags=["-w"])

tx_port = b.get_table("tx_port")
tx_port[0] = ct.c_int(out_idx)

in_fn = b.load_func("xdp_redirect_map", BPF.XDP)
out_fn = b.load_func("xdp_dummy", BPF.XDP)

b.attach_xdp(in_if, in_fn, flags)
b.attach_xdp(out_if, out_fn, flags)

这个sample讲的是将in ifdev的包文redirect到out ifdev发出去(比如in为eth0,out为eth1),
in_fn = b.load_func(“xdp_redirect_map”, BPF.XDP) //加载xdp_redirect_map函数,返回prog_fd给in_fn
in_if就是eth0 dev设备
b.attach_xdp(in_if, in_fn, flags),//attach xdp

attach_xdp

调用逻辑
(bcc)/src/cc/libbpf.c bpf_attach_xdp(const char *dev_name, int progfd, uint32_t flags)
—(linux)/tools/lib/bpf/netlink.c bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
建立netlink socket,发送
req.nh.nlmsg_type = RTM_SETLINK
req.ifinfo.ifi_family = AF_UNSPEC
req.ifinfo.ifi_index = ifindex; //传入out ifindex
nla->nla_type = NLA_F_NESTED | IFLA_XDP
memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); //传入xdp_redirect_map的prog_fd
接受端:
(linux)/net/core/rtnetlink.c
rtnl_setlink
根据ifm->ifi_index查询本net namespace的dev(后面简称outdev)
-do_setlink
从xdp[IFLA_XDP_PROG_ID中获取到prog_fd
–dev_change_xdp_fd

dev_change_xdp_fd

调用dev_xdp_install安装xdp函数
这里会调用dev->netdev_ops->ndo_bpf(XDP_SETUP_PROG)
以i40e网卡驱动为例,调用:
i40e_xdp_setup
将vsi->xdp_prog赋值为prog_fd
将vsi->rx_rings[i]->xdp_prog赋值为prog_fd
这样后面调用vsi->rx_rings[i]->xdp_prog时,就会调用到用户注入的代码

xdp收包

以i40e为例,底层驱动收包流程如下
i40e_napi_poll
—i40e_clean_rx_irq_zc
——i40e_run_xdp
———bpf_prog_run_xdp
————BPF_PROG_RUN
—————(*(prog)->bpf_func)(ctx, (prog)->insnsi)//这里就是用户态注入的函数本例注入的xdp_redirect_map函数(vsi->rx_rings[i]->xdp_prog->bpf_func)
——————swap_src_dst_mac(data);//交换src dst的mac,这样src为eth0 mac,dst为原nc的mac
——————tx_port.redirect_map//tx_port的设置是通过map机制,为eth2的ifdex
———————bpf_xdp_redirect_map(这个怎么来的?xdp_verifier_ops->xdp_func_proto->BPF_FUNC_redirect_map->bpf_xdp_redirect_map_proto->bpf_xdp_redirect_map)
————————struct bpf_redirect_info *ri = this_cpu_ptr(&bpf_redirect_info);
————————ri->ifindex = ifindex;
————————WRITE_ONCE(ri->map, map);
————————返回XDP_REDIRECT
———xdp_do_redirect
————xdp_do_redirect_map
————— __xdp_map_lookup_elem//根据index和map获取到目标端口(eth1)的信息
—————__bpf_tx_xdp_map  //将xdp数据赋值到目标eth1 dev的xdp_bluk_quue(this_cpu_ptr(obj->bulkq)->q[blukq->count])里面,这里遗留个flag MEM_TYPE_ZERO_COPY用于零拷贝(这个feature引入的文章https://lwn.net/Articles/754659/)
—————ri->map_to_flush = map;//设置map_to_flush标志
—— i40e_finalize_xdp_rx(rx_ring, xdp_xmit);//将xdp_bluk_quue里面的
——— xdp_do_flush_map
————__dev_map_flush
————— bq_xmit_all
—————— ndo_xdp_xmit(dev, count,q) //调用目标eth1的xdp发包

xdp发包

ndo_xdp_xmit

i40e网卡对应i40e_xdp_xmit
调用i40e_xmit_xdp_ring往DMA发包,这样从eth0收到的包文,就直接通过eth1发出去啦。

https://qmonnet.github.io/whirl-offload/2016/09/01/dive-into-bpf/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK