00001
00002
00003
00004
00005
00006
00007
00008
#include <linux/bitops.h>
00009
#include <linux/types.h>
00010
#include <linux/kernel.h>
00011
#include <linux/sched.h>
00012
#include <linux/mm.h>
00013
#include <linux/string.h>
00014
#include <linux/errno.h>
00015
#include <linux/netdevice.h>
00016
#include <linux/skbuff.h>
00017
#include <linux/init.h>
00018
00019
#include <net/dst.h>
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 static struct dst_entry *
dst_garbage_list;
00031
#if RT_CACHE_DEBUG >= 2
00032
static atomic_t dst_total = ATOMIC_INIT(0);
00033
#endif
00034 static spinlock_t
dst_lock = SPIN_LOCK_UNLOCKED;
00035
00036 static unsigned long dst_gc_timer_expires;
00037 static unsigned long dst_gc_timer_inc =
DST_GC_MAX;
00038
static void dst_run_gc(
unsigned long);
00039
00040 static struct timer_list
dst_gc_timer =
00041 { data:
DST_GC_MIN, function:
dst_run_gc };
00042
00043
00044 static void dst_run_gc(
unsigned long dummy)
00045 {
00046
int delayed = 0;
00047
struct dst_entry * dst, **dstp;
00048
00049
if (!spin_trylock(&
dst_lock)) {
00050 mod_timer(&
dst_gc_timer, jiffies + HZ/10);
00051
return;
00052 }
00053
00054
00055 del_timer(&
dst_gc_timer);
00056 dstp = &
dst_garbage_list;
00057
while ((dst = *dstp) != NULL) {
00058
if (atomic_read(&dst->__refcnt)) {
00059 dstp = &dst->
next;
00060 delayed++;
00061
continue;
00062 }
00063 *dstp = dst->
next;
00064
dst_destroy(dst);
00065 }
00066
if (!
dst_garbage_list) {
00067
dst_gc_timer_inc =
DST_GC_MAX;
00068
goto out;
00069 }
00070
if ((
dst_gc_timer_expires +=
dst_gc_timer_inc) >
DST_GC_MAX)
00071
dst_gc_timer_expires =
DST_GC_MAX;
00072
dst_gc_timer_inc +=
DST_GC_INC;
00073
dst_gc_timer.expires = jiffies +
dst_gc_timer_expires;
00074
#if RT_CACHE_DEBUG >= 2
00075
printk(
"dst_total: %d/%d %ld\n",
00076 atomic_read(&dst_total), delayed,
dst_gc_timer_expires);
00077
#endif
00078
add_timer(&
dst_gc_timer);
00079
00080 out:
00081 spin_unlock(&
dst_lock);
00082 }
00083
00084 static int dst_discard(
struct sk_buff *skb)
00085 {
00086
kfree_skb(skb);
00087
return 0;
00088 }
00089
00090 static int dst_blackhole(
struct sk_buff *skb)
00091 {
00092
kfree_skb(skb);
00093
return 0;
00094 }
00095
00096 void *
dst_alloc(
struct dst_ops * ops)
00097 {
00098
struct dst_entry * dst;
00099
00100
if (ops->
gc && atomic_read(&ops->
entries) > ops->
gc_thresh) {
00101
if (ops->
gc())
00102
return NULL;
00103 }
00104 dst = kmem_cache_alloc(ops->
kmem_cachep, SLAB_ATOMIC);
00105
if (!dst)
00106
return NULL;
00107 memset(dst, 0, ops->
entry_size);
00108 atomic_set(&dst->__refcnt, 0);
00109 dst->ops = ops;
00110 dst->lastuse = jiffies;
00111 dst->input =
dst_discard;
00112 dst->output =
dst_blackhole;
00113
#if RT_CACHE_DEBUG >= 2
00114
atomic_inc(&dst_total);
00115
#endif
00116
atomic_inc(&ops->
entries);
00117
return dst;
00118 }
00119
00120 void __dst_free(
struct dst_entry * dst)
00121 {
00122 spin_lock_bh(&
dst_lock);
00123
00124
00125
00126
00127
if (dst->
dev == NULL || !(dst->
dev->
flags&IFF_UP)) {
00128 dst->
input =
dst_discard;
00129 dst->
output =
dst_blackhole;
00130 }
00131 dst->
obsolete = 2;
00132 dst->
next =
dst_garbage_list;
00133
dst_garbage_list = dst;
00134
if (
dst_gc_timer_inc >
DST_GC_INC) {
00135
dst_gc_timer_inc =
DST_GC_INC;
00136
dst_gc_timer_expires =
DST_GC_MIN;
00137 mod_timer(&
dst_gc_timer, jiffies +
dst_gc_timer_expires);
00138 }
00139
00140 spin_unlock_bh(&
dst_lock);
00141 }
00142
00143 void dst_destroy(
struct dst_entry * dst)
00144 {
00145
struct neighbour *neigh = dst->
neighbour;
00146
struct hh_cache *hh = dst->
hh;
00147
00148 dst->
hh = NULL;
00149
if (hh && atomic_dec_and_test(&hh->hh_refcnt))
00150 kfree(hh);
00151
00152
if (neigh) {
00153 dst->
neighbour = NULL;
00154
neigh_release(neigh);
00155 }
00156
00157 atomic_dec(&dst->
ops->
entries);
00158
00159
if (dst->
ops->
destroy)
00160 dst->
ops->
destroy(dst);
00161
if (dst->
dev)
00162
dev_put(dst->
dev);
00163
#if RT_CACHE_DEBUG >= 2
00164
atomic_dec(&dst_total);
00165
#endif
00166
kmem_cache_free(dst->
ops->
kmem_cachep, dst);
00167 }
00168
00169 static int dst_dev_event(
struct notifier_block *
this,
unsigned long event,
void *ptr)
00170 {
00171
struct net_device *dev = ptr;
00172
struct dst_entry *dst;
00173
00174
switch (event) {
00175
case NETDEV_UNREGISTER:
00176
case NETDEV_DOWN:
00177 spin_lock_bh(&
dst_lock);
00178
for (dst =
dst_garbage_list; dst; dst = dst->
next) {
00179
if (dst->dev == dev) {
00180
00181
00182
00183
00184
00185
00186
if (event!=NETDEV_DOWN &&
00187 !(dev->features &
NETIF_F_DYNALLOC) &&
00188 dst->output ==
dst_blackhole) {
00189 dst->dev = &
loopback_dev;
00190
dev_put(dev);
00191
dev_hold(&
loopback_dev);
00192 dst->output =
dst_discard;
00193
if (dst->neighbour && dst->neighbour->dev == dev) {
00194 dst->neighbour->dev = &
loopback_dev;
00195
dev_put(dev);
00196
dev_hold(&
loopback_dev);
00197 }
00198 }
else {
00199 dst->input =
dst_discard;
00200 dst->output =
dst_blackhole;
00201 }
00202 }
00203 }
00204 spin_unlock_bh(&
dst_lock);
00205
break;
00206 }
00207
return NOTIFY_DONE;
00208 }
00209
00210 struct notifier_block
dst_dev_notifier = {
00211
dst_dev_event,
00212 NULL,
00213 0
00214 };
00215
00216 void __init
dst_init(
void)
00217 {
00218
register_netdevice_notifier(&
dst_dev_notifier);
00219 }