dst.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * net/dst.c Protocol independent destination cache.
  3.  *
  4.  * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  5.  *
  6.  */
  7. #include <linux/bitops.h>
  8. #include <linux/types.h>
  9. #include <linux/kernel.h>
  10. #include <linux/sched.h>
  11. #include <linux/mm.h>
  12. #include <linux/string.h>
  13. #include <linux/errno.h>
  14. #include <linux/netdevice.h>
  15. #include <linux/skbuff.h>
  16. #include <linux/init.h>
  17. #include <net/dst.h>
  18. /* Locking strategy:
  19.  * 1) Garbage collection state of dead destination cache
  20.  *    entries is protected by dst_lock.
  21.  * 2) GC is run only from BH context, and is the only remover
  22.  *    of entries.
  23.  * 3) Entries are added to the garbage list from both BH
  24.  *    and non-BH context, so local BH disabling is needed.
  25.  * 4) All operations modify state, so a spinlock is used.
  26.  */
  27. static struct dst_entry  *dst_garbage_list;
  28. #if RT_CACHE_DEBUG >= 2 
  29. static atomic_t  dst_total = ATOMIC_INIT(0);
  30. #endif
  31. static spinlock_t  dst_lock = SPIN_LOCK_UNLOCKED;
  32. static unsigned long dst_gc_timer_expires;
  33. static unsigned long dst_gc_timer_inc = DST_GC_MAX;
  34. static void dst_run_gc(unsigned long);
  35. static struct timer_list dst_gc_timer =
  36. { data: DST_GC_MIN, function: dst_run_gc };
  37. static void dst_run_gc(unsigned long dummy)
  38. {
  39. int    delayed = 0;
  40. struct dst_entry * dst, **dstp;
  41. if (!spin_trylock(&dst_lock)) {
  42. mod_timer(&dst_gc_timer, jiffies + HZ/10);
  43. return;
  44. }
  45. del_timer(&dst_gc_timer);
  46. dstp = &dst_garbage_list;
  47. while ((dst = *dstp) != NULL) {
  48. if (atomic_read(&dst->__refcnt)) {
  49. dstp = &dst->next;
  50. delayed++;
  51. continue;
  52. }
  53. *dstp = dst->next;
  54. dst_destroy(dst);
  55. }
  56. if (!dst_garbage_list) {
  57. dst_gc_timer_inc = DST_GC_MAX;
  58. goto out;
  59. }
  60. if ((dst_gc_timer_expires += dst_gc_timer_inc) > DST_GC_MAX)
  61. dst_gc_timer_expires = DST_GC_MAX;
  62. dst_gc_timer_inc += DST_GC_INC;
  63. dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
  64. #if RT_CACHE_DEBUG >= 2
  65. printk("dst_total: %d/%d %ldn",
  66.        atomic_read(&dst_total), delayed,  dst_gc_timer_expires);
  67. #endif
  68. add_timer(&dst_gc_timer);
  69. out:
  70. spin_unlock(&dst_lock);
  71. }
  72. static int dst_discard(struct sk_buff *skb)
  73. {
  74. kfree_skb(skb);
  75. return 0;
  76. }
  77. static int dst_blackhole(struct sk_buff *skb)
  78. {
  79. kfree_skb(skb);
  80. return 0;
  81. }
  82. void * dst_alloc(struct dst_ops * ops)
  83. {
  84. struct dst_entry * dst;
  85. if (ops->gc && atomic_read(&ops->entries) > ops->gc_thresh) {
  86. if (ops->gc())
  87. return NULL;
  88. }
  89. dst = kmem_cache_alloc(ops->kmem_cachep, SLAB_ATOMIC);
  90. if (!dst)
  91. return NULL;
  92. memset(dst, 0, ops->entry_size);
  93. dst->ops = ops;
  94. dst->lastuse = jiffies;
  95. dst->input = dst_discard;
  96. dst->output = dst_blackhole;
  97. #if RT_CACHE_DEBUG >= 2 
  98. atomic_inc(&dst_total);
  99. #endif
  100. atomic_inc(&ops->entries);
  101. return dst;
  102. }
  103. void __dst_free(struct dst_entry * dst)
  104. {
  105. spin_lock_bh(&dst_lock);
  106. /* The first case (dev==NULL) is required, when
  107.    protocol module is unloaded.
  108.  */
  109. if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) {
  110. dst->input = dst_discard;
  111. dst->output = dst_blackhole;
  112. }
  113. dst->obsolete = 2;
  114. dst->next = dst_garbage_list;
  115. dst_garbage_list = dst;
  116. if (dst_gc_timer_inc > DST_GC_INC) {
  117. del_timer(&dst_gc_timer);
  118. dst_gc_timer_inc = DST_GC_INC;
  119. dst_gc_timer_expires = DST_GC_MIN;
  120. dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
  121. add_timer(&dst_gc_timer);
  122. }
  123. spin_unlock_bh(&dst_lock);
  124. }
  125. void dst_destroy(struct dst_entry * dst)
  126. {
  127. struct neighbour *neigh = dst->neighbour;
  128. struct hh_cache *hh = dst->hh;
  129. dst->hh = NULL;
  130. if (hh && atomic_dec_and_test(&hh->hh_refcnt))
  131. kfree(hh);
  132. if (neigh) {
  133. dst->neighbour = NULL;
  134. neigh_release(neigh);
  135. }
  136. atomic_dec(&dst->ops->entries);
  137. if (dst->ops->destroy)
  138. dst->ops->destroy(dst);
  139. if (dst->dev)
  140. dev_put(dst->dev);
  141. #if RT_CACHE_DEBUG >= 2 
  142. atomic_dec(&dst_total);
  143. #endif
  144. kmem_cache_free(dst->ops->kmem_cachep, dst);
  145. }
  146. static int dst_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
  147. {
  148. struct net_device *dev = ptr;
  149. struct dst_entry *dst;
  150. switch (event) {
  151. case NETDEV_UNREGISTER:
  152. case NETDEV_DOWN:
  153. spin_lock_bh(&dst_lock);
  154. for (dst = dst_garbage_list; dst; dst = dst->next) {
  155. if (dst->dev == dev) {
  156. /* Dirty hack. We did it in 2.2 (in __dst_free),
  157.    we have _very_ good reasons not to repeat
  158.    this mistake in 2.3, but we have no choice
  159.    now. _It_ _is_ _explicit_ _deliberate_
  160.    _race_ _condition_.
  161.  */
  162. if (event!=NETDEV_DOWN &&
  163.     !(dev->features & NETIF_F_DYNALLOC) &&
  164.     dst->output == dst_blackhole) {
  165. dst->dev = &loopback_dev;
  166. dev_put(dev);
  167. dev_hold(&loopback_dev);
  168. dst->output = dst_discard;
  169. if (dst->neighbour && dst->neighbour->dev == dev) {
  170. dst->neighbour->dev = &loopback_dev;
  171. dev_put(dev);
  172. dev_hold(&loopback_dev);
  173. }
  174. } else {
  175. dst->input = dst_discard;
  176. dst->output = dst_blackhole;
  177. }
  178. }
  179. }
  180. spin_unlock_bh(&dst_lock);
  181. break;
  182. }
  183. return NOTIFY_DONE;
  184. }
  185. struct notifier_block dst_dev_notifier = {
  186. dst_dev_event,
  187. NULL,
  188. 0
  189. };
  190. void __init dst_init(void)
  191. {
  192. register_netdevice_notifier(&dst_dev_notifier);
  193. }