PF_RING

该捕获方案采用在内核层开出一个比较大的环形缓冲,然后应用层通过mmap映射到内核的缓冲空间,从增加底层缓存到减少
应用层系统调用等方面做了优化,数据捕获性能有了质的提高,而且其从驱动到应用层的接口库都是开源的,例子程序也很全。
 
官方的测试结果:
 
1 Gigabit tests performed using a Core2Duo 1.86 GHz, Ubuntu Server 9.10 (kernel 2.6.31-14), and an IXIA 400 traffic generator injecting traffic at wire rate (64 byte packets, 1.48 Mpps):
e1000e
Application transparent_mode=0 transparent_mode=1 transparent_mode=2
pfcount (with -a flag) 757 Kpps 795 Kpps 843 Kpps
pfcount (without -a flag) 661 Kpps 700 Kpps 762 Kpps
pcount (with PF_RING-aware libpcap) 730 Kpps 763 Kpps 830 Kpps
pcount (with vanilla libpcap) 544 Kpps
pfcount (with PF_RING DNA) 1’170 Kpps
igb
Application transparent_mode=0 transparent_mode=1 transparent_mode=2
pfcount (with -a flag) 650 Kpps 686 Kpps 761 Kpps
pfcount (without -a flag) 586 Kpps 613 Kpps 672 Kpps
pcount (with PF_RING-aware libpcap) 613 Kpps 644 Kpps 711 Kpps
pcount (with vanilla libpcap) 544 Kpps
pfcount (with PF_RING DNA)
 
 
e1000e\igb分别为intel的两款网卡驱动,transparent_mode为PF_RING驱动加载时的参数。PF_RING效率最高的是DNA (Direct NIC Access)模式,
但是该模式代码并未全部开源,而且使用有限制。


Luca 发明了一种PF_RING机制,类似于零拷贝技术。可以应用于linux内核级数据包捕获,libpcap也做了补充,提供了通用接口。
PF_RING 基本原理:网卡接收网络数据包,已往的方式是网卡接收数据包后经过内核函数处理,然后逐层(TCP/IP)上传,一直到应用层接口socket。 PF_RING将网卡接收的数据包存储在一个环状缓存,这也是为什么叫RING的原因。这个环状缓存有两个接口,一个供网卡向其中写数据包,另一个为应用 层程序提供读取数据包的接口,读取数据包的接口通过mmap实现。网卡的中断模式采用Device Polling,Linux下也称作NAPI,在网卡驱动程序中支持。而这种环状缓存是通过向内核中添加一种新的协议簇,添加一种新的带缓存的 socket来实现的,提供通用socket接口,这也是为什么叫PF_RING的原因。辅以一种称作rtirq的内核补丁,将会取得不错的数据捕捉效 率。实验平台采用
操作系统:FC5(2.6.16)
网卡:intel e1000千兆网卡
CPU:intel P4 3.2G
内存:1G

PF_RING 零拷贝技术比较相像,区别可能仅在于以socket和libpcap补丁的形式完成,以及rtirq补丁(本人对零拷贝的具体细节不是很熟)。主要由几种 技术组成:环状缓存、mmap、NAPI、rtirq,socket接口,这几样搭配起来就可以实现PF_RING(rtirq实际上是一个外在的提高性 能的补丁,起的作用是实时irq的作用)。PF_RING设计到Linux内核编程的诸多方面:如内存管理、进程管理和进程调度、内核同步、模块编程、内 核中断机制、内核网络实现以及网卡驱动。
PF_RING可以工作在2.4和2.6内核中,最好网卡支持NAPI(2.6内核很多网卡都支持NAPI,如intel e1000,8139,3c50x等),PF_RING以内核模块的形式存在。PF_RING文件结构如下:

