blob: 914a4c2aae423199f404188b5e1fc4e3ad1203e9 [file] [log] [blame]
Robert Olsson19baf832005-06-21 12:43:18 -07001/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version
5 * 2 of the License, or (at your option) any later version.
6 *
7 * Robert Olsson <robert.olsson@its.uu.se> Uppsala Universitet
8 * & Swedish University of Agricultural Sciences.
9 *
10 * Jens Laas <jens.laas@data.slu.se> Swedish University of
11 * Agricultural Sciences.
12 *
13 * Hans Liss <hans.liss@its.uu.se> Uppsala Universitet
14 *
15 * This work is based on the LPC-trie which is originally descibed in:
16 *
17 * An experimental study of compression methods for dynamic tries
18 * Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
19 * http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
20 *
21 *
22 * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
23 * IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
24 *
25 * Version: $Id: fib_trie.c,v 1.3 2005/06/08 14:20:01 robert Exp $
26 *
27 *
28 * Code from fib_hash has been reused which includes the following header:
29 *
30 *
31 * INET An implementation of the TCP/IP protocol suite for the LINUX
32 * operating system. INET is implemented using the BSD Socket
33 * interface as the means of communication with the user level.
34 *
35 * IPv4 FIB: lookup engine and maintenance routines.
36 *
37 *
38 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
39 *
40 * This program is free software; you can redistribute it and/or
41 * modify it under the terms of the GNU General Public License
42 * as published by the Free Software Foundation; either version
43 * 2 of the License, or (at your option) any later version.
44 */
45
Robert Olsson2f368952005-07-05 15:02:40 -070046#define VERSION "0.325"
Robert Olsson19baf832005-06-21 12:43:18 -070047
48#include <linux/config.h>
49#include <asm/uaccess.h>
50#include <asm/system.h>
51#include <asm/bitops.h>
52#include <linux/types.h>
53#include <linux/kernel.h>
54#include <linux/sched.h>
55#include <linux/mm.h>
56#include <linux/string.h>
57#include <linux/socket.h>
58#include <linux/sockios.h>
59#include <linux/errno.h>
60#include <linux/in.h>
61#include <linux/inet.h>
62#include <linux/netdevice.h>
63#include <linux/if_arp.h>
64#include <linux/proc_fs.h>
65#include <linux/skbuff.h>
66#include <linux/netlink.h>
67#include <linux/init.h>
68#include <linux/list.h>
69#include <net/ip.h>
70#include <net/protocol.h>
71#include <net/route.h>
72#include <net/tcp.h>
73#include <net/sock.h>
74#include <net/ip_fib.h>
75#include "fib_lookup.h"
76
77#undef CONFIG_IP_FIB_TRIE_STATS
78#define MAX_CHILDS 16384
79
80#define EXTRACT(p, n, str) ((str)<<(p)>>(32-(n)))
81#define KEYLENGTH (8*sizeof(t_key))
82#define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l))
83#define TKEY_GET_MASK(offset, bits) (((bits)==0)?0:((t_key)(-1) << (KEYLENGTH - bits) >> offset))
84
85static DEFINE_RWLOCK(fib_lock);
86
87typedef unsigned int t_key;
88
89#define T_TNODE 0
90#define T_LEAF 1
91#define NODE_TYPE_MASK 0x1UL
Olof Johansson91b9a272005-08-09 20:24:39 -070092#define NODE_PARENT(node) \
93 ((struct tnode *)((node)->parent & ~NODE_TYPE_MASK))
94#define NODE_SET_PARENT(node, ptr) \
95 ((node)->parent = (((unsigned long)(ptr)) | \
96 ((node)->parent & NODE_TYPE_MASK)))
97#define NODE_INIT_PARENT(node, type) \
98 ((node)->parent = (type))
99#define NODE_TYPE(node) \
100 ((node)->parent & NODE_TYPE_MASK)
Robert Olsson19baf832005-06-21 12:43:18 -0700101
Olof Johansson91b9a272005-08-09 20:24:39 -0700102#define IS_TNODE(n) (!(n->parent & T_LEAF))
103#define IS_LEAF(n) (n->parent & T_LEAF)
Robert Olsson19baf832005-06-21 12:43:18 -0700104
105struct node {
Olof Johansson91b9a272005-08-09 20:24:39 -0700106 t_key key;
107 unsigned long parent;
Robert Olsson19baf832005-06-21 12:43:18 -0700108};
109
110struct leaf {
Olof Johansson91b9a272005-08-09 20:24:39 -0700111 t_key key;
112 unsigned long parent;
Robert Olsson19baf832005-06-21 12:43:18 -0700113 struct hlist_head list;
114};
115
116struct leaf_info {
117 struct hlist_node hlist;
118 int plen;
119 struct list_head falh;
120};
121
122struct tnode {
Olof Johansson91b9a272005-08-09 20:24:39 -0700123 t_key key;
124 unsigned long parent;
125 unsigned short pos:5; /* 2log(KEYLENGTH) bits needed */
126 unsigned short bits:5; /* 2log(KEYLENGTH) bits needed */
127 unsigned short full_children; /* KEYLENGTH bits needed */
128 unsigned short empty_children; /* KEYLENGTH bits needed */
129 struct node *child[0];
Robert Olsson19baf832005-06-21 12:43:18 -0700130};
131
132#ifdef CONFIG_IP_FIB_TRIE_STATS
133struct trie_use_stats {
134 unsigned int gets;
135 unsigned int backtrack;
136 unsigned int semantic_match_passed;
137 unsigned int semantic_match_miss;
138 unsigned int null_node_hit;
Robert Olsson2f368952005-07-05 15:02:40 -0700139 unsigned int resize_node_skipped;
Robert Olsson19baf832005-06-21 12:43:18 -0700140};
141#endif
142
143struct trie_stat {
144 unsigned int totdepth;
145 unsigned int maxdepth;
146 unsigned int tnodes;
147 unsigned int leaves;
148 unsigned int nullpointers;
149 unsigned int nodesizes[MAX_CHILDS];
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700150};
Robert Olsson19baf832005-06-21 12:43:18 -0700151
152struct trie {
Olof Johansson91b9a272005-08-09 20:24:39 -0700153 struct node *trie;
Robert Olsson19baf832005-06-21 12:43:18 -0700154#ifdef CONFIG_IP_FIB_TRIE_STATS
155 struct trie_use_stats stats;
156#endif
Olof Johansson91b9a272005-08-09 20:24:39 -0700157 int size;
Robert Olsson19baf832005-06-21 12:43:18 -0700158 unsigned int revision;
159};
160
161static int trie_debug = 0;
162
Olof Johansson91b9a272005-08-09 20:24:39 -0700163#define DBG(x...) do { if (trie_debug) printk(x); } while (0)
164
Robert Olsson19baf832005-06-21 12:43:18 -0700165static int tnode_full(struct tnode *tn, struct node *n);
166static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
167static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull);
168static int tnode_child_length(struct tnode *tn);
169static struct node *resize(struct trie *t, struct tnode *tn);
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700170static struct tnode *inflate(struct trie *t, struct tnode *tn);
171static struct tnode *halve(struct trie *t, struct tnode *tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700172static void tnode_free(struct tnode *tn);
173static void trie_dump_seq(struct seq_file *seq, struct trie *t);
174extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio);
175extern int fib_detect_death(struct fib_info *fi, int order,
Olof Johansson91b9a272005-08-09 20:24:39 -0700176 struct fib_info **last_resort, int *last_idx, int *dflt);
Robert Olsson19baf832005-06-21 12:43:18 -0700177
178extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa, int z, int tb_id,
Olof Johansson91b9a272005-08-09 20:24:39 -0700179 struct nlmsghdr *n, struct netlink_skb_parms *req);
Robert Olsson19baf832005-06-21 12:43:18 -0700180
181static kmem_cache_t *fn_alias_kmem;
182static struct trie *trie_local = NULL, *trie_main = NULL;
183
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700184static inline struct node *tnode_get_child(struct tnode *tn, int i)
Robert Olsson19baf832005-06-21 12:43:18 -0700185{
Olof Johansson91b9a272005-08-09 20:24:39 -0700186 BUG_ON(i >= 1 << tn->bits);
Robert Olsson19baf832005-06-21 12:43:18 -0700187
Olof Johansson91b9a272005-08-09 20:24:39 -0700188 return tn->child[i];
Robert Olsson19baf832005-06-21 12:43:18 -0700189}
190
191static inline int tnode_child_length(struct tnode *tn)
192{
Olof Johansson91b9a272005-08-09 20:24:39 -0700193 return 1 << tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -0700194}
195
Robert Olsson19baf832005-06-21 12:43:18 -0700196static inline t_key tkey_extract_bits(t_key a, int offset, int bits)
197{
Olof Johansson91b9a272005-08-09 20:24:39 -0700198 if (offset < KEYLENGTH)
Robert Olsson19baf832005-06-21 12:43:18 -0700199 return ((t_key)(a << offset)) >> (KEYLENGTH - bits);
Olof Johansson91b9a272005-08-09 20:24:39 -0700200 else
Robert Olsson19baf832005-06-21 12:43:18 -0700201 return 0;
202}
203
204static inline int tkey_equals(t_key a, t_key b)
205{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700206 return a == b;
Robert Olsson19baf832005-06-21 12:43:18 -0700207}
208
209static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
210{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700211 if (bits == 0 || offset >= KEYLENGTH)
212 return 1;
Olof Johansson91b9a272005-08-09 20:24:39 -0700213 bits = bits > KEYLENGTH ? KEYLENGTH : bits;
214 return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700215}
Robert Olsson19baf832005-06-21 12:43:18 -0700216
217static inline int tkey_mismatch(t_key a, int offset, t_key b)
218{
219 t_key diff = a ^ b;
220 int i = offset;
221
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700222 if (!diff)
223 return 0;
224 while ((diff << i) >> (KEYLENGTH-1) == 0)
Robert Olsson19baf832005-06-21 12:43:18 -0700225 i++;
226 return i;
227}
228
Olof Johansson91b9a272005-08-09 20:24:39 -0700229/* Candidate for fib_semantics */
Robert Olsson19baf832005-06-21 12:43:18 -0700230
231static void fn_free_alias(struct fib_alias *fa)
232{
233 fib_release_info(fa->fa_info);
234 kmem_cache_free(fn_alias_kmem, fa);
235}
236
237/*
238 To understand this stuff, an understanding of keys and all their bits is
239 necessary. Every node in the trie has a key associated with it, but not
240 all of the bits in that key are significant.
241
242 Consider a node 'n' and its parent 'tp'.
243
244 If n is a leaf, every bit in its key is significant. Its presence is
245 necessitaded by path compression, since during a tree traversal (when
246 searching for a leaf - unless we are doing an insertion) we will completely
247 ignore all skipped bits we encounter. Thus we need to verify, at the end of
248 a potentially successful search, that we have indeed been walking the
249 correct key path.
250
251 Note that we can never "miss" the correct key in the tree if present by
252 following the wrong path. Path compression ensures that segments of the key
253 that are the same for all keys with a given prefix are skipped, but the
254 skipped part *is* identical for each node in the subtrie below the skipped
255 bit! trie_insert() in this implementation takes care of that - note the
256 call to tkey_sub_equals() in trie_insert().
257
258 if n is an internal node - a 'tnode' here, the various parts of its key
259 have many different meanings.
260
261 Example:
262 _________________________________________________________________
263 | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
264 -----------------------------------------------------------------
265 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
266
267 _________________________________________________________________
268 | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
269 -----------------------------------------------------------------
270 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
271
272 tp->pos = 7
273 tp->bits = 3
274 n->pos = 15
Olof Johansson91b9a272005-08-09 20:24:39 -0700275 n->bits = 4
Robert Olsson19baf832005-06-21 12:43:18 -0700276
277 First, let's just ignore the bits that come before the parent tp, that is
278 the bits from 0 to (tp->pos-1). They are *known* but at this point we do
279 not use them for anything.
280
281 The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the
282 index into the parent's child array. That is, they will be used to find
283 'n' among tp's children.
284
285 The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits
286 for the node n.
287
288 All the bits we have seen so far are significant to the node n. The rest
289 of the bits are really not needed or indeed known in n->key.
290
291 The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into
292 n's child array, and will of course be different for each child.
293
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700294
Robert Olsson19baf832005-06-21 12:43:18 -0700295 The rest of the bits, from (n->pos + n->bits) onward, are completely unknown
296 at this point.
297
298*/
299
300static void check_tnode(struct tnode *tn)
301{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700302 if (tn && tn->pos+tn->bits > 32) {
Robert Olsson19baf832005-06-21 12:43:18 -0700303 printk("TNODE ERROR tn=%p, pos=%d, bits=%d\n", tn, tn->pos, tn->bits);
304 }
305}
306
307static int halve_threshold = 25;
308static int inflate_threshold = 50;
309
310static struct leaf *leaf_new(void)
311{
312 struct leaf *l = kmalloc(sizeof(struct leaf), GFP_KERNEL);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700313 if (l) {
Robert Olsson19baf832005-06-21 12:43:18 -0700314 NODE_INIT_PARENT(l, T_LEAF);
315 INIT_HLIST_HEAD(&l->list);
316 }
317 return l;
318}
319
320static struct leaf_info *leaf_info_new(int plen)
321{
322 struct leaf_info *li = kmalloc(sizeof(struct leaf_info), GFP_KERNEL);
Olof Johansson91b9a272005-08-09 20:24:39 -0700323
324 if (!li)
325 return NULL;
326
327 li->plen = plen;
328 INIT_LIST_HEAD(&li->falh);
329
Robert Olsson19baf832005-06-21 12:43:18 -0700330 return li;
331}
332
333static inline void free_leaf(struct leaf *l)
334{
335 kfree(l);
336}
337
338static inline void free_leaf_info(struct leaf_info *li)
339{
340 kfree(li);
341}
342
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700343static struct tnode *tnode_alloc(unsigned int size)
344{
345 if (size <= PAGE_SIZE) {
346 return kmalloc(size, GFP_KERNEL);
347 } else {
348 return (struct tnode *)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700349 __get_free_pages(GFP_KERNEL, get_order(size));
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700350 }
351}
352
353static void __tnode_free(struct tnode *tn)
354{
355 unsigned int size = sizeof(struct tnode) +
Olof Johansson91b9a272005-08-09 20:24:39 -0700356 (1 << tn->bits) * sizeof(struct node *);
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700357
358 if (size <= PAGE_SIZE)
359 kfree(tn);
360 else
361 free_pages((unsigned long)tn, get_order(size));
362}
363
Robert Olsson19baf832005-06-21 12:43:18 -0700364static struct tnode* tnode_new(t_key key, int pos, int bits)
365{
366 int nchildren = 1<<bits;
367 int sz = sizeof(struct tnode) + nchildren * sizeof(struct node *);
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700368 struct tnode *tn = tnode_alloc(sz);
Robert Olsson19baf832005-06-21 12:43:18 -0700369
Olof Johansson91b9a272005-08-09 20:24:39 -0700370 if (tn) {
Robert Olsson19baf832005-06-21 12:43:18 -0700371 memset(tn, 0, sz);
372 NODE_INIT_PARENT(tn, T_TNODE);
373 tn->pos = pos;
374 tn->bits = bits;
375 tn->key = key;
376 tn->full_children = 0;
377 tn->empty_children = 1<<bits;
378 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700379
Olof Johansson91b9a272005-08-09 20:24:39 -0700380 DBG("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode),
381 (unsigned int) (sizeof(struct node) * 1<<bits));
Robert Olsson19baf832005-06-21 12:43:18 -0700382 return tn;
383}
384
385static void tnode_free(struct tnode *tn)
386{
Olof Johansson91b9a272005-08-09 20:24:39 -0700387 BUG_ON(!tn);
388
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700389 if (IS_LEAF(tn)) {
Robert Olsson19baf832005-06-21 12:43:18 -0700390 free_leaf((struct leaf *)tn);
Olof Johansson91b9a272005-08-09 20:24:39 -0700391 DBG("FL %p \n", tn);
392 } else {
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700393 __tnode_free(tn);
Olof Johansson91b9a272005-08-09 20:24:39 -0700394 DBG("FT %p \n", tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700395 }
396}
397
398/*
399 * Check whether a tnode 'n' is "full", i.e. it is an internal node
400 * and no bits are skipped. See discussion in dyntree paper p. 6
401 */
402
403static inline int tnode_full(struct tnode *tn, struct node *n)
404{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700405 if (n == NULL || IS_LEAF(n))
Robert Olsson19baf832005-06-21 12:43:18 -0700406 return 0;
407
408 return ((struct tnode *) n)->pos == tn->pos + tn->bits;
409}
410
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700411static inline void put_child(struct trie *t, struct tnode *tn, int i, struct node *n)
Robert Olsson19baf832005-06-21 12:43:18 -0700412{
413 tnode_put_child_reorg(tn, i, n, -1);
414}
415
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700416 /*
Robert Olsson19baf832005-06-21 12:43:18 -0700417 * Add a child at position i overwriting the old value.
418 * Update the value of full_children and empty_children.
419 */
420
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700421static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700422{
423 struct node *chi;
424 int isfull;
425
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700426 if (i >= 1<<tn->bits) {
Robert Olsson19baf832005-06-21 12:43:18 -0700427 printk("bits=%d, i=%d\n", tn->bits, i);
Olof Johansson91b9a272005-08-09 20:24:39 -0700428 BUG();
Robert Olsson19baf832005-06-21 12:43:18 -0700429 }
430 write_lock_bh(&fib_lock);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700431 chi = tn->child[i];
Robert Olsson19baf832005-06-21 12:43:18 -0700432
433 /* update emptyChildren */
434 if (n == NULL && chi != NULL)
435 tn->empty_children++;
436 else if (n != NULL && chi == NULL)
437 tn->empty_children--;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700438
Robert Olsson19baf832005-06-21 12:43:18 -0700439 /* update fullChildren */
Olof Johansson91b9a272005-08-09 20:24:39 -0700440 if (wasfull == -1)
Robert Olsson19baf832005-06-21 12:43:18 -0700441 wasfull = tnode_full(tn, chi);
442
443 isfull = tnode_full(tn, n);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700444 if (wasfull && !isfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700445 tn->full_children--;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700446 else if (!wasfull && isfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700447 tn->full_children++;
Olof Johansson91b9a272005-08-09 20:24:39 -0700448
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700449 if (n)
450 NODE_SET_PARENT(n, tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700451
452 tn->child[i] = n;
453 write_unlock_bh(&fib_lock);
454}
455
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700456static struct node *resize(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700457{
458 int i;
Robert Olsson2f368952005-07-05 15:02:40 -0700459 int err = 0;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700460 struct tnode *old_tn;
Robert Olsson19baf832005-06-21 12:43:18 -0700461
462 if (!tn)
463 return NULL;
464
Olof Johansson91b9a272005-08-09 20:24:39 -0700465 DBG("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
466 tn, inflate_threshold, halve_threshold);
Robert Olsson19baf832005-06-21 12:43:18 -0700467
468 /* No children */
469 if (tn->empty_children == tnode_child_length(tn)) {
470 tnode_free(tn);
471 return NULL;
472 }
473 /* One child */
474 if (tn->empty_children == tnode_child_length(tn) - 1)
475 for (i = 0; i < tnode_child_length(tn); i++) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700476 struct node *n;
Robert Olsson19baf832005-06-21 12:43:18 -0700477
478 write_lock_bh(&fib_lock);
Olof Johansson91b9a272005-08-09 20:24:39 -0700479 n = tn->child[i];
480 if (!n) {
Robert Olsson19baf832005-06-21 12:43:18 -0700481 write_unlock_bh(&fib_lock);
Olof Johansson91b9a272005-08-09 20:24:39 -0700482 continue;
Robert Olsson19baf832005-06-21 12:43:18 -0700483 }
Olof Johansson91b9a272005-08-09 20:24:39 -0700484
485 /* compress one level */
486 NODE_INIT_PARENT(n, NODE_TYPE(n));
487
Robert Olsson19baf832005-06-21 12:43:18 -0700488 write_unlock_bh(&fib_lock);
Olof Johansson91b9a272005-08-09 20:24:39 -0700489 tnode_free(tn);
490 return n;
Robert Olsson19baf832005-06-21 12:43:18 -0700491 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700492 /*
Robert Olsson19baf832005-06-21 12:43:18 -0700493 * Double as long as the resulting node has a number of
494 * nonempty nodes that are above the threshold.
495 */
496
497 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700498 * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
499 * the Helsinki University of Technology and Matti Tikkanen of Nokia
Robert Olsson19baf832005-06-21 12:43:18 -0700500 * Telecommunications, page 6:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700501 * "A node is doubled if the ratio of non-empty children to all
Robert Olsson19baf832005-06-21 12:43:18 -0700502 * children in the *doubled* node is at least 'high'."
503 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700504 * 'high' in this instance is the variable 'inflate_threshold'. It
505 * is expressed as a percentage, so we multiply it with
506 * tnode_child_length() and instead of multiplying by 2 (since the
507 * child array will be doubled by inflate()) and multiplying
508 * the left-hand side by 100 (to handle the percentage thing) we
Robert Olsson19baf832005-06-21 12:43:18 -0700509 * multiply the left-hand side by 50.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700510 *
511 * The left-hand side may look a bit weird: tnode_child_length(tn)
512 * - tn->empty_children is of course the number of non-null children
513 * in the current node. tn->full_children is the number of "full"
Robert Olsson19baf832005-06-21 12:43:18 -0700514 * children, that is non-null tnodes with a skip value of 0.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700515 * All of those will be doubled in the resulting inflated tnode, so
Robert Olsson19baf832005-06-21 12:43:18 -0700516 * we just count them one extra time here.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700517 *
Robert Olsson19baf832005-06-21 12:43:18 -0700518 * A clearer way to write this would be:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700519 *
Robert Olsson19baf832005-06-21 12:43:18 -0700520 * to_be_doubled = tn->full_children;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700521 * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
Robert Olsson19baf832005-06-21 12:43:18 -0700522 * tn->full_children;
523 *
524 * new_child_length = tnode_child_length(tn) * 2;
525 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700526 * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
Robert Olsson19baf832005-06-21 12:43:18 -0700527 * new_child_length;
528 * if (new_fill_factor >= inflate_threshold)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700529 *
530 * ...and so on, tho it would mess up the while () loop.
531 *
Robert Olsson19baf832005-06-21 12:43:18 -0700532 * anyway,
533 * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
534 * inflate_threshold
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700535 *
Robert Olsson19baf832005-06-21 12:43:18 -0700536 * avoid a division:
537 * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
538 * inflate_threshold * new_child_length
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700539 *
Robert Olsson19baf832005-06-21 12:43:18 -0700540 * expand not_to_be_doubled and to_be_doubled, and shorten:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700541 * 100 * (tnode_child_length(tn) - tn->empty_children +
Olof Johansson91b9a272005-08-09 20:24:39 -0700542 * tn->full_children) >= inflate_threshold * new_child_length
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700543 *
Robert Olsson19baf832005-06-21 12:43:18 -0700544 * expand new_child_length:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700545 * 100 * (tnode_child_length(tn) - tn->empty_children +
Olof Johansson91b9a272005-08-09 20:24:39 -0700546 * tn->full_children) >=
Robert Olsson19baf832005-06-21 12:43:18 -0700547 * inflate_threshold * tnode_child_length(tn) * 2
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700548 *
Robert Olsson19baf832005-06-21 12:43:18 -0700549 * shorten again:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700550 * 50 * (tn->full_children + tnode_child_length(tn) -
Olof Johansson91b9a272005-08-09 20:24:39 -0700551 * tn->empty_children) >= inflate_threshold *
Robert Olsson19baf832005-06-21 12:43:18 -0700552 * tnode_child_length(tn)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700553 *
Robert Olsson19baf832005-06-21 12:43:18 -0700554 */
555
556 check_tnode(tn);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700557
Robert Olsson2f368952005-07-05 15:02:40 -0700558 err = 0;
Robert Olsson19baf832005-06-21 12:43:18 -0700559 while ((tn->full_children > 0 &&
560 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
561 inflate_threshold * tnode_child_length(tn))) {
562
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700563 old_tn = tn;
564 tn = inflate(t, tn);
565 if (IS_ERR(tn)) {
566 tn = old_tn;
Robert Olsson2f368952005-07-05 15:02:40 -0700567#ifdef CONFIG_IP_FIB_TRIE_STATS
568 t->stats.resize_node_skipped++;
569#endif
570 break;
571 }
Robert Olsson19baf832005-06-21 12:43:18 -0700572 }
573
574 check_tnode(tn);
575
576 /*
577 * Halve as long as the number of empty children in this
578 * node is above threshold.
579 */
Robert Olsson2f368952005-07-05 15:02:40 -0700580
581 err = 0;
Robert Olsson19baf832005-06-21 12:43:18 -0700582 while (tn->bits > 1 &&
583 100 * (tnode_child_length(tn) - tn->empty_children) <
Robert Olsson2f368952005-07-05 15:02:40 -0700584 halve_threshold * tnode_child_length(tn)) {
Robert Olsson19baf832005-06-21 12:43:18 -0700585
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700586 old_tn = tn;
587 tn = halve(t, tn);
588 if (IS_ERR(tn)) {
589 tn = old_tn;
Robert Olsson2f368952005-07-05 15:02:40 -0700590#ifdef CONFIG_IP_FIB_TRIE_STATS
591 t->stats.resize_node_skipped++;
592#endif
593 break;
594 }
595 }
596
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700597
Robert Olsson19baf832005-06-21 12:43:18 -0700598 /* Only one child remains */
599
600 if (tn->empty_children == tnode_child_length(tn) - 1)
601 for (i = 0; i < tnode_child_length(tn); i++) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700602 struct node *n;
603
Robert Olsson19baf832005-06-21 12:43:18 -0700604 write_lock_bh(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -0700605
Olof Johansson91b9a272005-08-09 20:24:39 -0700606 n = tn->child[i];
607 if (!n) {
Robert Olsson19baf832005-06-21 12:43:18 -0700608 write_unlock_bh(&fib_lock);
Olof Johansson91b9a272005-08-09 20:24:39 -0700609 continue;
Robert Olsson19baf832005-06-21 12:43:18 -0700610 }
Olof Johansson91b9a272005-08-09 20:24:39 -0700611
612 /* compress one level */
613
614 NODE_INIT_PARENT(n, NODE_TYPE(n));
615
Robert Olsson19baf832005-06-21 12:43:18 -0700616 write_unlock_bh(&fib_lock);
Olof Johansson91b9a272005-08-09 20:24:39 -0700617 tnode_free(tn);
618 return n;
Robert Olsson19baf832005-06-21 12:43:18 -0700619 }
620
621 return (struct node *) tn;
622}
623
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700624static struct tnode *inflate(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700625{
626 struct tnode *inode;
627 struct tnode *oldtnode = tn;
628 int olen = tnode_child_length(tn);
629 int i;
630
Olof Johansson91b9a272005-08-09 20:24:39 -0700631 DBG("In inflate\n");
Robert Olsson19baf832005-06-21 12:43:18 -0700632
633 tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
634
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700635 if (!tn)
636 return ERR_PTR(-ENOMEM);
Robert Olsson2f368952005-07-05 15:02:40 -0700637
638 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700639 * Preallocate and store tnodes before the actual work so we
640 * don't get into an inconsistent state if memory allocation
641 * fails. In case of failure we return the oldnode and inflate
Robert Olsson2f368952005-07-05 15:02:40 -0700642 * of tnode is ignored.
643 */
Olof Johansson91b9a272005-08-09 20:24:39 -0700644
645 for (i = 0; i < olen; i++) {
Robert Olsson2f368952005-07-05 15:02:40 -0700646 struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i);
647
648 if (inode &&
649 IS_TNODE(inode) &&
650 inode->pos == oldtnode->pos + oldtnode->bits &&
651 inode->bits > 1) {
652 struct tnode *left, *right;
Robert Olsson2f368952005-07-05 15:02:40 -0700653 t_key m = TKEY_GET_MASK(inode->pos, 1);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700654
Robert Olsson2f368952005-07-05 15:02:40 -0700655 left = tnode_new(inode->key&(~m), inode->pos + 1,
656 inode->bits - 1);
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700657 if (!left)
658 goto nomem;
Olof Johansson91b9a272005-08-09 20:24:39 -0700659
Robert Olsson2f368952005-07-05 15:02:40 -0700660 right = tnode_new(inode->key|m, inode->pos + 1,
661 inode->bits - 1);
662
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700663 if (!right) {
664 tnode_free(left);
665 goto nomem;
666 }
Robert Olsson2f368952005-07-05 15:02:40 -0700667
668 put_child(t, tn, 2*i, (struct node *) left);
669 put_child(t, tn, 2*i+1, (struct node *) right);
670 }
671 }
672
Olof Johansson91b9a272005-08-09 20:24:39 -0700673 for (i = 0; i < olen; i++) {
Robert Olsson19baf832005-06-21 12:43:18 -0700674 struct node *node = tnode_get_child(oldtnode, i);
Olof Johansson91b9a272005-08-09 20:24:39 -0700675 struct tnode *left, *right;
676 int size, j;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700677
Robert Olsson19baf832005-06-21 12:43:18 -0700678 /* An empty child */
679 if (node == NULL)
680 continue;
681
682 /* A leaf or an internal node with skipped bits */
683
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700684 if (IS_LEAF(node) || ((struct tnode *) node)->pos >
Robert Olsson19baf832005-06-21 12:43:18 -0700685 tn->pos + tn->bits - 1) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700686 if (tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits,
Robert Olsson19baf832005-06-21 12:43:18 -0700687 1) == 0)
688 put_child(t, tn, 2*i, node);
689 else
690 put_child(t, tn, 2*i+1, node);
691 continue;
692 }
693
694 /* An internal node with two children */
695 inode = (struct tnode *) node;
696
697 if (inode->bits == 1) {
698 put_child(t, tn, 2*i, inode->child[0]);
699 put_child(t, tn, 2*i+1, inode->child[1]);
700
701 tnode_free(inode);
Olof Johansson91b9a272005-08-09 20:24:39 -0700702 continue;
Robert Olsson19baf832005-06-21 12:43:18 -0700703 }
704
Olof Johansson91b9a272005-08-09 20:24:39 -0700705 /* An internal node with more than two children */
Robert Olsson19baf832005-06-21 12:43:18 -0700706
Olof Johansson91b9a272005-08-09 20:24:39 -0700707 /* We will replace this node 'inode' with two new
708 * ones, 'left' and 'right', each with half of the
709 * original children. The two new nodes will have
710 * a position one bit further down the key and this
711 * means that the "significant" part of their keys
712 * (see the discussion near the top of this file)
713 * will differ by one bit, which will be "0" in
714 * left's key and "1" in right's key. Since we are
715 * moving the key position by one step, the bit that
716 * we are moving away from - the bit at position
717 * (inode->pos) - is the one that will differ between
718 * left and right. So... we synthesize that bit in the
719 * two new keys.
720 * The mask 'm' below will be a single "one" bit at
721 * the position (inode->pos)
722 */
Robert Olsson19baf832005-06-21 12:43:18 -0700723
Olof Johansson91b9a272005-08-09 20:24:39 -0700724 /* Use the old key, but set the new significant
725 * bit to zero.
726 */
Robert Olsson19baf832005-06-21 12:43:18 -0700727
Olof Johansson91b9a272005-08-09 20:24:39 -0700728 left = (struct tnode *) tnode_get_child(tn, 2*i);
729 put_child(t, tn, 2*i, NULL);
Robert Olsson19baf832005-06-21 12:43:18 -0700730
Olof Johansson91b9a272005-08-09 20:24:39 -0700731 BUG_ON(!left);
Robert Olsson2f368952005-07-05 15:02:40 -0700732
Olof Johansson91b9a272005-08-09 20:24:39 -0700733 right = (struct tnode *) tnode_get_child(tn, 2*i+1);
734 put_child(t, tn, 2*i+1, NULL);
Robert Olsson2f368952005-07-05 15:02:40 -0700735
Olof Johansson91b9a272005-08-09 20:24:39 -0700736 BUG_ON(!right);
Robert Olsson2f368952005-07-05 15:02:40 -0700737
Olof Johansson91b9a272005-08-09 20:24:39 -0700738 size = tnode_child_length(left);
739 for (j = 0; j < size; j++) {
740 put_child(t, left, j, inode->child[j]);
741 put_child(t, right, j, inode->child[j + size]);
Robert Olsson19baf832005-06-21 12:43:18 -0700742 }
Olof Johansson91b9a272005-08-09 20:24:39 -0700743 put_child(t, tn, 2*i, resize(t, left));
744 put_child(t, tn, 2*i+1, resize(t, right));
745
746 tnode_free(inode);
Robert Olsson19baf832005-06-21 12:43:18 -0700747 }
748 tnode_free(oldtnode);
749 return tn;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700750nomem:
751 {
752 int size = tnode_child_length(tn);
753 int j;
754
755 for(j = 0; j < size; j++)
756 if (tn->child[j])
757 tnode_free((struct tnode *)tn->child[j]);
758
759 tnode_free(tn);
760
761 return ERR_PTR(-ENOMEM);
762 }
Robert Olsson19baf832005-06-21 12:43:18 -0700763}
764
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700765static struct tnode *halve(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700766{
767 struct tnode *oldtnode = tn;
768 struct node *left, *right;
769 int i;
770 int olen = tnode_child_length(tn);
771
Olof Johansson91b9a272005-08-09 20:24:39 -0700772 DBG("In halve\n");
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700773
774 tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
Robert Olsson19baf832005-06-21 12:43:18 -0700775
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700776 if (!tn)
777 return ERR_PTR(-ENOMEM);
Robert Olsson2f368952005-07-05 15:02:40 -0700778
779 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700780 * Preallocate and store tnodes before the actual work so we
781 * don't get into an inconsistent state if memory allocation
782 * fails. In case of failure we return the oldnode and halve
Robert Olsson2f368952005-07-05 15:02:40 -0700783 * of tnode is ignored.
784 */
785
Olof Johansson91b9a272005-08-09 20:24:39 -0700786 for (i = 0; i < olen; i += 2) {
Robert Olsson2f368952005-07-05 15:02:40 -0700787 left = tnode_get_child(oldtnode, i);
788 right = tnode_get_child(oldtnode, i+1);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700789
Robert Olsson2f368952005-07-05 15:02:40 -0700790 /* Two nonempty children */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700791 if (left && right) {
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700792 struct tnode *newn;
793
794 newn = tnode_new(left->key, tn->pos + tn->bits, 1);
795
796 if (!newn)
797 goto nomem;
798
799 put_child(t, tn, i/2, (struct node *)newn);
Robert Olsson2f368952005-07-05 15:02:40 -0700800 }
Robert Olsson2f368952005-07-05 15:02:40 -0700801
Robert Olsson2f368952005-07-05 15:02:40 -0700802 }
Robert Olsson19baf832005-06-21 12:43:18 -0700803
Olof Johansson91b9a272005-08-09 20:24:39 -0700804 for (i = 0; i < olen; i += 2) {
805 struct tnode *newBinNode;
806
Robert Olsson19baf832005-06-21 12:43:18 -0700807 left = tnode_get_child(oldtnode, i);
808 right = tnode_get_child(oldtnode, i+1);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700809
Robert Olsson19baf832005-06-21 12:43:18 -0700810 /* At least one of the children is empty */
811 if (left == NULL) {
812 if (right == NULL) /* Both are empty */
813 continue;
814 put_child(t, tn, i/2, right);
Olof Johansson91b9a272005-08-09 20:24:39 -0700815 continue;
816 }
817
818 if (right == NULL) {
Robert Olsson19baf832005-06-21 12:43:18 -0700819 put_child(t, tn, i/2, left);
Olof Johansson91b9a272005-08-09 20:24:39 -0700820 continue;
821 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700822
Robert Olsson19baf832005-06-21 12:43:18 -0700823 /* Two nonempty children */
Olof Johansson91b9a272005-08-09 20:24:39 -0700824 newBinNode = (struct tnode *) tnode_get_child(tn, i/2);
825 put_child(t, tn, i/2, NULL);
Robert Olsson19baf832005-06-21 12:43:18 -0700826
Olof Johansson91b9a272005-08-09 20:24:39 -0700827 BUG_ON(!newBinNode);
Robert Olsson19baf832005-06-21 12:43:18 -0700828
Olof Johansson91b9a272005-08-09 20:24:39 -0700829 put_child(t, newBinNode, 0, left);
830 put_child(t, newBinNode, 1, right);
831 put_child(t, tn, i/2, resize(t, newBinNode));
Robert Olsson19baf832005-06-21 12:43:18 -0700832 }
833 tnode_free(oldtnode);
834 return tn;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700835nomem:
836 {
837 int size = tnode_child_length(tn);
838 int j;
839
840 for(j = 0; j < size; j++)
841 if (tn->child[j])
842 tnode_free((struct tnode *)tn->child[j]);
843
844 tnode_free(tn);
845
846 return ERR_PTR(-ENOMEM);
847 }
Robert Olsson19baf832005-06-21 12:43:18 -0700848}
849
Olof Johansson91b9a272005-08-09 20:24:39 -0700850static void trie_init(struct trie *t)
Robert Olsson19baf832005-06-21 12:43:18 -0700851{
Olof Johansson91b9a272005-08-09 20:24:39 -0700852 if (!t)
853 return;
854
855 t->size = 0;
856 t->trie = NULL;
857 t->revision = 0;
Robert Olsson19baf832005-06-21 12:43:18 -0700858#ifdef CONFIG_IP_FIB_TRIE_STATS
Olof Johansson91b9a272005-08-09 20:24:39 -0700859 memset(&t->stats, 0, sizeof(struct trie_use_stats));
Robert Olsson19baf832005-06-21 12:43:18 -0700860#endif
Robert Olsson19baf832005-06-21 12:43:18 -0700861}
862
863static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen)
864{
865 struct hlist_node *node;
866 struct leaf_info *li;
867
Olof Johansson91b9a272005-08-09 20:24:39 -0700868 hlist_for_each_entry(li, node, head, hlist)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700869 if (li->plen == plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700870 return li;
Olof Johansson91b9a272005-08-09 20:24:39 -0700871
Robert Olsson19baf832005-06-21 12:43:18 -0700872 return NULL;
873}
874
875static inline struct list_head * get_fa_head(struct leaf *l, int plen)
876{
Robert Olsson19baf832005-06-21 12:43:18 -0700877 struct leaf_info *li = find_leaf_info(&l->list, plen);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700878
Olof Johansson91b9a272005-08-09 20:24:39 -0700879 if (!li)
880 return NULL;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700881
Olof Johansson91b9a272005-08-09 20:24:39 -0700882 return &li->falh;
Robert Olsson19baf832005-06-21 12:43:18 -0700883}
884
885static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new)
886{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700887 struct leaf_info *li = NULL, *last = NULL;
Olof Johansson91b9a272005-08-09 20:24:39 -0700888 struct hlist_node *node;
Robert Olsson19baf832005-06-21 12:43:18 -0700889
890 write_lock_bh(&fib_lock);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700891
Olof Johansson91b9a272005-08-09 20:24:39 -0700892 if (hlist_empty(head)) {
Robert Olsson19baf832005-06-21 12:43:18 -0700893 hlist_add_head(&new->hlist, head);
Olof Johansson91b9a272005-08-09 20:24:39 -0700894 } else {
895 hlist_for_each_entry(li, node, head, hlist) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700896 if (new->plen > li->plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700897 break;
Olof Johansson91b9a272005-08-09 20:24:39 -0700898
Robert Olsson19baf832005-06-21 12:43:18 -0700899 last = li;
900 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700901 if (last)
Robert Olsson19baf832005-06-21 12:43:18 -0700902 hlist_add_after(&last->hlist, &new->hlist);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700903 else
Robert Olsson19baf832005-06-21 12:43:18 -0700904 hlist_add_before(&new->hlist, &li->hlist);
905 }
906 write_unlock_bh(&fib_lock);
907}
908
909static struct leaf *
910fib_find_node(struct trie *t, u32 key)
911{
912 int pos;
913 struct tnode *tn;
914 struct node *n;
915
916 pos = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700917 n = t->trie;
Robert Olsson19baf832005-06-21 12:43:18 -0700918
919 while (n != NULL && NODE_TYPE(n) == T_TNODE) {
920 tn = (struct tnode *) n;
Olof Johansson91b9a272005-08-09 20:24:39 -0700921
Robert Olsson19baf832005-06-21 12:43:18 -0700922 check_tnode(tn);
Olof Johansson91b9a272005-08-09 20:24:39 -0700923
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700924 if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700925 pos = tn->pos + tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -0700926 n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
Olof Johansson91b9a272005-08-09 20:24:39 -0700927 } else
Robert Olsson19baf832005-06-21 12:43:18 -0700928 break;
929 }
930 /* Case we have found a leaf. Compare prefixes */
931
Olof Johansson91b9a272005-08-09 20:24:39 -0700932 if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))
933 return (struct leaf *)n;
934
Robert Olsson19baf832005-06-21 12:43:18 -0700935 return NULL;
936}
937
938static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
939{
Olof Johansson91b9a272005-08-09 20:24:39 -0700940 int i;
Robert Olsson19baf832005-06-21 12:43:18 -0700941 int wasfull;
942 t_key cindex, key;
943 struct tnode *tp = NULL;
944
Olof Johansson91b9a272005-08-09 20:24:39 -0700945 BUG_ON(!tn);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700946
Robert Olsson19baf832005-06-21 12:43:18 -0700947 key = tn->key;
948 i = 0;
949
950 while (tn != NULL && NODE_PARENT(tn) != NULL) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700951 if (i > 10) {
Robert Olsson19baf832005-06-21 12:43:18 -0700952 printk("Rebalance tn=%p \n", tn);
Olof Johansson91b9a272005-08-09 20:24:39 -0700953 if (tn)
954 printk("tn->parent=%p \n", NODE_PARENT(tn));
955
Robert Olsson19baf832005-06-21 12:43:18 -0700956 printk("Rebalance tp=%p \n", tp);
Olof Johansson91b9a272005-08-09 20:24:39 -0700957 if (tp)
958 printk("tp->parent=%p \n", NODE_PARENT(tp));
Robert Olsson19baf832005-06-21 12:43:18 -0700959 }
960
Olof Johansson91b9a272005-08-09 20:24:39 -0700961 BUG_ON(i > 12); /* Why is this a bug? -ojn */
Robert Olsson19baf832005-06-21 12:43:18 -0700962 i++;
963
964 tp = NODE_PARENT(tn);
965 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
966 wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
967 tn = (struct tnode *) resize (t, (struct tnode *)tn);
968 tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull);
Olof Johansson91b9a272005-08-09 20:24:39 -0700969
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700970 if (!NODE_PARENT(tn))
Robert Olsson19baf832005-06-21 12:43:18 -0700971 break;
972
973 tn = NODE_PARENT(tn);
974 }
975 /* Handle last (top) tnode */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700976 if (IS_TNODE(tn))
Robert Olsson19baf832005-06-21 12:43:18 -0700977 tn = (struct tnode*) resize(t, (struct tnode *)tn);
978
979 return (struct node*) tn;
980}
981
Robert Olssonf835e472005-06-28 15:00:39 -0700982static struct list_head *
983fib_insert_node(struct trie *t, int *err, u32 key, int plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700984{
985 int pos, newpos;
986 struct tnode *tp = NULL, *tn = NULL;
987 struct node *n;
988 struct leaf *l;
989 int missbit;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700990 struct list_head *fa_head = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -0700991 struct leaf_info *li;
992 t_key cindex;
993
994 pos = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700995 n = t->trie;
Robert Olsson19baf832005-06-21 12:43:18 -0700996
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700997 /* If we point to NULL, stop. Either the tree is empty and we should
998 * just put a new leaf in if, or we have reached an empty child slot,
Robert Olsson19baf832005-06-21 12:43:18 -0700999 * and we should just put our new leaf in that.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001000 * If we point to a T_TNODE, check if it matches our key. Note that
1001 * a T_TNODE might be skipping any number of bits - its 'pos' need
Robert Olsson19baf832005-06-21 12:43:18 -07001002 * not be the parent's 'pos'+'bits'!
1003 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001004 * If it does match the current key, get pos/bits from it, extract
Robert Olsson19baf832005-06-21 12:43:18 -07001005 * the index from our key, push the T_TNODE and walk the tree.
1006 *
1007 * If it doesn't, we have to replace it with a new T_TNODE.
1008 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001009 * If we point to a T_LEAF, it might or might not have the same key
1010 * as we do. If it does, just change the value, update the T_LEAF's
1011 * value, and return it.
Robert Olsson19baf832005-06-21 12:43:18 -07001012 * If it doesn't, we need to replace it with a T_TNODE.
1013 */
1014
1015 while (n != NULL && NODE_TYPE(n) == T_TNODE) {
1016 tn = (struct tnode *) n;
Olof Johansson91b9a272005-08-09 20:24:39 -07001017
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001018 check_tnode(tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001019
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001020 if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
Robert Olsson19baf832005-06-21 12:43:18 -07001021 tp = tn;
Olof Johansson91b9a272005-08-09 20:24:39 -07001022 pos = tn->pos + tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -07001023 n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
1024
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001025 if (n && NODE_PARENT(n) != tn) {
Robert Olsson19baf832005-06-21 12:43:18 -07001026 printk("BUG tn=%p, n->parent=%p\n", tn, NODE_PARENT(n));
1027 BUG();
1028 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001029 } else
Robert Olsson19baf832005-06-21 12:43:18 -07001030 break;
1031 }
1032
1033 /*
1034 * n ----> NULL, LEAF or TNODE
1035 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001036 * tp is n's (parent) ----> NULL or TNODE
Robert Olsson19baf832005-06-21 12:43:18 -07001037 */
1038
Olof Johansson91b9a272005-08-09 20:24:39 -07001039 BUG_ON(tp && IS_LEAF(tp));
Robert Olsson19baf832005-06-21 12:43:18 -07001040
1041 /* Case 1: n is a leaf. Compare prefixes */
1042
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001043 if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
Olof Johansson91b9a272005-08-09 20:24:39 -07001044 struct leaf *l = (struct leaf *) n;
1045
Robert Olsson19baf832005-06-21 12:43:18 -07001046 li = leaf_info_new(plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001047
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001048 if (!li) {
Robert Olssonf835e472005-06-28 15:00:39 -07001049 *err = -ENOMEM;
1050 goto err;
1051 }
Robert Olsson19baf832005-06-21 12:43:18 -07001052
1053 fa_head = &li->falh;
1054 insert_leaf_info(&l->list, li);
1055 goto done;
1056 }
1057 t->size++;
1058 l = leaf_new();
1059
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001060 if (!l) {
Robert Olssonf835e472005-06-28 15:00:39 -07001061 *err = -ENOMEM;
1062 goto err;
1063 }
Robert Olsson19baf832005-06-21 12:43:18 -07001064
1065 l->key = key;
1066 li = leaf_info_new(plen);
1067
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001068 if (!li) {
Robert Olssonf835e472005-06-28 15:00:39 -07001069 tnode_free((struct tnode *) l);
1070 *err = -ENOMEM;
1071 goto err;
1072 }
Robert Olsson19baf832005-06-21 12:43:18 -07001073
1074 fa_head = &li->falh;
1075 insert_leaf_info(&l->list, li);
1076
Robert Olsson19baf832005-06-21 12:43:18 -07001077 if (t->trie && n == NULL) {
Olof Johansson91b9a272005-08-09 20:24:39 -07001078 /* Case 2: n is NULL, and will just insert a new leaf */
Robert Olsson19baf832005-06-21 12:43:18 -07001079
1080 NODE_SET_PARENT(l, tp);
Robert Olsson19baf832005-06-21 12:43:18 -07001081
Olof Johansson91b9a272005-08-09 20:24:39 -07001082 BUG_ON(!tp);
1083
1084 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1085 put_child(t, (struct tnode *)tp, cindex, (struct node *)l);
1086 } else {
1087 /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001088 /*
1089 * Add a new tnode here
Robert Olsson19baf832005-06-21 12:43:18 -07001090 * first tnode need some special handling
1091 */
1092
1093 if (tp)
Olof Johansson91b9a272005-08-09 20:24:39 -07001094 pos = tp->pos+tp->bits;
Robert Olsson19baf832005-06-21 12:43:18 -07001095 else
Olof Johansson91b9a272005-08-09 20:24:39 -07001096 pos = 0;
1097
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001098 if (n) {
Robert Olsson19baf832005-06-21 12:43:18 -07001099 newpos = tkey_mismatch(key, pos, n->key);
1100 tn = tnode_new(n->key, newpos, 1);
Olof Johansson91b9a272005-08-09 20:24:39 -07001101 } else {
Robert Olsson19baf832005-06-21 12:43:18 -07001102 newpos = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001103 tn = tnode_new(key, newpos, 1); /* First tnode */
Robert Olsson19baf832005-06-21 12:43:18 -07001104 }
Robert Olsson19baf832005-06-21 12:43:18 -07001105
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001106 if (!tn) {
Robert Olssonf835e472005-06-28 15:00:39 -07001107 free_leaf_info(li);
1108 tnode_free((struct tnode *) l);
1109 *err = -ENOMEM;
1110 goto err;
Olof Johansson91b9a272005-08-09 20:24:39 -07001111 }
1112
Robert Olsson19baf832005-06-21 12:43:18 -07001113 NODE_SET_PARENT(tn, tp);
1114
Olof Johansson91b9a272005-08-09 20:24:39 -07001115 missbit = tkey_extract_bits(key, newpos, 1);
Robert Olsson19baf832005-06-21 12:43:18 -07001116 put_child(t, tn, missbit, (struct node *)l);
1117 put_child(t, tn, 1-missbit, n);
1118
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001119 if (tp) {
Robert Olsson19baf832005-06-21 12:43:18 -07001120 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1121 put_child(t, (struct tnode *)tp, cindex, (struct node *)tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001122 } else {
Robert Olsson19baf832005-06-21 12:43:18 -07001123 t->trie = (struct node*) tn; /* First tnode */
1124 tp = tn;
1125 }
1126 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001127
1128 if (tp && tp->pos + tp->bits > 32)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001129 printk("ERROR tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
Robert Olsson19baf832005-06-21 12:43:18 -07001130 tp, tp->pos, tp->bits, key, plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001131
Robert Olsson19baf832005-06-21 12:43:18 -07001132 /* Rebalance the trie */
1133 t->trie = trie_rebalance(t, tp);
Robert Olssonf835e472005-06-28 15:00:39 -07001134done:
1135 t->revision++;
Olof Johansson91b9a272005-08-09 20:24:39 -07001136err:
Robert Olsson19baf832005-06-21 12:43:18 -07001137 return fa_head;
1138}
1139
1140static int
1141fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
1142 struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
1143{
1144 struct trie *t = (struct trie *) tb->tb_data;
1145 struct fib_alias *fa, *new_fa;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001146 struct list_head *fa_head = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001147 struct fib_info *fi;
1148 int plen = r->rtm_dst_len;
1149 int type = r->rtm_type;
1150 u8 tos = r->rtm_tos;
1151 u32 key, mask;
1152 int err;
1153 struct leaf *l;
1154
1155 if (plen > 32)
1156 return -EINVAL;
1157
1158 key = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001159 if (rta->rta_dst)
Robert Olsson19baf832005-06-21 12:43:18 -07001160 memcpy(&key, rta->rta_dst, 4);
1161
1162 key = ntohl(key);
1163
Olof Johansson91b9a272005-08-09 20:24:39 -07001164 DBG("Insert table=%d %08x/%d\n", tb->tb_id, key, plen);
Robert Olsson19baf832005-06-21 12:43:18 -07001165
Olof Johansson91b9a272005-08-09 20:24:39 -07001166 mask = ntohl(inet_make_mask(plen));
Robert Olsson19baf832005-06-21 12:43:18 -07001167
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001168 if (key & ~mask)
Robert Olsson19baf832005-06-21 12:43:18 -07001169 return -EINVAL;
1170
1171 key = key & mask;
1172
Olof Johansson91b9a272005-08-09 20:24:39 -07001173 fi = fib_create_info(r, rta, nlhdr, &err);
1174
1175 if (!fi)
Robert Olsson19baf832005-06-21 12:43:18 -07001176 goto err;
1177
1178 l = fib_find_node(t, key);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001179 fa = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001180
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001181 if (l) {
Robert Olsson19baf832005-06-21 12:43:18 -07001182 fa_head = get_fa_head(l, plen);
1183 fa = fib_find_alias(fa_head, tos, fi->fib_priority);
1184 }
1185
1186 /* Now fa, if non-NULL, points to the first fib alias
1187 * with the same keys [prefix,tos,priority], if such key already
1188 * exists or to the node before which we will insert new one.
1189 *
1190 * If fa is NULL, we will need to allocate a new one and
1191 * insert to the head of f.
1192 *
1193 * If f is NULL, no fib node matched the destination key
1194 * and we need to allocate a new one of those as well.
1195 */
1196
Olof Johansson91b9a272005-08-09 20:24:39 -07001197 if (fa && fa->fa_info->fib_priority == fi->fib_priority) {
Robert Olsson19baf832005-06-21 12:43:18 -07001198 struct fib_alias *fa_orig;
1199
1200 err = -EEXIST;
1201 if (nlhdr->nlmsg_flags & NLM_F_EXCL)
1202 goto out;
1203
1204 if (nlhdr->nlmsg_flags & NLM_F_REPLACE) {
1205 struct fib_info *fi_drop;
1206 u8 state;
1207
1208 write_lock_bh(&fib_lock);
1209
1210 fi_drop = fa->fa_info;
1211 fa->fa_info = fi;
1212 fa->fa_type = type;
1213 fa->fa_scope = r->rtm_scope;
1214 state = fa->fa_state;
1215 fa->fa_state &= ~FA_S_ACCESSED;
1216
1217 write_unlock_bh(&fib_lock);
1218
1219 fib_release_info(fi_drop);
1220 if (state & FA_S_ACCESSED)
Olof Johansson91b9a272005-08-09 20:24:39 -07001221 rt_cache_flush(-1);
Robert Olsson19baf832005-06-21 12:43:18 -07001222
Olof Johansson91b9a272005-08-09 20:24:39 -07001223 goto succeeded;
Robert Olsson19baf832005-06-21 12:43:18 -07001224 }
1225 /* Error if we find a perfect match which
1226 * uses the same scope, type, and nexthop
1227 * information.
1228 */
1229 fa_orig = fa;
1230 list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) {
1231 if (fa->fa_tos != tos)
1232 break;
1233 if (fa->fa_info->fib_priority != fi->fib_priority)
1234 break;
1235 if (fa->fa_type == type &&
1236 fa->fa_scope == r->rtm_scope &&
1237 fa->fa_info == fi) {
1238 goto out;
1239 }
1240 }
1241 if (!(nlhdr->nlmsg_flags & NLM_F_APPEND))
1242 fa = fa_orig;
1243 }
1244 err = -ENOENT;
Olof Johansson91b9a272005-08-09 20:24:39 -07001245 if (!(nlhdr->nlmsg_flags & NLM_F_CREATE))
Robert Olsson19baf832005-06-21 12:43:18 -07001246 goto out;
1247
1248 err = -ENOBUFS;
1249 new_fa = kmem_cache_alloc(fn_alias_kmem, SLAB_KERNEL);
1250 if (new_fa == NULL)
1251 goto out;
1252
1253 new_fa->fa_info = fi;
1254 new_fa->fa_tos = tos;
1255 new_fa->fa_type = type;
1256 new_fa->fa_scope = r->rtm_scope;
1257 new_fa->fa_state = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001258 /*
1259 * Insert new entry to the list.
1260 */
1261
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001262 if (!fa_head) {
Robert Olssonf835e472005-06-28 15:00:39 -07001263 fa_head = fib_insert_node(t, &err, key, plen);
1264 err = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001265 if (err)
Robert Olssonf835e472005-06-28 15:00:39 -07001266 goto out_free_new_fa;
1267 }
Robert Olsson19baf832005-06-21 12:43:18 -07001268
1269 write_lock_bh(&fib_lock);
1270
Olof Johansson91b9a272005-08-09 20:24:39 -07001271 list_add_tail(&new_fa->fa_list, (fa ? &fa->fa_list : fa_head));
Robert Olsson19baf832005-06-21 12:43:18 -07001272
1273 write_unlock_bh(&fib_lock);
1274
1275 rt_cache_flush(-1);
1276 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req);
1277succeeded:
1278 return 0;
Robert Olssonf835e472005-06-28 15:00:39 -07001279
1280out_free_new_fa:
1281 kmem_cache_free(fn_alias_kmem, new_fa);
Robert Olsson19baf832005-06-21 12:43:18 -07001282out:
1283 fib_release_info(fi);
Olof Johansson91b9a272005-08-09 20:24:39 -07001284err:
Robert Olsson19baf832005-06-21 12:43:18 -07001285 return err;
1286}
1287
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001288static inline int check_leaf(struct trie *t, struct leaf *l, t_key key, int *plen, const struct flowi *flp,
Patrick McHardy06c74272005-08-23 22:06:09 -07001289 struct fib_result *res)
Robert Olsson19baf832005-06-21 12:43:18 -07001290{
Patrick McHardy06c74272005-08-23 22:06:09 -07001291 int err, i;
Robert Olsson19baf832005-06-21 12:43:18 -07001292 t_key mask;
1293 struct leaf_info *li;
1294 struct hlist_head *hhead = &l->list;
1295 struct hlist_node *node;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001296
Robert Olsson19baf832005-06-21 12:43:18 -07001297 hlist_for_each_entry(li, node, hhead, hlist) {
Robert Olsson19baf832005-06-21 12:43:18 -07001298 i = li->plen;
1299 mask = ntohl(inet_make_mask(i));
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001300 if (l->key != (key & mask))
Robert Olsson19baf832005-06-21 12:43:18 -07001301 continue;
1302
Patrick McHardy06c74272005-08-23 22:06:09 -07001303 if ((err = fib_semantic_match(&li->falh, flp, res, l->key, mask, i)) <= 0) {
Robert Olsson19baf832005-06-21 12:43:18 -07001304 *plen = i;
1305#ifdef CONFIG_IP_FIB_TRIE_STATS
1306 t->stats.semantic_match_passed++;
1307#endif
Patrick McHardy06c74272005-08-23 22:06:09 -07001308 return err;
Robert Olsson19baf832005-06-21 12:43:18 -07001309 }
1310#ifdef CONFIG_IP_FIB_TRIE_STATS
1311 t->stats.semantic_match_miss++;
1312#endif
1313 }
Patrick McHardy06c74272005-08-23 22:06:09 -07001314 return 1;
Robert Olsson19baf832005-06-21 12:43:18 -07001315}
1316
1317static int
1318fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
1319{
1320 struct trie *t = (struct trie *) tb->tb_data;
1321 int plen, ret = 0;
1322 struct node *n;
1323 struct tnode *pn;
1324 int pos, bits;
Olof Johansson91b9a272005-08-09 20:24:39 -07001325 t_key key = ntohl(flp->fl4_dst);
Robert Olsson19baf832005-06-21 12:43:18 -07001326 int chopped_off;
1327 t_key cindex = 0;
1328 int current_prefix_length = KEYLENGTH;
Olof Johansson91b9a272005-08-09 20:24:39 -07001329 struct tnode *cn;
1330 t_key node_prefix, key_prefix, pref_mismatch;
1331 int mp;
1332
Robert Olsson19baf832005-06-21 12:43:18 -07001333 n = t->trie;
1334
1335 read_lock(&fib_lock);
Olof Johansson91b9a272005-08-09 20:24:39 -07001336
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001337 if (!n)
Robert Olsson19baf832005-06-21 12:43:18 -07001338 goto failed;
1339
1340#ifdef CONFIG_IP_FIB_TRIE_STATS
1341 t->stats.gets++;
1342#endif
1343
1344 /* Just a leaf? */
1345 if (IS_LEAF(n)) {
Patrick McHardy06c74272005-08-23 22:06:09 -07001346 if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
Robert Olsson19baf832005-06-21 12:43:18 -07001347 goto found;
1348 goto failed;
1349 }
1350 pn = (struct tnode *) n;
1351 chopped_off = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001352
Olof Johansson91b9a272005-08-09 20:24:39 -07001353 while (pn) {
Robert Olsson19baf832005-06-21 12:43:18 -07001354 pos = pn->pos;
1355 bits = pn->bits;
1356
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001357 if (!chopped_off)
Robert Olsson19baf832005-06-21 12:43:18 -07001358 cindex = tkey_extract_bits(MASK_PFX(key, current_prefix_length), pos, bits);
1359
1360 n = tnode_get_child(pn, cindex);
1361
1362 if (n == NULL) {
1363#ifdef CONFIG_IP_FIB_TRIE_STATS
1364 t->stats.null_node_hit++;
1365#endif
1366 goto backtrace;
1367 }
1368
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001369 if (IS_LEAF(n)) {
Patrick McHardy06c74272005-08-23 22:06:09 -07001370 if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
Robert Olsson19baf832005-06-21 12:43:18 -07001371 goto found;
Olof Johansson91b9a272005-08-09 20:24:39 -07001372 else
1373 goto backtrace;
1374 }
1375
1376#define HL_OPTIMIZE
1377#ifdef HL_OPTIMIZE
1378 cn = (struct tnode *)n;
1379
1380 /*
1381 * It's a tnode, and we can do some extra checks here if we
1382 * like, to avoid descending into a dead-end branch.
1383 * This tnode is in the parent's child array at index
1384 * key[p_pos..p_pos+p_bits] but potentially with some bits
1385 * chopped off, so in reality the index may be just a
1386 * subprefix, padded with zero at the end.
1387 * We can also take a look at any skipped bits in this
1388 * tnode - everything up to p_pos is supposed to be ok,
1389 * and the non-chopped bits of the index (se previous
1390 * paragraph) are also guaranteed ok, but the rest is
1391 * considered unknown.
1392 *
1393 * The skipped bits are key[pos+bits..cn->pos].
1394 */
1395
1396 /* If current_prefix_length < pos+bits, we are already doing
1397 * actual prefix matching, which means everything from
1398 * pos+(bits-chopped_off) onward must be zero along some
1399 * branch of this subtree - otherwise there is *no* valid
1400 * prefix present. Here we can only check the skipped
1401 * bits. Remember, since we have already indexed into the
1402 * parent's child array, we know that the bits we chopped of
1403 * *are* zero.
1404 */
1405
1406 /* NOTA BENE: CHECKING ONLY SKIPPED BITS FOR THE NEW NODE HERE */
1407
1408 if (current_prefix_length < pos+bits) {
1409 if (tkey_extract_bits(cn->key, current_prefix_length,
1410 cn->pos - current_prefix_length) != 0 ||
1411 !(cn->child[0]))
1412 goto backtrace;
1413 }
1414
1415 /*
1416 * If chopped_off=0, the index is fully validated and we
1417 * only need to look at the skipped bits for this, the new,
1418 * tnode. What we actually want to do is to find out if
1419 * these skipped bits match our key perfectly, or if we will
1420 * have to count on finding a matching prefix further down,
1421 * because if we do, we would like to have some way of
1422 * verifying the existence of such a prefix at this point.
1423 */
1424
1425 /* The only thing we can do at this point is to verify that
1426 * any such matching prefix can indeed be a prefix to our
1427 * key, and if the bits in the node we are inspecting that
1428 * do not match our key are not ZERO, this cannot be true.
1429 * Thus, find out where there is a mismatch (before cn->pos)
1430 * and verify that all the mismatching bits are zero in the
1431 * new tnode's key.
1432 */
1433
1434 /* Note: We aren't very concerned about the piece of the key
1435 * that precede pn->pos+pn->bits, since these have already been
1436 * checked. The bits after cn->pos aren't checked since these are
1437 * by definition "unknown" at this point. Thus, what we want to
1438 * see is if we are about to enter the "prefix matching" state,
1439 * and in that case verify that the skipped bits that will prevail
1440 * throughout this subtree are zero, as they have to be if we are
1441 * to find a matching prefix.
1442 */
1443
1444 node_prefix = MASK_PFX(cn->key, cn->pos);
1445 key_prefix = MASK_PFX(key, cn->pos);
1446 pref_mismatch = key_prefix^node_prefix;
1447 mp = 0;
1448
1449 /* In short: If skipped bits in this node do not match the search
1450 * key, enter the "prefix matching" state.directly.
1451 */
1452 if (pref_mismatch) {
1453 while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
1454 mp++;
1455 pref_mismatch = pref_mismatch <<1;
1456 }
1457 key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
1458
1459 if (key_prefix != 0)
1460 goto backtrace;
1461
1462 if (current_prefix_length >= cn->pos)
1463 current_prefix_length = mp;
1464 }
1465#endif
1466 pn = (struct tnode *)n; /* Descend */
1467 chopped_off = 0;
1468 continue;
1469
Robert Olsson19baf832005-06-21 12:43:18 -07001470backtrace:
1471 chopped_off++;
1472
1473 /* As zero don't change the child key (cindex) */
Olof Johansson91b9a272005-08-09 20:24:39 -07001474 while ((chopped_off <= pn->bits) && !(cindex & (1<<(chopped_off-1))))
Robert Olsson19baf832005-06-21 12:43:18 -07001475 chopped_off++;
Robert Olsson19baf832005-06-21 12:43:18 -07001476
1477 /* Decrease current_... with bits chopped off */
1478 if (current_prefix_length > pn->pos + pn->bits - chopped_off)
1479 current_prefix_length = pn->pos + pn->bits - chopped_off;
Olof Johansson91b9a272005-08-09 20:24:39 -07001480
Robert Olsson19baf832005-06-21 12:43:18 -07001481 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001482 * Either we do the actual chop off according or if we have
Robert Olsson19baf832005-06-21 12:43:18 -07001483 * chopped off all bits in this tnode walk up to our parent.
1484 */
1485
Olof Johansson91b9a272005-08-09 20:24:39 -07001486 if (chopped_off <= pn->bits) {
Robert Olsson19baf832005-06-21 12:43:18 -07001487 cindex &= ~(1 << (chopped_off-1));
Olof Johansson91b9a272005-08-09 20:24:39 -07001488 } else {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001489 if (NODE_PARENT(pn) == NULL)
Robert Olsson19baf832005-06-21 12:43:18 -07001490 goto failed;
Olof Johansson91b9a272005-08-09 20:24:39 -07001491
Robert Olsson19baf832005-06-21 12:43:18 -07001492 /* Get Child's index */
1493 cindex = tkey_extract_bits(pn->key, NODE_PARENT(pn)->pos, NODE_PARENT(pn)->bits);
1494 pn = NODE_PARENT(pn);
1495 chopped_off = 0;
1496
1497#ifdef CONFIG_IP_FIB_TRIE_STATS
1498 t->stats.backtrack++;
1499#endif
1500 goto backtrace;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001501 }
Robert Olsson19baf832005-06-21 12:43:18 -07001502 }
1503failed:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001504 ret = 1;
Robert Olsson19baf832005-06-21 12:43:18 -07001505found:
1506 read_unlock(&fib_lock);
1507 return ret;
1508}
1509
1510static int trie_leaf_remove(struct trie *t, t_key key)
1511{
1512 t_key cindex;
1513 struct tnode *tp = NULL;
1514 struct node *n = t->trie;
1515 struct leaf *l;
1516
Olof Johansson91b9a272005-08-09 20:24:39 -07001517 DBG("entering trie_leaf_remove(%p)\n", n);
Robert Olsson19baf832005-06-21 12:43:18 -07001518
1519 /* Note that in the case skipped bits, those bits are *not* checked!
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001520 * When we finish this, we will have NULL or a T_LEAF, and the
Robert Olsson19baf832005-06-21 12:43:18 -07001521 * T_LEAF may or may not match our key.
1522 */
1523
Olof Johansson91b9a272005-08-09 20:24:39 -07001524 while (n != NULL && IS_TNODE(n)) {
Robert Olsson19baf832005-06-21 12:43:18 -07001525 struct tnode *tn = (struct tnode *) n;
1526 check_tnode(tn);
1527 n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits));
1528
Olof Johansson91b9a272005-08-09 20:24:39 -07001529 if (n && NODE_PARENT(n) != tn) {
1530 printk("BUG tn=%p, n->parent=%p\n", tn, NODE_PARENT(n));
1531 BUG();
1532 }
1533 }
Robert Olsson19baf832005-06-21 12:43:18 -07001534 l = (struct leaf *) n;
1535
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001536 if (!n || !tkey_equals(l->key, key))
Robert Olsson19baf832005-06-21 12:43:18 -07001537 return 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001538
1539 /*
1540 * Key found.
1541 * Remove the leaf and rebalance the tree
Robert Olsson19baf832005-06-21 12:43:18 -07001542 */
1543
1544 t->revision++;
1545 t->size--;
1546
1547 tp = NODE_PARENT(n);
1548 tnode_free((struct tnode *) n);
1549
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001550 if (tp) {
Robert Olsson19baf832005-06-21 12:43:18 -07001551 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1552 put_child(t, (struct tnode *)tp, cindex, NULL);
1553 t->trie = trie_rebalance(t, tp);
Olof Johansson91b9a272005-08-09 20:24:39 -07001554 } else
Robert Olsson19baf832005-06-21 12:43:18 -07001555 t->trie = NULL;
1556
1557 return 1;
1558}
1559
1560static int
1561fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
Olof Johansson91b9a272005-08-09 20:24:39 -07001562 struct nlmsghdr *nlhdr, struct netlink_skb_parms *req)
Robert Olsson19baf832005-06-21 12:43:18 -07001563{
1564 struct trie *t = (struct trie *) tb->tb_data;
1565 u32 key, mask;
1566 int plen = r->rtm_dst_len;
1567 u8 tos = r->rtm_tos;
1568 struct fib_alias *fa, *fa_to_delete;
1569 struct list_head *fa_head;
1570 struct leaf *l;
Olof Johansson91b9a272005-08-09 20:24:39 -07001571 int kill_li = 0;
1572 struct leaf_info *li;
1573
Robert Olsson19baf832005-06-21 12:43:18 -07001574
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001575 if (plen > 32)
Robert Olsson19baf832005-06-21 12:43:18 -07001576 return -EINVAL;
1577
1578 key = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001579 if (rta->rta_dst)
Robert Olsson19baf832005-06-21 12:43:18 -07001580 memcpy(&key, rta->rta_dst, 4);
1581
1582 key = ntohl(key);
Olof Johansson91b9a272005-08-09 20:24:39 -07001583 mask = ntohl(inet_make_mask(plen));
Robert Olsson19baf832005-06-21 12:43:18 -07001584
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001585 if (key & ~mask)
Robert Olsson19baf832005-06-21 12:43:18 -07001586 return -EINVAL;
1587
1588 key = key & mask;
1589 l = fib_find_node(t, key);
1590
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001591 if (!l)
Robert Olsson19baf832005-06-21 12:43:18 -07001592 return -ESRCH;
1593
1594 fa_head = get_fa_head(l, plen);
1595 fa = fib_find_alias(fa_head, tos, 0);
1596
1597 if (!fa)
1598 return -ESRCH;
1599
Olof Johansson91b9a272005-08-09 20:24:39 -07001600 DBG("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
Robert Olsson19baf832005-06-21 12:43:18 -07001601
1602 fa_to_delete = NULL;
1603 fa_head = fa->fa_list.prev;
1604 list_for_each_entry(fa, fa_head, fa_list) {
1605 struct fib_info *fi = fa->fa_info;
1606
1607 if (fa->fa_tos != tos)
1608 break;
1609
1610 if ((!r->rtm_type ||
1611 fa->fa_type == r->rtm_type) &&
1612 (r->rtm_scope == RT_SCOPE_NOWHERE ||
1613 fa->fa_scope == r->rtm_scope) &&
1614 (!r->rtm_protocol ||
1615 fi->fib_protocol == r->rtm_protocol) &&
1616 fib_nh_match(r, nlhdr, rta, fi) == 0) {
1617 fa_to_delete = fa;
1618 break;
1619 }
1620 }
1621
Olof Johansson91b9a272005-08-09 20:24:39 -07001622 if (!fa_to_delete)
1623 return -ESRCH;
Robert Olsson19baf832005-06-21 12:43:18 -07001624
Olof Johansson91b9a272005-08-09 20:24:39 -07001625 fa = fa_to_delete;
1626 rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req);
Robert Olsson19baf832005-06-21 12:43:18 -07001627
Olof Johansson91b9a272005-08-09 20:24:39 -07001628 l = fib_find_node(t, key);
1629 li = find_leaf_info(&l->list, plen);
Robert Olsson19baf832005-06-21 12:43:18 -07001630
Olof Johansson91b9a272005-08-09 20:24:39 -07001631 write_lock_bh(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -07001632
Olof Johansson91b9a272005-08-09 20:24:39 -07001633 list_del(&fa->fa_list);
Robert Olsson19baf832005-06-21 12:43:18 -07001634
Olof Johansson91b9a272005-08-09 20:24:39 -07001635 if (list_empty(fa_head)) {
1636 hlist_del(&li->hlist);
1637 kill_li = 1;
Robert Olsson19baf832005-06-21 12:43:18 -07001638 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001639 write_unlock_bh(&fib_lock);
1640
1641 if (kill_li)
1642 free_leaf_info(li);
1643
1644 if (hlist_empty(&l->list))
1645 trie_leaf_remove(t, key);
1646
1647 if (fa->fa_state & FA_S_ACCESSED)
1648 rt_cache_flush(-1);
1649
1650 fn_free_alias(fa);
1651 return 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001652}
1653
1654static int trie_flush_list(struct trie *t, struct list_head *head)
1655{
1656 struct fib_alias *fa, *fa_node;
1657 int found = 0;
1658
1659 list_for_each_entry_safe(fa, fa_node, head, fa_list) {
1660 struct fib_info *fi = fa->fa_info;
Robert Olsson19baf832005-06-21 12:43:18 -07001661
Olof Johansson91b9a272005-08-09 20:24:39 -07001662 if (fi && (fi->fib_flags&RTNH_F_DEAD)) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001663 write_lock_bh(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -07001664 list_del(&fa->fa_list);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001665 write_unlock_bh(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -07001666
1667 fn_free_alias(fa);
1668 found++;
1669 }
1670 }
1671 return found;
1672}
1673
1674static int trie_flush_leaf(struct trie *t, struct leaf *l)
1675{
1676 int found = 0;
1677 struct hlist_head *lih = &l->list;
1678 struct hlist_node *node, *tmp;
1679 struct leaf_info *li = NULL;
1680
1681 hlist_for_each_entry_safe(li, node, tmp, lih, hlist) {
Robert Olsson19baf832005-06-21 12:43:18 -07001682 found += trie_flush_list(t, &li->falh);
1683
1684 if (list_empty(&li->falh)) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001685 write_lock_bh(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -07001686 hlist_del(&li->hlist);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001687 write_unlock_bh(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -07001688
1689 free_leaf_info(li);
1690 }
1691 }
1692 return found;
1693}
1694
1695static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
1696{
1697 struct node *c = (struct node *) thisleaf;
1698 struct tnode *p;
1699 int idx;
1700
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001701 if (c == NULL) {
1702 if (t->trie == NULL)
Robert Olsson19baf832005-06-21 12:43:18 -07001703 return NULL;
1704
1705 if (IS_LEAF(t->trie)) /* trie w. just a leaf */
1706 return (struct leaf *) t->trie;
1707
1708 p = (struct tnode*) t->trie; /* Start */
Olof Johansson91b9a272005-08-09 20:24:39 -07001709 } else
Robert Olsson19baf832005-06-21 12:43:18 -07001710 p = (struct tnode *) NODE_PARENT(c);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001711
Robert Olsson19baf832005-06-21 12:43:18 -07001712 while (p) {
1713 int pos, last;
1714
1715 /* Find the next child of the parent */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001716 if (c)
1717 pos = 1 + tkey_extract_bits(c->key, p->pos, p->bits);
1718 else
Robert Olsson19baf832005-06-21 12:43:18 -07001719 pos = 0;
1720
1721 last = 1 << p->bits;
Olof Johansson91b9a272005-08-09 20:24:39 -07001722 for (idx = pos; idx < last ; idx++) {
1723 if (!p->child[idx])
1724 continue;
Robert Olsson19baf832005-06-21 12:43:18 -07001725
Olof Johansson91b9a272005-08-09 20:24:39 -07001726 /* Decend if tnode */
1727 while (IS_TNODE(p->child[idx])) {
1728 p = (struct tnode*) p->child[idx];
1729 idx = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001730
Olof Johansson91b9a272005-08-09 20:24:39 -07001731 /* Rightmost non-NULL branch */
1732 if (p && IS_TNODE(p))
1733 while (p->child[idx] == NULL && idx < (1 << p->bits)) idx++;
Robert Olsson19baf832005-06-21 12:43:18 -07001734
Olof Johansson91b9a272005-08-09 20:24:39 -07001735 /* Done with this tnode? */
1736 if (idx >= (1 << p->bits) || p->child[idx] == NULL)
1737 goto up;
Robert Olsson19baf832005-06-21 12:43:18 -07001738 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001739 return (struct leaf*) p->child[idx];
Robert Olsson19baf832005-06-21 12:43:18 -07001740 }
1741up:
1742 /* No more children go up one step */
Olof Johansson91b9a272005-08-09 20:24:39 -07001743 c = (struct node *) p;
Robert Olsson19baf832005-06-21 12:43:18 -07001744 p = (struct tnode *) NODE_PARENT(p);
1745 }
1746 return NULL; /* Ready. Root of trie */
1747}
1748
1749static int fn_trie_flush(struct fib_table *tb)
1750{
1751 struct trie *t = (struct trie *) tb->tb_data;
1752 struct leaf *ll = NULL, *l = NULL;
1753 int found = 0, h;
1754
1755 t->revision++;
1756
Olof Johansson91b9a272005-08-09 20:24:39 -07001757 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001758 found += trie_flush_leaf(t, l);
1759
1760 if (ll && hlist_empty(&ll->list))
1761 trie_leaf_remove(t, ll->key);
1762 ll = l;
1763 }
1764
1765 if (ll && hlist_empty(&ll->list))
1766 trie_leaf_remove(t, ll->key);
1767
Olof Johansson91b9a272005-08-09 20:24:39 -07001768 DBG("trie_flush found=%d\n", found);
Robert Olsson19baf832005-06-21 12:43:18 -07001769 return found;
1770}
1771
Olof Johansson91b9a272005-08-09 20:24:39 -07001772static int trie_last_dflt = -1;
Robert Olsson19baf832005-06-21 12:43:18 -07001773
1774static void
1775fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
1776{
1777 struct trie *t = (struct trie *) tb->tb_data;
1778 int order, last_idx;
1779 struct fib_info *fi = NULL;
1780 struct fib_info *last_resort;
1781 struct fib_alias *fa = NULL;
1782 struct list_head *fa_head;
1783 struct leaf *l;
1784
1785 last_idx = -1;
1786 last_resort = NULL;
1787 order = -1;
1788
1789 read_lock(&fib_lock);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001790
Robert Olsson19baf832005-06-21 12:43:18 -07001791 l = fib_find_node(t, 0);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001792 if (!l)
Robert Olsson19baf832005-06-21 12:43:18 -07001793 goto out;
1794
1795 fa_head = get_fa_head(l, 0);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001796 if (!fa_head)
Robert Olsson19baf832005-06-21 12:43:18 -07001797 goto out;
1798
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001799 if (list_empty(fa_head))
Robert Olsson19baf832005-06-21 12:43:18 -07001800 goto out;
1801
1802 list_for_each_entry(fa, fa_head, fa_list) {
1803 struct fib_info *next_fi = fa->fa_info;
Olof Johansson91b9a272005-08-09 20:24:39 -07001804
Robert Olsson19baf832005-06-21 12:43:18 -07001805 if (fa->fa_scope != res->scope ||
1806 fa->fa_type != RTN_UNICAST)
1807 continue;
Olof Johansson91b9a272005-08-09 20:24:39 -07001808
Robert Olsson19baf832005-06-21 12:43:18 -07001809 if (next_fi->fib_priority > res->fi->fib_priority)
1810 break;
1811 if (!next_fi->fib_nh[0].nh_gw ||
1812 next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
1813 continue;
1814 fa->fa_state |= FA_S_ACCESSED;
Olof Johansson91b9a272005-08-09 20:24:39 -07001815
Robert Olsson19baf832005-06-21 12:43:18 -07001816 if (fi == NULL) {
1817 if (next_fi != res->fi)
1818 break;
1819 } else if (!fib_detect_death(fi, order, &last_resort,
1820 &last_idx, &trie_last_dflt)) {
1821 if (res->fi)
1822 fib_info_put(res->fi);
1823 res->fi = fi;
1824 atomic_inc(&fi->fib_clntref);
1825 trie_last_dflt = order;
1826 goto out;
1827 }
1828 fi = next_fi;
1829 order++;
1830 }
1831 if (order <= 0 || fi == NULL) {
1832 trie_last_dflt = -1;
1833 goto out;
1834 }
1835
1836 if (!fib_detect_death(fi, order, &last_resort, &last_idx, &trie_last_dflt)) {
1837 if (res->fi)
1838 fib_info_put(res->fi);
1839 res->fi = fi;
1840 atomic_inc(&fi->fib_clntref);
1841 trie_last_dflt = order;
1842 goto out;
1843 }
1844 if (last_idx >= 0) {
1845 if (res->fi)
1846 fib_info_put(res->fi);
1847 res->fi = last_resort;
1848 if (last_resort)
1849 atomic_inc(&last_resort->fib_clntref);
1850 }
1851 trie_last_dflt = last_idx;
1852 out:;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001853 read_unlock(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -07001854}
1855
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001856static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fib_table *tb,
Robert Olsson19baf832005-06-21 12:43:18 -07001857 struct sk_buff *skb, struct netlink_callback *cb)
1858{
1859 int i, s_i;
1860 struct fib_alias *fa;
1861
Olof Johansson91b9a272005-08-09 20:24:39 -07001862 u32 xkey = htonl(key);
Robert Olsson19baf832005-06-21 12:43:18 -07001863
Olof Johansson91b9a272005-08-09 20:24:39 -07001864 s_i = cb->args[3];
Robert Olsson19baf832005-06-21 12:43:18 -07001865 i = 0;
1866
1867 list_for_each_entry(fa, fah, fa_list) {
1868 if (i < s_i) {
1869 i++;
1870 continue;
1871 }
1872 if (fa->fa_info->fib_nh == NULL) {
1873 printk("Trie error _fib_nh=NULL in fa[%d] k=%08x plen=%d\n", i, key, plen);
1874 i++;
1875 continue;
1876 }
1877 if (fa->fa_info == NULL) {
1878 printk("Trie error fa_info=NULL in fa[%d] k=%08x plen=%d\n", i, key, plen);
1879 i++;
1880 continue;
1881 }
1882
1883 if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
1884 cb->nlh->nlmsg_seq,
1885 RTM_NEWROUTE,
1886 tb->tb_id,
1887 fa->fa_type,
1888 fa->fa_scope,
1889 &xkey,
1890 plen,
1891 fa->fa_tos,
David S. Miller90f66912005-06-21 14:43:28 -07001892 fa->fa_info, 0) < 0) {
Robert Olsson19baf832005-06-21 12:43:18 -07001893 cb->args[3] = i;
1894 return -1;
Olof Johansson91b9a272005-08-09 20:24:39 -07001895 }
Robert Olsson19baf832005-06-21 12:43:18 -07001896 i++;
1897 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001898 cb->args[3] = i;
Robert Olsson19baf832005-06-21 12:43:18 -07001899 return skb->len;
1900}
1901
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001902static int fn_trie_dump_plen(struct trie *t, int plen, struct fib_table *tb, struct sk_buff *skb,
Robert Olsson19baf832005-06-21 12:43:18 -07001903 struct netlink_callback *cb)
1904{
1905 int h, s_h;
1906 struct list_head *fa_head;
1907 struct leaf *l = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001908
Olof Johansson91b9a272005-08-09 20:24:39 -07001909 s_h = cb->args[2];
Robert Olsson19baf832005-06-21 12:43:18 -07001910
Olof Johansson91b9a272005-08-09 20:24:39 -07001911 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001912 if (h < s_h)
1913 continue;
1914 if (h > s_h)
1915 memset(&cb->args[3], 0,
1916 sizeof(cb->args) - 3*sizeof(cb->args[0]));
1917
1918 fa_head = get_fa_head(l, plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001919
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001920 if (!fa_head)
Robert Olsson19baf832005-06-21 12:43:18 -07001921 continue;
1922
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001923 if (list_empty(fa_head))
Robert Olsson19baf832005-06-21 12:43:18 -07001924 continue;
1925
1926 if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
Olof Johansson91b9a272005-08-09 20:24:39 -07001927 cb->args[2] = h;
Robert Olsson19baf832005-06-21 12:43:18 -07001928 return -1;
1929 }
1930 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001931 cb->args[2] = h;
Robert Olsson19baf832005-06-21 12:43:18 -07001932 return skb->len;
1933}
1934
1935static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb)
1936{
1937 int m, s_m;
1938 struct trie *t = (struct trie *) tb->tb_data;
1939
1940 s_m = cb->args[1];
1941
1942 read_lock(&fib_lock);
Olof Johansson91b9a272005-08-09 20:24:39 -07001943 for (m = 0; m <= 32; m++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001944 if (m < s_m)
1945 continue;
1946 if (m > s_m)
1947 memset(&cb->args[2], 0,
Olof Johansson91b9a272005-08-09 20:24:39 -07001948 sizeof(cb->args) - 2*sizeof(cb->args[0]));
Robert Olsson19baf832005-06-21 12:43:18 -07001949
1950 if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
1951 cb->args[1] = m;
1952 goto out;
1953 }
1954 }
1955 read_unlock(&fib_lock);
1956 cb->args[1] = m;
1957 return skb->len;
Olof Johansson91b9a272005-08-09 20:24:39 -07001958out:
Robert Olsson19baf832005-06-21 12:43:18 -07001959 read_unlock(&fib_lock);
1960 return -1;
1961}
1962
1963/* Fix more generic FIB names for init later */
1964
1965#ifdef CONFIG_IP_MULTIPLE_TABLES
1966struct fib_table * fib_hash_init(int id)
1967#else
1968struct fib_table * __init fib_hash_init(int id)
1969#endif
1970{
1971 struct fib_table *tb;
1972 struct trie *t;
1973
1974 if (fn_alias_kmem == NULL)
1975 fn_alias_kmem = kmem_cache_create("ip_fib_alias",
1976 sizeof(struct fib_alias),
1977 0, SLAB_HWCACHE_ALIGN,
1978 NULL, NULL);
1979
1980 tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie),
1981 GFP_KERNEL);
1982 if (tb == NULL)
1983 return NULL;
1984
1985 tb->tb_id = id;
1986 tb->tb_lookup = fn_trie_lookup;
1987 tb->tb_insert = fn_trie_insert;
1988 tb->tb_delete = fn_trie_delete;
1989 tb->tb_flush = fn_trie_flush;
1990 tb->tb_select_default = fn_trie_select_default;
1991 tb->tb_dump = fn_trie_dump;
1992 memset(tb->tb_data, 0, sizeof(struct trie));
1993
1994 t = (struct trie *) tb->tb_data;
1995
1996 trie_init(t);
1997
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001998 if (id == RT_TABLE_LOCAL)
Olof Johansson91b9a272005-08-09 20:24:39 -07001999 trie_local = t;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002000 else if (id == RT_TABLE_MAIN)
Olof Johansson91b9a272005-08-09 20:24:39 -07002001 trie_main = t;
Robert Olsson19baf832005-06-21 12:43:18 -07002002
2003 if (id == RT_TABLE_LOCAL)
2004 printk("IPv4 FIB: Using LC-trie version %s\n", VERSION);
2005
2006 return tb;
2007}
2008
2009/* Trie dump functions */
2010
2011static void putspace_seq(struct seq_file *seq, int n)
2012{
Olof Johansson91b9a272005-08-09 20:24:39 -07002013 while (n--)
2014 seq_printf(seq, " ");
Robert Olsson19baf832005-06-21 12:43:18 -07002015}
2016
2017static void printbin_seq(struct seq_file *seq, unsigned int v, int bits)
2018{
2019 while (bits--)
2020 seq_printf(seq, "%s", (v & (1<<bits))?"1":"0");
2021}
2022
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002023static void printnode_seq(struct seq_file *seq, int indent, struct node *n,
Robert Olsson19baf832005-06-21 12:43:18 -07002024 int pend, int cindex, int bits)
2025{
2026 putspace_seq(seq, indent);
2027 if (IS_LEAF(n))
2028 seq_printf(seq, "|");
2029 else
2030 seq_printf(seq, "+");
2031 if (bits) {
2032 seq_printf(seq, "%d/", cindex);
2033 printbin_seq(seq, cindex, bits);
2034 seq_printf(seq, ": ");
Olof Johansson91b9a272005-08-09 20:24:39 -07002035 } else
Robert Olsson19baf832005-06-21 12:43:18 -07002036 seq_printf(seq, "<root>: ");
2037 seq_printf(seq, "%s:%p ", IS_LEAF(n)?"Leaf":"Internal node", n);
2038
Robert Olsson19baf832005-06-21 12:43:18 -07002039 if (IS_LEAF(n)) {
Olof Johansson91b9a272005-08-09 20:24:39 -07002040 struct leaf *l = (struct leaf *)n;
Robert Olsson19baf832005-06-21 12:43:18 -07002041 struct fib_alias *fa;
2042 int i;
Olof Johansson91b9a272005-08-09 20:24:39 -07002043
2044 seq_printf(seq, "key=%d.%d.%d.%d\n",
2045 n->key >> 24, (n->key >> 16) % 256, (n->key >> 8) % 256, n->key % 256);
2046
2047 for (i = 32; i >= 0; i--)
2048 if (find_leaf_info(&l->list, i)) {
Robert Olsson19baf832005-06-21 12:43:18 -07002049 struct list_head *fa_head = get_fa_head(l, i);
Olof Johansson91b9a272005-08-09 20:24:39 -07002050
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002051 if (!fa_head)
Robert Olsson19baf832005-06-21 12:43:18 -07002052 continue;
2053
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002054 if (list_empty(fa_head))
Robert Olsson19baf832005-06-21 12:43:18 -07002055 continue;
2056
2057 putspace_seq(seq, indent+2);
2058 seq_printf(seq, "{/%d...dumping}\n", i);
2059
Robert Olsson19baf832005-06-21 12:43:18 -07002060 list_for_each_entry(fa, fa_head, fa_list) {
2061 putspace_seq(seq, indent+2);
Robert Olsson19baf832005-06-21 12:43:18 -07002062 if (fa->fa_info == NULL) {
2063 seq_printf(seq, "Error fa_info=NULL\n");
2064 continue;
2065 }
Olof Johansson91b9a272005-08-09 20:24:39 -07002066 if (fa->fa_info->fib_nh == NULL) {
2067 seq_printf(seq, "Error _fib_nh=NULL\n");
2068 continue;
2069 }
Robert Olsson19baf832005-06-21 12:43:18 -07002070
2071 seq_printf(seq, "{type=%d scope=%d TOS=%d}\n",
2072 fa->fa_type,
2073 fa->fa_scope,
2074 fa->fa_tos);
2075 }
2076 }
Olof Johansson91b9a272005-08-09 20:24:39 -07002077 } else {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002078 struct tnode *tn = (struct tnode *)n;
Olof Johansson91b9a272005-08-09 20:24:39 -07002079 int plen = ((struct tnode *)n)->pos;
2080 t_key prf = MASK_PFX(n->key, plen);
2081
2082 seq_printf(seq, "key=%d.%d.%d.%d/%d\n",
2083 prf >> 24, (prf >> 16) % 256, (prf >> 8) % 256, prf % 256, plen);
2084
Robert Olsson19baf832005-06-21 12:43:18 -07002085 putspace_seq(seq, indent); seq_printf(seq, "| ");
Olof Johansson91b9a272005-08-09 20:24:39 -07002086 seq_printf(seq, "{key prefix=%08x/", tn->key & TKEY_GET_MASK(0, tn->pos));
Robert Olsson19baf832005-06-21 12:43:18 -07002087 printbin_seq(seq, tkey_extract_bits(tn->key, 0, tn->pos), tn->pos);
2088 seq_printf(seq, "}\n");
2089 putspace_seq(seq, indent); seq_printf(seq, "| ");
2090 seq_printf(seq, "{pos=%d", tn->pos);
2091 seq_printf(seq, " (skip=%d bits)", tn->pos - pend);
2092 seq_printf(seq, " bits=%d (%u children)}\n", tn->bits, (1 << tn->bits));
2093 putspace_seq(seq, indent); seq_printf(seq, "| ");
2094 seq_printf(seq, "{empty=%d full=%d}\n", tn->empty_children, tn->full_children);
2095 }
2096}
2097
2098static void trie_dump_seq(struct seq_file *seq, struct trie *t)
2099{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002100 struct node *n = t->trie;
Olof Johansson91b9a272005-08-09 20:24:39 -07002101 int cindex = 0;
2102 int indent = 1;
2103 int pend = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07002104 int depth = 0;
Olof Johansson91b9a272005-08-09 20:24:39 -07002105 struct tnode *tn;
Robert Olsson19baf832005-06-21 12:43:18 -07002106
2107 read_lock(&fib_lock);
2108
2109 seq_printf(seq, "------ trie_dump of t=%p ------\n", t);
Robert Olsson19baf832005-06-21 12:43:18 -07002110
Olof Johansson91b9a272005-08-09 20:24:39 -07002111 if (!n) {
2112 seq_printf(seq, "------ trie is empty\n");
Robert Olsson19baf832005-06-21 12:43:18 -07002113
Olof Johansson91b9a272005-08-09 20:24:39 -07002114 read_unlock(&fib_lock);
2115 return;
Robert Olsson19baf832005-06-21 12:43:18 -07002116 }
Olof Johansson91b9a272005-08-09 20:24:39 -07002117
2118 printnode_seq(seq, indent, n, pend, cindex, 0);
2119
2120 if (!IS_TNODE(n)) {
2121 read_unlock(&fib_lock);
2122 return;
2123 }
2124
2125 tn = (struct tnode *)n;
2126 pend = tn->pos+tn->bits;
2127 putspace_seq(seq, indent); seq_printf(seq, "\\--\n");
2128 indent += 3;
2129 depth++;
2130
2131 while (tn && cindex < (1 << tn->bits)) {
2132 if (tn->child[cindex]) {
2133 /* Got a child */
2134
2135 printnode_seq(seq, indent, tn->child[cindex], pend, cindex, tn->bits);
2136 if (IS_LEAF(tn->child[cindex])) {
2137 cindex++;
2138 } else {
2139 /*
2140 * New tnode. Decend one level
2141 */
2142
2143 depth++;
2144 tn = (struct tnode *)tn->child[cindex];
2145 pend = tn->pos + tn->bits;
2146 putspace_seq(seq, indent); seq_printf(seq, "\\--\n");
2147 indent += 3;
2148 cindex = 0;
2149 }
2150 } else
2151 cindex++;
2152
2153 /*
2154 * Test if we are done
2155 */
2156
2157 while (cindex >= (1 << tn->bits)) {
2158 /*
2159 * Move upwards and test for root
2160 * pop off all traversed nodes
2161 */
2162
2163 if (NODE_PARENT(tn) == NULL) {
2164 tn = NULL;
2165 break;
2166 }
2167
2168 cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits);
2169 cindex++;
2170 tn = NODE_PARENT(tn);
2171 pend = tn->pos + tn->bits;
2172 indent -= 3;
2173 depth--;
2174 }
2175 }
Robert Olsson19baf832005-06-21 12:43:18 -07002176
2177 read_unlock(&fib_lock);
2178}
2179
2180static struct trie_stat *trie_stat_new(void)
2181{
Olof Johansson91b9a272005-08-09 20:24:39 -07002182 struct trie_stat *s;
Robert Olsson19baf832005-06-21 12:43:18 -07002183 int i;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002184
Olof Johansson91b9a272005-08-09 20:24:39 -07002185 s = kmalloc(sizeof(struct trie_stat), GFP_KERNEL);
2186 if (!s)
2187 return NULL;
2188
2189 s->totdepth = 0;
2190 s->maxdepth = 0;
2191 s->tnodes = 0;
2192 s->leaves = 0;
2193 s->nullpointers = 0;
2194
2195 for (i = 0; i < MAX_CHILDS; i++)
2196 s->nodesizes[i] = 0;
2197
Robert Olsson19baf832005-06-21 12:43:18 -07002198 return s;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002199}
Robert Olsson19baf832005-06-21 12:43:18 -07002200
2201static struct trie_stat *trie_collect_stats(struct trie *t)
2202{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002203 struct node *n = t->trie;
Robert Olsson19baf832005-06-21 12:43:18 -07002204 struct trie_stat *s = trie_stat_new();
2205 int cindex = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07002206 int pend = 0;
2207 int depth = 0;
2208
Olof Johansson91b9a272005-08-09 20:24:39 -07002209 if (!s)
2210 return NULL;
2211 if (!n)
2212 return s;
Robert Olsson19baf832005-06-21 12:43:18 -07002213
Olof Johansson91b9a272005-08-09 20:24:39 -07002214 read_lock(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -07002215
Olof Johansson91b9a272005-08-09 20:24:39 -07002216 if (IS_TNODE(n)) {
2217 struct tnode *tn = (struct tnode *)n;
2218 pend = tn->pos+tn->bits;
2219 s->nodesizes[tn->bits]++;
2220 depth++;
Robert Olsson19baf832005-06-21 12:43:18 -07002221
Olof Johansson91b9a272005-08-09 20:24:39 -07002222 while (tn && cindex < (1 << tn->bits)) {
2223 if (tn->child[cindex]) {
2224 /* Got a child */
Robert Olsson19baf832005-06-21 12:43:18 -07002225
Olof Johansson91b9a272005-08-09 20:24:39 -07002226 if (IS_LEAF(tn->child[cindex])) {
2227 cindex++;
2228
2229 /* stats */
2230 if (depth > s->maxdepth)
2231 s->maxdepth = depth;
2232 s->totdepth += depth;
2233 s->leaves++;
2234 } else {
Robert Olsson19baf832005-06-21 12:43:18 -07002235 /*
Olof Johansson91b9a272005-08-09 20:24:39 -07002236 * New tnode. Decend one level
Robert Olsson19baf832005-06-21 12:43:18 -07002237 */
Robert Olsson19baf832005-06-21 12:43:18 -07002238
Olof Johansson91b9a272005-08-09 20:24:39 -07002239 s->tnodes++;
2240 s->nodesizes[tn->bits]++;
2241 depth++;
Robert Olsson19baf832005-06-21 12:43:18 -07002242
Olof Johansson91b9a272005-08-09 20:24:39 -07002243 n = tn->child[cindex];
2244 tn = (struct tnode *)n;
2245 pend = tn->pos+tn->bits;
2246
2247 cindex = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07002248 }
Olof Johansson91b9a272005-08-09 20:24:39 -07002249 } else {
2250 cindex++;
2251 s->nullpointers++;
Robert Olsson19baf832005-06-21 12:43:18 -07002252 }
Olof Johansson91b9a272005-08-09 20:24:39 -07002253
2254 /*
2255 * Test if we are done
2256 */
2257
2258 while (cindex >= (1 << tn->bits)) {
2259 /*
2260 * Move upwards and test for root
2261 * pop off all traversed nodes
2262 */
2263
2264 if (NODE_PARENT(tn) == NULL) {
2265 tn = NULL;
2266 n = NULL;
2267 break;
2268 }
2269
2270 cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits);
2271 tn = NODE_PARENT(tn);
2272 cindex++;
2273 n = (struct node *)tn;
2274 pend = tn->pos+tn->bits;
2275 depth--;
2276 }
Robert Olsson19baf832005-06-21 12:43:18 -07002277 }
2278 }
2279
Olof Johansson91b9a272005-08-09 20:24:39 -07002280 read_unlock(&fib_lock);
Robert Olsson19baf832005-06-21 12:43:18 -07002281 return s;
2282}
2283
2284#ifdef CONFIG_PROC_FS
2285
2286static struct fib_alias *fib_triestat_get_first(struct seq_file *seq)
2287{
2288 return NULL;
2289}
2290
2291static struct fib_alias *fib_triestat_get_next(struct seq_file *seq)
2292{
2293 return NULL;
2294}
2295
2296static void *fib_triestat_seq_start(struct seq_file *seq, loff_t *pos)
2297{
Olof Johansson91b9a272005-08-09 20:24:39 -07002298 if (!ip_fib_main_table)
2299 return NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07002300
Olof Johansson91b9a272005-08-09 20:24:39 -07002301 if (*pos)
2302 return fib_triestat_get_next(seq);
2303 else
2304 return SEQ_START_TOKEN;
Robert Olsson19baf832005-06-21 12:43:18 -07002305}
2306
2307static void *fib_triestat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2308{
2309 ++*pos;
Olof Johansson91b9a272005-08-09 20:24:39 -07002310 if (v == SEQ_START_TOKEN)
2311 return fib_triestat_get_first(seq);
2312 else
2313 return fib_triestat_get_next(seq);
Robert Olsson19baf832005-06-21 12:43:18 -07002314}
2315
2316static void fib_triestat_seq_stop(struct seq_file *seq, void *v)
2317{
2318
2319}
2320
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002321/*
Robert Olsson19baf832005-06-21 12:43:18 -07002322 * This outputs /proc/net/fib_triestats
2323 *
2324 * It always works in backward compatibility mode.
2325 * The format of the file is not supposed to be changed.
2326 */
2327
2328static void collect_and_show(struct trie *t, struct seq_file *seq)
2329{
2330 int bytes = 0; /* How many bytes are used, a ref is 4 bytes */
2331 int i, max, pointers;
Olof Johansson91b9a272005-08-09 20:24:39 -07002332 struct trie_stat *stat;
Robert Olsson19baf832005-06-21 12:43:18 -07002333 int avdepth;
2334
2335 stat = trie_collect_stats(t);
2336
Olof Johansson91b9a272005-08-09 20:24:39 -07002337 bytes = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07002338 seq_printf(seq, "trie=%p\n", t);
2339
2340 if (stat) {
2341 if (stat->leaves)
Olof Johansson91b9a272005-08-09 20:24:39 -07002342 avdepth = stat->totdepth*100 / stat->leaves;
Robert Olsson19baf832005-06-21 12:43:18 -07002343 else
Olof Johansson91b9a272005-08-09 20:24:39 -07002344 avdepth = 0;
2345 seq_printf(seq, "Aver depth: %d.%02d\n", avdepth / 100, avdepth % 100);
Robert Olsson19baf832005-06-21 12:43:18 -07002346 seq_printf(seq, "Max depth: %4d\n", stat->maxdepth);
Olof Johansson91b9a272005-08-09 20:24:39 -07002347
Robert Olsson19baf832005-06-21 12:43:18 -07002348 seq_printf(seq, "Leaves: %d\n", stat->leaves);
2349 bytes += sizeof(struct leaf) * stat->leaves;
2350 seq_printf(seq, "Internal nodes: %d\n", stat->tnodes);
2351 bytes += sizeof(struct tnode) * stat->tnodes;
2352
2353 max = MAX_CHILDS-1;
2354
2355 while (max >= 0 && stat->nodesizes[max] == 0)
2356 max--;
2357 pointers = 0;
2358
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002359 for (i = 1; i <= max; i++)
Robert Olsson19baf832005-06-21 12:43:18 -07002360 if (stat->nodesizes[i] != 0) {
2361 seq_printf(seq, " %d: %d", i, stat->nodesizes[i]);
2362 pointers += (1<<i) * stat->nodesizes[i];
2363 }
2364 seq_printf(seq, "\n");
2365 seq_printf(seq, "Pointers: %d\n", pointers);
2366 bytes += sizeof(struct node *) * pointers;
2367 seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers);
2368 seq_printf(seq, "Total size: %d kB\n", bytes / 1024);
2369
2370 kfree(stat);
2371 }
2372
2373#ifdef CONFIG_IP_FIB_TRIE_STATS
2374 seq_printf(seq, "Counters:\n---------\n");
2375 seq_printf(seq,"gets = %d\n", t->stats.gets);
2376 seq_printf(seq,"backtracks = %d\n", t->stats.backtrack);
2377 seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
2378 seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
2379 seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
Robert Olsson2f368952005-07-05 15:02:40 -07002380 seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);
Robert Olsson19baf832005-06-21 12:43:18 -07002381#ifdef CLEAR_STATS
2382 memset(&(t->stats), 0, sizeof(t->stats));
2383#endif
2384#endif /* CONFIG_IP_FIB_TRIE_STATS */
2385}
2386
2387static int fib_triestat_seq_show(struct seq_file *seq, void *v)
2388{
2389 char bf[128];
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002390
Robert Olsson19baf832005-06-21 12:43:18 -07002391 if (v == SEQ_START_TOKEN) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002392 seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n",
Robert Olsson19baf832005-06-21 12:43:18 -07002393 sizeof(struct leaf), sizeof(struct tnode));
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002394 if (trie_local)
Robert Olsson19baf832005-06-21 12:43:18 -07002395 collect_and_show(trie_local, seq);
2396
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002397 if (trie_main)
Robert Olsson19baf832005-06-21 12:43:18 -07002398 collect_and_show(trie_main, seq);
Olof Johansson91b9a272005-08-09 20:24:39 -07002399 } else {
2400 snprintf(bf, sizeof(bf), "*\t%08X\t%08X", 200, 400);
2401
Robert Olsson19baf832005-06-21 12:43:18 -07002402 seq_printf(seq, "%-127s\n", bf);
2403 }
2404 return 0;
2405}
2406
2407static struct seq_operations fib_triestat_seq_ops = {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002408 .start = fib_triestat_seq_start,
2409 .next = fib_triestat_seq_next,
2410 .stop = fib_triestat_seq_stop,
2411 .show = fib_triestat_seq_show,
Robert Olsson19baf832005-06-21 12:43:18 -07002412};
2413
2414static int fib_triestat_seq_open(struct inode *inode, struct file *file)
2415{
2416 struct seq_file *seq;
2417 int rc = -ENOMEM;
2418
2419 rc = seq_open(file, &fib_triestat_seq_ops);
2420 if (rc)
2421 goto out_kfree;
2422
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002423 seq = file->private_data;
Robert Olsson19baf832005-06-21 12:43:18 -07002424out:
2425 return rc;
2426out_kfree:
2427 goto out;
2428}
2429
2430static struct file_operations fib_triestat_seq_fops = {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002431 .owner = THIS_MODULE,
2432 .open = fib_triestat_seq_open,
2433 .read = seq_read,
2434 .llseek = seq_lseek,
2435 .release = seq_release_private,
Robert Olsson19baf832005-06-21 12:43:18 -07002436};
2437
2438int __init fib_stat_proc_init(void)
2439{
2440 if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_seq_fops))
2441 return -ENOMEM;
2442 return 0;
2443}
2444
2445void __init fib_stat_proc_exit(void)
2446{
2447 proc_net_remove("fib_triestat");
2448}
2449
2450static struct fib_alias *fib_trie_get_first(struct seq_file *seq)
2451{
2452 return NULL;
2453}
2454
2455static struct fib_alias *fib_trie_get_next(struct seq_file *seq)
2456{
2457 return NULL;
2458}
2459
2460static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
2461{
Olof Johansson91b9a272005-08-09 20:24:39 -07002462 if (!ip_fib_main_table)
2463 return NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07002464
Olof Johansson91b9a272005-08-09 20:24:39 -07002465 if (*pos)
2466 return fib_trie_get_next(seq);
2467 else
2468 return SEQ_START_TOKEN;
Robert Olsson19baf832005-06-21 12:43:18 -07002469}
2470
2471static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2472{
2473 ++*pos;
Olof Johansson91b9a272005-08-09 20:24:39 -07002474 if (v == SEQ_START_TOKEN)
2475 return fib_trie_get_first(seq);
2476 else
2477 return fib_trie_get_next(seq);
2478
Robert Olsson19baf832005-06-21 12:43:18 -07002479}
2480
2481static void fib_trie_seq_stop(struct seq_file *seq, void *v)
2482{
Robert Olsson19baf832005-06-21 12:43:18 -07002483}
2484
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002485/*
Robert Olsson19baf832005-06-21 12:43:18 -07002486 * This outputs /proc/net/fib_trie.
2487 *
2488 * It always works in backward compatibility mode.
2489 * The format of the file is not supposed to be changed.
2490 */
2491
2492static int fib_trie_seq_show(struct seq_file *seq, void *v)
2493{
2494 char bf[128];
2495
2496 if (v == SEQ_START_TOKEN) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002497 if (trie_local)
Robert Olsson19baf832005-06-21 12:43:18 -07002498 trie_dump_seq(seq, trie_local);
2499
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002500 if (trie_main)
Robert Olsson19baf832005-06-21 12:43:18 -07002501 trie_dump_seq(seq, trie_main);
Olof Johansson91b9a272005-08-09 20:24:39 -07002502 } else {
Robert Olsson19baf832005-06-21 12:43:18 -07002503 snprintf(bf, sizeof(bf),
2504 "*\t%08X\t%08X", 200, 400);
2505 seq_printf(seq, "%-127s\n", bf);
2506 }
2507
2508 return 0;
2509}
2510
2511static struct seq_operations fib_trie_seq_ops = {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002512 .start = fib_trie_seq_start,
2513 .next = fib_trie_seq_next,
2514 .stop = fib_trie_seq_stop,
2515 .show = fib_trie_seq_show,
Robert Olsson19baf832005-06-21 12:43:18 -07002516};
2517
2518static int fib_trie_seq_open(struct inode *inode, struct file *file)
2519{
2520 struct seq_file *seq;
2521 int rc = -ENOMEM;
2522
2523 rc = seq_open(file, &fib_trie_seq_ops);
2524 if (rc)
2525 goto out_kfree;
2526
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002527 seq = file->private_data;
Robert Olsson19baf832005-06-21 12:43:18 -07002528out:
2529 return rc;
2530out_kfree:
2531 goto out;
2532}
2533
2534static struct file_operations fib_trie_seq_fops = {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002535 .owner = THIS_MODULE,
2536 .open = fib_trie_seq_open,
2537 .read = seq_read,
2538 .llseek = seq_lseek,
2539 .release= seq_release_private,
Robert Olsson19baf832005-06-21 12:43:18 -07002540};
2541
2542int __init fib_proc_init(void)
2543{
2544 if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_seq_fops))
2545 return -ENOMEM;
2546 return 0;
2547}
2548
2549void __init fib_proc_exit(void)
2550{
2551 proc_net_remove("fib_trie");
2552}
2553
2554#endif /* CONFIG_PROC_FS */