vyatta使用排错集
2015-01-15 14:25:28 阿炯

1、vyatta使用排错之nf_conntrack table full

2、vyatta使用排错之ping "No buffer space available"


1、vyatta使用排错之nf_conntrack table full

今天上午在使用时,发现在一台高流量高连接量(网页爬虫服务的NAT网关)vyatta软路由突然之间不能连接,内外网皆不能ping通;后之后联系idc的技术,对方接上显示器后发现机器并没有死机,无奈之下只能强制重启网关。

在事后登录进服务器,分析日志发现:
Jan 14 22:36:15 freeoarouter kernel: [3488779.794272] nf_conntrack: table full, dropping packet.
Jan 14 22:36:16 freeoarouter kernel: [3488779.799236] nf_conntrack: table full, dropping packet.
Jan 14 22:36:21 freeoarouter kernel: [3488785.101812] net_ratelimit: 1127 callbacks suppressed
Jan 14 22:36:21 freeoarouter kernel: [3488785.101816] nf_conntrack: table full, dropping packet.
Jan 14 22:36:21 freeoarouter kernel: [3488785.109806] nf_conntrack: table full, dropping packet.
Jan 14 22:36:26 freeoarouter kernel: [3488790.106935] net_ratelimit: 1175 callbacks suppressed
Jan 14 22:36:26 freeoarouter kernel: [3488790.106939] nf_conntrack: table full, dropping packet.
Jan 14 22:36:26 freeoarouter kernel: [3488790.108139] nf_conntrack: table full, dropping packet.
Jan 14 22:36:26 freeoarouter kernelJan 15 09:37:41 freeoarouter kernel: [    0.000000] Linux version 3.3.8-1-amd64-vyatta (root@vyatta) (gcc version 4.4.5 (Debian 4.4.5-8) ) #1 SMP Wed Mar 13 10:35:28 PDT 2013

原来是内核的tcp/ip协议栈的nf table满了,不能接收新的连接请求,只能丢弃。

ip_conntrack就是linux NAT的一个跟踪连接条目的模块,ip_conntrack模块会使用一个哈希表记录 tcp 通讯协议的 established connection记录,当这个哈希表满了的时候,便会导致nf_conntrack: table full, dropping packet错误。

nf_conntrack 工作在 3 层,支持 IPv4 和 IPv6,而 ip_conntrack 只支持 IPv4。目前大多的 ip_conntrack_* 已被 nf_conntrack_* 取代,很多 ip_conntrack_* 仅仅是个别名,原先的 ip_conntrack 的 /proc/sys/net/ipv4/netfilter/ 依然存在,但是新的 nf_conntrack 在 /proc/sys/net/netfilter/ 中,这个应该是做个向后的兼容。

nf_conntrack/ip_conntrack 用于nat来跟踪连接条目,它会使用一个哈希表来记录 established 的记录。nf_conntrack 在 2.6.15 被引入,而 ip_conntrack 在 2.6.22 被移除,如果该哈希表满了,就会出现上述的日志记录,时间一长系统就不可用了。

# more /proc/sys/net/netfilter/nf_*

查看目前 ip_conntrack buffer 的使用状况
more /proc/slabinfo |grep conntrack

nf_conntrack_expect      0      0    216   37    2 : tunables    0    0    0 : slabdata      0      0      0
nf_conntrack_ffffffff817cdf80 285487 310436    288   28    2 : tunables    0    0    0 : slabdata  11087  11087      0

第二行的第2列到第5列分别表示如下:
the number of currently active objects
the total number of available objects
the size of each object in bytes
the number of pages with at least one active object

查看当前系统的nf_conntrack的状态:
# sysctl -a|grep nf_conntrack
这里仅列出相关项:
...
net.netfilter.nf_conntrack_tcp_timeout_established = 432000

net.netfilter.nf_conntrack_max = 262144

net.netfilter.nf_conntrack_buckets = 32768

...

我的修改如下(/etc/sysctl.conf),因为机器内存较多。因为是http应用,432000s(5天)的超时是实在不可思议,我改为600s。

net.nf_conntrack_max = 655360
net.netfilter.nf_conntrack_tcp_timeout_established = 600
net.netfilter.nf_conntrack_buckets = 50000

完成修改后,使用sysctl -p使之生效,在用sysctl -a|grep nf_conntrack检查一下。

参考来源:
nf_conntrack: table full, dropping packet问题的解决思路

kernel: nf_conntrack: table full, dropping packet解决办法

Conntrack tuning

Netfilter conntrack performance tweaking, v0.8



2、vyatta使用排错之ping "No buffer space available"

现象:在ipsec局域网中时不时会ping不通另一个网段加入的新机器地址,在vyatta上只要一ping通就又好了。有时会报出上面的提示,然后ping退出。执行'show nat source translations'根本就出不来。


从网络上的资料可以大致总结一下:
发现问题是ARP缓存过小导致的,内核维护的arp表过于庞大,发生抖动,因此导致了这种情况。几个内核ARP参数:
===============================
gc_stale_time
决定检查一次相邻层记录的有效性的周期。当相邻层记录失效时,将在给它发送数据前,再解析一次。缺省值是60秒。

gc_thresh1
存在于ARP高速缓存中的最少层数,如果少于这个数,垃圾收集器将不会运行。缺省值是128。

gc_thresh2
保存在 ARP 高速缓存中的最多的记录软限制。垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。缺省值是 512。

gc_thresh3
保存在 ARP 高速缓存中的最多记录的硬限制,一旦高速缓存中的数目高于此,垃圾收集器将马上运行。缺省值是1024。

base_reachable_time
设置arp缓存的老化时间,默认是30s。
===============================

比如arp -an|wc -l的结果是300左右, 那么应当调高gc_thresh各项数值以防止抖动的发生。我的值是2836,就必须要调整了。

命令如下:

echo "512" > /proc/sys/net/ipv4/neigh/default/gc_thresh1
echo "2048" > /proc/sys/net/ipv4/neigh/default/gc_thresh2
echo "4096" > /proc/sys/net/ipv4/neigh/default/gc_thresh3
echo "60" > /proc/sys/net/ipv4/neigh/eth0/base_reachable_time
echo "120" > /proc/sys/net/ipv4/neigh/default/gc_stale_time

查看一下新的设置值:
cat /proc/sys/net/ipv4/neigh/default/gc_thresh*

也可以写入内核配置文件中
# vim /etc/sysctl.conf

在sysctl.conf最后面写入下面几行,如下:
net.ipv4.neigh.default.gc_thresh1 = 512
net.ipv4.neigh.default.gc_thresh2 = 2048
net.ipv4.neigh.default.gc_thresh3 = 4096
net.ipv4.neigh.eth0.base_reachable_time = 60
net.ipv4.neigh.default.gc_stale_time = 120

下面这条的作用是:当有个多个网卡,每个网卡在不同的网段,那么可以过滤掉非本网卡ARP请求的回应;但是如果多个网卡的ip在一个网段,那么就不行了。
net.ipv4.conf.all.arp_filter = 1

提高端口的利用率:
net.ipv4.tcp_fin_timeout=2
net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1

参考来源

Coping with the TCP TIME-WAIT state on busy Linux servers

How to receive a million packets per second

LVS 使用过程中的问题集(Socket连接消耗过度导致服务终止)

Ping 跨内网vyatta的机器(两段地址),多数时间都不通的情形。发现在系统级日志中有报警:

[57323810.012075] ipv4: Neighbour table overflow.
[57323810.026585] ipv4: Neighbour table overflow.
[57323810.031165] ipv4: Neighbour table overflow.
[57323810.032973] martian source 203.208.0.89 from 43.243.0.3, on dev eth0
[57323810.032977] ll header: ff:ff:ff:ff:ff:ff:d4:ae:52:6a:51:41:08:06
[57323810.040903] ipv4: Neighbour table overflow.

搜索得到如下说法:

第一种

内核维护的arp表过于庞大, 发生抖动, 因此导致了这种情况,几个内核ARP参数:
=================================
gc_stale_time
决定检查一次相邻层记录的有效性的周期。当相邻层记录失效时,将在给它发送数据前,再解析一次。缺省值是60秒。

gc_thresh1
存在于ARP高速缓存中的最少层数,如果少于这个数,垃圾收集器将不会运行。缺省值是128。

gc_thresh2
保存在 ARP 高速缓存中的最多的记录软限制。垃圾收集器在开始收集前,允许记录数超过这个数字 5 秒。缺省值是 512。

gc_thresh3
保存在 ARP 高速缓存中的最多记录的硬限制,一旦高速缓存中的数目高于此,垃圾收集器将马上运行。缺省值是1024。
=================================
比如arp -an|wc -l的结果是300左右, 那么应当调高gc_thresh各项数值,防止抖动的发生:
而我的vyatta的结果是:
root@shsbrouter:~# arp -an|wc -l
7842

算是很大了,近段时间加了很多的虚拟机,调整如下:
net.ipv4.neigh.default.gc_thresh1 = 2048
net.ipv4.neigh.default.gc_thresh2 = 4096
net.ipv4.neigh.default.gc_thresh3 = 8192
#Set ARP cache entry timeout
net.ipv4.neigh.default.gc_stale_time = 3600
#Force gc to clean-up quickly
net.ipv4.neigh.default.gc_interval = 3600

第二种
默认路由或者子网掩码设置错误,检查,下面是他人的分析过程:

于是查看了下 ARP 表,发现ARP表不断的在增长.一度增长到730多条记录.理论上来说,机器应该只会保存一条ARP记录,就是网关的.而现在保存了很多条记录,都是公网IP对应网关MAC地址的记录.以为是机器被人入侵了,种下了ARP欺骗神马的程序. 通过 tcpdump 抓包发现,确实是本机不断的在发送ARP请求包. 找了一个多小时,硬是没找到原因.

后来通过访问本机上的某个服务,ARP表中立即就增加了一条ARP记录. 是我的出口的IP,对应的服务器网关的MAC.

于是,理了一下思绪,为什么ARP表中的记录不是网关的MAC,而是直接对应我用户的公网IP和服务器网关的MAC地址.看一下网络通信的流程:

1. 用户请求服务器的服务到达服务器

2. 服务器响应请求,首先查找本机的路由表,如果有路由,直接通过该接口将数据丢过去.如果没有路由,则将数据丢给默认网关.

3. 丢数据出去,得解析ARP,将IP转换为MAC地址. 二层都是通过MAC地址通信的嘛

4. 于是查找本地的MAC地址表,有记录则发送过去.没记录,则广播ARP. 问谁是 x.x.x.x .

5. 现在的问题很显然是服务器在不断的广播ARP,而响应的则是服务器网关.而服务器网关是交换机.顺便查了下,交换机的代理ARP功能. 而这个功能交换机一般默认都是开启的.

6. 于是不断的添加ARP记录到ARP表中,都是用户的访问IP和网关的MAC地址

6. 去查了一下路由表,震惊了. 网关居然配置的自己本身的接口IP地址,而不是网关的IP. 怪不得.

7. 默认路由是自己的接口IP,为嘛还能与外界通信? 因为服务器是跟网关直连的呀! 我勒个擦


所以, 我这个问题,验证了第二种方法,默认路由或者子网掩码设置错误!而这个错误,导致了ARP记录过于庞大,最终服务器挂了.

而我的情况类似,查看系统的arp列表:
...
? (104.78.24.70) at <incomplete> on eth3
? (172.16.1.82) at 52:54:00:4d:46:a2 [ether] on eth2
? (115.205.7.146) at <incomplete> on eth3
? (121.29.54.59) at <incomplete> on eth3
? (172.16.0.154) at 52:54:00:eb:59:16 [ether] on eth2
? (60.28.113.115) at <incomplete> on eth3
? (184.105.247.200) at <incomplete> on eth3
? (184.105.139.103) at <incomplete> on eth3
? (49.115.26.151) at <incomplete> on eth3
? (211.90.37.133) at <incomplete> on eth3
...