主文件ring_packet.c,PF_RING的缓存、mmap、socket接口都是在这里完成的,1500行。
头文件ring.h,ring_packet.c所需要的函数、结构的定义
补丁文件:分别对dev.c,sock.h,netsyms.h进行补丁,将PF_RING的接口写进内核
NAPI:主要体现在网卡驱动上,对应e1000的网卡驱动

具体分析PF_RING的实现。(具体函数就不分析了,可见以前的文章)
PF_RING基本结构体:
1.ring_cluster,一个描述通用的环状缓存的结构体,将所有的环状婚存组成一个链表。
struct ring_cluster {
u_short cluster_id;
u_short num_cluster_elements;
enum cluster_type hashing_mode;
u_short hashing_id;
struct sock *sk[CLUSTER_LEN];
struct ring_cluster *next;
};
2.ring_opt,描述每个cluser具体的结构体,包括这个cluser的帮定的硬件,cluster内部的slot等信息。等待队列、内核锁和BPF在这里设置
struct ring_opt {
struct net_device *ring_netdev;

u_short ring_id;


u_short cluster_id;


struct net_device *reflector_dev;


unsigned long order;


unsigned long ring_memory;
FlowSlotInfo *slots_info;
char *ring_slots;


u_int pktToSample, sample_rate;


struct sk_filter *bpfFilter;


atomic_t num_ring_slots_waiters;
wait_queue_head_t ring_slots_waitqueue;
rwlock_t ring_index_lock;


u_int insert_page_id, insert_slot_id;
};

3.ring_element,专门为ring的上层sock结构构造了链表
struct ring_element {
struct list_head list;
struct sock *sk;
};
4.cluster_type,缓存类型,per_flow就是流动的类型,后者不大理解
enum cluster_type {
cluster_per_flow = 0,
cluster_round_robin
};
5.flowSlot,cluster中的slot描述结构
typedef struct flowSlot {
#ifdef RING_MAGIC
u_char magic;
#endif
u_char slot_state;
u_char bucket;
} FlowSlot;

6.flowSlotInfo,每个cluster都有一个专门描述SlotInfo的结构体,它的位置在整个内存的最前面
typedef struct flowSlotInfo {
u_int16_t version, sample_rate;
u_int32_t tot_slots, slot_len, da
ta_len, tot_mem;

u_int64_t tot_pkts, tot_lost;
u_int64_t tot_insert, tot_read;
u_int32_t insert_idx, remove_idx;
} FlowSlotInfo;

7.pcap_pkthdr,与libpcap中的pcap_pkthdr一样,同样是描述没个数据包的结构体
struct pcap_pkthdr {
struct timeval ts;
u_int32_t caplen;
u_int32_t len;
};
默认变量:
1.static struct list_head ring_table;
ring_table为list_head类型,实际上是ring_element的链表头,也就是ring的所有的sock/socket的链表
2.static struct ring_cluster *ring_cluster_list;
ring_cluster_list,ring_cluster类型指针,所有的ring_cluster组成的链表
默认常量:
static u_int bucket_len = 128,//每个slot大小是128byte??怎么想的?
num_slots = 4096,//每个cluster有几个slot
sample_rate = 1,//是否捕捉数据包
transparent_mode = 1,
enable_tx_capture = 0;//是否传送数据包
#define CLUSTER_LEN 8//默认cluster个数
#define PF_RING 27
不祥常量:
#define SOCK_RING PF_RING
#define SIORINGPOLL 0x8888
#define RING_MAGIC
#define RING_MAGIC_VALUE 0x88
#define RING_FLOWSLOT_VERSION 6
#define RING_VERSION "3.2.1"
#define SO_ADD_TO_CLUSTER 99
#define SO_REMOVE_FROM_CLUSTER 100
#define SO_SET_REFLECTOR 101
#ifdef INCLUDE_MAC_INFO
#define SKB_DISPLACEMENT 14
#else
#define SKB_DISPLACEMENT 0
#endif

你可能感兴趣的:(IDS--入侵检测)