
连接跟踪(conntrack)
连接跟踪是许多网络应用的基础。例如,Kubernetes Service、ServiceMesh sidecar、 软件四层负载均衡器 LVS/IPVS、Docker network、OVS、iptables 主机防火墙等等,都依赖连接跟踪功能。
连接跟踪,顾名思义,就是跟踪(并记录)连接的状态。 例如,图 1.1 是一台 IP 地址为 10.1.1.2 的 Linux 机器,我们能看到这台机器上有三条 连接:
-
机器访问外部 HTTP 服务的连接(目的端口 80)
-
外部访问机器内 FTP 服务的连接(目的端口 21)
-
机器访问外部 DNS 服务的连接(目的端口 53)
连接跟踪所做的事情就是发现并跟踪这些连接的状态,具体包括:
-
从数据包中提取元组(tuple)信息,辨别数据流(flow)和对应的连接(connection)。
-
为所有连接维护一个状态数据库(conntrack table),例如连接的创建时间、发送 包数、发送字节数等等。
-
-
需要注意的是,连接跟踪中所说的“连接”,概念和 TCP/IP 协议中“面向连接”(connection oriented)的“连接”并不完全相同,简单来说:
-
TCP/IP 协议中,连接是一个四层(Layer 4)的概念。TCP 是有连接的,或称面向连接的(connection oriented),发送出去的包都要求对端应答(ACK),并且有重传机制。UDP 是无连接的,发送的包无需对端应答,也没有重传机制。
-
conntrack(CT) 中,一个元组(tuple)定义的一条数据流(flow )就表示一条连接(connection)。后面会看到 UDP 甚至是 ICMP 这种三层协议在 CT 中也都是有连接记录的,但不是所有协议都会被连接跟踪。
Netfilter
Linux 的连接跟踪是在 Netfilter 中实现的。
Netfilter 是 Linux 内核中一个对数据 包进行控制、修改和过滤(manipulation and filtering)的框架。它在内核协议栈中设置了若干 hook 点,以此对数据包进行拦截、过滤或其他处理。
现在提到连接跟踪(conntrack),可能首先都会想到 Netfilter,Netfilter 只是 Linux 内核中的一种连接跟踪实现。换句话说,只要具备了 hook 能力,能拦截到进出主机的每个包,完全可以在此基础上自己实现一套连接跟踪。
云原生网络方案 Cilium 在 1.7.4+ 版本就实现了这样一套独立的连接跟踪和 NAT 机制 (完备功能需要 Kernel 4.19+)。其基本原理是:
-
基于 BPF hook 实现数据包的拦截功能(等价于 netfilter 里面的 hook 机制)
-
在 BPF hook 的基础上,实现一套全新的 conntrack 和 NAT 因此,即便卸载掉 Netfilter ,也不会影响 Cilium 对 Kubernetes ClusterIP、NodePort、ExternalIPs 和 LoadBalancer 等功能的支持。由于这套连接跟踪机制是独立于 Netfilter 的,因此它的 conntrack 和 NAT 信息也没有 存储在内核的(也就是 Netfilter 的)conntrack table 和 NAT table。所以常规的 conntrack/netstats/ss/lsof 等工具是看不到的,要使用 Cilium 的命令,例如:
$ cilium bpf nat list$ cilium bpf ct list global