全流量入侵检测系统的性能分析

问题背景

16年在房多多的时候参与开发nids,用bro来做抓包、解包和规则引擎。

当时对bro解析http的成功率做测试,生产环境中发现差不多有10%-20%的http请求并没有解析成功。

我当时的测试思路如下:

  • 客户端发送http请求,请求中带有特殊标记
  • 统计bro http日志中有带有标记的数量

10%-20%的解析失败,意味着有可能有攻击行为没有检测到。因此需要提升http流量解析的成功率。

当时在网上也搜到一些提升抓包性能的方案,比如pf_ring、dpdk等。不过当时理解不了原理,最近补了一些网络方面的知识,所以就来回顾一下这个案例。

我主要想弄清楚以下问题:

  • pf_ring真的能提高抓包性能么?
  • pf_ring为什么能提高性能?

基于以下两点原因,本文只讨论pf_ring、不讨论dpdk:

  • 端口扫描工具masscan支持pf_ring,而不支持dpdk。我后面要分析masscan
  • 精力有限,而pf_ring技术点比dpdk似乎要少一些、简单一点

另外本文只讨论 pf_ring的三种模式 中的默认模式

分析过程

  • 先理解一下”问题背景”里场景的性能

    从网卡上的流量到bro将http请求写到日志中,可以大概分成三个部分:

    1
    2
    3
    * 抓包(包从网卡到用户空间)
    * 解包(解析出http、dns、ssh、ftp等应用层协议)
    * 写磁盘

    这每一步都会有性能损耗,但是性能损耗的占比可能不同。所以仅提升”抓包”这一部分的性能有可能并不能提升整体性能。

    用一些性能工具(比如perf)结合代码 应该可以看出来bro每个阶段的cpu消耗占比。

    这篇文章只关注”抓包”这个环节的性能。

  • 为什么会丢包?

    丢包的原因太多了,在网络传输 -> 网卡 -> 驱动 -> 内核sk_buff -> tcp/ip协议栈 -> 用户态每一个环节都有可能丢包。

    可以看 图解Linux网络包接收过程 这篇文章了解完整的收包过程。

    关于”排查各个环节丢包的工具和思路”,由于没有实践过多少,这里就不推荐啥文章了。

  • 抓包过程中的性能和哪些因素有关?

    目前我理解的主要和三个方面有关:

    1
    2
    3
    * 内存拷贝的次数
    * 内核处理网卡中断的频率
    * 系统调用产生的中断次数

    所以pf_ring做了以下事情:

    1
    2
    3
    * 通过mmap映射,减少了一次内存拷贝
    * 通过napi机制减少内核响应网卡硬中断的次数
    * 也因为mmap映射,用户层不需要频繁地通过recvfrom等系统调用获取网络包

    如果想了解mmap怎么实现内核态和用户态的内存映射,可以参考 文章中的示例1 ,有demo代码可以跑起来。

    pf_ring的实现方式和文章中的差不多:

    1
    2
    * 内核同样会注册mmap函数供用户态调用
    * 内核同样会调用`remap_pfn_range`函数来做内存映射

    如果想了解napi机制,可以看 napi官方文档

    我对napi的理解:

    1
    2
    3
    * 它的作用是:将包从网卡放到内核内存
    * 如果每次都是网卡产生中断告诉cpu有数据包来了,在流量大的请求下就需要响应中断很多次。napi减少了硬中断的响应次数,所以提升了性能。
    * 它由内核驱动实现

    如果想了解napi和非napi的实现上的区别,可以参考 Linux kernel 链路层帧接收 并对照内核源码分析。此文章简要分析了两个驱动,分别代表了napi实现和非napi实现。

  • pf_ring真的可以提高libpcap性能么?

    新版本的libpcap采用PACKET_MMAP方式收包。

    PACKET_MMAP是内核实现的一种机制,发包和收包都可以用这个技术。它同样使用mmap减少了内存拷贝和系统调用,因此提升了性能。

    PACKET_MMAP的详细介绍推荐看内核文档,写得比较全(内容比较多,我也没完整过一遍)。

    我对”基于pf_ring非零拷贝的libpcap”和”基于packet_mmap的libpcap”对比,结论如下:

    1
    2
    3
    * 两者内存拷贝次数一样
    * 两者使用相同的驱动,都用到了napi
    * 用户态读数据时,基本都不需要经过系统调用

    根据这个对比,我觉得”pf_ring非零拷贝模式”应该不会大幅度提高抓包性能。

    为了验证自己的结论,就做个实验来看看。

  • 实验验证

    在自己实验前,看到 PF_RING与NAPI结合的捕包性能优化和仿真.pdf 这篇实践文章,推荐阅读。此文章结论是pf_ring可以提高抓包性能

    我做的实验过程见公众号中另一篇文章”验证pf_ring性能”,结论是pf_ring可以提高抓包成功率。

    实验结果上虽然可以看出来提高抓包成功率,但是看不出来是否有大幅度提升。

总结

实验的结论和我自己对原理的分析并没有对应上,也并没有完全解决我自己一开始想弄清楚的问题。

因为文章中的很多技术我在研究案例之前不怎么知道,另外也没有找到搞网络的大佬愿意帮我校对文章,所以不能保证文章中的结论都是对的。

如果读者发现有什么错误的地方,请公众号后台私信我。