概述
Linux内核在网络堆栈中支持挂载BPF Hook,可用于运行BPF程序。Cilium数据路径使用这些钩子加载BPF程序,组合使用并创建高级别的网络结构。
下面是Cilium使用的钩子列表和简要说明。有关每个挂钩的详细信息,请参阅BPF和XDP参考指南。
- XDP: XDP BPF钩子尽可能早地出现在网络驱动程序中,网络设备收到数据包时触发BPF程序的运行。因为程序在所有其它处理发生之前直接在分组数据上运行,它对性能提升的收益。此挂钩非常适合运行过滤程序,以丢弃恶意或意外流量,以及其他常见的DDOS保护机制。
- Traffic Control Ingress/Egress: 流量控制(tc)ingress 挂钩的BPF程序连接到网络接口,但将在网络堆栈完成数据包的初始处理后运行。与XDP相同的是钩子在堆栈的L3层之前运行,但可以访问与数据包相关联的大部分元数据。这是进行本地节点处理的理想选择,例如应用L3/L4端点策略和将流量重定向到端点。对于面向网络的设备,tc ingress钩子可以与上述XDP钩子耦合。完成此操作后,可以合理地假设此时的大部分流量都是合法的,并且目的地是主机。
容器通常使用称为veth对的虚拟设备,该虚拟设备充当将容器连接到主机的虚拟线路。通过连接到该veth对主机侧的TC入口钩子,Cilium可以监视并强制执行离开容器的所有流量的策略。通过将BPF程序附加到与每个容器相关联的veth对,并将所有网络流量路由到主机侧虚拟设备,同时将另一个BPF程序连接到tc入口钩子,Cilium可以对进入或离开节点的所有流量进行监控并实施策略。
- Socket operations: 套接字操作挂钩连接到特定的cgroup,并在TCP事件上运行。Cilium将BPF套接字操作程序附加到root cgroup,并使用该程序监视TCP状态转换,特别是已建立的状态转换。当套接字转换为已建立状态时,如果TCP套接字具有节点本地对等方(可能是本地代理),则BPF会附加套接字发送/接收程序。
- Socket send/recv: 套接字发送/接收钩子在TCP套接字执行的每个发送操作上运行。此时,钩子可以检查消息,或者丢弃消息,将消息发送到TCP层,或者将消息重定向到另一个套接字。Cilium使用它来加速数据路径重定向,如下所述。
将上述挂钩与虚拟接口(cilium_host、cilium _net)、可选overlay接口(cilium_vxlan)、Linux内核加密支持和用户空间代理(Envoy)cilium相结合,可以创建以下网络对象。
- Prefilter: prefilter对象运行一个XDP程序,并提供一组预过滤器规则,用于过滤来自网络的流量以获得最佳性能。具体而言,Cilium代理提供的一组CIDR映射用于执行查找,并且数据包要么被丢弃(例如,当目标不是有效端点时),要么被允许由堆栈处理。这可以根据需要轻松扩展,以构建新的预过滤器标准/功能。
- Endpoint Policy: 端点策略对象实现Cilium端点强制执行。使用映射查找与身份和策略相关的数据包,该层可以很好地扩展到许多端点。根据策略,该层可能会丢弃数据包、转发到本地端点、转发到服务对象或转发到L7策略对象以获取进一步的L7规则。这是Cilium数据路径中的主要对象,负责将数据包映射到身份并实施L3和L4策略。
- Service: 服务对象对对象接收到的每个数据包在目标IP和可选的目标端口上执行映射查找。如果找到匹配条目,数据包将转发到配置的L3/L4端点之一。服务块可用于通过TC入口钩子在任何接口上实现独立负载平衡器,或者可集成在端点策略对象中。
- L3 Encryption: 在Ingress方向L3加密对象标记要解密的数据包,将数据包传递到Linux xfrm(transform)层进行解密,数据包解密后,对象接收数据包,然后将其传递到堆栈上,供其他对象进一步处理。根据直接路由或Overlay模式,BPF尾部调用或将数据包传递给下一个对象的Linux路由堆栈。解密所需的密钥编码在IPsec报头中,因此在进入时,我们不需要进行映射查找来找到解密密钥。
在出口处,首先使用目的地IP执行映射查找,以确定是否应该加密分组,如果应该,则确定目的地节点上有哪些密钥可用。选择两个节点上可用的最新密钥,并将数据包标记为加密。然后将数据包传递到Linux xfrm层,在那里对其进行加密。在接收到现在加密的数据包后,通过将其发送到Linux堆栈进行路由,或者在使用Overlay的情况下执行直接尾部调用,将其传递到下一层。
- Socket Layer Enforcement: 套接字层强制执行使用两个钩子:套接字操作钩子和套接字发送/接收钩子来监视和连接与Cilium管理的端点相关的所有TCP套接字,包括任何L7代理。套接字操作钩子将识别用于加速的候选套接字。这些包括所有本地节点连接(端点到端点)和到Cilium代理的任何连接。这些已识别的连接将由套接字发送/接收挂钩处理所有消息,并将使用sockmap快速重定向进行加速。快速重定向确保Cilium中实现的所有策略对于关联的套接字/端点映射都有效,并且假设它们是有效的,则将消息直接发送到对等套接字。这是允许的,因为sockmap send/recv钩子确保消息不需要由上述任何对象处理。
- L7 Policy: L7策略对象将代理流量重定向到Cilium用户空间代理实例。Cilium使用Envoy实例作为其用户空间代理。Envoy然后将转发流量或基于配置的L7策略生成适当的拒绝消息。
Iptables Usage
根据使用的Linux内核版本,eBPF数据路径可以完全在eBPF中实现不同的功能集。如果某些必需的功能不可用,则使用传统iptables实现提供该功能。有关更多详细信息,请参见IPsec要求。
kube-proxy Interoperability
下图显示了kube proxy安装的iptables规则与Cilium安装的iptable规则的集成。
数据包生命周期
Endpoint to Endpoint
首先,我们展示了本地端点到端点流,其中包含可选的ingress/egress L7策略。然后是启用套接字层强制执行的同节点端点到端点流。在为TCP通信启用套接字层强制执行的情况下,发起连接的握手将遍历端点策略对象,直到TCP状态ESTABLISHED为止。在ESTABLISHED连接之后,只需要L7策略对象。
Egress from Endpoint
接下来,我们将显示要使用可选的Overlay网络从本地端点发出数据包。在可选的overlay中,网络流量被转发到对应于overlay的Linux网络接口。在默认情况下,覆盖接口名为cilium_ vxlan。与上述类似,当启用套接字层强制并且使用L7代理时,我们可以避免在端点和TCP流量的L7策略之间运行端点策略块。如果启用,可选的L3加密块将加密数据包。
Ingress to Endpoint
最后,我们还展示了通过可选的overlay网络进入本地端点。与上述套接字层类似,可以使用强制执行来避免代理和端点套接字之间的一组策略遍历。如果数据包在接收时被加密,则首先对其进行解密,然后通过正常流进行处理。
这就完成了数据路径概述。更多的BPF细节可以在BPF和XDP参考指南中找到。有关如何扩展L7策略的更多详细信息,请参阅Envoy部分
eBPF Maps
所有BPF映射都是以容量上限创建的。超出限制的插入将失败,从而限制数据路径的可伸缩性。下表显示了贴图的默认值。每个限制都可以在源代码中实现。如果需要,将根据要求添加配置选项。
Map Name | Scope | Default Limit | Scale Implications |
---|---|---|---|
Connection Tracking | node or endpoint | 1M TCP/256k UDP | Max 1M concurrent TCP connections, max 256k expected UDP answers |
NAT | node | 512k | Max 512k NAT entries |
Neighbor Table | node | 512k | Max 512k neighbor entries |
Endpoints | node | 64k | Max 64k local endpoints + host IPs per node |
IP cache | node | 512k | Max 256k endpoints (IPv4+IPv6), max 512k endpoints (IPv4 or IPv6) across all clusters |
Load Balancer | node | 64k | Max 64k cumulative backends across all services across all clusters |
Policy | endpoint | 16k | Max 16k allowed identity + port + protocol pairs for specific endpoint |
Proxy Map | node | 512k | Max 512k concurrent redirected TCP connections to proxy |
Tunnel | node | 64k | Max 32k nodes (IPv4+IPv6) or 64k nodes (IPv4 or IPv6) across all clusters |
IPv4 Fragmentation | node | 8k | Max 8k fragmented datagrams in flight simultaneously on the node |
Session Affinity | node | 64k | Max 64k affinities from different clients |
IP Masq | node | 16k | Max 16k IPv4 cidrs used by BPF-based ip-masq-agent |
Service Source Ranges | node | 64k | Max 64k cumulative LB source ranges across all services |
Egress Policy | endpoint | 16k | Max 16k endpoints across all destination CIDRs across all clusters |
对于某些BPF映射,可以使用cilium-agent
的命令行选项覆盖容量上限。以下参数可以设置容量–bpf-ct-global-tcp-max, --bpf-ct-global-any-max, --bpf-nat-global-max, --bpf-neigh-global-max, --bpf-policy-map-max, --bpf-fragments-map-max --bpf-lb-map-max.
如果指定了
--bpf-ct-global-tcp-max
或--bpf-ct-global-any-max
,则NAT表大小(--bpf-nat-global-max
)不得超过组合ct表大小(tcp+UDP)的2/3。如果未显式设置--bpf-nat-global-max
,或者使用动态bpf映射大小,则会自动设置该值(见下文)。
使用--bpf-map-dynamic-size-ratio
标志,在agent启动时根据给定的总系统内存比率确定几个大型bpf映射的容量上限。例如,给定的比率0.0025将导致这些映射使用的总系统内存的0.25%。
此标志影响以下消耗系统中大部分内存的BPF映射:cilium_ct_{4,6}_global
, cilium_ct_{4,6}_any
, cilium_nodeport_neigh{4,6}
, cilium_snat_v{4,6}_external
and cilium_lb{4,6}_reverse_sk
.
kube-proxy
根据机器拥有的内核数设置linux连接跟踪表中的最大条目数。kube-proxy
的默认值为每个核心最多32768个条目,最小131072个条目,而不管机器拥有多少个核心。
Cilium有自己的连接跟踪表作为BPF映射,这些映射的条目数是根据节点中的总内存量计算的,最少有131072个条目,而不管机器拥有多少内存。
下表显示了kube-proxy
和Cilium在配置Cilium时为自己的连接跟踪表设置的值—--bpf-map-dynamic-size-ratio:0.0025
。
vCPU | Memory (GiB) | Kube-proxy CT entries | Cilium CT entries |
---|---|---|---|
1 | 3.75 | 131072 | 131072 |
2 | 7.5 | 131072 | 131072 |
4 | 15 | 131072 | 131072 |
8 | 30 | 262144 | 284560 |
16 | 60 | 524288 | 569120 |
32 | 120 | 1048576 | 1138240 |
64 | 240 | 2097152 | 2276480 |
96 | 360 | 3145728 | 4552960 |