blob: f28f9f5f240cb599997d8ee4dc8f763456a92a1d [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 *
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090010 * Jens Laas <jens.laas@data.slu.se> Swedish University of
Robert Olsson19baf832005-06-21 12:43:18 -070011 * Agricultural Sciences.
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090012 *
Robert Olsson19baf832005-06-21 12:43:18 -070013 * Hans Liss <hans.liss@its.uu.se> Uppsala Universitet
14 *
15 * This work is based on the LPC-trie which is originally descibed in:
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +090016 *
Robert Olsson19baf832005-06-21 12:43:18 -070017 * 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.
Robert Olssonfd966252005-12-22 11:25:10 -080044 *
45 * Substantial contributions to this work comes from:
46 *
47 * David S. Miller, <davem@davemloft.net>
48 * Stephen Hemminger <shemminger@osdl.org>
49 * Paul E. McKenney <paulmck@us.ibm.com>
50 * Patrick McHardy <kaber@trash.net>
Robert Olsson19baf832005-06-21 12:43:18 -070051 */
52
Robert Olsson05eee482007-03-19 16:27:37 -070053#define VERSION "0.408"
Robert Olsson19baf832005-06-21 12:43:18 -070054
Robert Olsson19baf832005-06-21 12:43:18 -070055#include <asm/uaccess.h>
56#include <asm/system.h>
57#include <asm/bitops.h>
58#include <linux/types.h>
59#include <linux/kernel.h>
Robert Olsson19baf832005-06-21 12:43:18 -070060#include <linux/mm.h>
61#include <linux/string.h>
62#include <linux/socket.h>
63#include <linux/sockios.h>
64#include <linux/errno.h>
65#include <linux/in.h>
66#include <linux/inet.h>
Stephen Hemmingercd8787a2006-01-03 14:38:34 -080067#include <linux/inetdevice.h>
Robert Olsson19baf832005-06-21 12:43:18 -070068#include <linux/netdevice.h>
69#include <linux/if_arp.h>
70#include <linux/proc_fs.h>
Robert Olsson2373ce12005-08-25 13:01:29 -070071#include <linux/rcupdate.h>
Robert Olsson19baf832005-06-21 12:43:18 -070072#include <linux/skbuff.h>
73#include <linux/netlink.h>
74#include <linux/init.h>
75#include <linux/list.h>
76#include <net/ip.h>
77#include <net/protocol.h>
78#include <net/route.h>
79#include <net/tcp.h>
80#include <net/sock.h>
81#include <net/ip_fib.h>
82#include "fib_lookup.h"
83
84#undef CONFIG_IP_FIB_TRIE_STATS
Robert Olsson06ef9212006-03-20 21:35:01 -080085#define MAX_STAT_DEPTH 32
Robert Olsson19baf832005-06-21 12:43:18 -070086
Robert Olsson19baf832005-06-21 12:43:18 -070087#define KEYLENGTH (8*sizeof(t_key))
88#define MASK_PFX(k, l) (((l)==0)?0:(k >> (KEYLENGTH-l)) << (KEYLENGTH-l))
89#define TKEY_GET_MASK(offset, bits) (((bits)==0)?0:((t_key)(-1) << (KEYLENGTH - bits) >> offset))
90
Robert Olsson19baf832005-06-21 12:43:18 -070091typedef unsigned int t_key;
92
93#define T_TNODE 0
94#define T_LEAF 1
95#define NODE_TYPE_MASK 0x1UL
Robert Olsson2373ce12005-08-25 13:01:29 -070096#define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK)
97
Olof Johansson91b9a272005-08-09 20:24:39 -070098#define IS_TNODE(n) (!(n->parent & T_LEAF))
99#define IS_LEAF(n) (n->parent & T_LEAF)
Robert Olsson19baf832005-06-21 12:43:18 -0700100
101struct node {
Olof Johansson91b9a272005-08-09 20:24:39 -0700102 t_key key;
103 unsigned long parent;
Robert Olsson19baf832005-06-21 12:43:18 -0700104};
105
106struct leaf {
Olof Johansson91b9a272005-08-09 20:24:39 -0700107 t_key key;
108 unsigned long parent;
Robert Olsson19baf832005-06-21 12:43:18 -0700109 struct hlist_head list;
Robert Olsson2373ce12005-08-25 13:01:29 -0700110 struct rcu_head rcu;
Robert Olsson19baf832005-06-21 12:43:18 -0700111};
112
113struct leaf_info {
114 struct hlist_node hlist;
Robert Olsson2373ce12005-08-25 13:01:29 -0700115 struct rcu_head rcu;
Robert Olsson19baf832005-06-21 12:43:18 -0700116 int plen;
117 struct list_head falh;
118};
119
120struct tnode {
Olof Johansson91b9a272005-08-09 20:24:39 -0700121 t_key key;
122 unsigned long parent;
123 unsigned short pos:5; /* 2log(KEYLENGTH) bits needed */
124 unsigned short bits:5; /* 2log(KEYLENGTH) bits needed */
125 unsigned short full_children; /* KEYLENGTH bits needed */
126 unsigned short empty_children; /* KEYLENGTH bits needed */
Robert Olsson2373ce12005-08-25 13:01:29 -0700127 struct rcu_head rcu;
Olof Johansson91b9a272005-08-09 20:24:39 -0700128 struct node *child[0];
Robert Olsson19baf832005-06-21 12:43:18 -0700129};
130
131#ifdef CONFIG_IP_FIB_TRIE_STATS
132struct trie_use_stats {
133 unsigned int gets;
134 unsigned int backtrack;
135 unsigned int semantic_match_passed;
136 unsigned int semantic_match_miss;
137 unsigned int null_node_hit;
Robert Olsson2f368952005-07-05 15:02:40 -0700138 unsigned int resize_node_skipped;
Robert Olsson19baf832005-06-21 12:43:18 -0700139};
140#endif
141
142struct trie_stat {
143 unsigned int totdepth;
144 unsigned int maxdepth;
145 unsigned int tnodes;
146 unsigned int leaves;
147 unsigned int nullpointers;
Robert Olsson06ef9212006-03-20 21:35:01 -0800148 unsigned int nodesizes[MAX_STAT_DEPTH];
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700149};
Robert Olsson19baf832005-06-21 12:43:18 -0700150
151struct trie {
Olof Johansson91b9a272005-08-09 20:24:39 -0700152 struct node *trie;
Robert Olsson19baf832005-06-21 12:43:18 -0700153#ifdef CONFIG_IP_FIB_TRIE_STATS
154 struct trie_use_stats stats;
155#endif
Olof Johansson91b9a272005-08-09 20:24:39 -0700156 int size;
Robert Olsson19baf832005-06-21 12:43:18 -0700157 unsigned int revision;
158};
159
Robert Olsson19baf832005-06-21 12:43:18 -0700160static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
161static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull);
Robert Olsson19baf832005-06-21 12:43:18 -0700162static struct node *resize(struct trie *t, struct tnode *tn);
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700163static struct tnode *inflate(struct trie *t, struct tnode *tn);
164static struct tnode *halve(struct trie *t, struct tnode *tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700165static void tnode_free(struct tnode *tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700166
Christoph Lametere18b8902006-12-06 20:33:20 -0800167static struct kmem_cache *fn_alias_kmem __read_mostly;
Robert Olsson19baf832005-06-21 12:43:18 -0700168static struct trie *trie_local = NULL, *trie_main = NULL;
169
Stephen Hemminger06801912007-08-10 15:22:13 -0700170static inline struct tnode *node_parent(struct node *node)
171{
172 struct tnode *ret;
173
174 ret = (struct tnode *)(node->parent & ~NODE_TYPE_MASK);
175 return rcu_dereference(ret);
176}
177
178static inline void node_set_parent(struct node *node, struct tnode *ptr)
179{
180 rcu_assign_pointer(node->parent,
181 (unsigned long)ptr | NODE_TYPE(node));
182}
Robert Olsson2373ce12005-08-25 13:01:29 -0700183
184/* rcu_read_lock needs to be hold by caller from readside */
185
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700186static inline struct node *tnode_get_child(struct tnode *tn, int i)
Robert Olsson19baf832005-06-21 12:43:18 -0700187{
Olof Johansson91b9a272005-08-09 20:24:39 -0700188 BUG_ON(i >= 1 << tn->bits);
Robert Olsson19baf832005-06-21 12:43:18 -0700189
Robert Olsson2373ce12005-08-25 13:01:29 -0700190 return rcu_dereference(tn->child[i]);
Robert Olsson19baf832005-06-21 12:43:18 -0700191}
192
Stephen Hemmignerbb435b82005-08-09 20:25:39 -0700193static inline int tnode_child_length(const struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700194{
Olof Johansson91b9a272005-08-09 20:24:39 -0700195 return 1 << tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -0700196}
197
Robert Olsson19baf832005-06-21 12:43:18 -0700198static inline t_key tkey_extract_bits(t_key a, int offset, int bits)
199{
Olof Johansson91b9a272005-08-09 20:24:39 -0700200 if (offset < KEYLENGTH)
Robert Olsson19baf832005-06-21 12:43:18 -0700201 return ((t_key)(a << offset)) >> (KEYLENGTH - bits);
Olof Johansson91b9a272005-08-09 20:24:39 -0700202 else
Robert Olsson19baf832005-06-21 12:43:18 -0700203 return 0;
204}
205
206static inline int tkey_equals(t_key a, t_key b)
207{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700208 return a == b;
Robert Olsson19baf832005-06-21 12:43:18 -0700209}
210
211static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
212{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700213 if (bits == 0 || offset >= KEYLENGTH)
214 return 1;
Olof Johansson91b9a272005-08-09 20:24:39 -0700215 bits = bits > KEYLENGTH ? KEYLENGTH : bits;
216 return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700217}
Robert Olsson19baf832005-06-21 12:43:18 -0700218
219static inline int tkey_mismatch(t_key a, int offset, t_key b)
220{
221 t_key diff = a ^ b;
222 int i = offset;
223
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700224 if (!diff)
225 return 0;
226 while ((diff << i) >> (KEYLENGTH-1) == 0)
Robert Olsson19baf832005-06-21 12:43:18 -0700227 i++;
228 return i;
229}
230
Robert Olsson19baf832005-06-21 12:43:18 -0700231/*
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900232 To understand this stuff, an understanding of keys and all their bits is
233 necessary. Every node in the trie has a key associated with it, but not
Robert Olsson19baf832005-06-21 12:43:18 -0700234 all of the bits in that key are significant.
235
236 Consider a node 'n' and its parent 'tp'.
237
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900238 If n is a leaf, every bit in its key is significant. Its presence is
239 necessitated by path compression, since during a tree traversal (when
240 searching for a leaf - unless we are doing an insertion) we will completely
241 ignore all skipped bits we encounter. Thus we need to verify, at the end of
242 a potentially successful search, that we have indeed been walking the
Robert Olsson19baf832005-06-21 12:43:18 -0700243 correct key path.
244
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900245 Note that we can never "miss" the correct key in the tree if present by
246 following the wrong path. Path compression ensures that segments of the key
247 that are the same for all keys with a given prefix are skipped, but the
248 skipped part *is* identical for each node in the subtrie below the skipped
249 bit! trie_insert() in this implementation takes care of that - note the
Robert Olsson19baf832005-06-21 12:43:18 -0700250 call to tkey_sub_equals() in trie_insert().
251
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900252 if n is an internal node - a 'tnode' here, the various parts of its key
Robert Olsson19baf832005-06-21 12:43:18 -0700253 have many different meanings.
254
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900255 Example:
Robert Olsson19baf832005-06-21 12:43:18 -0700256 _________________________________________________________________
257 | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
258 -----------------------------------------------------------------
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900259 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Robert Olsson19baf832005-06-21 12:43:18 -0700260
261 _________________________________________________________________
262 | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
263 -----------------------------------------------------------------
264 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
265
266 tp->pos = 7
267 tp->bits = 3
268 n->pos = 15
Olof Johansson91b9a272005-08-09 20:24:39 -0700269 n->bits = 4
Robert Olsson19baf832005-06-21 12:43:18 -0700270
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900271 First, let's just ignore the bits that come before the parent tp, that is
272 the bits from 0 to (tp->pos-1). They are *known* but at this point we do
Robert Olsson19baf832005-06-21 12:43:18 -0700273 not use them for anything.
274
275 The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900276 index into the parent's child array. That is, they will be used to find
Robert Olsson19baf832005-06-21 12:43:18 -0700277 'n' among tp's children.
278
279 The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits
280 for the node n.
281
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900282 All the bits we have seen so far are significant to the node n. The rest
Robert Olsson19baf832005-06-21 12:43:18 -0700283 of the bits are really not needed or indeed known in n->key.
284
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900285 The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into
Robert Olsson19baf832005-06-21 12:43:18 -0700286 n's child array, and will of course be different for each child.
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900287
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700288
Robert Olsson19baf832005-06-21 12:43:18 -0700289 The rest of the bits, from (n->pos + n->bits) onward, are completely unknown
290 at this point.
291
292*/
293
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700294static inline void check_tnode(const struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700295{
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700296 WARN_ON(tn && tn->pos+tn->bits > 32);
Robert Olsson19baf832005-06-21 12:43:18 -0700297}
298
299static int halve_threshold = 25;
300static int inflate_threshold = 50;
Robert Olsson965ffea2007-03-19 16:29:58 -0700301static int halve_threshold_root = 8;
302static int inflate_threshold_root = 15;
Robert Olsson19baf832005-06-21 12:43:18 -0700303
Robert Olsson2373ce12005-08-25 13:01:29 -0700304
305static void __alias_free_mem(struct rcu_head *head)
306{
307 struct fib_alias *fa = container_of(head, struct fib_alias, rcu);
308 kmem_cache_free(fn_alias_kmem, fa);
309}
310
311static inline void alias_free_mem_rcu(struct fib_alias *fa)
312{
313 call_rcu(&fa->rcu, __alias_free_mem);
314}
315
316static void __leaf_free_rcu(struct rcu_head *head)
317{
318 kfree(container_of(head, struct leaf, rcu));
319}
320
Robert Olsson2373ce12005-08-25 13:01:29 -0700321static void __leaf_info_free_rcu(struct rcu_head *head)
322{
323 kfree(container_of(head, struct leaf_info, rcu));
324}
325
326static inline void free_leaf_info(struct leaf_info *leaf)
327{
328 call_rcu(&leaf->rcu, __leaf_info_free_rcu);
329}
330
331static struct tnode *tnode_alloc(unsigned int size)
332{
333 struct page *pages;
334
335 if (size <= PAGE_SIZE)
336 return kcalloc(size, 1, GFP_KERNEL);
337
338 pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size));
339 if (!pages)
340 return NULL;
341
342 return page_address(pages);
343}
344
345static void __tnode_free_rcu(struct rcu_head *head)
346{
347 struct tnode *tn = container_of(head, struct tnode, rcu);
348 unsigned int size = sizeof(struct tnode) +
349 (1 << tn->bits) * sizeof(struct node *);
350
351 if (size <= PAGE_SIZE)
352 kfree(tn);
353 else
354 free_pages((unsigned long)tn, get_order(size));
355}
356
357static inline void tnode_free(struct tnode *tn)
358{
Stephen Hemminger132adf52007-03-08 20:44:43 -0800359 if (IS_LEAF(tn)) {
Robert Olsson550e29b2006-04-04 12:53:35 -0700360 struct leaf *l = (struct leaf *) tn;
361 call_rcu_bh(&l->rcu, __leaf_free_rcu);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800362 } else
Robert Olsson550e29b2006-04-04 12:53:35 -0700363 call_rcu(&tn->rcu, __tnode_free_rcu);
Robert Olsson2373ce12005-08-25 13:01:29 -0700364}
365
Robert Olsson19baf832005-06-21 12:43:18 -0700366static struct leaf *leaf_new(void)
367{
368 struct leaf *l = kmalloc(sizeof(struct leaf), GFP_KERNEL);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700369 if (l) {
Robert Olsson2373ce12005-08-25 13:01:29 -0700370 l->parent = T_LEAF;
Robert Olsson19baf832005-06-21 12:43:18 -0700371 INIT_HLIST_HEAD(&l->list);
372 }
373 return l;
374}
375
376static struct leaf_info *leaf_info_new(int plen)
377{
378 struct leaf_info *li = kmalloc(sizeof(struct leaf_info), GFP_KERNEL);
Robert Olsson2373ce12005-08-25 13:01:29 -0700379 if (li) {
380 li->plen = plen;
381 INIT_LIST_HEAD(&li->falh);
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700382 }
Robert Olsson2373ce12005-08-25 13:01:29 -0700383 return li;
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700384}
385
Robert Olsson19baf832005-06-21 12:43:18 -0700386static struct tnode* tnode_new(t_key key, int pos, int bits)
387{
388 int nchildren = 1<<bits;
389 int sz = sizeof(struct tnode) + nchildren * sizeof(struct node *);
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700390 struct tnode *tn = tnode_alloc(sz);
Robert Olsson19baf832005-06-21 12:43:18 -0700391
Olof Johansson91b9a272005-08-09 20:24:39 -0700392 if (tn) {
Robert Olsson19baf832005-06-21 12:43:18 -0700393 memset(tn, 0, sz);
Robert Olsson2373ce12005-08-25 13:01:29 -0700394 tn->parent = T_TNODE;
Robert Olsson19baf832005-06-21 12:43:18 -0700395 tn->pos = pos;
396 tn->bits = bits;
397 tn->key = key;
398 tn->full_children = 0;
399 tn->empty_children = 1<<bits;
400 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700401
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700402 pr_debug("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode),
403 (unsigned int) (sizeof(struct node) * 1<<bits));
Robert Olsson19baf832005-06-21 12:43:18 -0700404 return tn;
405}
406
Robert Olsson19baf832005-06-21 12:43:18 -0700407/*
408 * Check whether a tnode 'n' is "full", i.e. it is an internal node
409 * and no bits are skipped. See discussion in dyntree paper p. 6
410 */
411
Stephen Hemmignerbb435b82005-08-09 20:25:39 -0700412static inline int tnode_full(const struct tnode *tn, const struct node *n)
Robert Olsson19baf832005-06-21 12:43:18 -0700413{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700414 if (n == NULL || IS_LEAF(n))
Robert Olsson19baf832005-06-21 12:43:18 -0700415 return 0;
416
417 return ((struct tnode *) n)->pos == tn->pos + tn->bits;
418}
419
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700420static inline void put_child(struct trie *t, struct tnode *tn, int i, struct node *n)
Robert Olsson19baf832005-06-21 12:43:18 -0700421{
422 tnode_put_child_reorg(tn, i, n, -1);
423}
424
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700425 /*
Robert Olsson19baf832005-06-21 12:43:18 -0700426 * Add a child at position i overwriting the old value.
427 * Update the value of full_children and empty_children.
428 */
429
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700430static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700431{
Robert Olsson2373ce12005-08-25 13:01:29 -0700432 struct node *chi = tn->child[i];
Robert Olsson19baf832005-06-21 12:43:18 -0700433 int isfull;
434
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700435 BUG_ON(i >= 1<<tn->bits);
436
Robert Olsson19baf832005-06-21 12:43:18 -0700437
438 /* update emptyChildren */
439 if (n == NULL && chi != NULL)
440 tn->empty_children++;
441 else if (n != NULL && chi == NULL)
442 tn->empty_children--;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700443
Robert Olsson19baf832005-06-21 12:43:18 -0700444 /* update fullChildren */
Olof Johansson91b9a272005-08-09 20:24:39 -0700445 if (wasfull == -1)
Robert Olsson19baf832005-06-21 12:43:18 -0700446 wasfull = tnode_full(tn, chi);
447
448 isfull = tnode_full(tn, n);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700449 if (wasfull && !isfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700450 tn->full_children--;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700451 else if (!wasfull && isfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700452 tn->full_children++;
Olof Johansson91b9a272005-08-09 20:24:39 -0700453
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700454 if (n)
Stephen Hemminger06801912007-08-10 15:22:13 -0700455 node_set_parent(n, tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700456
Robert Olsson2373ce12005-08-25 13:01:29 -0700457 rcu_assign_pointer(tn->child[i], n);
Robert Olsson19baf832005-06-21 12:43:18 -0700458}
459
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700460static struct node *resize(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700461{
462 int i;
Robert Olsson2f368952005-07-05 15:02:40 -0700463 int err = 0;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700464 struct tnode *old_tn;
Robert Olssone6308be2005-10-04 13:01:58 -0700465 int inflate_threshold_use;
466 int halve_threshold_use;
Robert Olsson05eee482007-03-19 16:27:37 -0700467 int max_resize;
Robert Olsson19baf832005-06-21 12:43:18 -0700468
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900469 if (!tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700470 return NULL;
471
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700472 pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
473 tn, inflate_threshold, halve_threshold);
Robert Olsson19baf832005-06-21 12:43:18 -0700474
475 /* No children */
476 if (tn->empty_children == tnode_child_length(tn)) {
477 tnode_free(tn);
478 return NULL;
479 }
480 /* One child */
481 if (tn->empty_children == tnode_child_length(tn) - 1)
482 for (i = 0; i < tnode_child_length(tn); i++) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700483 struct node *n;
Robert Olsson19baf832005-06-21 12:43:18 -0700484
Olof Johansson91b9a272005-08-09 20:24:39 -0700485 n = tn->child[i];
Robert Olsson2373ce12005-08-25 13:01:29 -0700486 if (!n)
Olof Johansson91b9a272005-08-09 20:24:39 -0700487 continue;
Olof Johansson91b9a272005-08-09 20:24:39 -0700488
489 /* compress one level */
Stephen Hemminger06801912007-08-10 15:22:13 -0700490 node_set_parent(n, NULL);
Olof Johansson91b9a272005-08-09 20:24:39 -0700491 tnode_free(tn);
492 return n;
Robert Olsson19baf832005-06-21 12:43:18 -0700493 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700494 /*
Robert Olsson19baf832005-06-21 12:43:18 -0700495 * Double as long as the resulting node has a number of
496 * nonempty nodes that are above the threshold.
497 */
498
499 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700500 * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
501 * the Helsinki University of Technology and Matti Tikkanen of Nokia
Robert Olsson19baf832005-06-21 12:43:18 -0700502 * Telecommunications, page 6:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700503 * "A node is doubled if the ratio of non-empty children to all
Robert Olsson19baf832005-06-21 12:43:18 -0700504 * children in the *doubled* node is at least 'high'."
505 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700506 * 'high' in this instance is the variable 'inflate_threshold'. It
507 * is expressed as a percentage, so we multiply it with
508 * tnode_child_length() and instead of multiplying by 2 (since the
509 * child array will be doubled by inflate()) and multiplying
510 * the left-hand side by 100 (to handle the percentage thing) we
Robert Olsson19baf832005-06-21 12:43:18 -0700511 * multiply the left-hand side by 50.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700512 *
513 * The left-hand side may look a bit weird: tnode_child_length(tn)
514 * - tn->empty_children is of course the number of non-null children
515 * in the current node. tn->full_children is the number of "full"
Robert Olsson19baf832005-06-21 12:43:18 -0700516 * children, that is non-null tnodes with a skip value of 0.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700517 * All of those will be doubled in the resulting inflated tnode, so
Robert Olsson19baf832005-06-21 12:43:18 -0700518 * we just count them one extra time here.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700519 *
Robert Olsson19baf832005-06-21 12:43:18 -0700520 * A clearer way to write this would be:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700521 *
Robert Olsson19baf832005-06-21 12:43:18 -0700522 * to_be_doubled = tn->full_children;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700523 * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
Robert Olsson19baf832005-06-21 12:43:18 -0700524 * tn->full_children;
525 *
526 * new_child_length = tnode_child_length(tn) * 2;
527 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700528 * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
Robert Olsson19baf832005-06-21 12:43:18 -0700529 * new_child_length;
530 * if (new_fill_factor >= inflate_threshold)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700531 *
532 * ...and so on, tho it would mess up the while () loop.
533 *
Robert Olsson19baf832005-06-21 12:43:18 -0700534 * anyway,
535 * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
536 * inflate_threshold
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700537 *
Robert Olsson19baf832005-06-21 12:43:18 -0700538 * avoid a division:
539 * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
540 * inflate_threshold * new_child_length
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700541 *
Robert Olsson19baf832005-06-21 12:43:18 -0700542 * expand not_to_be_doubled and to_be_doubled, and shorten:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700543 * 100 * (tnode_child_length(tn) - tn->empty_children +
Olof Johansson91b9a272005-08-09 20:24:39 -0700544 * tn->full_children) >= inflate_threshold * new_child_length
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700545 *
Robert Olsson19baf832005-06-21 12:43:18 -0700546 * expand new_child_length:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700547 * 100 * (tnode_child_length(tn) - tn->empty_children +
Olof Johansson91b9a272005-08-09 20:24:39 -0700548 * tn->full_children) >=
Robert Olsson19baf832005-06-21 12:43:18 -0700549 * inflate_threshold * tnode_child_length(tn) * 2
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700550 *
Robert Olsson19baf832005-06-21 12:43:18 -0700551 * shorten again:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700552 * 50 * (tn->full_children + tnode_child_length(tn) -
Olof Johansson91b9a272005-08-09 20:24:39 -0700553 * tn->empty_children) >= inflate_threshold *
Robert Olsson19baf832005-06-21 12:43:18 -0700554 * tnode_child_length(tn)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700555 *
Robert Olsson19baf832005-06-21 12:43:18 -0700556 */
557
558 check_tnode(tn);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700559
Robert Olssone6308be2005-10-04 13:01:58 -0700560 /* Keep root node larger */
561
Stephen Hemminger132adf52007-03-08 20:44:43 -0800562 if (!tn->parent)
Robert Olssone6308be2005-10-04 13:01:58 -0700563 inflate_threshold_use = inflate_threshold_root;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900564 else
Robert Olssone6308be2005-10-04 13:01:58 -0700565 inflate_threshold_use = inflate_threshold;
566
Robert Olsson2f368952005-07-05 15:02:40 -0700567 err = 0;
Robert Olsson05eee482007-03-19 16:27:37 -0700568 max_resize = 10;
569 while ((tn->full_children > 0 && max_resize-- &&
Robert Olsson19baf832005-06-21 12:43:18 -0700570 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
Robert Olssone6308be2005-10-04 13:01:58 -0700571 inflate_threshold_use * tnode_child_length(tn))) {
Robert Olsson19baf832005-06-21 12:43:18 -0700572
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700573 old_tn = tn;
574 tn = inflate(t, tn);
575 if (IS_ERR(tn)) {
576 tn = old_tn;
Robert Olsson2f368952005-07-05 15:02:40 -0700577#ifdef CONFIG_IP_FIB_TRIE_STATS
578 t->stats.resize_node_skipped++;
579#endif
580 break;
581 }
Robert Olsson19baf832005-06-21 12:43:18 -0700582 }
583
Robert Olsson05eee482007-03-19 16:27:37 -0700584 if (max_resize < 0) {
585 if (!tn->parent)
586 printk(KERN_WARNING "Fix inflate_threshold_root. Now=%d size=%d bits\n",
587 inflate_threshold_root, tn->bits);
588 else
589 printk(KERN_WARNING "Fix inflate_threshold. Now=%d size=%d bits\n",
590 inflate_threshold, tn->bits);
591 }
592
Robert Olsson19baf832005-06-21 12:43:18 -0700593 check_tnode(tn);
594
595 /*
596 * Halve as long as the number of empty children in this
597 * node is above threshold.
598 */
Robert Olsson2f368952005-07-05 15:02:40 -0700599
Robert Olssone6308be2005-10-04 13:01:58 -0700600
601 /* Keep root node larger */
602
Stephen Hemminger132adf52007-03-08 20:44:43 -0800603 if (!tn->parent)
Robert Olssone6308be2005-10-04 13:01:58 -0700604 halve_threshold_use = halve_threshold_root;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900605 else
Robert Olssone6308be2005-10-04 13:01:58 -0700606 halve_threshold_use = halve_threshold;
607
Robert Olsson2f368952005-07-05 15:02:40 -0700608 err = 0;
Robert Olsson05eee482007-03-19 16:27:37 -0700609 max_resize = 10;
610 while (tn->bits > 1 && max_resize-- &&
Robert Olsson19baf832005-06-21 12:43:18 -0700611 100 * (tnode_child_length(tn) - tn->empty_children) <
Robert Olssone6308be2005-10-04 13:01:58 -0700612 halve_threshold_use * tnode_child_length(tn)) {
Robert Olsson19baf832005-06-21 12:43:18 -0700613
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700614 old_tn = tn;
615 tn = halve(t, tn);
616 if (IS_ERR(tn)) {
617 tn = old_tn;
Robert Olsson2f368952005-07-05 15:02:40 -0700618#ifdef CONFIG_IP_FIB_TRIE_STATS
619 t->stats.resize_node_skipped++;
620#endif
621 break;
622 }
623 }
624
Robert Olsson05eee482007-03-19 16:27:37 -0700625 if (max_resize < 0) {
626 if (!tn->parent)
627 printk(KERN_WARNING "Fix halve_threshold_root. Now=%d size=%d bits\n",
628 halve_threshold_root, tn->bits);
629 else
630 printk(KERN_WARNING "Fix halve_threshold. Now=%d size=%d bits\n",
631 halve_threshold, tn->bits);
632 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700633
Robert Olsson19baf832005-06-21 12:43:18 -0700634 /* Only one child remains */
Robert Olsson19baf832005-06-21 12:43:18 -0700635 if (tn->empty_children == tnode_child_length(tn) - 1)
636 for (i = 0; i < tnode_child_length(tn); i++) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700637 struct node *n;
638
Olof Johansson91b9a272005-08-09 20:24:39 -0700639 n = tn->child[i];
Robert Olsson2373ce12005-08-25 13:01:29 -0700640 if (!n)
Olof Johansson91b9a272005-08-09 20:24:39 -0700641 continue;
Olof Johansson91b9a272005-08-09 20:24:39 -0700642
643 /* compress one level */
644
Stephen Hemminger06801912007-08-10 15:22:13 -0700645 node_set_parent(n, NULL);
Olof Johansson91b9a272005-08-09 20:24:39 -0700646 tnode_free(tn);
647 return n;
Robert Olsson19baf832005-06-21 12:43:18 -0700648 }
649
650 return (struct node *) tn;
651}
652
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700653static struct tnode *inflate(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700654{
655 struct tnode *inode;
656 struct tnode *oldtnode = tn;
657 int olen = tnode_child_length(tn);
658 int i;
659
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700660 pr_debug("In inflate\n");
Robert Olsson19baf832005-06-21 12:43:18 -0700661
662 tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
663
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700664 if (!tn)
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700665 return ERR_PTR(-ENOMEM);
Robert Olsson2f368952005-07-05 15:02:40 -0700666
667 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700668 * Preallocate and store tnodes before the actual work so we
669 * don't get into an inconsistent state if memory allocation
670 * fails. In case of failure we return the oldnode and inflate
Robert Olsson2f368952005-07-05 15:02:40 -0700671 * of tnode is ignored.
672 */
Olof Johansson91b9a272005-08-09 20:24:39 -0700673
674 for (i = 0; i < olen; i++) {
Robert Olsson2f368952005-07-05 15:02:40 -0700675 struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i);
676
677 if (inode &&
678 IS_TNODE(inode) &&
679 inode->pos == oldtnode->pos + oldtnode->bits &&
680 inode->bits > 1) {
681 struct tnode *left, *right;
Robert Olsson2f368952005-07-05 15:02:40 -0700682 t_key m = TKEY_GET_MASK(inode->pos, 1);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700683
Robert Olsson2f368952005-07-05 15:02:40 -0700684 left = tnode_new(inode->key&(~m), inode->pos + 1,
685 inode->bits - 1);
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700686 if (!left)
687 goto nomem;
Olof Johansson91b9a272005-08-09 20:24:39 -0700688
Robert Olsson2f368952005-07-05 15:02:40 -0700689 right = tnode_new(inode->key|m, inode->pos + 1,
690 inode->bits - 1);
691
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900692 if (!right) {
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700693 tnode_free(left);
694 goto nomem;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900695 }
Robert Olsson2f368952005-07-05 15:02:40 -0700696
697 put_child(t, tn, 2*i, (struct node *) left);
698 put_child(t, tn, 2*i+1, (struct node *) right);
699 }
700 }
701
Olof Johansson91b9a272005-08-09 20:24:39 -0700702 for (i = 0; i < olen; i++) {
Robert Olsson19baf832005-06-21 12:43:18 -0700703 struct node *node = tnode_get_child(oldtnode, i);
Olof Johansson91b9a272005-08-09 20:24:39 -0700704 struct tnode *left, *right;
705 int size, j;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700706
Robert Olsson19baf832005-06-21 12:43:18 -0700707 /* An empty child */
708 if (node == NULL)
709 continue;
710
711 /* A leaf or an internal node with skipped bits */
712
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700713 if (IS_LEAF(node) || ((struct tnode *) node)->pos >
Robert Olsson19baf832005-06-21 12:43:18 -0700714 tn->pos + tn->bits - 1) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700715 if (tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits,
Robert Olsson19baf832005-06-21 12:43:18 -0700716 1) == 0)
717 put_child(t, tn, 2*i, node);
718 else
719 put_child(t, tn, 2*i+1, node);
720 continue;
721 }
722
723 /* An internal node with two children */
724 inode = (struct tnode *) node;
725
726 if (inode->bits == 1) {
727 put_child(t, tn, 2*i, inode->child[0]);
728 put_child(t, tn, 2*i+1, inode->child[1]);
729
730 tnode_free(inode);
Olof Johansson91b9a272005-08-09 20:24:39 -0700731 continue;
Robert Olsson19baf832005-06-21 12:43:18 -0700732 }
733
Olof Johansson91b9a272005-08-09 20:24:39 -0700734 /* An internal node with more than two children */
Robert Olsson19baf832005-06-21 12:43:18 -0700735
Olof Johansson91b9a272005-08-09 20:24:39 -0700736 /* We will replace this node 'inode' with two new
737 * ones, 'left' and 'right', each with half of the
738 * original children. The two new nodes will have
739 * a position one bit further down the key and this
740 * means that the "significant" part of their keys
741 * (see the discussion near the top of this file)
742 * will differ by one bit, which will be "0" in
743 * left's key and "1" in right's key. Since we are
744 * moving the key position by one step, the bit that
745 * we are moving away from - the bit at position
746 * (inode->pos) - is the one that will differ between
747 * left and right. So... we synthesize that bit in the
748 * two new keys.
749 * The mask 'm' below will be a single "one" bit at
750 * the position (inode->pos)
751 */
Robert Olsson19baf832005-06-21 12:43:18 -0700752
Olof Johansson91b9a272005-08-09 20:24:39 -0700753 /* Use the old key, but set the new significant
754 * bit to zero.
755 */
Robert Olsson19baf832005-06-21 12:43:18 -0700756
Olof Johansson91b9a272005-08-09 20:24:39 -0700757 left = (struct tnode *) tnode_get_child(tn, 2*i);
758 put_child(t, tn, 2*i, NULL);
Robert Olsson19baf832005-06-21 12:43:18 -0700759
Olof Johansson91b9a272005-08-09 20:24:39 -0700760 BUG_ON(!left);
Robert Olsson2f368952005-07-05 15:02:40 -0700761
Olof Johansson91b9a272005-08-09 20:24:39 -0700762 right = (struct tnode *) tnode_get_child(tn, 2*i+1);
763 put_child(t, tn, 2*i+1, NULL);
Robert Olsson2f368952005-07-05 15:02:40 -0700764
Olof Johansson91b9a272005-08-09 20:24:39 -0700765 BUG_ON(!right);
Robert Olsson2f368952005-07-05 15:02:40 -0700766
Olof Johansson91b9a272005-08-09 20:24:39 -0700767 size = tnode_child_length(left);
768 for (j = 0; j < size; j++) {
769 put_child(t, left, j, inode->child[j]);
770 put_child(t, right, j, inode->child[j + size]);
Robert Olsson19baf832005-06-21 12:43:18 -0700771 }
Olof Johansson91b9a272005-08-09 20:24:39 -0700772 put_child(t, tn, 2*i, resize(t, left));
773 put_child(t, tn, 2*i+1, resize(t, right));
774
775 tnode_free(inode);
Robert Olsson19baf832005-06-21 12:43:18 -0700776 }
777 tnode_free(oldtnode);
778 return tn;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700779nomem:
780 {
781 int size = tnode_child_length(tn);
782 int j;
783
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700784 for (j = 0; j < size; j++)
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700785 if (tn->child[j])
786 tnode_free((struct tnode *)tn->child[j]);
787
788 tnode_free(tn);
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700789
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700790 return ERR_PTR(-ENOMEM);
791 }
Robert Olsson19baf832005-06-21 12:43:18 -0700792}
793
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700794static struct tnode *halve(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700795{
796 struct tnode *oldtnode = tn;
797 struct node *left, *right;
798 int i;
799 int olen = tnode_child_length(tn);
800
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700801 pr_debug("In halve\n");
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700802
803 tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
Robert Olsson19baf832005-06-21 12:43:18 -0700804
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700805 if (!tn)
806 return ERR_PTR(-ENOMEM);
Robert Olsson2f368952005-07-05 15:02:40 -0700807
808 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700809 * Preallocate and store tnodes before the actual work so we
810 * don't get into an inconsistent state if memory allocation
811 * fails. In case of failure we return the oldnode and halve
Robert Olsson2f368952005-07-05 15:02:40 -0700812 * of tnode is ignored.
813 */
814
Olof Johansson91b9a272005-08-09 20:24:39 -0700815 for (i = 0; i < olen; i += 2) {
Robert Olsson2f368952005-07-05 15:02:40 -0700816 left = tnode_get_child(oldtnode, i);
817 right = tnode_get_child(oldtnode, i+1);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700818
Robert Olsson2f368952005-07-05 15:02:40 -0700819 /* Two nonempty children */
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700820 if (left && right) {
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700821 struct tnode *newn;
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700822
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700823 newn = tnode_new(left->key, tn->pos + tn->bits, 1);
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700824
825 if (!newn)
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700826 goto nomem;
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700827
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700828 put_child(t, tn, i/2, (struct node *)newn);
Robert Olsson2f368952005-07-05 15:02:40 -0700829 }
Robert Olsson2f368952005-07-05 15:02:40 -0700830
Robert Olsson2f368952005-07-05 15:02:40 -0700831 }
Robert Olsson19baf832005-06-21 12:43:18 -0700832
Olof Johansson91b9a272005-08-09 20:24:39 -0700833 for (i = 0; i < olen; i += 2) {
834 struct tnode *newBinNode;
835
Robert Olsson19baf832005-06-21 12:43:18 -0700836 left = tnode_get_child(oldtnode, i);
837 right = tnode_get_child(oldtnode, i+1);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700838
Robert Olsson19baf832005-06-21 12:43:18 -0700839 /* At least one of the children is empty */
840 if (left == NULL) {
841 if (right == NULL) /* Both are empty */
842 continue;
843 put_child(t, tn, i/2, right);
Olof Johansson91b9a272005-08-09 20:24:39 -0700844 continue;
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700845 }
Olof Johansson91b9a272005-08-09 20:24:39 -0700846
847 if (right == NULL) {
Robert Olsson19baf832005-06-21 12:43:18 -0700848 put_child(t, tn, i/2, left);
Olof Johansson91b9a272005-08-09 20:24:39 -0700849 continue;
850 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700851
Robert Olsson19baf832005-06-21 12:43:18 -0700852 /* Two nonempty children */
Olof Johansson91b9a272005-08-09 20:24:39 -0700853 newBinNode = (struct tnode *) tnode_get_child(tn, i/2);
854 put_child(t, tn, i/2, NULL);
Olof Johansson91b9a272005-08-09 20:24:39 -0700855 put_child(t, newBinNode, 0, left);
856 put_child(t, newBinNode, 1, right);
857 put_child(t, tn, i/2, resize(t, newBinNode));
Robert Olsson19baf832005-06-21 12:43:18 -0700858 }
859 tnode_free(oldtnode);
860 return tn;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700861nomem:
862 {
863 int size = tnode_child_length(tn);
864 int j;
865
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700866 for (j = 0; j < size; j++)
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700867 if (tn->child[j])
868 tnode_free((struct tnode *)tn->child[j]);
869
870 tnode_free(tn);
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700871
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700872 return ERR_PTR(-ENOMEM);
873 }
Robert Olsson19baf832005-06-21 12:43:18 -0700874}
875
Olof Johansson91b9a272005-08-09 20:24:39 -0700876static void trie_init(struct trie *t)
Robert Olsson19baf832005-06-21 12:43:18 -0700877{
Olof Johansson91b9a272005-08-09 20:24:39 -0700878 if (!t)
879 return;
880
881 t->size = 0;
Robert Olsson2373ce12005-08-25 13:01:29 -0700882 rcu_assign_pointer(t->trie, NULL);
Olof Johansson91b9a272005-08-09 20:24:39 -0700883 t->revision = 0;
Robert Olsson19baf832005-06-21 12:43:18 -0700884#ifdef CONFIG_IP_FIB_TRIE_STATS
Olof Johansson91b9a272005-08-09 20:24:39 -0700885 memset(&t->stats, 0, sizeof(struct trie_use_stats));
Robert Olsson19baf832005-06-21 12:43:18 -0700886#endif
Robert Olsson19baf832005-06-21 12:43:18 -0700887}
888
Robert Olsson772cb712005-09-19 15:31:18 -0700889/* readside must use rcu_read_lock currently dump routines
Robert Olsson2373ce12005-08-25 13:01:29 -0700890 via get_fa_head and dump */
891
Robert Olsson772cb712005-09-19 15:31:18 -0700892static struct leaf_info *find_leaf_info(struct leaf *l, int plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700893{
Robert Olsson772cb712005-09-19 15:31:18 -0700894 struct hlist_head *head = &l->list;
Robert Olsson19baf832005-06-21 12:43:18 -0700895 struct hlist_node *node;
896 struct leaf_info *li;
897
Robert Olsson2373ce12005-08-25 13:01:29 -0700898 hlist_for_each_entry_rcu(li, node, head, hlist)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700899 if (li->plen == plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700900 return li;
Olof Johansson91b9a272005-08-09 20:24:39 -0700901
Robert Olsson19baf832005-06-21 12:43:18 -0700902 return NULL;
903}
904
905static inline struct list_head * get_fa_head(struct leaf *l, int plen)
906{
Robert Olsson772cb712005-09-19 15:31:18 -0700907 struct leaf_info *li = find_leaf_info(l, plen);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700908
Olof Johansson91b9a272005-08-09 20:24:39 -0700909 if (!li)
910 return NULL;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700911
Olof Johansson91b9a272005-08-09 20:24:39 -0700912 return &li->falh;
Robert Olsson19baf832005-06-21 12:43:18 -0700913}
914
915static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new)
916{
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900917 struct leaf_info *li = NULL, *last = NULL;
918 struct hlist_node *node;
Robert Olsson19baf832005-06-21 12:43:18 -0700919
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900920 if (hlist_empty(head)) {
921 hlist_add_head_rcu(&new->hlist, head);
922 } else {
923 hlist_for_each_entry(li, node, head, hlist) {
924 if (new->plen > li->plen)
925 break;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700926
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900927 last = li;
928 }
929 if (last)
930 hlist_add_after_rcu(&last->hlist, &new->hlist);
931 else
932 hlist_add_before_rcu(&new->hlist, &li->hlist);
933 }
Robert Olsson19baf832005-06-21 12:43:18 -0700934}
935
Robert Olsson2373ce12005-08-25 13:01:29 -0700936/* rcu_read_lock needs to be hold by caller from readside */
937
Robert Olsson19baf832005-06-21 12:43:18 -0700938static struct leaf *
939fib_find_node(struct trie *t, u32 key)
940{
941 int pos;
942 struct tnode *tn;
943 struct node *n;
944
945 pos = 0;
Robert Olsson2373ce12005-08-25 13:01:29 -0700946 n = rcu_dereference(t->trie);
Robert Olsson19baf832005-06-21 12:43:18 -0700947
948 while (n != NULL && NODE_TYPE(n) == T_TNODE) {
949 tn = (struct tnode *) n;
Olof Johansson91b9a272005-08-09 20:24:39 -0700950
Robert Olsson19baf832005-06-21 12:43:18 -0700951 check_tnode(tn);
Olof Johansson91b9a272005-08-09 20:24:39 -0700952
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700953 if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700954 pos = tn->pos + tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -0700955 n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
Olof Johansson91b9a272005-08-09 20:24:39 -0700956 } else
Robert Olsson19baf832005-06-21 12:43:18 -0700957 break;
958 }
959 /* Case we have found a leaf. Compare prefixes */
960
Olof Johansson91b9a272005-08-09 20:24:39 -0700961 if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))
962 return (struct leaf *)n;
963
Robert Olsson19baf832005-06-21 12:43:18 -0700964 return NULL;
965}
966
967static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
968{
Robert Olsson19baf832005-06-21 12:43:18 -0700969 int wasfull;
Stephen Hemminger06801912007-08-10 15:22:13 -0700970 t_key cindex, key = tn->key;
971 struct tnode *tp;
Robert Olsson19baf832005-06-21 12:43:18 -0700972
Stephen Hemminger06801912007-08-10 15:22:13 -0700973 while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) {
Robert Olsson19baf832005-06-21 12:43:18 -0700974 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
975 wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
976 tn = (struct tnode *) resize (t, (struct tnode *)tn);
977 tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull);
Olof Johansson91b9a272005-08-09 20:24:39 -0700978
Stephen Hemminger06801912007-08-10 15:22:13 -0700979 tp = node_parent((struct node *) tn);
980 if (!tp)
Robert Olsson19baf832005-06-21 12:43:18 -0700981 break;
Stephen Hemminger06801912007-08-10 15:22:13 -0700982 tn = tp;
Robert Olsson19baf832005-06-21 12:43:18 -0700983 }
Stephen Hemminger06801912007-08-10 15:22:13 -0700984
Robert Olsson19baf832005-06-21 12:43:18 -0700985 /* Handle last (top) tnode */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700986 if (IS_TNODE(tn))
Robert Olsson19baf832005-06-21 12:43:18 -0700987 tn = (struct tnode*) resize(t, (struct tnode *)tn);
988
989 return (struct node*) tn;
990}
991
Robert Olsson2373ce12005-08-25 13:01:29 -0700992/* only used from updater-side */
993
Robert Olssonf835e472005-06-28 15:00:39 -0700994static struct list_head *
995fib_insert_node(struct trie *t, int *err, u32 key, int plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700996{
997 int pos, newpos;
998 struct tnode *tp = NULL, *tn = NULL;
999 struct node *n;
1000 struct leaf *l;
1001 int missbit;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001002 struct list_head *fa_head = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001003 struct leaf_info *li;
1004 t_key cindex;
1005
1006 pos = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001007 n = t->trie;
Robert Olsson19baf832005-06-21 12:43:18 -07001008
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001009 /* If we point to NULL, stop. Either the tree is empty and we should
1010 * just put a new leaf in if, or we have reached an empty child slot,
Robert Olsson19baf832005-06-21 12:43:18 -07001011 * and we should just put our new leaf in that.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001012 * If we point to a T_TNODE, check if it matches our key. Note that
1013 * a T_TNODE might be skipping any number of bits - its 'pos' need
Robert Olsson19baf832005-06-21 12:43:18 -07001014 * not be the parent's 'pos'+'bits'!
1015 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001016 * If it does match the current key, get pos/bits from it, extract
Robert Olsson19baf832005-06-21 12:43:18 -07001017 * the index from our key, push the T_TNODE and walk the tree.
1018 *
1019 * If it doesn't, we have to replace it with a new T_TNODE.
1020 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001021 * If we point to a T_LEAF, it might or might not have the same key
1022 * as we do. If it does, just change the value, update the T_LEAF's
1023 * value, and return it.
Robert Olsson19baf832005-06-21 12:43:18 -07001024 * If it doesn't, we need to replace it with a T_TNODE.
1025 */
1026
1027 while (n != NULL && NODE_TYPE(n) == T_TNODE) {
1028 tn = (struct tnode *) n;
Olof Johansson91b9a272005-08-09 20:24:39 -07001029
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001030 check_tnode(tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001031
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001032 if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
Robert Olsson19baf832005-06-21 12:43:18 -07001033 tp = tn;
Olof Johansson91b9a272005-08-09 20:24:39 -07001034 pos = tn->pos + tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -07001035 n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
1036
Stephen Hemminger06801912007-08-10 15:22:13 -07001037 BUG_ON(n && node_parent(n) != tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001038 } else
Robert Olsson19baf832005-06-21 12:43:18 -07001039 break;
1040 }
1041
1042 /*
1043 * n ----> NULL, LEAF or TNODE
1044 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001045 * tp is n's (parent) ----> NULL or TNODE
Robert Olsson19baf832005-06-21 12:43:18 -07001046 */
1047
Olof Johansson91b9a272005-08-09 20:24:39 -07001048 BUG_ON(tp && IS_LEAF(tp));
Robert Olsson19baf832005-06-21 12:43:18 -07001049
1050 /* Case 1: n is a leaf. Compare prefixes */
1051
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001052 if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
Olof Johansson91b9a272005-08-09 20:24:39 -07001053 struct leaf *l = (struct leaf *) n;
1054
Robert Olsson19baf832005-06-21 12:43:18 -07001055 li = leaf_info_new(plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001056
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001057 if (!li) {
Robert Olssonf835e472005-06-28 15:00:39 -07001058 *err = -ENOMEM;
1059 goto err;
1060 }
Robert Olsson19baf832005-06-21 12:43:18 -07001061
1062 fa_head = &li->falh;
1063 insert_leaf_info(&l->list, li);
1064 goto done;
1065 }
1066 t->size++;
1067 l = leaf_new();
1068
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001069 if (!l) {
Robert Olssonf835e472005-06-28 15:00:39 -07001070 *err = -ENOMEM;
1071 goto err;
1072 }
Robert Olsson19baf832005-06-21 12:43:18 -07001073
1074 l->key = key;
1075 li = leaf_info_new(plen);
1076
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001077 if (!li) {
Robert Olssonf835e472005-06-28 15:00:39 -07001078 tnode_free((struct tnode *) l);
1079 *err = -ENOMEM;
1080 goto err;
1081 }
Robert Olsson19baf832005-06-21 12:43:18 -07001082
1083 fa_head = &li->falh;
1084 insert_leaf_info(&l->list, li);
1085
Robert Olsson19baf832005-06-21 12:43:18 -07001086 if (t->trie && n == NULL) {
Olof Johansson91b9a272005-08-09 20:24:39 -07001087 /* Case 2: n is NULL, and will just insert a new leaf */
Robert Olsson19baf832005-06-21 12:43:18 -07001088
Stephen Hemminger06801912007-08-10 15:22:13 -07001089 node_set_parent((struct node *)l, tp);
Robert Olsson19baf832005-06-21 12:43:18 -07001090
Olof Johansson91b9a272005-08-09 20:24:39 -07001091 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1092 put_child(t, (struct tnode *)tp, cindex, (struct node *)l);
1093 } else {
1094 /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001095 /*
1096 * Add a new tnode here
Robert Olsson19baf832005-06-21 12:43:18 -07001097 * first tnode need some special handling
1098 */
1099
1100 if (tp)
Olof Johansson91b9a272005-08-09 20:24:39 -07001101 pos = tp->pos+tp->bits;
Robert Olsson19baf832005-06-21 12:43:18 -07001102 else
Olof Johansson91b9a272005-08-09 20:24:39 -07001103 pos = 0;
1104
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001105 if (n) {
Robert Olsson19baf832005-06-21 12:43:18 -07001106 newpos = tkey_mismatch(key, pos, n->key);
1107 tn = tnode_new(n->key, newpos, 1);
Olof Johansson91b9a272005-08-09 20:24:39 -07001108 } else {
Robert Olsson19baf832005-06-21 12:43:18 -07001109 newpos = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001110 tn = tnode_new(key, newpos, 1); /* First tnode */
Robert Olsson19baf832005-06-21 12:43:18 -07001111 }
Robert Olsson19baf832005-06-21 12:43:18 -07001112
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001113 if (!tn) {
Robert Olssonf835e472005-06-28 15:00:39 -07001114 free_leaf_info(li);
1115 tnode_free((struct tnode *) l);
1116 *err = -ENOMEM;
1117 goto err;
Olof Johansson91b9a272005-08-09 20:24:39 -07001118 }
1119
Stephen Hemminger06801912007-08-10 15:22:13 -07001120 node_set_parent((struct node *)tn, tp);
Robert Olsson19baf832005-06-21 12:43:18 -07001121
Olof Johansson91b9a272005-08-09 20:24:39 -07001122 missbit = tkey_extract_bits(key, newpos, 1);
Robert Olsson19baf832005-06-21 12:43:18 -07001123 put_child(t, tn, missbit, (struct node *)l);
1124 put_child(t, tn, 1-missbit, n);
1125
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001126 if (tp) {
Robert Olsson19baf832005-06-21 12:43:18 -07001127 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1128 put_child(t, (struct tnode *)tp, cindex, (struct node *)tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001129 } else {
Robert Olsson2373ce12005-08-25 13:01:29 -07001130 rcu_assign_pointer(t->trie, (struct node *)tn); /* First tnode */
Robert Olsson19baf832005-06-21 12:43:18 -07001131 tp = tn;
1132 }
1133 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001134
1135 if (tp && tp->pos + tp->bits > 32)
Stephen Hemminger78c66712005-09-21 00:15:39 -07001136 printk(KERN_WARNING "fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
Robert Olsson19baf832005-06-21 12:43:18 -07001137 tp, tp->pos, tp->bits, key, plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001138
Robert Olsson19baf832005-06-21 12:43:18 -07001139 /* Rebalance the trie */
Robert Olsson2373ce12005-08-25 13:01:29 -07001140
1141 rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
Robert Olssonf835e472005-06-28 15:00:39 -07001142done:
1143 t->revision++;
Olof Johansson91b9a272005-08-09 20:24:39 -07001144err:
Robert Olsson19baf832005-06-21 12:43:18 -07001145 return fa_head;
1146}
1147
Robert Olssond562f1f2007-03-26 14:22:22 -07001148/*
1149 * Caller must hold RTNL.
1150 */
Thomas Graf4e902c52006-08-17 18:14:52 -07001151static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
Robert Olsson19baf832005-06-21 12:43:18 -07001152{
1153 struct trie *t = (struct trie *) tb->tb_data;
1154 struct fib_alias *fa, *new_fa;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001155 struct list_head *fa_head = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001156 struct fib_info *fi;
Thomas Graf4e902c52006-08-17 18:14:52 -07001157 int plen = cfg->fc_dst_len;
1158 u8 tos = cfg->fc_tos;
Robert Olsson19baf832005-06-21 12:43:18 -07001159 u32 key, mask;
1160 int err;
1161 struct leaf *l;
1162
1163 if (plen > 32)
1164 return -EINVAL;
1165
Thomas Graf4e902c52006-08-17 18:14:52 -07001166 key = ntohl(cfg->fc_dst);
Robert Olsson19baf832005-06-21 12:43:18 -07001167
Patrick McHardy2dfe55b2006-08-10 23:08:33 -07001168 pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);
Robert Olsson19baf832005-06-21 12:43:18 -07001169
Olof Johansson91b9a272005-08-09 20:24:39 -07001170 mask = ntohl(inet_make_mask(plen));
Robert Olsson19baf832005-06-21 12:43:18 -07001171
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001172 if (key & ~mask)
Robert Olsson19baf832005-06-21 12:43:18 -07001173 return -EINVAL;
1174
1175 key = key & mask;
1176
Thomas Graf4e902c52006-08-17 18:14:52 -07001177 fi = fib_create_info(cfg);
1178 if (IS_ERR(fi)) {
1179 err = PTR_ERR(fi);
Robert Olsson19baf832005-06-21 12:43:18 -07001180 goto err;
Thomas Graf4e902c52006-08-17 18:14:52 -07001181 }
Robert Olsson19baf832005-06-21 12:43:18 -07001182
1183 l = fib_find_node(t, key);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001184 fa = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001185
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001186 if (l) {
Robert Olsson19baf832005-06-21 12:43:18 -07001187 fa_head = get_fa_head(l, plen);
1188 fa = fib_find_alias(fa_head, tos, fi->fib_priority);
1189 }
1190
1191 /* Now fa, if non-NULL, points to the first fib alias
1192 * with the same keys [prefix,tos,priority], if such key already
1193 * exists or to the node before which we will insert new one.
1194 *
1195 * If fa is NULL, we will need to allocate a new one and
1196 * insert to the head of f.
1197 *
1198 * If f is NULL, no fib node matched the destination key
1199 * and we need to allocate a new one of those as well.
1200 */
1201
Olof Johansson91b9a272005-08-09 20:24:39 -07001202 if (fa && fa->fa_info->fib_priority == fi->fib_priority) {
Robert Olsson19baf832005-06-21 12:43:18 -07001203 struct fib_alias *fa_orig;
1204
1205 err = -EEXIST;
Thomas Graf4e902c52006-08-17 18:14:52 -07001206 if (cfg->fc_nlflags & NLM_F_EXCL)
Robert Olsson19baf832005-06-21 12:43:18 -07001207 goto out;
1208
Thomas Graf4e902c52006-08-17 18:14:52 -07001209 if (cfg->fc_nlflags & NLM_F_REPLACE) {
Robert Olsson19baf832005-06-21 12:43:18 -07001210 struct fib_info *fi_drop;
1211 u8 state;
1212
Robert Olsson2373ce12005-08-25 13:01:29 -07001213 err = -ENOBUFS;
Christoph Lametere94b1762006-12-06 20:33:17 -08001214 new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
Robert Olsson2373ce12005-08-25 13:01:29 -07001215 if (new_fa == NULL)
1216 goto out;
Robert Olsson19baf832005-06-21 12:43:18 -07001217
1218 fi_drop = fa->fa_info;
Robert Olsson2373ce12005-08-25 13:01:29 -07001219 new_fa->fa_tos = fa->fa_tos;
1220 new_fa->fa_info = fi;
Thomas Graf4e902c52006-08-17 18:14:52 -07001221 new_fa->fa_type = cfg->fc_type;
1222 new_fa->fa_scope = cfg->fc_scope;
Robert Olsson19baf832005-06-21 12:43:18 -07001223 state = fa->fa_state;
Robert Olsson2373ce12005-08-25 13:01:29 -07001224 new_fa->fa_state &= ~FA_S_ACCESSED;
Robert Olsson19baf832005-06-21 12:43:18 -07001225
Robert Olsson2373ce12005-08-25 13:01:29 -07001226 list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
1227 alias_free_mem_rcu(fa);
Robert Olsson19baf832005-06-21 12:43:18 -07001228
1229 fib_release_info(fi_drop);
1230 if (state & FA_S_ACCESSED)
Olof Johansson91b9a272005-08-09 20:24:39 -07001231 rt_cache_flush(-1);
Milan Kocianb8f55832007-05-23 14:55:06 -07001232 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen,
1233 tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE);
Robert Olsson19baf832005-06-21 12:43:18 -07001234
Olof Johansson91b9a272005-08-09 20:24:39 -07001235 goto succeeded;
Robert Olsson19baf832005-06-21 12:43:18 -07001236 }
1237 /* Error if we find a perfect match which
1238 * uses the same scope, type, and nexthop
1239 * information.
1240 */
1241 fa_orig = fa;
1242 list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) {
1243 if (fa->fa_tos != tos)
1244 break;
1245 if (fa->fa_info->fib_priority != fi->fib_priority)
1246 break;
Thomas Graf4e902c52006-08-17 18:14:52 -07001247 if (fa->fa_type == cfg->fc_type &&
1248 fa->fa_scope == cfg->fc_scope &&
Robert Olsson19baf832005-06-21 12:43:18 -07001249 fa->fa_info == fi) {
1250 goto out;
1251 }
1252 }
Thomas Graf4e902c52006-08-17 18:14:52 -07001253 if (!(cfg->fc_nlflags & NLM_F_APPEND))
Robert Olsson19baf832005-06-21 12:43:18 -07001254 fa = fa_orig;
1255 }
1256 err = -ENOENT;
Thomas Graf4e902c52006-08-17 18:14:52 -07001257 if (!(cfg->fc_nlflags & NLM_F_CREATE))
Robert Olsson19baf832005-06-21 12:43:18 -07001258 goto out;
1259
1260 err = -ENOBUFS;
Christoph Lametere94b1762006-12-06 20:33:17 -08001261 new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
Robert Olsson19baf832005-06-21 12:43:18 -07001262 if (new_fa == NULL)
1263 goto out;
1264
1265 new_fa->fa_info = fi;
1266 new_fa->fa_tos = tos;
Thomas Graf4e902c52006-08-17 18:14:52 -07001267 new_fa->fa_type = cfg->fc_type;
1268 new_fa->fa_scope = cfg->fc_scope;
Robert Olsson19baf832005-06-21 12:43:18 -07001269 new_fa->fa_state = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001270 /*
1271 * Insert new entry to the list.
1272 */
1273
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001274 if (!fa_head) {
Robert Olssonf835e472005-06-28 15:00:39 -07001275 err = 0;
Herbert Xub47b2ec2006-07-12 13:29:56 -07001276 fa_head = fib_insert_node(t, &err, key, plen);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001277 if (err)
Robert Olssonf835e472005-06-28 15:00:39 -07001278 goto out_free_new_fa;
1279 }
Robert Olsson19baf832005-06-21 12:43:18 -07001280
Robert Olsson2373ce12005-08-25 13:01:29 -07001281 list_add_tail_rcu(&new_fa->fa_list,
1282 (fa ? &fa->fa_list : fa_head));
Robert Olsson19baf832005-06-21 12:43:18 -07001283
1284 rt_cache_flush(-1);
Thomas Graf4e902c52006-08-17 18:14:52 -07001285 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
Milan Kocianb8f55832007-05-23 14:55:06 -07001286 &cfg->fc_nlinfo, 0);
Robert Olsson19baf832005-06-21 12:43:18 -07001287succeeded:
1288 return 0;
Robert Olssonf835e472005-06-28 15:00:39 -07001289
1290out_free_new_fa:
1291 kmem_cache_free(fn_alias_kmem, new_fa);
Robert Olsson19baf832005-06-21 12:43:18 -07001292out:
1293 fib_release_info(fi);
Olof Johansson91b9a272005-08-09 20:24:39 -07001294err:
Robert Olsson19baf832005-06-21 12:43:18 -07001295 return err;
1296}
1297
Robert Olsson2373ce12005-08-25 13:01:29 -07001298
Robert Olsson772cb712005-09-19 15:31:18 -07001299/* should be called with rcu_read_lock */
Stephen Hemminger0c7770c2005-08-23 21:59:41 -07001300static inline int check_leaf(struct trie *t, struct leaf *l,
1301 t_key key, int *plen, const struct flowi *flp,
Patrick McHardy06c74272005-08-23 22:06:09 -07001302 struct fib_result *res)
Robert Olsson19baf832005-06-21 12:43:18 -07001303{
Patrick McHardy06c74272005-08-23 22:06:09 -07001304 int err, i;
Al Viro888454c2006-09-19 13:42:46 -07001305 __be32 mask;
Robert Olsson19baf832005-06-21 12:43:18 -07001306 struct leaf_info *li;
1307 struct hlist_head *hhead = &l->list;
1308 struct hlist_node *node;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001309
Robert Olsson2373ce12005-08-25 13:01:29 -07001310 hlist_for_each_entry_rcu(li, node, hhead, hlist) {
Robert Olsson19baf832005-06-21 12:43:18 -07001311 i = li->plen;
Al Viro888454c2006-09-19 13:42:46 -07001312 mask = inet_make_mask(i);
1313 if (l->key != (key & ntohl(mask)))
Robert Olsson19baf832005-06-21 12:43:18 -07001314 continue;
1315
Al Viro888454c2006-09-19 13:42:46 -07001316 if ((err = fib_semantic_match(&li->falh, flp, res, htonl(l->key), mask, i)) <= 0) {
Robert Olsson19baf832005-06-21 12:43:18 -07001317 *plen = i;
1318#ifdef CONFIG_IP_FIB_TRIE_STATS
1319 t->stats.semantic_match_passed++;
1320#endif
Patrick McHardy06c74272005-08-23 22:06:09 -07001321 return err;
Robert Olsson19baf832005-06-21 12:43:18 -07001322 }
1323#ifdef CONFIG_IP_FIB_TRIE_STATS
1324 t->stats.semantic_match_miss++;
1325#endif
1326 }
Patrick McHardy06c74272005-08-23 22:06:09 -07001327 return 1;
Robert Olsson19baf832005-06-21 12:43:18 -07001328}
1329
1330static int
1331fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
1332{
1333 struct trie *t = (struct trie *) tb->tb_data;
1334 int plen, ret = 0;
1335 struct node *n;
1336 struct tnode *pn;
1337 int pos, bits;
Olof Johansson91b9a272005-08-09 20:24:39 -07001338 t_key key = ntohl(flp->fl4_dst);
Robert Olsson19baf832005-06-21 12:43:18 -07001339 int chopped_off;
1340 t_key cindex = 0;
1341 int current_prefix_length = KEYLENGTH;
Olof Johansson91b9a272005-08-09 20:24:39 -07001342 struct tnode *cn;
1343 t_key node_prefix, key_prefix, pref_mismatch;
1344 int mp;
1345
Robert Olsson2373ce12005-08-25 13:01:29 -07001346 rcu_read_lock();
Robert Olsson19baf832005-06-21 12:43:18 -07001347
Robert Olsson2373ce12005-08-25 13:01:29 -07001348 n = rcu_dereference(t->trie);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001349 if (!n)
Robert Olsson19baf832005-06-21 12:43:18 -07001350 goto failed;
1351
1352#ifdef CONFIG_IP_FIB_TRIE_STATS
1353 t->stats.gets++;
1354#endif
1355
1356 /* Just a leaf? */
1357 if (IS_LEAF(n)) {
Patrick McHardy06c74272005-08-23 22:06:09 -07001358 if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
Robert Olsson19baf832005-06-21 12:43:18 -07001359 goto found;
1360 goto failed;
1361 }
1362 pn = (struct tnode *) n;
1363 chopped_off = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001364
Olof Johansson91b9a272005-08-09 20:24:39 -07001365 while (pn) {
Robert Olsson19baf832005-06-21 12:43:18 -07001366 pos = pn->pos;
1367 bits = pn->bits;
1368
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001369 if (!chopped_off)
Robert Olsson19baf832005-06-21 12:43:18 -07001370 cindex = tkey_extract_bits(MASK_PFX(key, current_prefix_length), pos, bits);
1371
1372 n = tnode_get_child(pn, cindex);
1373
1374 if (n == NULL) {
1375#ifdef CONFIG_IP_FIB_TRIE_STATS
1376 t->stats.null_node_hit++;
1377#endif
1378 goto backtrace;
1379 }
1380
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001381 if (IS_LEAF(n)) {
Patrick McHardy06c74272005-08-23 22:06:09 -07001382 if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
Robert Olsson19baf832005-06-21 12:43:18 -07001383 goto found;
Olof Johansson91b9a272005-08-09 20:24:39 -07001384 else
1385 goto backtrace;
1386 }
1387
1388#define HL_OPTIMIZE
1389#ifdef HL_OPTIMIZE
1390 cn = (struct tnode *)n;
1391
1392 /*
1393 * It's a tnode, and we can do some extra checks here if we
1394 * like, to avoid descending into a dead-end branch.
1395 * This tnode is in the parent's child array at index
1396 * key[p_pos..p_pos+p_bits] but potentially with some bits
1397 * chopped off, so in reality the index may be just a
1398 * subprefix, padded with zero at the end.
1399 * We can also take a look at any skipped bits in this
1400 * tnode - everything up to p_pos is supposed to be ok,
1401 * and the non-chopped bits of the index (se previous
1402 * paragraph) are also guaranteed ok, but the rest is
1403 * considered unknown.
1404 *
1405 * The skipped bits are key[pos+bits..cn->pos].
1406 */
1407
1408 /* If current_prefix_length < pos+bits, we are already doing
1409 * actual prefix matching, which means everything from
1410 * pos+(bits-chopped_off) onward must be zero along some
1411 * branch of this subtree - otherwise there is *no* valid
1412 * prefix present. Here we can only check the skipped
1413 * bits. Remember, since we have already indexed into the
1414 * parent's child array, we know that the bits we chopped of
1415 * *are* zero.
1416 */
1417
1418 /* NOTA BENE: CHECKING ONLY SKIPPED BITS FOR THE NEW NODE HERE */
1419
1420 if (current_prefix_length < pos+bits) {
1421 if (tkey_extract_bits(cn->key, current_prefix_length,
1422 cn->pos - current_prefix_length) != 0 ||
1423 !(cn->child[0]))
1424 goto backtrace;
1425 }
1426
1427 /*
1428 * If chopped_off=0, the index is fully validated and we
1429 * only need to look at the skipped bits for this, the new,
1430 * tnode. What we actually want to do is to find out if
1431 * these skipped bits match our key perfectly, or if we will
1432 * have to count on finding a matching prefix further down,
1433 * because if we do, we would like to have some way of
1434 * verifying the existence of such a prefix at this point.
1435 */
1436
1437 /* The only thing we can do at this point is to verify that
1438 * any such matching prefix can indeed be a prefix to our
1439 * key, and if the bits in the node we are inspecting that
1440 * do not match our key are not ZERO, this cannot be true.
1441 * Thus, find out where there is a mismatch (before cn->pos)
1442 * and verify that all the mismatching bits are zero in the
1443 * new tnode's key.
1444 */
1445
1446 /* Note: We aren't very concerned about the piece of the key
1447 * that precede pn->pos+pn->bits, since these have already been
1448 * checked. The bits after cn->pos aren't checked since these are
1449 * by definition "unknown" at this point. Thus, what we want to
1450 * see is if we are about to enter the "prefix matching" state,
1451 * and in that case verify that the skipped bits that will prevail
1452 * throughout this subtree are zero, as they have to be if we are
1453 * to find a matching prefix.
1454 */
1455
1456 node_prefix = MASK_PFX(cn->key, cn->pos);
1457 key_prefix = MASK_PFX(key, cn->pos);
1458 pref_mismatch = key_prefix^node_prefix;
1459 mp = 0;
1460
1461 /* In short: If skipped bits in this node do not match the search
1462 * key, enter the "prefix matching" state.directly.
1463 */
1464 if (pref_mismatch) {
1465 while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
1466 mp++;
1467 pref_mismatch = pref_mismatch <<1;
1468 }
1469 key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
1470
1471 if (key_prefix != 0)
1472 goto backtrace;
1473
1474 if (current_prefix_length >= cn->pos)
1475 current_prefix_length = mp;
1476 }
1477#endif
1478 pn = (struct tnode *)n; /* Descend */
1479 chopped_off = 0;
1480 continue;
1481
Robert Olsson19baf832005-06-21 12:43:18 -07001482backtrace:
1483 chopped_off++;
1484
1485 /* As zero don't change the child key (cindex) */
Olof Johansson91b9a272005-08-09 20:24:39 -07001486 while ((chopped_off <= pn->bits) && !(cindex & (1<<(chopped_off-1))))
Robert Olsson19baf832005-06-21 12:43:18 -07001487 chopped_off++;
Robert Olsson19baf832005-06-21 12:43:18 -07001488
1489 /* Decrease current_... with bits chopped off */
1490 if (current_prefix_length > pn->pos + pn->bits - chopped_off)
1491 current_prefix_length = pn->pos + pn->bits - chopped_off;
Olof Johansson91b9a272005-08-09 20:24:39 -07001492
Robert Olsson19baf832005-06-21 12:43:18 -07001493 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001494 * Either we do the actual chop off according or if we have
Robert Olsson19baf832005-06-21 12:43:18 -07001495 * chopped off all bits in this tnode walk up to our parent.
1496 */
1497
Olof Johansson91b9a272005-08-09 20:24:39 -07001498 if (chopped_off <= pn->bits) {
Robert Olsson19baf832005-06-21 12:43:18 -07001499 cindex &= ~(1 << (chopped_off-1));
Olof Johansson91b9a272005-08-09 20:24:39 -07001500 } else {
Stephen Hemminger06801912007-08-10 15:22:13 -07001501 struct tnode *parent = node_parent((struct node *) pn);
1502 if (!parent)
Robert Olsson19baf832005-06-21 12:43:18 -07001503 goto failed;
Olof Johansson91b9a272005-08-09 20:24:39 -07001504
Robert Olsson19baf832005-06-21 12:43:18 -07001505 /* Get Child's index */
Stephen Hemminger06801912007-08-10 15:22:13 -07001506 cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits);
1507 pn = parent;
Robert Olsson19baf832005-06-21 12:43:18 -07001508 chopped_off = 0;
1509
1510#ifdef CONFIG_IP_FIB_TRIE_STATS
1511 t->stats.backtrack++;
1512#endif
1513 goto backtrace;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001514 }
Robert Olsson19baf832005-06-21 12:43:18 -07001515 }
1516failed:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001517 ret = 1;
Robert Olsson19baf832005-06-21 12:43:18 -07001518found:
Robert Olsson2373ce12005-08-25 13:01:29 -07001519 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07001520 return ret;
1521}
1522
Robert Olsson2373ce12005-08-25 13:01:29 -07001523/* only called from updater side */
Robert Olsson19baf832005-06-21 12:43:18 -07001524static int trie_leaf_remove(struct trie *t, t_key key)
1525{
1526 t_key cindex;
1527 struct tnode *tp = NULL;
1528 struct node *n = t->trie;
1529 struct leaf *l;
1530
Stephen Hemminger0c7770c2005-08-23 21:59:41 -07001531 pr_debug("entering trie_leaf_remove(%p)\n", n);
Robert Olsson19baf832005-06-21 12:43:18 -07001532
1533 /* Note that in the case skipped bits, those bits are *not* checked!
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001534 * When we finish this, we will have NULL or a T_LEAF, and the
Robert Olsson19baf832005-06-21 12:43:18 -07001535 * T_LEAF may or may not match our key.
1536 */
1537
Olof Johansson91b9a272005-08-09 20:24:39 -07001538 while (n != NULL && IS_TNODE(n)) {
Robert Olsson19baf832005-06-21 12:43:18 -07001539 struct tnode *tn = (struct tnode *) n;
1540 check_tnode(tn);
1541 n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits));
1542
Stephen Hemminger06801912007-08-10 15:22:13 -07001543 BUG_ON(n && node_parent(n) != tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001544 }
Robert Olsson19baf832005-06-21 12:43:18 -07001545 l = (struct leaf *) n;
1546
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001547 if (!n || !tkey_equals(l->key, key))
Robert Olsson19baf832005-06-21 12:43:18 -07001548 return 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001549
1550 /*
1551 * Key found.
1552 * Remove the leaf and rebalance the tree
Robert Olsson19baf832005-06-21 12:43:18 -07001553 */
1554
1555 t->revision++;
1556 t->size--;
1557
Stephen Hemminger06801912007-08-10 15:22:13 -07001558 tp = node_parent(n);
Robert Olsson19baf832005-06-21 12:43:18 -07001559 tnode_free((struct tnode *) n);
1560
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001561 if (tp) {
Robert Olsson19baf832005-06-21 12:43:18 -07001562 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1563 put_child(t, (struct tnode *)tp, cindex, NULL);
Robert Olsson2373ce12005-08-25 13:01:29 -07001564 rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
Olof Johansson91b9a272005-08-09 20:24:39 -07001565 } else
Robert Olsson2373ce12005-08-25 13:01:29 -07001566 rcu_assign_pointer(t->trie, NULL);
Robert Olsson19baf832005-06-21 12:43:18 -07001567
1568 return 1;
1569}
1570
Robert Olssond562f1f2007-03-26 14:22:22 -07001571/*
1572 * Caller must hold RTNL.
1573 */
Thomas Graf4e902c52006-08-17 18:14:52 -07001574static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
Robert Olsson19baf832005-06-21 12:43:18 -07001575{
1576 struct trie *t = (struct trie *) tb->tb_data;
1577 u32 key, mask;
Thomas Graf4e902c52006-08-17 18:14:52 -07001578 int plen = cfg->fc_dst_len;
1579 u8 tos = cfg->fc_tos;
Robert Olsson19baf832005-06-21 12:43:18 -07001580 struct fib_alias *fa, *fa_to_delete;
1581 struct list_head *fa_head;
1582 struct leaf *l;
Olof Johansson91b9a272005-08-09 20:24:39 -07001583 struct leaf_info *li;
1584
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001585 if (plen > 32)
Robert Olsson19baf832005-06-21 12:43:18 -07001586 return -EINVAL;
1587
Thomas Graf4e902c52006-08-17 18:14:52 -07001588 key = ntohl(cfg->fc_dst);
Olof Johansson91b9a272005-08-09 20:24:39 -07001589 mask = ntohl(inet_make_mask(plen));
Robert Olsson19baf832005-06-21 12:43:18 -07001590
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001591 if (key & ~mask)
Robert Olsson19baf832005-06-21 12:43:18 -07001592 return -EINVAL;
1593
1594 key = key & mask;
1595 l = fib_find_node(t, key);
1596
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001597 if (!l)
Robert Olsson19baf832005-06-21 12:43:18 -07001598 return -ESRCH;
1599
1600 fa_head = get_fa_head(l, plen);
1601 fa = fib_find_alias(fa_head, tos, 0);
1602
1603 if (!fa)
1604 return -ESRCH;
1605
Stephen Hemminger0c7770c2005-08-23 21:59:41 -07001606 pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
Robert Olsson19baf832005-06-21 12:43:18 -07001607
1608 fa_to_delete = NULL;
1609 fa_head = fa->fa_list.prev;
Robert Olsson2373ce12005-08-25 13:01:29 -07001610
Robert Olsson19baf832005-06-21 12:43:18 -07001611 list_for_each_entry(fa, fa_head, fa_list) {
1612 struct fib_info *fi = fa->fa_info;
1613
1614 if (fa->fa_tos != tos)
1615 break;
1616
Thomas Graf4e902c52006-08-17 18:14:52 -07001617 if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) &&
1618 (cfg->fc_scope == RT_SCOPE_NOWHERE ||
1619 fa->fa_scope == cfg->fc_scope) &&
1620 (!cfg->fc_protocol ||
1621 fi->fib_protocol == cfg->fc_protocol) &&
1622 fib_nh_match(cfg, fi) == 0) {
Robert Olsson19baf832005-06-21 12:43:18 -07001623 fa_to_delete = fa;
1624 break;
1625 }
1626 }
1627
Olof Johansson91b9a272005-08-09 20:24:39 -07001628 if (!fa_to_delete)
1629 return -ESRCH;
Robert Olsson19baf832005-06-21 12:43:18 -07001630
Olof Johansson91b9a272005-08-09 20:24:39 -07001631 fa = fa_to_delete;
Thomas Graf4e902c52006-08-17 18:14:52 -07001632 rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id,
Milan Kocianb8f55832007-05-23 14:55:06 -07001633 &cfg->fc_nlinfo, 0);
Robert Olsson19baf832005-06-21 12:43:18 -07001634
Olof Johansson91b9a272005-08-09 20:24:39 -07001635 l = fib_find_node(t, key);
Robert Olsson772cb712005-09-19 15:31:18 -07001636 li = find_leaf_info(l, plen);
Robert Olsson19baf832005-06-21 12:43:18 -07001637
Robert Olsson2373ce12005-08-25 13:01:29 -07001638 list_del_rcu(&fa->fa_list);
Robert Olsson19baf832005-06-21 12:43:18 -07001639
Olof Johansson91b9a272005-08-09 20:24:39 -07001640 if (list_empty(fa_head)) {
Robert Olsson2373ce12005-08-25 13:01:29 -07001641 hlist_del_rcu(&li->hlist);
Olof Johansson91b9a272005-08-09 20:24:39 -07001642 free_leaf_info(li);
Robert Olsson2373ce12005-08-25 13:01:29 -07001643 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001644
1645 if (hlist_empty(&l->list))
1646 trie_leaf_remove(t, key);
1647
1648 if (fa->fa_state & FA_S_ACCESSED)
1649 rt_cache_flush(-1);
1650
Robert Olsson2373ce12005-08-25 13:01:29 -07001651 fib_release_info(fa->fa_info);
1652 alias_free_mem_rcu(fa);
Olof Johansson91b9a272005-08-09 20:24:39 -07001653 return 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001654}
1655
1656static int trie_flush_list(struct trie *t, struct list_head *head)
1657{
1658 struct fib_alias *fa, *fa_node;
1659 int found = 0;
1660
1661 list_for_each_entry_safe(fa, fa_node, head, fa_list) {
1662 struct fib_info *fi = fa->fa_info;
Robert Olsson19baf832005-06-21 12:43:18 -07001663
Robert Olsson2373ce12005-08-25 13:01:29 -07001664 if (fi && (fi->fib_flags & RTNH_F_DEAD)) {
1665 list_del_rcu(&fa->fa_list);
1666 fib_release_info(fa->fa_info);
1667 alias_free_mem_rcu(fa);
Robert Olsson19baf832005-06-21 12:43:18 -07001668 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)) {
Robert Olsson2373ce12005-08-25 13:01:29 -07001685 hlist_del_rcu(&li->hlist);
Robert Olsson19baf832005-06-21 12:43:18 -07001686 free_leaf_info(li);
1687 }
1688 }
1689 return found;
1690}
1691
Robert Olsson2373ce12005-08-25 13:01:29 -07001692/* rcu_read_lock needs to be hold by caller from readside */
1693
Robert Olsson19baf832005-06-21 12:43:18 -07001694static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
1695{
1696 struct node *c = (struct node *) thisleaf;
1697 struct tnode *p;
1698 int idx;
Robert Olsson2373ce12005-08-25 13:01:29 -07001699 struct node *trie = rcu_dereference(t->trie);
Robert Olsson19baf832005-06-21 12:43:18 -07001700
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001701 if (c == NULL) {
Robert Olsson2373ce12005-08-25 13:01:29 -07001702 if (trie == NULL)
Robert Olsson19baf832005-06-21 12:43:18 -07001703 return NULL;
1704
Robert Olsson2373ce12005-08-25 13:01:29 -07001705 if (IS_LEAF(trie)) /* trie w. just a leaf */
1706 return (struct leaf *) trie;
Robert Olsson19baf832005-06-21 12:43:18 -07001707
Robert Olsson2373ce12005-08-25 13:01:29 -07001708 p = (struct tnode*) trie; /* Start */
Olof Johansson91b9a272005-08-09 20:24:39 -07001709 } else
Stephen Hemminger06801912007-08-10 15:22:13 -07001710 p = 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++) {
Robert Olsson2373ce12005-08-25 13:01:29 -07001723 c = rcu_dereference(p->child[idx]);
1724
1725 if (!c)
Olof Johansson91b9a272005-08-09 20:24:39 -07001726 continue;
Robert Olsson19baf832005-06-21 12:43:18 -07001727
Olof Johansson91b9a272005-08-09 20:24:39 -07001728 /* Decend if tnode */
Robert Olsson2373ce12005-08-25 13:01:29 -07001729 while (IS_TNODE(c)) {
1730 p = (struct tnode *) c;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001731 idx = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001732
Olof Johansson91b9a272005-08-09 20:24:39 -07001733 /* Rightmost non-NULL branch */
1734 if (p && IS_TNODE(p))
Robert Olsson2373ce12005-08-25 13:01:29 -07001735 while (!(c = rcu_dereference(p->child[idx]))
1736 && idx < (1<<p->bits)) idx++;
Robert Olsson19baf832005-06-21 12:43:18 -07001737
Olof Johansson91b9a272005-08-09 20:24:39 -07001738 /* Done with this tnode? */
Robert Olsson2373ce12005-08-25 13:01:29 -07001739 if (idx >= (1 << p->bits) || !c)
Olof Johansson91b9a272005-08-09 20:24:39 -07001740 goto up;
Robert Olsson19baf832005-06-21 12:43:18 -07001741 }
Robert Olsson2373ce12005-08-25 13:01:29 -07001742 return (struct leaf *) c;
Robert Olsson19baf832005-06-21 12:43:18 -07001743 }
1744up:
1745 /* No more children go up one step */
Olof Johansson91b9a272005-08-09 20:24:39 -07001746 c = (struct node *) p;
Stephen Hemminger06801912007-08-10 15:22:13 -07001747 p = node_parent(c);
Robert Olsson19baf832005-06-21 12:43:18 -07001748 }
1749 return NULL; /* Ready. Root of trie */
1750}
1751
Robert Olssond562f1f2007-03-26 14:22:22 -07001752/*
1753 * Caller must hold RTNL.
1754 */
Robert Olsson19baf832005-06-21 12:43:18 -07001755static int fn_trie_flush(struct fib_table *tb)
1756{
1757 struct trie *t = (struct trie *) tb->tb_data;
1758 struct leaf *ll = NULL, *l = NULL;
1759 int found = 0, h;
1760
1761 t->revision++;
1762
Olof Johansson91b9a272005-08-09 20:24:39 -07001763 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001764 found += trie_flush_leaf(t, l);
1765
1766 if (ll && hlist_empty(&ll->list))
1767 trie_leaf_remove(t, ll->key);
1768 ll = l;
1769 }
1770
1771 if (ll && hlist_empty(&ll->list))
1772 trie_leaf_remove(t, ll->key);
1773
Stephen Hemminger0c7770c2005-08-23 21:59:41 -07001774 pr_debug("trie_flush found=%d\n", found);
Robert Olsson19baf832005-06-21 12:43:18 -07001775 return found;
1776}
1777
Olof Johansson91b9a272005-08-09 20:24:39 -07001778static int trie_last_dflt = -1;
Robert Olsson19baf832005-06-21 12:43:18 -07001779
1780static void
1781fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
1782{
1783 struct trie *t = (struct trie *) tb->tb_data;
1784 int order, last_idx;
1785 struct fib_info *fi = NULL;
1786 struct fib_info *last_resort;
1787 struct fib_alias *fa = NULL;
1788 struct list_head *fa_head;
1789 struct leaf *l;
1790
1791 last_idx = -1;
1792 last_resort = NULL;
1793 order = -1;
1794
Robert Olsson2373ce12005-08-25 13:01:29 -07001795 rcu_read_lock();
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001796
Robert Olsson19baf832005-06-21 12:43:18 -07001797 l = fib_find_node(t, 0);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001798 if (!l)
Robert Olsson19baf832005-06-21 12:43:18 -07001799 goto out;
1800
1801 fa_head = get_fa_head(l, 0);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001802 if (!fa_head)
Robert Olsson19baf832005-06-21 12:43:18 -07001803 goto out;
1804
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001805 if (list_empty(fa_head))
Robert Olsson19baf832005-06-21 12:43:18 -07001806 goto out;
1807
Robert Olsson2373ce12005-08-25 13:01:29 -07001808 list_for_each_entry_rcu(fa, fa_head, fa_list) {
Robert Olsson19baf832005-06-21 12:43:18 -07001809 struct fib_info *next_fi = fa->fa_info;
Olof Johansson91b9a272005-08-09 20:24:39 -07001810
Robert Olsson19baf832005-06-21 12:43:18 -07001811 if (fa->fa_scope != res->scope ||
1812 fa->fa_type != RTN_UNICAST)
1813 continue;
Olof Johansson91b9a272005-08-09 20:24:39 -07001814
Robert Olsson19baf832005-06-21 12:43:18 -07001815 if (next_fi->fib_priority > res->fi->fib_priority)
1816 break;
1817 if (!next_fi->fib_nh[0].nh_gw ||
1818 next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
1819 continue;
1820 fa->fa_state |= FA_S_ACCESSED;
Olof Johansson91b9a272005-08-09 20:24:39 -07001821
Robert Olsson19baf832005-06-21 12:43:18 -07001822 if (fi == NULL) {
1823 if (next_fi != res->fi)
1824 break;
1825 } else if (!fib_detect_death(fi, order, &last_resort,
1826 &last_idx, &trie_last_dflt)) {
1827 if (res->fi)
1828 fib_info_put(res->fi);
1829 res->fi = fi;
1830 atomic_inc(&fi->fib_clntref);
1831 trie_last_dflt = order;
1832 goto out;
1833 }
1834 fi = next_fi;
1835 order++;
1836 }
1837 if (order <= 0 || fi == NULL) {
1838 trie_last_dflt = -1;
1839 goto out;
1840 }
1841
1842 if (!fib_detect_death(fi, order, &last_resort, &last_idx, &trie_last_dflt)) {
1843 if (res->fi)
1844 fib_info_put(res->fi);
1845 res->fi = fi;
1846 atomic_inc(&fi->fib_clntref);
1847 trie_last_dflt = order;
1848 goto out;
1849 }
1850 if (last_idx >= 0) {
1851 if (res->fi)
1852 fib_info_put(res->fi);
1853 res->fi = last_resort;
1854 if (last_resort)
1855 atomic_inc(&last_resort->fib_clntref);
1856 }
1857 trie_last_dflt = last_idx;
1858 out:;
Robert Olsson2373ce12005-08-25 13:01:29 -07001859 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07001860}
1861
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001862static 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 -07001863 struct sk_buff *skb, struct netlink_callback *cb)
1864{
1865 int i, s_i;
1866 struct fib_alias *fa;
1867
Al Viro32ab5f82006-09-26 22:21:45 -07001868 __be32 xkey = htonl(key);
Robert Olsson19baf832005-06-21 12:43:18 -07001869
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001870 s_i = cb->args[4];
Robert Olsson19baf832005-06-21 12:43:18 -07001871 i = 0;
1872
Robert Olsson2373ce12005-08-25 13:01:29 -07001873 /* rcu_read_lock is hold by caller */
1874
1875 list_for_each_entry_rcu(fa, fah, fa_list) {
Robert Olsson19baf832005-06-21 12:43:18 -07001876 if (i < s_i) {
1877 i++;
1878 continue;
1879 }
Stephen Hemminger78c66712005-09-21 00:15:39 -07001880 BUG_ON(!fa->fa_info);
Robert Olsson19baf832005-06-21 12:43:18 -07001881
1882 if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
1883 cb->nlh->nlmsg_seq,
1884 RTM_NEWROUTE,
1885 tb->tb_id,
1886 fa->fa_type,
1887 fa->fa_scope,
Thomas Grafbe403ea2006-08-17 18:15:17 -07001888 xkey,
Robert Olsson19baf832005-06-21 12:43:18 -07001889 plen,
1890 fa->fa_tos,
David S. Miller90f66912005-06-21 14:43:28 -07001891 fa->fa_info, 0) < 0) {
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001892 cb->args[4] = i;
Robert Olsson19baf832005-06-21 12:43:18 -07001893 return -1;
Olof Johansson91b9a272005-08-09 20:24:39 -07001894 }
Robert Olsson19baf832005-06-21 12:43:18 -07001895 i++;
1896 }
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001897 cb->args[4] = i;
Robert Olsson19baf832005-06-21 12:43:18 -07001898 return skb->len;
1899}
1900
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001901static 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 -07001902 struct netlink_callback *cb)
1903{
1904 int h, s_h;
1905 struct list_head *fa_head;
1906 struct leaf *l = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001907
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001908 s_h = cb->args[3];
Robert Olsson19baf832005-06-21 12:43:18 -07001909
Olof Johansson91b9a272005-08-09 20:24:39 -07001910 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001911 if (h < s_h)
1912 continue;
1913 if (h > s_h)
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001914 memset(&cb->args[4], 0,
1915 sizeof(cb->args) - 4*sizeof(cb->args[0]));
Robert Olsson19baf832005-06-21 12:43:18 -07001916
1917 fa_head = get_fa_head(l, plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001918
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001919 if (!fa_head)
Robert Olsson19baf832005-06-21 12:43:18 -07001920 continue;
1921
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001922 if (list_empty(fa_head))
Robert Olsson19baf832005-06-21 12:43:18 -07001923 continue;
1924
1925 if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001926 cb->args[3] = h;
Robert Olsson19baf832005-06-21 12:43:18 -07001927 return -1;
1928 }
1929 }
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001930 cb->args[3] = h;
Robert Olsson19baf832005-06-21 12:43:18 -07001931 return skb->len;
1932}
1933
1934static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb)
1935{
1936 int m, s_m;
1937 struct trie *t = (struct trie *) tb->tb_data;
1938
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001939 s_m = cb->args[2];
Robert Olsson19baf832005-06-21 12:43:18 -07001940
Robert Olsson2373ce12005-08-25 13:01:29 -07001941 rcu_read_lock();
Olof Johansson91b9a272005-08-09 20:24:39 -07001942 for (m = 0; m <= 32; m++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001943 if (m < s_m)
1944 continue;
1945 if (m > s_m)
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001946 memset(&cb->args[3], 0,
1947 sizeof(cb->args) - 3*sizeof(cb->args[0]));
Robert Olsson19baf832005-06-21 12:43:18 -07001948
1949 if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001950 cb->args[2] = m;
Robert Olsson19baf832005-06-21 12:43:18 -07001951 goto out;
1952 }
1953 }
Robert Olsson2373ce12005-08-25 13:01:29 -07001954 rcu_read_unlock();
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001955 cb->args[2] = m;
Robert Olsson19baf832005-06-21 12:43:18 -07001956 return skb->len;
Olof Johansson91b9a272005-08-09 20:24:39 -07001957out:
Robert Olsson2373ce12005-08-25 13:01:29 -07001958 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07001959 return -1;
1960}
1961
1962/* Fix more generic FIB names for init later */
1963
1964#ifdef CONFIG_IP_MULTIPLE_TABLES
Patrick McHardy2dfe55b2006-08-10 23:08:33 -07001965struct fib_table * fib_hash_init(u32 id)
Robert Olsson19baf832005-06-21 12:43:18 -07001966#else
Patrick McHardy2dfe55b2006-08-10 23:08:33 -07001967struct fib_table * __init fib_hash_init(u32 id)
Robert Olsson19baf832005-06-21 12:43:18 -07001968#endif
1969{
1970 struct fib_table *tb;
1971 struct trie *t;
1972
1973 if (fn_alias_kmem == NULL)
1974 fn_alias_kmem = kmem_cache_create("ip_fib_alias",
1975 sizeof(struct fib_alias),
1976 0, SLAB_HWCACHE_ALIGN,
Paul Mundt20c2df82007-07-20 10:11:58 +09001977 NULL);
Robert Olsson19baf832005-06-21 12:43:18 -07001978
1979 tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie),
1980 GFP_KERNEL);
1981 if (tb == NULL)
1982 return NULL;
1983
1984 tb->tb_id = id;
1985 tb->tb_lookup = fn_trie_lookup;
1986 tb->tb_insert = fn_trie_insert;
1987 tb->tb_delete = fn_trie_delete;
1988 tb->tb_flush = fn_trie_flush;
1989 tb->tb_select_default = fn_trie_select_default;
1990 tb->tb_dump = fn_trie_dump;
1991 memset(tb->tb_data, 0, sizeof(struct trie));
1992
1993 t = (struct trie *) tb->tb_data;
1994
1995 trie_init(t);
1996
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001997 if (id == RT_TABLE_LOCAL)
Olof Johansson91b9a272005-08-09 20:24:39 -07001998 trie_local = t;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001999 else if (id == RT_TABLE_MAIN)
Olof Johansson91b9a272005-08-09 20:24:39 -07002000 trie_main = t;
Robert Olsson19baf832005-06-21 12:43:18 -07002001
2002 if (id == RT_TABLE_LOCAL)
Stephen Hemminger78c66712005-09-21 00:15:39 -07002003 printk(KERN_INFO "IPv4 FIB: Using LC-trie version %s\n", VERSION);
Robert Olsson19baf832005-06-21 12:43:18 -07002004
2005 return tb;
2006}
2007
Robert Olsson19baf832005-06-21 12:43:18 -07002008#ifdef CONFIG_PROC_FS
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002009/* Depth first Trie walk iterator */
2010struct fib_trie_iter {
2011 struct tnode *tnode;
2012 struct trie *trie;
2013 unsigned index;
2014 unsigned depth;
2015};
Robert Olsson19baf832005-06-21 12:43:18 -07002016
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002017static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
Robert Olsson19baf832005-06-21 12:43:18 -07002018{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002019 struct tnode *tn = iter->tnode;
2020 unsigned cindex = iter->index;
2021 struct tnode *p;
2022
Eric W. Biederman6640e692007-01-24 14:42:04 -08002023 /* A single entry routing table */
2024 if (!tn)
2025 return NULL;
2026
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002027 pr_debug("get_next iter={node=%p index=%d depth=%d}\n",
2028 iter->tnode, iter->index, iter->depth);
2029rescan:
2030 while (cindex < (1<<tn->bits)) {
2031 struct node *n = tnode_get_child(tn, cindex);
2032
2033 if (n) {
2034 if (IS_LEAF(n)) {
2035 iter->tnode = tn;
2036 iter->index = cindex + 1;
2037 } else {
2038 /* push down one level */
2039 iter->tnode = (struct tnode *) n;
2040 iter->index = 0;
2041 ++iter->depth;
2042 }
2043 return n;
2044 }
2045
2046 ++cindex;
2047 }
2048
2049 /* Current node exhausted, pop back up */
Stephen Hemminger06801912007-08-10 15:22:13 -07002050 p = node_parent((struct node *)tn);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002051 if (p) {
2052 cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
2053 tn = p;
2054 --iter->depth;
2055 goto rescan;
2056 }
2057
2058 /* got root? */
Robert Olsson19baf832005-06-21 12:43:18 -07002059 return NULL;
2060}
2061
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002062static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
2063 struct trie *t)
Robert Olsson19baf832005-06-21 12:43:18 -07002064{
Robert Olsson5ddf0eb2006-03-20 21:34:12 -08002065 struct node *n ;
2066
Stephen Hemminger132adf52007-03-08 20:44:43 -08002067 if (!t)
Robert Olsson5ddf0eb2006-03-20 21:34:12 -08002068 return NULL;
2069
2070 n = rcu_dereference(t->trie);
2071
Stephen Hemminger132adf52007-03-08 20:44:43 -08002072 if (!iter)
Robert Olsson5ddf0eb2006-03-20 21:34:12 -08002073 return NULL;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002074
Eric W. Biederman6640e692007-01-24 14:42:04 -08002075 if (n) {
2076 if (IS_TNODE(n)) {
2077 iter->tnode = (struct tnode *) n;
2078 iter->trie = t;
2079 iter->index = 0;
2080 iter->depth = 1;
2081 } else {
2082 iter->tnode = NULL;
2083 iter->trie = t;
2084 iter->index = 0;
2085 iter->depth = 0;
2086 }
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002087 return n;
2088 }
Robert Olsson19baf832005-06-21 12:43:18 -07002089 return NULL;
2090}
2091
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002092static void trie_collect_stats(struct trie *t, struct trie_stat *s)
Robert Olsson19baf832005-06-21 12:43:18 -07002093{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002094 struct node *n;
2095 struct fib_trie_iter iter;
Robert Olsson19baf832005-06-21 12:43:18 -07002096
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002097 memset(s, 0, sizeof(*s));
Robert Olsson19baf832005-06-21 12:43:18 -07002098
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002099 rcu_read_lock();
2100 for (n = fib_trie_get_first(&iter, t); n;
2101 n = fib_trie_get_next(&iter)) {
2102 if (IS_LEAF(n)) {
2103 s->leaves++;
2104 s->totdepth += iter.depth;
2105 if (iter.depth > s->maxdepth)
2106 s->maxdepth = iter.depth;
2107 } else {
2108 const struct tnode *tn = (const struct tnode *) n;
2109 int i;
Robert Olsson19baf832005-06-21 12:43:18 -07002110
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002111 s->tnodes++;
Stephen Hemminger132adf52007-03-08 20:44:43 -08002112 if (tn->bits < MAX_STAT_DEPTH)
Robert Olsson06ef9212006-03-20 21:35:01 -08002113 s->nodesizes[tn->bits]++;
2114
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002115 for (i = 0; i < (1<<tn->bits); i++)
2116 if (!tn->child[i])
2117 s->nullpointers++;
2118 }
2119 }
2120 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07002121}
2122
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002123/*
Robert Olsson19baf832005-06-21 12:43:18 -07002124 * This outputs /proc/net/fib_triestats
Robert Olsson19baf832005-06-21 12:43:18 -07002125 */
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002126static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
Robert Olsson19baf832005-06-21 12:43:18 -07002127{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002128 unsigned i, max, pointers, bytes, avdepth;
Robert Olsson19baf832005-06-21 12:43:18 -07002129
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002130 if (stat->leaves)
2131 avdepth = stat->totdepth*100 / stat->leaves;
2132 else
2133 avdepth = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07002134
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002135 seq_printf(seq, "\tAver depth: %d.%02d\n", avdepth / 100, avdepth % 100 );
2136 seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth);
Robert Olsson19baf832005-06-21 12:43:18 -07002137
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002138 seq_printf(seq, "\tLeaves: %u\n", stat->leaves);
Olof Johansson91b9a272005-08-09 20:24:39 -07002139
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002140 bytes = sizeof(struct leaf) * stat->leaves;
2141 seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes);
2142 bytes += sizeof(struct tnode) * stat->tnodes;
Robert Olsson19baf832005-06-21 12:43:18 -07002143
Robert Olsson06ef9212006-03-20 21:35:01 -08002144 max = MAX_STAT_DEPTH;
2145 while (max > 0 && stat->nodesizes[max-1] == 0)
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002146 max--;
Robert Olsson19baf832005-06-21 12:43:18 -07002147
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002148 pointers = 0;
2149 for (i = 1; i <= max; i++)
2150 if (stat->nodesizes[i] != 0) {
2151 seq_printf(seq, " %d: %d", i, stat->nodesizes[i]);
2152 pointers += (1<<i) * stat->nodesizes[i];
2153 }
2154 seq_putc(seq, '\n');
2155 seq_printf(seq, "\tPointers: %d\n", pointers);
Robert Olsson19baf832005-06-21 12:43:18 -07002156
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002157 bytes += sizeof(struct node *) * pointers;
2158 seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers);
2159 seq_printf(seq, "Total size: %d kB\n", (bytes + 1023) / 1024);
Robert Olsson19baf832005-06-21 12:43:18 -07002160
2161#ifdef CONFIG_IP_FIB_TRIE_STATS
2162 seq_printf(seq, "Counters:\n---------\n");
2163 seq_printf(seq,"gets = %d\n", t->stats.gets);
2164 seq_printf(seq,"backtracks = %d\n", t->stats.backtrack);
2165 seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
2166 seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
2167 seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
Robert Olsson2f368952005-07-05 15:02:40 -07002168 seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);
Robert Olsson19baf832005-06-21 12:43:18 -07002169#ifdef CLEAR_STATS
2170 memset(&(t->stats), 0, sizeof(t->stats));
2171#endif
2172#endif /* CONFIG_IP_FIB_TRIE_STATS */
2173}
2174
2175static int fib_triestat_seq_show(struct seq_file *seq, void *v)
2176{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002177 struct trie_stat *stat;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002178
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002179 stat = kmalloc(sizeof(*stat), GFP_KERNEL);
2180 if (!stat)
2181 return -ENOMEM;
Robert Olsson19baf832005-06-21 12:43:18 -07002182
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002183 seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n",
2184 sizeof(struct leaf), sizeof(struct tnode));
Olof Johansson91b9a272005-08-09 20:24:39 -07002185
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002186 if (trie_local) {
2187 seq_printf(seq, "Local:\n");
2188 trie_collect_stats(trie_local, stat);
2189 trie_show_stats(seq, stat);
Robert Olsson19baf832005-06-21 12:43:18 -07002190 }
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002191
2192 if (trie_main) {
2193 seq_printf(seq, "Main:\n");
2194 trie_collect_stats(trie_main, stat);
2195 trie_show_stats(seq, stat);
2196 }
2197 kfree(stat);
2198
Robert Olsson19baf832005-06-21 12:43:18 -07002199 return 0;
2200}
2201
Robert Olsson19baf832005-06-21 12:43:18 -07002202static int fib_triestat_seq_open(struct inode *inode, struct file *file)
2203{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002204 return single_open(file, fib_triestat_seq_show, NULL);
Robert Olsson19baf832005-06-21 12:43:18 -07002205}
2206
Arjan van de Ven9a321442007-02-12 00:55:35 -08002207static const struct file_operations fib_triestat_fops = {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002208 .owner = THIS_MODULE,
2209 .open = fib_triestat_seq_open,
2210 .read = seq_read,
2211 .llseek = seq_lseek,
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002212 .release = single_release,
Robert Olsson19baf832005-06-21 12:43:18 -07002213};
2214
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002215static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
2216 loff_t pos)
Robert Olsson19baf832005-06-21 12:43:18 -07002217{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002218 loff_t idx = 0;
2219 struct node *n;
Robert Olsson19baf832005-06-21 12:43:18 -07002220
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002221 for (n = fib_trie_get_first(iter, trie_local);
2222 n; ++idx, n = fib_trie_get_next(iter)) {
2223 if (pos == idx)
2224 return n;
2225 }
Robert Olsson19baf832005-06-21 12:43:18 -07002226
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002227 for (n = fib_trie_get_first(iter, trie_main);
2228 n; ++idx, n = fib_trie_get_next(iter)) {
2229 if (pos == idx)
2230 return n;
2231 }
Robert Olsson19baf832005-06-21 12:43:18 -07002232 return NULL;
2233}
2234
2235static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
2236{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002237 rcu_read_lock();
2238 if (*pos == 0)
Olof Johansson91b9a272005-08-09 20:24:39 -07002239 return SEQ_START_TOKEN;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002240 return fib_trie_get_idx(seq->private, *pos - 1);
Robert Olsson19baf832005-06-21 12:43:18 -07002241}
2242
2243static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2244{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002245 struct fib_trie_iter *iter = seq->private;
2246 void *l = v;
2247
Robert Olsson19baf832005-06-21 12:43:18 -07002248 ++*pos;
Olof Johansson91b9a272005-08-09 20:24:39 -07002249 if (v == SEQ_START_TOKEN)
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002250 return fib_trie_get_idx(iter, 0);
Olof Johansson91b9a272005-08-09 20:24:39 -07002251
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002252 v = fib_trie_get_next(iter);
2253 BUG_ON(v == l);
2254 if (v)
2255 return v;
2256
2257 /* continue scan in next trie */
2258 if (iter->trie == trie_local)
2259 return fib_trie_get_first(iter, trie_main);
2260
2261 return NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07002262}
2263
2264static void fib_trie_seq_stop(struct seq_file *seq, void *v)
2265{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002266 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07002267}
2268
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002269static void seq_indent(struct seq_file *seq, int n)
2270{
2271 while (n-- > 0) seq_puts(seq, " ");
2272}
Robert Olsson19baf832005-06-21 12:43:18 -07002273
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002274static inline const char *rtn_scope(enum rt_scope_t s)
2275{
2276 static char buf[32];
2277
Stephen Hemminger132adf52007-03-08 20:44:43 -08002278 switch (s) {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002279 case RT_SCOPE_UNIVERSE: return "universe";
2280 case RT_SCOPE_SITE: return "site";
2281 case RT_SCOPE_LINK: return "link";
2282 case RT_SCOPE_HOST: return "host";
2283 case RT_SCOPE_NOWHERE: return "nowhere";
2284 default:
2285 snprintf(buf, sizeof(buf), "scope=%d", s);
2286 return buf;
2287 }
2288}
2289
2290static const char *rtn_type_names[__RTN_MAX] = {
2291 [RTN_UNSPEC] = "UNSPEC",
2292 [RTN_UNICAST] = "UNICAST",
2293 [RTN_LOCAL] = "LOCAL",
2294 [RTN_BROADCAST] = "BROADCAST",
2295 [RTN_ANYCAST] = "ANYCAST",
2296 [RTN_MULTICAST] = "MULTICAST",
2297 [RTN_BLACKHOLE] = "BLACKHOLE",
2298 [RTN_UNREACHABLE] = "UNREACHABLE",
2299 [RTN_PROHIBIT] = "PROHIBIT",
2300 [RTN_THROW] = "THROW",
2301 [RTN_NAT] = "NAT",
2302 [RTN_XRESOLVE] = "XRESOLVE",
2303};
2304
2305static inline const char *rtn_type(unsigned t)
2306{
2307 static char buf[32];
2308
2309 if (t < __RTN_MAX && rtn_type_names[t])
2310 return rtn_type_names[t];
2311 snprintf(buf, sizeof(buf), "type %d", t);
2312 return buf;
2313}
2314
2315/* Pretty print the trie */
Robert Olsson19baf832005-06-21 12:43:18 -07002316static int fib_trie_seq_show(struct seq_file *seq, void *v)
2317{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002318 const struct fib_trie_iter *iter = seq->private;
2319 struct node *n = v;
Robert Olsson19baf832005-06-21 12:43:18 -07002320
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002321 if (v == SEQ_START_TOKEN)
2322 return 0;
Robert Olsson19baf832005-06-21 12:43:18 -07002323
Stephen Hemminger06801912007-08-10 15:22:13 -07002324 if (!node_parent(n)) {
Robert Olsson095b8502007-01-26 19:06:01 -08002325 if (iter->trie == trie_local)
2326 seq_puts(seq, "<local>:\n");
2327 else
2328 seq_puts(seq, "<main>:\n");
2329 }
2330
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002331 if (IS_TNODE(n)) {
2332 struct tnode *tn = (struct tnode *) n;
Al Viro32ab5f82006-09-26 22:21:45 -07002333 __be32 prf = htonl(MASK_PFX(tn->key, tn->pos));
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002334
Robert Olsson1d25cd62005-09-19 15:29:52 -07002335 seq_indent(seq, iter->depth-1);
2336 seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n",
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002337 NIPQUAD(prf), tn->pos, tn->bits, tn->full_children,
Robert Olsson1d25cd62005-09-19 15:29:52 -07002338 tn->empty_children);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002339
Olof Johansson91b9a272005-08-09 20:24:39 -07002340 } else {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002341 struct leaf *l = (struct leaf *) n;
2342 int i;
Al Viro32ab5f82006-09-26 22:21:45 -07002343 __be32 val = htonl(l->key);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002344
2345 seq_indent(seq, iter->depth);
2346 seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));
2347 for (i = 32; i >= 0; i--) {
Robert Olsson772cb712005-09-19 15:31:18 -07002348 struct leaf_info *li = find_leaf_info(l, i);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002349 if (li) {
2350 struct fib_alias *fa;
2351 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
2352 seq_indent(seq, iter->depth+1);
2353 seq_printf(seq, " /%d %s %s", i,
2354 rtn_scope(fa->fa_scope),
2355 rtn_type(fa->fa_type));
2356 if (fa->fa_tos)
2357 seq_printf(seq, "tos =%d\n",
2358 fa->fa_tos);
2359 seq_putc(seq, '\n');
2360 }
2361 }
2362 }
Robert Olsson19baf832005-06-21 12:43:18 -07002363 }
2364
2365 return 0;
2366}
2367
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002368static const struct seq_operations fib_trie_seq_ops = {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002369 .start = fib_trie_seq_start,
2370 .next = fib_trie_seq_next,
2371 .stop = fib_trie_seq_stop,
2372 .show = fib_trie_seq_show,
Robert Olsson19baf832005-06-21 12:43:18 -07002373};
2374
2375static int fib_trie_seq_open(struct inode *inode, struct file *file)
2376{
2377 struct seq_file *seq;
2378 int rc = -ENOMEM;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002379 struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
2380
2381 if (!s)
2382 goto out;
Robert Olsson19baf832005-06-21 12:43:18 -07002383
2384 rc = seq_open(file, &fib_trie_seq_ops);
2385 if (rc)
2386 goto out_kfree;
2387
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002388 seq = file->private_data;
2389 seq->private = s;
2390 memset(s, 0, sizeof(*s));
Robert Olsson19baf832005-06-21 12:43:18 -07002391out:
2392 return rc;
2393out_kfree:
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002394 kfree(s);
Robert Olsson19baf832005-06-21 12:43:18 -07002395 goto out;
2396}
2397
Arjan van de Ven9a321442007-02-12 00:55:35 -08002398static const struct file_operations fib_trie_fops = {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002399 .owner = THIS_MODULE,
2400 .open = fib_trie_seq_open,
2401 .read = seq_read,
2402 .llseek = seq_lseek,
2403 .release = seq_release_private,
2404};
2405
Al Viro32ab5f82006-09-26 22:21:45 -07002406static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002407{
2408 static unsigned type2flags[RTN_MAX + 1] = {
2409 [7] = RTF_REJECT, [8] = RTF_REJECT,
2410 };
2411 unsigned flags = type2flags[type];
2412
2413 if (fi && fi->fib_nh->nh_gw)
2414 flags |= RTF_GATEWAY;
Al Viro32ab5f82006-09-26 22:21:45 -07002415 if (mask == htonl(0xFFFFFFFF))
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002416 flags |= RTF_HOST;
2417 flags |= RTF_UP;
2418 return flags;
2419}
2420
2421/*
2422 * This outputs /proc/net/route.
2423 * The format of the file is not supposed to be changed
2424 * and needs to be same as fib_hash output to avoid breaking
2425 * legacy utilities
2426 */
2427static int fib_route_seq_show(struct seq_file *seq, void *v)
2428{
Patrick McHardyc9e53cb2005-11-20 21:09:00 -08002429 const struct fib_trie_iter *iter = seq->private;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002430 struct leaf *l = v;
2431 int i;
2432 char bf[128];
2433
2434 if (v == SEQ_START_TOKEN) {
2435 seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "
2436 "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
2437 "\tWindow\tIRTT");
2438 return 0;
2439 }
2440
Patrick McHardyc9e53cb2005-11-20 21:09:00 -08002441 if (iter->trie == trie_local)
2442 return 0;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002443 if (IS_TNODE(l))
2444 return 0;
2445
2446 for (i=32; i>=0; i--) {
Robert Olsson772cb712005-09-19 15:31:18 -07002447 struct leaf_info *li = find_leaf_info(l, i);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002448 struct fib_alias *fa;
Al Viro32ab5f82006-09-26 22:21:45 -07002449 __be32 mask, prefix;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002450
2451 if (!li)
2452 continue;
2453
2454 mask = inet_make_mask(li->plen);
2455 prefix = htonl(l->key);
2456
2457 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
Herbert Xu1371e372005-10-15 09:42:39 +10002458 const struct fib_info *fi = fa->fa_info;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002459 unsigned flags = fib_flag_trans(fa->fa_type, mask, fi);
2460
2461 if (fa->fa_type == RTN_BROADCAST
2462 || fa->fa_type == RTN_MULTICAST)
2463 continue;
2464
2465 if (fi)
2466 snprintf(bf, sizeof(bf),
2467 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
2468 fi->fib_dev ? fi->fib_dev->name : "*",
2469 prefix,
2470 fi->fib_nh->nh_gw, flags, 0, 0,
2471 fi->fib_priority,
2472 mask,
2473 (fi->fib_advmss ? fi->fib_advmss + 40 : 0),
2474 fi->fib_window,
2475 fi->fib_rtt >> 3);
2476 else
2477 snprintf(bf, sizeof(bf),
2478 "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
2479 prefix, 0, flags, 0, 0, 0,
2480 mask, 0, 0, 0);
2481
2482 seq_printf(seq, "%-127s\n", bf);
2483 }
2484 }
2485
2486 return 0;
2487}
2488
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002489static const struct seq_operations fib_route_seq_ops = {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002490 .start = fib_trie_seq_start,
2491 .next = fib_trie_seq_next,
2492 .stop = fib_trie_seq_stop,
2493 .show = fib_route_seq_show,
2494};
2495
2496static int fib_route_seq_open(struct inode *inode, struct file *file)
2497{
2498 struct seq_file *seq;
2499 int rc = -ENOMEM;
2500 struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
2501
2502 if (!s)
2503 goto out;
2504
2505 rc = seq_open(file, &fib_route_seq_ops);
2506 if (rc)
2507 goto out_kfree;
2508
2509 seq = file->private_data;
2510 seq->private = s;
2511 memset(s, 0, sizeof(*s));
2512out:
2513 return rc;
2514out_kfree:
2515 kfree(s);
2516 goto out;
2517}
2518
Arjan van de Ven9a321442007-02-12 00:55:35 -08002519static const struct file_operations fib_route_fops = {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002520 .owner = THIS_MODULE,
2521 .open = fib_route_seq_open,
2522 .read = seq_read,
2523 .llseek = seq_lseek,
2524 .release = seq_release_private,
Robert Olsson19baf832005-06-21 12:43:18 -07002525};
2526
2527int __init fib_proc_init(void)
2528{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002529 if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_fops))
2530 goto out1;
2531
2532 if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_fops))
2533 goto out2;
2534
2535 if (!proc_net_fops_create("route", S_IRUGO, &fib_route_fops))
2536 goto out3;
2537
Robert Olsson19baf832005-06-21 12:43:18 -07002538 return 0;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002539
2540out3:
2541 proc_net_remove("fib_triestat");
2542out2:
2543 proc_net_remove("fib_trie");
2544out1:
2545 return -ENOMEM;
Robert Olsson19baf832005-06-21 12:43:18 -07002546}
2547
2548void __init fib_proc_exit(void)
2549{
2550 proc_net_remove("fib_trie");
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002551 proc_net_remove("fib_triestat");
2552 proc_net_remove("route");
Robert Olsson19baf832005-06-21 12:43:18 -07002553}
2554
2555#endif /* CONFIG_PROC_FS */