基于Linux平台的libpcap源码分析和优化
目录
1..... libpcap简介... 1
2..... libpcap捕包过程... 2
2.1 数据包基本捕包流程... 2
2.2 libpcap捕包过程... 4
2.3 libpcap 1.3.0源码对照... 6
2.3.1 创建环形队列... 6
2.3.2 捕获数据包... 6
3..... libpcap捕包优化分析... 7
3.1处理流程单一:... 7
3.2高中断服务负荷:... 8
3.3内核态到用户态上下文选择:... 8
3.4数据拷贝和内存分配消耗:... 8
4..... 延伸拓展... 8
4.1 libpcap多线程捕包... 8
4.2 Linux并行运算... 9
4.3 零拷贝发包... 9
5..... 参考资料:... 9
1. libpcap简介
libpcap是unix/linux平台下的网络数据包捕获函数包,大多数网络监控软件都以它为基础。Libpcap可以在绝大多数类unix平台下工作.Libpcap提供了系统独立的用户级别网络数据包捕获接口,并充分考虑到应用程序的可移植性。Libpcap可以在绝大多数类unix平台下工作。
在windows平台下,一个与libpcap 很类似的函数包 winpcap 提供捕获功能,其官方网站是http://winpcap.polito.it/。

2. libpcap捕包过程
2.1 数据包基本捕包流程
具体的Linux数据包处理流程如图1 所示。数据包从网卡经过内核最终到达用户空间的应用程序,其中经过三次处理:中断服务、软中断和应用程序,使用三个缓存:DMA、包队列和插口。
在网卡驱动中存在运行时内存分配,从内核到用户态时存在一次内存拷贝。

通过对图 1 进行分析可知,以下几个方面的问题可能会限制系统数据包的捕获处理能
力:
1)处理流程单一:整个处理流程串行化,其处理能力受限于整个流程的任何一处“短
板”。在多核架构系统中这样的处理方式无法发挥并行优势,存在极大的资源浪费。
2)高中断服务负荷:由于采用每接收一个数据包就产生一次中断的方式,当数据包以
很高的速率到达时,即使最快的处理器也会被持续的中断服务请求占用而无法处理数据包,从而导致数据包丢失。
3)内核态到用户态上下文选择:当数据包由内核态进入用户态时会发生上下文选择切
换,从而导致用户态任务延迟几毫秒开始。
4)数据拷贝和内存分配消耗:DMA 缓存、内核及用户内存间的数据拷贝占用了大量的CPU 资源。
2.2 libpcap捕包过程

在Linux中,数据包捕获的基础是PACKET套接字,libpcap是对PACKET套接字的简单封装.上图是libpcap的结构图,图中的流程分为两部分,箭头表示数据包的流向.上图左半部由网络子系统发起,是PACKET套接字捕获数据包的过程.PACKET套接字在网络协议栈和网卡(network interface card,NIC)设备之间设置钩子函数.当协议栈通过NIC发送数据包或者NIC接收到数据包由驱动送入协议栈处理时,数据包被钩子函数捕获送入PACKET 套接字中.
PACKET套接字的核心模块包括两个部分:
1) BPF(berkeley packet filter)过滤器.BPF根据用户设置的过滤规则计算应该接收的数据包长度值,如果该值比数据包的长度小,那么数据包将会被截短.特别地,如果该值为0,数据包会被PACKET套接字丢弃而直接返回协议栈进行网络层的处理.BPF在Linux中,BPF被用于内核进行数据包过滤,以减小提交给应用程序的数据包的包数和字节数,提高系统性能.
2)缓存队列(BufferQ).用于缓存供应用程序读取的数据包,如果队列长度超过了预设缓存区的长度,那么数据包将会被丢弃.共享内存队列,共享内存被划分为固定大小的帧,数据包被按顺序拷贝到帧中,然后内核设置数据有效位,表示该帧存放了一个有效的数据包.图2右半部由应用程序发起,从PACKET 套接字的缓存队列中获取数据包.在共享内存队列中,libpcap在打开NIC设备时,使用mmap 函数将共享内存映射到应用程序的虚拟空间中.libpcap根据帧大小按顺序读取缓存区.如果当前帧的数据有效位被设置,则将该数据包提交给应用程序处理,在处理完毕以后,libpcap清除当前帧的有效位,允许内核再次使用该帧;否则,libpcap使用poll()函数等待数据包的到达.与libpcap1.0之前版本相比,共享内存缓存队列减少了一次数据包拷贝和调用recvmsg()进入、退出内核态的系统开销,因此有较大的性能提升。
把上面比较抽象的文字翻译成一个简单的示例图如下所示:

