diff options
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r-- | net/ipv6/ip6_fib.c | 144 |
1 files changed, 140 insertions, 4 deletions
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) |