aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2006-08-05 02:20:06 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-09-22 17:53:39 -0400
commitc71099acce933455123ee505cc75964610a209ad (patch)
treecf167c926350ff6c4040289dacce54849824c240
parent5d0bbeeb144f631150881712607345c532e38e7e (diff)
[IPV6]: Multiple Routing Tables
Adds the framework to support multiple IPv6 routing tables. Currently all automatically generated routes are put into the same table. This could be changed at a later point after considering the produced locking overhead. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/ip6_fib.h39
-rw-r--r--include/net/ip6_route.h3
-rw-r--r--net/ipv6/Kconfig6
-rw-r--r--net/ipv6/addrconf.c6
-rw-r--r--net/ipv6/ip6_fib.c144
-rw-r--r--net/ipv6/route.c380
6 files changed, 441 insertions, 137 deletions
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index a66e9de16a6c..818411519c89 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -51,6 +51,8 @@ struct rt6key
51 int plen; 51 int plen;
52}; 52};
53 53
54struct fib6_table;
55
54struct rt6_info 56struct rt6_info
55{ 57{
56 union { 58 union {
@@ -71,6 +73,7 @@ struct rt6_info
71 u32 rt6i_flags; 73 u32 rt6i_flags;
72 u32 rt6i_metric; 74 u32 rt6i_metric;
73 atomic_t rt6i_ref; 75 atomic_t rt6i_ref;
76 struct fib6_table *rt6i_table;
74 77
75 struct rt6key rt6i_dst; 78 struct rt6key rt6i_dst;
76 struct rt6key rt6i_src; 79 struct rt6key rt6i_src;
@@ -143,12 +146,43 @@ struct rt6_statistics {
143 146
144typedef void (*f_pnode)(struct fib6_node *fn, void *); 147typedef void (*f_pnode)(struct fib6_node *fn, void *);
145 148
146extern struct fib6_node ip6_routing_table; 149struct fib6_table {
150 struct hlist_node tb6_hlist;
151 u32 tb6_id;
152 rwlock_t tb6_lock;
153 struct fib6_node tb6_root;
154};
155
156#define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC
157#define RT6_TABLE_MAIN RT_TABLE_MAIN
158#define RT6_TABLE_LOCAL RT6_TABLE_MAIN
159#define RT6_TABLE_DFLT RT6_TABLE_MAIN
160#define RT6_TABLE_INFO RT6_TABLE_MAIN
161#define RT6_TABLE_PREFIX RT6_TABLE_MAIN
162
163#ifdef CONFIG_IPV6_MULTIPLE_TABLES
164#define FIB6_TABLE_MIN 1
165#define FIB6_TABLE_MAX RT_TABLE_MAX
166#else
167#define FIB6_TABLE_MIN RT_TABLE_MAIN
168#define FIB6_TABLE_MAX FIB6_TABLE_MIN
169#endif
170
171#define RT6_F_STRICT 1
172#define RT6_F_HAS_SADDR 2
173
174typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *,
175 struct flowi *, int);
147 176
148/* 177/*
149 * exported functions 178 * exported functions
150 */ 179 */
151 180
181extern struct fib6_table * fib6_get_table(u32 id);
182extern struct fib6_table * fib6_new_table(u32 id);
183extern struct dst_entry * fib6_rule_lookup(struct flowi *fl, int flags,
184 pol_lookup_t lookup);
185
152extern struct fib6_node *fib6_lookup(struct fib6_node *root, 186extern struct fib6_node *fib6_lookup(struct fib6_node *root,
153 struct in6_addr *daddr, 187 struct in6_addr *daddr,
154 struct in6_addr *saddr); 188 struct in6_addr *saddr);
@@ -161,6 +195,9 @@ extern void fib6_clean_tree(struct fib6_node *root,
161 int (*func)(struct rt6_info *, void *arg), 195 int (*func)(struct rt6_info *, void *arg),
162 int prune, void *arg); 196 int prune, void *arg);
163 197
198extern void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
199 int prune, void *arg);
200
164extern int fib6_walk(struct fib6_walker_t *w); 201extern int fib6_walk(struct fib6_walker_t *w);
165extern int fib6_walk_continue(struct fib6_walker_t *w); 202extern int fib6_walk_continue(struct fib6_walker_t *w);
166 203
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 96b0e66406ec..d49c8c90eb68 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -58,7 +58,8 @@ extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg);
58extern int ip6_route_add(struct in6_rtmsg *rtmsg, 58extern int ip6_route_add(struct in6_rtmsg *rtmsg,
59 struct nlmsghdr *, 59 struct nlmsghdr *,
60 void *rtattr, 60 void *rtattr,
61 struct netlink_skb_parms *req); 61 struct netlink_skb_parms *req,
62 u32 table_id);
62extern int ip6_ins_rt(struct rt6_info *, 63extern int ip6_ins_rt(struct rt6_info *,
63 struct nlmsghdr *, 64 struct nlmsghdr *,
64 void *rtattr, 65 void *rtattr,
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 0ba06c0c5d39..159c63d99c81 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -136,3 +136,9 @@ config IPV6_TUNNEL
136 136
137 If unsure, say N. 137 If unsure, say N.
138 138
139config IPV6_MULTIPLE_TABLES
140 bool "IPv6: Multiple Routing Tables"
141 depends on IPV6 && EXPERIMENTAL
142 ---help---
143 Support multiple routing tables.
144
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c7852b38e03e..318767fcefdc 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1525,7 +1525,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
1525 if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT)) 1525 if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))
1526 rtmsg.rtmsg_flags |= RTF_NONEXTHOP; 1526 rtmsg.rtmsg_flags |= RTF_NONEXTHOP;
1527 1527
1528 ip6_route_add(&rtmsg, NULL, NULL, NULL); 1528 ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_PREFIX);
1529} 1529}
1530 1530
1531/* Create "default" multicast route to the interface */ 1531/* Create "default" multicast route to the interface */
@@ -1542,7 +1542,7 @@ static void addrconf_add_mroute(struct net_device *dev)
1542 rtmsg.rtmsg_ifindex = dev->ifindex; 1542 rtmsg.rtmsg_ifindex = dev->ifindex;
1543 rtmsg.rtmsg_flags = RTF_UP; 1543 rtmsg.rtmsg_flags = RTF_UP;
1544 rtmsg.rtmsg_type = RTMSG_NEWROUTE; 1544 rtmsg.rtmsg_type = RTMSG_NEWROUTE;
1545 ip6_route_add(&rtmsg, NULL, NULL, NULL); 1545 ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_LOCAL);
1546} 1546}
1547 1547
1548static void sit_route_add(struct net_device *dev) 1548static void sit_route_add(struct net_device *dev)
@@ -1559,7 +1559,7 @@ static void sit_route_add(struct net_device *dev)
1559 rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; 1559 rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP;
1560 rtmsg.rtmsg_ifindex = dev->ifindex; 1560 rtmsg.rtmsg_ifindex = dev->ifindex;
1561 1561
1562 ip6_route_add(&rtmsg, NULL, NULL, NULL); 1562 ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_MAIN);
1563} 1563}
1564 1564
1565static void addrconf_add_lroute(struct net_device *dev) 1565static void addrconf_add_lroute(struct net_device *dev)
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 764221220afd..fcd7da830aca 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -26,6 +26,7 @@
26#include <linux/netdevice.h> 26#include <linux/netdevice.h>
27#include <linux/in6.h> 27#include <linux/in6.h>
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/list.h>
29 30
30#ifdef CONFIG_PROC_FS 31#ifdef CONFIG_PROC_FS
31#include <linux/proc_fs.h> 32#include <linux/proc_fs.h>
@@ -147,6 +148,126 @@ static __inline__ void rt6_release(struct rt6_info *rt)
147 dst_free(&rt->u.dst); 148 dst_free(&rt->u.dst);
148} 149}
149 150
151static struct fib6_table fib6_main_tbl = {
152 .tb6_id = RT6_TABLE_MAIN,
153 .tb6_lock = RW_LOCK_UNLOCKED,
154 .tb6_root = {
155 .leaf = &ip6_null_entry,
156 .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
157 },
158};
159
160#ifdef CONFIG_IPV6_MULTIPLE_TABLES
161
162#define FIB_TABLE_HASHSZ 256
163static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
164
165static struct fib6_table *fib6_alloc_table(u32 id)
166{
167 struct fib6_table *table;
168
169 table = kzalloc(sizeof(*table), GFP_ATOMIC);
170 if (table != NULL) {
171 table->tb6_id = id;
172 table->tb6_lock = RW_LOCK_UNLOCKED;
173 table->tb6_root.leaf = &ip6_null_entry;
174 table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO;
175 }
176
177 return table;
178}
179
180static void fib6_link_table(struct fib6_table *tb)
181{
182 unsigned int h;
183
184 h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1);
185
186 /*
187 * No protection necessary, this is the only list mutatation
188 * operation, tables never disappear once they exist.
189 */
190 hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
191}
192
193struct fib6_table *fib6_new_table(u32 id)
194{
195 struct fib6_table *tb;
196
197 if (id == 0)
198 id = RT6_TABLE_MAIN;
199 tb = fib6_get_table(id);
200 if (tb)
201 return tb;
202
203 tb = fib6_alloc_table(id);
204 if (tb != NULL)
205 fib6_link_table(tb);
206
207 return tb;
208}
209
210struct fib6_table *fib6_get_table(u32 id)
211{
212 struct fib6_table *tb;
213 struct hlist_node *node;
214 unsigned int h;
215
216 if (id == 0)
217 id = RT6_TABLE_MAIN;
218 h = id & (FIB_TABLE_HASHSZ - 1);
219 rcu_read_lock();
220 hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) {
221 if (tb->tb6_id == id) {
222 rcu_read_unlock();
223 return tb;
224 }
225 }
226 rcu_read_unlock();
227
228 return NULL;
229}
230
231struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
232 pol_lookup_t lookup)
233{
234 /*
235 * TODO: Add rule lookup
236 */
237 struct fib6_table *table = fib6_get_table(RT6_TABLE_MAIN);
238
239 return (struct dst_entry *) lookup(table, fl, flags);
240}
241
242static void __init fib6_tables_init(void)
243{
244 fib6_link_table(&fib6_main_tbl);
245}
246
247#else
248
249struct fib6_table *fib6_new_table(u32 id)
250{
251 return fib6_get_table(id);
252}
253
254struct fib6_table *fib6_get_table(u32 id)
255{
256 return &fib6_main_tbl;
257}
258
259struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
260 pol_lookup_t lookup)
261{
262 return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags);
263}
264
265static void __init fib6_tables_init(void)
266{
267}
268
269#endif
270
150 271
151/* 272/*
152 * Routing Table 273 * Routing Table
@@ -1064,6 +1185,22 @@ void fib6_clean_tree(struct fib6_node *root,
1064 fib6_walk(&c.w); 1185 fib6_walk(&c.w);
1065} 1186}
1066 1187
1188void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
1189 int prune, void *arg)
1190{
1191 int i;
1192 struct fib6_table *table;
1193
1194 for (i = FIB6_TABLE_MIN; i <= FIB6_TABLE_MAX; i++) {
1195 table = fib6_get_table(i);
1196 if (table != NULL) {
1197 write_lock_bh(&table->tb6_lock);
1198 fib6_clean_tree(&table->tb6_root, func, prune, arg);
1199 write_unlock_bh(&table->tb6_lock);
1200 }
1201 }
1202}
1203
1067static int fib6_prune_clone(struct rt6_info *rt, void *arg) 1204static int fib6_prune_clone(struct rt6_info *rt, void *arg)
1068{ 1205{
1069 if (rt->rt6i_flags & RTF_CACHE) { 1206 if (rt->rt6i_flags & RTF_CACHE) {
@@ -1142,11 +1279,8 @@ void fib6_run_gc(unsigned long dummy)
1142 } 1279 }
1143 gc_args.more = 0; 1280 gc_args.more = 0;
1144 1281
1145
1146 write_lock_bh(&rt6_lock);
1147 ndisc_dst_gc(&gc_args.more); 1282 ndisc_dst_gc(&gc_args.more);
1148 fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); 1283 fib6_clean_all(fib6_age, 0, NULL);
1149 write_unlock_bh(&rt6_lock);
1150 1284
1151 if (gc_args.more) 1285 if (gc_args.more)
1152 mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); 1286 mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
@@ -1165,6 +1299,8 @@ void __init fib6_init(void)
1165 NULL, NULL); 1299 NULL, NULL);
1166 if (!fib6_node_kmem) 1300 if (!fib6_node_kmem)
1167 panic("cannot create fib6_nodes cache"); 1301 panic("cannot create fib6_nodes cache");
1302
1303 fib6_tables_init();
1168} 1304}
1169 1305
1170void fib6_gc_cleanup(void) 1306void fib6_gc_cleanup(void)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index ce1f49b595b0..73efdadb9ab8 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -140,16 +140,6 @@ struct rt6_info ip6_null_entry = {
140 .rt6i_ref = ATOMIC_INIT(1), 140 .rt6i_ref = ATOMIC_INIT(1),
141}; 141};
142 142
143struct fib6_node ip6_routing_table = {
144 .leaf = &ip6_null_entry,
145 .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
146};
147
148/* Protects all the ip6 fib */
149
150DEFINE_RWLOCK(rt6_lock);
151
152
153/* allocate dst with ip6_dst_ops */ 143/* allocate dst with ip6_dst_ops */
154static __inline__ struct rt6_info *ip6_dst_alloc(void) 144static __inline__ struct rt6_info *ip6_dst_alloc(void)
155{ 145{
@@ -188,8 +178,14 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt)
188 time_after(jiffies, rt->rt6i_expires)); 178 time_after(jiffies, rt->rt6i_expires));
189} 179}
190 180
181static inline int rt6_need_strict(struct in6_addr *daddr)
182{
183 return (ipv6_addr_type(daddr) &
184 (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
185}
186
191/* 187/*
192 * Route lookup. Any rt6_lock is implied. 188 * Route lookup. Any table->tb6_lock is implied.
193 */ 189 */
194 190
195static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, 191static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
@@ -441,27 +437,66 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
441} 437}
442#endif 438#endif
443 439
444struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, 440#define BACKTRACK() \
445 int oif, int strict) 441if (rt == &ip6_null_entry && flags & RT6_F_STRICT) { \
442 while ((fn = fn->parent) != NULL) { \
443 if (fn->fn_flags & RTN_TL_ROOT) { \
444 dst_hold(&rt->u.dst); \
445 goto out; \
446 } \
447 if (fn->fn_flags & RTN_RTINFO) \
448 goto restart; \
449 } \
450}
451
452static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table,
453 struct flowi *fl, int flags)
446{ 454{
447 struct fib6_node *fn; 455 struct fib6_node *fn;
448 struct rt6_info *rt; 456 struct rt6_info *rt;
449 457
450 read_lock_bh(&rt6_lock); 458 read_lock_bh(&table->tb6_lock);
451 fn = fib6_lookup(&ip6_routing_table, daddr, saddr); 459 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
452 rt = rt6_device_match(fn->leaf, oif, strict); 460restart:
461 rt = fn->leaf;
462 rt = rt6_device_match(rt, fl->oif, flags & RT6_F_STRICT);
463 BACKTRACK();
453 dst_hold(&rt->u.dst); 464 dst_hold(&rt->u.dst);
454 rt->u.dst.__use++; 465out:
455 read_unlock_bh(&rt6_lock); 466 read_unlock_bh(&table->tb6_lock);
456 467
457 rt->u.dst.lastuse = jiffies; 468 rt->u.dst.lastuse = jiffies;
458 if (rt->u.dst.error == 0) 469 rt->u.dst.__use++;
459 return rt; 470
460 dst_release(&rt->u.dst); 471 return rt;
472
473}
474
475struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
476 int oif, int strict)
477{
478 struct flowi fl = {
479 .oif = oif,
480 .nl_u = {
481 .ip6_u = {
482 .daddr = *daddr,
483 /* TODO: saddr */
484 },
485 },
486 };
487 struct dst_entry *dst;
488 int flags = strict ? RT6_F_STRICT : 0;
489
490 dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
491 if (dst->error == 0)
492 return (struct rt6_info *) dst;
493
494 dst_release(dst);
495
461 return NULL; 496 return NULL;
462} 497}
463 498
464/* ip6_ins_rt is called with FREE rt6_lock. 499/* ip6_ins_rt is called with FREE table->tb6_lock.
465 It takes new route entry, the addition fails by any reason the 500 It takes new route entry, the addition fails by any reason the
466 route is freed. In any case, if caller does not hold it, it may 501 route is freed. In any case, if caller does not hold it, it may
467 be destroyed. 502 be destroyed.
@@ -471,10 +506,12 @@ int ip6_ins_rt(struct rt6_info *rt, struct nlmsghdr *nlh,
471 void *_rtattr, struct netlink_skb_parms *req) 506 void *_rtattr, struct netlink_skb_parms *req)
472{ 507{
473 int err; 508 int err;
509 struct fib6_table *table;
474 510
475 write_lock_bh(&rt6_lock); 511 table = rt->rt6i_table;
476 err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr, req); 512 write_lock_bh(&table->tb6_lock);
477 write_unlock_bh(&rt6_lock); 513 err = fib6_add(&table->tb6_root, rt, nlh, _rtattr, req);
514 write_unlock_bh(&table->tb6_lock);
478 515
479 return err; 516 return err;
480} 517}
@@ -532,51 +569,40 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
532 return rt; 569 return rt;
533} 570}
534 571
535#define BACKTRACK() \ 572struct rt6_info *ip6_pol_route_input(struct fib6_table *table, struct flowi *fl,
536if (rt == &ip6_null_entry) { \ 573 int flags)
537 while ((fn = fn->parent) != NULL) { \
538 if (fn->fn_flags & RTN_ROOT) { \
539 goto out; \
540 } \
541 if (fn->fn_flags & RTN_RTINFO) \
542 goto restart; \
543 } \
544}
545
546
547void ip6_route_input(struct sk_buff *skb)
548{ 574{
549 struct fib6_node *fn; 575 struct fib6_node *fn;
550 struct rt6_info *rt, *nrt; 576 struct rt6_info *rt, *nrt;
551 int strict; 577 int strict = 0;
552 int attempts = 3; 578 int attempts = 3;
553 int err; 579 int err;
554 int reachable = RT6_SELECT_F_REACHABLE; 580 int reachable = RT6_SELECT_F_REACHABLE;
555 581
556 strict = ipv6_addr_type(&skb->nh.ipv6h->daddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; 582 if (flags & RT6_F_STRICT)
583 strict = RT6_SELECT_F_IFACE;
557 584
558relookup: 585relookup:
559 read_lock_bh(&rt6_lock); 586 read_lock_bh(&table->tb6_lock);
560 587
561restart_2: 588restart_2:
562 fn = fib6_lookup(&ip6_routing_table, &skb->nh.ipv6h->daddr, 589 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
563 &skb->nh.ipv6h->saddr);
564 590
565restart: 591restart:
566 rt = rt6_select(&fn->leaf, skb->dev->ifindex, strict | reachable); 592 rt = rt6_select(&fn->leaf, fl->iif, strict | reachable);
567 BACKTRACK(); 593 BACKTRACK();
568 if (rt == &ip6_null_entry || 594 if (rt == &ip6_null_entry ||
569 rt->rt6i_flags & RTF_CACHE) 595 rt->rt6i_flags & RTF_CACHE)
570 goto out; 596 goto out;
571 597
572 dst_hold(&rt->u.dst); 598 dst_hold(&rt->u.dst);
573 read_unlock_bh(&rt6_lock); 599 read_unlock_bh(&table->tb6_lock);
574 600
575 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) 601 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
576 nrt = rt6_alloc_cow(rt, &skb->nh.ipv6h->daddr, &skb->nh.ipv6h->saddr); 602 nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
577 else { 603 else {
578#if CLONE_OFFLINK_ROUTE 604#if CLONE_OFFLINK_ROUTE
579 nrt = rt6_alloc_clone(rt, &skb->nh.ipv6h->daddr); 605 nrt = rt6_alloc_clone(rt, &fl->fl6_dst);
580#else 606#else
581 goto out2; 607 goto out2;
582#endif 608#endif
@@ -587,7 +613,7 @@ restart:
587 613
588 dst_hold(&rt->u.dst); 614 dst_hold(&rt->u.dst);
589 if (nrt) { 615 if (nrt) {
590 err = ip6_ins_rt(nrt, NULL, NULL, &NETLINK_CB(skb)); 616 err = ip6_ins_rt(nrt, NULL, NULL, NULL);
591 if (!err) 617 if (!err)
592 goto out2; 618 goto out2;
593 } 619 }
@@ -596,7 +622,7 @@ restart:
596 goto out2; 622 goto out2;
597 623
598 /* 624 /*
599 * Race condition! In the gap, when rt6_lock was 625 * Race condition! In the gap, when table->tb6_lock was
600 * released someone could insert this route. Relookup. 626 * released someone could insert this route. Relookup.
601 */ 627 */
602 dst_release(&rt->u.dst); 628 dst_release(&rt->u.dst);
@@ -608,30 +634,54 @@ out:
608 goto restart_2; 634 goto restart_2;
609 } 635 }
610 dst_hold(&rt->u.dst); 636 dst_hold(&rt->u.dst);
611 read_unlock_bh(&rt6_lock); 637 read_unlock_bh(&table->tb6_lock);
612out2: 638out2:
613 rt->u.dst.lastuse = jiffies; 639 rt->u.dst.lastuse = jiffies;
614 rt->u.dst.__use++; 640 rt->u.dst.__use++;
615 skb->dst = (struct dst_entry *) rt; 641
616 return; 642 return rt;
617} 643}
618 644
619struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) 645void ip6_route_input(struct sk_buff *skb)
646{
647 struct ipv6hdr *iph = skb->nh.ipv6h;
648 struct flowi fl = {
649 .iif = skb->dev->ifindex,
650 .nl_u = {
651 .ip6_u = {
652 .daddr = iph->daddr,
653 .saddr = iph->saddr,
654 .flowlabel = (* (u32 *) iph)&IPV6_FLOWINFO_MASK,
655 },
656 },
657 .proto = iph->nexthdr,
658 };
659 int flags = 0;
660
661 if (rt6_need_strict(&iph->daddr))
662 flags |= RT6_F_STRICT;
663
664 skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
665}
666
667static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
668 struct flowi *fl, int flags)
620{ 669{
621 struct fib6_node *fn; 670 struct fib6_node *fn;
622 struct rt6_info *rt, *nrt; 671 struct rt6_info *rt, *nrt;
623 int strict; 672 int strict = 0;
624 int attempts = 3; 673 int attempts = 3;
625 int err; 674 int err;
626 int reachable = RT6_SELECT_F_REACHABLE; 675 int reachable = RT6_SELECT_F_REACHABLE;
627 676
628 strict = ipv6_addr_type(&fl->fl6_dst) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL) ? RT6_SELECT_F_IFACE : 0; 677 if (flags & RT6_F_STRICT)
678 strict = RT6_SELECT_F_IFACE;
629 679
630relookup: 680relookup:
631 read_lock_bh(&rt6_lock); 681 read_lock_bh(&table->tb6_lock);
632 682
633restart_2: 683restart_2:
634 fn = fib6_lookup(&ip6_routing_table, &fl->fl6_dst, &fl->fl6_src); 684 fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
635 685
636restart: 686restart:
637 rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); 687 rt = rt6_select(&fn->leaf, fl->oif, strict | reachable);
@@ -641,7 +691,7 @@ restart:
641 goto out; 691 goto out;
642 692
643 dst_hold(&rt->u.dst); 693 dst_hold(&rt->u.dst);
644 read_unlock_bh(&rt6_lock); 694 read_unlock_bh(&table->tb6_lock);
645 695
646 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) 696 if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP))
647 nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src); 697 nrt = rt6_alloc_cow(rt, &fl->fl6_dst, &fl->fl6_src);
@@ -667,7 +717,7 @@ restart:
667 goto out2; 717 goto out2;
668 718
669 /* 719 /*
670 * Race condition! In the gap, when rt6_lock was 720 * Race condition! In the gap, when table->tb6_lock was
671 * released someone could insert this route. Relookup. 721 * released someone could insert this route. Relookup.
672 */ 722 */
673 dst_release(&rt->u.dst); 723 dst_release(&rt->u.dst);
@@ -679,11 +729,21 @@ out:
679 goto restart_2; 729 goto restart_2;
680 } 730 }
681 dst_hold(&rt->u.dst); 731 dst_hold(&rt->u.dst);
682 read_unlock_bh(&rt6_lock); 732 read_unlock_bh(&table->tb6_lock);
683out2: 733out2:
684 rt->u.dst.lastuse = jiffies; 734 rt->u.dst.lastuse = jiffies;
685 rt->u.dst.__use++; 735 rt->u.dst.__use++;
686 return &rt->u.dst; 736 return rt;
737}
738
739struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
740{
741 int flags = 0;
742
743 if (rt6_need_strict(&fl->fl6_dst))
744 flags |= RT6_F_STRICT;
745
746 return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
687} 747}
688 748
689 749
@@ -906,7 +966,8 @@ int ipv6_get_hoplimit(struct net_device *dev)
906 */ 966 */
907 967
908int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, 968int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh,
909 void *_rtattr, struct netlink_skb_parms *req) 969 void *_rtattr, struct netlink_skb_parms *req,
970 u32 table_id)
910{ 971{
911 int err; 972 int err;
912 struct rtmsg *r; 973 struct rtmsg *r;
@@ -914,6 +975,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh,
914 struct rt6_info *rt = NULL; 975 struct rt6_info *rt = NULL;
915 struct net_device *dev = NULL; 976 struct net_device *dev = NULL;
916 struct inet6_dev *idev = NULL; 977 struct inet6_dev *idev = NULL;
978 struct fib6_table *table;
917 int addr_type; 979 int addr_type;
918 980
919 rta = (struct rtattr **) _rtattr; 981 rta = (struct rtattr **) _rtattr;
@@ -937,6 +999,12 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh,
937 if (rtmsg->rtmsg_metric == 0) 999 if (rtmsg->rtmsg_metric == 0)
938 rtmsg->rtmsg_metric = IP6_RT_PRIO_USER; 1000 rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;
939 1001
1002 table = fib6_new_table(table_id);
1003 if (table == NULL) {
1004 err = -ENOBUFS;
1005 goto out;
1006 }
1007
940 rt = ip6_dst_alloc(); 1008 rt = ip6_dst_alloc();
941 1009
942 if (rt == NULL) { 1010 if (rt == NULL) {
@@ -1093,6 +1161,7 @@ install_route:
1093 rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); 1161 rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));
1094 rt->u.dst.dev = dev; 1162 rt->u.dst.dev = dev;
1095 rt->rt6i_idev = idev; 1163 rt->rt6i_idev = idev;
1164 rt->rt6i_table = table;
1096 return ip6_ins_rt(rt, nlh, _rtattr, req); 1165 return ip6_ins_rt(rt, nlh, _rtattr, req);
1097 1166
1098out: 1167out:
@@ -1108,26 +1177,35 @@ out:
1108int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) 1177int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req)
1109{ 1178{
1110 int err; 1179 int err;
1180 struct fib6_table *table;
1111 1181
1112 write_lock_bh(&rt6_lock); 1182 table = rt->rt6i_table;
1183 write_lock_bh(&table->tb6_lock);
1113 1184
1114 err = fib6_del(rt, nlh, _rtattr, req); 1185 err = fib6_del(rt, nlh, _rtattr, req);
1115 dst_release(&rt->u.dst); 1186 dst_release(&rt->u.dst);
1116 1187
1117 write_unlock_bh(&rt6_lock); 1188 write_unlock_bh(&table->tb6_lock);
1118 1189
1119 return err; 1190 return err;
1120} 1191}
1121 1192
1122static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) 1193static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh,
1194 void *_rtattr, struct netlink_skb_parms *req,
1195 u32 table_id)
1123{ 1196{
1197 struct fib6_table *table;
1124 struct fib6_node *fn; 1198 struct fib6_node *fn;
1125 struct rt6_info *rt; 1199 struct rt6_info *rt;
1126 int err = -ESRCH; 1200 int err = -ESRCH;
1127 1201
1128 read_lock_bh(&rt6_lock); 1202 table = fib6_get_table(table_id);
1203 if (table == NULL)
1204 return err;
1205
1206 read_lock_bh(&table->tb6_lock);
1129 1207
1130 fn = fib6_locate(&ip6_routing_table, 1208 fn = fib6_locate(&table->tb6_root,
1131 &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len, 1209 &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len,
1132 &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len); 1210 &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);
1133 1211
@@ -1144,12 +1222,12 @@ static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_r
1144 rtmsg->rtmsg_metric != rt->rt6i_metric) 1222 rtmsg->rtmsg_metric != rt->rt6i_metric)
1145 continue; 1223 continue;
1146 dst_hold(&rt->u.dst); 1224 dst_hold(&rt->u.dst);
1147 read_unlock_bh(&rt6_lock); 1225 read_unlock_bh(&table->tb6_lock);
1148 1226
1149 return ip6_del_rt(rt, nlh, _rtattr, req); 1227 return ip6_del_rt(rt, nlh, _rtattr, req);
1150 } 1228 }
1151 } 1229 }
1152 read_unlock_bh(&rt6_lock); 1230 read_unlock_bh(&table->tb6_lock);
1153 1231
1154 return err; 1232 return err;
1155} 1233}
@@ -1161,10 +1239,15 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
1161 struct neighbour *neigh, u8 *lladdr, int on_link) 1239 struct neighbour *neigh, u8 *lladdr, int on_link)
1162{ 1240{
1163 struct rt6_info *rt, *nrt = NULL; 1241 struct rt6_info *rt, *nrt = NULL;
1164 int strict;
1165 struct fib6_node *fn; 1242 struct fib6_node *fn;
1243 struct fib6_table *table;
1166 struct netevent_redirect netevent; 1244 struct netevent_redirect netevent;
1167 1245
1246 /* TODO: Very lazy, might need to check all tables */
1247 table = fib6_get_table(RT6_TABLE_MAIN);
1248 if (table == NULL)
1249 return;
1250
1168 /* 1251 /*
1169 * Get the "current" route for this destination and 1252 * Get the "current" route for this destination and
1170 * check if the redirect has come from approriate router. 1253 * check if the redirect has come from approriate router.
@@ -1175,10 +1258,9 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,
1175 * is a bit fuzzy and one might need to check all possible 1258 * is a bit fuzzy and one might need to check all possible
1176 * routes. 1259 * routes.
1177 */ 1260 */
1178 strict = ipv6_addr_type(dest) & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL);
1179 1261
1180 read_lock_bh(&rt6_lock); 1262 read_lock_bh(&table->tb6_lock);
1181 fn = fib6_lookup(&ip6_routing_table, dest, NULL); 1263 fn = fib6_lookup(&table->tb6_root, dest, NULL);
1182restart: 1264restart:
1183 for (rt = fn->leaf; rt; rt = rt->u.next) { 1265 for (rt = fn->leaf; rt; rt = rt->u.next) {
1184 /* 1266 /*
@@ -1201,7 +1283,7 @@ restart:
1201 } 1283 }
1202 if (rt) 1284 if (rt)
1203 dst_hold(&rt->u.dst); 1285 dst_hold(&rt->u.dst);
1204 else if (strict) { 1286 else if (rt6_need_strict(dest)) {
1205 while ((fn = fn->parent) != NULL) { 1287 while ((fn = fn->parent) != NULL) {
1206 if (fn->fn_flags & RTN_ROOT) 1288 if (fn->fn_flags & RTN_ROOT)
1207 break; 1289 break;
@@ -1209,7 +1291,7 @@ restart:
1209 goto restart; 1291 goto restart;
1210 } 1292 }
1211 } 1293 }
1212 read_unlock_bh(&rt6_lock); 1294 read_unlock_bh(&table->tb6_lock);
1213 1295
1214 if (!rt) { 1296 if (!rt) {
1215 if (net_ratelimit()) 1297 if (net_ratelimit())
@@ -1384,6 +1466,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
1384#ifdef CONFIG_IPV6_SUBTREES 1466#ifdef CONFIG_IPV6_SUBTREES
1385 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); 1467 memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));
1386#endif 1468#endif
1469 rt->rt6i_table = ort->rt6i_table;
1387 } 1470 }
1388 return rt; 1471 return rt;
1389} 1472}
@@ -1394,9 +1477,14 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle
1394{ 1477{
1395 struct fib6_node *fn; 1478 struct fib6_node *fn;
1396 struct rt6_info *rt = NULL; 1479 struct rt6_info *rt = NULL;
1480 struct fib6_table *table;
1481
1482 table = fib6_get_table(RT6_TABLE_INFO);
1483 if (table == NULL)
1484 return NULL;
1397 1485
1398 write_lock_bh(&rt6_lock); 1486 write_lock_bh(&table->tb6_lock);
1399 fn = fib6_locate(&ip6_routing_table, prefix ,prefixlen, NULL, 0); 1487 fn = fib6_locate(&table->tb6_root, prefix ,prefixlen, NULL, 0);
1400 if (!fn) 1488 if (!fn)
1401 goto out; 1489 goto out;
1402 1490
@@ -1411,7 +1499,7 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle
1411 break; 1499 break;
1412 } 1500 }
1413out: 1501out:
1414 write_unlock_bh(&rt6_lock); 1502 write_unlock_bh(&table->tb6_lock);
1415 return rt; 1503 return rt;
1416} 1504}
1417 1505
@@ -1433,7 +1521,7 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle
1433 rtmsg.rtmsg_flags |= RTF_DEFAULT; 1521 rtmsg.rtmsg_flags |= RTF_DEFAULT;
1434 rtmsg.rtmsg_ifindex = ifindex; 1522 rtmsg.rtmsg_ifindex = ifindex;
1435 1523
1436 ip6_route_add(&rtmsg, NULL, NULL, NULL); 1524 ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_INFO);
1437 1525
1438 return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); 1526 return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex);
1439} 1527}
@@ -1442,12 +1530,14 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle
1442struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) 1530struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev)
1443{ 1531{
1444 struct rt6_info *rt; 1532 struct rt6_info *rt;
1445 struct fib6_node *fn; 1533 struct fib6_table *table;
1446 1534
1447 fn = &ip6_routing_table; 1535 table = fib6_get_table(RT6_TABLE_DFLT);
1536 if (table == NULL)
1537 return NULL;
1448 1538
1449 write_lock_bh(&rt6_lock); 1539 write_lock_bh(&table->tb6_lock);
1450 for (rt = fn->leaf; rt; rt=rt->u.next) { 1540 for (rt = table->tb6_root.leaf; rt; rt=rt->u.next) {
1451 if (dev == rt->rt6i_dev && 1541 if (dev == rt->rt6i_dev &&
1452 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && 1542 ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&
1453 ipv6_addr_equal(&rt->rt6i_gateway, addr)) 1543 ipv6_addr_equal(&rt->rt6i_gateway, addr))
@@ -1455,7 +1545,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
1455 } 1545 }
1456 if (rt) 1546 if (rt)
1457 dst_hold(&rt->u.dst); 1547 dst_hold(&rt->u.dst);
1458 write_unlock_bh(&rt6_lock); 1548 write_unlock_bh(&table->tb6_lock);
1459 return rt; 1549 return rt;
1460} 1550}
1461 1551
@@ -1474,28 +1564,31 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
1474 1564
1475 rtmsg.rtmsg_ifindex = dev->ifindex; 1565 rtmsg.rtmsg_ifindex = dev->ifindex;
1476 1566
1477 ip6_route_add(&rtmsg, NULL, NULL, NULL); 1567 ip6_route_add(&rtmsg, NULL, NULL, NULL, RT6_TABLE_DFLT);
1478 return rt6_get_dflt_router(gwaddr, dev); 1568 return rt6_get_dflt_router(gwaddr, dev);
1479} 1569}
1480 1570
1481void rt6_purge_dflt_routers(void) 1571void rt6_purge_dflt_routers(void)
1482{ 1572{
1483 struct rt6_info *rt; 1573 struct rt6_info *rt;
1574 struct fib6_table *table;
1575
1576 /* NOTE: Keep consistent with rt6_get_dflt_router */
1577 table = fib6_get_table(RT6_TABLE_DFLT);
1578 if (table == NULL)
1579 return;
1484 1580
1485restart: 1581restart:
1486 read_lock_bh(&rt6_lock); 1582 read_lock_bh(&table->tb6_lock);
1487 for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) { 1583 for (rt = table->tb6_root.leaf; rt; rt = rt->u.next) {
1488 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) { 1584 if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) {
1489 dst_hold(&rt->u.dst); 1585 dst_hold(&rt->u.dst);
1490 1586 read_unlock_bh(&table->tb6_lock);
1491 read_unlock_bh(&rt6_lock);
1492
1493 ip6_del_rt(rt, NULL, NULL, NULL); 1587 ip6_del_rt(rt, NULL, NULL, NULL);
1494
1495 goto restart; 1588 goto restart;
1496 } 1589 }
1497 } 1590 }
1498 read_unlock_bh(&rt6_lock); 1591 read_unlock_bh(&table->tb6_lock);
1499} 1592}
1500 1593
1501int ipv6_route_ioctl(unsigned int cmd, void __user *arg) 1594int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
@@ -1516,10 +1609,12 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
1516 rtnl_lock(); 1609 rtnl_lock();
1517 switch (cmd) { 1610 switch (cmd) {
1518 case SIOCADDRT: 1611 case SIOCADDRT:
1519 err = ip6_route_add(&rtmsg, NULL, NULL, NULL); 1612 err = ip6_route_add(&rtmsg, NULL, NULL, NULL,
1613 RT6_TABLE_MAIN);
1520 break; 1614 break;
1521 case SIOCDELRT: 1615 case SIOCDELRT:
1522 err = ip6_route_del(&rtmsg, NULL, NULL, NULL); 1616 err = ip6_route_del(&rtmsg, NULL, NULL, NULL,
1617 RT6_TABLE_MAIN);
1523 break; 1618 break;
1524 default: 1619 default:
1525 err = -EINVAL; 1620 err = -EINVAL;
@@ -1593,6 +1688,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
1593 1688
1594 ipv6_addr_copy(&rt->rt6i_dst.addr, addr); 1689 ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
1595 rt->rt6i_dst.plen = 128; 1690 rt->rt6i_dst.plen = 128;
1691 rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL);
1596 1692
1597 atomic_set(&rt->u.dst.__refcnt, 1); 1693 atomic_set(&rt->u.dst.__refcnt, 1);
1598 1694
@@ -1611,9 +1707,7 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg)
1611 1707
1612void rt6_ifdown(struct net_device *dev) 1708void rt6_ifdown(struct net_device *dev)
1613{ 1709{
1614 write_lock_bh(&rt6_lock); 1710 fib6_clean_all(fib6_ifdown, 0, dev);
1615 fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev);
1616 write_unlock_bh(&rt6_lock);
1617} 1711}
1618 1712
1619struct rt6_mtu_change_arg 1713struct rt6_mtu_change_arg
@@ -1663,13 +1757,12 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
1663 1757
1664void rt6_mtu_change(struct net_device *dev, unsigned mtu) 1758void rt6_mtu_change(struct net_device *dev, unsigned mtu)
1665{ 1759{
1666 struct rt6_mtu_change_arg arg; 1760 struct rt6_mtu_change_arg arg = {
1761 .dev = dev,
1762 .mtu = mtu,
1763 };
1667 1764
1668 arg.dev = dev; 1765 fib6_clean_all(rt6_mtu_change_route, 0, &arg);
1669 arg.mtu = mtu;
1670 read_lock_bh(&rt6_lock);
1671 fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg);
1672 read_unlock_bh(&rt6_lock);
1673} 1766}
1674 1767
1675static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, 1768static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta,
@@ -1719,7 +1812,7 @@ int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
1719 1812
1720 if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) 1813 if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
1721 return -EINVAL; 1814 return -EINVAL;
1722 return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb)); 1815 return ip6_route_del(&rtmsg, nlh, arg, &NETLINK_CB(skb), r->rtm_table);
1723} 1816}
1724 1817
1725int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 1818int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
@@ -1729,7 +1822,7 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
1729 1822
1730 if (inet6_rtm_to_rtmsg(r, arg, &rtmsg)) 1823 if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
1731 return -EINVAL; 1824 return -EINVAL;
1732 return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb)); 1825 return ip6_route_add(&rtmsg, nlh, arg, &NETLINK_CB(skb), r->rtm_table);
1733} 1826}
1734 1827
1735struct rt6_rtnl_dump_arg 1828struct rt6_rtnl_dump_arg
@@ -1761,6 +1854,10 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
1761 rtm->rtm_dst_len = rt->rt6i_dst.plen; 1854 rtm->rtm_dst_len = rt->rt6i_dst.plen;
1762 rtm->rtm_src_len = rt->rt6i_src.plen; 1855 rtm->rtm_src_len = rt->rt6i_src.plen;
1763 rtm->rtm_tos = 0; 1856 rtm->rtm_tos = 0;
1857 if (rt->rt6i_table)
1858 rtm->rtm_table = rt->rt6i_table->tb6_id;
1859 else
1860 rtm->rtm_table = RT6_TABLE_UNSPEC;
1764 rtm->rtm_table = RT_TABLE_MAIN; 1861 rtm->rtm_table = RT_TABLE_MAIN;
1765 if (rt->rt6i_flags&RTF_REJECT) 1862 if (rt->rt6i_flags&RTF_REJECT)
1766 rtm->rtm_type = RTN_UNREACHABLE; 1863 rtm->rtm_type = RTN_UNREACHABLE;
@@ -1868,7 +1965,6 @@ static void fib6_dump_end(struct netlink_callback *cb)
1868 1965
1869 if (w) { 1966 if (w) {
1870 cb->args[0] = 0; 1967 cb->args[0] = 0;
1871 fib6_walker_unlink(w);
1872 kfree(w); 1968 kfree(w);
1873 } 1969 }
1874 cb->done = (void*)cb->args[1]; 1970 cb->done = (void*)cb->args[1];
@@ -1883,13 +1979,20 @@ static int fib6_dump_done(struct netlink_callback *cb)
1883 1979
1884int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) 1980int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
1885{ 1981{
1982 struct fib6_table *table;
1886 struct rt6_rtnl_dump_arg arg; 1983 struct rt6_rtnl_dump_arg arg;
1887 struct fib6_walker_t *w; 1984 struct fib6_walker_t *w;
1888 int res; 1985 int i, res = 0;
1889 1986
1890 arg.skb = skb; 1987 arg.skb = skb;
1891 arg.cb = cb; 1988 arg.cb = cb;
1892 1989
1990 /*
1991 * cb->args[0] = pointer to walker structure
1992 * cb->args[1] = saved cb->done() pointer
1993 * cb->args[2] = current table being dumped
1994 */
1995
1893 w = (void*)cb->args[0]; 1996 w = (void*)cb->args[0];
1894 if (w == NULL) { 1997 if (w == NULL) {
1895 /* New dump: 1998 /* New dump:
@@ -1905,24 +2008,48 @@ int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
1905 w = kzalloc(sizeof(*w), GFP_ATOMIC); 2008 w = kzalloc(sizeof(*w), GFP_ATOMIC);
1906 if (w == NULL) 2009 if (w == NULL)
1907 return -ENOMEM; 2010 return -ENOMEM;
1908 RT6_TRACE("dump<%p", w);
1909 w->root = &ip6_routing_table;
1910 w->func = fib6_dump_node; 2011 w->func = fib6_dump_node;
1911 w->args = &arg; 2012 w->args = &arg;
1912 cb->args[0] = (long)w; 2013 cb->args[0] = (long)w;
1913 read_lock_bh(&rt6_lock); 2014 cb->args[2] = FIB6_TABLE_MIN;
1914 res = fib6_walk(w);
1915 read_unlock_bh(&rt6_lock);
1916 } else { 2015 } else {
1917 w->args = &arg; 2016 w->args = &arg;
1918 read_lock_bh(&rt6_lock); 2017 i = cb->args[2];
1919 res = fib6_walk_continue(w); 2018 if (i > FIB6_TABLE_MAX)
1920 read_unlock_bh(&rt6_lock); 2019 goto end;
2020
2021 table = fib6_get_table(i);
2022 if (table != NULL) {
2023 read_lock_bh(&table->tb6_lock);
2024 w->root = &table->tb6_root;
2025 res = fib6_walk_continue(w);
2026 read_unlock_bh(&table->tb6_lock);
2027 if (res != 0) {
2028 if (res < 0)
2029 fib6_walker_unlink(w);
2030 goto end;
2031 }
2032 }
2033
2034 fib6_walker_unlink(w);
2035 cb->args[2] = ++i;
1921 } 2036 }
1922#if RT6_DEBUG >= 3 2037
1923 if (res <= 0 && skb->len == 0) 2038 for (i = cb->args[2]; i <= FIB6_TABLE_MAX; i++) {
1924 RT6_TRACE("%p>dump end\n", w); 2039 table = fib6_get_table(i);
1925#endif 2040 if (table == NULL)
2041 continue;
2042
2043 read_lock_bh(&table->tb6_lock);
2044 w->root = &table->tb6_root;
2045 res = fib6_walk(w);
2046 read_unlock_bh(&table->tb6_lock);
2047 if (res)
2048 break;
2049 }
2050end:
2051 cb->args[2] = i;
2052
1926 res = res < 0 ? res : skb->len; 2053 res = res < 0 ? res : skb->len;
1927 /* res < 0 is an error. (really, impossible) 2054 /* res < 0 is an error. (really, impossible)
1928 res == 0 means that dump is complete, but skb still can contain data. 2055 res == 0 means that dump is complete, but skb still can contain data.
@@ -2102,16 +2229,13 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg)
2102 2229
2103static int rt6_proc_info(char *buffer, char **start, off_t offset, int length) 2230static int rt6_proc_info(char *buffer, char **start, off_t offset, int length)
2104{ 2231{
2105 struct rt6_proc_arg arg; 2232 struct rt6_proc_arg arg = {
2106 arg.buffer = buffer; 2233 .buffer = buffer,
2107 arg.offset = offset; 2234 .offset = offset,
2108 arg.length = length; 2235 .length = length,
2109 arg.skip = 0; 2236 };
2110 arg.len = 0;
2111 2237
2112 read_lock_bh(&rt6_lock); 2238 fib6_clean_all(rt6_info_route, 0, &arg);
2113 fib6_clean_tree(&ip6_routing_table, rt6_info_route, 0, &arg);
2114 read_unlock_bh(&rt6_lock);
2115 2239
2116 *start = buffer; 2240 *start = buffer;
2117 if (offset) 2241 if (offset)