在Kubernetes节点上安装我们的流量检测模块之后所有的Pod
会断网。经分析是由于流量检测模块的NFQUEUE
机制与kube-proxy
使用的iptables
的mark
机制冲突的原因。
在Linux内核中,网络数据包是由sk_buff
结构来表示的,一般数据包简写作SKB
。mark
是sk_buff
结构的一个字段, 如(include/linux/skbuff.h
):
1 | struct sk_buff { |
mark
并不是网络协议结构的部分,不会存在于任一层协议头中,而是Linux网络子系统用于在主机内部传递状态信息的标记机制。各种网络应用可以根据自身需要使用该字段来实现自身的状态传递。
这个mark
机制主要用在netfilter
框架中,所以也叫nfmark
。除了它之外,内核中还有conntrack
模块也有自己的mark
机制,一般叫做ctmark
。
之前的文章<<基于IPTABLES MARK机制实现策略路由>>也介绍过iptables
的MARK
模块,可以用于修改和匹配数据包的mark
值。
NFQUEUE
机制可以在内核中将数据通过NFQUEUE
通道将数据包送往用户态,在用户态进行安全检测,再将裁决(verdict
)结果送回内核。之前的文章<<NFQUEUE和libnetfilter_queue实例分析>>介绍了libnetfilter_queue
库的简单用法。我们的流量检测程序会使用libnetfilter_queue
库中的nfq_set_verdict2
在返回verdict
的同时,设置数据包的mark
值,以传递更多的信息给内核模块,函数原型如下:
1 | int nfq_set_verdict2(struct nfq_q_handle * qh, |
这就会导致数据包sk_buff
结构的mark
值被设置。而kube-proxy
实现也依赖iptables
的mark
机制, 会在主机上添加如下iptables
规则:
1 | -A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000 |
对于不合法的报文,kube-proxy
会给相应报文标记0x8000/0x8000
, 之后通过KUBE-FIREWALL
规则链将数据包丢弃。
如果我们的流量检测程序所设置的mark
值设置为kube-proxy
所依赖的0x8000
位,就会导致数据包被丢弃。