mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-03 18:20:25 +02:00 
			
		
		
		
	[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: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									1b43af5480
								
							
						
					
					
						commit
						abcab26830
					
				
					 4 changed files with 93 additions and 86 deletions
				
			
		| 
						 | 
				
			
			@ -94,6 +94,7 @@ struct dn_fib_node {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
struct dn_fib_table {
 | 
			
		||||
	struct hlist_node hlist;
 | 
			
		||||
	u32 n;
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		|||
		fib_rule_put(res->r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern struct dn_fib_table *dn_fib_tables[];
 | 
			
		||||
 | 
			
		||||
#else /* Endnode */
 | 
			
		||||
 | 
			
		||||
#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)
 | 
			
		|||
	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)
 | 
			
		||||
{
 | 
			
		||||
	struct dn_fib_table *tb;
 | 
			
		||||
| 
						 | 
				
			
			@ -762,22 +729,6 @@ int dn_fib_sync_up(struct net_device *dev)
 | 
			
		|||
        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 = {
 | 
			
		||||
	.notifier_call = dn_fib_dnaddr_event,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -210,7 +210,7 @@ unsigned dnet_addr_type(__le16 addr)
 | 
			
		|||
	struct flowi fl = { .nl_u = { .dn_u = { .daddr = addr } } };
 | 
			
		||||
	struct dn_fib_res res;
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,22 +413,59 @@ 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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -744,6 +781,8 @@ static int dn_fib_table_lookup(struct dn_fib_table *tb, const struct flowi *flp,
 | 
			
		|||
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;
 | 
			
		||||
	struct dn_fib_table *t;
 | 
			
		||||
	struct hlist_node *node, *next;
 | 
			
		||||
	unsigned int h;
 | 
			
		||||
 | 
			
		||||
	for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i)
 | 
			
		||||
		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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue