版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明 (作者:张华 发表于:2018-02-08)
conntrack遇到了’nf_conntrack: table full, dropping packet’怎么办?
Ubuntu上和conntrack相关的命令如下:
sudo apt install conntrack
sudo conntrack -L
sudo find /proc/ -name '*conntrack*'
sudo sysctl -a | grep conntrackroot@t440p:~# grep nf_conntrack /proc/slabinfo
nf_conntrack_expect 0 0 224 36 2 : tunables 0 0 0 : slabdata 0 0 0
nf_conntrack 425 425 320 25 2 : tunables 0 0 0 : slabdata 17 17 0
Ubuntu上的默认值如下:
root@t440p:~# sudo sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_max net.netfilter.nf_conntrack_tcp_timeout_established net.netfilter.nf_conntrack_buckets
net.netfilter.nf_conntrack_count = 77
net.netfilter.nf_conntrack_max = 262144
net.netfilter.nf_conntrack_tcp_timeout_established = 432000
net.netfilter.nf_conntrack_buckets = 65536
- net.netfilter.nf_conntrack_count为已建立连接,当net.netfilter.nf_conntrack_count > net.netfilter.nf_conntrack_max时会报错”ip_conntrack table full dropping packet”
- net.netfilter.nf_conntrack_tcp_timeout_established为ESTABLISHED的时间,默认为5天。
- net.netfilter.nf_conntrack_max可由公式(CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (ARCH / 32))计算得到,以16G的64位操作系统为例,CONNTRACK_MAX = 16*1024*1024*1024/16384/2 = 524288
- net.netfilter.nf_conntrack_buckets哈希表大小通常为总表的1/8,最大为1/2。CONNTRACK_BUCKETS = CONNTRACK_MAX / 8, 同样64G的64位操作系统,哈希最佳范围是 262144 ~ 1048576。正常地除以4即可(hashsize = nf_conntrack_max / 4), hashsize = 524288 / 4 = 131072
所以可使用下列配置:
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=524288
sysctl -w net.netfilter.nf_conntrack_buckets=131072
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established = 86400
如果这些配置还不能解决问题,可以从业务上将不需要跟踪的网卡排除,或者增大硬件配置:
iptables -t raw -A PREROUTING ! –I NIC -j NOTRACK
下面做了一个失败的试验,记录一下,本来理论上理解的nf_conntrack_tcp_timeout_established这个值应该是建立 establish连接之后的超时时间,如果客户端与服务端均不发消息,经过nf_conntrack_tcp_timeout_established这个时间后,conntrack表项就会被删除,然后服务器再主动给客户端发消息就会失败。但实际我测试的结果是我无论将nf_conntrack_tcp_timeout_established配置多大,过一两分钟conntrack表项都会被删除,并且服务器也能主动给客户端发消息时这个表项又会被重建。暂不清楚什么原因,有记录这里,有时间再弄。
该实验将证明nf_conntrack_tcp_timeout_established这个值不能低于业务中长连接的最长时间。但实际实验结果失败,表项被删除之后服务端还能往客户端发包。
在物理机(192.168.99.137)上启动一虚机(192.168.122.48), 物理机默认有状态防火墙配置。
hua@t440p:~$ sudo iptables-save |grep 122 |grep FORWARD
-A FORWARD -d 192.168.122.0/24 -o virbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT物理机上为方便实验做如下设置将ESTABLISHED的超时时间从5天改成4分钟:
root@t440p:~# sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=240
net.netfilter.nf_conntrack_tcp_timeout_established = 240
root@t440p:~# sysctl -p1, 在物理机上启动Server,
hua@t440p:~$ python
Python 2.7.12 (default, Nov 20 2017, 18:23:56)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(("192.168.99.137",8888))
serversocket.listen(5)
(clientsocket, address) = serversocket.accept()
#clientsocket.recv(1000)
#clientsocket.send("respond",100)2, 在虚机里启动Client, 并向服务器发送数据,但不关闭连接。
hua@xenial:~$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0",22222))
s.connect(("192.168.99.137", 8888))
s.send("request", 100)
#s.recv(1000)我们看到了conntrack中有相关记录项,它为ESTABLISHED状态。
root@t440p:~# netstat -tn |grep 8888
tcp 14 0 192.168.99.137:8888 192.168.122.48:22222 ESTABLISHED
root@t440p:~# conntrack -L |grep 8888
tcp 6 431884 ESTABLISHED src=192.168.122.48 dst=192.168.99.137 sport=22222 dport=8888 src=192.168.99.137 dst=192.168.122.48 sport=8888 dport=22222 [ASSURED] mark=0 use=13, 等4分钟(nf_conntrack_tcp_timeout_established=240)不发包, conntrack表项超时被清空,理论上应该此时无法再从服务端往客户端发包。但实际测试结果是还能发,conntrack表项又会被重建。与理论不符啊,纠结中。root@t440p:~# conntrack -L |grep 8888
conntrack v1.4.3 (conntrack-tools): 46 flow entries have been shown.
root@t440p:~# netstat -tn |grep 8888
tcp 7 0 192.168.99.137:8888 192.168.122.48:22222 ESTABLISHED