您的位置:首页 > 理论基础 > 计算机网络

《深入理解Linux网络技术内幕》阅读笔记(十八)

2015-10-08 16:53 369 查看






中央传递封包的函数是dst_output;本章所探讨的函数都是在此函数之前执行的,也就是替该函数把封包准备好。在此阶段,内核的任务包括:

1.查询下一个跳点。IP层必须知道外出设备以及用作下一个跳点的下一个路由器。

2.初始化IP报头。几个字段会在此阶段填入(诸如封包ID)。

3.处理选项。软件必须尊重需要把一个地址或时间戳加进报头里的那些选项。

4.分段。如果IP封包太大,无法在外出设备上传输,就必须分段。除非分段被显式禁止。

5.校验和。所有对报头的其他工作都做完后,还必须计算IP校验和。

6.由Netfilter检查。Linux防火墙系统有机会在处理的各个阶段(包括传输)把每个封包丢弃或调整。

7.更新统计数据。取决于传输结果,以及一些诸如分段的行动而定,相关的SNMP定时器可能必须被更新。



TCP和SCTP做了很多工作来准备分段,而使得IP层的工作变少了。相反的,列在左边的Raw IP和其他协议则把所有分段工作都留给了IP层。

只要传输是由本地产生(极少数例外),每个sk_buff缓冲区都会和其sock实例相关联,而且以skb->sk链接起来。



















frags向量里的数据是主缓冲区中数据的扩展,而frags_list里的数据代表的是独立缓冲区,也就是每个缓冲区都必须作为单独的IP片段而独立传输(frags用于分散/聚集I/O,frag_list用于数据分段)。

skb_is_nonlinear:当缓冲区被分段时,就返回true,即skb->data_len不为NULL。skb->data_len用途可参见下图:





每当ip_append_data分配一个新sk_buff结构来处理一个新数据片段时,就会把该片段排入一个名为sw_write_queue队列(和套接字sk相关)。此队列就是此函数的输出。稍后,那些函数只需把IP报头加入数据片段,然后把数据片段往下退至L2层(精确地讲,就是给dst_output函数)。注:该队列是FIFO队列。

exthdrlen(外部报头len):

transhdrlen(传输报头len):

外部报头的范例是那些由IPsec套件里的协议所使用的报头,例如鉴定报头AH以及封装安全有效载荷报头ESP。传输报头的范例就是那些常见的TCP,UDP以及ICMP协议的报头。

只有第一个片段必须包含传输报头和选用的外部报头。因此,建立第一个片段之后,transhdrlen和exthdrlen都会变为0。因此,transhdrlen !=0 表示ip_append_data工作在第一个片段。而transhdrlen =0 表示ip_append_data未工作在第一个片段。但是此种逻辑不适用于exthdrlen,因为每个IP封包都需要L4报头,但是很多都没有外部报头,因为没用到诸如IPsec的特殊功能。

IP封包的最大尺寸(报头加有效载荷)是64KB。这一点不仅适用于个别片段,也适用于整个封包。因此有如下安全性检查:

823         if (cork->length + length > 0xFFFF - fragheaderlen) {
824                 ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport,
825                                mtu-exthdrlen);
826                 return -EMSGSIZE;
827         }






IP报头的TTL字段(iph->ttl)的设定取决于目的地址是否为多播。通常,多播流量所用的值较小,因为多播最常用于传递流数据,例如音频和视频(如果接收的太晚,就没用了)。就单播和多播封包而言,指派给TTL字段的默认值分别为1和64.



上图中的所谓删除,只是把第一个缓冲区后面的所有缓冲区放入第一个缓冲区的frag_list链表,方便后续处理。

raw套接字(使用raw IP 的套接字)把IP报头包含在传给IP层的数据内,是有可能的。也就是说,可以要求IP层传递一段数据,而该数据内包含一个已初始化的IP报头。为此,raw IP使用IP_HDRINCL(包含报头)选项。



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: