aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/af_inet.c13
-rw-r--r--net/ipv4/fib_trie.c804
2 files changed, 385 insertions, 432 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index bf147f8db399..a9d84f93442c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1248,11 +1248,6 @@ module_init(inet_init);
1248/* ------------------------------------------------------------------------ */ 1248/* ------------------------------------------------------------------------ */
1249 1249
1250#ifdef CONFIG_PROC_FS 1250#ifdef CONFIG_PROC_FS
1251#ifdef CONFIG_IP_FIB_TRIE
1252extern int fib_stat_proc_init(void);
1253extern void fib_stat_proc_exit(void);
1254#endif
1255
1256static int __init ipv4_proc_init(void) 1251static int __init ipv4_proc_init(void)
1257{ 1252{
1258 int rc = 0; 1253 int rc = 0;
@@ -1265,19 +1260,11 @@ static int __init ipv4_proc_init(void)
1265 goto out_udp; 1260 goto out_udp;
1266 if (fib_proc_init()) 1261 if (fib_proc_init())
1267 goto out_fib; 1262 goto out_fib;
1268#ifdef CONFIG_IP_FIB_TRIE
1269 if (fib_stat_proc_init())
1270 goto out_fib_stat;
1271#endif
1272 if (ip_misc_proc_init()) 1263 if (ip_misc_proc_init())
1273 goto out_misc; 1264 goto out_misc;
1274out: 1265out:
1275 return rc; 1266 return rc;
1276out_misc: 1267out_misc:
1277#ifdef CONFIG_IP_FIB_TRIE
1278 fib_stat_proc_exit();
1279out_fib_stat:
1280#endif
1281 fib_proc_exit(); 1268 fib_proc_exit();
1282out_fib: 1269out_fib:
1283 udp4_proc_exit(); 1270 udp4_proc_exit();
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index b2dea4e5da77..1b63b4824164 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -43,7 +43,7 @@
43 * 2 of the License, or (at your option) any later version. 43 * 2 of the License, or (at your option) any later version.
44 */ 44 */
45 45
46#define VERSION "0.402" 46#define VERSION "0.403"
47 47
48#include <linux/config.h> 48#include <linux/config.h>
49#include <asm/uaccess.h> 49#include <asm/uaccess.h>
@@ -164,7 +164,6 @@ static struct node *resize(struct trie *t, struct tnode *tn);
164static struct tnode *inflate(struct trie *t, struct tnode *tn); 164static struct tnode *inflate(struct trie *t, struct tnode *tn);
165static struct tnode *halve(struct trie *t, struct tnode *tn); 165static struct tnode *halve(struct trie *t, struct tnode *tn);
166static void tnode_free(struct tnode *tn); 166static void tnode_free(struct tnode *tn);
167static void trie_dump_seq(struct seq_file *seq, struct trie *t);
168 167
169static kmem_cache_t *fn_alias_kmem __read_mostly; 168static kmem_cache_t *fn_alias_kmem __read_mostly;
170static struct trie *trie_local = NULL, *trie_main = NULL; 169static struct trie *trie_local = NULL, *trie_main = NULL;
@@ -1971,558 +1970,525 @@ struct fib_table * __init fib_hash_init(int id)
1971 return tb; 1970 return tb;
1972} 1971}
1973 1972
1974/* Trie dump functions */ 1973#ifdef CONFIG_PROC_FS
1974/* Depth first Trie walk iterator */
1975struct fib_trie_iter {
1976 struct tnode *tnode;
1977 struct trie *trie;
1978 unsigned index;
1979 unsigned depth;
1980};
1975 1981
1976static void putspace_seq(struct seq_file *seq, int n) 1982static struct node *fib_trie_get_next(struct fib_trie_iter *iter)
1977{ 1983{
1978 while (n--) 1984 struct tnode *tn = iter->tnode;
1979 seq_printf(seq, " "); 1985 unsigned cindex = iter->index;
1980} 1986 struct tnode *p;
1981 1987
1982static void printbin_seq(struct seq_file *seq, unsigned int v, int bits) 1988 pr_debug("get_next iter={node=%p index=%d depth=%d}\n",
1983{ 1989 iter->tnode, iter->index, iter->depth);
1984 while (bits--) 1990rescan:
1985 seq_printf(seq, "%s", (v & (1<<bits))?"1":"0"); 1991 while (cindex < (1<<tn->bits)) {
1986} 1992 struct node *n = tnode_get_child(tn, cindex);
1987 1993
1988static void printnode_seq(struct seq_file *seq, int indent, struct node *n, 1994 if (n) {
1989 int pend, int cindex, int bits) 1995 if (IS_LEAF(n)) {
1990{ 1996 iter->tnode = tn;
1991 putspace_seq(seq, indent); 1997 iter->index = cindex + 1;
1992 if (IS_LEAF(n)) 1998 } else {
1993 seq_printf(seq, "|"); 1999 /* push down one level */
1994 else 2000 iter->tnode = (struct tnode *) n;
1995 seq_printf(seq, "+"); 2001 iter->index = 0;
1996 if (bits) { 2002 ++iter->depth;
1997 seq_printf(seq, "%d/", cindex); 2003 }
1998 printbin_seq(seq, cindex, bits); 2004 return n;
1999 seq_printf(seq, ": "); 2005 }
2000 } else
2001 seq_printf(seq, "<root>: ");
2002 seq_printf(seq, "%s:%p ", IS_LEAF(n)?"Leaf":"Internal node", n);
2003 2006
2004 if (IS_LEAF(n)) { 2007 ++cindex;
2005 struct leaf *l = (struct leaf *)n; 2008 }
2006 struct fib_alias *fa;
2007 int i;
2008 2009
2009 seq_printf(seq, "key=%d.%d.%d.%d\n", 2010 /* Current node exhausted, pop back up */
2010 n->key >> 24, (n->key >> 16) % 256, (n->key >> 8) % 256, n->key % 256); 2011 p = NODE_PARENT(tn);
2011 2012 if (p) {
2012 for (i = 32; i >= 0; i--) 2013 cindex = tkey_extract_bits(tn->key, p->pos, p->bits)+1;
2013 if (find_leaf_info(&l->list, i)) { 2014 tn = p;
2014 struct list_head *fa_head = get_fa_head(l, i); 2015 --iter->depth;
2015 2016 goto rescan;
2016 if (!fa_head)
2017 continue;
2018
2019 if (list_empty(fa_head))
2020 continue;
2021
2022 putspace_seq(seq, indent+2);
2023 seq_printf(seq, "{/%d...dumping}\n", i);
2024
2025 list_for_each_entry_rcu(fa, fa_head, fa_list) {
2026 putspace_seq(seq, indent+2);
2027 if (fa->fa_info == NULL) {
2028 seq_printf(seq, "Error fa_info=NULL\n");
2029 continue;
2030 }
2031 if (fa->fa_info->fib_nh == NULL) {
2032 seq_printf(seq, "Error _fib_nh=NULL\n");
2033 continue;
2034 }
2035
2036 seq_printf(seq, "{type=%d scope=%d TOS=%d}\n",
2037 fa->fa_type,
2038 fa->fa_scope,
2039 fa->fa_tos);
2040 }
2041 }
2042 } else {
2043 struct tnode *tn = (struct tnode *)n;
2044 int plen = ((struct tnode *)n)->pos;
2045 t_key prf = MASK_PFX(n->key, plen);
2046
2047 seq_printf(seq, "key=%d.%d.%d.%d/%d\n",
2048 prf >> 24, (prf >> 16) % 256, (prf >> 8) % 256, prf % 256, plen);
2049
2050 putspace_seq(seq, indent); seq_printf(seq, "| ");
2051 seq_printf(seq, "{key prefix=%08x/", tn->key & TKEY_GET_MASK(0, tn->pos));
2052 printbin_seq(seq, tkey_extract_bits(tn->key, 0, tn->pos), tn->pos);
2053 seq_printf(seq, "}\n");
2054 putspace_seq(seq, indent); seq_printf(seq, "| ");
2055 seq_printf(seq, "{pos=%d", tn->pos);
2056 seq_printf(seq, " (skip=%d bits)", tn->pos - pend);
2057 seq_printf(seq, " bits=%d (%u children)}\n", tn->bits, (1 << tn->bits));
2058 putspace_seq(seq, indent); seq_printf(seq, "| ");
2059 seq_printf(seq, "{empty=%d full=%d}\n", tn->empty_children, tn->full_children);
2060 } 2017 }
2018
2019 /* got root? */
2020 return NULL;
2061} 2021}
2062 2022
2063static void trie_dump_seq(struct seq_file *seq, struct trie *t) 2023static struct node *fib_trie_get_first(struct fib_trie_iter *iter,
2024 struct trie *t)
2064{ 2025{
2065 struct node *n; 2026 struct node *n = rcu_dereference(t->trie);
2066 int cindex = 0;
2067 int indent = 1;
2068 int pend = 0;
2069 int depth = 0;
2070 struct tnode *tn;
2071
2072 rcu_read_lock();
2073 n = rcu_dereference(t->trie);
2074 seq_printf(seq, "------ trie_dump of t=%p ------\n", t);
2075 2027
2076 if (!n) { 2028 if (n && IS_TNODE(n)) {
2077 seq_printf(seq, "------ trie is empty\n"); 2029 iter->tnode = (struct tnode *) n;
2078 2030 iter->trie = t;
2079 rcu_read_unlock(); 2031 iter->index = 0;
2080 return; 2032 iter->depth = 0;
2033 return n;
2081 } 2034 }
2035 return NULL;
2036}
2082 2037
2083 printnode_seq(seq, indent, n, pend, cindex, 0); 2038static void trie_collect_stats(struct trie *t, struct trie_stat *s)
2084 2039{
2085 if (!IS_TNODE(n)) { 2040 struct node *n;
2086 rcu_read_unlock(); 2041 struct fib_trie_iter iter;
2087 return;
2088 }
2089
2090 tn = (struct tnode *)n;
2091 pend = tn->pos+tn->bits;
2092 putspace_seq(seq, indent); seq_printf(seq, "\\--\n");
2093 indent += 3;
2094 depth++;
2095
2096 while (tn && cindex < (1 << tn->bits)) {
2097 struct node *child = rcu_dereference(tn->child[cindex]);
2098 if (!child)
2099 cindex++;
2100 else {
2101 /* Got a child */
2102 printnode_seq(seq, indent, child, pend,
2103 cindex, tn->bits);
2104
2105 if (IS_LEAF(child))
2106 cindex++;
2107
2108 else {
2109 /*
2110 * New tnode. Decend one level
2111 */
2112
2113 depth++;
2114 n = child;
2115 tn = (struct tnode *)n;
2116 pend = tn->pos+tn->bits;
2117 putspace_seq(seq, indent);
2118 seq_printf(seq, "\\--\n");
2119 indent += 3;
2120 cindex = 0;
2121 }
2122 }
2123
2124 /*
2125 * Test if we are done
2126 */
2127
2128 while (cindex >= (1 << tn->bits)) {
2129 /*
2130 * Move upwards and test for root
2131 * pop off all traversed nodes
2132 */
2133 2042
2134 if (NODE_PARENT(tn) == NULL) { 2043 memset(s, 0, sizeof(*s));
2135 tn = NULL;
2136 break;
2137 }
2138 2044
2139 cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits); 2045 rcu_read_lock();
2140 cindex++; 2046 for (n = fib_trie_get_first(&iter, t); n;
2141 tn = NODE_PARENT(tn); 2047 n = fib_trie_get_next(&iter)) {
2142 pend = tn->pos + tn->bits; 2048 if (IS_LEAF(n)) {
2143 indent -= 3; 2049 s->leaves++;
2144 depth--; 2050 s->totdepth += iter.depth;
2051 if (iter.depth > s->maxdepth)
2052 s->maxdepth = iter.depth;
2053 } else {
2054 const struct tnode *tn = (const struct tnode *) n;
2055 int i;
2056
2057 s->tnodes++;
2058 s->nodesizes[tn->bits]++;
2059 for (i = 0; i < (1<<tn->bits); i++)
2060 if (!tn->child[i])
2061 s->nullpointers++;
2145 } 2062 }
2146 } 2063 }
2147 rcu_read_unlock(); 2064 rcu_read_unlock();
2148} 2065}
2149 2066
2150static struct trie_stat *trie_stat_new(void) 2067/*
2068 * This outputs /proc/net/fib_triestats
2069 */
2070static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
2151{ 2071{
2152 struct trie_stat *s; 2072 unsigned i, max, pointers, bytes, avdepth;
2153 int i;
2154 2073
2155 s = kmalloc(sizeof(struct trie_stat), GFP_KERNEL); 2074 if (stat->leaves)
2156 if (!s) 2075 avdepth = stat->totdepth*100 / stat->leaves;
2157 return NULL; 2076 else
2077 avdepth = 0;
2158 2078
2159 s->totdepth = 0; 2079 seq_printf(seq, "\tAver depth: %d.%02d\n", avdepth / 100, avdepth % 100 );
2160 s->maxdepth = 0; 2080 seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth);
2161 s->tnodes = 0;
2162 s->leaves = 0;
2163 s->nullpointers = 0;
2164 2081
2165 for (i = 0; i < MAX_CHILDS; i++) 2082 seq_printf(seq, "\tLeaves: %u\n", stat->leaves);
2166 s->nodesizes[i] = 0;
2167 2083
2168 return s; 2084 bytes = sizeof(struct leaf) * stat->leaves;
2169} 2085 seq_printf(seq, "\tInternal nodes: %d\n\t", stat->tnodes);
2086 bytes += sizeof(struct tnode) * stat->tnodes;
2170 2087
2171static struct trie_stat *trie_collect_stats(struct trie *t) 2088 max = MAX_CHILDS-1;
2172{ 2089 while (max >= 0 && stat->nodesizes[max] == 0)
2173 struct node *n; 2090 max--;
2174 struct trie_stat *s = trie_stat_new();
2175 int cindex = 0;
2176 int pend = 0;
2177 int depth = 0;
2178 2091
2179 if (!s) 2092 pointers = 0;
2180 return NULL; 2093 for (i = 1; i <= max; i++)
2094 if (stat->nodesizes[i] != 0) {
2095 seq_printf(seq, " %d: %d", i, stat->nodesizes[i]);
2096 pointers += (1<<i) * stat->nodesizes[i];
2097 }
2098 seq_putc(seq, '\n');
2099 seq_printf(seq, "\tPointers: %d\n", pointers);
2181 2100
2182 rcu_read_lock(); 2101 bytes += sizeof(struct node *) * pointers;
2183 n = rcu_dereference(t->trie); 2102 seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers);
2103 seq_printf(seq, "Total size: %d kB\n", (bytes + 1023) / 1024);
2184 2104
2185 if (!n) 2105#ifdef CONFIG_IP_FIB_TRIE_STATS
2186 return s; 2106 seq_printf(seq, "Counters:\n---------\n");
2107 seq_printf(seq,"gets = %d\n", t->stats.gets);
2108 seq_printf(seq,"backtracks = %d\n", t->stats.backtrack);
2109 seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
2110 seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
2111 seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
2112 seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);
2113#ifdef CLEAR_STATS
2114 memset(&(t->stats), 0, sizeof(t->stats));
2115#endif
2116#endif /* CONFIG_IP_FIB_TRIE_STATS */
2117}
2187 2118
2188 if (IS_TNODE(n)) { 2119static int fib_triestat_seq_show(struct seq_file *seq, void *v)
2189 struct tnode *tn = (struct tnode *)n; 2120{
2190 pend = tn->pos+tn->bits; 2121 struct trie_stat *stat;
2191 s->nodesizes[tn->bits]++;
2192 depth++;
2193
2194 while (tn && cindex < (1 << tn->bits)) {
2195 struct node *ch = rcu_dereference(tn->child[cindex]);
2196 if (ch) {
2197
2198 /* Got a child */
2199
2200 if (IS_LEAF(tn->child[cindex])) {
2201 cindex++;
2202
2203 /* stats */
2204 if (depth > s->maxdepth)
2205 s->maxdepth = depth;
2206 s->totdepth += depth;
2207 s->leaves++;
2208 } else {
2209 /*
2210 * New tnode. Decend one level
2211 */
2212
2213 s->tnodes++;
2214 s->nodesizes[tn->bits]++;
2215 depth++;
2216
2217 n = ch;
2218 tn = (struct tnode *)n;
2219 pend = tn->pos+tn->bits;
2220
2221 cindex = 0;
2222 }
2223 } else {
2224 cindex++;
2225 s->nullpointers++;
2226 }
2227 2122
2228 /* 2123 stat = kmalloc(sizeof(*stat), GFP_KERNEL);
2229 * Test if we are done 2124 if (!stat)
2230 */ 2125 return -ENOMEM;
2231 2126
2232 while (cindex >= (1 << tn->bits)) { 2127 seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n",
2233 /* 2128 sizeof(struct leaf), sizeof(struct tnode));
2234 * Move upwards and test for root
2235 * pop off all traversed nodes
2236 */
2237 2129
2238 if (NODE_PARENT(tn) == NULL) { 2130 if (trie_local) {
2239 tn = NULL; 2131 seq_printf(seq, "Local:\n");
2240 n = NULL; 2132 trie_collect_stats(trie_local, stat);
2241 break; 2133 trie_show_stats(seq, stat);
2242 } 2134 }
2243 2135
2244 cindex = tkey_extract_bits(tn->key, NODE_PARENT(tn)->pos, NODE_PARENT(tn)->bits); 2136 if (trie_main) {
2245 tn = NODE_PARENT(tn); 2137 seq_printf(seq, "Main:\n");
2246 cindex++; 2138 trie_collect_stats(trie_main, stat);
2247 n = (struct node *)tn; 2139 trie_show_stats(seq, stat);
2248 pend = tn->pos+tn->bits;
2249 depth--;
2250 }
2251 }
2252 } 2140 }
2141 kfree(stat);
2253 2142
2254 rcu_read_unlock(); 2143 return 0;
2255 return s;
2256} 2144}
2257 2145
2258#ifdef CONFIG_PROC_FS 2146static int fib_triestat_seq_open(struct inode *inode, struct file *file)
2259
2260static struct fib_alias *fib_triestat_get_first(struct seq_file *seq)
2261{ 2147{
2262 return NULL; 2148 return single_open(file, fib_triestat_seq_show, NULL);
2263} 2149}
2264 2150
2265static struct fib_alias *fib_triestat_get_next(struct seq_file *seq) 2151static struct file_operations fib_triestat_fops = {
2152 .owner = THIS_MODULE,
2153 .open = fib_triestat_seq_open,
2154 .read = seq_read,
2155 .llseek = seq_lseek,
2156 .release = single_release,
2157};
2158
2159static struct node *fib_trie_get_idx(struct fib_trie_iter *iter,
2160 loff_t pos)
2266{ 2161{
2162 loff_t idx = 0;
2163 struct node *n;
2164
2165 for (n = fib_trie_get_first(iter, trie_local);
2166 n; ++idx, n = fib_trie_get_next(iter)) {
2167 if (pos == idx)
2168 return n;
2169 }
2170
2171 for (n = fib_trie_get_first(iter, trie_main);
2172 n; ++idx, n = fib_trie_get_next(iter)) {
2173 if (pos == idx)
2174 return n;
2175 }
2267 return NULL; 2176 return NULL;
2268} 2177}
2269 2178
2270static void *fib_triestat_seq_start(struct seq_file *seq, loff_t *pos) 2179static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos)
2271{ 2180{
2272 if (!ip_fib_main_table) 2181 rcu_read_lock();
2273 return NULL; 2182 if (*pos == 0)
2274
2275 if (*pos)
2276 return fib_triestat_get_next(seq);
2277 else
2278 return SEQ_START_TOKEN; 2183 return SEQ_START_TOKEN;
2184 return fib_trie_get_idx(seq->private, *pos - 1);
2279} 2185}
2280 2186
2281static void *fib_triestat_seq_next(struct seq_file *seq, void *v, loff_t *pos) 2187static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos)
2282{ 2188{
2189 struct fib_trie_iter *iter = seq->private;
2190 void *l = v;
2191
2283 ++*pos; 2192 ++*pos;
2284 if (v == SEQ_START_TOKEN) 2193 if (v == SEQ_START_TOKEN)
2285 return fib_triestat_get_first(seq); 2194 return fib_trie_get_idx(iter, 0);
2286 else
2287 return fib_triestat_get_next(seq);
2288}
2289 2195
2290static void fib_triestat_seq_stop(struct seq_file *seq, void *v) 2196 v = fib_trie_get_next(iter);
2291{ 2197 BUG_ON(v == l);
2198 if (v)
2199 return v;
2292 2200
2293} 2201 /* continue scan in next trie */
2202 if (iter->trie == trie_local)
2203 return fib_trie_get_first(iter, trie_main);
2294 2204
2295/* 2205 return NULL;
2296 * This outputs /proc/net/fib_triestats 2206}
2297 *
2298 * It always works in backward compatibility mode.
2299 * The format of the file is not supposed to be changed.
2300 */
2301 2207
2302static void collect_and_show(struct trie *t, struct seq_file *seq) 2208static void fib_trie_seq_stop(struct seq_file *seq, void *v)
2303{ 2209{
2304 int bytes = 0; /* How many bytes are used, a ref is 4 bytes */ 2210 rcu_read_unlock();
2305 int i, max, pointers; 2211}
2306 struct trie_stat *stat;
2307 int avdepth;
2308
2309 stat = trie_collect_stats(t);
2310
2311 bytes = 0;
2312 seq_printf(seq, "trie=%p\n", t);
2313
2314 if (stat) {
2315 if (stat->leaves)
2316 avdepth = stat->totdepth*100 / stat->leaves;
2317 else
2318 avdepth = 0;
2319 seq_printf(seq, "Aver depth: %d.%02d\n", avdepth / 100, avdepth % 100);
2320 seq_printf(seq, "Max depth: %4d\n", stat->maxdepth);
2321 2212
2322 seq_printf(seq, "Leaves: %d\n", stat->leaves); 2213static void seq_indent(struct seq_file *seq, int n)
2323 bytes += sizeof(struct leaf) * stat->leaves; 2214{
2324 seq_printf(seq, "Internal nodes: %d\n", stat->tnodes); 2215 while (n-- > 0) seq_puts(seq, " ");
2325 bytes += sizeof(struct tnode) * stat->tnodes; 2216}
2326 2217
2327 max = MAX_CHILDS-1; 2218static inline const char *rtn_scope(enum rt_scope_t s)
2219{
2220 static char buf[32];
2328 2221
2329 while (max >= 0 && stat->nodesizes[max] == 0) 2222 switch(s) {
2330 max--; 2223 case RT_SCOPE_UNIVERSE: return "universe";
2331 pointers = 0; 2224 case RT_SCOPE_SITE: return "site";
2225 case RT_SCOPE_LINK: return "link";
2226 case RT_SCOPE_HOST: return "host";
2227 case RT_SCOPE_NOWHERE: return "nowhere";
2228 default:
2229 snprintf(buf, sizeof(buf), "scope=%d", s);
2230 return buf;
2231 }
2232}
2332 2233
2333 for (i = 1; i <= max; i++) 2234static const char *rtn_type_names[__RTN_MAX] = {
2334 if (stat->nodesizes[i] != 0) { 2235 [RTN_UNSPEC] = "UNSPEC",
2335 seq_printf(seq, " %d: %d", i, stat->nodesizes[i]); 2236 [RTN_UNICAST] = "UNICAST",
2336 pointers += (1<<i) * stat->nodesizes[i]; 2237 [RTN_LOCAL] = "LOCAL",
2337 } 2238 [RTN_BROADCAST] = "BROADCAST",
2338 seq_printf(seq, "\n"); 2239 [RTN_ANYCAST] = "ANYCAST",
2339 seq_printf(seq, "Pointers: %d\n", pointers); 2240 [RTN_MULTICAST] = "MULTICAST",
2340 bytes += sizeof(struct node *) * pointers; 2241 [RTN_BLACKHOLE] = "BLACKHOLE",
2341 seq_printf(seq, "Null ptrs: %d\n", stat->nullpointers); 2242 [RTN_UNREACHABLE] = "UNREACHABLE",
2342 seq_printf(seq, "Total size: %d kB\n", bytes / 1024); 2243 [RTN_PROHIBIT] = "PROHIBIT",
2244 [RTN_THROW] = "THROW",
2245 [RTN_NAT] = "NAT",
2246 [RTN_XRESOLVE] = "XRESOLVE",
2247};
2343 2248
2344 kfree(stat); 2249static inline const char *rtn_type(unsigned t)
2345 } 2250{
2251 static char buf[32];
2346 2252
2347#ifdef CONFIG_IP_FIB_TRIE_STATS 2253 if (t < __RTN_MAX && rtn_type_names[t])
2348 seq_printf(seq, "Counters:\n---------\n"); 2254 return rtn_type_names[t];
2349 seq_printf(seq,"gets = %d\n", t->stats.gets); 2255 snprintf(buf, sizeof(buf), "type %d", t);
2350 seq_printf(seq,"backtracks = %d\n", t->stats.backtrack); 2256 return buf;
2351 seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
2352 seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
2353 seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
2354 seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);
2355#ifdef CLEAR_STATS
2356 memset(&(t->stats), 0, sizeof(t->stats));
2357#endif
2358#endif /* CONFIG_IP_FIB_TRIE_STATS */
2359} 2257}
2360 2258
2361static int fib_triestat_seq_show(struct seq_file *seq, void *v) 2259/* Pretty print the trie */
2260static int fib_trie_seq_show(struct seq_file *seq, void *v)
2362{ 2261{
2363 char bf[128]; 2262 const struct fib_trie_iter *iter = seq->private;
2263 struct node *n = v;
2364 2264
2365 if (v == SEQ_START_TOKEN) { 2265 if (v == SEQ_START_TOKEN)
2366 seq_printf(seq, "Basic info: size of leaf: %Zd bytes, size of tnode: %Zd bytes.\n", 2266 return 0;
2367 sizeof(struct leaf), sizeof(struct tnode));
2368 if (trie_local)
2369 collect_and_show(trie_local, seq);
2370 2267
2371 if (trie_main) 2268 if (IS_TNODE(n)) {
2372 collect_and_show(trie_main, seq); 2269 struct tnode *tn = (struct tnode *) n;
2373 } else { 2270 t_key prf = ntohl(MASK_PFX(tn->key, tn->pos));
2374 snprintf(bf, sizeof(bf), "*\t%08X\t%08X", 200, 400);
2375 2271
2376 seq_printf(seq, "%-127s\n", bf); 2272 if (!NODE_PARENT(n)) {
2273 if (iter->trie == trie_local)
2274 seq_puts(seq, "<local>:\n");
2275 else
2276 seq_puts(seq, "<main>:\n");
2277 } else {
2278 seq_indent(seq, iter->depth-1);
2279 seq_printf(seq, " +-- %d.%d.%d.%d/%d\n",
2280 NIPQUAD(prf), tn->pos);
2281 }
2282 } else {
2283 struct leaf *l = (struct leaf *) n;
2284 int i;
2285 u32 val = ntohl(l->key);
2286
2287 seq_indent(seq, iter->depth);
2288 seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));
2289 for (i = 32; i >= 0; i--) {
2290 struct leaf_info *li = find_leaf_info(&l->list, i);
2291 if (li) {
2292 struct fib_alias *fa;
2293 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
2294 seq_indent(seq, iter->depth+1);
2295 seq_printf(seq, " /%d %s %s", i,
2296 rtn_scope(fa->fa_scope),
2297 rtn_type(fa->fa_type));
2298 if (fa->fa_tos)
2299 seq_printf(seq, "tos =%d\n",
2300 fa->fa_tos);
2301 seq_putc(seq, '\n');
2302 }
2303 }
2304 }
2377 } 2305 }
2306
2378 return 0; 2307 return 0;
2379} 2308}
2380 2309
2381static struct seq_operations fib_triestat_seq_ops = { 2310static struct seq_operations fib_trie_seq_ops = {
2382 .start = fib_triestat_seq_start, 2311 .start = fib_trie_seq_start,
2383 .next = fib_triestat_seq_next, 2312 .next = fib_trie_seq_next,
2384 .stop = fib_triestat_seq_stop, 2313 .stop = fib_trie_seq_stop,
2385 .show = fib_triestat_seq_show, 2314 .show = fib_trie_seq_show,
2386}; 2315};
2387 2316
2388static int fib_triestat_seq_open(struct inode *inode, struct file *file) 2317static int fib_trie_seq_open(struct inode *inode, struct file *file)
2389{ 2318{
2390 struct seq_file *seq; 2319 struct seq_file *seq;
2391 int rc = -ENOMEM; 2320 int rc = -ENOMEM;
2321 struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
2392 2322
2393 rc = seq_open(file, &fib_triestat_seq_ops); 2323 if (!s)
2324 goto out;
2325
2326 rc = seq_open(file, &fib_trie_seq_ops);
2394 if (rc) 2327 if (rc)
2395 goto out_kfree; 2328 goto out_kfree;
2396 2329
2397 seq = file->private_data; 2330 seq = file->private_data;
2331 seq->private = s;
2332 memset(s, 0, sizeof(*s));
2398out: 2333out:
2399 return rc; 2334 return rc;
2400out_kfree: 2335out_kfree:
2336 kfree(s);
2401 goto out; 2337 goto out;
2402} 2338}
2403 2339
2404static struct file_operations fib_triestat_seq_fops = { 2340static struct file_operations fib_trie_fops = {
2405 .owner = THIS_MODULE, 2341 .owner = THIS_MODULE,
2406 .open = fib_triestat_seq_open, 2342 .open = fib_trie_seq_open,
2407 .read = seq_read, 2343 .read = seq_read,
2408 .llseek = seq_lseek, 2344 .llseek = seq_lseek,
2409 .release = seq_release_private, 2345 .release = seq_release_private,
2410}; 2346};
2411 2347
2412int __init fib_stat_proc_init(void) 2348static unsigned fib_flag_trans(int type, u32 mask, const struct fib_info *fi)
2413{
2414 if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_seq_fops))
2415 return -ENOMEM;
2416 return 0;
2417}
2418
2419void __init fib_stat_proc_exit(void)
2420{ 2349{
2421 proc_net_remove("fib_triestat"); 2350 static unsigned type2flags[RTN_MAX + 1] = {
2422} 2351 [7] = RTF_REJECT, [8] = RTF_REJECT,
2352 };
2353 unsigned flags = type2flags[type];
2423 2354
2424static struct fib_alias *fib_trie_get_first(struct seq_file *seq) 2355 if (fi && fi->fib_nh->nh_gw)
2425{ 2356 flags |= RTF_GATEWAY;
2426 return NULL; 2357 if (mask == 0xFFFFFFFF)
2358 flags |= RTF_HOST;
2359 flags |= RTF_UP;
2360 return flags;
2427} 2361}
2428 2362
2429static struct fib_alias *fib_trie_get_next(struct seq_file *seq) 2363/*
2364 * This outputs /proc/net/route.
2365 * The format of the file is not supposed to be changed
2366 * and needs to be same as fib_hash output to avoid breaking
2367 * legacy utilities
2368 */
2369static int fib_route_seq_show(struct seq_file *seq, void *v)
2430{ 2370{
2431 return NULL; 2371 struct leaf *l = v;
2432} 2372 int i;
2373 char bf[128];
2433 2374
2434static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) 2375 if (v == SEQ_START_TOKEN) {
2435{ 2376 seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "
2436 if (!ip_fib_main_table) 2377 "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
2437 return NULL; 2378 "\tWindow\tIRTT");
2379 return 0;
2380 }
2438 2381
2439 if (*pos) 2382 if (IS_TNODE(l))
2440 return fib_trie_get_next(seq); 2383 return 0;
2441 else
2442 return SEQ_START_TOKEN;
2443}
2444 2384
2445static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) 2385 for (i=32; i>=0; i--) {
2446{ 2386 struct leaf_info *li = find_leaf_info(&l->list, i);
2447 ++*pos; 2387 struct fib_alias *fa;
2448 if (v == SEQ_START_TOKEN) 2388 u32 mask, prefix;
2449 return fib_trie_get_first(seq);
2450 else
2451 return fib_trie_get_next(seq);
2452 2389
2453} 2390 if (!li)
2391 continue;
2454 2392
2455static void fib_trie_seq_stop(struct seq_file *seq, void *v) 2393 mask = inet_make_mask(li->plen);
2456{ 2394 prefix = htonl(l->key);
2457}
2458 2395
2459/* 2396 list_for_each_entry_rcu(fa, &li->falh, fa_list) {
2460 * This outputs /proc/net/fib_trie. 2397 const struct fib_info *fi = rcu_dereference(fa->fa_info);
2461 * 2398 unsigned flags = fib_flag_trans(fa->fa_type, mask, fi);
2462 * It always works in backward compatibility mode.
2463 * The format of the file is not supposed to be changed.
2464 */
2465 2399
2466static int fib_trie_seq_show(struct seq_file *seq, void *v) 2400 if (fa->fa_type == RTN_BROADCAST
2467{ 2401 || fa->fa_type == RTN_MULTICAST)
2468 char bf[128]; 2402 continue;
2469 2403
2470 if (v == SEQ_START_TOKEN) { 2404 if (fi)
2471 if (trie_local) 2405 snprintf(bf, sizeof(bf),
2472 trie_dump_seq(seq, trie_local); 2406 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
2407 fi->fib_dev ? fi->fib_dev->name : "*",
2408 prefix,
2409 fi->fib_nh->nh_gw, flags, 0, 0,
2410 fi->fib_priority,
2411 mask,
2412 (fi->fib_advmss ? fi->fib_advmss + 40 : 0),
2413 fi->fib_window,
2414 fi->fib_rtt >> 3);
2415 else
2416 snprintf(bf, sizeof(bf),
2417 "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
2418 prefix, 0, flags, 0, 0, 0,
2419 mask, 0, 0, 0);
2473 2420
2474 if (trie_main) 2421 seq_printf(seq, "%-127s\n", bf);
2475 trie_dump_seq(seq, trie_main); 2422 }
2476 } else {
2477 snprintf(bf, sizeof(bf),
2478 "*\t%08X\t%08X", 200, 400);
2479 seq_printf(seq, "%-127s\n", bf);
2480 } 2423 }
2481 2424
2482 return 0; 2425 return 0;
2483} 2426}
2484 2427
2485static struct seq_operations fib_trie_seq_ops = { 2428static struct seq_operations fib_route_seq_ops = {
2486 .start = fib_trie_seq_start, 2429 .start = fib_trie_seq_start,
2487 .next = fib_trie_seq_next, 2430 .next = fib_trie_seq_next,
2488 .stop = fib_trie_seq_stop, 2431 .stop = fib_trie_seq_stop,
2489 .show = fib_trie_seq_show, 2432 .show = fib_route_seq_show,
2490}; 2433};
2491 2434
2492static int fib_trie_seq_open(struct inode *inode, struct file *file) 2435static int fib_route_seq_open(struct inode *inode, struct file *file)
2493{ 2436{
2494 struct seq_file *seq; 2437 struct seq_file *seq;
2495 int rc = -ENOMEM; 2438 int rc = -ENOMEM;
2439 struct fib_trie_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
2496 2440
2497 rc = seq_open(file, &fib_trie_seq_ops); 2441 if (!s)
2442 goto out;
2443
2444 rc = seq_open(file, &fib_route_seq_ops);
2498 if (rc) 2445 if (rc)
2499 goto out_kfree; 2446 goto out_kfree;
2500 2447
2501 seq = file->private_data; 2448 seq = file->private_data;
2449 seq->private = s;
2450 memset(s, 0, sizeof(*s));
2502out: 2451out:
2503 return rc; 2452 return rc;
2504out_kfree: 2453out_kfree:
2454 kfree(s);
2505 goto out; 2455 goto out;
2506} 2456}
2507 2457
2508static struct file_operations fib_trie_seq_fops = { 2458static struct file_operations fib_route_fops = {
2509 .owner = THIS_MODULE, 2459 .owner = THIS_MODULE,
2510 .open = fib_trie_seq_open, 2460 .open = fib_route_seq_open,
2511 .read = seq_read, 2461 .read = seq_read,
2512 .llseek = seq_lseek, 2462 .llseek = seq_lseek,
2513 .release= seq_release_private, 2463 .release = seq_release_private,
2514}; 2464};
2515 2465
2516int __init fib_proc_init(void) 2466int __init fib_proc_init(void)
2517{ 2467{
2518 if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_seq_fops)) 2468 if (!proc_net_fops_create("fib_trie", S_IRUGO, &fib_trie_fops))
2519 return -ENOMEM; 2469 goto out1;
2470
2471 if (!proc_net_fops_create("fib_triestat", S_IRUGO, &fib_triestat_fops))
2472 goto out2;
2473
2474 if (!proc_net_fops_create("route", S_IRUGO, &fib_route_fops))
2475 goto out3;
2476
2520 return 0; 2477 return 0;
2478
2479out3:
2480 proc_net_remove("fib_triestat");
2481out2:
2482 proc_net_remove("fib_trie");
2483out1:
2484 return -ENOMEM;
2521} 2485}
2522 2486
2523void __init fib_proc_exit(void) 2487void __init fib_proc_exit(void)
2524{ 2488{
2525 proc_net_remove("fib_trie"); 2489 proc_net_remove("fib_trie");
2490 proc_net_remove("fib_triestat");
2491 proc_net_remove("route");
2526} 2492}
2527 2493
2528#endif /* CONFIG_PROC_FS */ 2494#endif /* CONFIG_PROC_FS */