- 浏览: 1407406 次
- 性别:
- 来自: 火星
-
文章分类
最新评论
-
aidd:
内核处理time_wait状态详解 -
ahtest:
赞一下~~
一个简单的ruby Metaprogram的例子 -
itiProCareer:
简直胡说八道,误人子弟啊。。。。谁告诉你 Ruby 1.9 ...
ruby中的类变量与类实例变量 -
dear531:
还得补充一句,惊群了之后,数据打印显示,只有一个子线程继续接受 ...
linux已经不存在惊群现象 -
dear531:
我用select试验了,用的ubuntu12.10,内核3.5 ...
linux已经不存在惊群现象
首先来看校验相关的一些结构:
1 net_device结构:
包含一个features的域,这个表示设备的一些特性(比如控制校验),下面的几个flag就是用来控制校验:
每个flags的介绍,注释里面都写得很清楚,这里就不一一解释了。这里要注意的是NETIF_F_HW_CSUM,他其实表示在硬件上为所有协议校验。
2 sk_buff:
skb->csum和skb->ip_summed这两个域也是与校验相关的,这两个域的含义依赖于skb表示的是一个输入包还是一个输出帧。
当数据包是一个输入包时,skb->csum表示的是当前数据包的4层的checksum值,skb->ip_summed表示的是四层校验的状态,下面的几个宏定义表示了设备驱动传递给4层的一些信息(通过ip_sumed),这里要注意,一旦当四层接受了这个包,他可能会改变ip_summed的值。
CHECKSUM_NONE表示csum域中的校验值是错误的,也就是校验失败。这里要注意的是,一般来说当2层的校验失败后,驱动会直接丢掉这个包,可是如果输入帧是要被forward的,那么路由器不应该由于一个四层的校验失败而丢掉这个包(路由器不建议查看四层的校验值),它将会将这位置为CHECKSUM_NONE,然后将包发向目的地址,交由目的地址的主机来进行处理。
CHECKSUM_UNNECESSARY表示网卡已经计算和验证了四层的头和校验值。也就是计算了tcp udp的伪头。还有一种情况就是回环,因为在回环中错误发生的概率太低了,因此就不需要计算校验来节省cpu事件。
CHECKSUM_COMPLETE表示nic已经计算了4层头的校验,并且csum已经被赋值,此时4层的接收者只需要加伪头并验证校验结果。
接下来我们来看当数据包是输出包时的情况,此时csum表示为一个指针,它表示硬件网卡存放将要计算的校验值的地址。这个域在输出包时使用,只在校验值在硬件计算的情况下。比如NAT,它会修改ip头,此时就需要重新计算4层的校验值,也就是从4层传递下来的4层校验值需要在底层进行修改。当修改后,我们在底层就可以通过csum来存取这个校验值。
而此时ip_summed可以被设置的值有下面两种:
这时含义就完全不一样了。第一个表示已经计算好了校验值,设备不需要做任何事。
第二个表示4层的伪头的校验已经完毕,并且已经加入到ip头中,此时只需要设备计算整个头4层头的校验值。
主要来看一下ip输入数据包的处理,也就是ip协议处理函数。
具体的协议注册什么的,可以看我前面的blog,这里我们知道处理ip输入的函数是ip_rcv.
先来看下当执行ip_rcv执行之前,sk_buff的结构:
我们这里先不详细介绍net filter,这里我们只需要知道,在NF_HOOK中,会检测每个包(通过用户空间设置的规则)然后来决定要不要这个数据包通过。最后如果允许的话,就会调用 ip_rcv_finish函数。所以这里我们详细看下 ip_rcv_finish函数:
它主要会做两件事:
1 决定这个包是被传递给高层,还是被forward。
2 解析并执行一些ip option。
1 net_device结构:
包含一个features的域,这个表示设备的一些特性(比如控制校验),下面的几个flag就是用来控制校验:
#define NETIF_F_IP_CSUM 2 /* Can checksum TCP/UDP over IPv4. */ #define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */ #define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */ #define NETIF_F_IPV6_CSUM 16 /* Can checksum TCP/UDP over IPV6 */
每个flags的介绍,注释里面都写得很清楚,这里就不一一解释了。这里要注意的是NETIF_F_HW_CSUM,他其实表示在硬件上为所有协议校验。
2 sk_buff:
skb->csum和skb->ip_summed这两个域也是与校验相关的,这两个域的含义依赖于skb表示的是一个输入包还是一个输出帧。
当数据包是一个输入包时,skb->csum表示的是当前数据包的4层的checksum值,skb->ip_summed表示的是四层校验的状态,下面的几个宏定义表示了设备驱动传递给4层的一些信息(通过ip_sumed),这里要注意,一旦当四层接受了这个包,他可能会改变ip_summed的值。
/* Don't change this without changing skb_csum_unnecessary! */ #define CHECKSUM_NONE 0 #define CHECKSUM_UNNECESSARY 1 #define CHECKSUM_COMPLETE 2
CHECKSUM_NONE表示csum域中的校验值是错误的,也就是校验失败。这里要注意的是,一般来说当2层的校验失败后,驱动会直接丢掉这个包,可是如果输入帧是要被forward的,那么路由器不应该由于一个四层的校验失败而丢掉这个包(路由器不建议查看四层的校验值),它将会将这位置为CHECKSUM_NONE,然后将包发向目的地址,交由目的地址的主机来进行处理。
CHECKSUM_UNNECESSARY表示网卡已经计算和验证了四层的头和校验值。也就是计算了tcp udp的伪头。还有一种情况就是回环,因为在回环中错误发生的概率太低了,因此就不需要计算校验来节省cpu事件。
CHECKSUM_COMPLETE表示nic已经计算了4层头的校验,并且csum已经被赋值,此时4层的接收者只需要加伪头并验证校验结果。
接下来我们来看当数据包是输出包时的情况,此时csum表示为一个指针,它表示硬件网卡存放将要计算的校验值的地址。这个域在输出包时使用,只在校验值在硬件计算的情况下。比如NAT,它会修改ip头,此时就需要重新计算4层的校验值,也就是从4层传递下来的4层校验值需要在底层进行修改。当修改后,我们在底层就可以通过csum来存取这个校验值。
而此时ip_summed可以被设置的值有下面两种:
#define CHECKSUM_NONE 0 #define CHECKSUM_COMPLETE 2
这时含义就完全不一样了。第一个表示已经计算好了校验值,设备不需要做任何事。
第二个表示4层的伪头的校验已经完毕,并且已经加入到ip头中,此时只需要设备计算整个头4层头的校验值。
主要来看一下ip输入数据包的处理,也就是ip协议处理函数。
具体的协议注册什么的,可以看我前面的blog,这里我们知道处理ip输入的函数是ip_rcv.
先来看下当执行ip_rcv执行之前,sk_buff的结构:
![](/upload/attachment/119877/7a87af9b-00a3-3b11-bfb5-93675512470b.jpg)
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct iphdr *iph; u32 len; ///我们知道当为PACKET_OTHERHOST是,2层就会直接丢掉所有的包,可是如果网卡被设置为混杂模式,此时包就会传递到3层,这个时侯内核会有hook来处理这个,而我们这里就只需要直接丢掉所有的包。 if (skb->pkt_type == PACKET_OTHERHOST) goto drop; IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INRECEIVES); ///检测这个数据包是否被内核其他部分使用,也就是监测引用计数。如果有被其他部分使用,则直接复制一份副本,然后返回。 if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); goto out; } //检测skb->data的数据至少要和ip头大小一样。(这个原因很简单,每个包都必须包含一个ip头,如果比ip头还小,说明包头有错误了。 if (!pskb_may_pull(skb, sizeof(struct iphdr))) goto inhdr_error; ///取出ip头 iph = ip_hdr(skb); /* * RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum. * * Is the datagram acceptable? * * 1. Length at least the size of an ip header * 2. Version of 4 * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] * 4. Doesn't have a bogus length */ ///ip头的ihl域表示ip头的大小(就是也就是IP层头部包含多少个32位),version表示ip协议版本,这里第一个检测的原因是基本ip头的大小是20个字节,也就是最小为20个字节,20*8/32=5,所以最小必须是5。而这里版本,由于这个只处理ipv4,因此version必须是4. if (iph->ihl < 5 || iph->version != 4) goto inhdr_error; ///这次来检测整个ip头的大小(包括option)和skb->data.这个检测到这里才执行,是因为,必须首先确定ip头的基本正确。 if (!pskb_may_pull(skb, iph->ihl*4)) goto inhdr_error; iph = ip_hdr(skb); ///开始校验ip头,也就是开始三层校验。 if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) goto inhdr_error; ///取出整个ip头的长度(包括option) len = ntohs(iph->tot_len); ///接下来的检测是因为在2层由于要满足最小帧的大小,因此可能会填充一些空数据,而三层ip头计算长度时,会忽略这些空数据,因此这里的skb->len一定是大于或等于len if (skb->len < len) { IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS); goto drop; } else if (len < (iph->ihl*4)) ///这个判断是因为ip头不能被切包,也就是每个切好的包必须至少包含一个ip头。 goto inhdr_error; /* Our transport medium may have padded the buffer out. Now we know it * is IP we can trim to the true length of the frame. * Note this now means skb->len holds ntohs(iph->tot_len). */ ///这里也就是我们上面说的情况,需要把skb->len和len统一起来(去除掉空数据) if (pskb_trim_rcsum(skb, len)) { IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); goto drop; } /* Remove any debris in the socket control block */ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); ///调用net filter hook。 return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish); inhdr_error: IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS); drop: kfree_skb(skb); out: return NET_RX_DROP; }
我们这里先不详细介绍net filter,这里我们只需要知道,在NF_HOOK中,会检测每个包(通过用户空间设置的规则)然后来决定要不要这个数据包通过。最后如果允许的话,就会调用 ip_rcv_finish函数。所以这里我们详细看下 ip_rcv_finish函数:
它主要会做两件事:
1 决定这个包是被传递给高层,还是被forward。
2 解析并执行一些ip option。
static int ip_rcv_finish(struct sk_buff *skb) { const struct iphdr *iph = ip_hdr(skb); struct rtable *rt; /* * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ ///查找路由表的相关操作。 if (skb->dst == NULL) { ///查找路由。这里也会初始化skb->dst->input。 int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); if (unlikely(err)) { if (err == -EHOSTUNREACH) IP_INC_STATS_BH(dev_net(skb->dev), IPSTATS_MIB_INADDRERRORS); else if (err == -ENETUNREACH) IP_INC_STATS_BH(dev_net(skb->dev), IPSTATS_MIB_INNOROUTES); goto drop; } } ///QOS的相关操作. #ifdef CONFIG_NET_CLS_ROUTE if (unlikely(skb->dst->tclassid)) { struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id()); u32 idx = skb->dst->tclassid; st[idx&0xFF].o_packets++; st[idx&0xFF].o_bytes+=skb->len; st[(idx>>16)&0xFF].i_packets++; st[(idx>>16)&0xFF].i_bytes+=skb->len; } #endif ///当ihl比5大,意味着有option。因此调用ip_rcv_options来进行解析和执行。 if (iph->ihl > 5 && ip_rcv_options(skb)) goto drop; rt = skb->rtable; if (rt->rt_type == RTN_MULTICAST) IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCASTPKTS); else if (rt->rt_type == RTN_BROADCAST) IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCASTPKTS); ///最后调用skb->dst->input,而这个虚函数的的值,首先是在ip_route_input中赋值,然后在 ip_rcv_options也有可能被修改。这个虚函数要么被ip_local_deliver(也就是直接发向高层),要么是ip_forward(直接被forward).这两个函数以后会详细介绍。 return dst_input(skb); drop: kfree_skb(skb); return NET_RX_DROP; }
发表评论
-
Receive packet steering patch详解
2010-07-25 16:46 12207Receive packet steering简称rp ... -
内核中拥塞窗口初始值对http性能的影响分析
2010-07-11 00:20 9730这个是google的人提出的 ... -
linux 内核tcp拥塞处理(一)
2010-03-12 16:17 9625这次我们来分析tcp的拥塞控制,我们要知道协议栈都是很保守的, ... -
内核tcp协议栈SACK的处理
2010-01-24 21:13 12222上一篇处理ack的blog中我 ... -
内核tcp的ack的处理
2010-01-17 03:06 11217我们来看tcp输入对于ack,段的处理。 先是ack的处理, ... -
内核处理time_wait状态详解
2010-01-10 17:39 6859这次来详细看内核的time_wait状态的实现,在前面介绍定时 ... -
tcp协议栈处理各种事件的分析
2009-12-30 01:29 13664首先我们来看socket如何将一些状态的变化通知给对应的进程, ... -
linux内核sk_buff的结构分析
2009-12-25 00:42 47955我看的内核版本是2.6.32. 在内核中sk_buff表示一 ... -
tcp的输入段的处理
2009-12-18 00:56 8386tcp是全双工的协议,因此每一端都会有流控。一个tcp段有可能 ... -
内核协议栈tcp层的内存管理
2009-11-28 17:13 12133我们先来看tcp内存管理相关的几个内核参数,这些都能通过pro ... -
linux内核定时器的实现
2009-10-31 01:44 10219由于linux还不是一个实时的操作系统,因此如果需要更高精度, ... -
linux内核中tcp连接的断开处理
2009-10-25 21:47 10373我们这次主要来分析相关的两个断开函数close和shotdow ... -
linux内核tcp的定时器管理(二)
2009-10-05 20:52 5459这次我们来看后面的3个定时器; 首先是keep alive定 ... -
linux内核tcp的定时器管理(一)
2009-10-04 23:29 9867在内核中tcp协议栈有6种 ... -
linux 内核tcp接收数据的实现
2009-09-26 20:24 14570相比于发送数据,接收数据更复杂一些。接收数据这里和3层的接口是 ... -
linux 内核tcp数据发送的实现
2009-09-10 01:41 19845在分析之前先来看下SO_RCVTIMEO和SO_SNDTIME ... -
tcp connection setup的实现(三)
2009-09-03 00:34 5232先来看下accept的实现. 其实accept的作用很简单, ... -
tcp connection setup的实现(二)
2009-09-01 00:46 8452首先来看下内核如何处理3次握手的半连接队列和accept队列( ... -
tcp connection setup的实现(一)
2009-08-23 04:10 5856bind的实现: 先来介绍几个地址结构. struct ... -
linux内核中socket的实现
2009-08-15 04:38 21134首先来看整个与socket相关的操作提供了一个统一的接口sys ...
相关推荐
对于Linux系统而言,其内核中的TCP/IP协议栈是实现网络通信的基础,它负责解析、处理并转发网络数据。本文将深入探讨Linux协议栈实现的细节,特别是与TCP/IP协议流程相关的部分。 首先,TCP/IP协议栈可以分为四层,...
本文主要关注的是IP协议的实现,因为它是TCP/IP模型中最核心的部分之一。 #### 二、消息通讯简介 ##### 2.1 网络通讯路径 在Linux系统中,网络通讯路径涉及多个层次,从应用程序到物理层的数据传输过程中会经过多...
在构建Linux平台上的IP摄像头采集处理平台时,我们需要考虑多种技术方案来实现高效且可靠的视频流获取、处理和展示。以下是一些可行的解决方案及其详细说明: 1. USB摄像头采集处理方案: 利用Video4Linux接口是...
Linux_v4l2(Video for Linux Two)是Linux内核提供的一种接口,用于与视频捕获设备进行通信,包括图片采集。本教程将围绕Linux_v4l2接口来探讨如何在Linux环境下处理图像。 1. **Linux_v4l2接口**: Linux_v4l2是...
本文介绍了一种利用MPEG4IP流媒体处理平台在Linux环境下实现的实时授课系统,该系统能够有效地同步教师的授课视频、音频以及屏幕数据。 #### 关键技术与实现 本节详细介绍实时授课系统的三个关键方面:媒体数据的...
总之,嵌入式Linux下的多线程视频监控系统结合了Linux的多任务处理能力和V4L2的视频设备接口,构建出一个既经济又高效的远程监控解决方案,特别适合于家庭和其他民用场景。通过多线程技术,该系统可以同时服务多个...
9. 通信工程:本文介绍了如何使用通信工程技术实现视频服务器信号传输,该系统使用TCP/IP协议将视频数据传输到客户端。 10. 软件工程:本文介绍了如何使用软件工程技术实现视频监控系统,该系统使用Linux内核和V4L2...
在Linux环境下实现视频监控是一项技术含量较高的工作,它涉及到多个技术领域的融合,包括硬件设备的驱动、图像处理、网络通信以及前端展示等。本项目主要使用了Linux的Video for Linux Two(V4L2)框架来采集视频源...
标题 "v4l2onvif-master_ONVIF_ONVIFSERVER_onvifserver_v4l2onvif_" 暗示这是一个关于ONVIF协议实现的项目,特别是与Linux环境下的服务器和客户端相关。ONVIF是Open Network Video Interface Forum(开放网络视频...
总的来说,webcam_v4l2_x264项目是一个实用的示例,展示了如何在Linux环境下利用V4L2接口和x264编码器实现摄像头视频的捕捉、压缩和网络传输,以及在远程端进行解码和播放。这为开发自己的视频流应用或者研究相关...
7. **网络通信**:讲述如何配置网络接口,包括以太网控制器驱动和TCP/IP协议栈的配置,实现嵌入式设备的网络功能。 8. **应用程序开发**:介绍如何在Linux环境下进行C/C++编程,开发针对S3C2440的应用程序,以及...
总的来说,这个项目涉及到了Linux系统编程、QT图形界面开发、RTP协议的实现、V4L2接口的使用以及OpenCV的人脸识别技术,是一个综合性的实时视频传输解决方案。开发这样的系统有助于提升开发者在跨平台实时多媒体应用...
标题中的“一种改进的Linux下的IPv4_IPv6转换网关”指的是在Linux操作系统环境下,针对IPv4和IPv6网络间通信的一种优化解决方案。描述提到的传统方法是通过NAT-PT(Network Address Translation - Protocol ...
通过TCP/IP协议,它可以将视频流发送到网络,使用户能够通过监控终端(如Web浏览器)访问视频监控画面。 6. **硬件平台搭建**:系统硬件通常包括处理器(如S3C2440A)、存储器(如NAND/SDRAM/NOR Flash)以及视频...
总的来说,EDNS的内核实现是一项复杂的工作,涉及到对Linux内核代码的深入了解,以及对DNS协议和网络安全的深刻理解。通过这种方式增强DNS功能,可以提高系统的效率和安全性,但同时也需要谨慎处理潜在的负面影响。
7. 网络传输:如果摄像头用于网络视频传输,需要了解TCP/IP协议和相关网络编程知识。 总结,这个项目是关于在网络摄像头应用中整合v4l2框架,以提升其在Linux环境下的性能和兼容性。这涵盖了从底层硬件驱动到上层...
这个项目结合了硬件设备交互(v4l2)、跨平台GUI开发(Qt)以及云服务集成(百度语音识别),是一个典型的多媒体和网络通信结合的实例,对于学习和提升Linux下多媒体应用开发能力具有很高的实践价值。
这里主要采用H.263编码器对视频数据进行压缩,再通过TCP/IP协议栈中的RTP(Real-time Transport Protocol)进行传输。 ##### 1. H.263视频编码 H.263是一种适用于低带宽环境下的视频编码标准,特别适合嵌入式系统中...
总的来说,MD204 V4L编程软件是一款强大的工具,它使用户能够高效地管理和编程文本屏,适应各种应用场景,并且通过Linux的V4L接口实现了与硬件的无缝连接。无论是在工业环境还是其他领域,这款软件都能显著提高文本...
2. **视频捕捉库**:如`v4l2`(Video for Linux Two)接口,它是Linux系统下处理视频输入输出的主要API,允许应用程序访问摄像头和其他视频设备。 3. **流媒体服务器**:如`Motion`或`Gstreamer`,它们可以捕获、...