Commit abcab268 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[DECNET]: Increase number of possible routing tables to 2^32

Increase the number of possible routing tables to 2^32 by replacing the
fixed sized array of pointers by a hash table and replacing iterations
over all possible table IDs by hash table walking.
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1b43af54
...@@ -94,6 +94,7 @@ struct dn_fib_node { ...@@ -94,6 +94,7 @@ struct dn_fib_node {
struct dn_fib_table { struct dn_fib_table {
struct hlist_node hlist;
u32 n; u32 n;
int (*insert)(struct dn_fib_table *t, struct rtmsg *r, int (*insert)(struct dn_fib_table *t, struct rtmsg *r,
...@@ -177,8 +178,6 @@ static inline void dn_fib_res_put(struct dn_fib_res *res) ...@@ -177,8 +178,6 @@ static inline void dn_fib_res_put(struct dn_fib_res *res)
fib_rule_put(res->r); fib_rule_put(res->r);
} }
extern struct dn_fib_table *dn_fib_tables[];
#else /* Endnode */ #else /* Endnode */
#define dn_fib_init() do { } while(0) #define dn_fib_init() do { } while(0)
......
...@@ -532,39 +532,6 @@ int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) ...@@ -532,39 +532,6 @@ int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
return -ENOBUFS; return -ENOBUFS;
} }
int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
u32 t;
u32 s_t;
struct dn_fib_table *tb;
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_t = cb->args[0];
if (s_t == 0)
s_t = cb->args[0] = RT_MIN_TABLE;
for(t = s_t; t <= RT_TABLE_MAX; t++) {
if (t < s_t)
continue;
if (t > s_t)
memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0]));
tb = dn_fib_get_table(t, 0);
if (tb == NULL)
continue;
if (tb->dump(tb, skb, cb) < 0)
break;
}
cb->args[0] = t;
return skb->len;
}
static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa) static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
{ {
struct dn_fib_table *tb; struct dn_fib_table *tb;
...@@ -762,22 +729,6 @@ int dn_fib_sync_up(struct net_device *dev) ...@@ -762,22 +729,6 @@ int dn_fib_sync_up(struct net_device *dev)
return ret; return ret;
} }
void dn_fib_flush(void)
{
int flushed = 0;
struct dn_fib_table *tb;
u32 id;
for(id = RT_TABLE_MAX; id > 0; id--) {
if ((tb = dn_fib_get_table(id, 0)) == NULL)
continue;
flushed += tb->flush(tb);
}
if (flushed)
dn_rt_cache_flush(-1);
}
static struct notifier_block dn_fib_dnaddr_notifier = { static struct notifier_block dn_fib_dnaddr_notifier = {
.notifier_call = dn_fib_dnaddr_event, .notifier_call = dn_fib_dnaddr_event,
}; };
......
...@@ -210,7 +210,7 @@ unsigned dnet_addr_type(__le16 addr) ...@@ -210,7 +210,7 @@ unsigned dnet_addr_type(__le16 addr)
struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } }; struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } };
struct dn_fib_res res; struct dn_fib_res res;
unsigned ret = RTN_UNICAST; unsigned ret = RTN_UNICAST;
struct dn_fib_table *tb = dn_fib_tables[RT_TABLE_LOCAL]; struct dn_fib_table *tb = dn_fib_get_table(RT_TABLE_LOCAL, 0);
res.r = NULL; res.r = NULL;
......
...@@ -75,9 +75,9 @@ for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next) ...@@ -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) for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
#define RT_TABLE_MIN 1 #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); 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 kmem_cache_t *dn_hash_kmem __read_mostly;
static int dn_fib_hash_zombies; static int dn_fib_hash_zombies;
...@@ -361,7 +361,7 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, ...@@ -361,7 +361,7 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
{ {
int i, s_i; int i, s_i;
s_i = cb->args[3]; s_i = cb->args[4];
for(i = 0; f; i++, f = f->fn_next) { for(i = 0; f; i++, f = f->fn_next) {
if (i < s_i) if (i < s_i)
continue; continue;
...@@ -374,11 +374,11 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, ...@@ -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_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
f->fn_scope, &f->fn_key, dz->dz_order, f->fn_scope, &f->fn_key, dz->dz_order,
f->fn_info, NLM_F_MULTI) < 0) { f->fn_info, NLM_F_MULTI) < 0) {
cb->args[3] = i; cb->args[4] = i;
return -1; return -1;
} }
} }
cb->args[3] = i; cb->args[4] = i;
return skb->len; return skb->len;
} }
...@@ -389,20 +389,20 @@ static __inline__ int dn_hash_dump_zone(struct sk_buff *skb, ...@@ -389,20 +389,20 @@ static __inline__ int dn_hash_dump_zone(struct sk_buff *skb,
{ {
int h, s_h; int h, s_h;
s_h = cb->args[2]; s_h = cb->args[3];
for(h = 0; h < dz->dz_divisor; h++) { for(h = 0; h < dz->dz_divisor; h++) {
if (h < s_h) if (h < s_h)
continue; continue;
if (h > s_h) 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) if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
continue; continue;
if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) { if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
cb->args[2] = h; cb->args[3] = h;
return -1; return -1;
} }
} }
cb->args[2] = h; cb->args[3] = h;
return skb->len; return skb->len;
} }
...@@ -413,22 +413,59 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb, ...@@ -413,22 +413,59 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
struct dn_zone *dz; struct dn_zone *dz;
struct dn_hash *table = (struct dn_hash *)tb->data; 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); read_lock(&dn_fib_tables_lock);
for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) { for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
if (m < s_m) if (m < s_m)
continue; continue;
if (m > s_m) 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) { if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
cb->args[1] = m; cb->args[2] = m;
read_unlock(&dn_fib_tables_lock); read_unlock(&dn_fib_tables_lock);
return -1; return -1;
} }
} }
read_unlock(&dn_fib_tables_lock); 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; return skb->len;
} }
...@@ -744,6 +781,8 @@ out: ...@@ -744,6 +781,8 @@ out:
struct dn_fib_table *dn_fib_get_table(u32 n, int create) struct dn_fib_table *dn_fib_get_table(u32 n, int create)
{ {
struct dn_fib_table *t; struct dn_fib_table *t;
struct hlist_node *node;
unsigned int h;
if (n < RT_TABLE_MIN) if (n < RT_TABLE_MIN)
return NULL; return NULL;
...@@ -751,8 +790,15 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create) ...@@ -751,8 +790,15 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create)
if (n > RT_TABLE_MAX) if (n > RT_TABLE_MAX)
return NULL; return NULL;
if (dn_fib_tables[n]) h = n & (DN_FIB_TABLE_HASHSZ - 1);
return dn_fib_tables[n]; 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) if (!create)
return NULL; return NULL;
...@@ -773,33 +819,37 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create) ...@@ -773,33 +819,37 @@ struct dn_fib_table *dn_fib_get_table(u32 n, int create)
t->flush = dn_fib_table_flush; t->flush = dn_fib_table_flush;
t->dump = dn_fib_table_dump; t->dump = dn_fib_table_dump;
memset(t->data, 0, sizeof(struct dn_hash)); 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; 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) struct dn_fib_table *dn_fib_empty_table(void)
{ {
u32 id; u32 id;
for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; 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 dn_fib_get_table(id, 1);
return NULL; 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) void __init dn_fib_table_init(void)
{ {
dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
...@@ -810,10 +860,17 @@ void __init dn_fib_table_init(void) ...@@ -810,10 +860,17 @@ void __init dn_fib_table_init(void)
void __exit dn_fib_table_cleanup(void) void __exit dn_fib_table_cleanup(void)
{ {
int i; struct dn_fib_table *t;
struct hlist_node *node, *next;
for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i) unsigned int h;
dn_fib_del_tree(i);
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);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment