+ -
当前位置:首页 → 问答吧 → netfilter中early_drop()函数中的疑问(待解决)

netfilter中early_drop()函数中的疑问(待解决)

时间:2010-09-17

来源:互联网

在netfilter的连接跟踪模块中,初始化一个新链接时需要调用nf_conntrack_alloc()函数,在这个函数中需要判断连接数是否超过连接数的最大值(atomic_read(&net->ct.count) > nf_conntrack_max),之后调用early_drop()函数。小弟现在对early_drop()函数存在些疑问,请大家指点帮忙!
  1. 498 static noinline int early_drop(struct net *net, unsigned int hash)
  2. 499 {
  3.                         ...
  4. 507     rcu_read_lock();
  5. 508     for (i = 0; i < net->ct.htable_size; i++) {
  6. 509         hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash],
  7. 510                      hnnode) {
  8. 511             tmp = nf_ct_tuplehash_to_ctrack(h);//为什么要这么做?
  9. 512             if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
  10. 513                 ct = tmp;
  11. 514             cnt++;
  12. 515         }
  13. 516
  14. 517         if (ct != NULL) {
  15. 518             if (likely(!nf_ct_is_dying(ct) &&
  16. 519                    atomic_inc_not_zero(&ct->ct_general.use)))
  17. 520                 break;
  18. 521             else
  19. 522                 ct = NULL;
  20. 523         }
  21. 524
  22. 525         if (cnt >= NF_CT_EVICTION_RANGE)
  23. 526             break;
  24. 527
  25. 528         hash = (hash + 1) % net->ct.htable_size;
  26. 529     }
  27. 530     rcu_read_unlock();
  28. 531
  29. 532     if (!ct)
  30. 533         return dropped;
  31. 534
  32. 535     if (del_timer(&ct->timeout)) {
  33. 536         death_by_timeout((unsigned long)ct);
  34. 537         dropped = 1;
  35. 538         NF_CT_STAT_INC_ATOMIC(net, early_drop);
  36. 539     }
  37. 540     nf_ct_put(ct);//ct上的计数减1
  38. 541     return dropped;
  39. 542 }
复制代码
在这个函数中的问题是:

hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash],
510                      hnnode) {
511             tmp = nf_ct_tuplehash_to_ctrack(h);
512             if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
513                 ct = tmp;                 //当test_bit()多次满足时,ct都会发生变化,为什么要这么做? 还有就是cnt只在初始时被初始化为0,之后一直是cnt++,这样累加到8之后就跳出循环,其作用?
514             cnt++;
515         }            

if (cnt >= NF_CT_EVICTION_RANGE)  //cnt++,这样累加到8之后就跳出循环,不明白其含义
            break;

作者: __dreamcatcher   发布时间: 2010-09-17

本帖最后由 独孤九贱 于 2010-09-17 10:09 编辑
  1.         rcu_read_lock();
  2.         for (i = 0; i < nf_conntrack_htable_size; i++) {
  3.                 hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash],
  4.                                          hnnode) {
  5.                         tmp = nf_ct_tuplehash_to_ctrack(h);
  6.                         if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
  7.                                 ct = tmp;
  8.                         cnt++;
  9.                 }

  10.                 if (ct && unlikely(nf_ct_is_dying(ct) ||
  11.                                    !atomic_inc_not_zero(&ct->ct_general.use)))
  12.                         ct = NULL;
  13.                 if (ct || cnt >= NF_CT_EVICTION_RANGE)
  14.                         break;
  15.                 hash = (hash + 1) % nf_conntrack_htable_size;
  16.         }
  17.         rcu_read_unlock();
复制代码
这段代码的核心功能是,当会话表满了过会,清除一些半连接,为新的会话腾出空间来。它的思路很简单,就是遍历当前hash槽位的链,找到一个半连接。
这段代码由一个双重循环组成,第一重循环:
hlist_nulls_for_each_entry_rcu()遍历指定hash的槽位。当它结束时,有两种结果:
a、通过test_bit,已经找到了,此时ct就是要找的值;
b、没有找到,ct为NULL,cnt是一个计数器,累计在“当前hash槽位的查找次数”;

如果找到到后,即会判断ct的合法性:
  1.                 if (ct && unlikely(nf_ct_is_dying(ct) ||
  2.                                    !atomic_inc_not_zero(&ct->ct_general.use)))
  3.                         ct = NULL;
复制代码
结果合法,或者当cnt大于一个常数(NF_CT_EVICTION_RANGE),则退出外层循环。
  1.                 if (ct || cnt >= NF_CT_EVICTION_RANGE)
  2.                         break;
复制代码
ct找到了退出循环是理所当然的事情。至于cnt超限,也要退出循环,这是和下一句代码紧密相连的:
  1. hash = (hash + 1) % nf_conntrack_htable_size;
复制代码
也就是说,如果没有查找,或者cnt没有超限,hash值会往复递增,注意,是“往复”,往复的含义是:
  1. hash = (hash + 1) % nf_conntrack_htable_size
复制代码
而不是
  1. hash = hash + 1;
  2. if(hash > XXX)  break;
复制代码
。也就是说,周而复始的在下一个hash链中再找空位……这样一来,引入cnt的理由就显而意见了:必须得有一个变量来决定,如果ct一直找不到,得有一种决定退出外层循环的条件,cnt就是这个条件。所以,它只有初值会0,后面就一直递加了。作者认为,当查找的次数超过NF_CT_EVICTION_RANGE次,就必须得退出来了,不能一直占着CPU不放。你也可以自定义这个常数,4,16,32(当然,从效率的角度来讲,它不能太大了)……可以多做一些实现来得到一个经验值。我个人倒是认为8是一个比较好的值。

再退一步讲,个人认为,即使hash值不是一个“周而复始的值”,也应该有也一变量来决定查找的次数,不能长时间地占着hash表来查找……

作者: 独孤九贱   发布时间: 2010-09-17

你内核版本是多少?我的内核没有cnt累加。

作者: Godbach:   发布时间: 2010-09-17

热门下载

更多