blob: 0179d245c81fdad9379e3f097a58aa3314d3edca [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>
Jiri Slaby1977f032007-10-18 23:40:25 -070057#include <linux/bitops.h>
Robert Olsson19baf832005-06-21 12:43:18 -070058#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>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020076#include <net/net_namespace.h>
Robert Olsson19baf832005-06-21 12:43:18 -070077#include <net/ip.h>
78#include <net/protocol.h>
79#include <net/route.h>
80#include <net/tcp.h>
81#include <net/sock.h>
82#include <net/ip_fib.h>
83#include "fib_lookup.h"
84
85#undef CONFIG_IP_FIB_TRIE_STATS
Robert Olsson06ef9212006-03-20 21:35:01 -080086#define MAX_STAT_DEPTH 32
Robert Olsson19baf832005-06-21 12:43:18 -070087
Robert Olsson19baf832005-06-21 12:43:18 -070088#define KEYLENGTH (8*sizeof(t_key))
Robert Olsson19baf832005-06-21 12:43:18 -070089
Robert Olsson19baf832005-06-21 12:43:18 -070090typedef unsigned int t_key;
91
92#define T_TNODE 0
93#define T_LEAF 1
94#define NODE_TYPE_MASK 0x1UL
Robert Olsson2373ce12005-08-25 13:01:29 -070095#define NODE_TYPE(node) ((node)->parent & NODE_TYPE_MASK)
96
Olof Johansson91b9a272005-08-09 20:24:39 -070097#define IS_TNODE(n) (!(n->parent & T_LEAF))
98#define IS_LEAF(n) (n->parent & T_LEAF)
Robert Olsson19baf832005-06-21 12:43:18 -070099
100struct node {
Olof Johansson91b9a272005-08-09 20:24:39 -0700101 t_key key;
102 unsigned long parent;
Robert Olsson19baf832005-06-21 12:43:18 -0700103};
104
105struct leaf {
Olof Johansson91b9a272005-08-09 20:24:39 -0700106 t_key key;
107 unsigned long parent;
Robert Olsson19baf832005-06-21 12:43:18 -0700108 struct hlist_head list;
Robert Olsson2373ce12005-08-25 13:01:29 -0700109 struct rcu_head rcu;
Robert Olsson19baf832005-06-21 12:43:18 -0700110};
111
112struct leaf_info {
113 struct hlist_node hlist;
Robert Olsson2373ce12005-08-25 13:01:29 -0700114 struct rcu_head rcu;
Robert Olsson19baf832005-06-21 12:43:18 -0700115 int plen;
116 struct list_head falh;
117};
118
119struct tnode {
Olof Johansson91b9a272005-08-09 20:24:39 -0700120 t_key key;
121 unsigned long parent;
122 unsigned short pos:5; /* 2log(KEYLENGTH) bits needed */
123 unsigned short bits:5; /* 2log(KEYLENGTH) bits needed */
124 unsigned short full_children; /* KEYLENGTH bits needed */
125 unsigned short empty_children; /* KEYLENGTH bits needed */
Robert Olsson2373ce12005-08-25 13:01:29 -0700126 struct rcu_head rcu;
Olof Johansson91b9a272005-08-09 20:24:39 -0700127 struct node *child[0];
Robert Olsson19baf832005-06-21 12:43:18 -0700128};
129
130#ifdef CONFIG_IP_FIB_TRIE_STATS
131struct trie_use_stats {
132 unsigned int gets;
133 unsigned int backtrack;
134 unsigned int semantic_match_passed;
135 unsigned int semantic_match_miss;
136 unsigned int null_node_hit;
Robert Olsson2f368952005-07-05 15:02:40 -0700137 unsigned int resize_node_skipped;
Robert Olsson19baf832005-06-21 12:43:18 -0700138};
139#endif
140
141struct trie_stat {
142 unsigned int totdepth;
143 unsigned int maxdepth;
144 unsigned int tnodes;
145 unsigned int leaves;
146 unsigned int nullpointers;
Robert Olsson06ef9212006-03-20 21:35:01 -0800147 unsigned int nodesizes[MAX_STAT_DEPTH];
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700148};
Robert Olsson19baf832005-06-21 12:43:18 -0700149
150struct trie {
Olof Johansson91b9a272005-08-09 20:24:39 -0700151 struct node *trie;
Robert Olsson19baf832005-06-21 12:43:18 -0700152#ifdef CONFIG_IP_FIB_TRIE_STATS
153 struct trie_use_stats stats;
154#endif
Olof Johansson91b9a272005-08-09 20:24:39 -0700155 int size;
Robert Olsson19baf832005-06-21 12:43:18 -0700156 unsigned int revision;
157};
158
Robert Olsson19baf832005-06-21 12:43:18 -0700159static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
160static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull);
Robert Olsson19baf832005-06-21 12:43:18 -0700161static struct node *resize(struct trie *t, struct tnode *tn);
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700162static struct tnode *inflate(struct trie *t, struct tnode *tn);
163static struct tnode *halve(struct trie *t, struct tnode *tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700164static void tnode_free(struct tnode *tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700165
Christoph Lametere18b8902006-12-06 20:33:20 -0800166static struct kmem_cache *fn_alias_kmem __read_mostly;
Robert Olsson19baf832005-06-21 12:43:18 -0700167
Stephen Hemminger06801912007-08-10 15:22:13 -0700168static inline struct tnode *node_parent(struct node *node)
169{
170 struct tnode *ret;
171
172 ret = (struct tnode *)(node->parent & ~NODE_TYPE_MASK);
173 return rcu_dereference(ret);
174}
175
176static inline void node_set_parent(struct node *node, struct tnode *ptr)
177{
178 rcu_assign_pointer(node->parent,
179 (unsigned long)ptr | NODE_TYPE(node));
180}
Robert Olsson2373ce12005-08-25 13:01:29 -0700181
182/* rcu_read_lock needs to be hold by caller from readside */
183
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700184static inline struct node *tnode_get_child(struct tnode *tn, int i)
Robert Olsson19baf832005-06-21 12:43:18 -0700185{
Olof Johansson91b9a272005-08-09 20:24:39 -0700186 BUG_ON(i >= 1 << tn->bits);
Robert Olsson19baf832005-06-21 12:43:18 -0700187
Robert Olsson2373ce12005-08-25 13:01:29 -0700188 return rcu_dereference(tn->child[i]);
Robert Olsson19baf832005-06-21 12:43:18 -0700189}
190
Stephen Hemmignerbb435b82005-08-09 20:25:39 -0700191static inline int tnode_child_length(const struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700192{
Olof Johansson91b9a272005-08-09 20:24:39 -0700193 return 1 << tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -0700194}
195
Stephen Hemmingerab66b4a2007-08-10 15:22:58 -0700196static inline t_key mask_pfx(t_key k, unsigned short l)
197{
198 return (l == 0) ? 0 : k >> (KEYLENGTH-l) << (KEYLENGTH-l);
199}
200
Robert Olsson19baf832005-06-21 12:43:18 -0700201static inline t_key tkey_extract_bits(t_key a, int offset, int bits)
202{
Olof Johansson91b9a272005-08-09 20:24:39 -0700203 if (offset < KEYLENGTH)
Robert Olsson19baf832005-06-21 12:43:18 -0700204 return ((t_key)(a << offset)) >> (KEYLENGTH - bits);
Olof Johansson91b9a272005-08-09 20:24:39 -0700205 else
Robert Olsson19baf832005-06-21 12:43:18 -0700206 return 0;
207}
208
209static inline int tkey_equals(t_key a, t_key b)
210{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700211 return a == b;
Robert Olsson19baf832005-06-21 12:43:18 -0700212}
213
214static inline int tkey_sub_equals(t_key a, int offset, int bits, t_key b)
215{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700216 if (bits == 0 || offset >= KEYLENGTH)
217 return 1;
Olof Johansson91b9a272005-08-09 20:24:39 -0700218 bits = bits > KEYLENGTH ? KEYLENGTH : bits;
219 return ((a ^ b) << offset) >> (KEYLENGTH - bits) == 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700220}
Robert Olsson19baf832005-06-21 12:43:18 -0700221
222static inline int tkey_mismatch(t_key a, int offset, t_key b)
223{
224 t_key diff = a ^ b;
225 int i = offset;
226
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700227 if (!diff)
228 return 0;
229 while ((diff << i) >> (KEYLENGTH-1) == 0)
Robert Olsson19baf832005-06-21 12:43:18 -0700230 i++;
231 return i;
232}
233
Robert Olsson19baf832005-06-21 12:43:18 -0700234/*
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900235 To understand this stuff, an understanding of keys and all their bits is
236 necessary. Every node in the trie has a key associated with it, but not
Robert Olsson19baf832005-06-21 12:43:18 -0700237 all of the bits in that key are significant.
238
239 Consider a node 'n' and its parent 'tp'.
240
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900241 If n is a leaf, every bit in its key is significant. Its presence is
242 necessitated by path compression, since during a tree traversal (when
243 searching for a leaf - unless we are doing an insertion) we will completely
244 ignore all skipped bits we encounter. Thus we need to verify, at the end of
245 a potentially successful search, that we have indeed been walking the
Robert Olsson19baf832005-06-21 12:43:18 -0700246 correct key path.
247
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900248 Note that we can never "miss" the correct key in the tree if present by
249 following the wrong path. Path compression ensures that segments of the key
250 that are the same for all keys with a given prefix are skipped, but the
251 skipped part *is* identical for each node in the subtrie below the skipped
252 bit! trie_insert() in this implementation takes care of that - note the
Robert Olsson19baf832005-06-21 12:43:18 -0700253 call to tkey_sub_equals() in trie_insert().
254
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900255 if n is an internal node - a 'tnode' here, the various parts of its key
Robert Olsson19baf832005-06-21 12:43:18 -0700256 have many different meanings.
257
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900258 Example:
Robert Olsson19baf832005-06-21 12:43:18 -0700259 _________________________________________________________________
260 | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C |
261 -----------------------------------------------------------------
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900262 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Robert Olsson19baf832005-06-21 12:43:18 -0700263
264 _________________________________________________________________
265 | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u |
266 -----------------------------------------------------------------
267 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
268
269 tp->pos = 7
270 tp->bits = 3
271 n->pos = 15
Olof Johansson91b9a272005-08-09 20:24:39 -0700272 n->bits = 4
Robert Olsson19baf832005-06-21 12:43:18 -0700273
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900274 First, let's just ignore the bits that come before the parent tp, that is
275 the bits from 0 to (tp->pos-1). They are *known* but at this point we do
Robert Olsson19baf832005-06-21 12:43:18 -0700276 not use them for anything.
277
278 The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900279 index into the parent's child array. That is, they will be used to find
Robert Olsson19baf832005-06-21 12:43:18 -0700280 'n' among tp's children.
281
282 The bits from (tp->pos + tp->bits) to (n->pos - 1) - "S" - are skipped bits
283 for the node n.
284
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900285 All the bits we have seen so far are significant to the node n. The rest
Robert Olsson19baf832005-06-21 12:43:18 -0700286 of the bits are really not needed or indeed known in n->key.
287
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900288 The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into
Robert Olsson19baf832005-06-21 12:43:18 -0700289 n's child array, and will of course be different for each child.
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900290
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700291
Robert Olsson19baf832005-06-21 12:43:18 -0700292 The rest of the bits, from (n->pos + n->bits) onward, are completely unknown
293 at this point.
294
295*/
296
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700297static inline void check_tnode(const struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700298{
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700299 WARN_ON(tn && tn->pos+tn->bits > 32);
Robert Olsson19baf832005-06-21 12:43:18 -0700300}
301
Denis V. Lunevf5026fa2007-12-13 09:47:57 -0800302static const int halve_threshold = 25;
303static const int inflate_threshold = 50;
304static const int halve_threshold_root = 8;
305static const int inflate_threshold_root = 15;
Robert Olsson19baf832005-06-21 12:43:18 -0700306
Robert Olsson2373ce12005-08-25 13:01:29 -0700307
308static void __alias_free_mem(struct rcu_head *head)
309{
310 struct fib_alias *fa = container_of(head, struct fib_alias, rcu);
311 kmem_cache_free(fn_alias_kmem, fa);
312}
313
314static inline void alias_free_mem_rcu(struct fib_alias *fa)
315{
316 call_rcu(&fa->rcu, __alias_free_mem);
317}
318
319static void __leaf_free_rcu(struct rcu_head *head)
320{
321 kfree(container_of(head, struct leaf, rcu));
322}
323
Robert Olsson2373ce12005-08-25 13:01:29 -0700324static void __leaf_info_free_rcu(struct rcu_head *head)
325{
326 kfree(container_of(head, struct leaf_info, rcu));
327}
328
329static inline void free_leaf_info(struct leaf_info *leaf)
330{
331 call_rcu(&leaf->rcu, __leaf_info_free_rcu);
332}
333
334static struct tnode *tnode_alloc(unsigned int size)
335{
336 struct page *pages;
337
338 if (size <= PAGE_SIZE)
339 return kcalloc(size, 1, GFP_KERNEL);
340
341 pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size));
342 if (!pages)
343 return NULL;
344
345 return page_address(pages);
346}
347
348static void __tnode_free_rcu(struct rcu_head *head)
349{
350 struct tnode *tn = container_of(head, struct tnode, rcu);
351 unsigned int size = sizeof(struct tnode) +
352 (1 << tn->bits) * sizeof(struct node *);
353
354 if (size <= PAGE_SIZE)
355 kfree(tn);
356 else
357 free_pages((unsigned long)tn, get_order(size));
358}
359
360static inline void tnode_free(struct tnode *tn)
361{
Stephen Hemminger132adf52007-03-08 20:44:43 -0800362 if (IS_LEAF(tn)) {
Robert Olsson550e29b2006-04-04 12:53:35 -0700363 struct leaf *l = (struct leaf *) tn;
364 call_rcu_bh(&l->rcu, __leaf_free_rcu);
Stephen Hemminger132adf52007-03-08 20:44:43 -0800365 } else
Robert Olsson550e29b2006-04-04 12:53:35 -0700366 call_rcu(&tn->rcu, __tnode_free_rcu);
Robert Olsson2373ce12005-08-25 13:01:29 -0700367}
368
Robert Olsson19baf832005-06-21 12:43:18 -0700369static struct leaf *leaf_new(void)
370{
371 struct leaf *l = kmalloc(sizeof(struct leaf), GFP_KERNEL);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700372 if (l) {
Robert Olsson2373ce12005-08-25 13:01:29 -0700373 l->parent = T_LEAF;
Robert Olsson19baf832005-06-21 12:43:18 -0700374 INIT_HLIST_HEAD(&l->list);
375 }
376 return l;
377}
378
379static struct leaf_info *leaf_info_new(int plen)
380{
381 struct leaf_info *li = kmalloc(sizeof(struct leaf_info), GFP_KERNEL);
Robert Olsson2373ce12005-08-25 13:01:29 -0700382 if (li) {
383 li->plen = plen;
384 INIT_LIST_HEAD(&li->falh);
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700385 }
Robert Olsson2373ce12005-08-25 13:01:29 -0700386 return li;
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700387}
388
Robert Olsson19baf832005-06-21 12:43:18 -0700389static struct tnode* tnode_new(t_key key, int pos, int bits)
390{
391 int nchildren = 1<<bits;
392 int sz = sizeof(struct tnode) + nchildren * sizeof(struct node *);
Patrick McHardyf0e36f82005-07-05 14:44:55 -0700393 struct tnode *tn = tnode_alloc(sz);
Robert Olsson19baf832005-06-21 12:43:18 -0700394
Olof Johansson91b9a272005-08-09 20:24:39 -0700395 if (tn) {
Robert Olsson19baf832005-06-21 12:43:18 -0700396 memset(tn, 0, sz);
Robert Olsson2373ce12005-08-25 13:01:29 -0700397 tn->parent = T_TNODE;
Robert Olsson19baf832005-06-21 12:43:18 -0700398 tn->pos = pos;
399 tn->bits = bits;
400 tn->key = key;
401 tn->full_children = 0;
402 tn->empty_children = 1<<bits;
403 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700404
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700405 pr_debug("AT %p s=%u %u\n", tn, (unsigned int) sizeof(struct tnode),
406 (unsigned int) (sizeof(struct node) * 1<<bits));
Robert Olsson19baf832005-06-21 12:43:18 -0700407 return tn;
408}
409
Robert Olsson19baf832005-06-21 12:43:18 -0700410/*
411 * Check whether a tnode 'n' is "full", i.e. it is an internal node
412 * and no bits are skipped. See discussion in dyntree paper p. 6
413 */
414
Stephen Hemmignerbb435b82005-08-09 20:25:39 -0700415static inline int tnode_full(const struct tnode *tn, const struct node *n)
Robert Olsson19baf832005-06-21 12:43:18 -0700416{
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700417 if (n == NULL || IS_LEAF(n))
Robert Olsson19baf832005-06-21 12:43:18 -0700418 return 0;
419
420 return ((struct tnode *) n)->pos == tn->pos + tn->bits;
421}
422
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700423static inline void put_child(struct trie *t, struct tnode *tn, int i, struct node *n)
Robert Olsson19baf832005-06-21 12:43:18 -0700424{
425 tnode_put_child_reorg(tn, i, n, -1);
426}
427
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700428 /*
Robert Olsson19baf832005-06-21 12:43:18 -0700429 * Add a child at position i overwriting the old value.
430 * Update the value of full_children and empty_children.
431 */
432
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700433static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700434{
Robert Olsson2373ce12005-08-25 13:01:29 -0700435 struct node *chi = tn->child[i];
Robert Olsson19baf832005-06-21 12:43:18 -0700436 int isfull;
437
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700438 BUG_ON(i >= 1<<tn->bits);
439
Robert Olsson19baf832005-06-21 12:43:18 -0700440
441 /* update emptyChildren */
442 if (n == NULL && chi != NULL)
443 tn->empty_children++;
444 else if (n != NULL && chi == NULL)
445 tn->empty_children--;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700446
Robert Olsson19baf832005-06-21 12:43:18 -0700447 /* update fullChildren */
Olof Johansson91b9a272005-08-09 20:24:39 -0700448 if (wasfull == -1)
Robert Olsson19baf832005-06-21 12:43:18 -0700449 wasfull = tnode_full(tn, chi);
450
451 isfull = tnode_full(tn, n);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700452 if (wasfull && !isfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700453 tn->full_children--;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700454 else if (!wasfull && isfull)
Robert Olsson19baf832005-06-21 12:43:18 -0700455 tn->full_children++;
Olof Johansson91b9a272005-08-09 20:24:39 -0700456
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700457 if (n)
Stephen Hemminger06801912007-08-10 15:22:13 -0700458 node_set_parent(n, tn);
Robert Olsson19baf832005-06-21 12:43:18 -0700459
Robert Olsson2373ce12005-08-25 13:01:29 -0700460 rcu_assign_pointer(tn->child[i], n);
Robert Olsson19baf832005-06-21 12:43:18 -0700461}
462
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700463static struct node *resize(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700464{
465 int i;
Robert Olsson2f368952005-07-05 15:02:40 -0700466 int err = 0;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700467 struct tnode *old_tn;
Robert Olssone6308be2005-10-04 13:01:58 -0700468 int inflate_threshold_use;
469 int halve_threshold_use;
Robert Olsson05eee482007-03-19 16:27:37 -0700470 int max_resize;
Robert Olsson19baf832005-06-21 12:43:18 -0700471
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900472 if (!tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700473 return NULL;
474
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700475 pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n",
476 tn, inflate_threshold, halve_threshold);
Robert Olsson19baf832005-06-21 12:43:18 -0700477
478 /* No children */
479 if (tn->empty_children == tnode_child_length(tn)) {
480 tnode_free(tn);
481 return NULL;
482 }
483 /* One child */
484 if (tn->empty_children == tnode_child_length(tn) - 1)
485 for (i = 0; i < tnode_child_length(tn); i++) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700486 struct node *n;
Robert Olsson19baf832005-06-21 12:43:18 -0700487
Olof Johansson91b9a272005-08-09 20:24:39 -0700488 n = tn->child[i];
Robert Olsson2373ce12005-08-25 13:01:29 -0700489 if (!n)
Olof Johansson91b9a272005-08-09 20:24:39 -0700490 continue;
Olof Johansson91b9a272005-08-09 20:24:39 -0700491
492 /* compress one level */
Stephen Hemminger06801912007-08-10 15:22:13 -0700493 node_set_parent(n, NULL);
Olof Johansson91b9a272005-08-09 20:24:39 -0700494 tnode_free(tn);
495 return n;
Robert Olsson19baf832005-06-21 12:43:18 -0700496 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700497 /*
Robert Olsson19baf832005-06-21 12:43:18 -0700498 * Double as long as the resulting node has a number of
499 * nonempty nodes that are above the threshold.
500 */
501
502 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700503 * From "Implementing a dynamic compressed trie" by Stefan Nilsson of
504 * the Helsinki University of Technology and Matti Tikkanen of Nokia
Robert Olsson19baf832005-06-21 12:43:18 -0700505 * Telecommunications, page 6:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700506 * "A node is doubled if the ratio of non-empty children to all
Robert Olsson19baf832005-06-21 12:43:18 -0700507 * children in the *doubled* node is at least 'high'."
508 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700509 * 'high' in this instance is the variable 'inflate_threshold'. It
510 * is expressed as a percentage, so we multiply it with
511 * tnode_child_length() and instead of multiplying by 2 (since the
512 * child array will be doubled by inflate()) and multiplying
513 * the left-hand side by 100 (to handle the percentage thing) we
Robert Olsson19baf832005-06-21 12:43:18 -0700514 * multiply the left-hand side by 50.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700515 *
516 * The left-hand side may look a bit weird: tnode_child_length(tn)
517 * - tn->empty_children is of course the number of non-null children
518 * in the current node. tn->full_children is the number of "full"
Robert Olsson19baf832005-06-21 12:43:18 -0700519 * children, that is non-null tnodes with a skip value of 0.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700520 * All of those will be doubled in the resulting inflated tnode, so
Robert Olsson19baf832005-06-21 12:43:18 -0700521 * we just count them one extra time here.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700522 *
Robert Olsson19baf832005-06-21 12:43:18 -0700523 * A clearer way to write this would be:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700524 *
Robert Olsson19baf832005-06-21 12:43:18 -0700525 * to_be_doubled = tn->full_children;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700526 * not_to_be_doubled = tnode_child_length(tn) - tn->empty_children -
Robert Olsson19baf832005-06-21 12:43:18 -0700527 * tn->full_children;
528 *
529 * new_child_length = tnode_child_length(tn) * 2;
530 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700531 * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) /
Robert Olsson19baf832005-06-21 12:43:18 -0700532 * new_child_length;
533 * if (new_fill_factor >= inflate_threshold)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700534 *
535 * ...and so on, tho it would mess up the while () loop.
536 *
Robert Olsson19baf832005-06-21 12:43:18 -0700537 * anyway,
538 * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >=
539 * inflate_threshold
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700540 *
Robert Olsson19baf832005-06-21 12:43:18 -0700541 * avoid a division:
542 * 100 * (not_to_be_doubled + 2*to_be_doubled) >=
543 * inflate_threshold * new_child_length
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700544 *
Robert Olsson19baf832005-06-21 12:43:18 -0700545 * expand not_to_be_doubled and to_be_doubled, and shorten:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700546 * 100 * (tnode_child_length(tn) - tn->empty_children +
Olof Johansson91b9a272005-08-09 20:24:39 -0700547 * tn->full_children) >= inflate_threshold * new_child_length
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700548 *
Robert Olsson19baf832005-06-21 12:43:18 -0700549 * expand new_child_length:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700550 * 100 * (tnode_child_length(tn) - tn->empty_children +
Olof Johansson91b9a272005-08-09 20:24:39 -0700551 * tn->full_children) >=
Robert Olsson19baf832005-06-21 12:43:18 -0700552 * inflate_threshold * tnode_child_length(tn) * 2
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700553 *
Robert Olsson19baf832005-06-21 12:43:18 -0700554 * shorten again:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700555 * 50 * (tn->full_children + tnode_child_length(tn) -
Olof Johansson91b9a272005-08-09 20:24:39 -0700556 * tn->empty_children) >= inflate_threshold *
Robert Olsson19baf832005-06-21 12:43:18 -0700557 * tnode_child_length(tn)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700558 *
Robert Olsson19baf832005-06-21 12:43:18 -0700559 */
560
561 check_tnode(tn);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700562
Robert Olssone6308be2005-10-04 13:01:58 -0700563 /* Keep root node larger */
564
Stephen Hemminger132adf52007-03-08 20:44:43 -0800565 if (!tn->parent)
Robert Olssone6308be2005-10-04 13:01:58 -0700566 inflate_threshold_use = inflate_threshold_root;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900567 else
Robert Olssone6308be2005-10-04 13:01:58 -0700568 inflate_threshold_use = inflate_threshold;
569
Robert Olsson2f368952005-07-05 15:02:40 -0700570 err = 0;
Robert Olsson05eee482007-03-19 16:27:37 -0700571 max_resize = 10;
572 while ((tn->full_children > 0 && max_resize-- &&
Robert Olsson19baf832005-06-21 12:43:18 -0700573 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
Robert Olssone6308be2005-10-04 13:01:58 -0700574 inflate_threshold_use * tnode_child_length(tn))) {
Robert Olsson19baf832005-06-21 12:43:18 -0700575
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700576 old_tn = tn;
577 tn = inflate(t, tn);
578 if (IS_ERR(tn)) {
579 tn = old_tn;
Robert Olsson2f368952005-07-05 15:02:40 -0700580#ifdef CONFIG_IP_FIB_TRIE_STATS
581 t->stats.resize_node_skipped++;
582#endif
583 break;
584 }
Robert Olsson19baf832005-06-21 12:43:18 -0700585 }
586
Robert Olsson05eee482007-03-19 16:27:37 -0700587 if (max_resize < 0) {
588 if (!tn->parent)
589 printk(KERN_WARNING "Fix inflate_threshold_root. Now=%d size=%d bits\n",
590 inflate_threshold_root, tn->bits);
591 else
592 printk(KERN_WARNING "Fix inflate_threshold. Now=%d size=%d bits\n",
593 inflate_threshold, tn->bits);
594 }
595
Robert Olsson19baf832005-06-21 12:43:18 -0700596 check_tnode(tn);
597
598 /*
599 * Halve as long as the number of empty children in this
600 * node is above threshold.
601 */
Robert Olsson2f368952005-07-05 15:02:40 -0700602
Robert Olssone6308be2005-10-04 13:01:58 -0700603
604 /* Keep root node larger */
605
Stephen Hemminger132adf52007-03-08 20:44:43 -0800606 if (!tn->parent)
Robert Olssone6308be2005-10-04 13:01:58 -0700607 halve_threshold_use = halve_threshold_root;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900608 else
Robert Olssone6308be2005-10-04 13:01:58 -0700609 halve_threshold_use = halve_threshold;
610
Robert Olsson2f368952005-07-05 15:02:40 -0700611 err = 0;
Robert Olsson05eee482007-03-19 16:27:37 -0700612 max_resize = 10;
613 while (tn->bits > 1 && max_resize-- &&
Robert Olsson19baf832005-06-21 12:43:18 -0700614 100 * (tnode_child_length(tn) - tn->empty_children) <
Robert Olssone6308be2005-10-04 13:01:58 -0700615 halve_threshold_use * tnode_child_length(tn)) {
Robert Olsson19baf832005-06-21 12:43:18 -0700616
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700617 old_tn = tn;
618 tn = halve(t, tn);
619 if (IS_ERR(tn)) {
620 tn = old_tn;
Robert Olsson2f368952005-07-05 15:02:40 -0700621#ifdef CONFIG_IP_FIB_TRIE_STATS
622 t->stats.resize_node_skipped++;
623#endif
624 break;
625 }
626 }
627
Robert Olsson05eee482007-03-19 16:27:37 -0700628 if (max_resize < 0) {
629 if (!tn->parent)
630 printk(KERN_WARNING "Fix halve_threshold_root. Now=%d size=%d bits\n",
631 halve_threshold_root, tn->bits);
632 else
633 printk(KERN_WARNING "Fix halve_threshold. Now=%d size=%d bits\n",
634 halve_threshold, tn->bits);
635 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700636
Robert Olsson19baf832005-06-21 12:43:18 -0700637 /* Only one child remains */
Robert Olsson19baf832005-06-21 12:43:18 -0700638 if (tn->empty_children == tnode_child_length(tn) - 1)
639 for (i = 0; i < tnode_child_length(tn); i++) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700640 struct node *n;
641
Olof Johansson91b9a272005-08-09 20:24:39 -0700642 n = tn->child[i];
Robert Olsson2373ce12005-08-25 13:01:29 -0700643 if (!n)
Olof Johansson91b9a272005-08-09 20:24:39 -0700644 continue;
Olof Johansson91b9a272005-08-09 20:24:39 -0700645
646 /* compress one level */
647
Stephen Hemminger06801912007-08-10 15:22:13 -0700648 node_set_parent(n, NULL);
Olof Johansson91b9a272005-08-09 20:24:39 -0700649 tnode_free(tn);
650 return n;
Robert Olsson19baf832005-06-21 12:43:18 -0700651 }
652
653 return (struct node *) tn;
654}
655
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700656static struct tnode *inflate(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700657{
658 struct tnode *inode;
659 struct tnode *oldtnode = tn;
660 int olen = tnode_child_length(tn);
661 int i;
662
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700663 pr_debug("In inflate\n");
Robert Olsson19baf832005-06-21 12:43:18 -0700664
665 tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
666
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700667 if (!tn)
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700668 return ERR_PTR(-ENOMEM);
Robert Olsson2f368952005-07-05 15:02:40 -0700669
670 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700671 * Preallocate and store tnodes before the actual work so we
672 * don't get into an inconsistent state if memory allocation
673 * fails. In case of failure we return the oldnode and inflate
Robert Olsson2f368952005-07-05 15:02:40 -0700674 * of tnode is ignored.
675 */
Olof Johansson91b9a272005-08-09 20:24:39 -0700676
677 for (i = 0; i < olen; i++) {
Robert Olsson2f368952005-07-05 15:02:40 -0700678 struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i);
679
680 if (inode &&
681 IS_TNODE(inode) &&
682 inode->pos == oldtnode->pos + oldtnode->bits &&
683 inode->bits > 1) {
684 struct tnode *left, *right;
Stephen Hemmingerab66b4a2007-08-10 15:22:58 -0700685 t_key m = ~0U << (KEYLENGTH - 1) >> inode->pos;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700686
Robert Olsson2f368952005-07-05 15:02:40 -0700687 left = tnode_new(inode->key&(~m), inode->pos + 1,
688 inode->bits - 1);
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700689 if (!left)
690 goto nomem;
Olof Johansson91b9a272005-08-09 20:24:39 -0700691
Robert Olsson2f368952005-07-05 15:02:40 -0700692 right = tnode_new(inode->key|m, inode->pos + 1,
693 inode->bits - 1);
694
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900695 if (!right) {
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700696 tnode_free(left);
697 goto nomem;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900698 }
Robert Olsson2f368952005-07-05 15:02:40 -0700699
700 put_child(t, tn, 2*i, (struct node *) left);
701 put_child(t, tn, 2*i+1, (struct node *) right);
702 }
703 }
704
Olof Johansson91b9a272005-08-09 20:24:39 -0700705 for (i = 0; i < olen; i++) {
Robert Olsson19baf832005-06-21 12:43:18 -0700706 struct node *node = tnode_get_child(oldtnode, i);
Olof Johansson91b9a272005-08-09 20:24:39 -0700707 struct tnode *left, *right;
708 int size, j;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700709
Robert Olsson19baf832005-06-21 12:43:18 -0700710 /* An empty child */
711 if (node == NULL)
712 continue;
713
714 /* A leaf or an internal node with skipped bits */
715
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700716 if (IS_LEAF(node) || ((struct tnode *) node)->pos >
Robert Olsson19baf832005-06-21 12:43:18 -0700717 tn->pos + tn->bits - 1) {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700718 if (tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits,
Robert Olsson19baf832005-06-21 12:43:18 -0700719 1) == 0)
720 put_child(t, tn, 2*i, node);
721 else
722 put_child(t, tn, 2*i+1, node);
723 continue;
724 }
725
726 /* An internal node with two children */
727 inode = (struct tnode *) node;
728
729 if (inode->bits == 1) {
730 put_child(t, tn, 2*i, inode->child[0]);
731 put_child(t, tn, 2*i+1, inode->child[1]);
732
733 tnode_free(inode);
Olof Johansson91b9a272005-08-09 20:24:39 -0700734 continue;
Robert Olsson19baf832005-06-21 12:43:18 -0700735 }
736
Olof Johansson91b9a272005-08-09 20:24:39 -0700737 /* An internal node with more than two children */
Robert Olsson19baf832005-06-21 12:43:18 -0700738
Olof Johansson91b9a272005-08-09 20:24:39 -0700739 /* We will replace this node 'inode' with two new
740 * ones, 'left' and 'right', each with half of the
741 * original children. The two new nodes will have
742 * a position one bit further down the key and this
743 * means that the "significant" part of their keys
744 * (see the discussion near the top of this file)
745 * will differ by one bit, which will be "0" in
746 * left's key and "1" in right's key. Since we are
747 * moving the key position by one step, the bit that
748 * we are moving away from - the bit at position
749 * (inode->pos) - is the one that will differ between
750 * left and right. So... we synthesize that bit in the
751 * two new keys.
752 * The mask 'm' below will be a single "one" bit at
753 * the position (inode->pos)
754 */
Robert Olsson19baf832005-06-21 12:43:18 -0700755
Olof Johansson91b9a272005-08-09 20:24:39 -0700756 /* Use the old key, but set the new significant
757 * bit to zero.
758 */
Robert Olsson19baf832005-06-21 12:43:18 -0700759
Olof Johansson91b9a272005-08-09 20:24:39 -0700760 left = (struct tnode *) tnode_get_child(tn, 2*i);
761 put_child(t, tn, 2*i, NULL);
Robert Olsson19baf832005-06-21 12:43:18 -0700762
Olof Johansson91b9a272005-08-09 20:24:39 -0700763 BUG_ON(!left);
Robert Olsson2f368952005-07-05 15:02:40 -0700764
Olof Johansson91b9a272005-08-09 20:24:39 -0700765 right = (struct tnode *) tnode_get_child(tn, 2*i+1);
766 put_child(t, tn, 2*i+1, NULL);
Robert Olsson2f368952005-07-05 15:02:40 -0700767
Olof Johansson91b9a272005-08-09 20:24:39 -0700768 BUG_ON(!right);
Robert Olsson2f368952005-07-05 15:02:40 -0700769
Olof Johansson91b9a272005-08-09 20:24:39 -0700770 size = tnode_child_length(left);
771 for (j = 0; j < size; j++) {
772 put_child(t, left, j, inode->child[j]);
773 put_child(t, right, j, inode->child[j + size]);
Robert Olsson19baf832005-06-21 12:43:18 -0700774 }
Olof Johansson91b9a272005-08-09 20:24:39 -0700775 put_child(t, tn, 2*i, resize(t, left));
776 put_child(t, tn, 2*i+1, resize(t, right));
777
778 tnode_free(inode);
Robert Olsson19baf832005-06-21 12:43:18 -0700779 }
780 tnode_free(oldtnode);
781 return tn;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700782nomem:
783 {
784 int size = tnode_child_length(tn);
785 int j;
786
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700787 for (j = 0; j < size; j++)
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700788 if (tn->child[j])
789 tnode_free((struct tnode *)tn->child[j]);
790
791 tnode_free(tn);
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700792
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700793 return ERR_PTR(-ENOMEM);
794 }
Robert Olsson19baf832005-06-21 12:43:18 -0700795}
796
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700797static struct tnode *halve(struct trie *t, struct tnode *tn)
Robert Olsson19baf832005-06-21 12:43:18 -0700798{
799 struct tnode *oldtnode = tn;
800 struct node *left, *right;
801 int i;
802 int olen = tnode_child_length(tn);
803
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700804 pr_debug("In halve\n");
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700805
806 tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
Robert Olsson19baf832005-06-21 12:43:18 -0700807
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700808 if (!tn)
809 return ERR_PTR(-ENOMEM);
Robert Olsson2f368952005-07-05 15:02:40 -0700810
811 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700812 * Preallocate and store tnodes before the actual work so we
813 * don't get into an inconsistent state if memory allocation
814 * fails. In case of failure we return the oldnode and halve
Robert Olsson2f368952005-07-05 15:02:40 -0700815 * of tnode is ignored.
816 */
817
Olof Johansson91b9a272005-08-09 20:24:39 -0700818 for (i = 0; i < olen; i += 2) {
Robert Olsson2f368952005-07-05 15:02:40 -0700819 left = tnode_get_child(oldtnode, i);
820 right = tnode_get_child(oldtnode, i+1);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700821
Robert Olsson2f368952005-07-05 15:02:40 -0700822 /* Two nonempty children */
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700823 if (left && right) {
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700824 struct tnode *newn;
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700825
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700826 newn = tnode_new(left->key, tn->pos + tn->bits, 1);
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700827
828 if (!newn)
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700829 goto nomem;
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700830
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700831 put_child(t, tn, i/2, (struct node *)newn);
Robert Olsson2f368952005-07-05 15:02:40 -0700832 }
Robert Olsson2f368952005-07-05 15:02:40 -0700833
Robert Olsson2f368952005-07-05 15:02:40 -0700834 }
Robert Olsson19baf832005-06-21 12:43:18 -0700835
Olof Johansson91b9a272005-08-09 20:24:39 -0700836 for (i = 0; i < olen; i += 2) {
837 struct tnode *newBinNode;
838
Robert Olsson19baf832005-06-21 12:43:18 -0700839 left = tnode_get_child(oldtnode, i);
840 right = tnode_get_child(oldtnode, i+1);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700841
Robert Olsson19baf832005-06-21 12:43:18 -0700842 /* At least one of the children is empty */
843 if (left == NULL) {
844 if (right == NULL) /* Both are empty */
845 continue;
846 put_child(t, tn, i/2, right);
Olof Johansson91b9a272005-08-09 20:24:39 -0700847 continue;
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700848 }
Olof Johansson91b9a272005-08-09 20:24:39 -0700849
850 if (right == NULL) {
Robert Olsson19baf832005-06-21 12:43:18 -0700851 put_child(t, tn, i/2, left);
Olof Johansson91b9a272005-08-09 20:24:39 -0700852 continue;
853 }
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700854
Robert Olsson19baf832005-06-21 12:43:18 -0700855 /* Two nonempty children */
Olof Johansson91b9a272005-08-09 20:24:39 -0700856 newBinNode = (struct tnode *) tnode_get_child(tn, i/2);
857 put_child(t, tn, i/2, NULL);
Olof Johansson91b9a272005-08-09 20:24:39 -0700858 put_child(t, newBinNode, 0, left);
859 put_child(t, newBinNode, 1, right);
860 put_child(t, tn, i/2, resize(t, newBinNode));
Robert Olsson19baf832005-06-21 12:43:18 -0700861 }
862 tnode_free(oldtnode);
863 return tn;
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700864nomem:
865 {
866 int size = tnode_child_length(tn);
867 int j;
868
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700869 for (j = 0; j < size; j++)
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700870 if (tn->child[j])
871 tnode_free((struct tnode *)tn->child[j]);
872
873 tnode_free(tn);
Stephen Hemminger0c7770c2005-08-23 21:59:41 -0700874
Robert Olsson2f80b3c2005-08-09 20:25:06 -0700875 return ERR_PTR(-ENOMEM);
876 }
Robert Olsson19baf832005-06-21 12:43:18 -0700877}
878
Robert Olsson772cb712005-09-19 15:31:18 -0700879/* readside must use rcu_read_lock currently dump routines
Robert Olsson2373ce12005-08-25 13:01:29 -0700880 via get_fa_head and dump */
881
Robert Olsson772cb712005-09-19 15:31:18 -0700882static struct leaf_info *find_leaf_info(struct leaf *l, int plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700883{
Robert Olsson772cb712005-09-19 15:31:18 -0700884 struct hlist_head *head = &l->list;
Robert Olsson19baf832005-06-21 12:43:18 -0700885 struct hlist_node *node;
886 struct leaf_info *li;
887
Robert Olsson2373ce12005-08-25 13:01:29 -0700888 hlist_for_each_entry_rcu(li, node, head, hlist)
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700889 if (li->plen == plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700890 return li;
Olof Johansson91b9a272005-08-09 20:24:39 -0700891
Robert Olsson19baf832005-06-21 12:43:18 -0700892 return NULL;
893}
894
895static inline struct list_head * get_fa_head(struct leaf *l, int plen)
896{
Robert Olsson772cb712005-09-19 15:31:18 -0700897 struct leaf_info *li = find_leaf_info(l, plen);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700898
Olof Johansson91b9a272005-08-09 20:24:39 -0700899 if (!li)
900 return NULL;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700901
Olof Johansson91b9a272005-08-09 20:24:39 -0700902 return &li->falh;
Robert Olsson19baf832005-06-21 12:43:18 -0700903}
904
905static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new)
906{
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900907 struct leaf_info *li = NULL, *last = NULL;
908 struct hlist_node *node;
Robert Olsson19baf832005-06-21 12:43:18 -0700909
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900910 if (hlist_empty(head)) {
911 hlist_add_head_rcu(&new->hlist, head);
912 } else {
913 hlist_for_each_entry(li, node, head, hlist) {
914 if (new->plen > li->plen)
915 break;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700916
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +0900917 last = li;
918 }
919 if (last)
920 hlist_add_after_rcu(&last->hlist, &new->hlist);
921 else
922 hlist_add_before_rcu(&new->hlist, &li->hlist);
923 }
Robert Olsson19baf832005-06-21 12:43:18 -0700924}
925
Robert Olsson2373ce12005-08-25 13:01:29 -0700926/* rcu_read_lock needs to be hold by caller from readside */
927
Robert Olsson19baf832005-06-21 12:43:18 -0700928static struct leaf *
929fib_find_node(struct trie *t, u32 key)
930{
931 int pos;
932 struct tnode *tn;
933 struct node *n;
934
935 pos = 0;
Robert Olsson2373ce12005-08-25 13:01:29 -0700936 n = rcu_dereference(t->trie);
Robert Olsson19baf832005-06-21 12:43:18 -0700937
938 while (n != NULL && NODE_TYPE(n) == T_TNODE) {
939 tn = (struct tnode *) n;
Olof Johansson91b9a272005-08-09 20:24:39 -0700940
Robert Olsson19baf832005-06-21 12:43:18 -0700941 check_tnode(tn);
Olof Johansson91b9a272005-08-09 20:24:39 -0700942
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700943 if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
Olof Johansson91b9a272005-08-09 20:24:39 -0700944 pos = tn->pos + tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -0700945 n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
Olof Johansson91b9a272005-08-09 20:24:39 -0700946 } else
Robert Olsson19baf832005-06-21 12:43:18 -0700947 break;
948 }
949 /* Case we have found a leaf. Compare prefixes */
950
Olof Johansson91b9a272005-08-09 20:24:39 -0700951 if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key))
952 return (struct leaf *)n;
953
Robert Olsson19baf832005-06-21 12:43:18 -0700954 return NULL;
955}
956
957static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
958{
Robert Olsson19baf832005-06-21 12:43:18 -0700959 int wasfull;
Stephen Hemminger06801912007-08-10 15:22:13 -0700960 t_key cindex, key = tn->key;
961 struct tnode *tp;
Robert Olsson19baf832005-06-21 12:43:18 -0700962
Stephen Hemminger06801912007-08-10 15:22:13 -0700963 while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) {
Robert Olsson19baf832005-06-21 12:43:18 -0700964 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
965 wasfull = tnode_full(tp, tnode_get_child(tp, cindex));
966 tn = (struct tnode *) resize (t, (struct tnode *)tn);
967 tnode_put_child_reorg((struct tnode *)tp, cindex,(struct node*)tn, wasfull);
Olof Johansson91b9a272005-08-09 20:24:39 -0700968
Stephen Hemminger06801912007-08-10 15:22:13 -0700969 tp = node_parent((struct node *) tn);
970 if (!tp)
Robert Olsson19baf832005-06-21 12:43:18 -0700971 break;
Stephen Hemminger06801912007-08-10 15:22:13 -0700972 tn = tp;
Robert Olsson19baf832005-06-21 12:43:18 -0700973 }
Stephen Hemminger06801912007-08-10 15:22:13 -0700974
Robert Olsson19baf832005-06-21 12:43:18 -0700975 /* Handle last (top) tnode */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700976 if (IS_TNODE(tn))
Robert Olsson19baf832005-06-21 12:43:18 -0700977 tn = (struct tnode*) resize(t, (struct tnode *)tn);
978
979 return (struct node*) tn;
980}
981
Robert Olsson2373ce12005-08-25 13:01:29 -0700982/* only used from updater-side */
983
Robert Olssonf835e472005-06-28 15:00:39 -0700984static struct list_head *
985fib_insert_node(struct trie *t, int *err, u32 key, int plen)
Robert Olsson19baf832005-06-21 12:43:18 -0700986{
987 int pos, newpos;
988 struct tnode *tp = NULL, *tn = NULL;
989 struct node *n;
990 struct leaf *l;
991 int missbit;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700992 struct list_head *fa_head = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -0700993 struct leaf_info *li;
994 t_key cindex;
995
996 pos = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700997 n = t->trie;
Robert Olsson19baf832005-06-21 12:43:18 -0700998
Stephen Hemmingerc877efb2005-07-19 14:01:51 -0700999 /* If we point to NULL, stop. Either the tree is empty and we should
1000 * just put a new leaf in if, or we have reached an empty child slot,
Robert Olsson19baf832005-06-21 12:43:18 -07001001 * and we should just put our new leaf in that.
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001002 * If we point to a T_TNODE, check if it matches our key. Note that
1003 * a T_TNODE might be skipping any number of bits - its 'pos' need
Robert Olsson19baf832005-06-21 12:43:18 -07001004 * not be the parent's 'pos'+'bits'!
1005 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001006 * If it does match the current key, get pos/bits from it, extract
Robert Olsson19baf832005-06-21 12:43:18 -07001007 * the index from our key, push the T_TNODE and walk the tree.
1008 *
1009 * If it doesn't, we have to replace it with a new T_TNODE.
1010 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001011 * If we point to a T_LEAF, it might or might not have the same key
1012 * as we do. If it does, just change the value, update the T_LEAF's
1013 * value, and return it.
Robert Olsson19baf832005-06-21 12:43:18 -07001014 * If it doesn't, we need to replace it with a T_TNODE.
1015 */
1016
1017 while (n != NULL && NODE_TYPE(n) == T_TNODE) {
1018 tn = (struct tnode *) n;
Olof Johansson91b9a272005-08-09 20:24:39 -07001019
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001020 check_tnode(tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001021
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001022 if (tkey_sub_equals(tn->key, pos, tn->pos-pos, key)) {
Robert Olsson19baf832005-06-21 12:43:18 -07001023 tp = tn;
Olof Johansson91b9a272005-08-09 20:24:39 -07001024 pos = tn->pos + tn->bits;
Robert Olsson19baf832005-06-21 12:43:18 -07001025 n = tnode_get_child(tn, tkey_extract_bits(key, tn->pos, tn->bits));
1026
Stephen Hemminger06801912007-08-10 15:22:13 -07001027 BUG_ON(n && node_parent(n) != tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001028 } else
Robert Olsson19baf832005-06-21 12:43:18 -07001029 break;
1030 }
1031
1032 /*
1033 * n ----> NULL, LEAF or TNODE
1034 *
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001035 * tp is n's (parent) ----> NULL or TNODE
Robert Olsson19baf832005-06-21 12:43:18 -07001036 */
1037
Olof Johansson91b9a272005-08-09 20:24:39 -07001038 BUG_ON(tp && IS_LEAF(tp));
Robert Olsson19baf832005-06-21 12:43:18 -07001039
1040 /* Case 1: n is a leaf. Compare prefixes */
1041
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001042 if (n != NULL && IS_LEAF(n) && tkey_equals(key, n->key)) {
Olof Johansson91b9a272005-08-09 20:24:39 -07001043 struct leaf *l = (struct leaf *) n;
1044
Robert Olsson19baf832005-06-21 12:43:18 -07001045 li = leaf_info_new(plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001046
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001047 if (!li) {
Robert Olssonf835e472005-06-28 15:00:39 -07001048 *err = -ENOMEM;
1049 goto err;
1050 }
Robert Olsson19baf832005-06-21 12:43:18 -07001051
1052 fa_head = &li->falh;
1053 insert_leaf_info(&l->list, li);
1054 goto done;
1055 }
1056 t->size++;
1057 l = leaf_new();
1058
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001059 if (!l) {
Robert Olssonf835e472005-06-28 15:00:39 -07001060 *err = -ENOMEM;
1061 goto err;
1062 }
Robert Olsson19baf832005-06-21 12:43:18 -07001063
1064 l->key = key;
1065 li = leaf_info_new(plen);
1066
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001067 if (!li) {
Robert Olssonf835e472005-06-28 15:00:39 -07001068 tnode_free((struct tnode *) l);
1069 *err = -ENOMEM;
1070 goto err;
1071 }
Robert Olsson19baf832005-06-21 12:43:18 -07001072
1073 fa_head = &li->falh;
1074 insert_leaf_info(&l->list, li);
1075
Robert Olsson19baf832005-06-21 12:43:18 -07001076 if (t->trie && n == NULL) {
Olof Johansson91b9a272005-08-09 20:24:39 -07001077 /* Case 2: n is NULL, and will just insert a new leaf */
Robert Olsson19baf832005-06-21 12:43:18 -07001078
Stephen Hemminger06801912007-08-10 15:22:13 -07001079 node_set_parent((struct node *)l, tp);
Robert Olsson19baf832005-06-21 12:43:18 -07001080
Olof Johansson91b9a272005-08-09 20:24:39 -07001081 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1082 put_child(t, (struct tnode *)tp, cindex, (struct node *)l);
1083 } else {
1084 /* Case 3: n is a LEAF or a TNODE and the key doesn't match. */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001085 /*
1086 * Add a new tnode here
Robert Olsson19baf832005-06-21 12:43:18 -07001087 * first tnode need some special handling
1088 */
1089
1090 if (tp)
Olof Johansson91b9a272005-08-09 20:24:39 -07001091 pos = tp->pos+tp->bits;
Robert Olsson19baf832005-06-21 12:43:18 -07001092 else
Olof Johansson91b9a272005-08-09 20:24:39 -07001093 pos = 0;
1094
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001095 if (n) {
Robert Olsson19baf832005-06-21 12:43:18 -07001096 newpos = tkey_mismatch(key, pos, n->key);
1097 tn = tnode_new(n->key, newpos, 1);
Olof Johansson91b9a272005-08-09 20:24:39 -07001098 } else {
Robert Olsson19baf832005-06-21 12:43:18 -07001099 newpos = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001100 tn = tnode_new(key, newpos, 1); /* First tnode */
Robert Olsson19baf832005-06-21 12:43:18 -07001101 }
Robert Olsson19baf832005-06-21 12:43:18 -07001102
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001103 if (!tn) {
Robert Olssonf835e472005-06-28 15:00:39 -07001104 free_leaf_info(li);
1105 tnode_free((struct tnode *) l);
1106 *err = -ENOMEM;
1107 goto err;
Olof Johansson91b9a272005-08-09 20:24:39 -07001108 }
1109
Stephen Hemminger06801912007-08-10 15:22:13 -07001110 node_set_parent((struct node *)tn, tp);
Robert Olsson19baf832005-06-21 12:43:18 -07001111
Olof Johansson91b9a272005-08-09 20:24:39 -07001112 missbit = tkey_extract_bits(key, newpos, 1);
Robert Olsson19baf832005-06-21 12:43:18 -07001113 put_child(t, tn, missbit, (struct node *)l);
1114 put_child(t, tn, 1-missbit, n);
1115
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001116 if (tp) {
Robert Olsson19baf832005-06-21 12:43:18 -07001117 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1118 put_child(t, (struct tnode *)tp, cindex, (struct node *)tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001119 } else {
Robert Olsson2373ce12005-08-25 13:01:29 -07001120 rcu_assign_pointer(t->trie, (struct node *)tn); /* First tnode */
Robert Olsson19baf832005-06-21 12:43:18 -07001121 tp = tn;
1122 }
1123 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001124
1125 if (tp && tp->pos + tp->bits > 32)
Stephen Hemminger78c66712005-09-21 00:15:39 -07001126 printk(KERN_WARNING "fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n",
Robert Olsson19baf832005-06-21 12:43:18 -07001127 tp, tp->pos, tp->bits, key, plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001128
Robert Olsson19baf832005-06-21 12:43:18 -07001129 /* Rebalance the trie */
Robert Olsson2373ce12005-08-25 13:01:29 -07001130
1131 rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
Robert Olssonf835e472005-06-28 15:00:39 -07001132done:
1133 t->revision++;
Olof Johansson91b9a272005-08-09 20:24:39 -07001134err:
Robert Olsson19baf832005-06-21 12:43:18 -07001135 return fa_head;
1136}
1137
Robert Olssond562f1f2007-03-26 14:22:22 -07001138/*
1139 * Caller must hold RTNL.
1140 */
Thomas Graf4e902c52006-08-17 18:14:52 -07001141static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
Robert Olsson19baf832005-06-21 12:43:18 -07001142{
1143 struct trie *t = (struct trie *) tb->tb_data;
1144 struct fib_alias *fa, *new_fa;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001145 struct list_head *fa_head = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001146 struct fib_info *fi;
Thomas Graf4e902c52006-08-17 18:14:52 -07001147 int plen = cfg->fc_dst_len;
1148 u8 tos = cfg->fc_tos;
Robert Olsson19baf832005-06-21 12:43:18 -07001149 u32 key, mask;
1150 int err;
1151 struct leaf *l;
1152
1153 if (plen > 32)
1154 return -EINVAL;
1155
Thomas Graf4e902c52006-08-17 18:14:52 -07001156 key = ntohl(cfg->fc_dst);
Robert Olsson19baf832005-06-21 12:43:18 -07001157
Patrick McHardy2dfe55b2006-08-10 23:08:33 -07001158 pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen);
Robert Olsson19baf832005-06-21 12:43:18 -07001159
Olof Johansson91b9a272005-08-09 20:24:39 -07001160 mask = ntohl(inet_make_mask(plen));
Robert Olsson19baf832005-06-21 12:43:18 -07001161
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001162 if (key & ~mask)
Robert Olsson19baf832005-06-21 12:43:18 -07001163 return -EINVAL;
1164
1165 key = key & mask;
1166
Thomas Graf4e902c52006-08-17 18:14:52 -07001167 fi = fib_create_info(cfg);
1168 if (IS_ERR(fi)) {
1169 err = PTR_ERR(fi);
Robert Olsson19baf832005-06-21 12:43:18 -07001170 goto err;
Thomas Graf4e902c52006-08-17 18:14:52 -07001171 }
Robert Olsson19baf832005-06-21 12:43:18 -07001172
1173 l = fib_find_node(t, key);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001174 fa = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001175
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001176 if (l) {
Robert Olsson19baf832005-06-21 12:43:18 -07001177 fa_head = get_fa_head(l, plen);
1178 fa = fib_find_alias(fa_head, tos, fi->fib_priority);
1179 }
1180
1181 /* Now fa, if non-NULL, points to the first fib alias
1182 * with the same keys [prefix,tos,priority], if such key already
1183 * exists or to the node before which we will insert new one.
1184 *
1185 * If fa is NULL, we will need to allocate a new one and
1186 * insert to the head of f.
1187 *
1188 * If f is NULL, no fib node matched the destination key
1189 * and we need to allocate a new one of those as well.
1190 */
1191
Olof Johansson91b9a272005-08-09 20:24:39 -07001192 if (fa && fa->fa_info->fib_priority == fi->fib_priority) {
Robert Olsson19baf832005-06-21 12:43:18 -07001193 struct fib_alias *fa_orig;
1194
1195 err = -EEXIST;
Thomas Graf4e902c52006-08-17 18:14:52 -07001196 if (cfg->fc_nlflags & NLM_F_EXCL)
Robert Olsson19baf832005-06-21 12:43:18 -07001197 goto out;
1198
Thomas Graf4e902c52006-08-17 18:14:52 -07001199 if (cfg->fc_nlflags & NLM_F_REPLACE) {
Robert Olsson19baf832005-06-21 12:43:18 -07001200 struct fib_info *fi_drop;
1201 u8 state;
1202
Joonwoo Park67250332008-01-18 03:45:18 -08001203 if (fi->fib_treeref > 1)
1204 goto out;
1205
Robert Olsson2373ce12005-08-25 13:01:29 -07001206 err = -ENOBUFS;
Christoph Lametere94b1762006-12-06 20:33:17 -08001207 new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
Robert Olsson2373ce12005-08-25 13:01:29 -07001208 if (new_fa == NULL)
1209 goto out;
Robert Olsson19baf832005-06-21 12:43:18 -07001210
1211 fi_drop = fa->fa_info;
Robert Olsson2373ce12005-08-25 13:01:29 -07001212 new_fa->fa_tos = fa->fa_tos;
1213 new_fa->fa_info = fi;
Thomas Graf4e902c52006-08-17 18:14:52 -07001214 new_fa->fa_type = cfg->fc_type;
1215 new_fa->fa_scope = cfg->fc_scope;
Robert Olsson19baf832005-06-21 12:43:18 -07001216 state = fa->fa_state;
Robert Olsson2373ce12005-08-25 13:01:29 -07001217 new_fa->fa_state &= ~FA_S_ACCESSED;
Robert Olsson19baf832005-06-21 12:43:18 -07001218
Robert Olsson2373ce12005-08-25 13:01:29 -07001219 list_replace_rcu(&fa->fa_list, &new_fa->fa_list);
1220 alias_free_mem_rcu(fa);
Robert Olsson19baf832005-06-21 12:43:18 -07001221
1222 fib_release_info(fi_drop);
1223 if (state & FA_S_ACCESSED)
Olof Johansson91b9a272005-08-09 20:24:39 -07001224 rt_cache_flush(-1);
Milan Kocianb8f55832007-05-23 14:55:06 -07001225 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen,
1226 tb->tb_id, &cfg->fc_nlinfo, NLM_F_REPLACE);
Robert Olsson19baf832005-06-21 12:43:18 -07001227
Olof Johansson91b9a272005-08-09 20:24:39 -07001228 goto succeeded;
Robert Olsson19baf832005-06-21 12:43:18 -07001229 }
1230 /* Error if we find a perfect match which
1231 * uses the same scope, type, and nexthop
1232 * information.
1233 */
1234 fa_orig = fa;
1235 list_for_each_entry(fa, fa_orig->fa_list.prev, fa_list) {
1236 if (fa->fa_tos != tos)
1237 break;
1238 if (fa->fa_info->fib_priority != fi->fib_priority)
1239 break;
Thomas Graf4e902c52006-08-17 18:14:52 -07001240 if (fa->fa_type == cfg->fc_type &&
1241 fa->fa_scope == cfg->fc_scope &&
Robert Olsson19baf832005-06-21 12:43:18 -07001242 fa->fa_info == fi) {
1243 goto out;
1244 }
1245 }
Thomas Graf4e902c52006-08-17 18:14:52 -07001246 if (!(cfg->fc_nlflags & NLM_F_APPEND))
Robert Olsson19baf832005-06-21 12:43:18 -07001247 fa = fa_orig;
1248 }
1249 err = -ENOENT;
Thomas Graf4e902c52006-08-17 18:14:52 -07001250 if (!(cfg->fc_nlflags & NLM_F_CREATE))
Robert Olsson19baf832005-06-21 12:43:18 -07001251 goto out;
1252
1253 err = -ENOBUFS;
Christoph Lametere94b1762006-12-06 20:33:17 -08001254 new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL);
Robert Olsson19baf832005-06-21 12:43:18 -07001255 if (new_fa == NULL)
1256 goto out;
1257
1258 new_fa->fa_info = fi;
1259 new_fa->fa_tos = tos;
Thomas Graf4e902c52006-08-17 18:14:52 -07001260 new_fa->fa_type = cfg->fc_type;
1261 new_fa->fa_scope = cfg->fc_scope;
Robert Olsson19baf832005-06-21 12:43:18 -07001262 new_fa->fa_state = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001263 /*
1264 * Insert new entry to the list.
1265 */
1266
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001267 if (!fa_head) {
Robert Olssonf835e472005-06-28 15:00:39 -07001268 err = 0;
Herbert Xub47b2ec2006-07-12 13:29:56 -07001269 fa_head = fib_insert_node(t, &err, key, plen);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001270 if (err)
Robert Olssonf835e472005-06-28 15:00:39 -07001271 goto out_free_new_fa;
1272 }
Robert Olsson19baf832005-06-21 12:43:18 -07001273
Robert Olsson2373ce12005-08-25 13:01:29 -07001274 list_add_tail_rcu(&new_fa->fa_list,
1275 (fa ? &fa->fa_list : fa_head));
Robert Olsson19baf832005-06-21 12:43:18 -07001276
1277 rt_cache_flush(-1);
Thomas Graf4e902c52006-08-17 18:14:52 -07001278 rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id,
Milan Kocianb8f55832007-05-23 14:55:06 -07001279 &cfg->fc_nlinfo, 0);
Robert Olsson19baf832005-06-21 12:43:18 -07001280succeeded:
1281 return 0;
Robert Olssonf835e472005-06-28 15:00:39 -07001282
1283out_free_new_fa:
1284 kmem_cache_free(fn_alias_kmem, new_fa);
Robert Olsson19baf832005-06-21 12:43:18 -07001285out:
1286 fib_release_info(fi);
Olof Johansson91b9a272005-08-09 20:24:39 -07001287err:
Robert Olsson19baf832005-06-21 12:43:18 -07001288 return err;
1289}
1290
Robert Olsson2373ce12005-08-25 13:01:29 -07001291
Robert Olsson772cb712005-09-19 15:31:18 -07001292/* should be called with rcu_read_lock */
Stephen Hemminger0c7770c2005-08-23 21:59:41 -07001293static inline int check_leaf(struct trie *t, struct leaf *l,
1294 t_key key, int *plen, const struct flowi *flp,
Patrick McHardy06c74272005-08-23 22:06:09 -07001295 struct fib_result *res)
Robert Olsson19baf832005-06-21 12:43:18 -07001296{
Patrick McHardy06c74272005-08-23 22:06:09 -07001297 int err, i;
Al Viro888454c2006-09-19 13:42:46 -07001298 __be32 mask;
Robert Olsson19baf832005-06-21 12:43:18 -07001299 struct leaf_info *li;
1300 struct hlist_head *hhead = &l->list;
1301 struct hlist_node *node;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001302
Robert Olsson2373ce12005-08-25 13:01:29 -07001303 hlist_for_each_entry_rcu(li, node, hhead, hlist) {
Robert Olsson19baf832005-06-21 12:43:18 -07001304 i = li->plen;
Al Viro888454c2006-09-19 13:42:46 -07001305 mask = inet_make_mask(i);
1306 if (l->key != (key & ntohl(mask)))
Robert Olsson19baf832005-06-21 12:43:18 -07001307 continue;
1308
Al Viro888454c2006-09-19 13:42:46 -07001309 if ((err = fib_semantic_match(&li->falh, flp, res, htonl(l->key), mask, i)) <= 0) {
Robert Olsson19baf832005-06-21 12:43:18 -07001310 *plen = i;
1311#ifdef CONFIG_IP_FIB_TRIE_STATS
1312 t->stats.semantic_match_passed++;
1313#endif
Patrick McHardy06c74272005-08-23 22:06:09 -07001314 return err;
Robert Olsson19baf832005-06-21 12:43:18 -07001315 }
1316#ifdef CONFIG_IP_FIB_TRIE_STATS
1317 t->stats.semantic_match_miss++;
1318#endif
1319 }
Patrick McHardy06c74272005-08-23 22:06:09 -07001320 return 1;
Robert Olsson19baf832005-06-21 12:43:18 -07001321}
1322
1323static int
1324fn_trie_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
1325{
1326 struct trie *t = (struct trie *) tb->tb_data;
1327 int plen, ret = 0;
1328 struct node *n;
1329 struct tnode *pn;
1330 int pos, bits;
Olof Johansson91b9a272005-08-09 20:24:39 -07001331 t_key key = ntohl(flp->fl4_dst);
Robert Olsson19baf832005-06-21 12:43:18 -07001332 int chopped_off;
1333 t_key cindex = 0;
1334 int current_prefix_length = KEYLENGTH;
Olof Johansson91b9a272005-08-09 20:24:39 -07001335 struct tnode *cn;
1336 t_key node_prefix, key_prefix, pref_mismatch;
1337 int mp;
1338
Robert Olsson2373ce12005-08-25 13:01:29 -07001339 rcu_read_lock();
Robert Olsson19baf832005-06-21 12:43:18 -07001340
Robert Olsson2373ce12005-08-25 13:01:29 -07001341 n = rcu_dereference(t->trie);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001342 if (!n)
Robert Olsson19baf832005-06-21 12:43:18 -07001343 goto failed;
1344
1345#ifdef CONFIG_IP_FIB_TRIE_STATS
1346 t->stats.gets++;
1347#endif
1348
1349 /* Just a leaf? */
1350 if (IS_LEAF(n)) {
Patrick McHardy06c74272005-08-23 22:06:09 -07001351 if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
Robert Olsson19baf832005-06-21 12:43:18 -07001352 goto found;
1353 goto failed;
1354 }
1355 pn = (struct tnode *) n;
1356 chopped_off = 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001357
Olof Johansson91b9a272005-08-09 20:24:39 -07001358 while (pn) {
Robert Olsson19baf832005-06-21 12:43:18 -07001359 pos = pn->pos;
1360 bits = pn->bits;
1361
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001362 if (!chopped_off)
Stephen Hemmingerab66b4a2007-08-10 15:22:58 -07001363 cindex = tkey_extract_bits(mask_pfx(key, current_prefix_length),
1364 pos, bits);
Robert Olsson19baf832005-06-21 12:43:18 -07001365
1366 n = tnode_get_child(pn, cindex);
1367
1368 if (n == NULL) {
1369#ifdef CONFIG_IP_FIB_TRIE_STATS
1370 t->stats.null_node_hit++;
1371#endif
1372 goto backtrace;
1373 }
1374
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001375 if (IS_LEAF(n)) {
Patrick McHardy06c74272005-08-23 22:06:09 -07001376 if ((ret = check_leaf(t, (struct leaf *)n, key, &plen, flp, res)) <= 0)
Robert Olsson19baf832005-06-21 12:43:18 -07001377 goto found;
Olof Johansson91b9a272005-08-09 20:24:39 -07001378 else
1379 goto backtrace;
1380 }
1381
1382#define HL_OPTIMIZE
1383#ifdef HL_OPTIMIZE
1384 cn = (struct tnode *)n;
1385
1386 /*
1387 * It's a tnode, and we can do some extra checks here if we
1388 * like, to avoid descending into a dead-end branch.
1389 * This tnode is in the parent's child array at index
1390 * key[p_pos..p_pos+p_bits] but potentially with some bits
1391 * chopped off, so in reality the index may be just a
1392 * subprefix, padded with zero at the end.
1393 * We can also take a look at any skipped bits in this
1394 * tnode - everything up to p_pos is supposed to be ok,
1395 * and the non-chopped bits of the index (se previous
1396 * paragraph) are also guaranteed ok, but the rest is
1397 * considered unknown.
1398 *
1399 * The skipped bits are key[pos+bits..cn->pos].
1400 */
1401
1402 /* If current_prefix_length < pos+bits, we are already doing
1403 * actual prefix matching, which means everything from
1404 * pos+(bits-chopped_off) onward must be zero along some
1405 * branch of this subtree - otherwise there is *no* valid
1406 * prefix present. Here we can only check the skipped
1407 * bits. Remember, since we have already indexed into the
1408 * parent's child array, we know that the bits we chopped of
1409 * *are* zero.
1410 */
1411
1412 /* NOTA BENE: CHECKING ONLY SKIPPED BITS FOR THE NEW NODE HERE */
1413
1414 if (current_prefix_length < pos+bits) {
1415 if (tkey_extract_bits(cn->key, current_prefix_length,
1416 cn->pos - current_prefix_length) != 0 ||
1417 !(cn->child[0]))
1418 goto backtrace;
1419 }
1420
1421 /*
1422 * If chopped_off=0, the index is fully validated and we
1423 * only need to look at the skipped bits for this, the new,
1424 * tnode. What we actually want to do is to find out if
1425 * these skipped bits match our key perfectly, or if we will
1426 * have to count on finding a matching prefix further down,
1427 * because if we do, we would like to have some way of
1428 * verifying the existence of such a prefix at this point.
1429 */
1430
1431 /* The only thing we can do at this point is to verify that
1432 * any such matching prefix can indeed be a prefix to our
1433 * key, and if the bits in the node we are inspecting that
1434 * do not match our key are not ZERO, this cannot be true.
1435 * Thus, find out where there is a mismatch (before cn->pos)
1436 * and verify that all the mismatching bits are zero in the
1437 * new tnode's key.
1438 */
1439
1440 /* Note: We aren't very concerned about the piece of the key
1441 * that precede pn->pos+pn->bits, since these have already been
1442 * checked. The bits after cn->pos aren't checked since these are
1443 * by definition "unknown" at this point. Thus, what we want to
1444 * see is if we are about to enter the "prefix matching" state,
1445 * and in that case verify that the skipped bits that will prevail
1446 * throughout this subtree are zero, as they have to be if we are
1447 * to find a matching prefix.
1448 */
1449
Stephen Hemmingerab66b4a2007-08-10 15:22:58 -07001450 node_prefix = mask_pfx(cn->key, cn->pos);
1451 key_prefix = mask_pfx(key, cn->pos);
Olof Johansson91b9a272005-08-09 20:24:39 -07001452 pref_mismatch = key_prefix^node_prefix;
1453 mp = 0;
1454
1455 /* In short: If skipped bits in this node do not match the search
1456 * key, enter the "prefix matching" state.directly.
1457 */
1458 if (pref_mismatch) {
1459 while (!(pref_mismatch & (1<<(KEYLENGTH-1)))) {
1460 mp++;
1461 pref_mismatch = pref_mismatch <<1;
1462 }
1463 key_prefix = tkey_extract_bits(cn->key, mp, cn->pos-mp);
1464
1465 if (key_prefix != 0)
1466 goto backtrace;
1467
1468 if (current_prefix_length >= cn->pos)
1469 current_prefix_length = mp;
1470 }
1471#endif
1472 pn = (struct tnode *)n; /* Descend */
1473 chopped_off = 0;
1474 continue;
1475
Robert Olsson19baf832005-06-21 12:43:18 -07001476backtrace:
1477 chopped_off++;
1478
1479 /* As zero don't change the child key (cindex) */
Olof Johansson91b9a272005-08-09 20:24:39 -07001480 while ((chopped_off <= pn->bits) && !(cindex & (1<<(chopped_off-1))))
Robert Olsson19baf832005-06-21 12:43:18 -07001481 chopped_off++;
Robert Olsson19baf832005-06-21 12:43:18 -07001482
1483 /* Decrease current_... with bits chopped off */
1484 if (current_prefix_length > pn->pos + pn->bits - chopped_off)
1485 current_prefix_length = pn->pos + pn->bits - chopped_off;
Olof Johansson91b9a272005-08-09 20:24:39 -07001486
Robert Olsson19baf832005-06-21 12:43:18 -07001487 /*
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001488 * Either we do the actual chop off according or if we have
Robert Olsson19baf832005-06-21 12:43:18 -07001489 * chopped off all bits in this tnode walk up to our parent.
1490 */
1491
Olof Johansson91b9a272005-08-09 20:24:39 -07001492 if (chopped_off <= pn->bits) {
Robert Olsson19baf832005-06-21 12:43:18 -07001493 cindex &= ~(1 << (chopped_off-1));
Olof Johansson91b9a272005-08-09 20:24:39 -07001494 } else {
Stephen Hemminger06801912007-08-10 15:22:13 -07001495 struct tnode *parent = node_parent((struct node *) pn);
1496 if (!parent)
Robert Olsson19baf832005-06-21 12:43:18 -07001497 goto failed;
Olof Johansson91b9a272005-08-09 20:24:39 -07001498
Robert Olsson19baf832005-06-21 12:43:18 -07001499 /* Get Child's index */
Stephen Hemminger06801912007-08-10 15:22:13 -07001500 cindex = tkey_extract_bits(pn->key, parent->pos, parent->bits);
1501 pn = parent;
Robert Olsson19baf832005-06-21 12:43:18 -07001502 chopped_off = 0;
1503
1504#ifdef CONFIG_IP_FIB_TRIE_STATS
1505 t->stats.backtrack++;
1506#endif
1507 goto backtrace;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001508 }
Robert Olsson19baf832005-06-21 12:43:18 -07001509 }
1510failed:
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001511 ret = 1;
Robert Olsson19baf832005-06-21 12:43:18 -07001512found:
Robert Olsson2373ce12005-08-25 13:01:29 -07001513 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07001514 return ret;
1515}
1516
Robert Olsson2373ce12005-08-25 13:01:29 -07001517/* only called from updater side */
Robert Olsson19baf832005-06-21 12:43:18 -07001518static int trie_leaf_remove(struct trie *t, t_key key)
1519{
1520 t_key cindex;
1521 struct tnode *tp = NULL;
1522 struct node *n = t->trie;
1523 struct leaf *l;
1524
Stephen Hemminger0c7770c2005-08-23 21:59:41 -07001525 pr_debug("entering trie_leaf_remove(%p)\n", n);
Robert Olsson19baf832005-06-21 12:43:18 -07001526
1527 /* Note that in the case skipped bits, those bits are *not* checked!
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001528 * When we finish this, we will have NULL or a T_LEAF, and the
Robert Olsson19baf832005-06-21 12:43:18 -07001529 * T_LEAF may or may not match our key.
1530 */
1531
Olof Johansson91b9a272005-08-09 20:24:39 -07001532 while (n != NULL && IS_TNODE(n)) {
Robert Olsson19baf832005-06-21 12:43:18 -07001533 struct tnode *tn = (struct tnode *) n;
1534 check_tnode(tn);
1535 n = tnode_get_child(tn ,tkey_extract_bits(key, tn->pos, tn->bits));
1536
Stephen Hemminger06801912007-08-10 15:22:13 -07001537 BUG_ON(n && node_parent(n) != tn);
Olof Johansson91b9a272005-08-09 20:24:39 -07001538 }
Robert Olsson19baf832005-06-21 12:43:18 -07001539 l = (struct leaf *) n;
1540
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001541 if (!n || !tkey_equals(l->key, key))
Robert Olsson19baf832005-06-21 12:43:18 -07001542 return 0;
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001543
1544 /*
1545 * Key found.
1546 * Remove the leaf and rebalance the tree
Robert Olsson19baf832005-06-21 12:43:18 -07001547 */
1548
1549 t->revision++;
1550 t->size--;
1551
Stephen Hemminger06801912007-08-10 15:22:13 -07001552 tp = node_parent(n);
Robert Olsson19baf832005-06-21 12:43:18 -07001553 tnode_free((struct tnode *) n);
1554
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001555 if (tp) {
Robert Olsson19baf832005-06-21 12:43:18 -07001556 cindex = tkey_extract_bits(key, tp->pos, tp->bits);
1557 put_child(t, (struct tnode *)tp, cindex, NULL);
Robert Olsson2373ce12005-08-25 13:01:29 -07001558 rcu_assign_pointer(t->trie, trie_rebalance(t, tp));
Olof Johansson91b9a272005-08-09 20:24:39 -07001559 } else
Robert Olsson2373ce12005-08-25 13:01:29 -07001560 rcu_assign_pointer(t->trie, NULL);
Robert Olsson19baf832005-06-21 12:43:18 -07001561
1562 return 1;
1563}
1564
Robert Olssond562f1f2007-03-26 14:22:22 -07001565/*
1566 * Caller must hold RTNL.
1567 */
Thomas Graf4e902c52006-08-17 18:14:52 -07001568static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
Robert Olsson19baf832005-06-21 12:43:18 -07001569{
1570 struct trie *t = (struct trie *) tb->tb_data;
1571 u32 key, mask;
Thomas Graf4e902c52006-08-17 18:14:52 -07001572 int plen = cfg->fc_dst_len;
1573 u8 tos = cfg->fc_tos;
Robert Olsson19baf832005-06-21 12:43:18 -07001574 struct fib_alias *fa, *fa_to_delete;
1575 struct list_head *fa_head;
1576 struct leaf *l;
Olof Johansson91b9a272005-08-09 20:24:39 -07001577 struct leaf_info *li;
1578
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001579 if (plen > 32)
Robert Olsson19baf832005-06-21 12:43:18 -07001580 return -EINVAL;
1581
Thomas Graf4e902c52006-08-17 18:14:52 -07001582 key = ntohl(cfg->fc_dst);
Olof Johansson91b9a272005-08-09 20:24:39 -07001583 mask = ntohl(inet_make_mask(plen));
Robert Olsson19baf832005-06-21 12:43:18 -07001584
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001585 if (key & ~mask)
Robert Olsson19baf832005-06-21 12:43:18 -07001586 return -EINVAL;
1587
1588 key = key & mask;
1589 l = fib_find_node(t, key);
1590
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001591 if (!l)
Robert Olsson19baf832005-06-21 12:43:18 -07001592 return -ESRCH;
1593
1594 fa_head = get_fa_head(l, plen);
1595 fa = fib_find_alias(fa_head, tos, 0);
1596
1597 if (!fa)
1598 return -ESRCH;
1599
Stephen Hemminger0c7770c2005-08-23 21:59:41 -07001600 pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t);
Robert Olsson19baf832005-06-21 12:43:18 -07001601
1602 fa_to_delete = NULL;
1603 fa_head = fa->fa_list.prev;
Robert Olsson2373ce12005-08-25 13:01:29 -07001604
Robert Olsson19baf832005-06-21 12:43:18 -07001605 list_for_each_entry(fa, fa_head, fa_list) {
1606 struct fib_info *fi = fa->fa_info;
1607
1608 if (fa->fa_tos != tos)
1609 break;
1610
Thomas Graf4e902c52006-08-17 18:14:52 -07001611 if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) &&
1612 (cfg->fc_scope == RT_SCOPE_NOWHERE ||
1613 fa->fa_scope == cfg->fc_scope) &&
1614 (!cfg->fc_protocol ||
1615 fi->fib_protocol == cfg->fc_protocol) &&
1616 fib_nh_match(cfg, fi) == 0) {
Robert Olsson19baf832005-06-21 12:43:18 -07001617 fa_to_delete = fa;
1618 break;
1619 }
1620 }
1621
Olof Johansson91b9a272005-08-09 20:24:39 -07001622 if (!fa_to_delete)
1623 return -ESRCH;
Robert Olsson19baf832005-06-21 12:43:18 -07001624
Olof Johansson91b9a272005-08-09 20:24:39 -07001625 fa = fa_to_delete;
Thomas Graf4e902c52006-08-17 18:14:52 -07001626 rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id,
Milan Kocianb8f55832007-05-23 14:55:06 -07001627 &cfg->fc_nlinfo, 0);
Robert Olsson19baf832005-06-21 12:43:18 -07001628
Olof Johansson91b9a272005-08-09 20:24:39 -07001629 l = fib_find_node(t, key);
Robert Olsson772cb712005-09-19 15:31:18 -07001630 li = find_leaf_info(l, plen);
Robert Olsson19baf832005-06-21 12:43:18 -07001631
Robert Olsson2373ce12005-08-25 13:01:29 -07001632 list_del_rcu(&fa->fa_list);
Robert Olsson19baf832005-06-21 12:43:18 -07001633
Olof Johansson91b9a272005-08-09 20:24:39 -07001634 if (list_empty(fa_head)) {
Robert Olsson2373ce12005-08-25 13:01:29 -07001635 hlist_del_rcu(&li->hlist);
Olof Johansson91b9a272005-08-09 20:24:39 -07001636 free_leaf_info(li);
Robert Olsson2373ce12005-08-25 13:01:29 -07001637 }
Olof Johansson91b9a272005-08-09 20:24:39 -07001638
1639 if (hlist_empty(&l->list))
1640 trie_leaf_remove(t, key);
1641
1642 if (fa->fa_state & FA_S_ACCESSED)
1643 rt_cache_flush(-1);
1644
Robert Olsson2373ce12005-08-25 13:01:29 -07001645 fib_release_info(fa->fa_info);
1646 alias_free_mem_rcu(fa);
Olof Johansson91b9a272005-08-09 20:24:39 -07001647 return 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001648}
1649
1650static int trie_flush_list(struct trie *t, struct list_head *head)
1651{
1652 struct fib_alias *fa, *fa_node;
1653 int found = 0;
1654
1655 list_for_each_entry_safe(fa, fa_node, head, fa_list) {
1656 struct fib_info *fi = fa->fa_info;
Robert Olsson19baf832005-06-21 12:43:18 -07001657
Robert Olsson2373ce12005-08-25 13:01:29 -07001658 if (fi && (fi->fib_flags & RTNH_F_DEAD)) {
1659 list_del_rcu(&fa->fa_list);
1660 fib_release_info(fa->fa_info);
1661 alias_free_mem_rcu(fa);
Robert Olsson19baf832005-06-21 12:43:18 -07001662 found++;
1663 }
1664 }
1665 return found;
1666}
1667
1668static int trie_flush_leaf(struct trie *t, struct leaf *l)
1669{
1670 int found = 0;
1671 struct hlist_head *lih = &l->list;
1672 struct hlist_node *node, *tmp;
1673 struct leaf_info *li = NULL;
1674
1675 hlist_for_each_entry_safe(li, node, tmp, lih, hlist) {
Robert Olsson19baf832005-06-21 12:43:18 -07001676 found += trie_flush_list(t, &li->falh);
1677
1678 if (list_empty(&li->falh)) {
Robert Olsson2373ce12005-08-25 13:01:29 -07001679 hlist_del_rcu(&li->hlist);
Robert Olsson19baf832005-06-21 12:43:18 -07001680 free_leaf_info(li);
1681 }
1682 }
1683 return found;
1684}
1685
Robert Olsson2373ce12005-08-25 13:01:29 -07001686/* rcu_read_lock needs to be hold by caller from readside */
1687
Robert Olsson19baf832005-06-21 12:43:18 -07001688static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
1689{
1690 struct node *c = (struct node *) thisleaf;
1691 struct tnode *p;
1692 int idx;
Robert Olsson2373ce12005-08-25 13:01:29 -07001693 struct node *trie = rcu_dereference(t->trie);
Robert Olsson19baf832005-06-21 12:43:18 -07001694
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001695 if (c == NULL) {
Robert Olsson2373ce12005-08-25 13:01:29 -07001696 if (trie == NULL)
Robert Olsson19baf832005-06-21 12:43:18 -07001697 return NULL;
1698
Robert Olsson2373ce12005-08-25 13:01:29 -07001699 if (IS_LEAF(trie)) /* trie w. just a leaf */
1700 return (struct leaf *) trie;
Robert Olsson19baf832005-06-21 12:43:18 -07001701
Robert Olsson2373ce12005-08-25 13:01:29 -07001702 p = (struct tnode*) trie; /* Start */
Olof Johansson91b9a272005-08-09 20:24:39 -07001703 } else
Stephen Hemminger06801912007-08-10 15:22:13 -07001704 p = node_parent(c);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001705
Robert Olsson19baf832005-06-21 12:43:18 -07001706 while (p) {
1707 int pos, last;
1708
1709 /* Find the next child of the parent */
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001710 if (c)
1711 pos = 1 + tkey_extract_bits(c->key, p->pos, p->bits);
1712 else
Robert Olsson19baf832005-06-21 12:43:18 -07001713 pos = 0;
1714
1715 last = 1 << p->bits;
Olof Johansson91b9a272005-08-09 20:24:39 -07001716 for (idx = pos; idx < last ; idx++) {
Robert Olsson2373ce12005-08-25 13:01:29 -07001717 c = rcu_dereference(p->child[idx]);
1718
1719 if (!c)
Olof Johansson91b9a272005-08-09 20:24:39 -07001720 continue;
Robert Olsson19baf832005-06-21 12:43:18 -07001721
Olof Johansson91b9a272005-08-09 20:24:39 -07001722 /* Decend if tnode */
Robert Olsson2373ce12005-08-25 13:01:29 -07001723 while (IS_TNODE(c)) {
1724 p = (struct tnode *) c;
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09001725 idx = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07001726
Olof Johansson91b9a272005-08-09 20:24:39 -07001727 /* Rightmost non-NULL branch */
1728 if (p && IS_TNODE(p))
Robert Olsson2373ce12005-08-25 13:01:29 -07001729 while (!(c = rcu_dereference(p->child[idx]))
1730 && idx < (1<<p->bits)) idx++;
Robert Olsson19baf832005-06-21 12:43:18 -07001731
Olof Johansson91b9a272005-08-09 20:24:39 -07001732 /* Done with this tnode? */
Robert Olsson2373ce12005-08-25 13:01:29 -07001733 if (idx >= (1 << p->bits) || !c)
Olof Johansson91b9a272005-08-09 20:24:39 -07001734 goto up;
Robert Olsson19baf832005-06-21 12:43:18 -07001735 }
Robert Olsson2373ce12005-08-25 13:01:29 -07001736 return (struct leaf *) c;
Robert Olsson19baf832005-06-21 12:43:18 -07001737 }
1738up:
1739 /* No more children go up one step */
Olof Johansson91b9a272005-08-09 20:24:39 -07001740 c = (struct node *) p;
Stephen Hemminger06801912007-08-10 15:22:13 -07001741 p = node_parent(c);
Robert Olsson19baf832005-06-21 12:43:18 -07001742 }
1743 return NULL; /* Ready. Root of trie */
1744}
1745
Robert Olssond562f1f2007-03-26 14:22:22 -07001746/*
1747 * Caller must hold RTNL.
1748 */
Robert Olsson19baf832005-06-21 12:43:18 -07001749static int fn_trie_flush(struct fib_table *tb)
1750{
1751 struct trie *t = (struct trie *) tb->tb_data;
1752 struct leaf *ll = NULL, *l = NULL;
1753 int found = 0, h;
1754
1755 t->revision++;
1756
Olof Johansson91b9a272005-08-09 20:24:39 -07001757 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001758 found += trie_flush_leaf(t, l);
1759
1760 if (ll && hlist_empty(&ll->list))
1761 trie_leaf_remove(t, ll->key);
1762 ll = l;
1763 }
1764
1765 if (ll && hlist_empty(&ll->list))
1766 trie_leaf_remove(t, ll->key);
1767
Stephen Hemminger0c7770c2005-08-23 21:59:41 -07001768 pr_debug("trie_flush found=%d\n", found);
Robert Olsson19baf832005-06-21 12:43:18 -07001769 return found;
1770}
1771
Robert Olsson19baf832005-06-21 12:43:18 -07001772static void
1773fn_trie_select_default(struct fib_table *tb, const struct flowi *flp, struct fib_result *res)
1774{
1775 struct trie *t = (struct trie *) tb->tb_data;
1776 int order, last_idx;
1777 struct fib_info *fi = NULL;
1778 struct fib_info *last_resort;
1779 struct fib_alias *fa = NULL;
1780 struct list_head *fa_head;
1781 struct leaf *l;
1782
1783 last_idx = -1;
1784 last_resort = NULL;
1785 order = -1;
1786
Robert Olsson2373ce12005-08-25 13:01:29 -07001787 rcu_read_lock();
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001788
Robert Olsson19baf832005-06-21 12:43:18 -07001789 l = fib_find_node(t, 0);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001790 if (!l)
Robert Olsson19baf832005-06-21 12:43:18 -07001791 goto out;
1792
1793 fa_head = get_fa_head(l, 0);
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001794 if (!fa_head)
Robert Olsson19baf832005-06-21 12:43:18 -07001795 goto out;
1796
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001797 if (list_empty(fa_head))
Robert Olsson19baf832005-06-21 12:43:18 -07001798 goto out;
1799
Robert Olsson2373ce12005-08-25 13:01:29 -07001800 list_for_each_entry_rcu(fa, fa_head, fa_list) {
Robert Olsson19baf832005-06-21 12:43:18 -07001801 struct fib_info *next_fi = fa->fa_info;
Olof Johansson91b9a272005-08-09 20:24:39 -07001802
Robert Olsson19baf832005-06-21 12:43:18 -07001803 if (fa->fa_scope != res->scope ||
1804 fa->fa_type != RTN_UNICAST)
1805 continue;
Olof Johansson91b9a272005-08-09 20:24:39 -07001806
Robert Olsson19baf832005-06-21 12:43:18 -07001807 if (next_fi->fib_priority > res->fi->fib_priority)
1808 break;
1809 if (!next_fi->fib_nh[0].nh_gw ||
1810 next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
1811 continue;
1812 fa->fa_state |= FA_S_ACCESSED;
Olof Johansson91b9a272005-08-09 20:24:39 -07001813
Robert Olsson19baf832005-06-21 12:43:18 -07001814 if (fi == NULL) {
1815 if (next_fi != res->fi)
1816 break;
1817 } else if (!fib_detect_death(fi, order, &last_resort,
Denis V. Lunev971b8932007-12-08 00:32:23 -08001818 &last_idx, tb->tb_default)) {
Denis V. Luneva2bbe682007-12-08 00:31:44 -08001819 fib_result_assign(res, fi);
Denis V. Lunev971b8932007-12-08 00:32:23 -08001820 tb->tb_default = order;
Robert Olsson19baf832005-06-21 12:43:18 -07001821 goto out;
1822 }
1823 fi = next_fi;
1824 order++;
1825 }
1826 if (order <= 0 || fi == NULL) {
Denis V. Lunev971b8932007-12-08 00:32:23 -08001827 tb->tb_default = -1;
Robert Olsson19baf832005-06-21 12:43:18 -07001828 goto out;
1829 }
1830
Denis V. Lunev971b8932007-12-08 00:32:23 -08001831 if (!fib_detect_death(fi, order, &last_resort, &last_idx,
1832 tb->tb_default)) {
Denis V. Luneva2bbe682007-12-08 00:31:44 -08001833 fib_result_assign(res, fi);
Denis V. Lunev971b8932007-12-08 00:32:23 -08001834 tb->tb_default = order;
Robert Olsson19baf832005-06-21 12:43:18 -07001835 goto out;
1836 }
Denis V. Luneva2bbe682007-12-08 00:31:44 -08001837 if (last_idx >= 0)
1838 fib_result_assign(res, last_resort);
Denis V. Lunev971b8932007-12-08 00:32:23 -08001839 tb->tb_default = last_idx;
1840out:
Robert Olsson2373ce12005-08-25 13:01:29 -07001841 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07001842}
1843
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001844static 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 -07001845 struct sk_buff *skb, struct netlink_callback *cb)
1846{
1847 int i, s_i;
1848 struct fib_alias *fa;
1849
Al Viro32ab5f82006-09-26 22:21:45 -07001850 __be32 xkey = htonl(key);
Robert Olsson19baf832005-06-21 12:43:18 -07001851
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001852 s_i = cb->args[4];
Robert Olsson19baf832005-06-21 12:43:18 -07001853 i = 0;
1854
Robert Olsson2373ce12005-08-25 13:01:29 -07001855 /* rcu_read_lock is hold by caller */
1856
1857 list_for_each_entry_rcu(fa, fah, fa_list) {
Robert Olsson19baf832005-06-21 12:43:18 -07001858 if (i < s_i) {
1859 i++;
1860 continue;
1861 }
Stephen Hemminger78c66712005-09-21 00:15:39 -07001862 BUG_ON(!fa->fa_info);
Robert Olsson19baf832005-06-21 12:43:18 -07001863
1864 if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid,
1865 cb->nlh->nlmsg_seq,
1866 RTM_NEWROUTE,
1867 tb->tb_id,
1868 fa->fa_type,
1869 fa->fa_scope,
Thomas Grafbe403ea2006-08-17 18:15:17 -07001870 xkey,
Robert Olsson19baf832005-06-21 12:43:18 -07001871 plen,
1872 fa->fa_tos,
David S. Miller90f66912005-06-21 14:43:28 -07001873 fa->fa_info, 0) < 0) {
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001874 cb->args[4] = i;
Robert Olsson19baf832005-06-21 12:43:18 -07001875 return -1;
Olof Johansson91b9a272005-08-09 20:24:39 -07001876 }
Robert Olsson19baf832005-06-21 12:43:18 -07001877 i++;
1878 }
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001879 cb->args[4] = i;
Robert Olsson19baf832005-06-21 12:43:18 -07001880 return skb->len;
1881}
1882
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001883static 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 -07001884 struct netlink_callback *cb)
1885{
1886 int h, s_h;
1887 struct list_head *fa_head;
1888 struct leaf *l = NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07001889
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001890 s_h = cb->args[3];
Robert Olsson19baf832005-06-21 12:43:18 -07001891
Olof Johansson91b9a272005-08-09 20:24:39 -07001892 for (h = 0; (l = nextleaf(t, l)) != NULL; h++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001893 if (h < s_h)
1894 continue;
1895 if (h > s_h)
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001896 memset(&cb->args[4], 0,
1897 sizeof(cb->args) - 4*sizeof(cb->args[0]));
Robert Olsson19baf832005-06-21 12:43:18 -07001898
1899 fa_head = get_fa_head(l, plen);
Olof Johansson91b9a272005-08-09 20:24:39 -07001900
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001901 if (!fa_head)
Robert Olsson19baf832005-06-21 12:43:18 -07001902 continue;
1903
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001904 if (list_empty(fa_head))
Robert Olsson19baf832005-06-21 12:43:18 -07001905 continue;
1906
1907 if (fn_trie_dump_fa(l->key, plen, fa_head, tb, skb, cb)<0) {
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001908 cb->args[3] = h;
Robert Olsson19baf832005-06-21 12:43:18 -07001909 return -1;
1910 }
1911 }
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001912 cb->args[3] = h;
Robert Olsson19baf832005-06-21 12:43:18 -07001913 return skb->len;
1914}
1915
1916static int fn_trie_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb)
1917{
1918 int m, s_m;
1919 struct trie *t = (struct trie *) tb->tb_data;
1920
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001921 s_m = cb->args[2];
Robert Olsson19baf832005-06-21 12:43:18 -07001922
Robert Olsson2373ce12005-08-25 13:01:29 -07001923 rcu_read_lock();
Olof Johansson91b9a272005-08-09 20:24:39 -07001924 for (m = 0; m <= 32; m++) {
Robert Olsson19baf832005-06-21 12:43:18 -07001925 if (m < s_m)
1926 continue;
1927 if (m > s_m)
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001928 memset(&cb->args[3], 0,
1929 sizeof(cb->args) - 3*sizeof(cb->args[0]));
Robert Olsson19baf832005-06-21 12:43:18 -07001930
1931 if (fn_trie_dump_plen(t, 32-m, tb, skb, cb)<0) {
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001932 cb->args[2] = m;
Robert Olsson19baf832005-06-21 12:43:18 -07001933 goto out;
1934 }
1935 }
Robert Olsson2373ce12005-08-25 13:01:29 -07001936 rcu_read_unlock();
Patrick McHardy1af5a8c2006-08-10 23:10:46 -07001937 cb->args[2] = m;
Robert Olsson19baf832005-06-21 12:43:18 -07001938 return skb->len;
Olof Johansson91b9a272005-08-09 20:24:39 -07001939out:
Robert Olsson2373ce12005-08-25 13:01:29 -07001940 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07001941 return -1;
1942}
1943
1944/* Fix more generic FIB names for init later */
1945
Denis V. Lunev7b1a74fd2008-01-10 03:22:17 -08001946struct fib_table *fib_hash_init(u32 id)
Robert Olsson19baf832005-06-21 12:43:18 -07001947{
1948 struct fib_table *tb;
1949 struct trie *t;
1950
1951 if (fn_alias_kmem == NULL)
1952 fn_alias_kmem = kmem_cache_create("ip_fib_alias",
1953 sizeof(struct fib_alias),
1954 0, SLAB_HWCACHE_ALIGN,
Paul Mundt20c2df82007-07-20 10:11:58 +09001955 NULL);
Robert Olsson19baf832005-06-21 12:43:18 -07001956
1957 tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie),
1958 GFP_KERNEL);
1959 if (tb == NULL)
1960 return NULL;
1961
1962 tb->tb_id = id;
Denis V. Lunev971b8932007-12-08 00:32:23 -08001963 tb->tb_default = -1;
Robert Olsson19baf832005-06-21 12:43:18 -07001964 tb->tb_lookup = fn_trie_lookup;
1965 tb->tb_insert = fn_trie_insert;
1966 tb->tb_delete = fn_trie_delete;
1967 tb->tb_flush = fn_trie_flush;
1968 tb->tb_select_default = fn_trie_select_default;
1969 tb->tb_dump = fn_trie_dump;
Robert Olsson19baf832005-06-21 12:43:18 -07001970
1971 t = (struct trie *) tb->tb_data;
Stephen Hemmingerc28a1cf2008-01-12 20:49:13 -08001972 memset(t, 0, sizeof(*t));
Robert Olsson19baf832005-06-21 12:43:18 -07001973
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07001974 if (id == RT_TABLE_LOCAL)
Stephen Hemminger78c66712005-09-21 00:15:39 -07001975 printk(KERN_INFO "IPv4 FIB: Using LC-trie version %s\n", VERSION);
Robert Olsson19baf832005-06-21 12:43:18 -07001976
1977 return tb;
1978}
1979
Robert Olsson19baf832005-06-21 12:43:18 -07001980#ifdef CONFIG_PROC_FS
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07001981/* Depth first Trie walk iterator */
1982struct fib_trie_iter {
Denis V. Lunev1c340b22008-01-10 03:27:17 -08001983 struct seq_net_private p;
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08001984 struct trie *trie_local, *trie_main;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07001985 struct tnode *tnode;
1986 struct trie *trie;
1987 unsigned index;
1988 unsigned depth;
1989};
Robert Olsson19baf832005-06-21 12:43:18 -07001990
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07001991static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
Robert Olsson19baf832005-06-21 12:43:18 -07001992{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07001993 struct tnode *tn = iter->tnode;
1994 unsigned cindex = iter->index;
1995 struct tnode *p;
1996
Eric W. Biederman6640e692007-01-24 14:42:04 -08001997 /* A single entry routing table */
1998 if (!tn)
1999 return NULL;
2000
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002001 pr_debug("get_next iter={node=%p index=%d depth=%d}\n",
2002 iter->tnode, iter->index, iter->depth);
2003rescan:
2004 while (cindex < (1<<tn->bits)) {
2005 struct node *n = tnode_get_child(tn, cindex);
2006
2007 if (n) {
2008 if (IS_LEAF(n)) {
2009 iter->tnode = tn;
2010 iter->index = cindex + 1;
2011 } else {
2012 /* push down one level */
2013 iter->tnode = (struct tnode *) n;
2014 iter->index = 0;
2015 ++iter->depth;
2016 }
2017 return n;
2018 }
2019
2020 ++cindex;
2021 }
2022
2023 /* Current node exhausted, pop back up */
Stephen Hemminger06801912007-08-10 15:22:13 -07002024 p = node_parent((struct node *)tn);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002025 if (p) {
2026 cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
2027 tn = p;
2028 --iter->depth;
2029 goto rescan;
2030 }
2031
2032 /* got root? */
Robert Olsson19baf832005-06-21 12:43:18 -07002033 return NULL;
2034}
2035
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002036static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
2037 struct trie *t)
Robert Olsson19baf832005-06-21 12:43:18 -07002038{
Robert Olsson5ddf0eb2006-03-20 21:34:12 -08002039 struct node *n ;
2040
Stephen Hemminger132adf52007-03-08 20:44:43 -08002041 if (!t)
Robert Olsson5ddf0eb2006-03-20 21:34:12 -08002042 return NULL;
2043
2044 n = rcu_dereference(t->trie);
2045
Stephen Hemminger132adf52007-03-08 20:44:43 -08002046 if (!iter)
Robert Olsson5ddf0eb2006-03-20 21:34:12 -08002047 return NULL;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002048
Eric W. Biederman6640e692007-01-24 14:42:04 -08002049 if (n) {
2050 if (IS_TNODE(n)) {
2051 iter->tnode = (struct tnode *) n;
2052 iter->trie = t;
2053 iter->index = 0;
2054 iter->depth = 1;
2055 } else {
2056 iter->tnode = NULL;
2057 iter->trie = t;
2058 iter->index = 0;
2059 iter->depth = 0;
2060 }
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002061 return n;
2062 }
Robert Olsson19baf832005-06-21 12:43:18 -07002063 return NULL;
2064}
2065
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002066static void trie_collect_stats(struct trie *t, struct trie_stat *s)
Robert Olsson19baf832005-06-21 12:43:18 -07002067{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002068 struct node *n;
2069 struct fib_trie_iter iter;
Robert Olsson19baf832005-06-21 12:43:18 -07002070
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002071 memset(s, 0, sizeof(*s));
Robert Olsson19baf832005-06-21 12:43:18 -07002072
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002073 rcu_read_lock();
2074 for (n = fib_trie_get_first(&iter, t); n;
2075 n = fib_trie_get_next(&iter)) {
2076 if (IS_LEAF(n)) {
2077 s->leaves++;
2078 s->totdepth += iter.depth;
2079 if (iter.depth > s->maxdepth)
2080 s->maxdepth = iter.depth;
2081 } else {
2082 const struct tnode *tn = (const struct tnode *) n;
2083 int i;
Robert Olsson19baf832005-06-21 12:43:18 -07002084
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002085 s->tnodes++;
Stephen Hemminger132adf52007-03-08 20:44:43 -08002086 if (tn->bits < MAX_STAT_DEPTH)
Robert Olsson06ef9212006-03-20 21:35:01 -08002087 s->nodesizes[tn->bits]++;
2088
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002089 for (i = 0; i < (1<<tn->bits); i++)
2090 if (!tn->child[i])
2091 s->nullpointers++;
2092 }
2093 }
2094 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07002095}
2096
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002097/*
Robert Olsson19baf832005-06-21 12:43:18 -07002098 * This outputs /proc/net/fib_triestats
Robert Olsson19baf832005-06-21 12:43:18 -07002099 */
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002100static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
Robert Olsson19baf832005-06-21 12:43:18 -07002101{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002102 unsigned i, max, pointers, bytes, avdepth;
Robert Olsson19baf832005-06-21 12:43:18 -07002103
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002104 if (stat->leaves)
2105 avdepth = stat->totdepth*100 / stat->leaves;
2106 else
2107 avdepth = 0;
Robert Olsson19baf832005-06-21 12:43:18 -07002108
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002109 seq_printf(seq, "\tAver depth: %d.%02d\n", avdepth / 100, avdepth % 100 );
2110 seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth);
Robert Olsson19baf832005-06-21 12:43:18 -07002111
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002112 seq_printf(seq, "\tLeaves: %u\n", stat->leaves);
Olof Johansson91b9a272005-08-09 20:24:39 -07002113
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002114 bytes = sizeof(struct leaf) * stat->leaves;
2115 seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes);
2116 bytes += sizeof(struct tnode) * stat->tnodes;
Robert Olsson19baf832005-06-21 12:43:18 -07002117
Robert Olsson06ef9212006-03-20 21:35:01 -08002118 max = MAX_STAT_DEPTH;
2119 while (max > 0 && stat->nodesizes[max-1] == 0)
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002120 max--;
Robert Olsson19baf832005-06-21 12:43:18 -07002121
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002122 pointers = 0;
2123 for (i = 1; i <= max; i++)
2124 if (stat->nodesizes[i] != 0) {
2125 seq_printf(seq, " %d: %d", i, stat->nodesizes[i]);
2126 pointers += (1<<i) * stat->nodesizes[i];
2127 }
2128 seq_putc(seq, '\n');
2129 seq_printf(seq, "\tPointers: %d\n", pointers);
Robert Olsson19baf832005-06-21 12:43:18 -07002130
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002131 bytes += sizeof(struct node *) * pointers;
2132 seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers);
2133 seq_printf(seq, "Total size: %d kB\n", (bytes + 1023) / 1024);
Robert Olsson19baf832005-06-21 12:43:18 -07002134
2135#ifdef CONFIG_IP_FIB_TRIE_STATS
2136 seq_printf(seq, "Counters:\n---------\n");
2137 seq_printf(seq,"gets = %d\n", t->stats.gets);
2138 seq_printf(seq,"backtracks = %d\n", t->stats.backtrack);
2139 seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
2140 seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
2141 seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
Robert Olsson2f368952005-07-05 15:02:40 -07002142 seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);
Robert Olsson19baf832005-06-21 12:43:18 -07002143#ifdef CLEAR_STATS
2144 memset(&(t->stats), 0, sizeof(t->stats));
2145#endif
2146#endif /* CONFIG_IP_FIB_TRIE_STATS */
2147}
2148
2149static int fib_triestat_seq_show(struct seq_file *seq, void *v)
2150{
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002151 struct net *net = (struct net *)seq->private;
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002152 struct trie *trie_local, *trie_main;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002153 struct trie_stat *stat;
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002154 struct fib_table *tb;
2155
2156 trie_local = NULL;
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002157 tb = fib_get_table(net, RT_TABLE_LOCAL);
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002158 if (tb)
2159 trie_local = (struct trie *) tb->tb_data;
2160
2161 trie_main = NULL;
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002162 tb = fib_get_table(net, RT_TABLE_MAIN);
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002163 if (tb)
2164 trie_main = (struct trie *) tb->tb_data;
2165
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002166
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002167 stat = kmalloc(sizeof(*stat), GFP_KERNEL);
2168 if (!stat)
2169 return -ENOMEM;
Robert Olsson19baf832005-06-21 12:43:18 -07002170
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002171 seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n",
2172 sizeof(struct leaf), sizeof(struct tnode));
Olof Johansson91b9a272005-08-09 20:24:39 -07002173
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002174 if (trie_local) {
2175 seq_printf(seq, "Local:\n");
2176 trie_collect_stats(trie_local, stat);
2177 trie_show_stats(seq, stat);
Robert Olsson19baf832005-06-21 12:43:18 -07002178 }
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002179
2180 if (trie_main) {
2181 seq_printf(seq, "Main:\n");
2182 trie_collect_stats(trie_main, stat);
2183 trie_show_stats(seq, stat);
2184 }
2185 kfree(stat);
2186
Robert Olsson19baf832005-06-21 12:43:18 -07002187 return 0;
2188}
2189
Robert Olsson19baf832005-06-21 12:43:18 -07002190static int fib_triestat_seq_open(struct inode *inode, struct file *file)
2191{
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002192 int err;
2193 struct net *net;
2194
2195 net = get_proc_net(inode);
2196 if (net == NULL)
2197 return -ENXIO;
2198 err = single_open(file, fib_triestat_seq_show, net);
2199 if (err < 0) {
2200 put_net(net);
2201 return err;
2202 }
2203 return 0;
2204}
2205
2206static int fib_triestat_seq_release(struct inode *ino, struct file *f)
2207{
2208 struct seq_file *seq = f->private_data;
2209 put_net(seq->private);
2210 return single_release(ino, f);
Robert Olsson19baf832005-06-21 12:43:18 -07002211}
2212
Arjan van de Ven9a321442007-02-12 00:55:35 -08002213static const struct file_operations fib_triestat_fops = {
Stephen Hemmingerc877efb2005-07-19 14:01:51 -07002214 .owner = THIS_MODULE,
2215 .open = fib_triestat_seq_open,
2216 .read = seq_read,
2217 .llseek = seq_lseek,
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002218 .release = fib_triestat_seq_release,
Robert Olsson19baf832005-06-21 12:43:18 -07002219};
2220
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002221static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
2222 loff_t pos)
Robert Olsson19baf832005-06-21 12:43:18 -07002223{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002224 loff_t idx = 0;
2225 struct node *n;
Robert Olsson19baf832005-06-21 12:43:18 -07002226
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002227 for (n = fib_trie_get_first(iter, iter->trie_local);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002228 n; ++idx, n = fib_trie_get_next(iter)) {
2229 if (pos == idx)
2230 return n;
2231 }
Robert Olsson19baf832005-06-21 12:43:18 -07002232
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002233 for (n = fib_trie_get_first(iter, iter->trie_main);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002234 n; ++idx, n = fib_trie_get_next(iter)) {
2235 if (pos == idx)
2236 return n;
2237 }
Robert Olsson19baf832005-06-21 12:43:18 -07002238 return NULL;
2239}
2240
2241static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
2242{
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002243 struct fib_trie_iter *iter = seq->private;
2244 struct fib_table *tb;
2245
2246 if (!iter->trie_local) {
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002247 tb = fib_get_table(iter->p.net, RT_TABLE_LOCAL);
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002248 if (tb)
2249 iter->trie_local = (struct trie *) tb->tb_data;
2250 }
2251 if (!iter->trie_main) {
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002252 tb = fib_get_table(iter->p.net, RT_TABLE_MAIN);
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002253 if (tb)
2254 iter->trie_main = (struct trie *) tb->tb_data;
2255 }
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002256 rcu_read_lock();
2257 if (*pos == 0)
Olof Johansson91b9a272005-08-09 20:24:39 -07002258 return SEQ_START_TOKEN;
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002259 return fib_trie_get_idx(iter, *pos - 1);
Robert Olsson19baf832005-06-21 12:43:18 -07002260}
2261
2262static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2263{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002264 struct fib_trie_iter *iter = seq->private;
2265 void *l = v;
2266
Robert Olsson19baf832005-06-21 12:43:18 -07002267 ++*pos;
Olof Johansson91b9a272005-08-09 20:24:39 -07002268 if (v == SEQ_START_TOKEN)
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002269 return fib_trie_get_idx(iter, 0);
Olof Johansson91b9a272005-08-09 20:24:39 -07002270
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002271 v = fib_trie_get_next(iter);
2272 BUG_ON(v == l);
2273 if (v)
2274 return v;
2275
2276 /* continue scan in next trie */
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002277 if (iter->trie == iter->trie_local)
2278 return fib_trie_get_first(iter, iter->trie_main);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002279
2280 return NULL;
Robert Olsson19baf832005-06-21 12:43:18 -07002281}
2282
2283static void fib_trie_seq_stop(struct seq_file *seq, void *v)
2284{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002285 rcu_read_unlock();
Robert Olsson19baf832005-06-21 12:43:18 -07002286}
2287
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002288static void seq_indent(struct seq_file *seq, int n)
2289{
2290 while (n-- > 0) seq_puts(seq, " ");
2291}
Robert Olsson19baf832005-06-21 12:43:18 -07002292
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002293static inline const char *rtn_scope(enum rt_scope_t s)
2294{
2295 static char buf[32];
2296
Stephen Hemminger132adf52007-03-08 20:44:43 -08002297 switch (s) {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002298 case RT_SCOPE_UNIVERSE: return "universe";
2299 case RT_SCOPE_SITE: return "site";
2300 case RT_SCOPE_LINK: return "link";
2301 case RT_SCOPE_HOST: return "host";
2302 case RT_SCOPE_NOWHERE: return "nowhere";
2303 default:
2304 snprintf(buf, sizeof(buf), "scope=%d", s);
2305 return buf;
2306 }
2307}
2308
2309static const char *rtn_type_names[__RTN_MAX] = {
2310 [RTN_UNSPEC] = "UNSPEC",
2311 [RTN_UNICAST] = "UNICAST",
2312 [RTN_LOCAL] = "LOCAL",
2313 [RTN_BROADCAST] = "BROADCAST",
2314 [RTN_ANYCAST] = "ANYCAST",
2315 [RTN_MULTICAST] = "MULTICAST",
2316 [RTN_BLACKHOLE] = "BLACKHOLE",
2317 [RTN_UNREACHABLE] = "UNREACHABLE",
2318 [RTN_PROHIBIT] = "PROHIBIT",
2319 [RTN_THROW] = "THROW",
2320 [RTN_NAT] = "NAT",
2321 [RTN_XRESOLVE] = "XRESOLVE",
2322};
2323
2324static inline const char *rtn_type(unsigned t)
2325{
2326 static char buf[32];
2327
2328 if (t < __RTN_MAX && rtn_type_names[t])
2329 return rtn_type_names[t];
2330 snprintf(buf, sizeof(buf), "type %d", t);
2331 return buf;
2332}
2333
2334/* Pretty print the trie */
Robert Olsson19baf832005-06-21 12:43:18 -07002335static int fib_trie_seq_show(struct seq_file *seq, void *v)
2336{
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002337 const struct fib_trie_iter *iter = seq->private;
2338 struct node *n = v;
Robert Olsson19baf832005-06-21 12:43:18 -07002339
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002340 if (v == SEQ_START_TOKEN)
2341 return 0;
Robert Olsson19baf832005-06-21 12:43:18 -07002342
Stephen Hemminger06801912007-08-10 15:22:13 -07002343 if (!node_parent(n)) {
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002344 if (iter->trie == iter->trie_local)
Robert Olsson095b8502007-01-26 19:06:01 -08002345 seq_puts(seq, "<local>:\n");
2346 else
2347 seq_puts(seq, "<main>:\n");
2348 }
2349
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002350 if (IS_TNODE(n)) {
2351 struct tnode *tn = (struct tnode *) n;
Stephen Hemmingerab66b4a2007-08-10 15:22:58 -07002352 __be32 prf = htonl(mask_pfx(tn->key, tn->pos));
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002353
Robert Olsson1d25cd62005-09-19 15:29:52 -07002354 seq_indent(seq, iter->depth-1);
2355 seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n",
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002356 NIPQUAD(prf), tn->pos, tn->bits, tn->full_children,
Robert Olsson1d25cd62005-09-19 15:29:52 -07002357 tn->empty_children);
YOSHIFUJI Hideakie905a9e2007-02-09 23:24:47 +09002358
Olof Johansson91b9a272005-08-09 20:24:39 -07002359 } else {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002360 struct leaf *l = (struct leaf *) n;
2361 int i;
Al Viro32ab5f82006-09-26 22:21:45 -07002362 __be32 val = htonl(l->key);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002363
2364 seq_indent(seq, iter->depth);
2365 seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));
2366 for (i = 32; i >= 0; i--) {
Robert Olsson772cb712005-09-19 15:31:18 -07002367 struct leaf_info *li = find_leaf_info(l, i);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002368 if (li) {
2369 struct fib_alias *fa;
2370 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
2371 seq_indent(seq, iter->depth+1);
2372 seq_printf(seq, " /%d %s %s", i,
2373 rtn_scope(fa->fa_scope),
2374 rtn_type(fa->fa_type));
2375 if (fa->fa_tos)
2376 seq_printf(seq, "tos =%d\n",
2377 fa->fa_tos);
2378 seq_putc(seq, '\n');
2379 }
2380 }
2381 }
Robert Olsson19baf832005-06-21 12:43:18 -07002382 }
2383
2384 return 0;
2385}
2386
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002387static const struct seq_operations fib_trie_seq_ops = {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002388 .start = fib_trie_seq_start,
2389 .next = fib_trie_seq_next,
2390 .stop = fib_trie_seq_stop,
2391 .show = fib_trie_seq_show,
Robert Olsson19baf832005-06-21 12:43:18 -07002392};
2393
2394static int fib_trie_seq_open(struct inode *inode, struct file *file)
2395{
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002396 return seq_open_net(inode, file, &fib_trie_seq_ops,
2397 sizeof(struct fib_trie_iter));
Robert Olsson19baf832005-06-21 12:43:18 -07002398}
2399
Arjan van de Ven9a321442007-02-12 00:55:35 -08002400static const struct file_operations fib_trie_fops = {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002401 .owner = THIS_MODULE,
2402 .open = fib_trie_seq_open,
2403 .read = seq_read,
2404 .llseek = seq_lseek,
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002405 .release = seq_release_net,
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002406};
2407
Al Viro32ab5f82006-09-26 22:21:45 -07002408static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002409{
2410 static unsigned type2flags[RTN_MAX + 1] = {
2411 [7] = RTF_REJECT, [8] = RTF_REJECT,
2412 };
2413 unsigned flags = type2flags[type];
2414
2415 if (fi && fi->fib_nh->nh_gw)
2416 flags |= RTF_GATEWAY;
Al Viro32ab5f82006-09-26 22:21:45 -07002417 if (mask == htonl(0xFFFFFFFF))
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002418 flags |= RTF_HOST;
2419 flags |= RTF_UP;
2420 return flags;
2421}
2422
2423/*
2424 * This outputs /proc/net/route.
2425 * The format of the file is not supposed to be changed
2426 * and needs to be same as fib_hash output to avoid breaking
2427 * legacy utilities
2428 */
2429static int fib_route_seq_show(struct seq_file *seq, void *v)
2430{
Patrick McHardyc9e53cb2005-11-20 21:09:00 -08002431 const struct fib_trie_iter *iter = seq->private;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002432 struct leaf *l = v;
2433 int i;
2434 char bf[128];
2435
2436 if (v == SEQ_START_TOKEN) {
2437 seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "
2438 "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
2439 "\tWindow\tIRTT");
2440 return 0;
2441 }
2442
Eric W. Biederman877a9bf2007-12-07 00:47:47 -08002443 if (iter->trie == iter->trie_local)
Patrick McHardyc9e53cb2005-11-20 21:09:00 -08002444 return 0;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002445 if (IS_TNODE(l))
2446 return 0;
2447
2448 for (i=32; i>=0; i--) {
Robert Olsson772cb712005-09-19 15:31:18 -07002449 struct leaf_info *li = find_leaf_info(l, i);
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002450 struct fib_alias *fa;
Al Viro32ab5f82006-09-26 22:21:45 -07002451 __be32 mask, prefix;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002452
2453 if (!li)
2454 continue;
2455
2456 mask = inet_make_mask(li->plen);
2457 prefix = htonl(l->key);
2458
2459 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
Herbert Xu1371e372005-10-15 09:42:39 +10002460 const struct fib_info *fi = fa->fa_info;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002461 unsigned flags = fib_flag_trans(fa->fa_type, mask, fi);
2462
2463 if (fa->fa_type == RTN_BROADCAST
2464 || fa->fa_type == RTN_MULTICAST)
2465 continue;
2466
2467 if (fi)
2468 snprintf(bf, sizeof(bf),
2469 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
2470 fi->fib_dev ? fi->fib_dev->name : "*",
2471 prefix,
2472 fi->fib_nh->nh_gw, flags, 0, 0,
2473 fi->fib_priority,
2474 mask,
2475 (fi->fib_advmss ? fi->fib_advmss + 40 : 0),
2476 fi->fib_window,
2477 fi->fib_rtt >> 3);
2478 else
2479 snprintf(bf, sizeof(bf),
2480 "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
2481 prefix, 0, flags, 0, 0, 0,
2482 mask, 0, 0, 0);
2483
2484 seq_printf(seq, "%-127s\n", bf);
2485 }
2486 }
2487
2488 return 0;
2489}
2490
Stephen Hemmingerf6908082007-03-12 14:34:29 -07002491static const struct seq_operations fib_route_seq_ops = {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002492 .start = fib_trie_seq_start,
2493 .next = fib_trie_seq_next,
2494 .stop = fib_trie_seq_stop,
2495 .show = fib_route_seq_show,
2496};
2497
2498static int fib_route_seq_open(struct inode *inode, struct file *file)
2499{
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002500 return seq_open_net(inode, file, &fib_route_seq_ops,
2501 sizeof(struct fib_trie_iter));
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002502}
2503
Arjan van de Ven9a321442007-02-12 00:55:35 -08002504static const struct file_operations fib_route_fops = {
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002505 .owner = THIS_MODULE,
2506 .open = fib_route_seq_open,
2507 .read = seq_read,
2508 .llseek = seq_lseek,
Denis V. Lunev1c340b22008-01-10 03:27:17 -08002509 .release = seq_release_net,
Robert Olsson19baf832005-06-21 12:43:18 -07002510};
2511
Denis V. Lunev61a02652008-01-10 03:21:09 -08002512int __net_init fib_proc_init(struct net *net)
Robert Olsson19baf832005-06-21 12:43:18 -07002513{
Denis V. Lunev61a02652008-01-10 03:21:09 -08002514 if (!proc_net_fops_create(net, "fib_trie", S_IRUGO, &fib_trie_fops))
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002515 goto out1;
2516
Denis V. Lunev61a02652008-01-10 03:21:09 -08002517 if (!proc_net_fops_create(net, "fib_triestat", S_IRUGO,
2518 &fib_triestat_fops))
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002519 goto out2;
2520
Denis V. Lunev61a02652008-01-10 03:21:09 -08002521 if (!proc_net_fops_create(net, "route", S_IRUGO, &fib_route_fops))
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002522 goto out3;
2523
Robert Olsson19baf832005-06-21 12:43:18 -07002524 return 0;
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002525
2526out3:
Denis V. Lunev61a02652008-01-10 03:21:09 -08002527 proc_net_remove(net, "fib_triestat");
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002528out2:
Denis V. Lunev61a02652008-01-10 03:21:09 -08002529 proc_net_remove(net, "fib_trie");
Stephen Hemmingercb7b5932005-09-09 13:35:42 -07002530out1:
2531 return -ENOMEM;
Robert Olsson19baf832005-06-21 12:43:18 -07002532}
2533
Denis V. Lunev61a02652008-01-10 03:21:09 -08002534void __net_exit fib_proc_exit(struct net *net)
Robert Olsson19baf832005-06-21 12:43:18 -07002535{
Denis V. Lunev61a02652008-01-10 03:21:09 -08002536 proc_net_remove(net, "fib_trie");
2537 proc_net_remove(net, "fib_triestat");
2538 proc_net_remove(net, "route");
Robert Olsson19baf832005-06-21 12:43:18 -07002539}
2540
2541#endif /* CONFIG_PROC_FS */