问题场景

我们使用suricata来做流量分析,suricata部署在一台多网卡的48核心的物理机上,由于业务需要,suricata监听流量的网卡从5块提升为了6块,新加了网卡enp176s0f1,然后发现suricata的日志中有多条类似报错:

 - [ERRCODE: SC_ERR_PF_RING_OPEN(34)] - Failed to open enp176s0f1: pfring_open error. Check if enp176s0f1 exists and pf_ring module is loaded.

分析

从日志看是由于pfring监听新网卡失败了,要不就是pfring的问题要不就是新网卡的问题。所以,为了缩小目标,需要先定位下是谁的问题。

排查

1,定位是pfring问题的方法:
suricata监听配置中保留新加的网卡enp176s0f1,把suricata监听的6块网卡改成小于等于5块,suricata运行正常。
2,查看系统日志是否有异常,发现有pfring的提示信息

# dmesg -T
[Tue May 26 11:29:09 2020] [PF_RING] Exceeded the maximum number of list items

3,利用强大的搜索引擎开始搜索报错,发现和MAX_NUM_RING_SOCKETS变量有关系,于是就下载源码开始查这个变量和报错的相关代码。发现是监听ring的socket超过了256导致了报错。

# grep -n MAX_NUM_RING_SOCKETS * -r
kernel/linux/pf_ring.h:34:#define MAX_NUM_RING_SOCKETS          256
kernel/linux/pf_ring.h:344:#define MAX_NUM_LIST_ELEMENTS MAX_NUM_RING_SOCKETS /* sizeof(bits_set) [see below] */
kernel/linux/pf_ring.h:998:#define MAX_NUM_ZC_BOUND_SOCKETS MAX_NUM_RING_SOCKETS

# grep  -n 'Exceeded the maximum number of list items' * -r
kernel/pf_ring.c:606:    printk("[PF_RING] Exceeded the maximum number of list items\n");

# vim kernel/pf_ring.c +606
 605   if(l->num_elements >= MAX_NUM_LIST_ELEMENTS) {
 606     printk("[PF_RING] Exceeded the maximum number of list items\n");
 607     return(-1); /* Too many */
 608   }

4,我们suricata使用workers模式运行,所以每个线程处理所有逻辑(包含使用pfring抓包)。结合suricata的pfring监听网卡的相关配置,我们发现每块网卡的threads数是auto,默认auto就是使用cpu的核心数48作为线程数。所以,6块网卡suricata启动的线程数就是6*48=288,超过了256的限制,所以最后一块网卡pfring open失败了。

pfring:
  - interface: enp175s0f0
    threads: auto
    cluster-id: 81
    cluster-type: cluster_flow
  - interface: enp175s0f1
    threads: auto
    cluster-id: 82
    cluster-type: cluster_flow
  - interface: enp24s0f1
    threads: auto
    cluster-id: 83
    cluster-type: cluster_flow
  - interface: enp24s0f0
    threads: auto
    cluster-id: 84
    cluster-type: cluster_flow
  - interface: enp176s0f1
    threads: auto
    cluster-id: 85
    cluster-type: cluster_flow
  - interface: enp134s0f1
    threads: auto
    cluster-id: 86
    cluster-type: cluster_flow

解决

1,增大源码中MAX_NUM_RING_SOCKETS的value,然后重新制作rpm包
2,根据每块网卡流量大小,合理调整threads数。对应流向小的网卡,threads调整为8,流量大的网卡调整大点,所有网卡的threads数量不超过256即可。(建议)

参考

https://groups.google.com/forum/#!topic/security-onion/uiR9zSmu9Zc
https://github.com/ntop/PF_RING