xref: /openbmc/linux/net/ipv4/fib_trie.c (revision 90f66914)
119baf839SRobert Olsson /*
219baf839SRobert Olsson  *   This program is free software; you can redistribute it and/or
319baf839SRobert Olsson  *   modify it under the terms of the GNU General Public License
419baf839SRobert Olsson  *   as published by the Free Software Foundation; either version
519baf839SRobert Olsson  *   2 of the License, or (at your option) any later version.
619baf839SRobert Olsson  *
719baf839SRobert Olsson  *   Robert Olsson <robert.olsson@its.uu.se> Uppsala Universitet
819baf839SRobert Olsson  *     & Swedish University of Agricultural Sciences.
919baf839SRobert Olsson  *
1019baf839SRobert Olsson  *   Jens Laas <jens.laas@data.slu.se> Swedish University of
1119baf839SRobert Olsson  *     Agricultural Sciences.
1219baf839SRobert Olsson  *
1319baf839SRobert Olsson  *   Hans Liss <hans.liss@its.uu.se>  Uppsala Universitet
1419baf839SRobert Olsson  *
1519baf839SRobert Olsson  * This work is based on the LPC-trie which is originally descibed in:
1619baf839SRobert Olsson  *
1719baf839SRobert Olsson  * An experimental study of compression methods for dynamic tries
1819baf839SRobert Olsson  * Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
1919baf839SRobert Olsson  * http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
2019baf839SRobert Olsson  *
2119baf839SRobert Olsson  *
2219baf839SRobert Olsson  * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
2319baf839SRobert Olsson  * IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
2419baf839SRobert Olsson  *
2519baf839SRobert Olsson  * Version:	$Id: fib_trie.c,v 1.3 2005/06/08 14:20:01 robert Exp $
2619baf839SRobert Olsson  *
2719baf839SRobert Olsson  *
2819baf839SRobert Olsson  * Code from fib_hash has been reused which includes the following header:
2919baf839SRobert Olsson  *
3019baf839SRobert Olsson  *
3119baf839SRobert Olsson  * INET		An implementation of the TCP/IP protocol suite for the LINUX
3219baf839SRobert Olsson  *		operating system.  INET is implemented using the  BSD Socket
3319baf839SRobert Olsson  *		interface as the means of communication with the user level.
3419baf839SRobert Olsson  *
3519baf839SRobert Olsson  *		IPv4 FIB: lookup engine and maintenance routines.
3619baf839SRobert Olsson  *
3719baf839SRobert Olsson  *
3819baf839SRobert Olsson  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
3919baf839SRobert Olsson  *
4019baf839SRobert Olsson  *		This program is free software; you can redistribute it and/or
4119baf839SRobert Olsson  *		modify it under the terms of the GNU General Public License
4219baf839SRobert Olsson  *		as published by the Free Software Foundation; either version
4319baf839SRobert Olsson  *		2 of the License, or (at your option) any later version.
4419baf839SRobert Olsson  */
4519baf839SRobert Olsson 
4619baf839SRobert Olsson #define VERSION "0.323"
4719baf839SRobert Olsson 
4819baf839SRobert Olsson #include <linux/config.h>
4919baf839SRobert Olsson #include <asm/uaccess.h>
5019baf839SRobert Olsson #include <asm/system.h>
5119baf839SRobert Olsson #include <asm/bitops.h>
5219baf839SRobert Olsson #include <linux/types.h>
5319baf839SRobert Olsson #include <linux/kernel.h>
5419baf839SRobert Olsson #include <linux/sched.h>
5519baf839SRobert Olsson #include <linux/mm.h>
5619baf839SRobert Olsson #include <linux/string.h>
5719baf839SRobert Olsson #include <linux/socket.h>
5819baf839SRobert Olsson #include <linux/sockios.h>
5919baf839SRobert Olsson #include <linux/errno.h>
6019baf839SRobert Olsson #include <linux/in.h>
6119baf839SRobert Olsson #include <linux/inet.h>
6219baf839SRobert Olsson #include <linux/netdevice.h>
6319baf839SRobert Olsson #include <linux/if_arp.h>
6419baf839SRobert Olsson #include <linux/proc_fs.h>
6519baf839SRobert Olsson #include <linux/skbuff.h>
6619baf839SRobert Olsson #include <linux/netlink.h>
6719baf839SRobert Olsson #include <linux/init.h>
6819baf839SRobert Olsson #include <linux/list.h>
6919baf839SRobert Olsson #include <net/ip.h>
7019baf839SRobert Olsson #include <net/protocol.h>
7119baf839SRobert Olsson #include <net/route.h>
7219baf839SRobert Olsson #include <net/tcp.h>
7319baf839SRobert Olsson #include <net/sock.h>
7419baf839SRobert Olsson #include <net/ip_fib.h>
7519baf839SRobert Olsson #include "fib_lookup.h"
7619baf839SRobert Olsson 
7719baf839SRobert Olsson #undef CONFIG_IP_FIB_TRIE_STATS
7819baf839SRobert Olsson #define MAX_CHILDS 16384
7919baf839SRobert Olsson 
8019baf839SRobert Olsson #define EXTRACT(p, n, str) ((str)<<(p)>>(32-(n)))
8119baf839SRobert Olsson #define KEYLENGTH (8*sizeof(t_key))
8219baf839SRobert Olsson #define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l))
8319baf839SRobert Olsson #define TKEY_GET_MASK(offset, bits) (((bits)==0)?0:((t_key)(-1) << (KEYLENGTH - bits) >> offset))
8419baf839SRobert Olsson 
8519baf839SRobert Olsson static DEFINE_RWLOCK(fib_lock);
8619baf839SRobert Olsson 
8719baf839SRobert Olsson typedef unsigned int t_key;
8819baf839SRobert Olsson 
8919baf839SRobert Olsson #define T_TNODE 0
9019baf839SRobert Olsson #define T_LEAF  1
9119baf839SRobert Olsson #define NODE_TYPE_MASK	0x1UL
9219baf839SRobert Olsson #define NODE_PARENT(_node) \
9319baf839SRobert Olsson ((struct tnode *)((_node)->_parent & ~NODE_TYPE_MASK))
9419baf839SRobert Olsson #define NODE_SET_PARENT(_node, _ptr) \
9519baf839SRobert Olsson ((_node)->_parent = (((unsigned long)(_ptr)) | \
9619baf839SRobert Olsson                      ((_node)->_parent & NODE_TYPE_MASK)))
9719baf839SRobert Olsson #define NODE_INIT_PARENT(_node, _type) \
9819baf839SRobert Olsson ((_node)->_parent = (_type))
9919baf839SRobert Olsson #define NODE_TYPE(_node) \
10019baf839SRobert Olsson ((_node)->_parent & NODE_TYPE_MASK)
10119baf839SRobert Olsson 
10219baf839SRobert Olsson #define IS_TNODE(n) (!(n->_parent & T_LEAF))
10319baf839SRobert Olsson #define IS_LEAF(n) (n->_parent & T_LEAF)
10419baf839SRobert Olsson 
10519baf839SRobert Olsson struct node {
10619baf839SRobert Olsson         t_key key;
10719baf839SRobert Olsson 	unsigned long _parent;
10819baf839SRobert Olsson };
10919baf839SRobert Olsson 
11019baf839SRobert Olsson struct leaf {
11119baf839SRobert Olsson         t_key key;
11219baf839SRobert Olsson 	unsigned long _parent;
11319baf839SRobert Olsson 	struct hlist_head list;
11419baf839SRobert Olsson };
11519baf839SRobert Olsson 
11619baf839SRobert Olsson struct leaf_info {
11719baf839SRobert Olsson 	struct hlist_node hlist;
11819baf839SRobert Olsson 	int plen;
11919baf839SRobert Olsson 	struct list_head falh;
12019baf839SRobert Olsson };
12119baf839SRobert Olsson 
12219baf839SRobert Olsson struct tnode {
12319baf839SRobert Olsson         t_key key;
12419baf839SRobert Olsson 	unsigned long _parent;
12519baf839SRobert Olsson         unsigned short pos:5;        /* 2log(KEYLENGTH) bits needed */
12619baf839SRobert Olsson         unsigned short bits:5;       /* 2log(KEYLENGTH) bits needed */
12719baf839SRobert Olsson         unsigned short full_children;  /* KEYLENGTH bits needed */
12819baf839SRobert Olsson         unsigned short empty_children; /* KEYLENGTH bits needed */
12919baf839SRobert Olsson         struct node *child[0];
13019baf839SRobert Olsson };
13119baf839SRobert Olsson 
13219baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
13319baf839SRobert Olsson struct trie_use_stats {
13419baf839SRobert Olsson 	unsigned int gets;
13519baf839SRobert Olsson 	unsigned int backtrack;
13619baf839SRobert Olsson 	unsigned int semantic_match_passed;
13719baf839SRobert Olsson 	unsigned int semantic_match_miss;
13819baf839SRobert Olsson 	unsigned int null_node_hit;
13919baf839SRobert Olsson };
14019baf839SRobert Olsson #endif
14119baf839SRobert Olsson 
14219baf839SRobert Olsson struct trie_stat {
14319baf839SRobert Olsson 	unsigned int totdepth;
14419baf839SRobert Olsson 	unsigned int maxdepth;
14519baf839SRobert Olsson 	unsigned int tnodes;
14619baf839SRobert Olsson 	unsigned int leaves;
14719baf839SRobert Olsson 	unsigned int nullpointers;
14819baf839SRobert Olsson 	unsigned int nodesizes[MAX_CHILDS];
14919baf839SRobert Olsson };
15019baf839SRobert Olsson 
15119baf839SRobert Olsson struct trie {
15219baf839SRobert Olsson         struct node *trie;
15319baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
15419baf839SRobert Olsson 	struct trie_use_stats stats;
15519baf839SRobert Olsson #endif
15619baf839SRobert Olsson         int size;
15719baf839SRobert Olsson 	unsigned int revision;
15819baf839SRobert Olsson };
15919baf839SRobert Olsson 
16019baf839SRobert Olsson static int trie_debug = 0;
16119baf839SRobert Olsson 
16219baf839SRobert Olsson static int tnode_full(struct tnode *tn, struct node *n);
16319baf839SRobert Olsson static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
16419baf839SRobert Olsson static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull);
16519baf839SRobert Olsson static int tnode_child_length(struct tnode *tn);
16619baf839SRobert Olsson static struct node *resize(struct trie *t, struct tnode *tn);
16719baf839SRobert Olsson static struct tnode *inflate(struct trie *t, struct tnode *tn);
16819baf839SRobert Olsson static struct tnode *halve(struct trie *t, struct tnode *tn);
16919baf839SRobert Olsson static void tnode_free(struct tnode *tn);
17019baf839SRobert Olsson static void trie_dump_seq(struct seq_file *seq, struct trie *t);
17119baf839SRobert Olsson extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio);
17219baf839SRobert Olsson extern int fib_detect_death(struct fib_info *fi, int order,
17319baf839SRobert Olsson                             struct fib_info **last_resort, int *last_idx, int *dflt);
17419baf839SRobert Olsson 
17519baf839SRobert Olsson extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa, int z, int tb_id,
17619baf839SRobert Olsson                struct nlmsghdr *n, struct netlink_skb_parms *req);
17719baf839SRobert Olsson 
17819baf839SRobert Olsson static kmem_cache_t *fn_alias_kmem;
17919baf839SRobert Olsson static struct trie *trie_local = NULL, *trie_main = NULL;
18019baf839SRobert Olsson 
18119baf839SRobert Olsson static void trie_bug(char *err)
18219baf839SRobert Olsson {
18319baf839SRobert Olsson 	printk("Trie Bug: %s\n", err);
18419baf839SRobert Olsson 	BUG();
18519baf839SRobert Olsson }
18619baf839SRobert Olsson 
18719baf839SRobert Olsson static inline struct node *tnode_get_child(struct tnode *tn, int i)
18819baf839SRobert Olsson {
18919baf839SRobert Olsson         if (i >=  1<<tn->bits)
19019baf839SRobert Olsson                 trie_bug("tnode_get_child");
19119baf839SRobert Olsson 
19219baf839SRobert Olsson         return tn->child[i];
19319baf839SRobert Olsson }
19419baf839SRobert Olsson 
19519baf839SRobert Olsson static inline int tnode_child_length(struct tnode *tn)
19619baf839SRobert Olsson {
19719baf839SRobert Olsson         return 1<<tn->bits;
19819baf839SRobert Olsson }
19919baf839SRobert Olsson 
20019baf839SRobert Olsson /*
20119baf839SRobert Olsson   _________________________________________________________________
20219baf839SRobert Olsson   | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
20319baf839SRobert Olsson   ----------------------------------------------------------------
20419baf839SRobert Olsson     0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
20519baf839SRobert Olsson 
20619baf839SRobert Olsson   _________________________________________________________________
20719baf839SRobert Olsson   | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
20819baf839SRobert Olsson   -----------------------------------------------------------------
20919baf839SRobert Olsson    16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31
21019baf839SRobert Olsson 
21119baf839SRobert Olsson   tp->pos = 7
21219baf839SRobert Olsson   tp->bits = 3
21319baf839SRobert Olsson   n->pos = 15
21419baf839SRobert Olsson   n->bits=4
21519baf839SRobert Olsson   KEYLENGTH=32
21619baf839SRobert Olsson */
21719baf839SRobert Olsson 
21819baf839SRobert Olsson static inline t_key tkey_extract_bits(t_key a, int offset, int bits)
21919baf839SRobert Olsson {
22019baf839SRobert Olsson         if (offset < KEYLENGTH)
22119baf839SRobert Olsson 		return ((t_key)(a << offset)) >> (KEYLENGTH - bits);
22219baf839SRobert Olsson         else
22319baf839SRobert Olsson 		return 0;
22419baf839SRobert Olsson }
22519baf839SRobert Olsson 
22619baf839SRobert Olsson static inline int tkey_equals(t_key a, t_key b)
22719baf839SRobert Olsson {
22819baf839SRobert Olsson   return a == b;
22919baf839SRobert Olsson }
23019baf839SRobert Olsson 
23119baf839SRobert Olsson static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
23219baf839SRobert Olsson {
23319baf839SRobert Olsson      if (bits == 0 || offset >= KEYLENGTH)
23419baf839SRobert Olsson             return 1;
23519baf839SRobert Olsson         bits = bits > KEYLENGTH ? KEYLENGTH : bits;
23619baf839SRobert Olsson         return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
23719baf839SRobert Olsson }
23819baf839SRobert Olsson 
23919baf839SRobert Olsson static inline int tkey_mismatch(t_key a, int offset, t_key b)
24019baf839SRobert Olsson {
24119baf839SRobert Olsson 	t_key diff = a ^ b;
24219baf839SRobert Olsson 	int i = offset;
24319baf839SRobert Olsson 
24419baf839SRobert Olsson 	if(!diff)
24519baf839SRobert Olsson 	  return 0;
24619baf839SRobert Olsson 	while((diff << i) >> (KEYLENGTH-1) == 0)
24719baf839SRobert Olsson 		i++;
24819baf839SRobert Olsson 	return i;
24919baf839SRobert Olsson }
25019baf839SRobert Olsson 
25119baf839SRobert Olsson /* Candiate for fib_semantics */
25219baf839SRobert Olsson 
25319baf839SRobert Olsson static void fn_free_alias(struct fib_alias *fa)
25419baf839SRobert Olsson {
25519baf839SRobert Olsson 	fib_release_info(fa->fa_info);
25619baf839SRobert Olsson 	kmem_cache_free(fn_alias_kmem, fa);
25719baf839SRobert Olsson }
25819baf839SRobert Olsson 
25919baf839SRobert Olsson /*
26019baf839SRobert Olsson   To understand this stuff, an understanding of keys and all their bits is
26119baf839SRobert Olsson   necessary. Every node in the trie has a key associated with it, but not
26219baf839SRobert Olsson   all of the bits in that key are significant.
26319baf839SRobert Olsson 
26419baf839SRobert Olsson   Consider a node 'n' and its parent 'tp'.
26519baf839SRobert Olsson 
26619baf839SRobert Olsson   If n is a leaf, every bit in its key is significant. Its presence is
26719baf839SRobert Olsson   necessitaded by path compression, since during a tree traversal (when
26819baf839SRobert Olsson   searching for a leaf - unless we are doing an insertion) we will completely
26919baf839SRobert Olsson   ignore all skipped bits we encounter. Thus we need to verify, at the end of
27019baf839SRobert Olsson   a potentially successful search, that we have indeed been walking the
27119baf839SRobert Olsson   correct key path.
27219baf839SRobert Olsson 
27319baf839SRobert Olsson   Note that we can never "miss" the correct key in the tree if present by
27419baf839SRobert Olsson   following the wrong path. Path compression ensures that segments of the key
27519baf839SRobert Olsson   that are the same for all keys with a given prefix are skipped, but the
27619baf839SRobert Olsson   skipped part *is* identical for each node in the subtrie below the skipped
27719baf839SRobert Olsson   bit! trie_insert() in this implementation takes care of that - note the
27819baf839SRobert Olsson   call to tkey_sub_equals() in trie_insert().
27919baf839SRobert Olsson 
28019baf839SRobert Olsson   if n is an internal node - a 'tnode' here, the various parts of its key
28119baf839SRobert Olsson   have many different meanings.
28219baf839SRobert Olsson 
28319baf839SRobert Olsson   Example:
28419baf839SRobert Olsson   _________________________________________________________________
28519baf839SRobert Olsson   | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
28619baf839SRobert Olsson   -----------------------------------------------------------------
28719baf839SRobert Olsson     0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
28819baf839SRobert Olsson 
28919baf839SRobert Olsson   _________________________________________________________________
29019baf839SRobert Olsson   | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
29119baf839SRobert Olsson   -----------------------------------------------------------------
29219baf839SRobert Olsson    16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31
29319baf839SRobert Olsson 
29419baf839SRobert Olsson   tp->pos = 7
29519baf839SRobert Olsson   tp->bits = 3
29619baf839SRobert Olsson   n->pos = 15
29719baf839SRobert Olsson   n->bits=4
29819baf839SRobert Olsson 
29919baf839SRobert Olsson   First, let's just ignore the bits that come before the parent tp, that is
30019baf839SRobert Olsson   the bits from 0 to (tp->pos-1). They are *known* but at this point we do
30119baf839SRobert Olsson   not use them for anything.
30219baf839SRobert Olsson 
30319baf839SRobert Olsson   The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the
30419baf839SRobert Olsson   index into the parent's child array. That is, they will be used to find
30519baf839SRobert Olsson   'n' among tp's children.
30619baf839SRobert Olsson 
30719baf839SRobert Olsson   The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits
30819baf839SRobert Olsson   for the node n.
30919baf839SRobert Olsson 
31019baf839SRobert Olsson   All the bits we have seen so far are significant to the node n. The rest
31119baf839SRobert Olsson   of the bits are really not needed or indeed known in n->key.
31219baf839SRobert Olsson 
31319baf839SRobert Olsson   The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into
31419baf839SRobert Olsson   n's child array, and will of course be different for each child.
31519baf839SRobert Olsson 
31619baf839SRobert Olsson   The rest of the bits, from (n->pos + n->bits) onward, are completely unknown
31719baf839SRobert Olsson   at this point.
31819baf839SRobert Olsson 
31919baf839SRobert Olsson */
32019baf839SRobert Olsson 
32119baf839SRobert Olsson static void check_tnode(struct tnode *tn)
32219baf839SRobert Olsson {
32319baf839SRobert Olsson 	if(tn && tn->pos+tn->bits > 32) {
32419baf839SRobert Olsson 		printk("TNODE ERROR tn=%p, pos=%d, bits=%d\n", tn, tn->pos, tn->bits);
32519baf839SRobert Olsson 	}
32619baf839SRobert Olsson }
32719baf839SRobert Olsson 
32819baf839SRobert Olsson static int halve_threshold = 25;
32919baf839SRobert Olsson static int inflate_threshold = 50;
33019baf839SRobert Olsson 
33119baf839SRobert Olsson static struct leaf *leaf_new(void)
33219baf839SRobert Olsson {
33319baf839SRobert Olsson 	struct leaf *l = kmalloc(sizeof(struct leaf),  GFP_KERNEL);
33419baf839SRobert Olsson 	if(l) {
33519baf839SRobert Olsson 		NODE_INIT_PARENT(l, T_LEAF);
33619baf839SRobert Olsson 		INIT_HLIST_HEAD(&l->list);
33719baf839SRobert Olsson 	}
33819baf839SRobert Olsson 	return l;
33919baf839SRobert Olsson }
34019baf839SRobert Olsson 
34119baf839SRobert Olsson static struct leaf_info *leaf_info_new(int plen)
34219baf839SRobert Olsson {
34319baf839SRobert Olsson 	struct leaf_info *li = kmalloc(sizeof(struct leaf_info),  GFP_KERNEL);
34419baf839SRobert Olsson 	li->plen = plen;
34519baf839SRobert Olsson 	INIT_LIST_HEAD(&li->falh);
34619baf839SRobert Olsson 	return li;
34719baf839SRobert Olsson }
34819baf839SRobert Olsson 
34919baf839SRobert Olsson static inline void free_leaf(struct leaf *l)
35019baf839SRobert Olsson {
35119baf839SRobert Olsson 	kfree(l);
35219baf839SRobert Olsson }
35319baf839SRobert Olsson 
35419baf839SRobert Olsson static inline void free_leaf_info(struct leaf_info *li)
35519baf839SRobert Olsson {
35619baf839SRobert Olsson 	kfree(li);
35719baf839SRobert Olsson }
35819baf839SRobert Olsson 
35919baf839SRobert Olsson static struct tnode* tnode_new(t_key key, int pos, int bits)
36019baf839SRobert Olsson {
36119baf839SRobert Olsson 	int nchildren = 1<<bits;
36219baf839SRobert Olsson 	int sz = sizeof(struct tnode) + nchildren * sizeof(struct node *);
36319baf839SRobert Olsson 	struct tnode *tn = kmalloc(sz,  GFP_KERNEL);
36419baf839SRobert Olsson 
36519baf839SRobert Olsson 	if(tn)  {
36619baf839SRobert Olsson 		memset(tn, 0, sz);
36719baf839SRobert Olsson 		NODE_INIT_PARENT(tn, T_TNODE);
36819baf839SRobert Olsson 		tn->pos = pos;
36919baf839SRobert Olsson 		tn->bits = bits;
37019baf839SRobert Olsson 		tn->key = key;
37119baf839SRobert Olsson 		tn->full_children = 0;
37219baf839SRobert Olsson 		tn->empty_children = 1<<bits;
37319baf839SRobert Olsson 	}
37419baf839SRobert Olsson 	if(trie_debug > 0)
37519baf839SRobert Olsson 		printk("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode),
37619baf839SRobert Olsson 		       (unsigned int) (sizeof(struct node) * 1<<bits));
37719baf839SRobert Olsson 	return tn;
37819baf839SRobert Olsson }
37919baf839SRobert Olsson 
38019baf839SRobert Olsson static void tnode_free(struct tnode *tn)
38119baf839SRobert Olsson {
38219baf839SRobert Olsson 	if(!tn) {
38319baf839SRobert Olsson 		trie_bug("tnode_free\n");
38419baf839SRobert Olsson 	}
38519baf839SRobert Olsson 	if(IS_LEAF(tn)) {
38619baf839SRobert Olsson 		free_leaf((struct leaf *)tn);
38719baf839SRobert Olsson 		if(trie_debug > 0 )
38819baf839SRobert Olsson 			printk("FL %p \n", tn);
38919baf839SRobert Olsson 	}
39019baf839SRobert Olsson 	else if(IS_TNODE(tn)) {
39119baf839SRobert Olsson 		kfree(tn);
39219baf839SRobert Olsson 		if(trie_debug > 0 )
39319baf839SRobert Olsson 			printk("FT %p \n", tn);
39419baf839SRobert Olsson 	}
39519baf839SRobert Olsson 	else {
39619baf839SRobert Olsson 		trie_bug("tnode_free\n");
39719baf839SRobert Olsson 	}
39819baf839SRobert Olsson }
39919baf839SRobert Olsson 
40019baf839SRobert Olsson /*
40119baf839SRobert Olsson  * Check whether a tnode 'n' is "full", i.e. it is an internal node
40219baf839SRobert Olsson  * and no bits are skipped. See discussion in dyntree paper p. 6
40319baf839SRobert Olsson  */
40419baf839SRobert Olsson 
40519baf839SRobert Olsson static inline int tnode_full(struct tnode *tn, struct node *n)
40619baf839SRobert Olsson {
40719baf839SRobert Olsson 	if(n == NULL || IS_LEAF(n))
40819baf839SRobert Olsson 		return 0;
40919baf839SRobert Olsson 
41019baf839SRobert Olsson 	return ((struct tnode *) n)->pos == tn->pos + tn->bits;
41119baf839SRobert Olsson }
41219baf839SRobert Olsson 
41319baf839SRobert Olsson static inline void put_child(struct trie *t, struct tnode *tn, int i, struct node *n)
41419baf839SRobert Olsson {
41519baf839SRobert Olsson 	tnode_put_child_reorg(tn, i, n, -1);
41619baf839SRobert Olsson }
41719baf839SRobert Olsson 
41819baf839SRobert Olsson  /*
41919baf839SRobert Olsson   * Add a child at position i overwriting the old value.
42019baf839SRobert Olsson   * Update the value of full_children and empty_children.
42119baf839SRobert Olsson   */
42219baf839SRobert Olsson 
42319baf839SRobert Olsson static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull)
42419baf839SRobert Olsson {
42519baf839SRobert Olsson 	struct node *chi;
42619baf839SRobert Olsson 	int isfull;
42719baf839SRobert Olsson 
42819baf839SRobert Olsson 	if(i >=  1<<tn->bits) {
42919baf839SRobert Olsson 		printk("bits=%d, i=%d\n", tn->bits, i);
43019baf839SRobert Olsson 		trie_bug("tnode_put_child_reorg bits");
43119baf839SRobert Olsson 	}
43219baf839SRobert Olsson 	write_lock_bh(&fib_lock);
43319baf839SRobert Olsson 	chi = tn->child[i];
43419baf839SRobert Olsson 
43519baf839SRobert Olsson 	/* update emptyChildren */
43619baf839SRobert Olsson 	if (n == NULL && chi != NULL)
43719baf839SRobert Olsson 		tn->empty_children++;
43819baf839SRobert Olsson 	else if (n != NULL && chi == NULL)
43919baf839SRobert Olsson 		tn->empty_children--;
44019baf839SRobert Olsson 
44119baf839SRobert Olsson 	/* update fullChildren */
44219baf839SRobert Olsson         if (wasfull == -1)
44319baf839SRobert Olsson 		wasfull = tnode_full(tn, chi);
44419baf839SRobert Olsson 
44519baf839SRobert Olsson 	isfull = tnode_full(tn, n);
44619baf839SRobert Olsson 	if (wasfull && !isfull)
44719baf839SRobert Olsson 		tn->full_children--;
44819baf839SRobert Olsson 
44919baf839SRobert Olsson 	else if (!wasfull && isfull)
45019baf839SRobert Olsson 		tn->full_children++;
45119baf839SRobert Olsson 	if(n)
45219baf839SRobert Olsson 		NODE_SET_PARENT(n, tn);
45319baf839SRobert Olsson 
45419baf839SRobert Olsson 	tn->child[i] = n;
45519baf839SRobert Olsson 	write_unlock_bh(&fib_lock);
45619baf839SRobert Olsson }
45719baf839SRobert Olsson 
45819baf839SRobert Olsson static struct node *resize(struct trie *t, struct tnode *tn)
45919baf839SRobert Olsson {
46019baf839SRobert Olsson 	int i;
46119baf839SRobert Olsson 
46219baf839SRobert Olsson  	if (!tn)
46319baf839SRobert Olsson 		return NULL;
46419baf839SRobert Olsson 
46519baf839SRobert Olsson 	if(trie_debug)
46619baf839SRobert Olsson 		printk("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
46719baf839SRobert Olsson 		      tn, inflate_threshold, halve_threshold);
46819baf839SRobert Olsson 
46919baf839SRobert Olsson 	/* No children */
47019baf839SRobert Olsson 	if (tn->empty_children == tnode_child_length(tn)) {
47119baf839SRobert Olsson 		tnode_free(tn);
47219baf839SRobert Olsson 		return NULL;
47319baf839SRobert Olsson 	}
47419baf839SRobert Olsson 	/* One child */
47519baf839SRobert Olsson 	if (tn->empty_children == tnode_child_length(tn) - 1)
47619baf839SRobert Olsson 		for (i = 0; i < tnode_child_length(tn); i++) {
47719baf839SRobert Olsson 
47819baf839SRobert Olsson 			write_lock_bh(&fib_lock);
47919baf839SRobert Olsson 			if (tn->child[i] != NULL) {
48019baf839SRobert Olsson 
48119baf839SRobert Olsson 				/* compress one level */
48219baf839SRobert Olsson 				struct node *n = tn->child[i];
48319baf839SRobert Olsson 				if(n)
48419baf839SRobert Olsson 					NODE_INIT_PARENT(n, NODE_TYPE(n));
48519baf839SRobert Olsson 
48619baf839SRobert Olsson 				write_unlock_bh(&fib_lock);
48719baf839SRobert Olsson 				tnode_free(tn);
48819baf839SRobert Olsson 				return n;
48919baf839SRobert Olsson 			}
49019baf839SRobert Olsson 			write_unlock_bh(&fib_lock);
49119baf839SRobert Olsson 		}
49219baf839SRobert Olsson 	/*
49319baf839SRobert Olsson 	 * Double as long as the resulting node has a number of
49419baf839SRobert Olsson 	 * nonempty nodes that are above the threshold.
49519baf839SRobert Olsson 	 */
49619baf839SRobert Olsson 
49719baf839SRobert Olsson 	/*
49819baf839SRobert Olsson 	 * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
49919baf839SRobert Olsson 	 * the Helsinki University of Technology and Matti Tikkanen of Nokia
50019baf839SRobert Olsson 	 * Telecommunications, page 6:
50119baf839SRobert Olsson 	 * "A node is doubled if the ratio of non-empty children to all
50219baf839SRobert Olsson 	 * children in the *doubled* node is at least 'high'."
50319baf839SRobert Olsson 	 *
50419baf839SRobert Olsson 	 * 'high' in this instance is the variable 'inflate_threshold'. It
50519baf839SRobert Olsson 	 * is expressed as a percentage, so we multiply it with
50619baf839SRobert Olsson 	 * tnode_child_length() and instead of multiplying by 2 (since the
50719baf839SRobert Olsson 	 * child array will be doubled by inflate()) and multiplying
50819baf839SRobert Olsson 	 * the left-hand side by 100 (to handle the percentage thing) we
50919baf839SRobert Olsson 	 * multiply the left-hand side by 50.
51019baf839SRobert Olsson 	 *
51119baf839SRobert Olsson 	 * The left-hand side may look a bit weird: tnode_child_length(tn)
51219baf839SRobert Olsson 	 * - tn->empty_children is of course the number of non-null children
51319baf839SRobert Olsson 	 * in the current node. tn->full_children is the number of "full"
51419baf839SRobert Olsson 	 * children, that is non-null tnodes with a skip value of 0.
51519baf839SRobert Olsson 	 * All of those will be doubled in the resulting inflated tnode, so
51619baf839SRobert Olsson 	 * we just count them one extra time here.
51719baf839SRobert Olsson 	 *
51819baf839SRobert Olsson 	 * A clearer way to write this would be:
51919baf839SRobert Olsson 	 *
52019baf839SRobert Olsson 	 * to_be_doubled = tn->full_children;
52119baf839SRobert Olsson 	 * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
52219baf839SRobert Olsson 	 *     tn->full_children;
52319baf839SRobert Olsson 	 *
52419baf839SRobert Olsson 	 * new_child_length = tnode_child_length(tn) * 2;
52519baf839SRobert Olsson 	 *
52619baf839SRobert Olsson 	 * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
52719baf839SRobert Olsson 	 *      new_child_length;
52819baf839SRobert Olsson 	 * if (new_fill_factor >= inflate_threshold)
52919baf839SRobert Olsson 	 *
53019baf839SRobert Olsson 	 * ...and so on, tho it would mess up the while() loop.
53119baf839SRobert Olsson 	 *
53219baf839SRobert Olsson 	 * anyway,
53319baf839SRobert Olsson 	 * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
53419baf839SRobert Olsson 	 *      inflate_threshold
53519baf839SRobert Olsson 	 *
53619baf839SRobert Olsson 	 * avoid a division:
53719baf839SRobert Olsson 	 * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
53819baf839SRobert Olsson 	 *      inflate_threshold * new_child_length
53919baf839SRobert Olsson 	 *
54019baf839SRobert Olsson 	 * expand not_to_be_doubled and to_be_doubled, and shorten:
54119baf839SRobert Olsson 	 * 100 * (tnode_child_length(tn) - tn->empty_children +
54219baf839SRobert Olsson 	 *    tn->full_children ) >= inflate_threshold * new_child_length
54319baf839SRobert Olsson 	 *
54419baf839SRobert Olsson 	 * expand new_child_length:
54519baf839SRobert Olsson 	 * 100 * (tnode_child_length(tn) - tn->empty_children +
54619baf839SRobert Olsson 	 *    tn->full_children ) >=
54719baf839SRobert Olsson 	 *      inflate_threshold * tnode_child_length(tn) * 2
54819baf839SRobert Olsson 	 *
54919baf839SRobert Olsson 	 * shorten again:
55019baf839SRobert Olsson 	 * 50 * (tn->full_children + tnode_child_length(tn) -
55119baf839SRobert Olsson 	 *    tn->empty_children ) >= inflate_threshold *
55219baf839SRobert Olsson 	 *    tnode_child_length(tn)
55319baf839SRobert Olsson 	 *
55419baf839SRobert Olsson 	 */
55519baf839SRobert Olsson 
55619baf839SRobert Olsson 	check_tnode(tn);
55719baf839SRobert Olsson 
55819baf839SRobert Olsson 	while ((tn->full_children > 0 &&
55919baf839SRobert Olsson 	       50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
56019baf839SRobert Olsson 				inflate_threshold * tnode_child_length(tn))) {
56119baf839SRobert Olsson 
56219baf839SRobert Olsson 		tn = inflate(t, tn);
56319baf839SRobert Olsson 	}
56419baf839SRobert Olsson 
56519baf839SRobert Olsson 	check_tnode(tn);
56619baf839SRobert Olsson 
56719baf839SRobert Olsson 	/*
56819baf839SRobert Olsson 	 * Halve as long as the number of empty children in this
56919baf839SRobert Olsson 	 * node is above threshold.
57019baf839SRobert Olsson 	 */
57119baf839SRobert Olsson 	while (tn->bits > 1 &&
57219baf839SRobert Olsson 	       100 * (tnode_child_length(tn) - tn->empty_children) <
57319baf839SRobert Olsson 	       halve_threshold * tnode_child_length(tn))
57419baf839SRobert Olsson 
57519baf839SRobert Olsson 		tn = halve(t, tn);
57619baf839SRobert Olsson 
57719baf839SRobert Olsson 	/* Only one child remains */
57819baf839SRobert Olsson 
57919baf839SRobert Olsson 	if (tn->empty_children == tnode_child_length(tn) - 1)
58019baf839SRobert Olsson 		for (i = 0; i < tnode_child_length(tn); i++) {
58119baf839SRobert Olsson 
58219baf839SRobert Olsson 			write_lock_bh(&fib_lock);
58319baf839SRobert Olsson 			if (tn->child[i] != NULL) {
58419baf839SRobert Olsson 				/* compress one level */
58519baf839SRobert Olsson 				struct node *n = tn->child[i];
58619baf839SRobert Olsson 
58719baf839SRobert Olsson 				if(n)
58819baf839SRobert Olsson 					NODE_INIT_PARENT(n, NODE_TYPE(n));
58919baf839SRobert Olsson 
59019baf839SRobert Olsson 				write_unlock_bh(&fib_lock);
59119baf839SRobert Olsson 				tnode_free(tn);
59219baf839SRobert Olsson 				return n;
59319baf839SRobert Olsson 			}
59419baf839SRobert Olsson 			write_unlock_bh(&fib_lock);
59519baf839SRobert Olsson 		}
59619baf839SRobert Olsson 
59719baf839SRobert Olsson 	return (struct node *) tn;
59819baf839SRobert Olsson }
59919baf839SRobert Olsson 
60019baf839SRobert Olsson static struct tnode *inflate(struct trie *t, struct tnode *tn)
60119baf839SRobert Olsson {
60219baf839SRobert Olsson 	struct tnode *inode;
60319baf839SRobert Olsson 	struct tnode *oldtnode = tn;
60419baf839SRobert Olsson 	int olen = tnode_child_length(tn);
60519baf839SRobert Olsson 	int i;
60619baf839SRobert Olsson 
60719baf839SRobert Olsson   	if(trie_debug)
60819baf839SRobert Olsson 		printk("In inflate\n");
60919baf839SRobert Olsson 
61019baf839SRobert Olsson 	tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
61119baf839SRobert Olsson 
61219baf839SRobert Olsson 	if (!tn)
61319baf839SRobert Olsson 		trie_bug("tnode_new failed");
61419baf839SRobert Olsson 
61519baf839SRobert Olsson 	for(i = 0; i < olen; i++) {
61619baf839SRobert Olsson 		struct node *node = tnode_get_child(oldtnode, i);
61719baf839SRobert Olsson 
61819baf839SRobert Olsson 		/* An empty child */
61919baf839SRobert Olsson 		if (node == NULL)
62019baf839SRobert Olsson 			continue;
62119baf839SRobert Olsson 
62219baf839SRobert Olsson 		/* A leaf or an internal node with skipped bits */
62319baf839SRobert Olsson 
62419baf839SRobert Olsson 		if(IS_LEAF(node) || ((struct tnode *) node)->pos >
62519baf839SRobert Olsson 		   tn->pos + tn->bits - 1) {
62619baf839SRobert Olsson 			if(tkey_extract_bits(node->key, tn->pos + tn->bits - 1,
62719baf839SRobert Olsson 					     1) == 0)
62819baf839SRobert Olsson 				put_child(t, tn, 2*i, node);
62919baf839SRobert Olsson 			else
63019baf839SRobert Olsson 				put_child(t, tn, 2*i+1, node);
63119baf839SRobert Olsson 			continue;
63219baf839SRobert Olsson 		}
63319baf839SRobert Olsson 
63419baf839SRobert Olsson 		/* An internal node with two children */
63519baf839SRobert Olsson 		inode = (struct tnode *) node;
63619baf839SRobert Olsson 
63719baf839SRobert Olsson 		if (inode->bits == 1) {
63819baf839SRobert Olsson 			put_child(t, tn, 2*i, inode->child[0]);
63919baf839SRobert Olsson 			put_child(t, tn, 2*i+1, inode->child[1]);
64019baf839SRobert Olsson 
64119baf839SRobert Olsson 			tnode_free(inode);
64219baf839SRobert Olsson 		}
64319baf839SRobert Olsson 
64419baf839SRobert Olsson 			/* An internal node with more than two children */
64519baf839SRobert Olsson 		else {
64619baf839SRobert Olsson 			struct tnode *left, *right;
64719baf839SRobert Olsson 			int size, j;
64819baf839SRobert Olsson 
64919baf839SRobert Olsson 			/* We will replace this node 'inode' with two new
65019baf839SRobert Olsson 			 * ones, 'left' and 'right', each with half of the
65119baf839SRobert Olsson 			 * original children. The two new nodes will have
65219baf839SRobert Olsson 			 * a position one bit further down the key and this
65319baf839SRobert Olsson 			 * means that the "significant" part of their keys
65419baf839SRobert Olsson 			 * (see the discussion near the top of this file)
65519baf839SRobert Olsson 			 * will differ by one bit, which will be "0" in
65619baf839SRobert Olsson 			 * left's key and "1" in right's key. Since we are
65719baf839SRobert Olsson 			 * moving the key position by one step, the bit that
65819baf839SRobert Olsson 			 * we are moving away from - the bit at position
65919baf839SRobert Olsson 			 * (inode->pos) - is the one that will differ between
66019baf839SRobert Olsson 			 * left and right. So... we synthesize that bit in the
66119baf839SRobert Olsson 			 * two  new keys.
66219baf839SRobert Olsson 			 * The mask 'm' below will be a single "one" bit at
66319baf839SRobert Olsson 			 * the position (inode->pos)
66419baf839SRobert Olsson 			 */
66519baf839SRobert Olsson 
66619baf839SRobert Olsson 			t_key m = TKEY_GET_MASK(inode->pos, 1);
66719baf839SRobert Olsson 
66819baf839SRobert Olsson 			/* Use the old key, but set the new significant
66919baf839SRobert Olsson 			 *   bit to zero.
67019baf839SRobert Olsson 			 */
67119baf839SRobert Olsson 			left = tnode_new(inode->key&(~m), inode->pos + 1,
67219baf839SRobert Olsson 					 inode->bits - 1);
67319baf839SRobert Olsson 
67419baf839SRobert Olsson 			if(!left)
67519baf839SRobert Olsson 				trie_bug("tnode_new failed");
67619baf839SRobert Olsson 
67719baf839SRobert Olsson 
67819baf839SRobert Olsson 			/* Use the old key, but set the new significant
67919baf839SRobert Olsson 			 * bit to one.
68019baf839SRobert Olsson 			 */
68119baf839SRobert Olsson 			right = tnode_new(inode->key|m, inode->pos + 1,
68219baf839SRobert Olsson 					  inode->bits - 1);
68319baf839SRobert Olsson 
68419baf839SRobert Olsson 			if(!right)
68519baf839SRobert Olsson 				trie_bug("tnode_new failed");
68619baf839SRobert Olsson 
68719baf839SRobert Olsson 			size = tnode_child_length(left);
68819baf839SRobert Olsson 			for(j = 0; j < size; j++) {
68919baf839SRobert Olsson 				put_child(t, left, j, inode->child[j]);
69019baf839SRobert Olsson 				put_child(t, right, j, inode->child[j + size]);
69119baf839SRobert Olsson 			}
69219baf839SRobert Olsson 			put_child(t, tn, 2*i, resize(t, left));
69319baf839SRobert Olsson 			put_child(t, tn, 2*i+1, resize(t, right));
69419baf839SRobert Olsson 
69519baf839SRobert Olsson 			tnode_free(inode);
69619baf839SRobert Olsson 		}
69719baf839SRobert Olsson 	}
69819baf839SRobert Olsson 	tnode_free(oldtnode);
69919baf839SRobert Olsson 	return tn;
70019baf839SRobert Olsson }
70119baf839SRobert Olsson 
70219baf839SRobert Olsson static struct tnode *halve(struct trie *t, struct tnode *tn)
70319baf839SRobert Olsson {
70419baf839SRobert Olsson 	struct tnode *oldtnode = tn;
70519baf839SRobert Olsson 	struct node *left, *right;
70619baf839SRobert Olsson 	int i;
70719baf839SRobert Olsson 	int olen = tnode_child_length(tn);
70819baf839SRobert Olsson 
70919baf839SRobert Olsson 	if(trie_debug) printk("In halve\n");
71019baf839SRobert Olsson 
71119baf839SRobert Olsson 	tn=tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
71219baf839SRobert Olsson 
71319baf839SRobert Olsson 	if(!tn)
71419baf839SRobert Olsson 		trie_bug("tnode_new failed");
71519baf839SRobert Olsson 
71619baf839SRobert Olsson 	for(i = 0; i < olen; i += 2) {
71719baf839SRobert Olsson 		left = tnode_get_child(oldtnode, i);
71819baf839SRobert Olsson 		right = tnode_get_child(oldtnode, i+1);
71919baf839SRobert Olsson 
72019baf839SRobert Olsson 		/* At least one of the children is empty */
72119baf839SRobert Olsson 		if (left == NULL) {
72219baf839SRobert Olsson 			if (right == NULL)    /* Both are empty */
72319baf839SRobert Olsson 				continue;
72419baf839SRobert Olsson 			put_child(t, tn, i/2, right);
72519baf839SRobert Olsson 		} else if (right == NULL)
72619baf839SRobert Olsson 			put_child(t, tn, i/2, left);
72719baf839SRobert Olsson 
72819baf839SRobert Olsson 		/* Two nonempty children */
72919baf839SRobert Olsson 		else {
73019baf839SRobert Olsson 			struct tnode *newBinNode =
73119baf839SRobert Olsson 				tnode_new(left->key, tn->pos + tn->bits, 1);
73219baf839SRobert Olsson 
73319baf839SRobert Olsson 			if(!newBinNode)
73419baf839SRobert Olsson 				trie_bug("tnode_new failed");
73519baf839SRobert Olsson 
73619baf839SRobert Olsson 			put_child(t, newBinNode, 0, left);
73719baf839SRobert Olsson 			put_child(t, newBinNode, 1, right);
73819baf839SRobert Olsson 			put_child(t, tn, i/2, resize(t, newBinNode));
73919baf839SRobert Olsson 		}
74019baf839SRobert Olsson 	}
74119baf839SRobert Olsson 	tnode_free(oldtnode);
74219baf839SRobert Olsson 	return tn;
74319baf839SRobert Olsson }
74419baf839SRobert Olsson 
74519baf839SRobert Olsson static void *trie_init(struct trie *t)
74619baf839SRobert Olsson {
74719baf839SRobert Olsson 	if(t) {
74819baf839SRobert Olsson 		t->size = 0;
74919baf839SRobert Olsson 		t->trie = NULL;
75019baf839SRobert Olsson 		t->revision = 0;
75119baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
75219baf839SRobert Olsson        		memset(&t->stats, 0, sizeof(struct trie_use_stats));
75319baf839SRobert Olsson #endif
75419baf839SRobert Olsson 	}
75519baf839SRobert Olsson 	return t;
75619baf839SRobert Olsson }
75719baf839SRobert Olsson 
75819baf839SRobert Olsson static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen)
75919baf839SRobert Olsson {
76019baf839SRobert Olsson 	struct hlist_node *node;
76119baf839SRobert Olsson 	struct leaf_info *li;
76219baf839SRobert Olsson 
76319baf839SRobert Olsson 	hlist_for_each_entry(li, node, head, hlist) {
76419baf839SRobert Olsson 
76519baf839SRobert Olsson 		if ( li->plen == plen )
76619baf839SRobert Olsson 			return li;
76719baf839SRobert Olsson 	}
76819baf839SRobert Olsson 	return NULL;
76919baf839SRobert Olsson }
77019baf839SRobert Olsson 
77119baf839SRobert Olsson static inline struct list_head * get_fa_head(struct leaf *l, int plen)
77219baf839SRobert Olsson {
77319baf839SRobert Olsson 	struct list_head *fa_head=NULL;
77419baf839SRobert Olsson 	struct leaf_info *li = find_leaf_info(&l->list, plen);
77519baf839SRobert Olsson 
77619baf839SRobert Olsson 	if(li)
77719baf839SRobert Olsson 		fa_head = &li->falh;
77819baf839SRobert Olsson 
77919baf839SRobert Olsson 	return fa_head;
78019baf839SRobert Olsson }
78119baf839SRobert Olsson 
78219baf839SRobert Olsson static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new)
78319baf839SRobert Olsson {
78419baf839SRobert Olsson 	struct leaf_info *li=NULL, *last=NULL;
78519baf839SRobert Olsson 	struct hlist_node *node, *tmp;
78619baf839SRobert Olsson 
78719baf839SRobert Olsson 	write_lock_bh(&fib_lock);
78819baf839SRobert Olsson 
78919baf839SRobert Olsson 	if(hlist_empty(head))
79019baf839SRobert Olsson 		hlist_add_head(&new->hlist, head);
79119baf839SRobert Olsson 	else {
79219baf839SRobert Olsson 		hlist_for_each_entry_safe(li, node, tmp, head, hlist) {
79319baf839SRobert Olsson 
79419baf839SRobert Olsson 			if (new->plen > li->plen)
79519baf839SRobert Olsson 				break;
79619baf839SRobert Olsson 
79719baf839SRobert Olsson 			last = li;
79819baf839SRobert Olsson 		}
79919baf839SRobert Olsson 		if(last)
80019baf839SRobert Olsson 			hlist_add_after(&last->hlist, &new->hlist);
80119baf839SRobert Olsson 		else
80219baf839SRobert Olsson 			hlist_add_before(&new->hlist, &li->hlist);
80319baf839SRobert Olsson 	}
80419baf839SRobert Olsson 	write_unlock_bh(&fib_lock);
80519baf839SRobert Olsson }
80619baf839SRobert Olsson 
80719baf839SRobert Olsson static struct leaf *
80819baf839SRobert Olsson fib_find_node(struct trie *t, u32 key)
80919baf839SRobert Olsson {
81019baf839SRobert Olsson 	int pos;
81119baf839SRobert Olsson 	struct tnode *tn;
81219baf839SRobert Olsson 	struct node *n;
81319baf839SRobert Olsson 
81419baf839SRobert Olsson 	pos = 0;
81519baf839SRobert Olsson 	n=t->trie;
81619baf839SRobert Olsson 
81719baf839SRobert Olsson 	while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {
81819baf839SRobert Olsson 		tn = (struct tnode *) n;
81919baf839SRobert Olsson 
82019baf839SRobert Olsson 		check_tnode(tn);
82119baf839SRobert Olsson 
82219baf839SRobert Olsson 		if(tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
82319baf839SRobert Olsson 			pos=tn->pos + tn->bits;
82419baf839SRobert Olsson 			n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
82519baf839SRobert Olsson 		}
82619baf839SRobert Olsson 		else
82719baf839SRobert Olsson 			break;
82819baf839SRobert Olsson 	}
82919baf839SRobert Olsson 	/* Case we have found a leaf. Compare prefixes */
83019baf839SRobert Olsson 
83119baf839SRobert Olsson 	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
83219baf839SRobert Olsson 		struct leaf *l = (struct leaf *) n;
83319baf839SRobert Olsson 		return l;
83419baf839SRobert Olsson 	}
83519baf839SRobert Olsson 	return NULL;
83619baf839SRobert Olsson }
83719baf839SRobert Olsson 
83819baf839SRobert Olsson static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
83919baf839SRobert Olsson {
84019baf839SRobert Olsson 	int i = 0;
84119baf839SRobert Olsson 	int wasfull;
84219baf839SRobert Olsson 	t_key cindex, key;
84319baf839SRobert Olsson 	struct tnode *tp = NULL;
84419baf839SRobert Olsson 
84519baf839SRobert Olsson 	if(!tn)
84619baf839SRobert Olsson 		BUG();
84719baf839SRobert Olsson 
84819baf839SRobert Olsson 	key = tn->key;
84919baf839SRobert Olsson 	i = 0;
85019baf839SRobert Olsson 
85119baf839SRobert Olsson 	while (tn != NULL && NODE_PARENT(tn) != NULL) {
85219baf839SRobert Olsson 
85319baf839SRobert Olsson 		if( i > 10 ) {
85419baf839SRobert Olsson 			printk("Rebalance tn=%p \n", tn);
85519baf839SRobert Olsson 			if(tn) 		printk("tn->parent=%p \n", NODE_PARENT(tn));
85619baf839SRobert Olsson 
85719baf839SRobert Olsson 			printk("Rebalance tp=%p \n", tp);
85819baf839SRobert Olsson 			if(tp) 		printk("tp->parent=%p \n", NODE_PARENT(tp));
85919baf839SRobert Olsson 		}
86019baf839SRobert Olsson 
86119baf839SRobert Olsson 		if( i > 12 ) BUG();
86219baf839SRobert Olsson 		i++;
86319baf839SRobert Olsson 
86419baf839SRobert Olsson 		tp = NODE_PARENT(tn);
86519baf839SRobert Olsson 		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
86619baf839SRobert Olsson 		wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
86719baf839SRobert Olsson 		tn = (struct tnode *) resize (t, (struct tnode *)tn);
86819baf839SRobert Olsson 		tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull);
86919baf839SRobert Olsson 
87019baf839SRobert Olsson 		if(!NODE_PARENT(tn))
87119baf839SRobert Olsson 			break;
87219baf839SRobert Olsson 
87319baf839SRobert Olsson 		tn = NODE_PARENT(tn);
87419baf839SRobert Olsson 	}
87519baf839SRobert Olsson 	/* Handle last (top) tnode */
87619baf839SRobert Olsson 	if (IS_TNODE(tn))
87719baf839SRobert Olsson 		tn = (struct tnode*) resize(t, (struct tnode *)tn);
87819baf839SRobert Olsson 
87919baf839SRobert Olsson 	return (struct node*) tn;
88019baf839SRobert Olsson }
88119baf839SRobert Olsson 
88219baf839SRobert Olsson static struct list_head *
88319baf839SRobert Olsson fib_insert_node(struct trie *t, u32 key, int plen)
88419baf839SRobert Olsson {
88519baf839SRobert Olsson 	int pos, newpos;
88619baf839SRobert Olsson 	struct tnode *tp = NULL, *tn = NULL;
88719baf839SRobert Olsson 	struct node *n;
88819baf839SRobert Olsson 	struct leaf *l;
88919baf839SRobert Olsson 	int missbit;
89019baf839SRobert Olsson 	struct list_head *fa_head=NULL;
89119baf839SRobert Olsson 	struct leaf_info *li;
89219baf839SRobert Olsson 	t_key cindex;
89319baf839SRobert Olsson 
89419baf839SRobert Olsson 	pos = 0;
89519baf839SRobert Olsson 	n=t->trie;
89619baf839SRobert Olsson 
89719baf839SRobert Olsson 	/* If we point to NULL, stop. Either the tree is empty and we should
89819baf839SRobert Olsson 	 * just put a new leaf in if, or we have reached an empty child slot,
89919baf839SRobert Olsson 	 * and we should just put our new leaf in that.
90019baf839SRobert Olsson 	 * If we point to a T_TNODE, check if it matches our key. Note that
90119baf839SRobert Olsson 	 * a T_TNODE might be skipping any number of bits - its 'pos' need
90219baf839SRobert Olsson 	 * not be the parent's 'pos'+'bits'!
90319baf839SRobert Olsson 	 *
90419baf839SRobert Olsson 	 * If it does match the current key, get pos/bits from it, extract
90519baf839SRobert Olsson 	 * the index from our key, push the T_TNODE and walk the tree.
90619baf839SRobert Olsson 	 *
90719baf839SRobert Olsson 	 * If it doesn't, we have to replace it with a new T_TNODE.
90819baf839SRobert Olsson 	 *
90919baf839SRobert Olsson 	 * If we point to a T_LEAF, it might or might not have the same key
91019baf839SRobert Olsson 	 * as we do. If it does, just change the value, update the T_LEAF's
91119baf839SRobert Olsson 	 * value, and return it.
91219baf839SRobert Olsson 	 * If it doesn't, we need to replace it with a T_TNODE.
91319baf839SRobert Olsson 	 */
91419baf839SRobert Olsson 
91519baf839SRobert Olsson 	while (n != NULL &&  NODE_TYPE(n) == T_TNODE) {
91619baf839SRobert Olsson 		tn = (struct tnode *) n;
91719baf839SRobert Olsson 
91819baf839SRobert Olsson 		check_tnode(tn);
91919baf839SRobert Olsson 
92019baf839SRobert Olsson 		if(tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
92119baf839SRobert Olsson 			tp = tn;
92219baf839SRobert Olsson 			pos=tn->pos + tn->bits;
92319baf839SRobert Olsson 			n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
92419baf839SRobert Olsson 
92519baf839SRobert Olsson 			if(n && NODE_PARENT(n) != tn) {
92619baf839SRobert Olsson 				printk("BUG tn=%p, n->parent=%p\n", tn, NODE_PARENT(n));
92719baf839SRobert Olsson 				BUG();
92819baf839SRobert Olsson 			}
92919baf839SRobert Olsson 		}
93019baf839SRobert Olsson 		else
93119baf839SRobert Olsson 			break;
93219baf839SRobert Olsson 	}
93319baf839SRobert Olsson 
93419baf839SRobert Olsson 	/*
93519baf839SRobert Olsson 	 * n  ----> NULL, LEAF or TNODE
93619baf839SRobert Olsson 	 *
93719baf839SRobert Olsson 	 * tp is n's (parent) ----> NULL or TNODE
93819baf839SRobert Olsson 	 */
93919baf839SRobert Olsson 
94019baf839SRobert Olsson 	if(tp && IS_LEAF(tp))
94119baf839SRobert Olsson 		BUG();
94219baf839SRobert Olsson 
94319baf839SRobert Olsson 	t->revision++;
94419baf839SRobert Olsson 
94519baf839SRobert Olsson 	/* Case 1: n is a leaf. Compare prefixes */
94619baf839SRobert Olsson 
94719baf839SRobert Olsson 	if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
94819baf839SRobert Olsson 		struct leaf *l = ( struct leaf *)  n;
94919baf839SRobert Olsson 
95019baf839SRobert Olsson 		li = leaf_info_new(plen);
95119baf839SRobert Olsson 
95219baf839SRobert Olsson 		if(! li)
95319baf839SRobert Olsson 			BUG();
95419baf839SRobert Olsson 
95519baf839SRobert Olsson 		fa_head = &li->falh;
95619baf839SRobert Olsson 		insert_leaf_info(&l->list, li);
95719baf839SRobert Olsson 		goto done;
95819baf839SRobert Olsson 	}
95919baf839SRobert Olsson 	t->size++;
96019baf839SRobert Olsson 	l = leaf_new();
96119baf839SRobert Olsson 
96219baf839SRobert Olsson 	if(! l)
96319baf839SRobert Olsson 		BUG();
96419baf839SRobert Olsson 
96519baf839SRobert Olsson 	l->key = key;
96619baf839SRobert Olsson 	li = leaf_info_new(plen);
96719baf839SRobert Olsson 
96819baf839SRobert Olsson 	if(! li)
96919baf839SRobert Olsson 		BUG();
97019baf839SRobert Olsson 
97119baf839SRobert Olsson 	fa_head = &li->falh;
97219baf839SRobert Olsson 	insert_leaf_info(&l->list, li);
97319baf839SRobert Olsson 
97419baf839SRobert Olsson 	/* Case 2: n is NULL, and will just insert a new leaf */
97519baf839SRobert Olsson 	if (t->trie && n == NULL) {
97619baf839SRobert Olsson 
97719baf839SRobert Olsson 		NODE_SET_PARENT(l, tp);
97819baf839SRobert Olsson 
97919baf839SRobert Olsson 		if (!tp)
98019baf839SRobert Olsson 			BUG();
98119baf839SRobert Olsson 
98219baf839SRobert Olsson 		else {
98319baf839SRobert Olsson 			cindex = tkey_extract_bits(key, tp->pos, tp->bits);
98419baf839SRobert Olsson 			put_child(t, (struct tnode *)tp, cindex, (struct node *)l);
98519baf839SRobert Olsson 		}
98619baf839SRobert Olsson 	}
98719baf839SRobert Olsson 	/* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
98819baf839SRobert Olsson 	else {
98919baf839SRobert Olsson 		/*
99019baf839SRobert Olsson 		 *  Add a new tnode here
99119baf839SRobert Olsson 		 *  first tnode need some special handling
99219baf839SRobert Olsson 		 */
99319baf839SRobert Olsson 
99419baf839SRobert Olsson 		if (tp)
99519baf839SRobert Olsson 			pos=tp->pos+tp->bits;
99619baf839SRobert Olsson 		else
99719baf839SRobert Olsson 			pos=0;
99819baf839SRobert Olsson 		if(n) {
99919baf839SRobert Olsson 			newpos = tkey_mismatch(key, pos, n->key);
100019baf839SRobert Olsson 			tn = tnode_new(n->key, newpos, 1);
100119baf839SRobert Olsson 		}
100219baf839SRobert Olsson 		else {
100319baf839SRobert Olsson 			newpos = 0;
100419baf839SRobert Olsson 			tn = tnode_new(key, newpos, 1); /* First tnode */
100519baf839SRobert Olsson 		}
100619baf839SRobert Olsson 		if(!tn)
100719baf839SRobert Olsson 			trie_bug("tnode_pfx_new failed");
100819baf839SRobert Olsson 
100919baf839SRobert Olsson 		NODE_SET_PARENT(tn, tp);
101019baf839SRobert Olsson 
101119baf839SRobert Olsson 		missbit=tkey_extract_bits(key, newpos, 1);
101219baf839SRobert Olsson 		put_child(t, tn, missbit, (struct node *)l);
101319baf839SRobert Olsson 		put_child(t, tn, 1-missbit, n);
101419baf839SRobert Olsson 
101519baf839SRobert Olsson 		if(tp) {
101619baf839SRobert Olsson 			cindex = tkey_extract_bits(key, tp->pos, tp->bits);
101719baf839SRobert Olsson 			put_child(t, (struct tnode *)tp, cindex, (struct node *)tn);
101819baf839SRobert Olsson 		}
101919baf839SRobert Olsson 		else {
102019baf839SRobert Olsson 			t->trie = (struct node*) tn; /* First tnode */
102119baf839SRobert Olsson 			tp = tn;
102219baf839SRobert Olsson 		}
102319baf839SRobert Olsson 	}
102419baf839SRobert Olsson 	if(tp && tp->pos+tp->bits > 32) {
102519baf839SRobert Olsson 		printk("ERROR tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
102619baf839SRobert Olsson 		       tp, tp->pos, tp->bits, key, plen);
102719baf839SRobert Olsson 	}
102819baf839SRobert Olsson 	/* Rebalance the trie */
102919baf839SRobert Olsson 	t->trie = trie_rebalance(t, tp);
103019baf839SRobert Olsson done:;
103119baf839SRobert Olsson 	return fa_head;
103219baf839SRobert Olsson }
103319baf839SRobert Olsson 
103419baf839SRobert Olsson static int
103519baf839SRobert Olsson fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
103619baf839SRobert Olsson 	       struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
103719baf839SRobert Olsson {
103819baf839SRobert Olsson 	struct trie *t = (struct trie *) tb->tb_data;
103919baf839SRobert Olsson 	struct fib_alias *fa, *new_fa;
104019baf839SRobert Olsson 	struct list_head *fa_head=NULL;
104119baf839SRobert Olsson 	struct fib_info *fi;
104219baf839SRobert Olsson 	int plen = r->rtm_dst_len;
104319baf839SRobert Olsson 	int type = r->rtm_type;
104419baf839SRobert Olsson 	u8 tos = r->rtm_tos;
104519baf839SRobert Olsson 	u32 key, mask;
104619baf839SRobert Olsson 	int err;
104719baf839SRobert Olsson 	struct leaf *l;
104819baf839SRobert Olsson 
104919baf839SRobert Olsson 	if (plen > 32)
105019baf839SRobert Olsson 		return -EINVAL;
105119baf839SRobert Olsson 
105219baf839SRobert Olsson 	key = 0;
105319baf839SRobert Olsson 	if (rta->rta_dst)
105419baf839SRobert Olsson 		memcpy(&key, rta->rta_dst, 4);
105519baf839SRobert Olsson 
105619baf839SRobert Olsson 	key = ntohl(key);
105719baf839SRobert Olsson 
105819baf839SRobert Olsson 	if(trie_debug)
105919baf839SRobert Olsson 		printk("Insert table=%d %08x/%d\n", tb->tb_id, key, plen);
106019baf839SRobert Olsson 
106119baf839SRobert Olsson 	mask =  ntohl( inet_make_mask(plen) );
106219baf839SRobert Olsson 
106319baf839SRobert Olsson 	if(key & ~mask)
106419baf839SRobert Olsson 		return -EINVAL;
106519baf839SRobert Olsson 
106619baf839SRobert Olsson 	key = key & mask;
106719baf839SRobert Olsson 
106819baf839SRobert Olsson 	if  ((fi = fib_create_info(r, rta, nlhdr, &err)) == NULL)
106919baf839SRobert Olsson 		goto err;
107019baf839SRobert Olsson 
107119baf839SRobert Olsson 	l = fib_find_node(t, key);
107219baf839SRobert Olsson 	fa = NULL;
107319baf839SRobert Olsson 
107419baf839SRobert Olsson 	if(l) {
107519baf839SRobert Olsson 		fa_head = get_fa_head(l, plen);
107619baf839SRobert Olsson 		fa = fib_find_alias(fa_head, tos, fi->fib_priority);
107719baf839SRobert Olsson 	}
107819baf839SRobert Olsson 
107919baf839SRobert Olsson 	/* Now fa, if non-NULL, points to the first fib alias
108019baf839SRobert Olsson 	 * with the same keys [prefix,tos,priority], if such key already
108119baf839SRobert Olsson 	 * exists or to the node before which we will insert new one.
108219baf839SRobert Olsson 	 *
108319baf839SRobert Olsson 	 * If fa is NULL, we will need to allocate a new one and
108419baf839SRobert Olsson 	 * insert to the head of f.
108519baf839SRobert Olsson 	 *
108619baf839SRobert Olsson 	 * If f is NULL, no fib node matched the destination key
108719baf839SRobert Olsson 	 * and we need to allocate a new one of those as well.
108819baf839SRobert Olsson 	 */
108919baf839SRobert Olsson 
109019baf839SRobert Olsson 	if (fa &&
109119baf839SRobert Olsson 	    fa->fa_info->fib_priority == fi->fib_priority) {
109219baf839SRobert Olsson 		struct fib_alias *fa_orig;
109319baf839SRobert Olsson 
109419baf839SRobert Olsson 		err = -EEXIST;
109519baf839SRobert Olsson 		if (nlhdr->nlmsg_flags & NLM_F_EXCL)
109619baf839SRobert Olsson 			goto out;
109719baf839SRobert Olsson 
109819baf839SRobert Olsson 		if (nlhdr->nlmsg_flags & NLM_F_REPLACE) {
109919baf839SRobert Olsson 			struct fib_info *fi_drop;
110019baf839SRobert Olsson 			u8 state;
110119baf839SRobert Olsson 
110219baf839SRobert Olsson 			write_lock_bh(&fib_lock);
110319baf839SRobert Olsson 
110419baf839SRobert Olsson 			fi_drop = fa->fa_info;
110519baf839SRobert Olsson 			fa->fa_info = fi;
110619baf839SRobert Olsson 			fa->fa_type = type;
110719baf839SRobert Olsson 			fa->fa_scope = r->rtm_scope;
110819baf839SRobert Olsson 			state = fa->fa_state;
110919baf839SRobert Olsson 			fa->fa_state &= ~FA_S_ACCESSED;
111019baf839SRobert Olsson 
111119baf839SRobert Olsson 			write_unlock_bh(&fib_lock);
111219baf839SRobert Olsson 
111319baf839SRobert Olsson 			fib_release_info(fi_drop);
111419baf839SRobert Olsson 			if (state & FA_S_ACCESSED)
111519baf839SRobert Olsson 			  rt_cache_flush(-1);
111619baf839SRobert Olsson 
111719baf839SRobert Olsson 			    goto succeeded;
111819baf839SRobert Olsson 		}
111919baf839SRobert Olsson 		/* Error if we find a perfect match which
112019baf839SRobert Olsson 		 * uses the same scope, type, and nexthop
112119baf839SRobert Olsson 		 * information.
112219baf839SRobert Olsson 		 */
112319baf839SRobert Olsson 		fa_orig = fa;
112419baf839SRobert Olsson 		list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) {
112519baf839SRobert Olsson 			if (fa->fa_tos != tos)
112619baf839SRobert Olsson 				break;
112719baf839SRobert Olsson 			if (fa->fa_info->fib_priority != fi->fib_priority)
112819baf839SRobert Olsson 				break;
112919baf839SRobert Olsson 			if (fa->fa_type == type &&
113019baf839SRobert Olsson 			    fa->fa_scope == r->rtm_scope &&
113119baf839SRobert Olsson 			    fa->fa_info == fi) {
113219baf839SRobert Olsson 				goto out;
113319baf839SRobert Olsson 			}
113419baf839SRobert Olsson 		}
113519baf839SRobert Olsson 		if (!(nlhdr->nlmsg_flags & NLM_F_APPEND))
113619baf839SRobert Olsson 			fa = fa_orig;
113719baf839SRobert Olsson 	}
113819baf839SRobert Olsson 	err = -ENOENT;
113919baf839SRobert Olsson 	if (!(nlhdr->nlmsg_flags&NLM_F_CREATE))
114019baf839SRobert Olsson 		goto out;
114119baf839SRobert Olsson 
114219baf839SRobert Olsson 	err = -ENOBUFS;
114319baf839SRobert Olsson 	new_fa = kmem_cache_alloc(fn_alias_kmem, SLAB_KERNEL);
114419baf839SRobert Olsson 	if (new_fa == NULL)
114519baf839SRobert Olsson 		goto out;
114619baf839SRobert Olsson 
114719baf839SRobert Olsson 	new_fa->fa_info = fi;
114819baf839SRobert Olsson 	new_fa->fa_tos = tos;
114919baf839SRobert Olsson 	new_fa->fa_type = type;
115019baf839SRobert Olsson 	new_fa->fa_scope = r->rtm_scope;
115119baf839SRobert Olsson 	new_fa->fa_state = 0;
115219baf839SRobert Olsson #if 0
115319baf839SRobert Olsson 	new_fa->dst  = NULL;
115419baf839SRobert Olsson #endif
115519baf839SRobert Olsson 	/*
115619baf839SRobert Olsson 	 * Insert new entry to the list.
115719baf839SRobert Olsson 	 */
115819baf839SRobert Olsson 
115919baf839SRobert Olsson 	if(!fa_head)
116019baf839SRobert Olsson 		fa_head = fib_insert_node(t, key, plen);
116119baf839SRobert Olsson 
116219baf839SRobert Olsson 	write_lock_bh(&fib_lock);
116319baf839SRobert Olsson 
116419baf839SRobert Olsson 	list_add_tail(&new_fa->fa_list,
116519baf839SRobert Olsson 		 (fa ? &fa->fa_list : fa_head));
116619baf839SRobert Olsson 
116719baf839SRobert Olsson 	write_unlock_bh(&fib_lock);
116819baf839SRobert Olsson 
116919baf839SRobert Olsson 	rt_cache_flush(-1);
117019baf839SRobert Olsson 	rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req);
117119baf839SRobert Olsson succeeded:
117219baf839SRobert Olsson 	return 0;
117319baf839SRobert Olsson out:
117419baf839SRobert Olsson 	fib_release_info(fi);
117519baf839SRobert Olsson err:;
117619baf839SRobert Olsson 	return err;
117719baf839SRobert Olsson }
117819baf839SRobert Olsson 
117919baf839SRobert Olsson static inline int check_leaf(struct trie *t, struct leaf *l,  t_key key, int *plen, const struct flowi *flp,
118019baf839SRobert Olsson 			     struct fib_result *res, int *err)
118119baf839SRobert Olsson {
118219baf839SRobert Olsson 	int i;
118319baf839SRobert Olsson 	t_key mask;
118419baf839SRobert Olsson 	struct leaf_info *li;
118519baf839SRobert Olsson 	struct hlist_head *hhead = &l->list;
118619baf839SRobert Olsson 	struct hlist_node *node;
118719baf839SRobert Olsson 
118819baf839SRobert Olsson 	hlist_for_each_entry(li, node, hhead, hlist) {
118919baf839SRobert Olsson 
119019baf839SRobert Olsson 		i = li->plen;
119119baf839SRobert Olsson 		mask = ntohl(inet_make_mask(i));
119219baf839SRobert Olsson 		if (l->key != (key & mask))
119319baf839SRobert Olsson 			continue;
119419baf839SRobert Olsson 
119519baf839SRobert Olsson 		if (((*err) = fib_semantic_match(&li->falh, flp, res, l->key, mask, i)) == 0) {
119619baf839SRobert Olsson 			*plen = i;
119719baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
119819baf839SRobert Olsson 			t->stats.semantic_match_passed++;
119919baf839SRobert Olsson #endif
120019baf839SRobert Olsson 			return 1;
120119baf839SRobert Olsson 		}
120219baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
120319baf839SRobert Olsson 		t->stats.semantic_match_miss++;
120419baf839SRobert Olsson #endif
120519baf839SRobert Olsson 	}
120619baf839SRobert Olsson 	return 0;
120719baf839SRobert Olsson }
120819baf839SRobert Olsson 
120919baf839SRobert Olsson static int
121019baf839SRobert Olsson fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
121119baf839SRobert Olsson {
121219baf839SRobert Olsson 	struct trie *t = (struct trie *) tb->tb_data;
121319baf839SRobert Olsson 	int plen, ret = 0;
121419baf839SRobert Olsson 	struct node *n;
121519baf839SRobert Olsson 	struct tnode *pn;
121619baf839SRobert Olsson 	int pos, bits;
121719baf839SRobert Olsson 	t_key key=ntohl(flp->fl4_dst);
121819baf839SRobert Olsson 	int chopped_off;
121919baf839SRobert Olsson 	t_key cindex = 0;
122019baf839SRobert Olsson 	int current_prefix_length = KEYLENGTH;
122119baf839SRobert Olsson 	n = t->trie;
122219baf839SRobert Olsson 
122319baf839SRobert Olsson 	read_lock(&fib_lock);
122419baf839SRobert Olsson 	if(!n)
122519baf839SRobert Olsson 		goto failed;
122619baf839SRobert Olsson 
122719baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
122819baf839SRobert Olsson 	t->stats.gets++;
122919baf839SRobert Olsson #endif
123019baf839SRobert Olsson 
123119baf839SRobert Olsson 	/* Just a leaf? */
123219baf839SRobert Olsson 	if (IS_LEAF(n)) {
123319baf839SRobert Olsson 		if( check_leaf(t, (struct leaf *)n, key, &plen, flp, res, &ret) )
123419baf839SRobert Olsson 			goto found;
123519baf839SRobert Olsson 		goto failed;
123619baf839SRobert Olsson 	}
123719baf839SRobert Olsson 	pn = (struct tnode *) n;
123819baf839SRobert Olsson 	chopped_off = 0;
123919baf839SRobert Olsson 
124019baf839SRobert Olsson         while (pn) {
124119baf839SRobert Olsson 
124219baf839SRobert Olsson 		pos = pn->pos;
124319baf839SRobert Olsson 		bits = pn->bits;
124419baf839SRobert Olsson 
124519baf839SRobert Olsson 		if(!chopped_off)
124619baf839SRobert Olsson 			cindex = tkey_extract_bits(MASK_PFX(key, current_prefix_length), pos, bits);
124719baf839SRobert Olsson 
124819baf839SRobert Olsson 		n = tnode_get_child(pn, cindex);
124919baf839SRobert Olsson 
125019baf839SRobert Olsson 		if (n == NULL) {
125119baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
125219baf839SRobert Olsson 			t->stats.null_node_hit++;
125319baf839SRobert Olsson #endif
125419baf839SRobert Olsson 			goto backtrace;
125519baf839SRobert Olsson 		}
125619baf839SRobert Olsson 
125719baf839SRobert Olsson 		if (IS_TNODE(n)) {
125819baf839SRobert Olsson #define HL_OPTIMIZE
125919baf839SRobert Olsson #ifdef HL_OPTIMIZE
126019baf839SRobert Olsson 			struct tnode *cn = (struct tnode *)n;
126119baf839SRobert Olsson 			t_key node_prefix, key_prefix, pref_mismatch;
126219baf839SRobert Olsson 			int mp;
126319baf839SRobert Olsson 
126419baf839SRobert Olsson 			/*
126519baf839SRobert Olsson 			 * It's a tnode, and we can do some extra checks here if we
126619baf839SRobert Olsson 			 * like, to avoid descending into a dead-end branch.
126719baf839SRobert Olsson 			 * This tnode is in the parent's child array at index
126819baf839SRobert Olsson 			 * key[p_pos..p_pos+p_bits] but potentially with some bits
126919baf839SRobert Olsson 			 * chopped off, so in reality the index may be just a
127019baf839SRobert Olsson 			 * subprefix, padded with zero at the end.
127119baf839SRobert Olsson 			 * We can also take a look at any skipped bits in this
127219baf839SRobert Olsson 			 * tnode - everything up to p_pos is supposed to be ok,
127319baf839SRobert Olsson 			 * and the non-chopped bits of the index (se previous
127419baf839SRobert Olsson 			 * paragraph) are also guaranteed ok, but the rest is
127519baf839SRobert Olsson 			 * considered unknown.
127619baf839SRobert Olsson 			 *
127719baf839SRobert Olsson 			 * The skipped bits are key[pos+bits..cn->pos].
127819baf839SRobert Olsson 			 */
127919baf839SRobert Olsson 
128019baf839SRobert Olsson 			/* If current_prefix_length < pos+bits, we are already doing
128119baf839SRobert Olsson 			 * actual prefix  matching, which means everything from
128219baf839SRobert Olsson 			 * pos+(bits-chopped_off) onward must be zero along some
128319baf839SRobert Olsson 			 * branch of this subtree - otherwise there is *no* valid
128419baf839SRobert Olsson 			 * prefix present. Here we can only check the skipped
128519baf839SRobert Olsson 			 * bits. Remember, since we have already indexed into the
128619baf839SRobert Olsson 			 * parent's child array, we know that the bits we chopped of
128719baf839SRobert Olsson 			 * *are* zero.
128819baf839SRobert Olsson 			 */
128919baf839SRobert Olsson 
129019baf839SRobert Olsson 			/* NOTA BENE: CHECKING ONLY SKIPPED BITS FOR THE NEW NODE HERE */
129119baf839SRobert Olsson 
129219baf839SRobert Olsson 			if (current_prefix_length < pos+bits) {
129319baf839SRobert Olsson 				if (tkey_extract_bits(cn->key, current_prefix_length,
129419baf839SRobert Olsson 						      cn->pos - current_prefix_length) != 0 ||
129519baf839SRobert Olsson 				    !(cn->child[0]))
129619baf839SRobert Olsson 					goto backtrace;
129719baf839SRobert Olsson 			}
129819baf839SRobert Olsson 
129919baf839SRobert Olsson 			/*
130019baf839SRobert Olsson 			 * If chopped_off=0, the index is fully validated and we
130119baf839SRobert Olsson 			 * only need to look at the skipped bits for this, the new,
130219baf839SRobert Olsson 			 * tnode. What we actually want to do is to find out if
130319baf839SRobert Olsson 			 * these skipped bits match our key perfectly, or if we will
130419baf839SRobert Olsson 			 * have to count on finding a matching prefix further down,
130519baf839SRobert Olsson 			 * because if we do, we would like to have some way of
130619baf839SRobert Olsson 			 * verifying the existence of such a prefix at this point.
130719baf839SRobert Olsson 			 */
130819baf839SRobert Olsson 
130919baf839SRobert Olsson 			/* The only thing we can do at this point is to verify that
131019baf839SRobert Olsson 			 * any such matching prefix can indeed be a prefix to our
131119baf839SRobert Olsson 			 * key, and if the bits in the node we are inspecting that
131219baf839SRobert Olsson 			 * do not match our key are not ZERO, this cannot be true.
131319baf839SRobert Olsson 			 * Thus, find out where there is a mismatch (before cn->pos)
131419baf839SRobert Olsson 			 * and verify that all the mismatching bits are zero in the
131519baf839SRobert Olsson 			 * new tnode's key.
131619baf839SRobert Olsson 			 */
131719baf839SRobert Olsson 
131819baf839SRobert Olsson 			/* Note: We aren't very concerned about the piece of the key
131919baf839SRobert Olsson 			 * that precede pn->pos+pn->bits, since these have already been
132019baf839SRobert Olsson 			 * checked. The bits after cn->pos aren't checked since these are
132119baf839SRobert Olsson 			 * by definition "unknown" at this point. Thus, what we want to
132219baf839SRobert Olsson 			 * see is if we are about to enter the "prefix matching" state,
132319baf839SRobert Olsson 			 * and in that case verify that the skipped bits that will prevail
132419baf839SRobert Olsson 			 * throughout this subtree are zero, as they have to be if we are
132519baf839SRobert Olsson 			 * to find a matching prefix.
132619baf839SRobert Olsson 			 */
132719baf839SRobert Olsson 
132819baf839SRobert Olsson 			node_prefix = MASK_PFX(cn->key, cn->pos);
132919baf839SRobert Olsson 			key_prefix =  MASK_PFX(key, cn->pos);
133019baf839SRobert Olsson 			pref_mismatch = key_prefix^node_prefix;
133119baf839SRobert Olsson 			mp = 0;
133219baf839SRobert Olsson 
133319baf839SRobert Olsson 			/* In short: If skipped bits in this node do not match the search
133419baf839SRobert Olsson 			 * key, enter the "prefix matching" state.directly.
133519baf839SRobert Olsson 			 */
133619baf839SRobert Olsson 			if (pref_mismatch) {
133719baf839SRobert Olsson 				while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
133819baf839SRobert Olsson 					mp++;
133919baf839SRobert Olsson 					pref_mismatch = pref_mismatch <<1;
134019baf839SRobert Olsson 				}
134119baf839SRobert Olsson 				key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
134219baf839SRobert Olsson 
134319baf839SRobert Olsson 				if (key_prefix != 0)
134419baf839SRobert Olsson 					goto backtrace;
134519baf839SRobert Olsson 
134619baf839SRobert Olsson 				if (current_prefix_length >= cn->pos)
134719baf839SRobert Olsson 					current_prefix_length=mp;
134819baf839SRobert Olsson 		       }
134919baf839SRobert Olsson #endif
135019baf839SRobert Olsson 		       pn = (struct tnode *)n; /* Descend */
135119baf839SRobert Olsson 		       chopped_off = 0;
135219baf839SRobert Olsson 		       continue;
135319baf839SRobert Olsson 		}
135419baf839SRobert Olsson 		if (IS_LEAF(n)) {
135519baf839SRobert Olsson 			if( check_leaf(t, (struct leaf *)n, key, &plen, flp, res, &ret))
135619baf839SRobert Olsson 				goto found;
135719baf839SRobert Olsson 	       }
135819baf839SRobert Olsson backtrace:
135919baf839SRobert Olsson 		chopped_off++;
136019baf839SRobert Olsson 
136119baf839SRobert Olsson 		/* As zero don't change the child key (cindex) */
136219baf839SRobert Olsson 		while ((chopped_off <= pn->bits) && !(cindex & (1<<(chopped_off-1)))) {
136319baf839SRobert Olsson 			chopped_off++;
136419baf839SRobert Olsson 		}
136519baf839SRobert Olsson 
136619baf839SRobert Olsson 		/* Decrease current_... with bits chopped off */
136719baf839SRobert Olsson 		if (current_prefix_length > pn->pos + pn->bits - chopped_off)
136819baf839SRobert Olsson 			current_prefix_length = pn->pos + pn->bits - chopped_off;
136919baf839SRobert Olsson 
137019baf839SRobert Olsson 		/*
137119baf839SRobert Olsson 		 * Either we do the actual chop off according or if we have
137219baf839SRobert Olsson 		 * chopped off all bits in this tnode walk up to our parent.
137319baf839SRobert Olsson 		 */
137419baf839SRobert Olsson 
137519baf839SRobert Olsson 		if(chopped_off <= pn->bits)
137619baf839SRobert Olsson 			cindex &= ~(1 << (chopped_off-1));
137719baf839SRobert Olsson 		else {
137819baf839SRobert Olsson 			if( NODE_PARENT(pn) == NULL)
137919baf839SRobert Olsson 				goto failed;
138019baf839SRobert Olsson 
138119baf839SRobert Olsson 			/* Get Child's index */
138219baf839SRobert Olsson 			cindex = tkey_extract_bits(pn->key, NODE_PARENT(pn)->pos, NODE_PARENT(pn)->bits);
138319baf839SRobert Olsson 			pn = NODE_PARENT(pn);
138419baf839SRobert Olsson 			chopped_off = 0;
138519baf839SRobert Olsson 
138619baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
138719baf839SRobert Olsson 			t->stats.backtrack++;
138819baf839SRobert Olsson #endif
138919baf839SRobert Olsson 			goto backtrace;
139019baf839SRobert Olsson 		}
139119baf839SRobert Olsson 	}
139219baf839SRobert Olsson failed:
139319baf839SRobert Olsson 	ret =  1;
139419baf839SRobert Olsson found:
139519baf839SRobert Olsson 	read_unlock(&fib_lock);
139619baf839SRobert Olsson 	return ret;
139719baf839SRobert Olsson }
139819baf839SRobert Olsson 
139919baf839SRobert Olsson static int trie_leaf_remove(struct trie *t, t_key key)
140019baf839SRobert Olsson {
140119baf839SRobert Olsson 	t_key cindex;
140219baf839SRobert Olsson 	struct tnode *tp = NULL;
140319baf839SRobert Olsson 	struct node *n = t->trie;
140419baf839SRobert Olsson 	struct leaf *l;
140519baf839SRobert Olsson 
140619baf839SRobert Olsson 	if(trie_debug)
140719baf839SRobert Olsson 		printk("entering trie_leaf_remove(%p)\n", n);
140819baf839SRobert Olsson 
140919baf839SRobert Olsson 	/* Note that in the case skipped bits, those bits are *not* checked!
141019baf839SRobert Olsson 	 * When we finish this, we will have NULL or a T_LEAF, and the
141119baf839SRobert Olsson 	 * T_LEAF may or may not match our key.
141219baf839SRobert Olsson 	 */
141319baf839SRobert Olsson 
141419baf839SRobert Olsson         while (n != NULL && IS_TNODE(n)) {
141519baf839SRobert Olsson 		struct tnode *tn = (struct tnode *) n;
141619baf839SRobert Olsson 		check_tnode(tn);
141719baf839SRobert Olsson 		n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits));
141819baf839SRobert Olsson 
141919baf839SRobert Olsson 			if(n && NODE_PARENT(n) != tn) {
142019baf839SRobert Olsson 				printk("BUG tn=%p, n->parent=%p\n", tn, NODE_PARENT(n));
142119baf839SRobert Olsson 				BUG();
142219baf839SRobert Olsson 			}
142319baf839SRobert Olsson         }
142419baf839SRobert Olsson 	l = (struct leaf *) n;
142519baf839SRobert Olsson 
142619baf839SRobert Olsson 	if(!n || !tkey_equals(l->key, key))
142719baf839SRobert Olsson 		return 0;
142819baf839SRobert Olsson 
142919baf839SRobert Olsson 	/*
143019baf839SRobert Olsson 	 * Key found.
143119baf839SRobert Olsson 	 * Remove the leaf and rebalance the tree
143219baf839SRobert Olsson 	 */
143319baf839SRobert Olsson 
143419baf839SRobert Olsson 	t->revision++;
143519baf839SRobert Olsson 	t->size--;
143619baf839SRobert Olsson 
143719baf839SRobert Olsson 	tp = NODE_PARENT(n);
143819baf839SRobert Olsson 	tnode_free((struct tnode *) n);
143919baf839SRobert Olsson 
144019baf839SRobert Olsson 	if(tp) {
144119baf839SRobert Olsson 		cindex = tkey_extract_bits(key, tp->pos, tp->bits);
144219baf839SRobert Olsson 		put_child(t, (struct tnode *)tp, cindex, NULL);
144319baf839SRobert Olsson 		t->trie = trie_rebalance(t, tp);
144419baf839SRobert Olsson 	}
144519baf839SRobert Olsson 	else
144619baf839SRobert Olsson 		t->trie = NULL;
144719baf839SRobert Olsson 
144819baf839SRobert Olsson 	return 1;
144919baf839SRobert Olsson }
145019baf839SRobert Olsson 
145119baf839SRobert Olsson static int
145219baf839SRobert Olsson fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
145319baf839SRobert Olsson 	       struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
145419baf839SRobert Olsson {
145519baf839SRobert Olsson 	struct trie *t = (struct trie *) tb->tb_data;
145619baf839SRobert Olsson 	u32 key, mask;
145719baf839SRobert Olsson 	int plen = r->rtm_dst_len;
145819baf839SRobert Olsson 	u8 tos = r->rtm_tos;
145919baf839SRobert Olsson 	struct fib_alias *fa, *fa_to_delete;
146019baf839SRobert Olsson 	struct list_head *fa_head;
146119baf839SRobert Olsson 	struct leaf *l;
146219baf839SRobert Olsson 
146319baf839SRobert Olsson 	if (plen > 32)
146419baf839SRobert Olsson 		return -EINVAL;
146519baf839SRobert Olsson 
146619baf839SRobert Olsson 	key = 0;
146719baf839SRobert Olsson 	if (rta->rta_dst)
146819baf839SRobert Olsson 		memcpy(&key, rta->rta_dst, 4);
146919baf839SRobert Olsson 
147019baf839SRobert Olsson 	key = ntohl(key);
147119baf839SRobert Olsson 	mask =  ntohl( inet_make_mask(plen) );
147219baf839SRobert Olsson 
147319baf839SRobert Olsson 	if(key & ~mask)
147419baf839SRobert Olsson 		return -EINVAL;
147519baf839SRobert Olsson 
147619baf839SRobert Olsson 	key = key & mask;
147719baf839SRobert Olsson 	l = fib_find_node(t, key);
147819baf839SRobert Olsson 
147919baf839SRobert Olsson 	if(!l)
148019baf839SRobert Olsson 		return -ESRCH;
148119baf839SRobert Olsson 
148219baf839SRobert Olsson 	fa_head = get_fa_head(l, plen);
148319baf839SRobert Olsson 	fa = fib_find_alias(fa_head, tos, 0);
148419baf839SRobert Olsson 
148519baf839SRobert Olsson 	if (!fa)
148619baf839SRobert Olsson 		return -ESRCH;
148719baf839SRobert Olsson 
148819baf839SRobert Olsson 	if (trie_debug)
148919baf839SRobert Olsson 		printk("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
149019baf839SRobert Olsson 
149119baf839SRobert Olsson 	fa_to_delete = NULL;
149219baf839SRobert Olsson 	fa_head = fa->fa_list.prev;
149319baf839SRobert Olsson 	list_for_each_entry(fa, fa_head, fa_list) {
149419baf839SRobert Olsson 		struct fib_info *fi = fa->fa_info;
149519baf839SRobert Olsson 
149619baf839SRobert Olsson 		if (fa->fa_tos != tos)
149719baf839SRobert Olsson 			break;
149819baf839SRobert Olsson 
149919baf839SRobert Olsson 		if ((!r->rtm_type ||
150019baf839SRobert Olsson 		     fa->fa_type == r->rtm_type) &&
150119baf839SRobert Olsson 		    (r->rtm_scope == RT_SCOPE_NOWHERE ||
150219baf839SRobert Olsson 		     fa->fa_scope == r->rtm_scope) &&
150319baf839SRobert Olsson 		    (!r->rtm_protocol ||
150419baf839SRobert Olsson 		     fi->fib_protocol == r->rtm_protocol) &&
150519baf839SRobert Olsson 		    fib_nh_match(r, nlhdr, rta, fi) == 0) {
150619baf839SRobert Olsson 			fa_to_delete = fa;
150719baf839SRobert Olsson 			break;
150819baf839SRobert Olsson 		}
150919baf839SRobert Olsson 	}
151019baf839SRobert Olsson 
151119baf839SRobert Olsson 	if (fa_to_delete) {
151219baf839SRobert Olsson 		int kill_li = 0;
151319baf839SRobert Olsson 		struct leaf_info *li;
151419baf839SRobert Olsson 
151519baf839SRobert Olsson 		fa = fa_to_delete;
151619baf839SRobert Olsson 		rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);
151719baf839SRobert Olsson 
151819baf839SRobert Olsson 		l = fib_find_node(t, key);
151919baf839SRobert Olsson 		li = find_leaf_info(&l->list, plen);
152019baf839SRobert Olsson 
152119baf839SRobert Olsson 		write_lock_bh(&fib_lock);
152219baf839SRobert Olsson 
152319baf839SRobert Olsson 		list_del(&fa->fa_list);
152419baf839SRobert Olsson 
152519baf839SRobert Olsson 		if(list_empty(fa_head)) {
152619baf839SRobert Olsson 			hlist_del(&li->hlist);
152719baf839SRobert Olsson 			kill_li = 1;
152819baf839SRobert Olsson 		}
152919baf839SRobert Olsson 		write_unlock_bh(&fib_lock);
153019baf839SRobert Olsson 
153119baf839SRobert Olsson 		if(kill_li)
153219baf839SRobert Olsson 			free_leaf_info(li);
153319baf839SRobert Olsson 
153419baf839SRobert Olsson 		if(hlist_empty(&l->list))
153519baf839SRobert Olsson 			trie_leaf_remove(t, key);
153619baf839SRobert Olsson 
153719baf839SRobert Olsson 		if (fa->fa_state & FA_S_ACCESSED)
153819baf839SRobert Olsson 			rt_cache_flush(-1);
153919baf839SRobert Olsson 
154019baf839SRobert Olsson 		fn_free_alias(fa);
154119baf839SRobert Olsson 		return 0;
154219baf839SRobert Olsson 	}
154319baf839SRobert Olsson 	return -ESRCH;
154419baf839SRobert Olsson }
154519baf839SRobert Olsson 
154619baf839SRobert Olsson static int trie_flush_list(struct trie *t, struct list_head *head)
154719baf839SRobert Olsson {
154819baf839SRobert Olsson 	struct fib_alias *fa, *fa_node;
154919baf839SRobert Olsson 	int found = 0;
155019baf839SRobert Olsson 
155119baf839SRobert Olsson 	list_for_each_entry_safe(fa, fa_node, head, fa_list) {
155219baf839SRobert Olsson 		struct fib_info *fi = fa->fa_info;
155319baf839SRobert Olsson 
155419baf839SRobert Olsson 		if (fi && (fi->fib_flags&RTNH_F_DEAD)) {
155519baf839SRobert Olsson 
155619baf839SRobert Olsson  			write_lock_bh(&fib_lock);
155719baf839SRobert Olsson 			list_del(&fa->fa_list);
155819baf839SRobert Olsson 			write_unlock_bh(&fib_lock);
155919baf839SRobert Olsson 
156019baf839SRobert Olsson 			fn_free_alias(fa);
156119baf839SRobert Olsson 			found++;
156219baf839SRobert Olsson 		}
156319baf839SRobert Olsson 	}
156419baf839SRobert Olsson 	return found;
156519baf839SRobert Olsson }
156619baf839SRobert Olsson 
156719baf839SRobert Olsson static int trie_flush_leaf(struct trie *t, struct leaf *l)
156819baf839SRobert Olsson {
156919baf839SRobert Olsson 	int found = 0;
157019baf839SRobert Olsson 	struct hlist_head *lih = &l->list;
157119baf839SRobert Olsson 	struct hlist_node *node, *tmp;
157219baf839SRobert Olsson 	struct leaf_info *li = NULL;
157319baf839SRobert Olsson 
157419baf839SRobert Olsson 	hlist_for_each_entry_safe(li, node, tmp, lih, hlist) {
157519baf839SRobert Olsson 
157619baf839SRobert Olsson 		found += trie_flush_list(t, &li->falh);
157719baf839SRobert Olsson 
157819baf839SRobert Olsson 		if (list_empty(&li->falh)) {
157919baf839SRobert Olsson 
158019baf839SRobert Olsson  			write_lock_bh(&fib_lock);
158119baf839SRobert Olsson 			hlist_del(&li->hlist);
158219baf839SRobert Olsson 			write_unlock_bh(&fib_lock);
158319baf839SRobert Olsson 
158419baf839SRobert Olsson 			free_leaf_info(li);
158519baf839SRobert Olsson 		}
158619baf839SRobert Olsson 	}
158719baf839SRobert Olsson 	return found;
158819baf839SRobert Olsson }
158919baf839SRobert Olsson 
159019baf839SRobert Olsson static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
159119baf839SRobert Olsson {
159219baf839SRobert Olsson 	struct node *c = (struct node *) thisleaf;
159319baf839SRobert Olsson 	struct tnode *p;
159419baf839SRobert Olsson 	int idx;
159519baf839SRobert Olsson 
159619baf839SRobert Olsson 	if(c == NULL) {
159719baf839SRobert Olsson 		if(t->trie == NULL)
159819baf839SRobert Olsson 			return NULL;
159919baf839SRobert Olsson 
160019baf839SRobert Olsson 		if (IS_LEAF(t->trie))          /* trie w. just a leaf */
160119baf839SRobert Olsson 			return (struct leaf *) t->trie;
160219baf839SRobert Olsson 
160319baf839SRobert Olsson 		p = (struct tnode*) t->trie;  /* Start */
160419baf839SRobert Olsson 	}
160519baf839SRobert Olsson 	else
160619baf839SRobert Olsson 		p = (struct tnode *) NODE_PARENT(c);
160719baf839SRobert Olsson 	while (p) {
160819baf839SRobert Olsson 		int pos, last;
160919baf839SRobert Olsson 
161019baf839SRobert Olsson 		/*  Find the next child of the parent */
161119baf839SRobert Olsson 		if(c)
161219baf839SRobert Olsson 			pos  = 1 + tkey_extract_bits(c->key, p->pos, p->bits);
161319baf839SRobert Olsson 		else
161419baf839SRobert Olsson 			pos = 0;
161519baf839SRobert Olsson 
161619baf839SRobert Olsson 		last = 1 << p->bits;
161719baf839SRobert Olsson 		for(idx = pos; idx < last ; idx++) {
161819baf839SRobert Olsson 			if( p->child[idx]) {
161919baf839SRobert Olsson 
162019baf839SRobert Olsson 				/* Decend if tnode */
162119baf839SRobert Olsson 
162219baf839SRobert Olsson 				while (IS_TNODE(p->child[idx])) {
162319baf839SRobert Olsson 					p = (struct tnode*) p->child[idx];
162419baf839SRobert Olsson 					idx = 0;
162519baf839SRobert Olsson 
162619baf839SRobert Olsson 					/* Rightmost non-NULL branch */
162719baf839SRobert Olsson 					if( p && IS_TNODE(p) )
162819baf839SRobert Olsson 						while ( p->child[idx] == NULL && idx < (1 << p->bits) ) idx++;
162919baf839SRobert Olsson 
163019baf839SRobert Olsson 					/* Done with this tnode? */
163119baf839SRobert Olsson 					if( idx >= (1 << p->bits) || p->child[idx] == NULL )
163219baf839SRobert Olsson 						goto up;
163319baf839SRobert Olsson 				}
163419baf839SRobert Olsson 				return (struct leaf*) p->child[idx];
163519baf839SRobert Olsson 			}
163619baf839SRobert Olsson 		}
163719baf839SRobert Olsson up:
163819baf839SRobert Olsson 		/* No more children go up one step  */
163919baf839SRobert Olsson 		c = (struct node*) p;
164019baf839SRobert Olsson 		p = (struct tnode *) NODE_PARENT(p);
164119baf839SRobert Olsson 	}
164219baf839SRobert Olsson 	return NULL; /* Ready. Root of trie */
164319baf839SRobert Olsson }
164419baf839SRobert Olsson 
164519baf839SRobert Olsson static int fn_trie_flush(struct fib_table *tb)
164619baf839SRobert Olsson {
164719baf839SRobert Olsson 	struct trie *t = (struct trie *) tb->tb_data;
164819baf839SRobert Olsson 	struct leaf *ll = NULL, *l = NULL;
164919baf839SRobert Olsson 	int found = 0, h;
165019baf839SRobert Olsson 
165119baf839SRobert Olsson 	t->revision++;
165219baf839SRobert Olsson 
165319baf839SRobert Olsson 	for (h=0; (l = nextleaf(t, l)) != NULL; h++) {
165419baf839SRobert Olsson 		found += trie_flush_leaf(t, l);
165519baf839SRobert Olsson 
165619baf839SRobert Olsson 		if (ll && hlist_empty(&ll->list))
165719baf839SRobert Olsson 			trie_leaf_remove(t, ll->key);
165819baf839SRobert Olsson 		ll = l;
165919baf839SRobert Olsson 	}
166019baf839SRobert Olsson 
166119baf839SRobert Olsson 	if (ll && hlist_empty(&ll->list))
166219baf839SRobert Olsson 		trie_leaf_remove(t, ll->key);
166319baf839SRobert Olsson 
166419baf839SRobert Olsson 	if(trie_debug)
166519baf839SRobert Olsson 		printk("trie_flush found=%d\n", found);
166619baf839SRobert Olsson 	return found;
166719baf839SRobert Olsson }
166819baf839SRobert Olsson 
166919baf839SRobert Olsson static int trie_last_dflt=-1;
167019baf839SRobert Olsson 
167119baf839SRobert Olsson static void
167219baf839SRobert Olsson fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
167319baf839SRobert Olsson {
167419baf839SRobert Olsson 	struct trie *t = (struct trie *) tb->tb_data;
167519baf839SRobert Olsson 	int order, last_idx;
167619baf839SRobert Olsson 	struct fib_info *fi = NULL;
167719baf839SRobert Olsson 	struct fib_info *last_resort;
167819baf839SRobert Olsson 	struct fib_alias *fa = NULL;
167919baf839SRobert Olsson 	struct list_head *fa_head;
168019baf839SRobert Olsson 	struct leaf *l;
168119baf839SRobert Olsson 
168219baf839SRobert Olsson 	last_idx = -1;
168319baf839SRobert Olsson 	last_resort = NULL;
168419baf839SRobert Olsson 	order = -1;
168519baf839SRobert Olsson 
168619baf839SRobert Olsson 	read_lock(&fib_lock);
168719baf839SRobert Olsson 
168819baf839SRobert Olsson 	l = fib_find_node(t, 0);
168919baf839SRobert Olsson 	if(!l)
169019baf839SRobert Olsson 		goto out;
169119baf839SRobert Olsson 
169219baf839SRobert Olsson 	fa_head = get_fa_head(l, 0);
169319baf839SRobert Olsson 	if(!fa_head)
169419baf839SRobert Olsson 		goto out;
169519baf839SRobert Olsson 
169619baf839SRobert Olsson 	if (list_empty(fa_head))
169719baf839SRobert Olsson 		goto out;
169819baf839SRobert Olsson 
169919baf839SRobert Olsson 	list_for_each_entry(fa, fa_head, fa_list) {
170019baf839SRobert Olsson 		struct fib_info *next_fi = fa->fa_info;
170119baf839SRobert Olsson 
170219baf839SRobert Olsson 		if (fa->fa_scope != res->scope ||
170319baf839SRobert Olsson 		    fa->fa_type != RTN_UNICAST)
170419baf839SRobert Olsson 			continue;
170519baf839SRobert Olsson 
170619baf839SRobert Olsson 		if (next_fi->fib_priority > res->fi->fib_priority)
170719baf839SRobert Olsson 			break;
170819baf839SRobert Olsson 		if (!next_fi->fib_nh[0].nh_gw ||
170919baf839SRobert Olsson 		    next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
171019baf839SRobert Olsson 			continue;
171119baf839SRobert Olsson 		fa->fa_state |= FA_S_ACCESSED;
171219baf839SRobert Olsson 
171319baf839SRobert Olsson 		if (fi == NULL) {
171419baf839SRobert Olsson 			if (next_fi != res->fi)
171519baf839SRobert Olsson 				break;
171619baf839SRobert Olsson 		} else if (!fib_detect_death(fi, order, &last_resort,
171719baf839SRobert Olsson 					     &last_idx, &trie_last_dflt)) {
171819baf839SRobert Olsson 			if (res->fi)
171919baf839SRobert Olsson 				fib_info_put(res->fi);
172019baf839SRobert Olsson 			res->fi = fi;
172119baf839SRobert Olsson 			atomic_inc(&fi->fib_clntref);
172219baf839SRobert Olsson 			trie_last_dflt = order;
172319baf839SRobert Olsson 			goto out;
172419baf839SRobert Olsson 		}
172519baf839SRobert Olsson 		fi = next_fi;
172619baf839SRobert Olsson 		order++;
172719baf839SRobert Olsson 	}
172819baf839SRobert Olsson 	if (order <= 0 || fi == NULL) {
172919baf839SRobert Olsson 		trie_last_dflt = -1;
173019baf839SRobert Olsson 		goto out;
173119baf839SRobert Olsson 	}
173219baf839SRobert Olsson 
173319baf839SRobert Olsson 	if (!fib_detect_death(fi, order, &last_resort, &last_idx, &trie_last_dflt)) {
173419baf839SRobert Olsson 		if (res->fi)
173519baf839SRobert Olsson 			fib_info_put(res->fi);
173619baf839SRobert Olsson 		res->fi = fi;
173719baf839SRobert Olsson 		atomic_inc(&fi->fib_clntref);
173819baf839SRobert Olsson 		trie_last_dflt = order;
173919baf839SRobert Olsson 		goto out;
174019baf839SRobert Olsson 	}
174119baf839SRobert Olsson 	if (last_idx >= 0) {
174219baf839SRobert Olsson 		if (res->fi)
174319baf839SRobert Olsson 			fib_info_put(res->fi);
174419baf839SRobert Olsson 		res->fi = last_resort;
174519baf839SRobert Olsson 		if (last_resort)
174619baf839SRobert Olsson 			atomic_inc(&last_resort->fib_clntref);
174719baf839SRobert Olsson 	}
174819baf839SRobert Olsson 	trie_last_dflt = last_idx;
174919baf839SRobert Olsson  out:;
175019baf839SRobert Olsson 	read_unlock(&fib_lock);
175119baf839SRobert Olsson }
175219baf839SRobert Olsson 
175319baf839SRobert Olsson static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fib_table *tb,
175419baf839SRobert Olsson 			   struct sk_buff *skb, struct netlink_callback *cb)
175519baf839SRobert Olsson {
175619baf839SRobert Olsson 	int i, s_i;
175719baf839SRobert Olsson 	struct fib_alias *fa;
175819baf839SRobert Olsson 
175919baf839SRobert Olsson 	u32 xkey=htonl(key);
176019baf839SRobert Olsson 
176119baf839SRobert Olsson 	s_i=cb->args[3];
176219baf839SRobert Olsson 	i = 0;
176319baf839SRobert Olsson 
176419baf839SRobert Olsson 	list_for_each_entry(fa, fah, fa_list) {
176519baf839SRobert Olsson 		if (i < s_i) {
176619baf839SRobert Olsson 			i++;
176719baf839SRobert Olsson 			continue;
176819baf839SRobert Olsson 		}
176919baf839SRobert Olsson 		if (fa->fa_info->fib_nh == NULL) {
177019baf839SRobert Olsson 			printk("Trie error _fib_nh=NULL in fa[%d] k=%08x plen=%d\n", i, key, plen);
177119baf839SRobert Olsson 			i++;
177219baf839SRobert Olsson 			continue;
177319baf839SRobert Olsson 		}
177419baf839SRobert Olsson 		if (fa->fa_info == NULL) {
177519baf839SRobert Olsson 			printk("Trie error fa_info=NULL in fa[%d] k=%08x plen=%d\n", i, key, plen);
177619baf839SRobert Olsson 			i++;
177719baf839SRobert Olsson 			continue;
177819baf839SRobert Olsson 		}
177919baf839SRobert Olsson 
178019baf839SRobert Olsson 		if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
178119baf839SRobert Olsson 				  cb->nlh->nlmsg_seq,
178219baf839SRobert Olsson 				  RTM_NEWROUTE,
178319baf839SRobert Olsson 				  tb->tb_id,
178419baf839SRobert Olsson 				  fa->fa_type,
178519baf839SRobert Olsson 				  fa->fa_scope,
178619baf839SRobert Olsson 				  &xkey,
178719baf839SRobert Olsson 				  plen,
178819baf839SRobert Olsson 				  fa->fa_tos,
178990f66914SDavid S. Miller 				  fa->fa_info, 0) < 0) {
179019baf839SRobert Olsson 			cb->args[3] = i;
179119baf839SRobert Olsson 			return -1;
179219baf839SRobert Olsson 			}
179319baf839SRobert Olsson 		i++;
179419baf839SRobert Olsson 	}
179519baf839SRobert Olsson 	cb->args[3]=i;
179619baf839SRobert Olsson 	return skb->len;
179719baf839SRobert Olsson }
179819baf839SRobert Olsson 
179919baf839SRobert Olsson static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, struct sk_buff *skb,
180019baf839SRobert Olsson 			     struct netlink_callback *cb)
180119baf839SRobert Olsson {
180219baf839SRobert Olsson 	int h, s_h;
180319baf839SRobert Olsson 	struct list_head *fa_head;
180419baf839SRobert Olsson 	struct leaf *l = NULL;
180519baf839SRobert Olsson 	s_h=cb->args[2];
180619baf839SRobert Olsson 
180719baf839SRobert Olsson 	for (h=0; (l = nextleaf(t, l)) != NULL; h++) {
180819baf839SRobert Olsson 
180919baf839SRobert Olsson 		if (h < s_h)
181019baf839SRobert Olsson 			continue;
181119baf839SRobert Olsson 		if (h > s_h)
181219baf839SRobert Olsson 			memset(&cb->args[3], 0,
181319baf839SRobert Olsson 			       sizeof(cb->args) - 3*sizeof(cb->args[0]));
181419baf839SRobert Olsson 
181519baf839SRobert Olsson 		fa_head = get_fa_head(l, plen);
181619baf839SRobert Olsson 
181719baf839SRobert Olsson 		if(!fa_head)
181819baf839SRobert Olsson 			continue;
181919baf839SRobert Olsson 
182019baf839SRobert Olsson 		if(list_empty(fa_head))
182119baf839SRobert Olsson 			continue;
182219baf839SRobert Olsson 
182319baf839SRobert Olsson 		if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
182419baf839SRobert Olsson 			cb->args[2]=h;
182519baf839SRobert Olsson 			return -1;
182619baf839SRobert Olsson 		}
182719baf839SRobert Olsson 	}
182819baf839SRobert Olsson 	cb->args[2]=h;
182919baf839SRobert Olsson 	return skb->len;
183019baf839SRobert Olsson }
183119baf839SRobert Olsson 
183219baf839SRobert Olsson static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb)
183319baf839SRobert Olsson {
183419baf839SRobert Olsson 	int m, s_m;
183519baf839SRobert Olsson 	struct trie *t = (struct trie *) tb->tb_data;
183619baf839SRobert Olsson 
183719baf839SRobert Olsson 	s_m = cb->args[1];
183819baf839SRobert Olsson 
183919baf839SRobert Olsson 	read_lock(&fib_lock);
184019baf839SRobert Olsson 	for (m=0; m<=32; m++) {
184119baf839SRobert Olsson 
184219baf839SRobert Olsson 		if (m < s_m)
184319baf839SRobert Olsson 			continue;
184419baf839SRobert Olsson 		if (m > s_m)
184519baf839SRobert Olsson 			memset(&cb->args[2], 0,
184619baf839SRobert Olsson 			       sizeof(cb->args) - 2*sizeof(cb->args[0]));
184719baf839SRobert Olsson 
184819baf839SRobert Olsson 		if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
184919baf839SRobert Olsson 			cb->args[1] = m;
185019baf839SRobert Olsson 			goto out;
185119baf839SRobert Olsson 		}
185219baf839SRobert Olsson 	}
185319baf839SRobert Olsson 	read_unlock(&fib_lock);
185419baf839SRobert Olsson 	cb->args[1] = m;
185519baf839SRobert Olsson 	return skb->len;
185619baf839SRobert Olsson  out:
185719baf839SRobert Olsson 	read_unlock(&fib_lock);
185819baf839SRobert Olsson 	return -1;
185919baf839SRobert Olsson }
186019baf839SRobert Olsson 
186119baf839SRobert Olsson /* Fix more generic FIB names for init later */
186219baf839SRobert Olsson 
186319baf839SRobert Olsson #ifdef CONFIG_IP_MULTIPLE_TABLES
186419baf839SRobert Olsson struct fib_table * fib_hash_init(int id)
186519baf839SRobert Olsson #else
186619baf839SRobert Olsson struct fib_table * __init fib_hash_init(int id)
186719baf839SRobert Olsson #endif
186819baf839SRobert Olsson {
186919baf839SRobert Olsson 	struct fib_table *tb;
187019baf839SRobert Olsson 	struct trie *t;
187119baf839SRobert Olsson 
187219baf839SRobert Olsson 	if (fn_alias_kmem == NULL)
187319baf839SRobert Olsson 		fn_alias_kmem = kmem_cache_create("ip_fib_alias",
187419baf839SRobert Olsson 						  sizeof(struct fib_alias),
187519baf839SRobert Olsson 						  0, SLAB_HWCACHE_ALIGN,
187619baf839SRobert Olsson 						  NULL, NULL);
187719baf839SRobert Olsson 
187819baf839SRobert Olsson 	tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie),
187919baf839SRobert Olsson 		     GFP_KERNEL);
188019baf839SRobert Olsson 	if (tb == NULL)
188119baf839SRobert Olsson 		return NULL;
188219baf839SRobert Olsson 
188319baf839SRobert Olsson 	tb->tb_id = id;
188419baf839SRobert Olsson 	tb->tb_lookup = fn_trie_lookup;
188519baf839SRobert Olsson 	tb->tb_insert = fn_trie_insert;
188619baf839SRobert Olsson 	tb->tb_delete = fn_trie_delete;
188719baf839SRobert Olsson 	tb->tb_flush = fn_trie_flush;
188819baf839SRobert Olsson 	tb->tb_select_default = fn_trie_select_default;
188919baf839SRobert Olsson 	tb->tb_dump = fn_trie_dump;
189019baf839SRobert Olsson 	memset(tb->tb_data, 0, sizeof(struct trie));
189119baf839SRobert Olsson 
189219baf839SRobert Olsson 	t = (struct trie *) tb->tb_data;
189319baf839SRobert Olsson 
189419baf839SRobert Olsson 	trie_init(t);
189519baf839SRobert Olsson 
189619baf839SRobert Olsson 	if (id == RT_TABLE_LOCAL)
189719baf839SRobert Olsson                 trie_local=t;
189819baf839SRobert Olsson 	  else if (id == RT_TABLE_MAIN)
189919baf839SRobert Olsson                 trie_main=t;
190019baf839SRobert Olsson 
190119baf839SRobert Olsson 	if (id == RT_TABLE_LOCAL)
190219baf839SRobert Olsson 		printk("IPv4 FIB: Using LC-trie version %s\n", VERSION);
190319baf839SRobert Olsson 
190419baf839SRobert Olsson 	return tb;
190519baf839SRobert Olsson }
190619baf839SRobert Olsson 
190719baf839SRobert Olsson /* Trie dump functions */
190819baf839SRobert Olsson 
190919baf839SRobert Olsson static void putspace_seq(struct seq_file *seq, int n)
191019baf839SRobert Olsson {
191119baf839SRobert Olsson 	while (n--) seq_printf(seq, " ");
191219baf839SRobert Olsson }
191319baf839SRobert Olsson 
191419baf839SRobert Olsson static void printbin_seq(struct seq_file *seq, unsigned int v, int bits)
191519baf839SRobert Olsson {
191619baf839SRobert Olsson 	while (bits--)
191719baf839SRobert Olsson 		seq_printf(seq, "%s", (v & (1<<bits))?"1":"0");
191819baf839SRobert Olsson }
191919baf839SRobert Olsson 
192019baf839SRobert Olsson static void printnode_seq(struct seq_file *seq, int indent, struct node *n,
192119baf839SRobert Olsson 		   int pend, int cindex, int bits)
192219baf839SRobert Olsson {
192319baf839SRobert Olsson 	putspace_seq(seq, indent);
192419baf839SRobert Olsson 	if (IS_LEAF(n))
192519baf839SRobert Olsson 		seq_printf(seq, "|");
192619baf839SRobert Olsson 	else
192719baf839SRobert Olsson 		seq_printf(seq, "+");
192819baf839SRobert Olsson 	if (bits) {
192919baf839SRobert Olsson 		seq_printf(seq, "%d/", cindex);
193019baf839SRobert Olsson 		printbin_seq(seq, cindex, bits);
193119baf839SRobert Olsson 		seq_printf(seq, ": ");
193219baf839SRobert Olsson 	}
193319baf839SRobert Olsson 	else
193419baf839SRobert Olsson 		seq_printf(seq, "<root>: ");
193519baf839SRobert Olsson 	seq_printf(seq, "%s:%p ", IS_LEAF(n)?"Leaf":"Internal node", n);
193619baf839SRobert Olsson 
193719baf839SRobert Olsson 	if (IS_LEAF(n))
193819baf839SRobert Olsson 		seq_printf(seq, "key=%d.%d.%d.%d\n",
193919baf839SRobert Olsson 			   n->key >> 24, (n->key >> 16) % 256, (n->key >> 8) % 256, n->key % 256);
194019baf839SRobert Olsson 	else {
194119baf839SRobert Olsson 		int plen=((struct tnode *)n)->pos;
194219baf839SRobert Olsson 		t_key prf=MASK_PFX(n->key, plen);
194319baf839SRobert Olsson 		seq_printf(seq, "key=%d.%d.%d.%d/%d\n",
194419baf839SRobert Olsson 			   prf >> 24, (prf >> 16) % 256, (prf >> 8) % 256, prf % 256, plen);
194519baf839SRobert Olsson 	}
194619baf839SRobert Olsson 	if (IS_LEAF(n)) {
194719baf839SRobert Olsson 		struct leaf *l=(struct leaf *)n;
194819baf839SRobert Olsson 		struct fib_alias *fa;
194919baf839SRobert Olsson 		int i;
195019baf839SRobert Olsson 		for (i=32; i>=0; i--)
195119baf839SRobert Olsson 		  if(find_leaf_info(&l->list, i)) {
195219baf839SRobert Olsson 
195319baf839SRobert Olsson 				struct list_head *fa_head = get_fa_head(l, i);
195419baf839SRobert Olsson 
195519baf839SRobert Olsson 				if(!fa_head)
195619baf839SRobert Olsson 					continue;
195719baf839SRobert Olsson 
195819baf839SRobert Olsson 				if(list_empty(fa_head))
195919baf839SRobert Olsson 					continue;
196019baf839SRobert Olsson 
196119baf839SRobert Olsson 				putspace_seq(seq, indent+2);
196219baf839SRobert Olsson 				seq_printf(seq, "{/%d...dumping}\n", i);
196319baf839SRobert Olsson 
196419baf839SRobert Olsson 
196519baf839SRobert Olsson 				list_for_each_entry(fa, fa_head, fa_list) {
196619baf839SRobert Olsson 					putspace_seq(seq, indent+2);
196719baf839SRobert Olsson 					if (fa->fa_info->fib_nh == NULL) {
196819baf839SRobert Olsson 						seq_printf(seq, "Error _fib_nh=NULL\n");
196919baf839SRobert Olsson 						continue;
197019baf839SRobert Olsson 					}
197119baf839SRobert Olsson 					if (fa->fa_info == NULL) {
197219baf839SRobert Olsson 						seq_printf(seq, "Error fa_info=NULL\n");
197319baf839SRobert Olsson 						continue;
197419baf839SRobert Olsson 					}
197519baf839SRobert Olsson 
197619baf839SRobert Olsson 					seq_printf(seq, "{type=%d scope=%d TOS=%d}\n",
197719baf839SRobert Olsson 					      fa->fa_type,
197819baf839SRobert Olsson 					      fa->fa_scope,
197919baf839SRobert Olsson 					      fa->fa_tos);
198019baf839SRobert Olsson 				}
198119baf839SRobert Olsson 			}
198219baf839SRobert Olsson 	}
198319baf839SRobert Olsson 	else if (IS_TNODE(n)) {
198419baf839SRobert Olsson 		struct tnode *tn=(struct tnode *)n;
198519baf839SRobert Olsson 		putspace_seq(seq, indent); seq_printf(seq, "|    ");
198619baf839SRobert Olsson 		seq_printf(seq, "{key prefix=%08x/", tn->key&TKEY_GET_MASK(0, tn->pos));
198719baf839SRobert Olsson 		printbin_seq(seq, tkey_extract_bits(tn->key, 0, tn->pos), tn->pos);
198819baf839SRobert Olsson 		seq_printf(seq, "}\n");
198919baf839SRobert Olsson 		putspace_seq(seq, indent); seq_printf(seq, "|    ");
199019baf839SRobert Olsson 		seq_printf(seq, "{pos=%d", tn->pos);
199119baf839SRobert Olsson 		seq_printf(seq, " (skip=%d bits)", tn->pos - pend);
199219baf839SRobert Olsson 		seq_printf(seq, " bits=%d (%u children)}\n", tn->bits, (1 << tn->bits));
199319baf839SRobert Olsson 		putspace_seq(seq, indent); seq_printf(seq, "|    ");
199419baf839SRobert Olsson 		seq_printf(seq, "{empty=%d full=%d}\n", tn->empty_children, tn->full_children);
199519baf839SRobert Olsson 	}
199619baf839SRobert Olsson }
199719baf839SRobert Olsson 
199819baf839SRobert Olsson static void trie_dump_seq(struct seq_file *seq, struct trie *t)
199919baf839SRobert Olsson {
200019baf839SRobert Olsson 	struct node *n=t->trie;
200119baf839SRobert Olsson 	int cindex=0;
200219baf839SRobert Olsson 	int indent=1;
200319baf839SRobert Olsson 	int pend=0;
200419baf839SRobert Olsson 	int depth = 0;
200519baf839SRobert Olsson 
200619baf839SRobert Olsson   	read_lock(&fib_lock);
200719baf839SRobert Olsson 
200819baf839SRobert Olsson 	seq_printf(seq, "------ trie_dump of t=%p ------\n", t);
200919baf839SRobert Olsson 	if (n) {
201019baf839SRobert Olsson 		printnode_seq(seq, indent, n, pend, cindex, 0);
201119baf839SRobert Olsson 		if (IS_TNODE(n)) {
201219baf839SRobert Olsson 			struct tnode *tn=(struct tnode *)n;
201319baf839SRobert Olsson 			pend = tn->pos+tn->bits;
201419baf839SRobert Olsson 			putspace_seq(seq, indent); seq_printf(seq, "\\--\n");
201519baf839SRobert Olsson 			indent += 3;
201619baf839SRobert Olsson 			depth++;
201719baf839SRobert Olsson 
201819baf839SRobert Olsson 			while (tn && cindex < (1 << tn->bits)) {
201919baf839SRobert Olsson 				if (tn->child[cindex]) {
202019baf839SRobert Olsson 
202119baf839SRobert Olsson 					/* Got a child */
202219baf839SRobert Olsson 
202319baf839SRobert Olsson 					printnode_seq(seq, indent, tn->child[cindex], pend, cindex, tn->bits);
202419baf839SRobert Olsson 					if (IS_LEAF(tn->child[cindex])) {
202519baf839SRobert Olsson 						cindex++;
202619baf839SRobert Olsson 
202719baf839SRobert Olsson 					}
202819baf839SRobert Olsson 					else {
202919baf839SRobert Olsson 						/*
203019baf839SRobert Olsson 						 * New tnode. Decend one level
203119baf839SRobert Olsson 						 */
203219baf839SRobert Olsson 
203319baf839SRobert Olsson 						depth++;
203419baf839SRobert Olsson 						n=tn->child[cindex];
203519baf839SRobert Olsson 						tn=(struct tnode *)n;
203619baf839SRobert Olsson 						pend=tn->pos+tn->bits;
203719baf839SRobert Olsson 						putspace_seq(seq, indent); seq_printf(seq, "\\--\n");
203819baf839SRobert Olsson 						indent+=3;
203919baf839SRobert Olsson 						cindex=0;
204019baf839SRobert Olsson 					}
204119baf839SRobert Olsson 				}
204219baf839SRobert Olsson 				else
204319baf839SRobert Olsson 					cindex++;
204419baf839SRobert Olsson 
204519baf839SRobert Olsson 				/*
204619baf839SRobert Olsson 				 * Test if we are done
204719baf839SRobert Olsson 				 */
204819baf839SRobert Olsson 
204919baf839SRobert Olsson 				while (cindex >= (1 << tn->bits)) {
205019baf839SRobert Olsson 
205119baf839SRobert Olsson 					/*
205219baf839SRobert Olsson 					 * Move upwards and test for root
205319baf839SRobert Olsson 					 * pop off all traversed  nodes
205419baf839SRobert Olsson 					 */
205519baf839SRobert Olsson 
205619baf839SRobert Olsson 					if (NODE_PARENT(tn) == NULL) {
205719baf839SRobert Olsson 						tn = NULL;
205819baf839SRobert Olsson 						n = NULL;
205919baf839SRobert Olsson 						break;
206019baf839SRobert Olsson 					}
206119baf839SRobert Olsson 					else {
206219baf839SRobert Olsson 						cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits);
206319baf839SRobert Olsson 						tn = NODE_PARENT(tn);
206419baf839SRobert Olsson 						cindex++;
206519baf839SRobert Olsson 						n=(struct node *)tn;
206619baf839SRobert Olsson 						pend=tn->pos+tn->bits;
206719baf839SRobert Olsson 						indent-=3;
206819baf839SRobert Olsson 						depth--;
206919baf839SRobert Olsson 					}
207019baf839SRobert Olsson 				}
207119baf839SRobert Olsson 			}
207219baf839SRobert Olsson 		}
207319baf839SRobert Olsson 		else n = NULL;
207419baf839SRobert Olsson 	}
207519baf839SRobert Olsson 	else seq_printf(seq, "------ trie is empty\n");
207619baf839SRobert Olsson 
207719baf839SRobert Olsson   	read_unlock(&fib_lock);
207819baf839SRobert Olsson }
207919baf839SRobert Olsson 
208019baf839SRobert Olsson static struct trie_stat *trie_stat_new(void)
208119baf839SRobert Olsson {
208219baf839SRobert Olsson 	struct trie_stat *s = kmalloc(sizeof(struct trie_stat), GFP_KERNEL);
208319baf839SRobert Olsson 	int i;
208419baf839SRobert Olsson 
208519baf839SRobert Olsson 	if(s) {
208619baf839SRobert Olsson 		s->totdepth = 0;
208719baf839SRobert Olsson 		s->maxdepth = 0;
208819baf839SRobert Olsson 		s->tnodes = 0;
208919baf839SRobert Olsson 		s->leaves = 0;
209019baf839SRobert Olsson 		s->nullpointers = 0;
209119baf839SRobert Olsson 
209219baf839SRobert Olsson 		for(i=0; i< MAX_CHILDS; i++)
209319baf839SRobert Olsson 			s->nodesizes[i] = 0;
209419baf839SRobert Olsson 	}
209519baf839SRobert Olsson 	return s;
209619baf839SRobert Olsson }
209719baf839SRobert Olsson 
209819baf839SRobert Olsson static struct trie_stat *trie_collect_stats(struct trie *t)
209919baf839SRobert Olsson {
210019baf839SRobert Olsson 	struct node *n=t->trie;
210119baf839SRobert Olsson 	struct trie_stat *s = trie_stat_new();
210219baf839SRobert Olsson 	int cindex = 0;
210319baf839SRobert Olsson 	int indent = 1;
210419baf839SRobert Olsson 	int pend = 0;
210519baf839SRobert Olsson 	int depth = 0;
210619baf839SRobert Olsson 
210719baf839SRobert Olsson 	read_lock(&fib_lock);
210819baf839SRobert Olsson 
210919baf839SRobert Olsson 	if (s) {
211019baf839SRobert Olsson 		if (n) {
211119baf839SRobert Olsson 			if (IS_TNODE(n)) {
211219baf839SRobert Olsson 				struct tnode *tn = (struct tnode *)n;
211319baf839SRobert Olsson 				pend=tn->pos+tn->bits;
211419baf839SRobert Olsson 				indent += 3;
211519baf839SRobert Olsson 				s->nodesizes[tn->bits]++;
211619baf839SRobert Olsson 				depth++;
211719baf839SRobert Olsson 
211819baf839SRobert Olsson 				while (tn && cindex < (1 << tn->bits)) {
211919baf839SRobert Olsson 					if (tn->child[cindex]) {
212019baf839SRobert Olsson 						/* Got a child */
212119baf839SRobert Olsson 
212219baf839SRobert Olsson 						if (IS_LEAF(tn->child[cindex])) {
212319baf839SRobert Olsson 							cindex++;
212419baf839SRobert Olsson 
212519baf839SRobert Olsson 							/* stats */
212619baf839SRobert Olsson 							if (depth > s->maxdepth)
212719baf839SRobert Olsson 								s->maxdepth = depth;
212819baf839SRobert Olsson 							s->totdepth += depth;
212919baf839SRobert Olsson 							s->leaves++;
213019baf839SRobert Olsson 						}
213119baf839SRobert Olsson 
213219baf839SRobert Olsson 						else {
213319baf839SRobert Olsson 							/*
213419baf839SRobert Olsson 							 * New tnode. Decend one level
213519baf839SRobert Olsson 							 */
213619baf839SRobert Olsson 
213719baf839SRobert Olsson 							s->tnodes++;
213819baf839SRobert Olsson 							s->nodesizes[tn->bits]++;
213919baf839SRobert Olsson 							depth++;
214019baf839SRobert Olsson 
214119baf839SRobert Olsson 							n = tn->child[cindex];
214219baf839SRobert Olsson 							tn = (struct tnode *)n;
214319baf839SRobert Olsson 							pend = tn->pos+tn->bits;
214419baf839SRobert Olsson 
214519baf839SRobert Olsson 							indent += 3;
214619baf839SRobert Olsson 							cindex = 0;
214719baf839SRobert Olsson 						}
214819baf839SRobert Olsson 					}
214919baf839SRobert Olsson 					else {
215019baf839SRobert Olsson 						cindex++;
215119baf839SRobert Olsson 						s->nullpointers++;
215219baf839SRobert Olsson 					}
215319baf839SRobert Olsson 
215419baf839SRobert Olsson 					/*
215519baf839SRobert Olsson 					 * Test if we are done
215619baf839SRobert Olsson 					 */
215719baf839SRobert Olsson 
215819baf839SRobert Olsson 					while (cindex >= (1 << tn->bits)) {
215919baf839SRobert Olsson 
216019baf839SRobert Olsson 						/*
216119baf839SRobert Olsson 						 * Move upwards and test for root
216219baf839SRobert Olsson 						 * pop off all traversed  nodes
216319baf839SRobert Olsson 						 */
216419baf839SRobert Olsson 
216519baf839SRobert Olsson 
216619baf839SRobert Olsson 						if (NODE_PARENT(tn) == NULL) {
216719baf839SRobert Olsson 							tn = NULL;
216819baf839SRobert Olsson 							n = NULL;
216919baf839SRobert Olsson 							break;
217019baf839SRobert Olsson 						}
217119baf839SRobert Olsson 						else {
217219baf839SRobert Olsson 							cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits);
217319baf839SRobert Olsson 							tn = NODE_PARENT(tn);
217419baf839SRobert Olsson 							cindex++;
217519baf839SRobert Olsson 							n = (struct node *)tn;
217619baf839SRobert Olsson 							pend=tn->pos+tn->bits;
217719baf839SRobert Olsson 							indent -= 3;
217819baf839SRobert Olsson 							depth--;
217919baf839SRobert Olsson 						}
218019baf839SRobert Olsson  					}
218119baf839SRobert Olsson 				}
218219baf839SRobert Olsson 			}
218319baf839SRobert Olsson 			else n = NULL;
218419baf839SRobert Olsson 		}
218519baf839SRobert Olsson 	}
218619baf839SRobert Olsson 
218719baf839SRobert Olsson 	read_unlock(&fib_lock);
218819baf839SRobert Olsson 	return s;
218919baf839SRobert Olsson }
219019baf839SRobert Olsson 
219119baf839SRobert Olsson #ifdef CONFIG_PROC_FS
219219baf839SRobert Olsson 
219319baf839SRobert Olsson static struct fib_alias *fib_triestat_get_first(struct seq_file *seq)
219419baf839SRobert Olsson {
219519baf839SRobert Olsson 	return NULL;
219619baf839SRobert Olsson }
219719baf839SRobert Olsson 
219819baf839SRobert Olsson static struct fib_alias *fib_triestat_get_next(struct seq_file *seq)
219919baf839SRobert Olsson {
220019baf839SRobert Olsson 	return NULL;
220119baf839SRobert Olsson }
220219baf839SRobert Olsson 
220319baf839SRobert Olsson static void *fib_triestat_seq_start(struct seq_file *seq, loff_t *pos)
220419baf839SRobert Olsson {
220519baf839SRobert Olsson 	void *v = NULL;
220619baf839SRobert Olsson 
220719baf839SRobert Olsson 	if (ip_fib_main_table)
220819baf839SRobert Olsson 		v = *pos ? fib_triestat_get_next(seq) : SEQ_START_TOKEN;
220919baf839SRobert Olsson 	return v;
221019baf839SRobert Olsson }
221119baf839SRobert Olsson 
221219baf839SRobert Olsson static void *fib_triestat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
221319baf839SRobert Olsson {
221419baf839SRobert Olsson 	++*pos;
221519baf839SRobert Olsson 	return v == SEQ_START_TOKEN ? fib_triestat_get_first(seq) : fib_triestat_get_next(seq);
221619baf839SRobert Olsson }
221719baf839SRobert Olsson 
221819baf839SRobert Olsson static void fib_triestat_seq_stop(struct seq_file *seq, void *v)
221919baf839SRobert Olsson {
222019baf839SRobert Olsson 
222119baf839SRobert Olsson }
222219baf839SRobert Olsson 
222319baf839SRobert Olsson /*
222419baf839SRobert Olsson  *	This outputs /proc/net/fib_triestats
222519baf839SRobert Olsson  *
222619baf839SRobert Olsson  *	It always works in backward compatibility mode.
222719baf839SRobert Olsson  *	The format of the file is not supposed to be changed.
222819baf839SRobert Olsson  */
222919baf839SRobert Olsson 
223019baf839SRobert Olsson static void collect_and_show(struct trie *t, struct seq_file *seq)
223119baf839SRobert Olsson {
223219baf839SRobert Olsson 	int bytes = 0; /* How many bytes are used, a ref is 4 bytes */
223319baf839SRobert Olsson 	int i, max, pointers;
223419baf839SRobert Olsson         struct trie_stat *stat;
223519baf839SRobert Olsson 	int avdepth;
223619baf839SRobert Olsson 
223719baf839SRobert Olsson 	stat = trie_collect_stats(t);
223819baf839SRobert Olsson 
223919baf839SRobert Olsson 	bytes=0;
224019baf839SRobert Olsson 	seq_printf(seq, "trie=%p\n", t);
224119baf839SRobert Olsson 
224219baf839SRobert Olsson 	if (stat) {
224319baf839SRobert Olsson 		if (stat->leaves)
224419baf839SRobert Olsson 			avdepth=stat->totdepth*100 / stat->leaves;
224519baf839SRobert Olsson 		else
224619baf839SRobert Olsson 			avdepth=0;
224719baf839SRobert Olsson 		seq_printf(seq, "Aver depth: %d.%02d\n", avdepth / 100, avdepth % 100 );
224819baf839SRobert Olsson 		seq_printf(seq, "Max depth: %4d\n", stat->maxdepth);
224919baf839SRobert Olsson 
225019baf839SRobert Olsson 		seq_printf(seq, "Leaves: %d\n", stat->leaves);
225119baf839SRobert Olsson 		bytes += sizeof(struct leaf) * stat->leaves;
225219baf839SRobert Olsson 		seq_printf(seq, "Internal nodes: %d\n", stat->tnodes);
225319baf839SRobert Olsson 		bytes += sizeof(struct tnode) * stat->tnodes;
225419baf839SRobert Olsson 
225519baf839SRobert Olsson 		max = MAX_CHILDS-1;
225619baf839SRobert Olsson 
225719baf839SRobert Olsson 		while (max >= 0 && stat->nodesizes[max] == 0)
225819baf839SRobert Olsson 			max--;
225919baf839SRobert Olsson 		pointers = 0;
226019baf839SRobert Olsson 
226119baf839SRobert Olsson 		for (i = 1; i <= max; i++)
226219baf839SRobert Olsson 			if (stat->nodesizes[i] != 0) {
226319baf839SRobert Olsson 				seq_printf(seq, "  %d: %d",  i, stat->nodesizes[i]);
226419baf839SRobert Olsson 				pointers += (1<<i) * stat->nodesizes[i];
226519baf839SRobert Olsson 			}
226619baf839SRobert Olsson 		seq_printf(seq, "\n");
226719baf839SRobert Olsson 		seq_printf(seq, "Pointers: %d\n", pointers);
226819baf839SRobert Olsson 		bytes += sizeof(struct node *) * pointers;
226919baf839SRobert Olsson 		seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers);
227019baf839SRobert Olsson 		seq_printf(seq, "Total size: %d  kB\n", bytes / 1024);
227119baf839SRobert Olsson 
227219baf839SRobert Olsson 		kfree(stat);
227319baf839SRobert Olsson 	}
227419baf839SRobert Olsson 
227519baf839SRobert Olsson #ifdef CONFIG_IP_FIB_TRIE_STATS
227619baf839SRobert Olsson 	seq_printf(seq, "Counters:\n---------\n");
227719baf839SRobert Olsson 	seq_printf(seq,"gets = %d\n", t->stats.gets);
227819baf839SRobert Olsson 	seq_printf(seq,"backtracks = %d\n", t->stats.backtrack);
227919baf839SRobert Olsson 	seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
228019baf839SRobert Olsson 	seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
228119baf839SRobert Olsson 	seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
228219baf839SRobert Olsson #ifdef CLEAR_STATS
228319baf839SRobert Olsson 	memset(&(t->stats), 0, sizeof(t->stats));
228419baf839SRobert Olsson #endif
228519baf839SRobert Olsson #endif /*  CONFIG_IP_FIB_TRIE_STATS */
228619baf839SRobert Olsson }
228719baf839SRobert Olsson 
228819baf839SRobert Olsson static int fib_triestat_seq_show(struct seq_file *seq, void *v)
228919baf839SRobert Olsson {
229019baf839SRobert Olsson 	char bf[128];
229119baf839SRobert Olsson 
229219baf839SRobert Olsson 	if (v == SEQ_START_TOKEN) {
229319baf839SRobert Olsson 		seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n",
229419baf839SRobert Olsson 			   sizeof(struct leaf), sizeof(struct tnode));
229519baf839SRobert Olsson 		if (trie_local)
229619baf839SRobert Olsson 			collect_and_show(trie_local, seq);
229719baf839SRobert Olsson 
229819baf839SRobert Olsson 		if (trie_main)
229919baf839SRobert Olsson 			collect_and_show(trie_main, seq);
230019baf839SRobert Olsson 	}
230119baf839SRobert Olsson 	else {
230219baf839SRobert Olsson 		snprintf(bf, sizeof(bf),
230319baf839SRobert Olsson 			 "*\t%08X\t%08X", 200, 400);
230419baf839SRobert Olsson 
230519baf839SRobert Olsson 		seq_printf(seq, "%-127s\n", bf);
230619baf839SRobert Olsson 	}
230719baf839SRobert Olsson 	return 0;
230819baf839SRobert Olsson }
230919baf839SRobert Olsson 
231019baf839SRobert Olsson static struct seq_operations fib_triestat_seq_ops = {
231119baf839SRobert Olsson 	.start  = fib_triestat_seq_start,
231219baf839SRobert Olsson 	.next   = fib_triestat_seq_next,
231319baf839SRobert Olsson 	.stop   = fib_triestat_seq_stop,
231419baf839SRobert Olsson 	.show   = fib_triestat_seq_show,
231519baf839SRobert Olsson };
231619baf839SRobert Olsson 
231719baf839SRobert Olsson static int fib_triestat_seq_open(struct inode *inode, struct file *file)
231819baf839SRobert Olsson {
231919baf839SRobert Olsson 	struct seq_file *seq;
232019baf839SRobert Olsson 	int rc = -ENOMEM;
232119baf839SRobert Olsson 
232219baf839SRobert Olsson 	rc = seq_open(file, &fib_triestat_seq_ops);
232319baf839SRobert Olsson 	if (rc)
232419baf839SRobert Olsson 		goto out_kfree;
232519baf839SRobert Olsson 
232619baf839SRobert Olsson 	seq	     = file->private_data;
232719baf839SRobert Olsson out:
232819baf839SRobert Olsson 	return rc;
232919baf839SRobert Olsson out_kfree:
233019baf839SRobert Olsson 	goto out;
233119baf839SRobert Olsson }
233219baf839SRobert Olsson 
233319baf839SRobert Olsson static struct file_operations fib_triestat_seq_fops = {
233419baf839SRobert Olsson 	.owner		= THIS_MODULE,
233519baf839SRobert Olsson 	.open           = fib_triestat_seq_open,
233619baf839SRobert Olsson 	.read           = seq_read,
233719baf839SRobert Olsson 	.llseek         = seq_lseek,
233819baf839SRobert Olsson 	.release	= seq_release_private,
233919baf839SRobert Olsson };
234019baf839SRobert Olsson 
234119baf839SRobert Olsson int __init fib_stat_proc_init(void)
234219baf839SRobert Olsson {
234319baf839SRobert Olsson 	if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_seq_fops))
234419baf839SRobert Olsson 		return -ENOMEM;
234519baf839SRobert Olsson 	return 0;
234619baf839SRobert Olsson }
234719baf839SRobert Olsson 
234819baf839SRobert Olsson void __init fib_stat_proc_exit(void)
234919baf839SRobert Olsson {
235019baf839SRobert Olsson 	proc_net_remove("fib_triestat");
235119baf839SRobert Olsson }
235219baf839SRobert Olsson 
235319baf839SRobert Olsson static struct fib_alias *fib_trie_get_first(struct seq_file *seq)
235419baf839SRobert Olsson {
235519baf839SRobert Olsson 	return NULL;
235619baf839SRobert Olsson }
235719baf839SRobert Olsson 
235819baf839SRobert Olsson static struct fib_alias *fib_trie_get_next(struct seq_file *seq)
235919baf839SRobert Olsson {
236019baf839SRobert Olsson 	return NULL;
236119baf839SRobert Olsson }
236219baf839SRobert Olsson 
236319baf839SRobert Olsson static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
236419baf839SRobert Olsson {
236519baf839SRobert Olsson 	void *v = NULL;
236619baf839SRobert Olsson 
236719baf839SRobert Olsson 	if (ip_fib_main_table)
236819baf839SRobert Olsson 		v = *pos ? fib_trie_get_next(seq) : SEQ_START_TOKEN;
236919baf839SRobert Olsson 	return v;
237019baf839SRobert Olsson }
237119baf839SRobert Olsson 
237219baf839SRobert Olsson static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
237319baf839SRobert Olsson {
237419baf839SRobert Olsson 	++*pos;
237519baf839SRobert Olsson 	return v == SEQ_START_TOKEN ? fib_trie_get_first(seq) : fib_trie_get_next(seq);
237619baf839SRobert Olsson }
237719baf839SRobert Olsson 
237819baf839SRobert Olsson static void fib_trie_seq_stop(struct seq_file *seq, void *v)
237919baf839SRobert Olsson {
238019baf839SRobert Olsson 
238119baf839SRobert Olsson }
238219baf839SRobert Olsson 
238319baf839SRobert Olsson /*
238419baf839SRobert Olsson  *	This outputs /proc/net/fib_trie.
238519baf839SRobert Olsson  *
238619baf839SRobert Olsson  *	It always works in backward compatibility mode.
238719baf839SRobert Olsson  *	The format of the file is not supposed to be changed.
238819baf839SRobert Olsson  */
238919baf839SRobert Olsson 
239019baf839SRobert Olsson static int fib_trie_seq_show(struct seq_file *seq, void *v)
239119baf839SRobert Olsson {
239219baf839SRobert Olsson 	char bf[128];
239319baf839SRobert Olsson 
239419baf839SRobert Olsson 	if (v == SEQ_START_TOKEN) {
239519baf839SRobert Olsson 		if (trie_local)
239619baf839SRobert Olsson 			trie_dump_seq(seq, trie_local);
239719baf839SRobert Olsson 
239819baf839SRobert Olsson 		if (trie_main)
239919baf839SRobert Olsson 			trie_dump_seq(seq, trie_main);
240019baf839SRobert Olsson 	}
240119baf839SRobert Olsson 
240219baf839SRobert Olsson 	else {
240319baf839SRobert Olsson 		snprintf(bf, sizeof(bf),
240419baf839SRobert Olsson 			 "*\t%08X\t%08X", 200, 400);
240519baf839SRobert Olsson 		seq_printf(seq, "%-127s\n", bf);
240619baf839SRobert Olsson 	}
240719baf839SRobert Olsson 
240819baf839SRobert Olsson 	return 0;
240919baf839SRobert Olsson }
241019baf839SRobert Olsson 
241119baf839SRobert Olsson static struct seq_operations fib_trie_seq_ops = {
241219baf839SRobert Olsson 	.start  = fib_trie_seq_start,
241319baf839SRobert Olsson 	.next   = fib_trie_seq_next,
241419baf839SRobert Olsson 	.stop   = fib_trie_seq_stop,
241519baf839SRobert Olsson 	.show   = fib_trie_seq_show,
241619baf839SRobert Olsson };
241719baf839SRobert Olsson 
241819baf839SRobert Olsson static int fib_trie_seq_open(struct inode *inode, struct file *file)
241919baf839SRobert Olsson {
242019baf839SRobert Olsson 	struct seq_file *seq;
242119baf839SRobert Olsson 	int rc = -ENOMEM;
242219baf839SRobert Olsson 
242319baf839SRobert Olsson 	rc = seq_open(file, &fib_trie_seq_ops);
242419baf839SRobert Olsson 	if (rc)
242519baf839SRobert Olsson 		goto out_kfree;
242619baf839SRobert Olsson 
242719baf839SRobert Olsson 	seq	     = file->private_data;
242819baf839SRobert Olsson out:
242919baf839SRobert Olsson 	return rc;
243019baf839SRobert Olsson out_kfree:
243119baf839SRobert Olsson 	goto out;
243219baf839SRobert Olsson }
243319baf839SRobert Olsson 
243419baf839SRobert Olsson static struct file_operations fib_trie_seq_fops = {
243519baf839SRobert Olsson 	.owner		= THIS_MODULE,
243619baf839SRobert Olsson 	.open           = fib_trie_seq_open,
243719baf839SRobert Olsson 	.read           = seq_read,
243819baf839SRobert Olsson 	.llseek         = seq_lseek,
243919baf839SRobert Olsson 	.release	= seq_release_private,
244019baf839SRobert Olsson };
244119baf839SRobert Olsson 
244219baf839SRobert Olsson int __init fib_proc_init(void)
244319baf839SRobert Olsson {
244419baf839SRobert Olsson 	if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_seq_fops))
244519baf839SRobert Olsson 		return -ENOMEM;
244619baf839SRobert Olsson 	return 0;
244719baf839SRobert Olsson }
244819baf839SRobert Olsson 
244919baf839SRobert Olsson void __init fib_proc_exit(void)
245019baf839SRobert Olsson {
245119baf839SRobert Olsson 	proc_net_remove("fib_trie");
245219baf839SRobert Olsson }
245319baf839SRobert Olsson 
245419baf839SRobert Olsson #endif /* CONFIG_PROC_FS */
2455