Oracle Linux 6.5中/proc/net/snmp不显示Udp InCSumErrors的排查与疑问
嘿,我来帮你解决这两个问题,结合你提到的内核代码细节,咱们一步步说:
你的Oracle Linux 6.5用的是2.6.32内核,这个版本的UDP SNMP统计项命名和EL7(比如你说的OL7.4)不一样——EL7里的InCsumErrors在EL6里对应的是CsumErrors,你可以通过以下两种方式查看:
用netstat命令快速查看:
执行netstat -su,输出的UDP部分里会有Checksum errors字段,这就是你要找的校验和错误统计:$ netstat -su Udp: 14520 packets received 312 packets to unknown port received. 0 packet receive errors 14208 packets sent 0 receive buffer errors 0 send buffer errors 18 checksum errors直接读取内核proc文件:
执行cat /proc/net/snmp | grep UDP,输出里的CsumErrors就是对应统计值:$ cat /proc/net/snmp | grep UDP UDP: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors CsumErrors UDP: 14520 312 22 14208 0 0 18
你猜的没错——即使RcvbufErrors为0,InErrors也可能由校验和之外的原因导致,这和你在内核代码里的发现完全一致。结合2.6.32内核的udp.c源码,我整理了几个典型场景:
非法的UDP数据包格式
比如收到的UDP数据包长度小于UDP头部长度(8字节),或者UDP头部里的长度字段和实际数据包长度不匹配,内核会直接丢弃数据包并递增UDP_MIB_INERRORS,但不会触发校验和错误或接收缓冲区错误:if (udp_hdr(skb)->len < sizeof(struct udphdr) || ntohs(udp_hdr(skb)->len) < sizeof(struct udphdr)) { UDP_INC_STATS_BH(UDP_MIB_INERRORS); goto drop; }内存分配失败
当内核尝试复制或克隆接收的skb(套接字缓冲区)时,如果内存不足导致操作失败,会递增UDP_MIB_INERRORS,但这不属于接收缓冲区满的情况(所以RcvbufErrors保持0):skb = skb_clone(skb, GFP_ATOMIC); if (!skb) { UDP_INC_STATS_BH(UDP_MIB_INERRORS); goto out; }IP层传递的数据包存在异常
如果IP层校验和正确,但数据包内容存在其他问题(比如IP选项错误、分段重组失败后传递给UDP的skb有缺陷),UDP层无法正常处理时也会递增InErrors,同样不会关联到CsumErrors或RcvbufErrors。
所以总结一下:InErrors是UDP层接收失败的总入口,校验和错误、接收缓冲区满只是其中两个细分场景,还有不少其他情况会触发它。
内容的提问来源于stack exchange,提问作者David Castell

