加入收藏 | 设为首页 | 会员中心 | 我要投稿 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_local_deliver_finish()中会完成IP协议层处理,再交由上层协议模块处理:ICMP、 IGMP、UDP、TCP。在ip_local_deliver_finish函数中,由于IP报头已经处理完,剔除IP报头,并设置skb- >transport_header指向传输层协议报头位置。

__skb_pull(skb, ip_hdrlen(skb));     
skb_reset_transport_header(skb);

protocol是IP报头中的的上层协议号,以它在inet_protos哈希表中查找处理 protocol的协议模块,取出得到ipprot。

hash = protocol & (MAX_INET_PROTOS - 1);     
ipprot = rcu_dereference(inet_protos[hash]);

而关于inet_protos,它的数据结构是哈希表,用来存储IP层上的协 议,包括传输层协议和3.5层协议,它在IP协议模块加载时被添加。

if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
  printk(KERN_CRIT "inet_init: Cannot add ICMP protocoln");
 if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
  printk(KERN_CRIT "inet_init: Cannot add UDP protocoln");
 if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)
  printk(KERN_CRIT "inet_init: Cannot add TCP protocoln");
#ifdef CONFIG_IP_MULTICAST
 if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)
  printk(KERN_CRIT "inet_init: Cannot add IGMP protocoln");
#endif

然后通过调用handler交由上层协议处理,至此,IP层协议处理完成。

ret = ipprot->handler(skb);

IP分 片

在收到IP分片时,会暂时存储到一个哈希表ip4_frags中,它在IP协议模块加载时初始化,inet_init() -> ipfrag_init()。要留意的是ip4_frag_match用于匹配IP分片是否属于同一个报文;ip_expire用于在IP分片超时时进行处理。

[cpp] view plaincopy   
       
    void __init ipfrag_init(void)     
    {     
     ip4_frags_ctl_register();     
     register_pernet_subsys(&ip4_frags_ops);     
     ip4_frags.hashfn = ip4_hashfn;     
     ip4_frags.constructor = ip4_frag_init;     
     ip4_frags.destructor = ip4_frag_free;     
     ip4_frags.skb_free = NULL;     
     ip4_frags.qsize = sizeof(struct ipq);     
     ip4_frags.match = ip4_frag_match;     
     ip4_frags.frag_expire = ip_expire;     
     ip4_frags.secret_interval = 10 * 60 * HZ;     
     inet_frags_init(&ip4_frags);     
    }

当收到一个IP分片,首先用ip_find()查找IP分片,实际上就是从ip4_frag表中取出相应项。这里的哈希值是由 IP报头的(标识,源IP,目的IP,协议号)得到的。

hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, 

iph->protocol);     
q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash);

net_frag_find实现直正的查找

根据hash值取得ip4_frag->hash[hash]项 – inet_frag_queue,它是一个队列,然后遍历该队列,当net, id, saddr, daddr, protocol, user相匹配时,就是要找的IP分片。如果没有匹配的,则调用inet_frag_create创建它。

struct 

inet_frag_queue *inet_frag_find(struct netns_frags *nf,     
  struct inet_frags *f, void *key, unsigned int hash)     
 __releases(&f->lock)     
{     
 struct inet_frag_queue *q;     
 struct hlist_node *n;     
         
 hlist_for_each_entry(q, n, &f->hash[hash], list) {     
  if (q->net == nf && f->match(q, key)) {     
   atomic_inc(&q->refcnt);     
   read_unlock(&f->lock);     
   return q;     
  }     
 }     
 read_unlock(&f->lock);     
         
 return inet_frag_create(nf, f, key);     
}

inet_frag_create创建一个IP分片队列ipq,并插入相应队列中。

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

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

热点阅读