2.3 libpcap 1.3.0源码对照
对应于libpcap 1.3.0源代码如下:
2.3.1 创建环形队列
主要步骤:
1.[setup] socket() -------> creation of the capture socket
2.setsockopt() ---> allocation of the
circular buffer (ring)
3.mmap() ---------> maping of the allocated
buffer to the
user process
对应libpcap-1.3.0源代码:
static
int
create_ring(pcap_t *handle, int *status)函数中:
2.pcap-linux.c:3594行
if
(setsockopt(handle->fd, SOL_PACKET, PACKET_RX_RING,
(void
*) &req, sizeof(req))) {
3.Pcap-linux.c:3627行
handle->md.mmapbuf = mmap(0,
handle->md.mmapbuflen,
PROT_READ|PROT_WRITE, MAP_SHARED,
handle->fd, 0);
2.3.2 捕获数据包
[capture] poll() ---------> to wait for
incoming packets
[process]trigger the user process
[reset frame] reset the status of the frame for
kernel to reuse
对应libpcap-1.3.0源代码:
static int
pcap_read_linux_mmap(pcap_t *handle, int
max_packets, pcap_handler callback, u_char *user)函数中:
1.pcap-linux.c:3811行
ret = poll(&pollinfo, 1, timeout);
2.pcap-linux.c:4053行
callback(user, &pcaphdr, bp);
3.pcap-linux.c:4060行
switch (handle->md.tp_version) {
case TPACKET_V1:
h.h1->tp_status = TP_STATUS_KERNEL;
break;
3. libpcap捕包优化分析
我们把之前2.1提到的可能会限制系统数据包的捕获处理能力的地方写出来:
3.1处理流程单一:
因为原生的libpcap是单线程的,一个数据包的处理流程是“捕包—处理包—捕下个包-处理下个包。。。”所以处理包的时间长短会影响下一个捕包的开始时间,解决这个有2个办法,一个是优化处理包流程,缩短处理包时间,但这个方法治标不治本,另一个方法是用多线程的方式捕包和处理包。

3.2高中断服务负荷:
这个是操作系统捕包的关键,现在一般有2种思路
A:把网卡的多个收包队列中断均衡的绑定到多个不同的cpu上。(网上有很多教程)
B:更换网卡驱动,可以把网卡一般现有的驱动即依赖中断接收数据包,改为轮询方式,例如现在的NAPI驱动和Intel的DPDK都有用到。
3.3内核态到用户态上下文选择:
现在的libpcap1.3.0支持一次捕获多个数据包, 通过指定pcap_dispatch(pcap_t
*p, int cnt, pcap_handler callback, u_char *user)接口中的cnt变量,而且现在的捕包不是基于recvmsg的系统调用,而是共享内存队列,所以大大减少了上下切换。
3.4数据拷贝和内存分配消耗:
由于采用了现在的共享内存环形队列,即零拷贝技术,用户态和内核态只有一份数据拷贝,所以捕获每个数据包都减少了一次数据拷贝。
4. 延伸拓展
4.1 libpcap多线程捕包
用什么样的多线程架构方式更能发挥libpcap捕包性能?
4.2 Linux并行运算
使用多线程或移植到多线程的时候,有什么注意事项?
4.3 零拷贝发包
既然操作系统有“PACKET_RX_RING”这个关键字支持零拷贝捕包,那会不会也有零拷贝发包呢?
5. 参考资料:
Libpcap-MT:一种多线程的通用数据包捕获库
温曙光,文献资料
高速网络数据包捕获技术研究
郭占东,文献资料
网络安全开发包详解
刘文涛,书籍
基于 linux 平台的 libpcap 源代码分析
施聪,IBM论坛
PACKET_MMAP's documentation
Uaca,国外网络资料
基于Linux平台的libpcap源码分析和优化的更多相关文章
- Linux 内核调度器源码分析 - 初始化
导语 上篇系列文 混部之殇-论云原生资源隔离技术之CPU隔离(一) 介绍了云原生混部场景中CPU资源隔离核心技术:内核调度器,本系列文章<Linux内核调度器源码分析>将从源码的角度剖析内 ...
- 转载~Linux 平台下阅读源码的工具
Linux 平台下阅读源码的工具 前言 看源代码是一个程序员必须经历的事情,也是可以提升能力的一个捷径.个人认为: 要完全掌握一个软件的方法只有阅读源码在Windows下有sourceinsight这 ...
- spark源码分析以及优化
第一章.spark源码分析之RDD四种依赖关系 一.RDD四种依赖关系 RDD四种依赖关系,分别是 ShuffleDependency.PrunDependency.RangeDependency和O ...
- 转:基于 linux 平台的 libpcap 源代码分析
libpcap 是 unix/linux 平台下的网络数据包捕获函数包,大多数网络监控软件都以它为基础.Libpcap 可以在绝大多数类 unix 平台下工作,本文分析了 libpcap 在 linu ...
- Java -- 基于JDK1.8的LinkedList源码分析
1,上周末我们一起分析了ArrayList的源码并进行了一些总结,因为最近在看Collection这一块的东西,下面的图也是大致的总结了Collection里面重要的接口和类,如果没有意外的话后面基本 ...
- Linux 平台下阅读源码的工具链
原文:http://blog.jobbole.com/101322/ 前言 看源代码是一个程序员必须经历的事情,也是可以提升能力的一个捷径.个人认为: 要完全掌握一个软件的方法只有阅读源码. 在Win ...
- Java集合基于JDK1.8的ArrayList源码分析
本篇分析ArrayList的源码,在分析之前先跟大家谈一谈数组.数组可能是我们最早接触到的数据结构之一,它是在内存中划分出一块连续的地址空间用来进行元素的存储,由于它直接操作内存,所以数组的性能要比集 ...
- Java集合基于JDK1.8的LinkedList源码分析
上篇我们分析了ArrayList的底层实现,知道了ArrayList底层是基于数组实现的,因此具有查找修改快而插入删除慢的特点.本篇介绍的LinkedList是List接口的另一种实现,它的底层是基于 ...
- 基于ReentrantLock的AQS的源码分析(独占、非中断、不超时部分)
刚刚看完了并发实践这本书,算是理论具备了,看到了AQS的介绍,再看看源码,发现要想把并发理解透还是很难得,花了几个小时细分析了一下把可能出现的场景尽可能的往代码中去套,还是有些收获,但是真的很费脑,还 ...
随机推荐
- readonly
readonly 关键字是可以在字段上使用的修饰符. 当字段声明包括 readonly 修饰符时,该声明引入的字段赋值只能作为声明的一部分出现,或者出现在同一类的构造函数中. 示例 在此示例 ...
- easyui窗口组件
注意首先要在title后面导入配置文件,前后顺序不能乱 <!-- 1.JQuery的js包 --><script type="text/javascript" s ...
- Python简单爬虫入门一
为大家介绍一个简单的爬虫工具BeautifulSoup BeautifulSoup拥有强大的解析网页及查找元素的功能本次测试环境为python3.4(由于python2.7编码格式问题) 此工具在搜索 ...
- InfluxDB学习之InfluxDB数据保留策略(Retention Policies)
InfluxDB每秒可以处理成千上万条数据,要将这些数据全部保存下来会占用大量的存储空间,有时我们可能并不需要将所有历史数据进行存储,因此,InfluxDB推出了数据保留策略(Retention Po ...
- hadoop2.2.0伪分布式搭建3--安装Hadoop
3.1上传hadoop安装包 3.2解压hadoop安装包 mkdir /cloud #解压到/cloud/目录下 tar -zxvf hadoop-2.2.0.tar.gz -C /cloud/ 3 ...
- [WPF系列]基础Combox
示例 参考 WPF combobox SelectedValue binding to string Confused with wpf ComboBox DisplayMemberPath, ...
- python 聊天室
server端程序 # -*- coding: utf-8 -*- #!/usr/bin/python """ """ import soc ...
- 【第一篇献给markdown】markdown入门
Markdown 是一种轻量级的「标记语言」,语法十分简单,常用的标记符号也不超过十个.虽然功能很强大,但是上手估计不用十分钟. 一些认识 Markdown 官方文档 这里可以看到官方的 Markdo ...
- 自定义框架(MyMvc)
//初次接触自定义框架,简单的登录功能的实现流程:: 当我们实现登录功能的时候,首先会创建一个login.jsp 会写这些登录表单 <form action="loginAction. ...
- JSPatch
链接: JSPatch github项目主页 JSPatch技术文档 JSPatch基础用法总结 JSPatch – 动态更新iOS APP JSPatch使用小记 end