“
在《云原生网络利器–Cilium总览篇》的文章中,整体的介绍了一下Cilium中常见技术术语和总体的架构介绍。接下来的篇幅会重点介绍eBPF的一些关键特性,以及在Cilium中使用eBPF做了哪些工作,并介绍基本的原理。
01总述
eBPF是一种可以在不改变Kernel的前提下,开发Kernel相关能力的一种技术。开发eBPF的程序需要使用C语言,因为Kernel是C语言开发的,eBPF在开发的过程中会依赖Kernel的uapi以及Linux的Hepler方法来完成处理。Linux是基于事件模型的系统,也支持了eBPF类型Hook,在一些Hook点执行挂载的eBPF程序。在不同的挂载点,支持不同类型的eBPF程序类型。
为什么eBPF会有类型?主要考虑的是,Linux本身的能力非常多,而提供给外部可调用的方法是很少的,那就需要为不同的场景和能力,开放不同的系统调用能力,哪些能力在哪些类型下可以被调用,就跟eBPF的程序类型有关系了。
举例,对于处理网络的eBPF程序,不需要给这类型的程序开放处理存储的能力。对于一个程序而言,主要就包含了数据结构和算法两个部分。
在eBPF中也是一样,程序自己的数据结构是可以自由定义的,但是有一些和内核相关的能力以及eBPF内置提供的数据处理,就必须要依赖特定的数据结构,这里的数据结构就是eBPF的不同类型的Maps。
接下来就是算法,eBPF的算法是有一定的限制的,对于要调用内核的能力的,需要通过LinuxHepler的方式来完成调用,而LinuxHepler是跟着Linux的内核版本走的,当需要Linux开放一些新的能力给外部,就需要开发Linux的Helper,合并到Kernel之后,eBPF的程序才可以使用。
还有一部分的算法就是eBPF程序自己的业务逻辑了,同时在eBPF的算法部分中,有一个很重要的部分,就是eBPF程序之间互相调用的能力,这里有一个专业术语叫TailCall(尾部调用)。可以理解成,eBPFA程序,调用eBPFB程序的时候,是经过TailCall的方式,这种方式的调用,程序调用不会有返回,而是直接进入到另外一个程序,但是不同eBPF程序之间是可以通过Pin的机制共享这些数据结构的。
Cilium中使用了大量得eBPF技术,实现了K8s的容器网络的能力。
02技术术语
为了更好的理解Cilium实现的数据平面的能力,首先需要对一些常见的eBPF的相关概念,有一个初步的认识,这样能更好的帮助理解原理。以下整理一些技术术语,不包含所有的,只是列出来一些主要的点。
eBPF的命令:
对eBPF的常见操作是通过系统调用SYSCALL完成的。常见的操作:对eBPFMap的增删改查操作;Object对象的Pin和Get操作;eBPF程序的挂载和卸载。
eBPF的Map类型:
这里描述了eBPFMaps支持哪些类型的Maps,不同类型Map的使用方式和场景会不一样。
eBPF的程序类型:
以下描述了eBPF程序的类型种类,不同种类的eBPF会完成不同的能力。举例,如果是和XDP相关的能力,程序的类型就是BPF_PROG_TYPE_XDP;如果是tc相关的能力,程序的类型就是BPF_PROG_TYPE_SCHED_CLS和BPF_PROG_TYPE_SCHED_ACT。什么样的LinuxHelper被加载,是由eBPF的程序类型决定的。
eBPF的挂载类型:
不同的eBPF程序类型,就会有不同的挂载类型。
eBPFTailCall:
顾名思义就是尾部调用,主要的特点就是eBPF的程序从一个调用到另一个,不像一般的程序语言的方法调用是有返回值,TailCall不会有返回值的,而是从一个eBPF直接就执行到下一个eBPF程序,两个eBPF之间是同级的,不是方法调用的关系。
eBPFSection:
可以简单理解成eBPF程序的执行入口,可以在程序中指定Section。举例:__section(“from-netdev”)。如果不指定的话,会有默认的Section。在学习Cilium的eBPF程序的时候,推荐阅读的入口就是以每一种eBPF的C语言程序的Section部分为学习入口。
eBPFObjectPin:
正如字面意思,指的是将eBPFMapPin到Linux的bpffs这个虚拟的文件系统中。主要的作用是让eBPF的Maps,可以被eBPF程序或者用户态的应用读取和共享,在通过ObjGet之前,是需要先完成Pin动作,才可以被Get。
LinuxHelper:
从Linux系统的角度,提供一些对外访问Linux系统能力的方法,供外部程序去使用。外部程序要使用Kernel的接口,那就只能通过LinuxHelper来完成。
不同的Kernel版本支持的LinuxHelper是不同的,版本越高,支持的能力越多,高级的能力也越多,使用这些高级能力的实现时,网络性能也会越高,这也是为什么很多Cilium的高级能力都需要特定版本的Kernel。更多详情请参加bpf-helpers。
XDP:
eXpressDataPath,是数据包进入主机后,最早的一个支持eBPF的Hook点。可以在此阶段完成如过滤包、LB等场景的能力。同时从运行的时机,又可以分为是硬件级的、网络驱动级的、内核级的,依次执行时机是硬件级的最早(性能最好),网络驱动级的其次,内核级的是最晚(性能最差,一般用于Poc,不建议生产使用)。
挂载XDP的eBPF程序(这里的sec就是代表eBPF的Section):
iplinksetdevem1xdpobjprog.osecfoobar
XDP返回码:
返回码代表的是在处理过程中,根据不同的逻辑需要对数据包进行不同的处理行为。举例,当觉得数据包需要被丢弃的时候,就需要在eBPF程序中返回XDP_DROP,当觉得数据包被重定向出去的时候,可以返回XDP_TX/XDP_REDIRECT;当觉得数据包需要继续进入到内核的时候,可以返回XDP_PASS。
tc:
TrafficControl,每一个Linux识别的网络设备都支持tc的能力,包括物理的和虚拟的。在容器网络相关的网络设备的进出口的地方,可以利用tc的能力来完成对网络数据包的控制能力。
同时,tc是支持两个方向的,一个是ingress的方向,一个egress的方向。而XDP只支持ingress的方向。可以理解成使用了tc的能力,可以在数据包进入一个网络设备的时候,进行相关处理,在出去的时候,也可以进行数据包的处理。而使用XDP的时候,只能在进入网络设备的时候,进行数据包的处理。
挂载tc的eBPF程序(这里的egress就是方向,sec就是代表eBPF的Section):
tcfilteradddevem1egressbpfdaobjprog.osecfoobar
tc返回码:
返回码代表的是在处理过程中,根据不同的逻辑需要对数据包进行不同的处理行为。举例,当觉得数据包需要被丢弃的时候,就需要在eBPF程序中返回TC_ACT_SHOT/TC_ACT_STOLEN,当觉得数据包被重定向出去的时候,可以返回TC_ACT_REDIRECT;当觉得数据包需要继续进入到内核的时候,可以返回TC_ACT_OK。
SocketRedirect:
这是一种可以直接将一个Socket的数据包redirect到另一个Socket的能力,无需经过内核的网络协议栈,就可以加速本地的网络通信能力。注意这里是只在本地Socket之间数据包的通信,可以使用这种机制。这个能力也是Kernel提供的,属于eBPF范畴能力的体现。
具体的使用场景主要包含Pod内容器之间的通信,以及主机上的Socket网络之间的通信,以及所有可以本地通过Socket互相通信的程序之间。不局限于容器,二进制运行的主机进程也可以。
下图提供一种从Pod内两个容器的SocketRedirect加速场景为例,介绍一下SocketRedirect的能力。可以看到SocketRedirect大概的使用方式,帮助理解,但是SocketRedirect不仅仅局限于这个场景,只要是本地的Socket都是可以使用这种特性。
CTXRedirect:
这是Cilium网络区别于其它网络方案的特点之一,通过Kernel的redirect完成网络设备到网络设备的数据包的传输能力。ctx_redirect(conststruct__sk_buff*ctx__maybe_unused,intifindex,__u32flags),从方法的定义中就可以看出来,将数据包转发到ifindex这个网络设备去。
在Cilium中,核心思想就是bypassnetfilter/iptables,直接通过redirect将数据包转来转去,缩短数据包的传输路径,提升网络性能。传统的玩法是所有网络设备的数据包,都要经过内核网络协议栈进行传递,数据路径比较长,对netfilter/iptables的体系依赖性比较强。
如下图,这里的数据包的redirect的方向是哪一个,取决于使用的内核的版本,大致可以帮助理解CTXRedirect的作用。下图仅仅是为了说明redirect是什么意思,不包含所有的数据路径,因为有一些数据流是一定要经过内核的处理,不在此图中具体分析。
这里在内核版本较高的情况下,还可以使用CTXRedirect的升级能力,也就是CTXRedirectPeer和CTXRedirectNeigh,网络性能会更好。
NodePortAcceleration:
基于XDP的技术,在南北向NodePort访问K8s服务的时候,进行网络加速的能力。包括直接redirect到本地Pod;包括redirect到当前物理网卡或其它物理网卡的方式,forward数据包去真正运行Pod的机器,这种情况下,会使用到XDP_REDIRECT或者XDP_TX,具体取决于当前使用的Cilium版本是不是使用了支持XDP多网卡的Feature。
不管是本地的Pod,还是其它机器的Pod,都是使用的eBPF的网络技术完成数据包的处理能力,缩短了数据包在整个网络上的传输路径。如上图,物理网卡上的数据包的路径部分的箭头。
03原理概述
这里的原理概述主要是,从Cilium中使用到的网络设备,以及网络设备上被挂载的eBPF程序,来理解Cilium在数据路径中,实现了哪些有特色的网络能力,以及从中可以看出来实现的大概原理。
cilium_host/cilium_net:
CiliumAgent在启动的时候,会初始化这一对虚拟网络设备。这是一对vethpair的虚拟的网络设备。其中cilium_net是cilium_host的parent,而且没有ip地址,它是一种netdevice,可以看成和物理网卡类似的设备。cilium_host有设置ip地址,这个ip地址会作为Pod的网关,可以查看Pod的路由信息,看到对应的网关地址就是cilium_host的ip地址。
那是不是会理解成容器Pod里的数据包要想出去,就先将数据包发往cilium_host?其实不是,通过arp的命令查看对应的mac地址,可以看到对应的mac地址,其实是lxc-xxx的地址,lxc-xxx是什么,会在下面提到。所以Pod出来的数据包的第一跳,真正要经过的路径是lxc-xxx。
那数据包到达lxc-xxx之后会发生什么?这个就要提到挂载在lxc-xxx的tcingress的from-container,这个Section对应的eBPF程序。那cilium_net是负责处理什么?cilium_net的网络设备上也会挂载eBPF程序,这个程序是bpf_host_cilium_net.o文件中的to-hostSection,挂载的方向是tcingress。主要完成ctx的encrypt相关的mark操作。
在Kernel和Cilium版本比较低的时候,数据包要进入Pod,都需要经过cilium_host设备,但是在高内核版本和比较新的版本Cilium版本中,cilium_host就显得不那么重要了,主要用来处理本地流量访问Pod的情况。cilium_host挂载的eBPF程序通过tc的方式完成,包括from-host和to-host。cilium_net挂载的eBPF程序通过tc的方式完成,包括to-host。
cilium_vxlan:
CiliumAgent在启动的时候,会初始化这个虚拟的网络设备。主要的作用就是完成在overlay网络模式下,基于vxlan/vtep完成跨主机的网络数据通信。
Cilium使用UDP端口作为vtep端点的服务。vxlan的数据包路由,也是通过Kernel的路由子系统完成路由发现,最后通过物理网卡,完成跨主机的overlay网络。cilium_vxlan挂载的eBPF程序通过tc的方式完成,包括from-overlay和to-overlay,具体from-overlay和to-overlay在下面会有相关说明。
lxc-xxx/eth0:
每一个Pod都会有的一对vethpair。这也是容器网络中最常见Linux提供的虚拟网络设备。一端在主机的网络空间,一端在容器的网络空间。
其中eth0是容器端的,lxc-xxx是主机端的。eth0有自己的ip地址,lxc-xxx是没有ip地址的。对于容器的出口流量,使用了tcingress的方式,在lxc-xxx主机端的设备上挂载了eBPF程序,程序的Section是from-container,具体from-container是负责什么,会在下面有相关说明。
每一个Pod的对应的eBPF程序是在创建Pod的时候,由CNI调用CiliumAgent的createendpoint的接口,由这个接口完成Pod相关eBPF程序的编译和挂载。
现在有了from-container来处理Pod的出口流量,那是不是应该也有一个to-container来负责处理Pod的入口流量,同时也挂载在lxc-xxx的tc上?的确是有to-container,但是却不是挂载在lxc-xxx的tc上的,而是保存在eBPF的一种Map中,这种Map是专门用来保存eBPF程序的(BPF_MAP_TYPE_PROG_ARRAY),见图中的POLICY_CALL_MAP这个map中的item。
tcingress/egress:
tc是Linux中的能力,也是有Hook的,同时支持给tc挂载eBPF程序,来处理网络数据包。tc对数据包的处理,支持ingress和egress。
ingress可以理解成数据包进入时候的Hook,还有一个是egress的Hook。两个Hook处理数据包的时机不一样,用来处理的能力也就不一样。tc在Cilium中使用的是最多的,所有的网络设备都可以使用tc,不管是物理的,还是虚拟的都一样。这也是tc为什么在Cilium中被广泛使用。在Cilium还没有支持XDP的南北向的LB的时候,就是由tc来完成LB能力的。
XDPingress:
XDP也是eBPF的Hook点,是数据路径最靠前的Hook点,一般可以用于对数据的快速过滤,以及可以基于XDP实现LB的能力。除了已经在数据路径比较靠前,XDP的支持方式还有3种类型,一种是由硬件来支持,实现XDP的Offload效果;一种是基于硬件网卡驱动,在驱动层实现;一种是Linux内置实现的,也是性能最差的一种,不推荐生产上使用这种方式。越早处理性能越好,所以Offload机制的XDP效果最好,其次是网卡驱动的方式,最后是Linux内置的实现。
eBPFSection:
Section是eBPF程序的执行入口,类似main函数,但是每一个object文件中是可以包含多个Section的。在Cilium中主要包含XDPfrom-netdev,tcfrom-netdev,to-netdev,from-network,from-overlay,to-overlay,from-host,to-host,from-container,to-container,cgroup/connect,cgroup/bind,cgroup/post_bind,cgroup/sendmsg,cgroup/recvmsg,cgroup/getpeername,sk_msg,sockops。
eBPFMaps:
Cilium中使用了很多eBPF中的Maps。从文章开始的技术术语中,了解了相关概念之后,可以从map的name上看得出,这个map主要负责的是哪一部分的能力。
具体主要包括以下这些:cilium_call_policy,cilium_ct4_global,cilium_ct_any4_global,cilium_events,cilium_ipcache,cilium_ipv4_frag_datagrams,cilium_lb4_affinity,cilium_lb4_backends,cilium_lb4_reverse_nat,cilium_lb4_reverse_sk,cilium_lb4_service_v2,cilium_lb_affinity_match,cilium_lxc,cilium_metrics,cilium_nodeport_neigh4,cilium_singals,cilium_snat_v4_external,cilium_tunnel_map,cilium_lb4_maglev,cilium_lb4_source_range,cilium_ipmasq_v4,cilium_encrypt_state,cilium_egress_gw_policy_v4,cilium_ep_to_policy。
还有一小部分是根据运行时生成出来的,如:cilium_policy_[epid],cilium_calls_hostns_[epid],cilium_calls_netdev_[ifindex],cilium_calls_[epid],cilium_policy_[epid]。
XDPfrom-netdev:
这是一个eBPFSection,挂载在物理网卡的tcingress上的eBPF程序。主要的作用是,完成主机数据包到达主机,对数据包进行处理。
只有当开启了ENABLE_NODEPORT_ACCELERATION能力,才会在XDP阶段直接接手处理NodePort的访问。如果是没有开启的,数据包会直接进入内核,由tc的from-netdev来完成NodePort的处理。
当开启了之后,主要还是和tc的from-netdev类似,调用nodeport_lb4完成nodeport类型的LB操作。可以处理外部通过K8sNodePort的服务访问方式,访问服务,包括dnat、lb、ct等操作,将外部的访问流量打到本地的Pod,或者通过XDP的redirect的方式,将数据流量转发到相同网卡或者不同网卡,然后最终将数据流量转发到提供服务的Pod所在的主机。
除了上述能力,对于XDP的from-netdev,如果开启了ENABLE_PREFILTER,还会负责Pre-Filter,可以理解成类似ddos的场景,当不被允许的访问流量到达之后,可以进行一个快速的验证,如果不被允许的,会快速的被Drop掉。
tcfrom-netdev:
这是一个eBPFSection,挂载在物理网卡的tcingress上的eBPF程序。主要的作用是,完成主机数据包到达主机,对数据包进行处理。
这里主要有两个场景会涉及到from-netdev,第一个就是开启了主机的防火墙,这里的防火墙不是iptables实现的,而是基于eBPF实现的HostNetworkPolicy,用于处理什么样的数据包是可以访问主机的;第二个就是开启了NodePort,可以处理外部通过K8SNodePort的服务访问方式,访问服务,包括dnat、lb、ct等操作,将外部的访问流量打到本地的Pod,或者通过tc的redirect的方式,将数据流量转发到to-netdev进行snat之后,再转发到提供服务的Pod所在的主机。
to-netdev:
这是一个eBPFSection,挂载在物理网卡的tcegress上的eBPF程序。主要的作用是,完成主机数据包出主机,对数据包进行处理。
这里主要有两个场景会涉及到to-netdev,第一个就是开启了主机的防火墙,这里的防火墙不是iptables实现的,而是基于eBPF实现的HostNetworkPolicy,用于处理什么样的数据包是可以出主机的,通过handle_to_netdev_ipv4方法完成;第二个就是开启了NodePort之后,在需要访问的BackendPod不在主机的时候,会在这里完成snat操作,通过handle_nat_fwd方法和nodeport_nat_ipv4_fwd方法完成snat。
from-host:
这是一个eBPFSection。挂载在cilium_host的tcegress上eBPF程序。主要完成数据流量导入到Cilium-managed的network中去。举例,如本地进程访问本地主机的Pod。
具体完成的事情大致包含:
1.通过tailcall机制完成要进入到Pod的数据包。参见:
ep_tail_call(ctx,CILIUM_CALL_IPV4_FROM_HOST);
2.通过ipv4_host_policy_egress(ctx,secctx,ipcache_srcid,monitor)完成hostpolicy的验证,也就是eBPF的主机防火墙,这个是在cilium_host的egresspath上,也就是即将要进入到Pod的一侧;
3.通过rewrite_dmac_to_host(ctx,secctx)完成dst的mac地址的设置,将其dst的mac设置成,cilium-host的主机端的cilium_net的mac地址,也就是下一跳,当经过cilium-host的packet,需经过下面步骤查询到的endpoint是localhost的endpoint,这个时候就需要回到host,那回到host的时候,就需要设置packet的目的mac地址为cilium_net的mac地址,这样packet就会被发送到KernelStack去,回到主机上;
4.通过lookup_ip4_endpoint找到要访问的endpoint,然后使用ipv4_local_delivery方法,完成数据包的转发处理。在处理的过程中,会根据是不是有NetworkPolicy来决定是不是要做验证。具体ipv4_local_delivery的作用如下:ipv4_local_delivery这个方法的主要作用,是处理本地的packet到Pod的核心方法。不管是Pod到Pod的,还是cilium_host到Pod的,还是overlay到Pod的,还是物理网卡到Pod的,只要是确定了是本地的endpoint,那packet要进入Pod就是要这个方法来处理的。
to-host:
这是一个eBPFSection,挂载在cilium_host的tcingress上eBPF程序。to-host主要处理的是ENCRYPT加密操作和TO_PROXY。
对于ENCRYPT,主要是将ctx→cb[CB_ENCRYPT_IDENTITY]的srcidentity转换成24bit的identity,然后设置到ctx的mark的value中,用于标记数据包的安全身份;TO_PROXY主要作用是当开启了基于eBPF的tproxy时候,提前抓取proxysocket,然后将其与ctx关联起来,这是tproxy需要的配置,为真正的packet转发到代理做好准备。
from-container:
这是一个eBPFSection,这个Section是和Pod最直接关联的eBPF的程序。挂载在Pod主机侧的虚拟网络设备上,也就是lxc-xxx这个网络设备,方向为ingress。
主要完成的事情包括如下:
1.当packet要从Pod出去,首先packet会经过eth0到达Pod对应的lxc-xxx的tcingress,这里的ebpf程序的Section是from-container。
2.数据包是从Pod发出去的,如果是original类型的数据包,会在这里完成数据包的dnat操作,管理连接跟踪;如果是reply类型的数据包,会完成reversednat的操作。
3.对于有NetworkPolicy验证需要的数据包,会经过tproxy的方式,将数据包发往ciliumproxy去验证是不是可以access,对于正常的从服务端返回的reply数据包,会标记成skippolicy,也就是不需要做验证。具体实现参考policy_can_egress4方法。从Pod里出来的数据包的目的方向大致可以分为几个路径:第一个是Pod访问本地的Pod,经过ipv4_local_delivery来完成数据包的转发;第二个是Pod访问外网,经过KernelStack完成解析后,经过物理网卡的to-netdev出去;第三个是Pod访问本地的非Pod的,也是经过KernelStack完成;第四个是Pod访问非本机的集群其它机器中的Pod,经过KernelStack完成解析后,经过物理网卡to-netdev出去;第五个是Pod经过overlay网络访问非本机的集群其它机器中的Pod,经过cilium_vxlan,然后经过KernelStack完成解析后经过物理网卡出去。
to-container:
这是一个eBPFSection,这是一个比较特别的eBPF的程序。它和Pod相关,但是却不是挂载在tcegress上的,而是以eBPF程序,保存在eBPF中的map中的,eBPF中有一种map类型,是可以保存eBPF程序的(BPF_MAP_TYPE_PROG_ARRAY),同时map中的程序都有自己的id编号,可以用来在tailcall中直接调用,to-container就是其中之一,而且是每一个Pod都有自己独立的to-container,和其它和Pod相关的eBPF程序一样。
它的主要作用就是,在数据包进入Pod进入之前,完成Policy的验证,如果验证通过了会使用Linux的redirect方法,将数据包转发到Pod的虚拟网络设备上。至于是lxc-xxx还是eth0,看内核的版本支持不支持redirectpeer,如果支持redirectpeer,就会直接转发到Pod的eth0,如果不支持就会转发到Pod的主机侧的lxc-xxx上。
from-overlay:
这是一个eBPFSection,在选择使用Cilium的overlay网络模型时,会使用到和overlay相关的虚拟网络设备,这些设备是Agent在启动的时候,在主机空间创建出来的,基于vxlan的技术完成overlay网络。
from-overlay的挂载点,就是挂载在cilium_vxlan这个网络设备的tcingress上的,主要处理的数据包是进入Pod的,在进入Pod之前会先经过cilium_vxlan的from-overlay处理。
主要完成的工作包括以下几点:
1.包括ipsec安全相关的处理;
2.包括将数据包通过ipv4_local_delivery方法,传递到后端服务在本机的Pod中的case,其中也会经过to-container;
3.通过NodePort访问服务时,服务不在本地的时候,使用和from-netdev类似的方式,去处理NodePort的请求,其中包括dnat、ct等操作,最后通过,ep_tail_call(ctx,CILIUM_CALL_IPV4_NODEPORT_NAT)或者ep_tail_call(ctx,CILIUM_CALL_IPV4_NODEPORT_DSR)方法完成数据包的处理,具体是哪种,取决于NodePort的LB策略,是snat还是dsr。
4.数据包都是从物理网卡到达主机的,那是怎样到达cilium_vxlan的?这个是由挂载在物理网卡的from-netdev,根据隧道类型,将数据包通过redirect的方式,传递到cilium_vxlan的。参见:from-netdev的encap_and_redirect_with_nodeid方法,其中主要有两个方法,一是__encap_with_nodeid(ctx,tunnel_endpoint,seclabel,monitor)方法完成encapsulating,二是ctx_redirect(ctx,ENCAP_IFINDEX,0)方法完成将数据包redirect到cilium_vxlan对应的ENCAP_IFINDEX这个ifindex。
to-overlay:
这是一个eBPFSection,在选择使用Cilium的overlay网络模型时,会使用到和overlay相关的虚拟网络设备,这些设备是CiliumAgent在启动的时候在主机空间创建出来的,基于vxlan的技术完成overlay网络。
to-overlay的挂载点就是挂载在cilium_vxlan这个网络设备的egress上的。主要完成的工作包括:通过nodeport_nat_ipv4_fwd和snat_v4_process完成egress方向的snat操作,snat的作用是跨主机访问的时候,需要将源地址改成主机的地址。
to-overlay处理的数据包是通过lxc-xxx的from-container程序redirect过来的数据包,这说明to-overlay处理的是Pod通过vxlan出去的数据包。
from-network:
这是一个eBPFSection,挂载在物理网络的设备中tcingress,如物理机器的eth0网卡,但是这个eBPF的程序是可选的,只有当设置了EncryptInterface的时候,才会编译和挂载这个程序。
主要完成的工作是对数据包的解密操作,如果没有使用ipsec的加密,也就是ENABLE_IPSEC为false,这里不会对数据包有任何修改,直接将数据包放回Kernel。如果使用了IPSEC,解密的时候,才会使用到这个程序,如果没有使用到,这个程序是不需要编译和挂载的。
主要实现的方式是设置ctx的mark为MARK_MAGIC_DECRYPT(0x0D00),然后将数据包放回KernelStack,由KernelStack完成IPsecdecryption。
cgroup/connect,cgroup/bind,cgroup/post_bind,cgroup/sendmsg,cgroup/recvmsg,cgroup/getpeername:
这是一些eBPFSection,在Cilium中,使用了和cgroup相关的eBPF的能力,主要完成的事情是监测socket的ops。在socket的操作过程中,执行相关的eBPF程序来完成SocketLB能力。
举例,当要创建连接的时候,会先做一次dnat,找到真正的后端的Pod的真实ip地址,用真实的ip地址来完成客户端和服务端的连接,而不是通过中间一层代理的方式,这样数据通信的效率得到提升,也是上文提到的HostReachableService的能力体现。包括在创建连接,指定bind的地址,以及发送和接受数据包的过程中,都可以做一些特殊的处理,来提升网络性能。
sk_msg/sockops:
这是一些eBPFSection,在Cilium中支持socket加速的特性,可以完成本地socket和socket之间数据包的redirect,而不需要经过内核底层的网络协议栈。
举例:在一个Pod中有两个容器,这两个容器之间会基于socket进行通信,这个场景是可以基于这个特性完成加速,当然不仅仅支持这一种case,只要是本地的socket之间,都是可以完成加速,因为加速的范围是基于cgroup监听的所有主机上的socket。
主要实现的方式是依赖于eBPF中的sockmap和msg_redirect_hash。sockmap中保存的是socket,msg_redirect_hash是内核提供的,配合sockmap完成socket到socket的数据包的直接redirect。
具体哪些socket需要被处理,通过使用sockops中的能力,监测已经建立连接的socket,将状态为BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB的socket放到sockmap中。sockmap具体对应的eBPF的map类型可以是BPF_MAP_TYPE_SOCKHASH。
04总结
Cilium是一个使用eBPF的技术实现数据路径,在不同的网络设备中redirect数据包,缩短数据路径,达到加速的效果。
特点是高级的特性对Kernel的要求比较高,而且不同的Kernel版本,会导致不同的数据路径。
要想达到最好的网络性能,推荐最低的Kernel的最低版本为5.10。如果只是想让Cilium可以运行起来,那最低的Kernel的最低版本是4.9.17。
作者:熊中祥「DaoCloud道客」技术合伙人云原生技术专家
转载请注明:http://www.0431gb208.com/sjsbszl/4604.html