《一种基于PF_RING的高速网络数据采集方法.pdf》由会员分享,可在线阅读,更多相关《一种基于PF_RING的高速网络数据采集方法.pdf(14页珍藏版)》请在专利查询网上搜索。
1、(10)申请公布号 CN 103617142 A (43)申请公布日 2014.03.05 CN 103617142 A (21)申请号 201310647294.2 (22)申请日 2013.12.04 201310407788.3 2013.09.09 CN G06F 13/38(2006.01) G06F 13/42(2006.01) (71)申请人 南京邮电大学 地址 210003 江苏省南京市鼓楼区新模范马 路 66 号 (72)发明人 陈丹伟 吴帆 胡文博 (74)专利代理机构 南京知识律师事务所 32207 代理人 汪旭东 (54) 发明名称 一种基于 pf_ring 的高速网络。
2、数据采集方法 (57) 摘要 本发明公开了一种基于 pf_ring 的高速网络 数据采集方法, 该方法是基于内存池机制实现内 存管理模块, 用来代替 pf_ring 套接字中的环形 缓冲区, 从而实现在网络报文收发过程中都出现 尽量少的内存间拷贝 ; 本发明所述方法包括如下 步骤 : 步骤1 : 在内核态注册Pf_kks协议 ; 步骤2 : 为 Pf_kks 定义专用的套接字操作集 ; 步骤 3 : 创 建网络设备通知链表项 ; 步骤 4 : 实现 PF_KKS 协 议在核态的工作实体 Ring 结构 ; 步骤 5 : 实现内 存池结构。 (66)本国优先权数据 (51)Int.Cl. 权利要。
3、求书 1 页 说明书 9 页 附图 3 页 (19)中华人民共和国国家知识产权局 (12)发明专利申请 权利要求书1页 说明书9页 附图3页 (10)申请公布号 CN 103617142 A CN 103617142 A 1/1 页 2 1. 一种基于 pf_ring 的高速网络数据采集方法, 其特征在于, 所述方法包括如下步骤 : 步骤 1 : 在内核态注册 Pf_kks 协议 ; 步骤 2 : 为 Pf_kks 定义专用的套接字操作集 ; 步骤 3 : 创建网络设备通知链表项 ; 步骤 4 : 实现 PF_KKS 协议在核态的工作实体 Ring 结构 ; 步骤 5 : 实现内存池结构。 2。
4、.根据权利要求1所述的一种基于pf_ring的高速网络数据采集方法, 其特征在于, 上 述的步骤 4 中所述的 Ring 的结构包括 : 标志位 (Flags) , 网络流方向 (Direction) , Master Socket, ring 内存 (Ring Memory) , 核心态内存 (Memory Pool In Kernel) ; 其中标志位 (Flags) 标识了 ring 环的状态与 ring 环的 id 号 ; 网络流方向 (Direction) 告诉设备是输 出还是输入网络流 ; Master Socket标识了主socket ; ring内存 (Ring Memory)。
5、 标识了ring 结构在系统内存中的大小, 长度 ; 核心态内存 (Memory Pool In Kernel) 标识了指向 ring 结构在内核态中的内存。 3.根据权利要求1所述的一种基于pf_ring的高速网络数据采集方法, 其特征在于, 上 述的步骤 5 中所述的内存池结构包括 : 内存控制块结构与内存分片首部结构 ; 将一整块内 存划分为大小相等的内存块, 并将这些内存块链成链表, 成为可用内存链表 ; 在申请内存的 时候取出可用内存链表的第一项返回给申请者 ; 在释放内存的时候将内存块链回可用内存 链表即可 ; 在实际使用的时候, 尤其是开发阶段, 在每个内存块的头部保留一些控制信。
6、息和 Cookie 信息, 在内存块的尾部也保留一些 Cookie 信息, 在申请和释放内存的时候检查这些 信息, 有效的发现内存重复释放、 内存溢出、 释放指针错误问题。 4. 根据权利要求 1 所述的一种基于 pf_ring 的高速网络数据采集方法, 其特征在于 : 在所述方法中收发网络数据包时, 当网卡通过中断接收到数据包, 调用 net_rx_action() 处理分组, 在netif_receive_skb()函数中会将数据包派发到PacketRecv()分组处理例程 中 ; 发送数据包通过 dev_queue_xmit() 将自己创建的 skb 从指定网卡上发送出去。 5. 根据权。
7、利要求 1 所述的一种基于 pf_ring 的高速网络数据采集方法, 其特征在于 : 在所述方法中创建链表项后可将链表项插入到内核网络设备通知链表中, 当系统中的网络 设备发生变化时, PF_KKS 接收相应消息, 通过注册的句柄函数进行相应的处理。 6. 根据权利要求 1 所述的一种基于 pf_ring 的高速网络数据采集方法, 其特征在于 : 在所述方法中改变了原有 pf_ring 总的环形缓冲区。 权 利 要 求 书 CN 103617142 A 2 1/9 页 3 一种基于 pf_ring 的高速网络数据采集方法 技术领域 0001 本发明涉及计算机高速网络数据采集技术领域, 特别涉及。
8、一种基于 pf_ring 的高 速网络数据采集方法。 背景技术 0002 现阶段大多数的网络安全、 审计、 计费产品都是以数据包捕获技术作为其工作基 础的。随着网络带宽的逐渐增大, 对高速网络数据采集技术要求越来越高。 0003 传统的网络数据采集技术多数基于 Libpcap 函数库, 通过这个函数库与内核之间 进行交互, 从而采集网络数据。 但由于该手段在低效的网络协议架构中存在很多方面不足 : 数据从网卡到内核态再到用户态传输过程中存在频繁的系统调用, 多次的内存拷贝, 多次 上下文切换的开销。导致了 CPU 大量时间耗费在以上的过程中。这使得系统处理网络数据 的能力低下, 当网络流量较大。
9、时, 丢包率也逐渐上升。 0004 现阶段, 零拷贝技术 ,NAPI,DNA,pf_ring 套接字等技术都陆续被提出来解决高速 网络数据采集问题。而由于 pf_ring 是在零拷贝的基础上提出的一种新的解决方案, 而且 不必修改网卡驱动, 并且同时提供了传统的Libpcap接口, 可以只需要在替换Libpcap的条 件下就提高高速网络数据采集的性能。具有很好的移植性。因此通用性也更强。 0005 Pf_ring 基本原理是把从网卡接受到的数据包存储在一个环状缓存中, 该环状缓 存提供两个接口 : 应用程序可以通过其中一个进行读取数据包, 网卡通过另一个接口写入 数据包。但是这也导致网络数据包。
10、在向外发送时, 不能通过 pf_ring 接口。而零拷贝的原 理是网络报文在收发过程中不会出现内存间的拷贝, 这说明 pf_ring 不能算是完全的零拷 贝技术, 发送的数据包不能通过 pf_ring 接口。而本发明能够很好地解决上面的问题。 发明内容 0006 本发明目的是在 pf_ring 套接字基础上, 提出一种基于 pf_ring 的高速网络数据 采集方法, 该方法是基于内存池机制实现内存管理模块, 用来代替 pf_ring 套接字中的环 形缓冲区, 从而实现在网络报文收发过程中都出现尽量少的内存间拷贝。 0007 本发明解决其技术问题所采用的技术方案是 : 本发明提出一种基于 pf_。
11、ring 的高 速网络数据采集方法, 该方法包括如下步骤 : 0008 步骤 1 : 在内核态注册 Pf_kks 协议 ; 0009 步骤 2 : 为 Pf_kks 定义专用的套接字操作集 ; 0010 步骤 3 : 创建网络设备通知链表项 ; 0011 步骤 4 : 实现 PF_KKS 协议在核态的工作实体 Ring 结构 ; 0012 步骤 5 : 实现内存池结构。 0013 在本发明中收发网络数据包时, 当网卡通过中断接收到数据包, 调用 net_rx_ action() 处理分组, 在 netif_receive_skb() 函数中会将数据包派发到 PacketRecv() 分 组处理。
12、例程中, 从而实现接收数据截获 ; 发送数据包通过 dev_queue_xmit() 将自己创建的 说 明 书 CN 103617142 A 3 2/9 页 4 skb 从指定网卡上发送出去。在本发明中创建链表项后可将链表项插入到内核网络设备通 知链表中, 当系统中的网络设备发生变化时 (UP、 DOWN 等) , PF_KKS 接收相应消息, 通过注册 的句柄函数进行相应的处理。 在本发明中创建链表项后可将链表项插入到内核网络设备通 知链表中, 当系统中的网络设备发生变化时 (UP、 DOWN 等) , PF_KKS 接收相应消息, 通过注册 的句柄函数进行相应的处理。在本发明中改变了原有 。
13、pf_ring 总的环形缓冲区, 实现了内 存池结构, 并且有效的利用了内存。 0014 本发明提出一种基于 pf_ring 的高速网络数据采集方法, 该方法针对由于 pf_ ring 套接字中的环状缓存只提供应用程序读取数据包与网卡写入数据包的两个接口, 导致 网络数据包发送过程中不能通过 pf_ring 接口。本发明对 pf_ring 套接字中的环状缓存 进行了修改, 引进了内存池的机制, 保证网络数据在收发过程中都可以使用改进的 pf_ring 接口。 0015 一、 体系结构 0016 图 1 给出了改进后的 pf_ring 套接字的体系结构。命名为 Pf_kks。该系统被注册 成一个。
14、协议模块, 通过用户态程序打开一个套接字将该协议绑定到特定的网络设备, 协议 从网卡驱动收发数据包, 所有的数据包将会落地到模块申请的缓冲内存池中, 然后被有序 整理成会话, 对用户态程序输出会话流。 0017 下面给出几个主要部分的说明 : 0018 KksProtoHook: 主要是在内核队列中注册 Hook, 获取数据帧。 0019 Kbuffer Pool : 本发明最主要的部分。实现了内存池机制。当网络数据流量通过 硬件落地到系统中时, 实际上是一个个的数据帧。 本发明采用内存池的机制, 让这些数据帧 一个个不连续的存储在已经划分好的内存池中。 0020 二、 系统技术方案 0021。
15、 内存池 : 图 2 给出了内存池原理的示意图。它主要是将一整块内存划分为大小相 等的内存块, 并将这些内存块链成链表, 成为可用内存链表。 在申请内存的时候取出可用内 存链表的第一项返回给申请者。在释放内存的时候将内存块链回可用内存链表即可。在实 际使用的时候, 尤其是开发阶段, 在每个内存块的头部保留一些控制信息和 Cookie 信息, 在内存块的尾部也保留一些 Cookie 信息, 在申请和释放内存的时候检查这些信息可以有 效的发现内存重复释放、 内存溢出、 释放指针错误等问题。 0022 Ring 结构包括 : 标志位 (Flags) , 网络流方向 (Direction) , Mas。
16、ter Socket, ring 内存 (Ring Memory) , 核心态内存 (Memory Pool In Kernel) 。其中标志位 (Flags) 标识了 ring 环的状态与 ring 环的 id 号。网络流方向 (Direction) 可以告诉设备是输出还是输入 网络流。Master Socket 标识了主 socket。ring 内存 (Ring Memory) 标识了 ring 结构在 系统内存中的大小, 长度。核心态内存 (Memory Pool In Kernel) 标识了指向 ring 结构在 内核态中的内存。 0023 Kbuffer 结构 : 该结构体主要提出用。
17、来控制每一个收到的原始网络数据包。面对 跨越用户态和核态的环境中, 单纯的指针和链表结构不再适用 (核态和用户态的虚拟地址 不能通用) 。为了解决这个问题, 参考 Linux 系统中 sk_buff 的结构, 提出了 Kbuffer 的结 构体来存储网络数据包。Kbuffer 是从共享内存池中分配, 以便实现核态和用户态的共享。 并且 Kbuffer 结构体中不使用指针来处理数据中的协议首部, 而改为使用首部偏移量加长 说 明 书 CN 103617142 A 4 3/9 页 5 度再配合上处理宏来解决协议首部识别和处理的任务。图 3 给出了 Kbuffer 结构示意图。 实际上, 一个完整的。
18、 Kbuffer 是由两部分组成的 : Kbuffer 数据结构和一块对应的内存块。 这样设计的目的是为了提高内存块的使用效率。仅当网络流量首次落地到本系统中, 才在 划分的内存块中进行一次拷贝的操作 ; 其他所有在系统中的内存操作, 实际上仅仅只是对 Kbuffer 数据结构这个控制块进行操作, 所有的创建、 拷贝、 删除操作落到物理的内存块中, 仅仅是对引用计数的变化。 这样就可以有效的减少重复拷贝, 增加内存使用效率, 提高系统 的实时性。 附图说明 0024 图 1 是本发明的 Pf_kks 体系结构。 0025 图 2 是本发明的内存池原理示意图。 0026 图 3 是本发明的 Kb。
19、uffer 结构示意图。 0027 图 4 是本发明的方法流程图。 具体实施方式 0028 下面通过结合说明书附图, 进一步说明本发明的技术方案。 0029 实施例 1 0030 如图4所示, 本发明提出一种基于pf_ring的高速网络数据采集方法, 该方法包括 如下步骤 : 0031 步骤 1 : 在内核态注册 Pf_kks 协议 ; 0032 步骤 2 : 为 Pf_kks 定义专用的套接字操作集 ; 0033 步骤 3 : 创建网络设备通知链表项 ; 0034 步骤 4 : 实现 PF_KKS 协议在核态的工作实体 Ring 结构 ; 0035 步骤 5 : 实现内存池结构。 0036 。
20、在本发明中收发网络数据包时, 当网卡通过中断接收到数据包, 调用 net_rx_ action() 处理分组, 在 netif_receive_skb() 函数中会将数据包派发到 PacketRecv() 分 组处理例程中, 从而实现接收数据截获 ; 发送数据包通过 dev_queue_xmit() 将自己创建的 skb 从指定网卡上发送出去。在本发明中创建链表项后可将链表项插入到内核网络设备通 知链表中, 当系统中的网络设备发生变化时 (UP、 DOWN 等) , PF_KKS 接收相应消息, 通过注册 的句柄函数进行相应的处理。 在本发明中创建链表项后可将链表项插入到内核网络设备通 知链表。
21、中, 当系统中的网络设备发生变化时 (UP、 DOWN 等) , PF_KKS 接收相应消息, 通过注册 的句柄函数进行相应的处理。在本发明中改变了原有 pf_ring 总的环形缓冲区, 实现了内 存池结构, 并且有效的利用了内存。 0037 本发明提出一种基于 pf_ring 的高速网络数据采集方法, 该方法针对由于 pf_ ring 套接字中的环状缓存只提供应用程序读取数据包与网卡写入数据包的两个接口, 导致 网络数据包发送过程中不能通过 pf_ring 接口。本发明对 pf_ring 套接字中的环状缓存 进行了修改, 引进了内存池的机制, 保证网络数据在收发过程中都可以使用改进的 pf_。
22、ring 接口。 0038 一、 体系结构 说 明 书 CN 103617142 A 5 4/9 页 6 0039 图 1 给出了改进后的 pf_ring 套接字的体系结构。命名为 Pf_kks。该系统被注册 成一个协议模块, 通过用户态程序打开一个套接字将该协议绑定到特定的网络设备, 协议 从网卡驱动收发数据包, 所有的数据包将会落地到模块申请的缓冲内存池中, 然后被有序 整理成会话, 对用户态程序输出会话流。 0040 下面我们给出几个主要部分的说明 : 0041 KksProtoHook: 主要是在内核队列中注册 Hook, 获取数据帧。 0042 Kbuffer Pool : 本发明最。
23、主要的部分。实现了内存池机制。当网络数据流量通过 硬件落地到系统中时, 实际上是一个个的数据帧。 本发明采用内存池的机制, 让这些数据帧 一个个不连续的存储在已经划分好的内存池中。 0043 二、 主要技术方案 0044 内存池 : 图 2 给出了内存池原理的示意图。它主要是将一整块内存划分为大小相 等的内存块, 并将这些内存块链成链表, 成为可用内存链表。 在申请内存的时候取出可用内 存链表的第一项返回给申请者。在释放内存的时候将内存块链回可用内存链表即可。在实 际使用的时候, 尤其是开发阶段, 在每个内存块的头部保留一些控制信息和 Cookie 信息, 在内存块的尾部也保留一些 Cooki。
24、e 信息, 在申请和释放内存的时候检查这些信息可以有 效的发现内存重复释放、 内存溢出、 释放指针错误等问题。 0045 Ring 结构包括 : 标志位 (Flags) , 网络流方向 (Direction) , Master Socket, ring 内存 (Ring Memory) , 核心态内存 (Memory Pool In Kernel) 。其中标志位 (Flags) 标识了 ring 环的状态与 ring 环的 id 号。网络流方向 (Direction) 可以告诉设备是输出还是输入 网络流。Master Socket 标识了主 socket。ring 内存 (Ring Memor。
25、y) 标识了 ring 结构在 系统内存中的大小, 长度。核心态内存 (Memory Pool In Kernel) 标识了指向 ring 结构在 内核态中的内存。 0046 Kbuffer 结构 : 该结构体主要提出用来控制每一个收到的原始网络数据包。面对 跨越用户态和核态的环境中, 单纯的指针和链表结构不再适用 (核态和用户态的虚拟地址 不能通用) 。为了解决这个问题, 参考 Linux 系统中 sk_buff 的结构, 提出了 Kbuffer 的结 构体来存储网络数据包。Kbuffer 是从共享内存池中分配, 以便实现核态和用户态的共享。 并且 Kbuffer 结构体中不使用指针来处理数。
26、据中的协议首部, 而改为使用首部偏移量加长 度再配合上处理宏来解决协议首部识别和处理的任务。图 3 给出了 Kbuffer 结构示意图。 实际上, 一个完整的 Kbuffer 是由两部分组成的 : Kbuffer 数据结构和一块对应的内存块。 这样设计的目的是为了提高内存块的使用效率。仅当网络流量首次落地到本系统中, 才在 划分的内存块中进行一次拷贝的操作 ; 其他所有在系统中的内存操作, 实际上仅仅只是对 Kbuffer 数据结构这个控制块进行操作, 所有的创建、 拷贝、 删除操作落到物理的内存块中, 仅仅是对引用计数的变化。 这样就可以有效的减少重复拷贝, 增加内存使用效率, 提高系统 的。
27、实时性。 0047 实施例 2 0048 假设有一台装有 Linux 系统的 PC 机, 要实现 Pf_kks 这一体系架构, 那么具体实施 方式为 : 0049 (1) 协议的注册 0050 模仿 pf_ring, 将本系统注册成为一个网络协议模块, 以便成为一个通用的系统, 说 明 书 CN 103617142 A 6 5/9 页 7 不受硬件限制。当前, 内核最多支持 31 个协议域 (0 为未指定, 32 为 MAX) 。而当前的定义 中还有 27,28,30 为空 (详见 linux/socket.h) , 故对于协议号作如下的申明 : #define PF_ KKS27/*The 。
28、protocol number of Kakashi*/ 0051 内核中, 结构体 net_proto_family 用于表示一个协议域, 而全局数组变量 static struct net_proto_family*net_familiesNPROTO 是一个有 32 项的数组, 用于保存当前 内核中所有已注册的协议域, 函数 sock_register 用于把一个协议域注册到内核中, 即把 一个协议域跟 net_families 数组中的某一项相关联。为本系统的模块定义如下协议域 : 0052 0053 0054 调用 sock_register() 函数将 KKS 协议域注册到内核中。。
29、 0055 proto 结构体表示了一个传输层协议绑定的操作集, 比如对于 IPPROTO_TCP, 它就 是tcp_prot, 对于IPPROTO_UDP, 它就是udp_prot。 本系统中, 为KKS定义了自己的操作集 : 0056 0057 调用 proto_register() 函数将 KksProto 协议操作集注册到内核中。 0058 在 OSI 七层模型中, INET 和 BSD 套接字之间的接口通过 Internet 地址族套接字 操作集实现, 这些操作集实际是一组协议的操作例程, 在 include/linux/net.h 中定义为 proto_ops。为 KKS 定义如下。
30、的套接字操作集 : 0059 说 明 书 CN 103617142 A 7 6/9 页 8 0060 0061 创建网络设备通知链表项, 插入到内核网络设备通知链表中。当系统中的网络设 备发生变化时 (UP、 DOWN 等) , PF_KKS 接收相应消息, 通过注册的句柄函数进行相应的处理。 0062 static struct notifier_block KksNetdevNotifier= 0063 .notifier_call=KksNotifier, 0064 ; 0065 其中主要要处理的两个消息为 NETDEV_REGISTER 和 NETDEV_UNREGISTER。 006。
31、6 当模块初始化时, 系统就会通知表链来识别当前的网络设备, 并在模块中创建可 说 明 书 CN 103617142 A 8 7/9 页 9 用设备链 (KksAwareDeviceList) , 为协议后续使用网络设备做准备。 0067 为 PF_KKS 协议设定了三种工作模式 : 0068 1、 transparent_mode=0 0069 数据包通过标准 linux 接口来接收, 所有的驱动都可以使用这种模式。 0070 2、 transparent_mode=1 0071 数据包使用拷贝方式, 同时由 PF_KKS 和标准 linux 接口来接收, 需要特定网卡驱 动。 0072 3。
32、、 transparent_mode=2 0073 数据包仅拷贝到 PF_KKS, 不再经过标准 linux 接口, 需要特定网卡驱动。 0074 (2) Ring 的使用 0075 参考 Pf_ring 关于数据采集部分的设计思想, 本系统中提出了一个 Ring 环的结 构, 作为从网络设备驱动采集数据、 协议层会话重组和用户态应用层协议数据流交互的载 体。 0076 0077 说 明 书 CN 103617142 A 9 8/9 页 10 0078 每一个 Ring 环就是一个 PF_KKS 协议在核态的工作实体, 它通过从用户态打开标 准原始套接字来创建 (socket 函数) , 通过。
33、套接字的绑定操作 (bind 函数) 将打开的 Ring 绑 定到位于可用设备链中的某一指定设备 (如 eth0、 wlan0 等) 。 0079 (3) 内存池结构的实现 0080 每一个 Ring 环都会维护一个内存池结构, 分配用于存储数据包的内存块。 0081 其中内存池控制块结构如下 : 0082 说 明 书 CN 103617142 A 10 9/9 页 11 0083 0084 内存分片首部结构如下 : 0085 0086 对于模式transparent=0, 创建一个对象struct packet_type并将其Hook到协系 统的协议栈中 (dev_add_pack 函数和 。
34、dev_remove_pack 函数) 。将其中的 func 句柄设置为 函数 PakcetRecv(), type 设置为 ETH_P_ALL(以便处理所有协议的二层数据帧) 。 0087 这时, 在传统方式接收网络数据包时, 当网卡通过中断接收到数据包, 调用 net_rx_action() 处理分组, 在 netif_receive_skb() 函数中会将数据包派发到我们的 PacketRecv() 分组处理例程中, 从而实现接收数据截获 ; 发送数据包通过 dev_queue_ xmit() 将自己创建的 skb 从指定网卡上发送出去。 说 明 书 CN 103617142 A 11 1/3 页 12 图 1 图 2 说 明 书 附 图 CN 103617142 A 12 2/3 页 13 图 3 说 明 书 附 图 CN 103617142 A 13 3/3 页 14 图 4 说 明 书 附 图 CN 103617142 A 14 。