- 浏览: 229173 次
- 性别:
- 来自: 北京
最新评论
-
qq452739204:
如果构造的报文大于mtu值,是否需要分片之后再发送出去列?
Linux内核构造数据包并发送(二)(dev_queue_xmit方式) -
xingzengmou:
你好,我搞的原理跟你差不多,但播放的时候有papapa的声音, ...
AudioRecord和AudioTrack类的使用 -
wenjiefeng:
楼主,你有录制pcm格式和播放pcm格式的录音器的demo吗, ...
AudioRecord和AudioTrack类的使用 -
lovepeakingA:
...
AudioRecord和AudioTrack类的使用 -
ZaneLee007:
假的,不学无术
Android禁用键盘的所有按键
参看: http://www.linuxjournal.com/article/6345 http://www.ibm.com/developerworks/cn/java/j-zerocopy/index.html http://blog.chinaunix.net/u/5251/showart_411109.html
1.传统的报文捕获实现过程 数据链路层通过网卡驱动程序判断报文的目的物理地址是否为广播地址或者组播地址,若不是则再判断是否为本机 MAC 地址,若不是将直接丢弃该报文,不向上层提交,不然上交报文;报文被提交到网络 IP 层以后,IP 网络层判断报文(struct sk_buff) IP 头部所含目标 IP 地址是否为本机 IP 地址,如果不是,则不向上层提交,若是则将其提交到 TCP 或者 UDP 层;传输层获取传输层头部目标端口,判断该端口是否已被打开,如果没有打开,则不作处理,不向上层提交,若该端口已经被打开,则将该报文送到该连接(struct sock 和 struct socket 对应一个网络连接)的报文接收队列中,同时唤醒该连接上休眠的等待进程,进程从报文接收队列中取得报文然后返回。下面的例子是 Linux 下: a. TCP/IP 协议栈框架结构 b. TCP/IP 协议栈接收数据包的过程 数据报文在 Linux 内核协议中流动分为 2 个过程,即自上而下和自下而上 2 个过程。其中,内核协议栈捕获网络报文是一个自下而上的过程,而上层应用获取网络数据的过程则是一个自上而下的过程。下面简要分析内核协议栈捕获数据报文的过程。
1.2 传统的报文捕获机制分析 以太网采用了CSMA/CD 技术,通过广播机制实现数据传输。在系统正常工作时,应用程序只能接收到以本机为目标逐句的数据报文,以及广播报文和组播报文。因此要捕获不属于自己的报文,必须直接访问网络底层,首先将网卡置于混杂模式,使之可以接收其它类型的数据,然后系统直接访问数据链路层,捕获数据,最后提交给应用,这样就实现了捕获流经网卡的所有报文。 a. BSD 分组过滤器 BPF BSD 系统及许多源于 Berkeley 的实现均使用 BPF 机制作为数据链路层访问手段。在支持 BPF 机制的系统上,每个数据链路层核心程序都在收到一个保温后直接调用 BPF 接口,并将该报文的拷贝传递给该接口。 BPF 接口不仅可以对数据链路层进行直接监听,而且还可以实现信息过滤。任何一个打开 BPF 接口的应用程序都可以安装自己的过滤器,然后由 BPF 接口对捕获到的每个报文分别进行处理。BPF 的过滤机制基于寄存器级别,并且可以对每个报文应用进程专有的过滤机制,这样,进程就可以实现只捕获自己感兴趣的报文,甚至还可以选择只捕获报文的特定部分。为了减小系统开销,BPF 接口采用了下面 3 项技术: 为了访问 BPF 接口,应用进程需要打开一个 BPF 设备。当该设备被打开后,便会被锁定,随后应用可以使用一系列操作来设置设备属性,包括:装在过滤规则、设置超时时间和缓冲区大小、设置网卡混杂工作模式等。这一切预备工作完成后,应用就可以开始报文捕获循环了。 b. SVR4 的数据链路提供者接口 DLPI c. Linux 的 SOCK_PACKET 接口 而如果按照下列方式创建套接字后,上层应用程序将只会获得 IP 协议类型的数据帧。 与 BPF 相比,Linux 下的 SOCK_PACKET 机制有以下几点不同: Libpcap 作为一个公开的报文捕获函数库,在其实现上完全支持上述几种接口,因此使用它的应用程序可以独立于操作系统所提供的实际链路层访问方式。大致流程如下: 在自下而上的数据捕获流程中: 在网卡驱动的接收中断处理例程完成对报文的处理后,报文便被送入内核协议栈层。
Linux 系统其协议栈对于工作在数据链路层的 SOCK_PACKET 机制提供了很好的支持,同时它也完全支持 BPF机制,下面将基于 Linux 操作系统基础上,分析 libpcap 函数库对于上述两种机制的实现。 1. libpcap 函数库如利用工作在数据链路层的套接字 sock_packet 来完成网络数据报文的读取,具体实现流程大概是: 2. libpcap 如利用工作在数据链路层的 BSD 分组过滤器来完成网络数据报文的读取,大致过程是: BPF 提供了直接对数据链路层进行访问的接口,并且可以在该层实现对于 IP 地址,数据报文类型以及端口的选择性过滤,最终只向上提交用户关心的数据部分,减少了内存操作,大大提高了报文捕获系统的工作效率。 libpcap 函数库绕过 TCP 层(UDP 层)和 IP 层繁杂的协议处理过程,直接将数据帧从数据链路层拷贝到应用程序缓冲区中。虽然这样的实现机制能够大量节省数据报文在传输过程中所消耗的 CPU 时间,但是在 libpcap 的整个报文捕获过程中,系统调用、数据拷贝和网卡接收中断处理仍然是系统主要的性能影响因素。
1.1 协议栈运行机制分析
当操作系统协议栈正常工作时,应用程序只能接收到发往本机的数据包,其它地址的数据包将被丢弃。数据包通路分为数据链路层、网络层、传输层、套接字层和应用层几个层次。
操作系统的内核协议栈基本可以分为数据链路层、IP 层、TCP/UDP 层、INET Socket 层、BSD Socket 层,以及应用层几个部分。
内核协议栈包括一组发送接收函数和相关的关键数据结构。用户层的网络连接信息通过内核数据结构 struct socket 和 struct sock 来维护。数据缓冲区是由两个数据结构 struct msghdr 和 struct sk_buff 来维护的。其中 struct msghdr 由 BSD socket 层和 INET socket 层来维护,struct msghdr 用于存放应用程序数据缓冲区的地址和大小,而在 TCP、IP 及以下各层使用 struct sk_buff 来管理报文数据缓冲区。内核在 tcp_sendmsg() 和 tcp_recvmsg() 函数中通过内存拷贝操作实现 2 种数据结构(struct msghdr 和 struct sk_buff)之间的信息传递。报文信息在传输层(TCP 层),网络层(IP 层)及以下各层时,不会进行拷贝操作,仅在结构 sk_buff 的不同协议头之间移动数据指针,这样可以避免不必要的拷贝开销。
本文以 Intel 1000M 网卡驱动 e1000 为例,对照图 2.3 中的内核协议栈框架,详细分析在 Linux 内核协议栈中数据报文通过的路径。
(1)网络报文到达后,网卡通过 DMA 方式将数据报文送到网卡驱动程序缓冲区并在传输结束时产生硬件接收中断。系统根据中断类型调用相应硬中断处理程序,由此便完成数据由物理层到链路层的传递。
(2)硬中断处理程序 do_IRQ() 根据寄存器状态会间接调用 e1000_intr() 处理接收到的报文,最后函数 e1000_clean_rx_irq() 会调用 netif_rx() 将驱动程序接收缓冲环(rx_ring) 报文添加到系统接收队列 backlog 中,操作系统在空闲时调用上层软中断处理函数 net_rx_action()。在这个函数中,根据已注册的数据报文类型(如 ETH_P_IP 或者 ETH_P_ALL)调用相应类型处理函数(通常情况下为 ip_rcv(),后面将以该函数为例对 IP 层的报文处理路径进行说明),这样网络数据由链路层进入到了 IP 层。
(3)在报文处理函数 ip_rcv() 中,当根据路由结果判断数据应发送到上层 TCP 协议处理时,系统协议栈会根据 tcp_v4_rcv(),随后调用 tcp_v4_do_rcv(),通过 tcp_v4_do_rcv() 将 sk->backlog 队列中的报文填充到 sk->receive_queue 队列中,同时唤醒在连接控制结构(struct sock)等待队列(即休眠队列 sk_sleep)上的所有进程,激活由上到下的接收过程。
通过设置网卡工作模式,报文捕获系统便可以在网络上截获位于 OSI 协议模型中数据链路层上的报文。目前大多数操作系统都为应用提供了直接访问数据链路层的手段,它使应用可以监视数据链路层上的报文而不需使用特殊硬件设备。
目前 UNIX 操作系统中有 3 种常用的数据链路层访问机制,它们分别是:BSD 系统中采用的 BPF,SVR4 的数据链路提供者接口(DLPI)和 Linux 的 SOCKET_PACKET 接口,还有其它类似的链路层访问机制。
(1)BPF 过滤只在内核实现,减少了拷贝数据量。不然的话,由于从内核空间到用户空间的拷贝比较昂贵,而如果对于每个报文都进行拷贝,那么 BPF 接口将不能满足高速数据传输的需求。
(2)每个报文中只有部分敏感数据需要 BPF 接口捕获,该部分的长度和被称为报文捕获长度。大多数应用通常只需要报文头,而不需要报文中的数据内容。该方法同样减少了内核空间到用户空间的数据拷贝量。
(3)BPF 批量地向应用传递数据,而不是对于每个到达的报文都进行一次专门的数据拷贝操作。该缓冲区只有在满或者超时发生后才将数据拷贝到应用空间。缓冲区和超时值可由应用在初始化时灵活指定。设置缓冲区的目的在于减少拷贝以及系统调用次数。BPF 给每个应用进程维护 2 个缓冲区,当一个缓冲区向应用拷贝数据时,启用另一个缓冲区接收新的报文。
用得不多,省略。
Linux 中访问数据链路层可以通过创建 SOCK_PACKET 套接字接口来实现。与原始套接字接口的实现相类似,也需要 root 权限,创建该类型的套接字时第 3 个参数指定捕获数据帧的类型。例如,若想获取所有网络数据帧,我们可以按下面的方式创建套接字:
fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))
fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP))
(1)该套接字不提供类似于 BPF 接口中基于内核的缓冲和过滤机制。它只提供套接字接收缓冲区,但由于多个网络帧不能存储在一起,应用便不可能一次性读取多个报文,因此从内核向应用拷贝数据的开销必然会增加。
(2)Linux 不提供针对设备的过滤。应用必须自己丢弃来自不感兴趣设备的数据。存在的问题是这可能会给应用返回过多的数据,而这可能造成数据拥塞。
(1)应用调用 pcap_lookupdev() 函数,这是一个与平台无关的接口,主要用来查找可以实现数据报文捕获的设备。
(2)根据(1)中所找到的设备,调用 pcap_open_live(),创建 struct pcap_t 类型的捕获句柄,准备开始捕获。
(3)如果用户设置了过滤规则,应用会编译和安装该过滤规则,具体是通过 pcap_compile() 和 pcap_setfilter() 这 2 个接口函数来实现。
(4)应用开始进入报文捕获循环,调用 pcap_loop() 捕获报文。在抓到报文后,应用会将数据流转换成数据帧,随后提起帧中信息,判断报文类型。如果为 IP 报文,则转入 IP 报文处理流程;如果为其它类型的报文,则会转入相应类型的报文处理类型之中。在处理完一个报文之后,执行流会转到报文捕获循环的开始处继续运行。
(5)最后,应用通过调用 pcap_close() 关闭捕获句柄,释放系统初始化时所申请的全部资源。
(1)网络数据包进入网卡缓存后设置网卡相关状态寄存器并触发网卡接收终端,即网卡向中断控制寄存器发出中断信号。中断控制寄存器接到中断信号后,向 CPU 发出中断处理请求信号。
(2)CPU 在执行完当前正在执行的指令后视状态寄存器的情况而决定是否响应中断。
(3)如允许响应中断,则向中断控制器发出响应电信号。
(4)接到 CPU 的响应信号后,中断控制器准备好当前中断的类型号放入相关数据寄存器。随后,CPU 从该寄存器内读取中断类型号,读取中断向量表,获得中断处理例程的入口地址,然后转入中断处理过程。
(5)中断处理例程根据中断类型号,调用当前发出中断的设备的中断处理函数。
(6)在该中断处理的函数调用中,通过读取网卡相关状态寄存器来判别该中断是属于发送中断还是接收终端,或是其他的由于错误导致的中断,然后根据该状态寄存器调用相应的处理函数。经过一些处理,如校验和验证,接收中断处理例程开始分配套接字缓存器 sk_buff。
(7)套接字缓冲区 sk_buff 分配成功以后,执行流将会拷贝网卡数据到缓冲区内(或者在 DMA 数据传输方式下,数据传输绕开 CPU 处理,此处分配的缓冲区可以直接用于下一次的报文接收工作)。
(1)当网络数据报文到达以后,网卡通过 DMA 方式将数据报文传输到网卡驱动程序接收缓冲环(rx_ring)中接收描述符所指示的位置上,并且在数据传输结束时触发硬件接收中断。系统根据寄存器中的中断类型号调用相应的中断处理程序,最后执行流会间接调用到网卡中断处理程序中的报文接收处理子程序。
(2)在报文接收处理例程中,内核处理数据报文并通过函数 netif_rx() 将驱动程序接收缓冲环(rx_ring)中的数据添加到系统接收队列 backlog 中。操作系统在空闲时调用中断处理程序下半部分即软中断处理函数 net_rx_action()。此函数的主要功能是,检查系统中已经注册的数据包类型并调用相应的处理函数来处理数据报文。libpcap 函数库注册的报文接收类型为 ETH_P_ALL,即接收所有的网络数据帧,其处理函数为 packet_rcv()。该函数工作在数据链路层。
(3)packet_rcv() 函数将直接调用 skb_queue_tail() 将数据报文存放在代表相应网络连接控制结构(struct sock)的接收队列 receive_queue 中。这样数据报文在接收过程中就绕过了 TCP 层和 IP 层繁琐的协议处理过程。
(4)最后,睡眠在 sk 等待队列上的函数 packet_recvmsg() 会接收链路层数据帧并将该数据帧直接拷贝到应用程序缓冲区中。
(1)当网络数据报文到达以后,网卡通过 DMA 方式将数据报文传输到网卡驱动程序接收缓冲环(rx_ring)中接收描述符所指示的位置上,并且在数据传输结束时触发硬件接收中断。随后,网卡驱动程序会将报文提交到系统协议栈。
(2)如果 BPF 正在进行侦听,则网卡驱动程序会首先调用 BPF 模块,该模块会将数据报文发送给过滤器模块,过滤器模块随后按照预先配置的规则对数据报文进行处理,随后经过过滤的数据报文被提交给上层应用程序。
(3)网卡驱动重新获取控制权,数据报文被提交给上层的系统协议栈,进行正常的协议处理工作。
发表评论
-
ARP头
2010-12-01 17:20 1262ifndef _NET_IF_ARP_H_ #d ... -
自己用libpcap来抓包
2010-12-01 16:40 6967#define APP_NAME &quo ... -
MAC文本格式地址to网络字节序
2010-12-01 16:38 2153#include <sys/types.h& ... -
C语言实现修改IE浏览器的代理设置
2010-11-24 17:18 4637写了一个用C语言实现修 ... -
[转]通过例子学习Lua
2010-11-17 21:25 4772据说本文作者是OGDEV的HACK达人 通过例子学习 ... -
size_t和ssize_t类型
2010-10-22 10:11 1742size_t 是为了方便系统之间的移植而定义的在32位系统 ... -
sendfile() -- 通过 socket 拷贝文件
2010-10-19 08:53 2717原型: #include <sys/sendfi ... -
零拷贝与 sendfile
2010-10-19 08:47 3729最近在搞zerocopy的东西,看到了这篇文章,拷过来备用! ... -
C++队列实现和队列简介
2010-10-09 11:04 2861队列简介: 队列(Queue)是一种数据结构,可以在队 ... -
定长队列写入文件并读取
2010-10-09 10:57 1397#include "stdio.h" ... -
循环队列
2010-10-09 10:55 1690相信绝大多数都学习过《数据结构》这门课程,而对这门课程里 ... -
自动、静态、 寄存器、易失变量的区别
2010-09-30 08:08 1601自动变量 什么是 ... -
stdarg.h
2010-09-27 09:12 1830stdarg.h是C语言中C标 ... -
extern用法详解
2010-09-27 08:33 14011 基本解释 extern ... -
给线程变量pthread_t *thread动态分配空间
2010-09-26 08:36 3160线程的创建是用下面的几个函数来实现的. #inc ... -
Linux Daemon In C
2010-09-26 08:22 2417This is a template for a Lin ... -
typedef 的用法
2010-09-25 20:43 938用途一: 定义一种类型的别名,而不只是简单 ... -
编写守护进程
2010-09-17 10:43 916#include <stdio.h> #incl ... -
抓包程序的包存储队列
2010-09-17 09:08 818typedef struct _Node { in ... -
浅谈C中的malloc和free
2010-09-03 19:37 906在C语言的学习中,对内存管理这部分的知识掌握尤其重要!之前对C ...
相关推荐
本文提出了一种名为PF-DMA(Packet Filtering Direct Memory Access)的新型零拷贝报文捕获技术,它是在Linux系统环境下实现的。PF-DMA通过扩展和替换内核函数,如net_dev_alloc_skb()和dev_kfree_skb(),在不改变...
2. **高速报文捕获**:在千兆网络环境下,报文捕获需要达到线速,即与网络传输速率相匹配,以避免数据丢失。研究中提到的内存映射和零拷贝技术是提高报文捕获效率的关键。内存映射允许应用程序直接访问内存在硬件...
网络监测用得到的文档,主要是零拷贝的技术的实现过程
为了解决这一问题,研究人员采用“零拷贝”(Zero Copy)的技术思想,设计并实现了一个适用于IPv6高速网络环境下的数据分组捕获平台(High Speed Packet Capture Platform,简称HSPCP)。该研究旨在提高数据分组捕获...
文章中的智能网卡通过FPGA和零拷贝技术的结合,实现了报文捕获、分析、分类和过滤等功能。这种设计使得智能网卡能够进行高效的数据包捕获,并对数据包进行有效的分类与过滤,只把重要的数据报文提交给上层应用软件...
论文中提到的PCPUZ(Packet Capture Platform Based on Universal Zero-Copy)是一种针对网络报文捕获的通用零拷贝平台。PCPUZ通过对Linux内核的套接字缓冲区的内存分配和释放机制进行修改,使得用户程序能够直接...
提出了一种基于PF_DMA的零拷贝报文捕获改进方法,对相关Linux内核函数进行扩展和替换,在不改变原有内核和网卡驱动代码的基础上,实现报文的零拷贝,实验结果表明,该方法保持了PF_DMA捕包的高效率,同时具有更好的...
通过原始套接字,可以更加自如地控制Windows下的多种协议,而且能够对网络底层的传输机制进行控制。 网络数据包截获机制一般指通过截获整个网络的所有信息流,根据信息源主机、目标主机、服务协议端口等信息,简单...
【NETBIOS协议分析】是网络技术中的一个重要环节,它主要涉及网络通信和Windows操作系统环境下的应用程序交互。NETBIOS,全称“网络基本输入输出系统”,是一种在局域网上提供名字服务、会话服务和数据报服务的协议...
2.解压缩packetvb-1.0.0.3.bin.zip,把其中的vbpcap.dll拷贝到c:\windows\system32目录下 3.“开始”-->“运行”,输入“regsvr32 c:\windows\system32\vbpcap.dll”,注册vbpcap.dll 4.打开VB,“工程”-->“引用”-...
6. **错误处理**:在Keil环境下,需要捕获并处理可能出现的错误,如套接字创建失败、网络中断、内存分配失败等。 7. **调试工具**:Keil IDE提供了强大的调试功能,如设置断点、查看变量值、单步执行、调用堆栈分析...
分组捕获库接收计算机发送和接收的每一个链路层帧的拷贝。高层协议(如:FTP、TCP、UDP、DNS、IP等)交换的报文都被封装在链路层帧(Frame)中,并沿着物理介质(如以太网的电缆)传输。 六、Ethereal(或WireShark...
9. **性能优化**:对于高性能网络应用,源码可能包含了一些优化策略,如缓冲区管理、零拷贝技术等,以减少CPU和内存的使用。 10. **API设计**:PacketNet-code 可能提供了一套API,使得其他程序可以方便地调用其...
基于连接修改和传递技术的TCP迁移方法具有较高的灵活性,适用于多种网络环境下的TCP连接迁移需求。 #### 五、基于重构连接现场的TCP迁移方法 **技术实现背景** 随着网络应用的不断发展,传统的TCP连接迁移方法已经...
测试结果表明,该系统能够显著提高数据报文的采集能力,对于现代高带宽网络环境下的流量监控具有重要的应用价值。未来的研究将进一步探索如何在更大规模的网络环境中部署和优化此类高性能流量采集系统。