本章介绍IP分组的结构和基本的IP处理过程,包括输入,转发和输出。下图显示了IP层常见的组织形式。
在之前的文章中,我们看到了网络接口如何把到达的IP分组放到IP输入队列ipintrq中去,并如何调用一个软件中断,如下图所示:
因为硬件中断的优先级比软件中断的要高,所以在发生一次软件中断之前,有的分组可能会被放到队列中。在软件中断中,ipintr
函数不断从ipintrq中移走和处理分组,直到对垒为空。在最终的目的地,IP把分组重装为数据包,并通过函数调用把该数据包直接
传给适当的运输层协议。如果分组没有到达最后的目的地,并且如果主机被配置成一个路由器,则IP把分组传给ip_forward。传输
协议和ip_forward把要输出的分组传给ip_output,由ip_output完成ip首部,选择输出接口以及在必要时对分组分片。最终的分组
被传给合适的网络接口输出函数。
当产生差错时,IP丢弃该分组,并在某些条件下向分组的源站发出一个差错报文,这些报文是ICMP的一部分。
1.IP分组
我们把传输层协议交给IP的数据称为报文。典型的报文包含一个传输层首部和应用程序数据。下图所示的传输协议时UDP。IP在报
文的首部前加上它自己的首部形成一个数据包。如果在选定的网络中,数据报长度太大,IP就把数据包分裂成几个分片,每个分片
包含它自己的IP首部和一段原来的数据报的数据。
下图显示了IP首部的结构。
下图包含了IP结构中的各成员的名字
标准的IP首部长度是20个字节,所以ip_hl必须大于等于5.大于5表示IP选项紧跟在标准首部后,如ip_hl的最大值为15,允许最多
40各字节的选项。ip_hl是以4字节为单位计算的。
2.输入处理:ipintr函数
当接口把分组放到ipintrq上排队后,通过schednetisr调用一个软中断。当该软中断发生时,如果IP处理过程已经由schednetisr
调度,则内核调用ipintr。在调用ipintr之前,cpu的优先级被改成splnet。
ipintr是一个大函数,主要分4部分讨论:
1.对到达分组验证
2.选项处理及转发
3.分组重装
4.分用
其中选项处理和分用重装比较复杂,会在以后作为单独的章节进行说明。
2.1.验证
2.2.选项处理和转发
接下来调用ip_dooptions来处理IP选项,然后决定分组是否到达它最后的目的地。如果分组没有到达最后目的地,则Net/3会
尝试转发该分组;如果分组到达最后目的地,就被交付给合适的传输层协议。
1.选项处理
ip_dooptions处理选项,如果ip_dooptions返回0,ipintr将继续处理该分组;否则ip_dooptions通过转发或丢弃分组完成对该
分组的处理,ipintr可以处理输入队列中的下一个分组。
处理完选项后,ipintr通过把ip首部内的ip_dst与配置的所有本地接口的ip地址比较,以决定分组是否已经到达最终目的地。ipintr
必须考虑与接口相关的几个广播地址、一个或多个单播地址以及任意多个多播地址。
2.转发
如果ip_dst与所有地址都不匹配,分组还没有达到最终目的地。如果不准备转发,则丢弃分组,否则,ip_forward尝试把分组路由
到它的最终目的地。
2.3.分组重装和分用
ipintr函数最后进行分组的重组和分组,在后面的章节会详细进行介绍。
最后ipintr调用选定protosw结构中的pr_input函数来处理数据报包含的运输报文,当pr_input返回时,ipintr继续处理ipintrq中的
下一个分组。
3.IP头部检验:in_cksum函数
- SHORT checksum(USHORT* buffer, int size)
- {
- unsigned long cksum = 0;
- while(size>1)
- {
- cksum += *buffer++;
- size -= sizeof(USHORT);
- }
- if(size)
- {
- cksum += *(UCHAR*)buffer;
- }
- cksum = (cksum>>16) + (cksum&0xffff);
- cksum += (cksum>>16);
- return (USHORT)(~cksum);
- }
SHORT checksum(USHORT* buffer, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum>>16) + (cksum&0xffff);
cksum += (cksum>>16);
return (USHORT)(~cksum);
}