diff options
author | Thomas Graf <tgraf@suug.ch> | 2006-08-05 02:20:06 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:53:39 -0400 |
commit | c71099acce933455123ee505cc75964610a209ad (patch) | |
tree | cf167c926350ff6c4040289dacce54849824c240 | |
parent | 5d0bbeeb144f631150881712607345c532e38e7e (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.h | 39 | ||||
-rw-r--r-- | include/net/ip6_route.h | 3 | ||||
-rw-r--r-- | net/ipv6/Kconfig | 6 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 6 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 144 | ||||
-rw-r--r-- | net/ipv6/route.c | 380 |
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 | ||
54 | struct fib6_table; | ||
55 | |||
54 | struct rt6_info | 56 | struct 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 | ||
144 | typedef void (*f_pnode)(struct fib6_node *fn, void *); | 147 | typedef void (*f_pnode)(struct fib6_node *fn, void *); |
145 | 148 | ||
146 | extern struct fib6_node ip6_routing_table; | 149 | struct 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 | |||
174 | typedef 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 | ||
181 | extern struct fib6_table * fib6_get_table(u32 id); | ||
182 | extern struct fib6_table * fib6_new_table(u32 id); | ||
183 | extern struct dst_entry * fib6_rule_lookup(struct flowi *fl, int flags, | ||
184 | pol_lookup_t lookup); | ||
185 | |||
152 | extern struct fib6_node *fib6_lookup(struct fib6_node *root, | 186 | extern 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 | ||
198 | extern void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), | ||
199 | int prune, void *arg); | ||
200 | |||
164 | extern int fib6_walk(struct fib6_walker_t *w); | 201 | extern int fib6_walk(struct fib6_walker_t *w); |
165 | extern int fib6_walk_continue(struct fib6_walker_t *w); | 202 | extern 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); | |||
58 | extern int ip6_route_add(struct in6_rtmsg *rtmsg, | 58 | extern 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); | ||
62 | extern int ip6_ins_rt(struct rt6_info *, | 63 | extern 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 | ||
139 | config 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 | ||
1548 | static void sit_route_add(struct net_device *dev) | 1548 | static 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 | ||
1565 | static void addrconf_add_lroute(struct net_device *dev) | 1565 | static 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 | ||
151 | static 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 | ||
163 | static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; | ||
164 | |||
165 | static 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 | |||
180 | static 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 | |||
193 | struct 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 | |||
210 | struct 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 | |||
231 | struct 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 | |||
242 | static void __init fib6_tables_init(void) | ||
243 | { | ||
244 | fib6_link_table(&fib6_main_tbl); | ||
245 | } | ||
246 | |||
247 | #else | ||
248 | |||
249 | struct fib6_table *fib6_new_table(u32 id) | ||
250 | { | ||
251 | return fib6_get_table(id); | ||
252 | } | ||
253 | |||
254 | struct fib6_table *fib6_get_table(u32 id) | ||
255 | { | ||
256 | return &fib6_main_tbl; | ||
257 | } | ||
258 | |||
259 | struct 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 | |||
265 | static 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 | ||
1188 | void 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 | |||
1067 | static int fib6_prune_clone(struct rt6_info *rt, void *arg) | 1204 | static 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 | ||
1170 | void fib6_gc_cleanup(void) | 1306 | void 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 | ||
143 | struct 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 | |||
150 | DEFINE_RWLOCK(rt6_lock); | ||
151 | |||
152 | |||
153 | /* allocate dst with ip6_dst_ops */ | 143 | /* allocate dst with ip6_dst_ops */ |
154 | static __inline__ struct rt6_info *ip6_dst_alloc(void) | 144 | static __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 | ||
181 | static 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 | ||
195 | static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, | 191 | static __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 | ||
444 | struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, | 440 | #define BACKTRACK() \ |
445 | int oif, int strict) | 441 | if (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 | |||
452 | static 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); | 460 | restart: |
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++; | 465 | out: |
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 | |||
475 | struct 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() \ | 572 | struct rt6_info *ip6_pol_route_input(struct fib6_table *table, struct flowi *fl, |
536 | if (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 | |||
547 | void 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 | ||
558 | relookup: | 585 | relookup: |
559 | read_lock_bh(&rt6_lock); | 586 | read_lock_bh(&table->tb6_lock); |
560 | 587 | ||
561 | restart_2: | 588 | restart_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 | ||
565 | restart: | 591 | restart: |
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); |
612 | out2: | 638 | out2: |
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 | ||
619 | struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | 645 | void 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 | |||
667 | static 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 | ||
630 | relookup: | 680 | relookup: |
631 | read_lock_bh(&rt6_lock); | 681 | read_lock_bh(&table->tb6_lock); |
632 | 682 | ||
633 | restart_2: | 683 | restart_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 | ||
636 | restart: | 686 | restart: |
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); |
683 | out2: | 733 | out2: |
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 | |||
739 | struct 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 | ||
908 | int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, | 968 | int 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 | ||
1098 | out: | 1167 | out: |
@@ -1108,26 +1177,35 @@ out: | |||
1108 | int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1177 | int 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 | ||
1122 | static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) | 1193 | static 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); |
1182 | restart: | 1264 | restart: |
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 | } |
1413 | out: | 1501 | out: |
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 | |||
1442 | struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev) | 1530 | struct 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 | ||
1481 | void rt6_purge_dflt_routers(void) | 1571 | void 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 | ||
1485 | restart: | 1581 | restart: |
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 | ||
1501 | int ipv6_route_ioctl(unsigned int cmd, void __user *arg) | 1594 | int 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 | ||
1612 | void rt6_ifdown(struct net_device *dev) | 1708 | void 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 | ||
1619 | struct rt6_mtu_change_arg | 1713 | struct rt6_mtu_change_arg |
@@ -1663,13 +1757,12 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) | |||
1663 | 1757 | ||
1664 | void rt6_mtu_change(struct net_device *dev, unsigned mtu) | 1758 | void 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 | ||
1675 | static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta, | 1768 | static 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 | ||
1725 | int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) | 1818 | int 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 | ||
1735 | struct rt6_rtnl_dump_arg | 1828 | struct 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 | ||
1884 | int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) | 1980 | int 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 | } | ||
2050 | end: | ||
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 | ||
2103 | static int rt6_proc_info(char *buffer, char **start, off_t offset, int length) | 2230 | static 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) |