有个人长的像洋葱,走着走着就哭了…….

关于af_packet启动失败的分析

Beats | 作者 ggg | 发布于2017年10月25日 | 阅读数:4671

之前产品基于旁路分析采用的是pf_ring的抓包模式
最近需要在相关服务器上安装packetbeat来监控指定流量,pf_ring涉及到内核模块不太适用在生产环境动内核
因此改用af_packet抓包模式
没想到使用af_packet模式时遇到一个坑,经google发现有网友也遇到了同样的问题,链接如下:https://discuss.elastic.co/t/p ... 94640 
配置:


packetbeat.interfaces.type: af_packet
packetbeat.interfaces.snaplen: 1514


故障现象是packetbeat在流量不大的情况下都会有丢包
经dump抓包分析发现会抓到超过以太网mtu大小的包,而配置的snaplen是1514,所以丢了部分内容
为什么以太网包会抓到超过mtu大小,其实是因为本机网卡TSO offload的缘故,也解释了旁路镜像没有这种坑
一种方法就是关闭TSO offload,一种就是调大snaplen
结果调到TCP窗口大小65535时packet启动报错:


CRIT Exiting: Initializing sniffer failed: Error creating sniffer: setsockopt packet_rx_ring: cannot allocate memory Exiting: Initializing sniffer failed: Error creating sniffer: setsockopt packet_rx_ring: cannot allocate memory


strace提示


 setsockopt(4, SOL_PACKET, PACKET_RX_RING, {block_size=8388608, block_nr=3, frame_size=65536, frame_nr=384}, 16) = -1 ENOMEM (Cannot allocate memory)


也就是申请8Mb的连续内存失败,跟踪内核源码
net/packet/af_packet.c中packet_setsockopt()->packet_set_ring()->alloc_pg_vec()->alloc_one_pg_vec_page()
最后调用到__get_free_pages()
在linux 2.6的内核中,__get_free_pages()可以申请得到的内存最大是2^MAX_ORDER个内存页面
而MAX_ORDER在内核编译前已确定为10,一个内存page为4k
所以只能申请到4Mb的连续内存块
 
至此搞清楚为什么设置snaplen为65535后无法启动packetbeat了 
目前只能牺牲点offload带来的一点点性能提升 
ethtool -K em2 TSO off          
 
已邀请:

要回复问题请先登录注册