bcc钱包地址生成linux,从Bcc到xdp原理分析

Bcc

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)

8393417a57fb7293affbba03ea05c9ef.png

xdp注入流程

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发出去啦。

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值