dst.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

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