您正在查看 "ip协议" 分类下的文章
2006年12月12日 星期二 下午 06:45
IP选项中目前还比较有用的就是源站选路选项(IPOPT_SSRR和IPOPT_LSRR),和记录路由选项(IPOPT_RR),ping程序的-R命令选项可以启用IPOPT_RR选项,以提供记录路由的功能。通过-R发送出去的回显请求包带有IPOPT_RR选项,共40字节,除去code, len, ptr三字节,另外发送数据报的源端也把自己的出口IP地址填入选项的IP清单中,这样,还有8个IP地址的空间可用,所以,用ping程序来确定数据报的路由,其功能是非常有限的。
当网络中的一台主机收到带有RR选项的回显请求包后,其网络层的接收函数ip_rcv |
2006年12月12日 星期二 上午 07:44
构建完成的IP选项(通过setsockopt系统调用,使用IP_OPTIONS命令),存放在套接字结构体struct inet_sock的成员opt中,在随后的数据报发送过程中,会根据opt的指示把相关的IP选项加到IP首部中,下面以一个原始套接字上的数据报发送为例,详细分析整个过程。
raw_sendmsg定义了一个局部变量struct ipcm_cookie ipc,其定义如下:
struct ipcm_cookie
{
u32 |
2006年12月11日 星期一 下午 10:27
IP首部中有4bit用于表示首部长度,其单位是4个字节,所以,IP首部的最大长度是15*4=60字节,而IP固定首部的长度是20字节,所以一个IP首部最大允许有40字节长度的选项。
IP选项的一般格式是1个字节的代码(code),一个字节的长度(len),一个字节的指针(ptr),指针的值从1开始计数,指向IP选项的内容,一般其值为4(跳过前面3字节的code, len, ptr),长度包括前面3字节在内的整个IP选项,最大值为40。
代码表示不同类型的IP选项,其可能的取值有:
|
2006年11月29日 星期三 下午 10:02
前面有讲到过在函数ip_append_data中实现了对IP数据报的分片,这个讲法是错误的,需要纠正一下,ip_append_data的主要任务只是创建发送网络数据的套接字缓冲区(skb),它根据输出路由查询得到的输出网络设备接口的MTU,把超过MTU长度的应用数据分割开,并创建了多个skb,放入套接字的发送缓冲队列(sk_write_queue),但它并没有为任何一个skb数据加上网络层首部,并且,随后在ip_push_pending_frames函数中,又把发送缓冲队列中的所有的skb,以一个链表的形式追加到第一个skb的end成员后面的struct skb_shared_info结构体中的frag_list上,并只为第一个skb加上了网络层首部,所以,实际上,整个应用数据还只是在一个skb中,ip_append_data这样做只是为接下来的真正的IP数据的分片作好准备。
ip_push_pending_frames在完成了skb的组装后,把它交给了函数ip_output,ip_output又调用了函数ip_finish_output,该函数对skb的长度再次进行判断,如果长度超过输出设备的mtu的值,并且符合其它分片条件,则调用ip_fragment进行数据报的分片,否则直接调用ip_finish_output2输出到数据链路层。
IP数据的分片涉及 |
2006年11月23日 星期四 下午 11:29
还是在测试环境中,环回设备mylo的mtu被设置为16*1024+20+20+12,20+20+12是为传输层及网络层首部及它们可能出现的选项预留的,16K是真正的应用数据,所以,一般的环回接口的mtu被设置为16K+52字节。为了测试应用数据在网络层被依据设备的mtu进行分片,下面把mylo的mtu设置为6+20+20+12,总共为58字节。因为环回接口的mtu不受以太网mtu的68至1500的范围的限制,同时,可以确保DUMMY协议不会出现传输层首部和网络层首部的选项,我们可以这么设。
具体的,IP数据报的分片是在做完输出路由的查询后,在ip_append_data函数中完成,因为在完成输出路由的查询前,不知道本次输出的输出设备接口是哪个,自然也不知道mtu是多大。现在,测试程序dummytest发送676字节长度的应用数据,由于DUMMY协议的传输层首部长度为5字节(只在第一个分片里面出现),网络层首部长度为20字节,同时,58字节的mtu被对齐为52字节( (58-20) & ~7 + 20 ),所以,676字节的数据要被分成 (676+5)/(52-20) = 22个IP数据报分片。
22个数据报分片中,第一个分片是比较特殊的,因为它是唯一一个包含有传输层首部的分片,该分片的skb用 |
2006年11月22日 星期三 下午 12:18
DUMMY协议是一个虚构的传输层协议,在以前的构建过程中,为了简便起见,DUMMY协议也是不具备网络层首部的。接下来,打算让DUMMY协议在网络层支持IP协议,拥有一个IP首部。这步工作完成后,一个完整的DUMMY数据报看上去应该是这个样子的:
14字节以太网部首部+20字节IP首部+5字节DUMMY首部+数据内容
因为DUMMY协议是确定没有IP选项的,所以IP首部可以确定为20字节。前面已经完成了输出路由的查询,邻居的绑定,使得DUMMY协议完全可以加上以太网首部了。接下来,在得到了输出路由,绑定了邻居后,需要先为DUMMY数据报加上一个IP首部。在dummy_sendmsg函数中,完成输出路由查询后,先调用ip_append_data构建输出用的套接字缓存(struct sk_buff)。
ip_append_data所做的工作还包括对大于目的入口指定的mtu(dst->metrics[RTAX_MTU-1])的数据进行分片(只针对udp协议,和虚拟的dummy协议),但现在只考虑最简单的情况:无数据分片。同时,下面的分析也忽略IP选项的存在。
struct inet_sock是inet域对网络层套接字struct sock的一个扩充,其完整的定义如 |
2006年08月11日 星期五 下午 02:46
我们还是以我们的ping程序为例,当它通过我们的my_inet模块发出一个回显请求的icmp包后,会收到对端的回显应答icmp包。这个应答包被网卡接收到后,是如何通过协议栈的层层处理,最后达到应用程序的?我们现在就来看这个问题。 我们先从应用程序开始,自上而下来看IP数据包的接收流程。ping程序通过系统调用接口 ssize_t recvfrom( int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); 来接收数据包。参数s即为socket的描述符,buf是接收缓冲区,len是其长度,from可以为NULL,如果不为NULL,协议栈会为其填充该数据报的对端地址,fromlen是from的长度。 该系统调用直接调用内核函数sys_recvfrom,最终会调用到RAW协议的接收函数myraw_recvmsg。在myraw_recvmsg函数中,首先会对传入的flag作一些检查,这些我们暂时不关注。然后调用skb_recv_datagram函数接收IP数据报。 &nbs |
|
|