Redian新闻
>
eBPF技术实践:加速容器网络转发,耗时降低60%+!

eBPF技术实践:加速容器网络转发,耗时降低60%+!

公众号新闻

背景

Linux 具有功能丰富的网络协议栈,并且兼顾了非常优秀的性能。但是,这是相对的。单纯从网络协议栈各个子系统的角度来说,确实做到了功能与性能的平衡。不过,当把多个子系统组合起来,去满足实际的业务需求,功能与性能的天平就会倾斜。


容器网络就是非常典型的例子,早期的容器网络,利用 bridge、netfilter + iptables (或lvs)、veth等子系统的组合,实现了基本的网络转发;然而,性能却不尽如人意。原因也比较明确:受限于当时的技术发展情况,为了满足数据包在不同网络 namespace 之间的转发,当时可以选择的方案只有 bridge + veth 组合;为了实现 POD 提供服务、访问 NODE 之外的网络等需求,可以选择的方案只有 netfilter + iptables(或 lvs)。这些组合的技术方案增加了更多的网络转发耗时,故而在性能上有了更多的损耗。


然而,eBPF 技术的出现,彻底改变了这一切。eBPF 技术带来的内核可编程能力,可以在原有漫长转发路径上,制造一些“虫洞”,让报文快速到达目的地。针对容器网络的场景,我们可以利用 eBPF,略过 bridge、netfilter 等子系统,加速报文转发


下面我们以容器网络为场景,用实际数据做支撑,深入分析 eBPF 加速容器网络转发的原理。


网络拓扑

  • 如图,两台设备 Node-A/B 通过 eth1 直连,网段为 192.168.1.0/24。
  • Node-A/B 中分别创建容器 Pod-A/B,容器网卡名为 ve0,是 veth 设备,网段为172.17.0.0/16。
  • Node-A/B 中分别创建桥接口 br0,网段为 172.17.0.0/16,通过 lxc0(veth 设备)与 Pod-A/B 连通。
  • 在 Node、Pod 网络 namespace 中,分别设置静态路由;其中,Pod 中静态路由网关为 br0,Node 中静态路由网关为对端 Node 接口地址。
  • 为了方便测试与分析,我们将 eth1 的网卡队列设置为 1,并且将网卡中断绑定到 CPU0。
# ethtool -L eth1 combined 1# echo 0 > /proc/irq/$(cat /proc/interrupts | awk -F ':' '/eth1/ {gsub(/ /,""); print $1}')/smp_affinity_list

bridge

bridge + veth 是容器网络最早的转发模式,我们结合上面的网络拓扑,分析一下网络数据包的转发路径。
  • 在上面网络拓扑中,eth1 收到目的地址为 172.17.0.0/16 网段的报文,会经过路由查找,走到 br0 的发包流程。
  • br0 的发包流程,会根据 FDB 表查找目的 MAC 地址归属的子接口,如果没有查找到,就洪泛(遍历所有子接口,发送报文);否则,选择特定子接口,发送报文。在本例中,会选择 lxc0 接口,发送报文。
  • lxc0 口是 veth 口,内核的实现是 veth 口发包,对端(peer)的 veth 口就会收包。在本例中,Pod-A/B 中的 ve0 口会收到报文。
  • 至此,完成收包方向的主要流程。
  • 当报文从 Pod-A/B 中发出,会先在 Pod 的网络 namespace 中查找路由,假设流量从 Pod-A 发往 Pod-B,那么会命中我们之前设置的静态路由:172.17.0.200 via 172.17.0.1 dev ve0,最终报文会从 ve0 口发出,目的 MAC 地址为 Node-A 上面 br0 的地址。
  • ve0 口是 veth 口,和收包方向类似,对端的 veth 口 lxc0 会收到报文。
  • lxc0 口是 br0 的子接口,由于报文目的 MAC 地址为 br0 的接口地址,报文会经过br0 口上送到 3 层协议栈处理。
  • 3 层协议栈会查找路由,命中我们之前设置的静态路由:172.17.0.200 via 192.168.1.20 dev eth1,最终报文会从 eth1 口发出,发给 Node-B。
  • 至此,完成发包方向的主要流程。

上面的流程比较抽象,我们用 perf ftrace 可以非常直观地看到报文都经过了哪些内核协议栈路径。


收包路径

# perf ftrace -C0 -G '__netif_receive_skb_list_core' -g 'smp_*'

  • 如图,收包路径主要经历路由查找、桥转发、veth 转发、veth 收包等阶段,中间多次经过 netfilter 的 hook 点。
  • 最终调用 enqueue_to_backlog 函数,数据包暂存到每个  CPU 私有的 input_pkt_queue中,一次软中断结束,总耗时 79us。
  • 但是报文并没有到达终点,后续软中断到来时,会有机会调用 process_backlog,处理每个 CPU 私有的 input_pkt_queue,将报文丢入 Pod 网络 namespace 的协议栈继续处理,直到将报文送往 socket 的队列,才算是到达了终点。
  • 综上,收包路径要消耗2个软中断,才能将报文送达终点。

发包路径

# perf ftrace -C0 -G '__netif_receive_skb_core' -g 'smp_*'

  • 如图,发包路径主要经历 veth 收包、桥上送、路由查找、物理网卡转发等阶段,中间多次经过 netfilter 的 hook点 。
  • 最终调用网卡驱动发包函数,一次软中断结束,总耗时 62us。


分析

由 perf ftrace 的结果可以看出,利用 bridge + veth 的转发模式,会多次经历netfilter、路由等子系统,过程非常冗长,导致了转发性能的下降。


我们接下来看一下,如何用eBPF跳过非必须的流程,加速网络转发。


TC redirect

首先,我们先看一下内核协议栈主要支持的 eBPF hook 点,在这些 hook 点我们可以注入 eBPF 程序,实现具体的业务需求。


我们可以看到,与网络转发相关的 hook 点主要有 XDP(eXpress Data Path)、TC(Traffic Control)、LWT(Light Weight Tunnel)等。


针对于容器网络转发的场景,比较合适的 hook 点是 TC。因为 TC hook 点是协议栈的入口和出口,比较底层,eBPF 程序能够获取非常全面的上下文(如:socket、cgroup 信息等),这点是 XDP 没有办法做到的。而 LWT 则比较靠上层,报文到达这个 hook 点,会经过很多子系统(如:netfilter)。


加速收包路径

如图,在 eth1 的 TC hook 点(收包方向)挂载 eBPF 程序。

# tc qdisc add dev eth1 clsact# tc filter add dev eth1 ingress bpf da obj ingress_redirect.o sec classifier-redirect

eBPF 程序如下所示,其中 lxc0 接口的 index 为 2。bpf_redirect 函数为内核提供的 helper 函数,该函数会将 eth1 收到的数据包,直接转发至 lxc0 接口。

SEC("classifier-redirect") int cls_redirect(struct __sk_buff *skb) {    /* The ifindex of lxc0 is 2 */       return bpf_redirect(2, 0); }


加速发包路径

如图,在 lxc0 的 TC hook 点(收包方向)挂载 eBPF 程序。

# tc qdisc add dev lxc0 clsact # tc filter add dev lxc0 ingress bpf da obj egress_redirect.o sec classifier-redirect

eBPF 程序如下所示,其中 eth1 接口的 index 为 1。bpf_redirect 函数会将 lxc0 收到的数据包,直接转发至 eth1 接口。

SEC("classifier-redirect") int cls_redirect(struct __sk_buff *skb) {    /* The ifindex of eth1 is 1 */        return bpf_redirect(1, 0); }

分析

由上面的操作可以看到,我们直接跳过了 bridge 的转发,利用 eBPF 程序,将 eth1 与 lxc0 之间建立了一个快速转发通路。下面我们用 perf ftrace 看一下加速效果。

收包路径

# perf ftrace -C0 -G '__netif_receive_skb_list_core' -g 'smp_*'


如图,在收包路径的 TC 子系统中,由 bpf_redirect 函数设置转发信息( lxc0 接口 index),由 skb_do_redirect 函数直接调用了 lxc0 接口的 veth_xmit 函数;略过了路由、bridge、netfilter 等子系统。


最终调用 enqueue_to_backlog 函数,数据包暂存到每个 CPU 私有的input_pkt_queue 中,一次软中断结束,总耗时 43us;比 bridge 转发模式的 79us,耗时减少约 45%。


但是,收包路径仍然要消耗 2 个软中断,才能将报文送达终点。


发包路径

如图,在发包路径的 TC 子系统中,由 bpf_redirect 函数设置转发信息( eth1 接口 index ),由 skb_do_redirect 函数直接调用了 eth1 接口的 xmit 函数;略过了路由、bridge、netfilter 等子系统。


最终调用网卡驱动发包函数,一次软中断结束,总耗时 36us相比 bridge 模式 62us耗时减少了约 42%


小结

由 perf ftrace 的结果可以看出,利用 eBPF 在 TC 子系统注入转发逻辑,可以跳过内核协议栈非必须的流程,实现加速转发。收发两个方向的耗时分别减少40%左右,性能提升非常可观


但是,我们在收包路径上面仍然需要消耗 2 个软中断,才能将报文送往目的地。接下来我们看,如何利用 redirect peer 技术来优化这个流程。


TC redirect peer

加速收包路径

如图,在 eth1 的 TC hook 点(收包方向)挂载 eBPF 程序。

# tc qdisc add dev eth1 clsact # tc filter add dev eth1 ingress bpf da obj ingress_redirect_peer.o sec classifier-redirect

eBPF 程序如下所示,其中 lxc0 接口的 index 为 2。bpf_redirect_peer 函数为内核提供的 helper 函数,该函数会将 eth1 收到的数据包,直接转发至 lxc0 接口的 peer 接口,即 ve0 接口。

SEC("classifier-redirect") int cls_redirect(struct __sk_buff *skb) {    /* The ifindex of lxc0 is 2 */        return bpf_redirect_peer(2, 0); }

分析

由于 bpf_redirect_peer 会直接将数据包转发到 Pod 网络 namespace 中,避免了enqueue_to_backlog 操作,节省了一次软中断,性能理论上会有提升。我们用 perf ftrace 验证一下。

# perf ftrace -C0 -G '__netif_receive_skb_list_core' -g 'smp_*

'

如图,在收包路径的 TC 子系统中,由 bpf_redirect_peer 函数设置转发信息( lxc0 接口 index),由 skb_do_redirect 函数调用 veth_peer_dev 查找 lxc0 的 peer 接口,设置 skb->dev = ve0,返回 EAGAIN 给 tcf_classify 函数。


tcf_classify 函数会判断 skb_do_redirect 的返回值,如果是 EAGAIN,则触发 __netif_receive_skb_core 函数伪递归调用(通过 goto  实现)。这样,就非常巧妙地实现了网络 namespace 的切换(在一次软中断上下文中)。


最终,通过 tcp_v4_rcv 函数到达报文的终点,整个转发流程耗时 75us。从上面的函数耗时可以看到,ip_list_rcv 函数相当于 Pod 网络 namespace 的耗时,本文描述的 3 种转发模式,这段转发路径是相同的。所以,将 ip_list_rcv 函数耗时减去,转发耗时约为 14us(这里还忽略了2次软中断调度的时间)。比 TC redirect 模式的 43us、bridge 模式的 79us,转发耗时分别减少为 67%、82%


总结

