转发到指定网卡_Life of a Packet in Cilium:实地探索 PodtoService 转发路径及 BPF 处理逻辑...

本文详细分析了Cilium中Pod访问ServiceIP的数据包转发路径,从POD1发送开始,经过BPF程序分析,内核路由判断,物理网卡egress处理,数据中心网络路由,直到到达目标POD4。通过理解每个转发步骤,揭示了Cilium如何利用BPF实现高效和安全的网络转发。
摘要由CSDN通过智能技术生成

原载于:http://arthurchiao.art/blog/cilium-life-of-a-packet-pod-to-service-zh/

引言

面临的问题

传统的基于二层转发(Linux bridge、Netfilter/iptables、OVS 等)和/或 三层路由的网络虚拟化方案中,数据包的转发路径通常非常清晰,通过一些常见工 具或命令就能判断包的下一跳(可能是一个端口或网络设备),最终能画出一张类似下 图的网络拓扑图 [1]:

60479b88f2af90ad55ca8813fdfc37e7.png

Fig 1. Network topology inside an OpenStack compute node

当网络出现问题时,例如,一个容器访问另一个容器网络不通,只要沿着这条路径上的设 备依次抓包,再配合路由表、ARP 表分析,一般很快就能定位到问题出在那个环节

不幸的是,在 Cilium/eBPF 方案中,网络拓扑已经没有这么直观了,例如,下面是默认 安装时 Cilium 节点的网络拓扑:

88e7a06d1fdfc61309f07fb951869748.png

Fig 2. Network topology inside an Cilium-powered k8s node

可以看到,各个设备之间看上去都是“孤立的”,很多地方并没有桥接设备或常规的路由/转 发规则将它们连起来。如果用 tcpdump 抓包,会看到包一会从一个地方消失了,一会 又从另一个地方冒出来了,中间怎么过来的,一头雾水,只知道是 eBPF 干的。

这可能是上手 Cilium 网络排障(trouble shooting)时最苦恼的事情之一

本文目的

本文试图用常规 Linux 工具来探索 Cilium 的整个转发路径,并分析在每个转发 节点分别做了什么事情,最终得到一张与图 1 一样直观的转发路径图,结果如图 3 所示:

cf1e6f51eaeda3ba36daf8215c7282a0.png

Fig 3. Traffic path of Pod-to-ServiceIP

具体来说,我们从一个 Pod 访问 ServiceIP 开始,并假设这个 ServiceIP 对应 的后端 Pod 位于另一台 node 上,然后探索包所经过的路径和处理过程。

[2,3,5] 都有较大的篇幅介绍 Cilium/eBPF 的转发路径,但并没有具体到 BPF 代码层面。

如前面所说,转发路径的许多地方是靠 BPF 代码“粘合”到一起的,因此完成本文的任务 离不开对相应 BPF 代码的分析,这是本文最大的不同。

但要理解整个转发路径,还是强烈建议理论先行,在阅读本文之前先理解 [2,3]。

环境及配置信息

Cilium 的 eBPF 转发路径随跨主机网络方案内核版本而有差异,本文假设:

1.跨主机网络方案:直接路由(BGP [4])2.Linux kernel 4.19:Cilium/eBPF 的较完整功能依赖这个版本及以上的内核3.Cilium 1.8.2,配置:

kube-proxy-replacement=probe(默认)•enable-ipv4=true(默认)•datapath-mode=veth(默认)

4.没有对通信双方应用任何 network policy(默认)5.两个物理网卡做 bond,宿主机 IP 配置在 bond 上

满足以上 2 & 3 条件下,所有对包的拦截和修改操作都由 BPF 代码完成,不依赖 Netfilter/iptables,即所谓的 kube-proxy free 模式。

其他说明

为方便起见,本文会在宿主机上用 nsenter-ctn 进入到容器执行命令,它 其实是对 nsenter 命令的一个简单封装:

{% raw %}

(NODE1) $ cat ~/.bashrc...function nsenter-ctn () {
        CTN=$1  # container ID or name    PID=$(sudo docker inspect --format "{
    {.State.Pid}}" $CTN)    shift 1 # remove the first argument, shift others to the left    nsenter -t $PID $@}

{% endraw %}

这和登录到容器里执行相应的命令效果是一样的,更多信息参考 man nseneter

Step 1: POD1 eth0 发送

下面几个网络设备在我们的场景中用不到,因此后面的拓扑图中不再画它们:

1.cilium_net/cilium_host 这对 veth pair 在 Kernel 4.19 + Cilium 1.8 部署中已经没什么作用了(事实上社区在考虑去掉它们)。2.cilium_vxlan 这个设备是 VxLAN 封装/接封装用的,在直接路由模式中不会出现。

拓扑简化为下图:

f634455030e612ec011c752d51094ef2.png

Fig. Step 1.

1.1 访问 ServiceIP

从 POD1 访问 ServiceIP 开始,例如:

# * -n: execute command in pod's network namespace# * 10.224.1.1: ServiceIP(NODE1) $ nsenter-ctn POD1 -n curl 10.224.1.1:80

包会从容器的 eth0 虚拟网卡发出去,此时能确定的 IP 和 MAC 地址信息有,

1.src_ip=POD1_IP2.src_mac=POD1_MAC3.dst_ip=Se

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值