Chinaunix首页 | 论坛 | 博客
  • 博客访问: 795455
  • 博文数量: 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 15:21:17

转:http://blog.csdn.net/nerdx/article/details/12223547
  1. //  转发数据库  
  2. //      1.容量  
  3. //          net_bridge->hash[BR_HASH_SIZE],其中BR_HASH_SIZE为(1<<8),有256个bucket  
  4. //      2.老化机制,  
  5. //          2.1 gc函数,到期时会顺序遍历age_list上的转发项,修改gc函数下一次到期时间为age_list中第一个没有过期的转发项的剩余时间。  
  6. //          2.2 age_list链表,保存除本机l2地址以外的所有转发项,按照到期时间进行排序,新添加或更新的转发项保存在age_list尾部。  
  7.   
  8.   
  9. //  网桥转发数据库初始化  
  10. //  调用路径:br_init->br_fdb_init  
  11. 1.1 void __init br_fdb_init(void)  
  12. {  
  13.     //创建转发项的SLAB cache  
  14.     br_fdb_cache = kmem_cache_create("bridge_fdb_cache",  
  15.                      sizeof(struct net_bridge_fdb_entry),  
  16.                      0,  
  17.                      SLAB_HWCACHE_ALIGN, NULL, NULL);  
  18. }  
  19.   
  20.   
  21. //  查询转发项  
  22. //      __br_fdb_xxx不会递增net_bridge_fdb_entry的引用计数,br_fdb_xxx会递增net_bridge_fdb_entry的引用计数          
  23. //  参数:  
  24. //      addr,目的l2地址  
  25. //  函数主要任务:  
  26. //      hash l2地址到正确的bucket,遍历bucket查找具有相同l2地址的转发项  
  27. 2.1 struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,  
  28.                       const unsigned char *addr)  
  29. {  
  30.     struct hlist_node *h;  
  31.     struct net_bridge_fdb_entry *fdb;  
  32.     //net_bridge->hash为转发数据库的hash表  
  33.     hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) {//遍历对应的bucket的链表  
  34.         if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {//比较转发项的地址与查询的地址  
  35.             if (unlikely(has_expired(br, fdb)))  
  36.                 break;  
  37.             return fdb;//找到返回转发项  
  38.         }  
  39.     }  
  40.   
  41.     return NULL;//否则返回null  
  42. }  
  43.   
  44. //  添加转发项  
  45. //      转发数据库由hash_lock保护  
  46. 2.2 int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,  
  47.           const unsigned char *addr, int is_local)  
  48. {  
  49.     int ret;  
  50.   
  51.     spin_lock_bh(&br->hash_lock);//获取hash表的锁,关下半部中断  
  52.     ret = fdb_insert(br, source, addr, is_local);//  
  53.     spin_unlock_bh(&br->hash_lock);  
  54.     return ret;  
  55. }  
  56. //  调用路径:br_fdb_insert->fdb_insert  
  57. //  函数主要任务:  
  58. //      1.遍历对应的bucket  
  59. //      2.如果对应的转发项已经存在  
  60. //          2.1 转发项为本机地址,添加的地址为本机地址,返回  
  61. //          2.2 转发项非本机,添加的地址为本机,更新已有的转发项  
  62. //          2.3 转发项非本机,添加的地址非本机  
  63. //              2.3.1 如果转发项静态配置,则不更新已有转发项  
  64. //              2.3.2 否则从age_list上删除转发项,更新已有转发项  
  65. //      3.转发项不存在,分配新的转发项,更新转发项,添加到hash表  
  66.   
  67. //  对已有选项的更新:  
  68. //      1.设置转发项是否为本机  
  69. //      2.本机转发项设置为static  
  70. //      3.非本机转发项添加到age_list上      
  71. 2.3 static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,  
  72.           const unsigned char *addr, int is_local)  
  73. {  
  74.     struct hlist_node *h;  
  75.     struct net_bridge_fdb_entry *fdb;  
  76.     int hash = br_mac_hash(addr);  
  77.   
  78.     if (!is_valid_ether_addr(addr))//非全0,非广播或多播地址  
  79.         return -EADDRNOTAVAIL;  
  80.   
  81.     hlist_for_each_entry(fdb, h, &br->hash[hash], hlist) {//遍历对应的bucket  
  82.         if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) {//已存在l2地址对应的转发项  
  83.             if (fdb->is_local) {//转发项为本机地址  
  84.                 if (is_local) //要添加的本机地址已经存在,直接返回  
  85.                     return 0;  
  86.   
  87.                 return -EEXIST;//返回错误  
  88.             }  
  89.   
  90.             if (is_local) {//转发项非本机地址,将此转发项修改为本机地址  
  91.                 printk(KERN_WARNING "%s adding interface with same address "  
  92.                        "as a received packet\n",  
  93.                        source->dev->name);  
  94.                 goto update;  
  95.             }  
  96.   
  97.             if (fdb->is_static)//转发项静态配置  
  98.                 return 0;  
  99.   
  100.             list_del(&fdb->u.age_list);//将fdb从br->age_list链表上删除  
  101.             goto update;  
  102.         }  
  103.     }  
  104.   
  105.     fdb = kmem_cache_alloc(br_fdb_cache, GFP_ATOMIC);//分配新的转发项  
  106.     if (!fdb)  
  107.         return ENOMEM;  
  108.   
  109.     memcpy(fdb->addr.addr, addr, ETH_ALEN);//复制l2地址  
  110.     atomic_set(&fdb->use_count, 1);  
  111.     hlist_add_head_rcu(&fdb->hlist, &br->hash[hash]);//添加到对应的bucket  
  112.   
  113.     if (!timer_pending(&br->gc_timer)) {  
  114.         br->gc_timer.expires = jiffies + hold_time(br);  
  115.         add_timer(&br->gc_timer);//启动垃圾回收定时器  
  116.     }  
  117.   
  118.  update:  
  119.     fdb->dst = source;//到达此l2地址的端口  
  120.     fdb->is_local = is_local;//指示是否为本机地址  
  121.     fdb->is_static = is_local;//本机地址为静态配置地址  
  122.     fdb->ageing_timer = jiffies;//最近一次被使用的时间  
  123.     if (!is_local)   
  124.         list_add_tail(&fdb->u.age_list, &br->age_list);//对于非本机地址的转发项,添加到br->age_list链表,执行垃圾回收机制  
  125.   
  126.     return 0;  
  127. }  
  128.   
  129. //  垃圾回收定时器  
  130. //      除本机地址外的所有转发项,链接在lru链表中,遍历链表,直到最后一个没有过期的转发项。  
  131. //  转发项到期时间:  
  132. //      1.正常情况下,300HZ  
  133. //      2.拓扑发生变化时,short aging机制,过期时间为15HZ  
  134.   
  135. //  函数主要任务:  
  136. //      1.遍历age_list,释放过期的转发项  
  137. //      2.修改gc下一次到期时间为最近到期的邻居项的到期时间。  
  138. 2.5 void br_fdb_cleanup(unsigned long _data)  
  139. {  
  140.     struct net_bridge *br = (struct net_bridge *)_data;  
  141.     struct list_head *l, *n;  
  142.     unsigned long delay;  
  143.     //在获取转发数据库的锁之后进行清理操作  
  144.     spin_lock_bh(&br->hash_lock);  
  145.     //1.当拓扑发生改变时,启动short aging机制,过期时间为15HZ,转发数据库中的项很快过期  
  146.     //2.在正常情况下,过期时间为300HZ  
  147.     delay = hold_time(br);  
  148.   
  149.     list_for_each_safe(l, n, &br->age_list) {//安全方式遍历age_list  
  150.         struct net_bridge_fdb_entry *f;  
  151.         unsigned long expires;  
  152.   
  153.         f = list_entry(l, struct net_bridge_fdb_entry, u.age_list);  
  154.         expires = f->ageing_timer + delay;//转发项的到期时间  
  155.   
  156.         if (time_before_eq(expires, jiffies)) {//如果转发项到期  
  157.             WARN_ON(f->is_static);  
  158.             pr_debug("expire age %lu jiffies %lu\n",  
  159.                  f->ageing_timer, jiffies);  
  160.             fdb_delete(f);  
  161.         } else {  
  162.             mod_timer(&br->gc_timer, expires);//第一个没有过期的转发项,之后的所有转发项都不会过期,则调整gc_timer的下一次运行时间,返回  
  163.             break;  
  164.         }  
  165.     }  
  166.     spin_unlock_bh(&br->hash_lock);  
  167. }  
  168.   
  169. //  调用路径br_fdb_cleanup->fdb_delete  
  170. 2.6 static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f)  
  171. {  
  172.     hlist_del_rcu(&f->hlist);//从hash表上删除此转发项  
  173.     if (!f->is_static)//is_static=1,说明为本机地址,本机地址不会出现在age_list上  
  174.         list_del(&f->u.age_list);//从age_list上删除此转发项  
  175.   
  176.     br_fdb_put(f);//递减引用计数,为0时,直接释放  
  177. }  
阅读(532) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~