aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_fib.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_fib.c')
-rw-r--r--net/ipv6/ip6_fib.c171
1 files changed, 151 insertions, 20 deletions
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 1f2316187ca4..bececbe9dd2c 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -158,7 +158,26 @@ static struct fib6_table fib6_main_tbl = {
158}; 158};
159 159
160#ifdef CONFIG_IPV6_MULTIPLE_TABLES 160#ifdef CONFIG_IPV6_MULTIPLE_TABLES
161#define FIB_TABLE_HASHSZ 256
162#else
163#define FIB_TABLE_HASHSZ 1
164#endif
165static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
166
167static void fib6_link_table(struct fib6_table *tb)
168{
169 unsigned int h;
170
171 h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1);
161 172
173 /*
174 * No protection necessary, this is the only list mutatation
175 * operation, tables never disappear once they exist.
176 */
177 hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
178}
179
180#ifdef CONFIG_IPV6_MULTIPLE_TABLES
162static struct fib6_table fib6_local_tbl = { 181static struct fib6_table fib6_local_tbl = {
163 .tb6_id = RT6_TABLE_LOCAL, 182 .tb6_id = RT6_TABLE_LOCAL,
164 .tb6_lock = RW_LOCK_UNLOCKED, 183 .tb6_lock = RW_LOCK_UNLOCKED,
@@ -168,9 +187,6 @@ static struct fib6_table fib6_local_tbl = {
168 }, 187 },
169}; 188};
170 189
171#define FIB_TABLE_HASHSZ 256
172static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
173
174static struct fib6_table *fib6_alloc_table(u32 id) 190static struct fib6_table *fib6_alloc_table(u32 id)
175{ 191{
176 struct fib6_table *table; 192 struct fib6_table *table;
@@ -186,19 +202,6 @@ static struct fib6_table *fib6_alloc_table(u32 id)
186 return table; 202 return table;
187} 203}
188 204
189static void fib6_link_table(struct fib6_table *tb)
190{
191 unsigned int h;
192
193 h = tb->tb6_id & (FIB_TABLE_HASHSZ - 1);
194
195 /*
196 * No protection necessary, this is the only list mutatation
197 * operation, tables never disappear once they exist.
198 */
199 hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]);
200}
201
202struct fib6_table *fib6_new_table(u32 id) 205struct fib6_table *fib6_new_table(u32 id)
203{ 206{
204 struct fib6_table *tb; 207 struct fib6_table *tb;
@@ -263,10 +266,135 @@ struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags,
263 266
264static void __init fib6_tables_init(void) 267static void __init fib6_tables_init(void)
265{ 268{
269 fib6_link_table(&fib6_main_tbl);
266} 270}
267 271
268#endif 272#endif
269 273
274static int fib6_dump_node(struct fib6_walker_t *w)
275{
276 int res;
277 struct rt6_info *rt;
278
279 for (rt = w->leaf; rt; rt = rt->u.next) {
280 res = rt6_dump_route(rt, w->args);
281 if (res < 0) {
282 /* Frame is full, suspend walking */
283 w->leaf = rt;
284 return 1;
285 }
286 BUG_TRAP(res!=0);
287 }
288 w->leaf = NULL;
289 return 0;
290}
291
292static void fib6_dump_end(struct netlink_callback *cb)
293{
294 struct fib6_walker_t *w = (void*)cb->args[2];
295
296 if (w) {
297 cb->args[2] = 0;
298 kfree(w);
299 }
300 cb->done = (void*)cb->args[3];
301 cb->args[1] = 3;
302}
303
304static int fib6_dump_done(struct netlink_callback *cb)
305{
306 fib6_dump_end(cb);
307 return cb->done ? cb->done(cb) : 0;
308}
309
310static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb,
311 struct netlink_callback *cb)
312{
313 struct fib6_walker_t *w;
314 int res;
315
316 w = (void *)cb->args[2];
317 w->root = &table->tb6_root;
318
319 if (cb->args[4] == 0) {
320 read_lock_bh(&table->tb6_lock);
321 res = fib6_walk(w);
322 read_unlock_bh(&table->tb6_lock);
323 if (res > 0)
324 cb->args[4] = 1;
325 } else {
326 read_lock_bh(&table->tb6_lock);
327 res = fib6_walk_continue(w);
328 read_unlock_bh(&table->tb6_lock);
329 if (res != 0) {
330 if (res < 0)
331 fib6_walker_unlink(w);
332 goto end;
333 }
334 fib6_walker_unlink(w);
335 cb->args[4] = 0;
336 }
337end:
338 return res;
339}
340
341int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
342{
343 unsigned int h, s_h;
344 unsigned int e = 0, s_e;
345 struct rt6_rtnl_dump_arg arg;
346 struct fib6_walker_t *w;
347 struct fib6_table *tb;
348 struct hlist_node *node;
349 int res = 0;
350
351 s_h = cb->args[0];
352 s_e = cb->args[1];
353
354 w = (void *)cb->args[2];
355 if (w == NULL) {
356 /* New dump:
357 *
358 * 1. hook callback destructor.
359 */
360 cb->args[3] = (long)cb->done;
361 cb->done = fib6_dump_done;
362
363 /*
364 * 2. allocate and initialize walker.
365 */
366 w = kzalloc(sizeof(*w), GFP_ATOMIC);
367 if (w == NULL)
368 return -ENOMEM;
369 w->func = fib6_dump_node;
370 cb->args[2] = (long)w;
371 }
372
373 arg.skb = skb;
374 arg.cb = cb;
375 w->args = &arg;
376
377 for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
378 e = 0;
379 hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) {
380 if (e < s_e)
381 goto next;
382 res = fib6_dump_table(tb, skb, cb);
383 if (res != 0)
384 goto out;
385next:
386 e++;
387 }
388 }
389out:
390 cb->args[1] = e;
391 cb->args[0] = h;
392
393 res = res < 0 ? res : skb->len;
394 if (res <= 0)
395 fib6_dump_end(cb);
396 return res;
397}
270 398
271/* 399/*
272 * Routing Table 400 * Routing Table
@@ -1187,17 +1315,20 @@ static void fib6_clean_tree(struct fib6_node *root,
1187void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), 1315void fib6_clean_all(int (*func)(struct rt6_info *, void *arg),
1188 int prune, void *arg) 1316 int prune, void *arg)
1189{ 1317{
1190 int i;
1191 struct fib6_table *table; 1318 struct fib6_table *table;
1319 struct hlist_node *node;
1320 unsigned int h;
1192 1321
1193 for (i = FIB6_TABLE_MIN; i <= FIB6_TABLE_MAX; i++) { 1322 rcu_read_lock();
1194 table = fib6_get_table(i); 1323 for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
1195 if (table != NULL) { 1324 hlist_for_each_entry_rcu(table, node, &fib_table_hash[h],
1325 tb6_hlist) {
1196 write_lock_bh(&table->tb6_lock); 1326 write_lock_bh(&table->tb6_lock);
1197 fib6_clean_tree(&table->tb6_root, func, prune, arg); 1327 fib6_clean_tree(&table->tb6_root, func, prune, arg);
1198 write_unlock_bh(&table->tb6_lock); 1328 write_unlock_bh(&table->tb6_lock);
1199 } 1329 }
1200 } 1330 }
1331 rcu_read_unlock();
1201} 1332}
1202 1333
1203static int fib6_prune_clone(struct rt6_info *rt, void *arg) 1334static int fib6_prune_clone(struct rt6_info *rt, void *arg)