aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_frontend.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_frontend.c')
-rw-r--r--net/ipv4/fib_frontend.c102
1 files changed, 68 insertions, 34 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 2696ede52de2..ad4c14f968a1 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -37,6 +37,7 @@
37#include <linux/skbuff.h> 37#include <linux/skbuff.h>
38#include <linux/netlink.h> 38#include <linux/netlink.h>
39#include <linux/init.h> 39#include <linux/init.h>
40#include <linux/list.h>
40 41
41#include <net/ip.h> 42#include <net/ip.h>
42#include <net/protocol.h> 43#include <net/protocol.h>
@@ -51,48 +52,67 @@
51 52
52#ifndef CONFIG_IP_MULTIPLE_TABLES 53#ifndef CONFIG_IP_MULTIPLE_TABLES
53 54
54#define RT_TABLE_MIN RT_TABLE_MAIN
55
56struct fib_table *ip_fib_local_table; 55struct fib_table *ip_fib_local_table;
57struct fib_table *ip_fib_main_table; 56struct fib_table *ip_fib_main_table;
58 57
59#else 58#define FIB_TABLE_HASHSZ 1
59static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
60 60
61#define RT_TABLE_MIN 1 61#else
62 62
63struct fib_table *fib_tables[RT_TABLE_MAX+1]; 63#define FIB_TABLE_HASHSZ 256
64static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
64 65
65struct fib_table *__fib_new_table(u32 id) 66struct fib_table *fib_new_table(u32 id)
66{ 67{
67 struct fib_table *tb; 68 struct fib_table *tb;
69 unsigned int h;
68 70
71 if (id == 0)
72 id = RT_TABLE_MAIN;
73 tb = fib_get_table(id);
74 if (tb)
75 return tb;
69 tb = fib_hash_init(id); 76 tb = fib_hash_init(id);
70 if (!tb) 77 if (!tb)
71 return NULL; 78 return NULL;
72 fib_tables[id] = tb; 79 h = id & (FIB_TABLE_HASHSZ - 1);
80 hlist_add_head_rcu(&tb->tb_hlist, &fib_table_hash[h]);
73 return tb; 81 return tb;
74} 82}
75 83
84struct fib_table *fib_get_table(u32 id)
85{
86 struct fib_table *tb;
87 struct hlist_node *node;
88 unsigned int h;
76 89
90 if (id == 0)
91 id = RT_TABLE_MAIN;
92 h = id & (FIB_TABLE_HASHSZ - 1);
93 rcu_read_lock();
94 hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb_hlist) {
95 if (tb->tb_id == id) {
96 rcu_read_unlock();
97 return tb;
98 }
99 }
100 rcu_read_unlock();
101 return NULL;
102}
77#endif /* CONFIG_IP_MULTIPLE_TABLES */ 103#endif /* CONFIG_IP_MULTIPLE_TABLES */
78 104
79
80static void fib_flush(void) 105static void fib_flush(void)
81{ 106{
82 int flushed = 0; 107 int flushed = 0;
83#ifdef CONFIG_IP_MULTIPLE_TABLES
84 struct fib_table *tb; 108 struct fib_table *tb;
85 u32 id; 109 struct hlist_node *node;
110 unsigned int h;
86 111
87 for (id = RT_TABLE_MAX; id>0; id--) { 112 for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
88 if ((tb = fib_get_table(id))==NULL) 113 hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist)
89 continue; 114 flushed += tb->tb_flush(tb);
90 flushed += tb->tb_flush(tb);
91 } 115 }
92#else /* CONFIG_IP_MULTIPLE_TABLES */
93 flushed += ip_fib_main_table->tb_flush(ip_fib_main_table);
94 flushed += ip_fib_local_table->tb_flush(ip_fib_local_table);
95#endif /* CONFIG_IP_MULTIPLE_TABLES */
96 116
97 if (flushed) 117 if (flushed)
98 rt_cache_flush(-1); 118 rt_cache_flush(-1);
@@ -334,29 +354,37 @@ int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
334 354
335int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) 355int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
336{ 356{
337 u32 t; 357 unsigned int h, s_h;
338 u32 s_t; 358 unsigned int e = 0, s_e;
339 struct fib_table *tb; 359 struct fib_table *tb;
360 struct hlist_node *node;
361 int dumped = 0;
340 362
341 if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) && 363 if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
342 ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED) 364 ((struct rtmsg*)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
343 return ip_rt_dump(skb, cb); 365 return ip_rt_dump(skb, cb);
344 366
345 s_t = cb->args[0]; 367 s_h = cb->args[0];
346 if (s_t == 0) 368 s_e = cb->args[1];
347 s_t = cb->args[0] = RT_TABLE_MIN; 369
348 370 for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
349 for (t=s_t; t<=RT_TABLE_MAX; t++) { 371 e = 0;
350 if (t < s_t) continue; 372 hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist) {
351 if (t > s_t) 373 if (e < s_e)
352 memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0])); 374 goto next;
353 if ((tb = fib_get_table(t))==NULL) 375 if (dumped)
354 continue; 376 memset(&cb->args[2], 0, sizeof(cb->args) -
355 if (tb->tb_dump(tb, skb, cb) < 0) 377 2 * sizeof(cb->args[0]));
356 break; 378 if (tb->tb_dump(tb, skb, cb) < 0)
379 goto out;
380 dumped = 1;
381next:
382 e++;
383 }
357 } 384 }
358 385out:
359 cb->args[0] = t; 386 cb->args[1] = e;
387 cb->args[0] = h;
360 388
361 return skb->len; 389 return skb->len;
362} 390}
@@ -654,9 +682,15 @@ static struct notifier_block fib_netdev_notifier = {
654 682
655void __init ip_fib_init(void) 683void __init ip_fib_init(void)
656{ 684{
685 unsigned int i;
686
687 for (i = 0; i < FIB_TABLE_HASHSZ; i++)
688 INIT_HLIST_HEAD(&fib_table_hash[i]);
657#ifndef CONFIG_IP_MULTIPLE_TABLES 689#ifndef CONFIG_IP_MULTIPLE_TABLES
658 ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL); 690 ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL);
691 hlist_add_head_rcu(&ip_fib_local_table->tb_hlist, &fib_table_hash[0]);
659 ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN); 692 ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN);
693 hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]);
660#else 694#else
661 fib4_rules_init(); 695 fib4_rules_init();
662#endif 696#endif