本文以容器网络为例,对比了 3 种容器网络转发模式的性能差异。通过 perf ftrace 的函数调用关系以及耗时情况,详细分析了导致性能差异的原因。我们演示了仅仅通过几行 eBPF 代码,就可以大大缩短报文转发路径,加速内核网络转发的效率,网络转发耗时最多可减少82%


目前 eBPF 技术在开源社区非常流行,在 tracing、安全、网络等领域有广泛应用,我们可以利用这项技术做很多有意思的事情。感兴趣的朋友可以加入我们,一起讨论交流。

作者:王栋栋,字节跳动系统技术与工程团队内核工程师,10年系统工程师工作经验,关注Linux networking、eBPF等领域。目前在字节跳动,主要负责eBPF、内核网络协议栈相关的开发工作。



【OSCHINA 2022 中国开源开发者问卷】来啦
你的反馈将有助于反映中国开源的全貌
问卷结尾还可抽取我们的周边好物哦~
期待来自你的反馈!


往期推荐



微软做了谷歌做不到的事

已超1000万行代码,Java再次输给了Kotlin...

刚标准化就被废弃,谷歌:不爱了



这里有最新开源资讯、软件更新、技术干货等内容
点这里 ↓↓↓ 记得 关注✔ 标星⭐ 哦~

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
关于UFO我们确切知道哪些?AI 应用的全流程存储加速方案技术解析和实践分享Docker 容器网络及其配置详解推荐直播 | 创造 • 探究 • 实践:义务教育课程改革主题研讨会暨《让学生创造着长大》新书发布会英语课时降低引争议,中国人到底该怎么学英语?Webpack 创始人推出比 Webpack“快 700 倍”的 Turbopack,基于 Rust 编写2022投行IPO收入排行榜:最高47亿!最低608万华为智能编码助手、微软 VS code 开发工具最新技术实践 | QCon 上海甲醛克星!日本京都大学耗时多年研发,1000盆绿植不如用个它!Apache Doris 在橙联的应用实践:数仓架构全面革新,千万数据计算时间从 2 小时变成 3 分钟多伦多世嘉宝马戏团氟化-硼磷酸盐ABPF:性能优异的深紫外非线性光学材料 | NSR为了拍片,耗时6年、40次赌上性命!这神作每一帧都让人灵魂战栗vivo 云原生容器探索和落地实践 | Q推荐新财年10月排期表已出!EB-2和EB-3移民排期前进二个月左右, EB-5区域中心及EB-5直投项目移民排期倒退了275天Magna预测2023年全球广告收入增长5%;IAB技术实验室更新其OpenRTB规范(广告狂人日报)中国工商银行基于eBPF技术的云原生可观测图谱探索与实践eBPF 技术实践:加速容器网络转发,耗时降低60%+后 OpenStack 时代,以容器为代表的虚拟化技术将有怎样的演进?| Q推荐在华 15 个“零碳工厂”,施耐德电气如何用技术实现“绿色”目标酱爆菜脯五花肉第二十三届脑电数据分析技术实战班(线上直播,2022.10.21-25)让无服务器微服务超越容器,开发工具初创公司Fermyon 推出 WebAssembly 云FOODS | 麦当劳联名CPFM推出成人专属的儿童套餐,还能免费抽奖得CPFM同款??异构混排在vivo互联网的技术实践 | Q推荐eBPF 是用来干什么的?(图)晚霞不可错过!5张图带你搞懂容器网络原理聚生态之力,英特尔加速未来网络转型疯了!马斯克粉丝花419万,耗时700小时为偶像建雕塑,又丑又辣眼睛!网友:这不是我的毕设吗?189再开闸,最低65分获邀!澳洲用工荒,286种最缺人职业公布!禽流感“卷土重来”,已波及37个国家...Diffusion预训练成本降低6.5倍,微调硬件成本降低7倍!Colossal-AI完整开源方案低成本加速AIGC产业落地去哪儿网 Service Mesh 落地实践:100%容器化打底,业务友好是接入关键当人老后—1理论与实践:如何写好一个方法
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。