diff options
Diffstat (limited to 'net/ipv4/fib_frontend.c')
-rw-r--r-- | net/ipv4/fib_frontend.c | 102 |
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 | |||
56 | struct fib_table *ip_fib_local_table; | 55 | struct fib_table *ip_fib_local_table; |
57 | struct fib_table *ip_fib_main_table; | 56 | struct fib_table *ip_fib_main_table; |
58 | 57 | ||
59 | #else | 58 | #define FIB_TABLE_HASHSZ 1 |
59 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | ||
60 | 60 | ||
61 | #define RT_TABLE_MIN 1 | 61 | #else |
62 | 62 | ||
63 | struct fib_table *fib_tables[RT_TABLE_MAX+1]; | 63 | #define FIB_TABLE_HASHSZ 256 |
64 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | ||
64 | 65 | ||
65 | struct fib_table *__fib_new_table(u32 id) | 66 | struct 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 | ||
84 | struct 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 | |||
80 | static void fib_flush(void) | 105 | static 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 | ||
335 | int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | 355 | int 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; | ||
381 | next: | ||
382 | e++; | ||
383 | } | ||
357 | } | 384 | } |
358 | 385 | out: | |
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 | ||
655 | void __init ip_fib_init(void) | 683 | void __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 |