法律状态公告日
法律状态信息
法律状态
2017-03-15
授权
授权
2014-04-02
实质审查的生效 IPC(主分类):G06F13/38 申请日:20131204
实质审查的生效
2014-03-05
公开
公开
技术领域
本发明涉及计算机高速网络数据采集技术领域,特别涉及一种基于pf_ring的高速网络数 据采集方法。
背景技术
现阶段大多数的网络安全、审计、计费产品都是以数据包捕获技术作为其工作基础的。 随着网络带宽的逐渐增大,对高速网络数据采集技术要求越来越高。
传统的网络数据采集技术多数基于Libpcap函数库,通过这个函数库与内核之间进行交 互,从而采集网络数据。但由于该手段在低效的网络协议架构中存在很多方面不足:数据从 网卡到内核态再到用户态传输过程中存在频繁的系统调用,多次的内存拷贝,多次上下文切 换的开销。导致了CPU大量时间耗费在以上的过程中。这使得系统处理网络数据的能力低下, 当网络流量较大时,丢包率也逐渐上升。
现阶段,零拷贝技术,NAPI,DNA,pf_ring套接字等技术都陆续被提出来解决高速网络数 据采集问题。而由于pf_ring是在零拷贝的基础上提出的一种新的解决方案,而且不必修改 网卡驱动,并且同时提供了传统的Libpcap接口,可以只需要在替换Libpcap的条件下就提 高高速网络数据采集的性能。具有很好的移植性。因此通用性也更强。
Pf_ring基本原理是把从网卡接受到的数据包存储在一个环状缓存中,该环状缓存提供 两个接口:应用程序可以通过其中一个进行读取数据包,网卡通过另一个接口写入数据包。 但是这也导致网络数据包在向外发送时,不能通过pf_ring接口。而零拷贝的原理是网络报 文在收发过程中不会出现内存间的拷贝,这说明pf_ring不能算是完全的零拷贝技术,发送 的数据包不能通过pf_ring接口。而本发明能够很好地解决上面的问题。
发明内容
本发明目的是在pf_ring套接字基础上,提出一种基于pf_ring的高速网络数据采集方法, 该方法是基于内存池机制实现内存管理模块,用来代替pf_ring套接字中的环形缓冲区,从而 实现在网络报文收发过程中都出现尽量少的内存间拷贝。
本发明解决其技术问题所采用的技术方案是:本发明提出一种基于pf_ring的高速网络数 据采集方法,该方法包括如下步骤:
步骤1:在内核态注册Pf_kks协议;
步骤2:为Pf_kks定义专用的套接字操作集;
步骤3:创建网络设备通知链表项;
步骤4:实现PF_KKS协议在核态的工作实体Ring结构;
步骤5:实现内存池结构。
在本发明中收发网络数据包时,当网卡通过中断接收到数据包,调用net_rx_action()处理 分组,在netif_receive_skb()函数中会将数据包派发到PacketRecv()分组处理例程中,从而实 现接收数据截获;发送数据包通过dev_queue_xmit()将自己创建的skb从指定网卡上发送出去。 在本发明中创建链表项后可将链表项插入到内核网络设备通知链表中,当系统中的网络设备 发生变化时(UP、DOWN等),PF_KKS接收相应消息,通过注册的句柄函数进行相应的处 理。在本发明中创建链表项后可将链表项插入到内核网络设备通知链表中,当系统中的网络 设备发生变化时(UP、DOWN等),PF_KKS接收相应消息,通过注册的句柄函数进行相应 的处理。在本发明中改变了原有pf_ring总的环形缓冲区,实现了内存池结构,并且有效的利 用了内存。
本发明提出一种基于pf_ring的高速网络数据采集方法,该方法针对由于pf_ring套接字 中的环状缓存只提供应用程序读取数据包与网卡写入数据包的两个接口,导致网络数据包发 送过程中不能通过pf_ring接口。本发明对pf_ring套接字中的环状缓存进行了修改,引进了 内存池的机制,保证网络数据在收发过程中都可以使用改进的pf_ring接口。
一、体系结构
图1给出了改进后的pf_ring套接字的体系结构。命名为Pf_kks。该系统被注册成一个协 议模块,通过用户态程序打开一个套接字将该协议绑定到特定的网络设备,协议从网卡驱动 收发数据包,所有的数据包将会落地到模块申请的缓冲内存池中,然后被有序整理成会话, 对用户态程序输出会话流。
下面给出几个主要部分的说明:
KksProtoHook:主要是在内核队列中注册Hook,获取数据帧。
Kbuffer Pool:本发明最主要的部分。实现了内存池机制。当网络数据流量通过硬件落地 到系统中时,实际上是一个个的数据帧。本发明采用内存池的机制,让这些数据帧一个个不 连续的存储在已经划分好的内存池中。
二、系统技术方案
内存池:图2给出了内存池原理的示意图。它主要是将一整块内存划分为大小相等的内 存块,并将这些内存块链成链表,成为可用内存链表。在申请内存的时候取出可用内存链表 的第一项返回给申请者。在释放内存的时候将内存块链回可用内存链表即可。在实际使用的 时候,尤其是开发阶段,在每个内存块的头部保留一些控制信息和Cookie信息,在内存块的 尾部也保留一些Cookie信息,在申请和释放内存的时候检查这些信息可以有效的发现内存重 复释放、内存溢出、释放指针错误等问题。
Ring结构包括:标志位(Flags),网络流方向(Direction),Master 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结构在内核态中的内存。
Kbuffer结构:该结构体主要提出用来控制每一个收到的原始网络数据包。面对跨越用户 态和核态的环境中,单纯的指针和链表结构不再适用(核态和用户态的虚拟地址不能通用)。 为了解决这个问题,参考Linux系统中sk_buff的结构,提出了Kbuffer的结构体来存储网络 数据包。Kbuffer是从共享内存池中分配,以便实现核态和用户态的共享。并且Kbuffer结构 体中不使用指针来处理数据中的协议首部,而改为使用首部偏移量加长度再配合上处理宏来 解决协议首部识别和处理的任务。图3给出了Kbuffer结构示意图。实际上,一个完整的Kbuffer 是由两部分组成的:Kbuffer数据结构和一块对应的内存块。这样设计的目的是为了提高内存 块的使用效率。仅当网络流量首次落地到本系统中,才在划分的内存块中进行一次拷贝的操 作;其他所有在系统中的内存操作,实际上仅仅只是对Kbuffer数据结构这个控制块进行操作, 所有的创建、拷贝、删除操作落到物理的内存块中,仅仅是对引用计数的变化。这样就可以 有效的减少重复拷贝,增加内存使用效率,提高系统的实时性。
附图说明
图1是本发明的Pf_kks体系结构。
图2是本发明的内存池原理示意图。
图3是本发明的Kbuffer结构示意图。
图4是本发明的方法流程图。
具体实施方式
下面通过结合说明书附图,进一步说明本发明的技术方案。
实施例1
如图4所示,本发明提出一种基于pf_ring的高速网络数据采集方法,该方法包括如下步 骤:
步骤1:在内核态注册Pf_kks协议;
步骤2:为Pf_kks定义专用的套接字操作集;
步骤3:创建网络设备通知链表项;
步骤4:实现PF_KKS协议在核态的工作实体Ring结构;
步骤5:实现内存池结构。
在本发明中收发网络数据包时,当网卡通过中断接收到数据包,调用net_rx_action()处理 分组,在netif_receive_skb()函数中会将数据包派发到PacketRecv()分组处理例程中,从而实 现接收数据截获;发送数据包通过dev_queue_xmit()将自己创建的skb从指定网卡上发送出去。 在本发明中创建链表项后可将链表项插入到内核网络设备通知链表中,当系统中的网络设备 发生变化时(UP、DOWN等),PF_KKS接收相应消息,通过注册的句柄函数进行相应的处 理。在本发明中创建链表项后可将链表项插入到内核网络设备通知链表中,当系统中的网络 设备发生变化时(UP、DOWN等),PF_KKS接收相应消息,通过注册的句柄函数进行相应 的处理。在本发明中改变了原有pf_ring总的环形缓冲区,实现了内存池结构,并且有效的利 用了内存。
本发明提出一种基于pf_ring的高速网络数据采集方法,该方法针对由于pf_ring套接字 中的环状缓存只提供应用程序读取数据包与网卡写入数据包的两个接口,导致网络数据包发 送过程中不能通过pf_ring接口。本发明对pf_ring套接字中的环状缓存进行了修改,引进了 内存池的机制,保证网络数据在收发过程中都可以使用改进的pf_ring接口。
一、体系结构
图1给出了改进后的pf_ring套接字的体系结构。命名为Pf_kks。该系统被注册成一个协 议模块,通过用户态程序打开一个套接字将该协议绑定到特定的网络设备,协议从网卡驱动 收发数据包,所有的数据包将会落地到模块申请的缓冲内存池中,然后被有序整理成会话, 对用户态程序输出会话流。
下面我们给出几个主要部分的说明:
KksProtoHook:主要是在内核队列中注册Hook,获取数据帧。
Kbuffer Pool:本发明最主要的部分。实现了内存池机制。当网络数据流量通过硬件落地 到系统中时,实际上是一个个的数据帧。本发明采用内存池的机制,让这些数据帧一个个不 连续的存储在已经划分好的内存池中。
二、主要技术方案
内存池:图2给出了内存池原理的示意图。它主要是将一整块内存划分为大小相等的 内存块,并将这些内存块链成链表,成为可用内存链表。在申请内存的时候取出可用内存链 表的第一项返回给申请者。在释放内存的时候将内存块链回可用内存链表即可。在实际使用 的时候,尤其是开发阶段,在每个内存块的头部保留一些控制信息和Cookie信息,在内存块 的尾部也保留一些Cookie信息,在申请和释放内存的时候检查这些信息可以有效的发现内存 重复释放、内存溢出、释放指针错误等问题。
Ring结构包括:标志位(Flags),网络流方向(Direction),Master 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结构在内核态中的内存。
Kbuffer结构:该结构体主要提出用来控制每一个收到的原始网络数据包。面对跨越用户 态和核态的环境中,单纯的指针和链表结构不再适用(核态和用户态的虚拟地址不能通用)。 为了解决这个问题,参考Linux系统中sk_buff的结构,提出了Kbuffer的结构体来存储网络 数据包。Kbuffer是从共享内存池中分配,以便实现核态和用户态的共享。并且Kbuffer结构 体中不使用指针来处理数据中的协议首部,而改为使用首部偏移量加长度再配合上处理宏来 解决协议首部识别和处理的任务。图3给出了Kbuffer结构示意图。实际上,一个完整的Kbuffer 是由两部分组成的:Kbuffer数据结构和一块对应的内存块。这样设计的目的是为了提高内存 块的使用效率。仅当网络流量首次落地到本系统中,才在划分的内存块中进行一次拷贝的操 作;其他所有在系统中的内存操作,实际上仅仅只是对Kbuffer数据结构这个控制块进行操作, 所有的创建、拷贝、删除操作落到物理的内存块中,仅仅是对引用计数的变化。这样就可以 有效的减少重复拷贝,增加内存使用效率,提高系统的实时性。
实施例2
假设有一台装有Linux系统的PC机,要实现Pf_kks这一体系架构,那么具体实施方式 为:
(1)协议的注册
模仿pf_ring,将本系统注册成为一个网络协议模块,以便成为一个通用的系统,不受硬 件限制。当前,内核最多支持31个协议域(0为未指定,32为MAX)。而当前的定义中还有 27,28,30为空(详见linux/socket.h),故对于协议号作如下的申明:#define PF_KKS 27/*The protocol number of Kakashi*/
内核中,结构体net_proto_family用于表示一个协议域,而全局数组变量static struct net_proto_family*net_families[NPROTO]是一个有32项的数组,用于保存当前内核中所有已注 册的协议域,函数sock_register用于把一个协议域注册到内核中,即把一个协议域跟 net_families数组中的某一项相关联。为本系统的模块定义如下协议域:
调用sock_register()函数将KKS协议域注册到内核中。
proto结构体表示了一个传输层协议绑定的操作集,比如对于IPPROTO_TCP,它就是 tcp_prot,对于IPPROTO_UDP,它就是udp_prot。本系统中,为KKS定义了自己的操作集:
调用proto_register()函数将KksProto协议操作集注册到内核中。
在OSI七层模型中,INET和BSD套接字之间的接口通过Internet地址族套接字操作 集实现,这些操作集实际是一组协议的操作例程,在include/linux/net.h中定义为proto_ops。 为KKS定义如下的套接字操作集:
创建网络设备通知链表项,插入到内核网络设备通知链表中。当系统中的网络设备发生 变化时(UP、DOWN等),PF_KKS接收相应消息,通过注册的句柄函数进行相应的处理。
static struct notifier_block KksNetdevNotifier={
.notifier_call=KksNotifier,
};
其中主要要处理的两个消息为NETDEV_REGISTER和NETDEV_UNREGISTER。
当模块初始化时,系统就会通知表链来识别当前的网络设备,并在模块中创建可用设备 链(KksAwareDeviceList),为协议后续使用网络设备做准备。
为PF_KKS协议设定了三种工作模式:
1、transparent_mode=0
数据包通过标准linux接口来接收,所有的驱动都可以使用这种模式。
2、transparent_mode=1
数据包使用拷贝方式,同时由PF_KKS和标准linux接口来接收,需要特定网卡驱动。
3、transparent_mode=2
数据包仅拷贝到PF_KKS,不再经过标准linux接口,需要特定网卡驱动。
(2)Ring的使用
参考Pf_ring关于数据采集部分的设计思想,本系统中提出了一个Ring环的结构,作为 从网络设备驱动采集数据、协议层会话重组和用户态应用层协议数据流交互的载体。
每一个Ring环就是一个PF_KKS协议在核态的工作实体,它通过从用户态打开标准原始 套接字来创建(socket函数),通过套接字的绑定操作(bind函数)将打开的Ring绑定到位 于可用设备链中的某一指定设备(如eth0、wlan0等)。
(3)内存池结构的实现
每一个Ring环都会维护一个内存池结构,分配用于存储数据包的内存块。
其中内存池控制块结构如下:
内存分片首部结构如下:
对于模式transparent=0,创建一个对象struct packet_type并将其Hook到协系统的协议栈 中(dev_add_pack函数和dev_remove_pack函数)。将其中的func句柄设置为函数PakcetRecv(), type设置为ETH_P_ALL(以便处理所有协议的二层数据帧)。
这时,在传统方式接收网络数据包时,当网卡通过中断接收到数据包,调用net_rx_action() 处理分组,在netif_receive_skb()函数中会将数据包派发到我们的PacketRecv()分组处理例程 中,从而实现接收数据截获;发送数据包通过dev_queue_xmit()将自己创建的skb从指定网卡 上发送出去。
机译: 基于隧道环境的无线传感器网络数据采集方法
机译: 一种改善高速互联网络数据传输的方法和系统
机译: 基于人工神经网络数据局部的缓存数据支持高速人工神经网络操作的数据管理设备