加入收藏 | 设为首页 | 会员中心 | 我要投稿 源码网 (https://www.900php.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

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

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

首先获取该IP分片偏移位置offset,和IP分片偏移结束 位置end,其中skb->len – ihl表示IP分片的报文长度,三者间关系即为end = offset + skb->len – ihl。

offset = ntohs(ip_hdr(skb)->frag_off);     
flags = offset & ~IP_OFFSET;     
offset &= IP_OFFSET;     
offset <<= 3;  /* offset is in 8-byte chunks */ 
ihl = ip_hdrlen(skb);     
/* Determine the position of this fragment. */ 
end = offset + skb->len - ihl;

如果该IP分片是最后一片(MF=0,offset!=0),即设置q.last_iin |= INET_FRAG_LAST_IN,表示收到了最后一个分片,qp->q.len = end,此时q.len是整个IP报文的总长度。

if 

((flags & IP_MF) == 0) {     
 if (end < qp->q.len ||     
     ((qp->q.last_in & INET_FRAG_LAST_IN) && end != qp->q.len))     
  goto err;     
 qp->q.last_in |= INET_FRAG_LAST_IN;     
 qp->q.len = end;     
}

如果该IP分片不是最后一片(MF=1),当end不是8字节倍数时,通过end &= ~7处理为8字节整数倍(但此时会忽略 掉多出的字节,如end=14 => end=8);然后如果该分片更靠后,则q.len = end。

else {     
 if (end&7) {     
  end &= ~7;     
  if (skb->ip_summed != CHECKSUM_UNNECESSARY)     
   skb->ip_summed = CHECKSUM_NONE;     
 }     
 if (end > qp->q.len) {     
  /* Some bits beyond end -> corruption. */ 
  if (qp->q.last_in & INET_FRAG_LAST_IN)     
   goto err;     
  qp->q.len = end;     
 }     
}

查找q.fragments链表,找到该IP分片要插入的位置,这里的q.fragments就是struct sk_buff类型,即各个IP分片 skb都会插入到该链表中,插入的位置按偏移顺序由小到大排列,prev表示插入的前一个IP分片,next表示插入的后一个IP分片 。

prev = NULL;     
for (next = qp->q.fragments; next != NULL; next = next->next) {     
 if (FRAG_CB(next)->offset >= offset)     
  break; /* bingo! */ 
 prev = next;     
}

然后将skb插入到链表中,要注意fragments为空和不为空的情形,在下图中给出。

skb->next = next;  

   
if (prev)     
 prev->next = skb;     
else 
 qp->q.fragments = skb;

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

增加q.meat计数,表示已收到的IP分片的总长度;如果offset为0,则表明是第一个IP分片,设置 q.last_in |= INET_FRAG_FIRST_IN。

qp->q.meat += skb->len;     
if (offset == 0)     
 qp->q.last_in |= INET_FRAG_FIRST_IN;

(编辑:源码网)

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

热点阅读