Chinaunix首页 | 论坛 | 博客
  • 博客访问: 818870
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2014-02-12 16:08:29

转:http://blog.csdn.net/nerdx/article/details/12911337
  1. //  入口路由缓冲查找  
  2. //  返回值:  
  3. //      0,路由查找成功  
  4. //      -ENOBUFF,内存问题导致查找失败  
  5. //      -EINVAL,常规查找失败  
  6. //  hash值计算:  
  7. //      目的地址,源地址,入口设备index,tos进行hash  
  8. //  函数主要任务:  
  9. //      1.根据hash值遍历bucket  
  10. //      2.比较5元组  
  11. //      3.如果缓存命中,更新引用计数,绑定到skb->dst  
  12. //      4.否则,如果为本地多播地址,或者内核支持多播路由,多播路由中查找  
  13. //      5.否则,在路由表中查找  
  14.   
  15. //  注:缓存确定5元组 = <目的地址,源地址,入口索引,出口索引=0,tos>  
  16. 1.1 int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,  
  17.            u8 tos, struct net_device *dev)  
  18. {  
  19.     struct rtable * rth;  
  20.     unsigned    hash;  
  21.     int iif = dev->ifindex;  
  22.   
  23.     tos &= IPTOS_RT_MASK;  
  24.     hash = rt_hash_code(daddr, saddr ^ (iif << 5), tos);  
  25.   
  26.     rcu_read_lock();  
  27.     for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;  
  28.          rth = rcu_dereference(rth->u.rt_next)) {  
  29.         if (rth->fl.fl4_dst == daddr &&  
  30.             rth->fl.fl4_src == saddr &&  
  31.             rth->fl.iif == iif &&  
  32.             //ofi=0,表示此路由为入口路由  
  33.             rth->fl.oif == 0 &&  
  34.             rth->fl.fl4_tos == tos) {  
  35.             rth->u.dst.lastuse = jiffies;  
  36.             dst_hold(&rth->u.dst);  
  37.             //引用计数  
  38.             rth->u.dst.__use++;  
  39.             //缓存命中次数  
  40.             RT_CACHE_STAT_INC(in_hit);  
  41.             rcu_read_unlock();  
  42.             //将路由缓存绑定到skb  
  43.             skb->dst = (struct dst_entry*)rth;  
  44.             return 0;  
  45.         }  
  46.         RT_CACHE_STAT_INC(in_hlist_search);  
  47.     }  
  48.     rcu_read_unlock();  
  49.     //目的地址为多播地址  
  50.     if (MULTICAST(daddr)) {  
  51.         struct in_device *in_dev;  
  52.         rcu_read_lock();  
  53.         //设备的ipv4配置信息  
  54.         if ((in_dev = __in_dev_get(dev)) != NULL) {  
  55.             int our = ip_check_mc(in_dev, daddr, saddr,  
  56.                 skb->nh.iph->protocol);  
  57.             //本地配置的多播地址,或者内核支持多播路由  
  58.             if (our|| (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev)))   
  59.             {  
  60.                 rcu_read_unlock();  
  61.                 //多播路由  
  62.                 return ip_route_input_mc(skb, daddr, saddr,  
  63.                              tos, dev, our);  
  64.             }  
  65.         }  
  66.         rcu_read_unlock();  
  67.         return -EINVAL;  
  68.     }  
  69.     //在路由表中查找  
  70.     return ip_route_input_slow(skb, daddr, saddr, tos, dev);  
  71. }  
  72.   
  73. //  判断是否接收此ip多播  
  74. //      接收条件:  
  75. //          1.组播协议报文,接收  
  76. //          2.设备已加入此多播组  
  77. //              2.1 指定了源地址  
  78. //                  2.1.1 源地址在多播组的源地址链表  
  79. //                      2.1.1.1 源地址的包含计数!=0,或者源地址的排除计数!=多播组的排除计数,接收  
  80. //                  2.1.2 源地址不在多播组的源地址链表  
  81. //                      2.1.2.1 多播组的排斥计数!=0,接收  
  82. //              2.2 无源地址,默认接收  
  83. 2.1 int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)  
  84. {  
  85.     struct ip_mc_list *im;  
  86.     struct ip_sf_list *psf;  
  87.     int rv = 0;  
  88.   
  89.     read_lock(&in_dev->mc_list_lock);  
  90.     //设备的多播链表in_device->mc_list  
  91.     for (im=in_dev->mc_list; im; im=im->next) {  
  92.         if (im->multiaddr == mc_addr)  
  93.             break;  
  94.     }  
  95.     //组播协议,本地接收  
  96.     if (im && proto == IPPROTO_IGMP) {  
  97.         rv = 1;  
  98.     } else if (im) {  
  99.         //判断源地址是否在多播组中的源地址列表  
  100.         if (src_addr) {  
  101.             for (psf=im->sources; psf; psf=psf->sf_next) {  
  102.                 if (psf->sf_inaddr == src_addr)  
  103.                     break;  
  104.             }  
  105.             //源地址在多播组源地址链表中  
  106.             if (psf)  
  107.             {  
  108.                 //源地址接收计数>0,或者源地址排斥计数!=多播组排斥计数  
  109.                 rv = psf->sf_count[MCAST_INCLUDE] ||  
  110.                     psf->sf_count[MCAST_EXCLUDE] !=  
  111.                     im->sfcount[MCAST_EXCLUDE];  
  112.             }  
  113.             else  
  114.             {  
  115.                 //源地址不在多播组链表中,排斥计数!=0  
  116.                 rv = im->sfcount[MCAST_EXCLUDE] != 0;  
  117.             }  
  118.         //没有指定源地址,默认接收  
  119.         } else  
  120.             rv = 1;   
  121.     }  
  122.     read_unlock(&in_dev->mc_list_lock);  
  123.     return rv;  
  124. }  
  125. //  路由入口多播地址  
  126. //      1.分配路由缓存  
  127. //      2.初始化路由缓存的ipv4搜索关键字  
  128. //      3.初始化路由缓存选项  
  129. //      4.初始化路由缓存输入,输出函数  
  130. //      5.插入到路由缓存hash表中  
  131.   
  132. //  注:入口路由的出口设备索引=0,出口设备=回环设备  
  133. 3.1 static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,  
  134.                 u8 tos, struct net_device *dev, int our)  
  135. {  
  136.     unsigned hash;  
  137.     struct rtable *rth;  
  138.     u32 spec_dst;  
  139.     struct in_device *in_dev = in_dev_get(dev);  
  140.     u32 itag = 0;  
  141.   
  142.     //分配路由缓存  
  143.     rth = dst_alloc(&ipv4_dst_ops);  
  144.   
  145.     rth->u.dst.output = ip_rt_bug;//多播入口路由的输出函数  
  146.     atomic_set(&rth->u.dst.__refcnt, 1);//引用计数=1  
  147.     rth->u.dst.flags= DST_HOST;//DST_HOST,tcp使用标志,表示主机路由(即它不是到网络或到一个广播/多播地址的路由)  
  148.     if (in_dev->cnf.no_policy)  
  149.         rth->u.dst.flags |= DST_NOPOLICY;//DST_NOXFRM, DST_NOPOLICY, DST_NOHASH只用于IPsec  
  150.   
  151.     rth->u.dst.dev   = &loopback_dev;//入口路由,使用回环设备作为其出口设备  
  152.     dev_hold(rth->u.dst.dev);//路由缓存关联到设备,增加设备的引用计数  
  153.   
  154.     //路由项的搜索关键字  
  155.     rth->fl.fl4_dst  = daddr;  
  156.     rth->fl.fl4_tos  = tos;  
  157.     rth->fl.fl4_src  = saddr;  
  158.     rth->fl.iif  = dev->ifindex;  
  159.     rth->fl.oif  = 0;//入口路由的出口设备索引=0,表示为入口路由  
  160.   
  161.   
  162.     //目的,源ip地址  
  163.     rth->rt_dst  = daddr;  
  164.     rth->rt_src  = saddr;  
  165.     rth->rt_iif  = dev->ifindex;//入口设备索引  
  166.     rth->rt_gateway  = daddr;//下一跳网关初始化为目的地址  
  167.     rth->rt_spec_dst= spec_dst;//RFC 1122中指定的目的地址  
  168.     rth->rt_type = RTN_MULTICAST;//路由类型,间接定义了当路由查找匹配时应该采取的动作  
  169.     rth->rt_flags    = RTCF_MULTICAST;//表示路由的目的地址为多播地址  
  170.     rth->idev    = in_dev_get(rth->u.dst.dev);//使用入口设备的ipv4配置信息作为路由缓存的ipv4配置信息  
  171.   
  172.     //本地配置的多播地址  
  173.     if (our) {  
  174.         rth->u.dst.input= ip_local_deliver;//向本地传递  
  175.         rth->rt_flags |= RTCF_LOCAL;//路由的目的地址为本地地址  
  176.     }  
  177.   
  178. //内核支持多播路由  
  179. #ifdef CONFIG_IP_MROUTE  
  180.     //目标地址非组播地址  
  181.     //入口设备支持多播路由  
  182.     if (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))  
  183.         rth->u.dst.input = ip_mr_input;  
  184. #endif  
  185.   
  186.     in_dev_put(in_dev);  
  187.     hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);  
  188.     //插入到路由缓存中  
  189.     return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);  
  190.   
  191. }  
阅读(1132) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~