加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核分析 - 网络[八]:IP协议

发布时间:2016-10-16 06:06:01 所属栏目:Linux 来源:站长网
导读:副标题#e# 内核版本:2.6.34 这篇是关于IP层协议接收报文时的处理,重点说明了路由表的查找,以及IP分片重组。 ip_rcv 进入IP层报文接收函数 丢弃掉不是发往本机的报文,skb-pkt_type在网卡接收报文处理以太网头时会根据dst mac设置, 协议栈的书会讲不是发

ip_frag_reasm函数实现IP分片的重组

ip_frag_reasm传入的参数是prev,而重组完成后ip_defrag会将skb替换成重 组后的新的skb,而在之前的操作中,skb插入了qp->q.fragments中,并且prev->next即为skb,因此第一步就是让skb变 成qp->q.fragments,即IP分片的头部。

if (prev) {
 head = prev->next;
 fp = skb_clone(head, GFP_ATOMIC);
 if (!fp)
  goto out_nomem;
 fp->next = head->next;
 prev->next = fp;

 skb_morph(head, qp->q.fragments);
 head->next = qp->q.fragments->next;
 kfree_skb(qp->q.fragments);
 qp->q.fragments = head;
}

下面图示说明了上面代码段作用,skb是IP分片3,通过skb_clone拷贝一份3_copy替代之前的分片3,再通过 skb_morph拷贝q.fragments到原始IP分片3,替代分片1,并释放分片1:

Linux内核分析 - 网络[八]:IP协议

获取IP报头长度 ihlen,head就是ip_defrag传入参数中的skb,并且它已经成为了IP分片队列的头部;len为整个IP报头+报文的总长度,qp- >q.len是未分片前IP报文的长度。

ihlen = ip_hdrlen(head);     
len = ihlen + qp->q.len;

此时head就是skb,并且它的skb->data存储了第一个IP分片的内容,其它IP分片的 内容将存储在紧接skb的空间 – frag_list;skb_push将skb->data回归原位,即未处理IP报头前的位置,因为之前的IP分片 处理会调用skb_pull移走IP报头,将它回归原位是因为skb即将作为重组后的报文而被处理,那里会真正的skb_pull移走IP报头 ,再交由上层协议处理。

skb_shinfo(head)->frag_list = head->next;     
skb_push(head, head->data - skb_network_header(head));

上面所说的frag_list是struct skb_shared_info的 一个属性,在分配skb时分配在其后空间,通过skb_shinfo(skb)进行引用。下面分配skb大小size和skb_shared_info大小的代码 摘自[net/core/skbuff.c]

size = SKB_DATA_ALIGN(size);     
data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),     
  gfp_mask, node);

这里要弄清楚sk_buff中线性存储区和paged buffer的区别,线性存储区就是存储报文,如果是分 片后的,则只是第一个分片的内容;而paged buffer则存储其余分片的内容。而skb->data_len则表示paged buffer中内容长 度,而skb->len则是paged buffer + linear buffer。下面这段代码就是根据余下的分片增加data_len和len计数。

for (fp=head->next; fp; fp = fp->next) {
 head->data_len += fp->len;
 head->len += fp->len;
 ……     
}

IP分片已经重组完成,分片从q.fragments链表移到了frag_list上,因此head->next和qp->q.fragments置为 NULL。偏移量frag_off置0,总长度tot_len置为所有分片的长度和,这样,skb就相当于没有分片的完整的大数据包,继续向上 传递。

head->next = NULL;     
head->dev = dev;     
……
iph = ip_hdr(head);     
iph->frag_off = 0;     
iph->tot_len = htons(len);     
IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);     
qp->q.fragments = NULL;

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读