|
@@ -75,9 +75,9 @@ for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
|
|
|
for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
|
|
|
|
|
|
#define RT_TABLE_MIN 1
|
|
|
-
|
|
|
+#define DN_FIB_TABLE_HASHSZ 256
|
|
|
+static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ];
|
|
|
static DEFINE_RWLOCK(dn_fib_tables_lock);
|
|
|
-struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1];
|
|
|
|
|
|
static kmem_cache_t *dn_hash_kmem __read_mostly;
|
|
|
static int dn_fib_hash_zombies;
|
|
@@ -361,7 +361,7 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
|
|
|
{
|
|
|
int i, s_i;
|
|
|
|
|
|
- s_i = cb->args[3];
|
|
|
+ s_i = cb->args[4];
|
|
|
for(i = 0; f; i++, f = f->fn_next) {
|
|
|
if (i < s_i)
|
|
|
continue;
|
|
@@ -374,11 +374,11 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
|
|
|
(f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
|
|
|
f->fn_scope, &f->fn_key, dz->dz_order,
|
|
|
f->fn_info, NLM_F_MULTI) < 0) {
|
|
|
- cb->args[3] = i;
|
|
|
+ cb->args[4] = i;
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
- cb->args[3] = i;
|
|
|
+ cb->args[4] = i;
|
|
|
return skb->len;
|
|
|
}
|
|
|
|
|
@@ -389,20 +389,20 @@ static __inline__ int dn_hash_dump_zone(struct sk_buff *skb,
|
|
|
{
|
|
|
int h, s_h;
|
|
|
|
|
|
- s_h = cb->args[2];
|
|
|
+ s_h = cb->args[3];
|
|
|
for(h = 0; h < dz->dz_divisor; h++) {
|
|
|
if (h < s_h)
|
|
|
continue;
|
|
|
if (h > s_h)
|
|
|
- memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
|
|
|
+ memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0]));
|
|
|
if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
|
|
|
continue;
|
|
|
if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
|
|
|
- cb->args[2] = h;
|
|
|
+ cb->args[3] = h;
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
- cb->args[2] = h;
|
|
|
+ cb->args[3] = h;
|
|
|
return skb->len;
|
|
|
}
|
|
|
|
|
@@ -413,26 +413,63 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
|
|
|
struct dn_zone *dz;
|
|
|
struct dn_hash *table = (struct dn_hash *)tb->data;
|
|
|
|
|
|
- s_m = cb->args[1];
|
|
|
+ s_m = cb->args[2];
|
|
|
read_lock(&dn_fib_tables_lock);
|
|
|
for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
|
|
|
if (m < s_m)
|
|
|
continue;
|
|
|
if (m > s_m)
|
|
|
- memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));
|
|
|
+ memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
|
|
|
|
|
|
if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
|
|
|
- cb->args[1] = m;
|
|
|
+ cb->args[2] = m;
|
|
|
read_unlock(&dn_fib_tables_lock);
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
read_unlock(&dn_fib_tables_lock);
|
|
|
- cb->args[1] = m;
|
|
|
+ cb->args[2] = m;
|
|
|
|
|
|
return skb->len;
|
|
|
}
|
|
|
|
|
|
+int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|
|
+{
|
|
|
+ unsigned int h, s_h;
|
|
|
+ unsigned int e = 0, s_e;
|
|
|
+ struct dn_fib_table *tb;
|
|
|
+ struct hlist_node *node;
|
|
|
+ int dumped = 0;
|
|
|
+
|
|
|
+ if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
|
|
|
+ ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
|
|
|
+ return dn_cache_dump(skb, cb);
|
|
|
+
|
|
|
+ s_h = cb->args[0];
|
|
|
+ s_e = cb->args[1];
|
|
|
+
|
|
|
+ for (h = s_h; h < DN_FIB_TABLE_HASHSZ; h++, s_h = 0) {
|
|
|
+ e = 0;
|
|
|
+ hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist) {
|
|
|
+ if (e < s_e)
|
|
|
+ goto next;
|
|
|
+ if (dumped)
|
|
|
+ memset(&cb->args[2], 0, sizeof(cb->args) -
|
|
|
+ 2 * sizeof(cb->args[0]));
|
|
|
+ if (tb->dump(tb, skb, cb) < 0)
|
|
|
+ goto out;
|
|
|
+ dumped = 1;
|
|
|
+next:
|
|
|
+ e++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+out:
|
|
|
+ cb->args[1] = e;
|
|
|
+ cb->args[0] = h;
|
|
|
+
|
|
|
+ return skb->len;
|
|
|
+}
|
|
|
+
|
|
|
static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
|
|
|
{
|
|
|
struct dn_hash *table = (struct dn_hash *)tb->data;
|
|
@@ -744,6 +781,8 @@ out:
|
|
|
struct dn_fib_table *dn_fib_get_table(u32 n, int create)
|
|
|
{
|
|
|
struct dn_fib_table *t;
|
|
|
+ struct hlist_node *node;
|
|
|
+ unsigned int h;
|
|
|
|
|
|
if (n < RT_TABLE_MIN)
|
|
|
return NULL;
|
|
@@ -751,8 +790,15 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create)
|
|
|
if (n > RT_TABLE_MAX)
|
|
|
return NULL;
|
|
|
|
|
|
- if (dn_fib_tables[n])
|
|
|
- return dn_fib_tables[n];
|
|
|
+ h = n & (DN_FIB_TABLE_HASHSZ - 1);
|
|
|
+ rcu_read_lock();
|
|
|
+ hlist_for_each_entry_rcu(t, node, &dn_fib_table_hash[h], hlist) {
|
|
|
+ if (t->n == n) {
|
|
|
+ rcu_read_unlock();
|
|
|
+ return t;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ rcu_read_unlock();
|
|
|
|
|
|
if (!create)
|
|
|
return NULL;
|
|
@@ -773,33 +819,37 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create)
|
|
|
t->flush = dn_fib_table_flush;
|
|
|
t->dump = dn_fib_table_dump;
|
|
|
memset(t->data, 0, sizeof(struct dn_hash));
|
|
|
- dn_fib_tables[n] = t;
|
|
|
+ hlist_add_head_rcu(&t->hlist, &dn_fib_table_hash[h]);
|
|
|
|
|
|
return t;
|
|
|
}
|
|
|
|
|
|
-static void dn_fib_del_tree(u32 n)
|
|
|
-{
|
|
|
- struct dn_fib_table *t;
|
|
|
-
|
|
|
- write_lock(&dn_fib_tables_lock);
|
|
|
- t = dn_fib_tables[n];
|
|
|
- dn_fib_tables[n] = NULL;
|
|
|
- write_unlock(&dn_fib_tables_lock);
|
|
|
-
|
|
|
- kfree(t);
|
|
|
-}
|
|
|
-
|
|
|
struct dn_fib_table *dn_fib_empty_table(void)
|
|
|
{
|
|
|
u32 id;
|
|
|
|
|
|
for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
|
|
|
- if (dn_fib_tables[id] == NULL)
|
|
|
+ if (dn_fib_get_table(id, 0) == NULL)
|
|
|
return dn_fib_get_table(id, 1);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+void dn_fib_flush(void)
|
|
|
+{
|
|
|
+ int flushed = 0;
|
|
|
+ struct dn_fib_table *tb;
|
|
|
+ struct hlist_node *node;
|
|
|
+ unsigned int h;
|
|
|
+
|
|
|
+ for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
|
|
|
+ hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist)
|
|
|
+ flushed += tb->flush(tb);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (flushed)
|
|
|
+ dn_rt_cache_flush(-1);
|
|
|
+}
|
|
|
+
|
|
|
void __init dn_fib_table_init(void)
|
|
|
{
|
|
|
dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
|
|
@@ -810,10 +860,17 @@ void __init dn_fib_table_init(void)
|
|
|
|
|
|
void __exit dn_fib_table_cleanup(void)
|
|
|
{
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i)
|
|
|
- dn_fib_del_tree(i);
|
|
|
+ struct dn_fib_table *t;
|
|
|
+ struct hlist_node *node, *next;
|
|
|
+ unsigned int h;
|
|
|
|
|
|
- return;
|
|
|
+ write_lock(&dn_fib_tables_lock);
|
|
|
+ for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
|
|
|
+ hlist_for_each_entry_safe(t, node, next, &dn_fib_table_hash[h],
|
|
|
+ hlist) {
|
|
|
+ hlist_del(&t->hlist);
|
|
|
+ kfree(t);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ write_unlock(&dn_fib_tables_lock);
|
|
|
}
|