1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/config.h>
19#include <asm/uaccess.h>
20#include <asm/system.h>
21#include <asm/bitops.h>
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/sched.h>
25#include <linux/mm.h>
26#include <linux/string.h>
27#include <linux/socket.h>
28#include <linux/sockios.h>
29#include <linux/errno.h>
30#include <linux/in.h>
31#include <linux/inet.h>
32#include <linux/netdevice.h>
33#include <linux/if_arp.h>
34#include <linux/proc_fs.h>
35#include <linux/skbuff.h>
36#include <linux/netlink.h>
37#include <linux/init.h>
38
39#include <net/ip.h>
40#include <net/protocol.h>
41#include <net/route.h>
42#include <net/tcp.h>
43#include <net/sock.h>
44#include <net/ip_fib.h>
45
46#define FTprint(a...)
47
48
49
50
51
52
53
54
55
56
57
58typedef struct {
59 u32 datum;
60} fn_key_t;
61
62typedef struct {
63 u32 datum;
64} fn_hash_idx_t;
65
66struct fib_node
67{
68 struct fib_node *fn_next;
69 struct fib_info *fn_info;
70#define FIB_INFO(f) ((f)->fn_info)
71 fn_key_t fn_key;
72 u8 fn_tos;
73 u8 fn_type;
74 u8 fn_scope;
75 u8 fn_state;
76};
77
78#define FN_S_ZOMBIE 1
79#define FN_S_ACCESSED 2
80
81static int fib_hash_zombies;
82
83struct fn_zone
84{
85 struct fn_zone *fz_next;
86 struct fib_node **fz_hash;
87 int fz_nent;
88
89 int fz_divisor;
90 u32 fz_hashmask;
91#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
92
93 int fz_order;
94 u32 fz_mask;
95#define FZ_MASK(fz) ((fz)->fz_mask)
96};
97
98
99
100
101
102struct fn_hash
103{
104 struct fn_zone *fn_zones[33];
105 struct fn_zone *fn_zone_list;
106};
107
108static __inline__ fn_hash_idx_t fn_hash(fn_key_t key, struct fn_zone *fz)
109{
110 u32 h = ntohl(key.datum)>>(32 - fz->fz_order);
111 h ^= (h>>20);
112 h ^= (h>>10);
113 h ^= (h>>5);
114 h &= FZ_HASHMASK(fz);
115 return *(fn_hash_idx_t*)&h;
116}
117
118#define fz_key_0(key) ((key).datum = 0)
119#define fz_prefix(key,fz) ((key).datum)
120
121static __inline__ fn_key_t fz_key(u32 dst, struct fn_zone *fz)
122{
123 fn_key_t k;
124 k.datum = dst & FZ_MASK(fz);
125 return k;
126}
127
128static __inline__ struct fib_node ** fz_chain_p(fn_key_t key, struct fn_zone *fz)
129{
130 return &fz->fz_hash[fn_hash(key, fz).datum];
131}
132
133static __inline__ struct fib_node * fz_chain(fn_key_t key, struct fn_zone *fz)
134{
135 return fz->fz_hash[fn_hash(key, fz).datum];
136}
137
138extern __inline__ int fn_key_eq(fn_key_t a, fn_key_t b)
139{
140 return a.datum == b.datum;
141}
142
143extern __inline__ int fn_key_leq(fn_key_t a, fn_key_t b)
144{
145 return a.datum <= b.datum;
146}
147
148#define FZ_MAX_DIVISOR 1024
149
150#ifdef CONFIG_IP_ROUTE_LARGE_TABLES
151
152static __inline__ void fn_rebuild_zone(struct fn_zone *fz,
153 struct fib_node **old_ht,
154 int old_divisor)
155{
156 int i;
157 struct fib_node *f, **fp, *next;
158
159 for (i=0; i<old_divisor; i++) {
160 for (f=old_ht[i]; f; f=next) {
161 next = f->fn_next;
162 for (fp = fz_chain_p(f->fn_key, fz);
163 *fp && fn_key_leq((*fp)->fn_key, f->fn_key);
164 fp = &(*fp)->fn_next)
165 ;
166 f->fn_next = *fp;
167 *fp = f;
168 }
169 }
170}
171
172static void fn_rehash_zone(struct fn_zone *fz)
173{
174 struct fib_node **ht, **old_ht;
175 int old_divisor, new_divisor;
176 u32 new_hashmask;
177
178 old_divisor = fz->fz_divisor;
179
180 switch (old_divisor) {
181 case 16:
182 new_divisor = 256;
183 new_hashmask = 0xFF;
184 break;
185 case 256:
186 new_divisor = 1024;
187 new_hashmask = 0x3FF;
188 break;
189 default:
190 printk(KERN_CRIT "route.c: bad divisor %d!\n", old_divisor);
191 return;
192 }
193#if RT_CACHE_DEBUG >= 2
194 printk("fn_rehash_zone: hash for zone %d grows from %d\n", fz->fz_order, old_divisor);
195#endif
196
197 ht = kmalloc(new_divisor*sizeof(struct fib_node*), GFP_KERNEL);
198
199 if (ht) {
200 memset(ht, 0, new_divisor*sizeof(struct fib_node*));
201 start_bh_atomic();
202 old_ht = fz->fz_hash;
203 fz->fz_hash = ht;
204 fz->fz_hashmask = new_hashmask;
205 fz->fz_divisor = new_divisor;
206 fn_rebuild_zone(fz, old_ht, old_divisor);
207 end_bh_atomic();
208 kfree(old_ht);
209 }
210}
211#endif
212
213static void fn_free_node(struct fib_node * f)
214{
215 fib_release_info(FIB_INFO(f));
216 kfree_s(f, sizeof(struct fib_node));
217}
218
219
220static struct fn_zone *
221fn_new_zone(struct fn_hash *table, int z)
222{
223 int i;
224 struct fn_zone *fz = kmalloc(sizeof(struct fn_zone), GFP_KERNEL);
225 if (!fz)
226 return NULL;
227
228 memset(fz, 0, sizeof(struct fn_zone));
229 if (z) {
230 fz->fz_divisor = 16;
231 fz->fz_hashmask = 0xF;
232 } else {
233 fz->fz_divisor = 1;
234 fz->fz_hashmask = 0;
235 }
236 fz->fz_hash = kmalloc(fz->fz_divisor*sizeof(struct fib_node*), GFP_KERNEL);
237 if (!fz->fz_hash) {
238 kfree(fz);
239 return NULL;
240 }
241 memset(fz->fz_hash, 0, fz->fz_divisor*sizeof(struct fib_node*));
242 fz->fz_order = z;
243 fz->fz_mask = inet_make_mask(z);
244
245
246 for (i=z+1; i<=32; i++)
247 if (table->fn_zones[i])
248 break;
249 if (i>32) {
250
251 fz->fz_next = table->fn_zone_list;
252 table->fn_zone_list = fz;
253 } else {
254 fz->fz_next = table->fn_zones[i]->fz_next;
255 table->fn_zones[i]->fz_next = fz;
256 }
257 table->fn_zones[z] = fz;
258 return fz;
259}
260
261static int
262fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
263{
264 int err;
265 struct fn_zone *fz;
266 struct fn_hash *t = (struct fn_hash*)tb->tb_data;
267
268 for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
269 struct fib_node *f;
270 fn_key_t k = fz_key(key->dst, fz);
271
272 for (f = fz_chain(k, fz); f; f = f->fn_next) {
273 if (!fn_key_eq(k, f->fn_key)) {
274 if (fn_key_leq(k, f->fn_key))
275 break;
276 else
277 continue;
278 }
279#ifdef CONFIG_IP_ROUTE_TOS
280 if (f->fn_tos && f->fn_tos != key->tos)
281 continue;
282#endif
283 f->fn_state |= FN_S_ACCESSED;
284
285 if (f->fn_state&FN_S_ZOMBIE)
286 continue;
287 if (f->fn_scope < key->scope)
288 continue;
289
290 err = fib_semantic_match(f->fn_type, FIB_INFO(f), key, res);
291 if (err == 0) {
292 res->type = f->fn_type;
293 res->scope = f->fn_scope;
294 res->prefixlen = fz->fz_order;
295 res->prefix = &fz_prefix(f->fn_key, fz);
296 return 0;
297 }
298 if (err < 0)
299 return err;
300 }
301 }
302 return 1;
303}
304
305static int fn_hash_last_dflt=-1;
306
307static int fib_detect_death(struct fib_info *fi, int order,
308 struct fib_info **last_resort, int *last_idx)
309{
310 struct neighbour *n;
311 int state = NUD_NONE;
312
313 n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev);
314 if (n) {
315 state = n->nud_state;
316 neigh_release(n);
317 }
318 if (state==NUD_REACHABLE)
319 return 0;
320 if ((state&NUD_VALID) && order != fn_hash_last_dflt)
321 return 0;
322 if ((state&NUD_VALID) ||
323 (*last_idx<0 && order > fn_hash_last_dflt)) {
324 *last_resort = fi;
325 *last_idx = order;
326 }
327 return 1;
328}
329
330static void
331fn_hash_select_default(struct fib_table *tb, const struct rt_key *key, struct fib_result *res)
332{
333 int order, last_idx;
334 struct fib_node *f;
335 struct fib_info *fi = NULL;
336 struct fib_info *last_resort;
337 struct fn_hash *t = (struct fn_hash*)tb->tb_data;
338 struct fn_zone *fz = t->fn_zones[0];
339
340 if (fz == NULL)
341 return;
342
343 last_idx = -1;
344 last_resort = NULL;
345 order = -1;
346
347 for (f = fz->fz_hash[0]; f; f = f->fn_next) {
348 struct fib_info *next_fi = FIB_INFO(f);
349
350 if ((f->fn_state&FN_S_ZOMBIE) ||
351 f->fn_scope != res->scope ||
352 f->fn_type != RTN_UNICAST)
353 continue;
354
355 if (next_fi->fib_priority > res->fi->fib_priority)
356 break;
357 if (!next_fi->fib_nh[0].nh_gw || next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK)
358 continue;
359 f->fn_state |= FN_S_ACCESSED;
360
361 if (fi == NULL) {
362 if (next_fi != res->fi)
363 break;
364 } else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
365 res->fi = fi;
366 fn_hash_last_dflt = order;
367 return;
368 }
369 fi = next_fi;
370 order++;
371 }
372
373 if (order<=0 || fi==NULL) {
374 fn_hash_last_dflt = -1;
375 return;
376 }
377
378 if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
379 res->fi = fi;
380 fn_hash_last_dflt = order;
381 return;
382 }
383
384 if (last_idx >= 0)
385 res->fi = last_resort;
386 fn_hash_last_dflt = last_idx;
387}
388
389#define FIB_SCAN(f, fp) \
390for ( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
391
392#define FIB_SCAN_KEY(f, fp, key) \
393for ( ; ((f) = *(fp)) != NULL && fn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
394
395#ifndef CONFIG_IP_ROUTE_TOS
396#define FIB_SCAN_TOS(f, fp, key, tos) FIB_SCAN_KEY(f, fp, key)
397#else
398#define FIB_SCAN_TOS(f, fp, key, tos) \
399for ( ; ((f) = *(fp)) != NULL && fn_key_eq((f)->fn_key, (key)) && \
400 (f)->fn_tos == (tos) ; (fp) = &(f)->fn_next)
401#endif
402
403
404#ifdef CONFIG_RTNETLINK
405static void rtmsg_fib(int, struct fib_node*, int, int,
406 struct nlmsghdr *n,
407 struct netlink_skb_parms *);
408#else
409#define rtmsg_fib(a, b, c, d, e, f)
410#endif
411
412
413static int
414fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
415 struct nlmsghdr *n, struct netlink_skb_parms *req)
416{
417 struct fn_hash *table = (struct fn_hash*)tb->tb_data;
418 struct fib_node *new_f, *f, **fp, **del_fp;
419 struct fn_zone *fz;
420 struct fib_info *fi;
421
422 int z = r->rtm_dst_len;
423 int type = r->rtm_type;
424#ifdef CONFIG_IP_ROUTE_TOS
425 u8 tos = r->rtm_tos;
426#endif
427 fn_key_t key;
428 int err;
429
430FTprint("tb(%d)_insert: %d %08x/%d %d %08x\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
431*(u32*)rta->rta_dst : 0, z, rta->rta_oif ? *rta->rta_oif : -1,
432rta->rta_prefsrc ? *(u32*)rta->rta_prefsrc : 0);
433 if (z > 32)
434 return -EINVAL;
435 fz = table->fn_zones[z];
436 if (!fz && !(fz = fn_new_zone(table, z)))
437 return -ENOBUFS;
438
439 fz_key_0(key);
440 if (rta->rta_dst) {
441 u32 dst;
442 memcpy(&dst, rta->rta_dst, 4);
443 if (dst & ~FZ_MASK(fz))
444 return -EINVAL;
445 key = fz_key(dst, fz);
446 }
447
448 if ((fi = fib_create_info(r, rta, n, &err)) == NULL)
449 return err;
450
451#ifdef CONFIG_IP_ROUTE_LARGE_TABLES
452 if (fz->fz_nent > (fz->fz_divisor<<2) &&
453 fz->fz_divisor < FZ_MAX_DIVISOR &&
454 (z==32 || (1<<z) > fz->fz_divisor))
455 fn_rehash_zone(fz);
456#endif
457
458 fp = fz_chain_p(key, fz);
459
460
461
462
463 FIB_SCAN(f, fp) {
464 if (fn_key_leq(key,f->fn_key))
465 break;
466 }
467
468#ifdef CONFIG_IP_ROUTE_TOS
469
470
471
472 FIB_SCAN_KEY(f, fp, key) {
473 if (f->fn_tos <= tos)
474 break;
475 }
476#endif
477
478 del_fp = NULL;
479
480 if (f && (f->fn_state&FN_S_ZOMBIE) &&
481#ifdef CONFIG_IP_ROUTE_TOS
482 f->fn_tos == tos &&
483#endif
484 fn_key_eq(f->fn_key, key)) {
485 del_fp = fp;
486 fp = &f->fn_next;
487 f = *fp;
488 goto create;
489 }
490
491 FIB_SCAN_TOS(f, fp, key, tos) {
492 if (fi->fib_priority <= FIB_INFO(f)->fib_priority)
493 break;
494 }
495
496
497
498
499
500
501 if (f &&
502#ifdef CONFIG_IP_ROUTE_TOS
503 f->fn_tos == tos &&
504#endif
505 fn_key_eq(f->fn_key, key) &&
506 fi->fib_priority == FIB_INFO(f)->fib_priority) {
507 struct fib_node **ins_fp;
508
509 err = -EEXIST;
510 if (n->nlmsg_flags&NLM_F_EXCL)
511 goto out;
512
513 if (n->nlmsg_flags&NLM_F_REPLACE) {
514 del_fp = fp;
515 fp = &f->fn_next;
516 f = *fp;
517 goto replace;
518 }
519
520 ins_fp = fp;
521 err = -EEXIST;
522
523 FIB_SCAN_TOS(f, fp, key, tos) {
524 if (fi->fib_priority != FIB_INFO(f)->fib_priority)
525 break;
526 if (f->fn_type == type && f->fn_scope == r->rtm_scope
527 && FIB_INFO(f) == fi)
528 goto out;
529 }
530
531 if (!(n->nlmsg_flags&NLM_F_APPEND)) {
532 fp = ins_fp;
533 f = *fp;
534 }
535 }
536
537create:
538 err = -ENOENT;
539 if (!(n->nlmsg_flags&NLM_F_CREATE))
540 goto out;
541
542replace:
543 err = -ENOBUFS;
544 new_f = (struct fib_node *) kmalloc(sizeof(struct fib_node), GFP_KERNEL);
545 if (new_f == NULL)
546 goto out;
547
548 memset(new_f, 0, sizeof(struct fib_node));
549
550 new_f->fn_key = key;
551#ifdef CONFIG_IP_ROUTE_TOS
552 new_f->fn_tos = tos;
553#endif
554 new_f->fn_type = type;
555 new_f->fn_scope = r->rtm_scope;
556 FIB_INFO(new_f) = fi;
557
558
559
560
561
562 new_f->fn_next = f;
563 *fp = new_f;
564 fz->fz_nent++;
565
566 if (del_fp) {
567 f = *del_fp;
568
569 *del_fp = f->fn_next;
570 synchronize_bh();
571
572 if (!(f->fn_state&FN_S_ZOMBIE))
573 rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
574 if (f->fn_state&FN_S_ACCESSED)
575 rt_cache_flush(-1);
576 fn_free_node(f);
577 fz->fz_nent--;
578 } else {
579 rt_cache_flush(-1);
580 }
581 rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->tb_id, n, req);
582 return 0;
583
584out:
585 fib_release_info(fi);
586 return err;
587}
588
589
590static int
591fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
592 struct nlmsghdr *n, struct netlink_skb_parms *req)
593{
594 struct fn_hash *table = (struct fn_hash*)tb->tb_data;
595 struct fib_node **fp, **del_fp, *f;
596 int z = r->rtm_dst_len;
597 struct fn_zone *fz;
598 fn_key_t key;
599 int matched;
600#ifdef CONFIG_IP_ROUTE_TOS
601 u8 tos = r->rtm_tos;
602#endif
603
604FTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
605 *(u32*)rta->rta_dst : 0, z, rta->rta_oif ? *rta->rta_oif : -1);
606 if (z > 32)
607 return -EINVAL;
608 if ((fz = table->fn_zones[z]) == NULL)
609 return -ESRCH;
610
611 fz_key_0(key);
612 if (rta->rta_dst) {
613 u32 dst;
614 memcpy(&dst, rta->rta_dst, 4);
615 if (dst & ~FZ_MASK(fz))
616 return -EINVAL;
617 key = fz_key(dst, fz);
618 }
619
620 fp = fz_chain_p(key, fz);
621
622 FIB_SCAN(f, fp) {
623 if (fn_key_eq(f->fn_key, key))
624 break;
625 if (fn_key_leq(key, f->fn_key))
626 return -ESRCH;
627 }
628#ifdef CONFIG_IP_ROUTE_TOS
629 FIB_SCAN_KEY(f, fp, key) {
630 if (f->fn_tos == tos)
631 break;
632 }
633#endif
634
635 matched = 0;
636 del_fp = NULL;
637 FIB_SCAN_TOS(f, fp, key, tos) {
638 struct fib_info * fi = FIB_INFO(f);
639
640 if (f->fn_state&FN_S_ZOMBIE)
641 return -ESRCH;
642
643 matched++;
644
645 if (del_fp == NULL &&
646 (!r->rtm_type || f->fn_type == r->rtm_type) &&
647 (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
648 (!r->rtm_protocol || fi->fib_protocol == r->rtm_protocol) &&
649 fib_nh_match(r, n, rta, fi) == 0)
650 del_fp = fp;
651 }
652
653 if (del_fp) {
654 f = *del_fp;
655 rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
656
657 if (matched != 1) {
658 *del_fp = f->fn_next;
659 synchronize_bh();
660
661 if (f->fn_state&FN_S_ACCESSED)
662 rt_cache_flush(-1);
663 fn_free_node(f);
664 fz->fz_nent--;
665 } else {
666 f->fn_state |= FN_S_ZOMBIE;
667 if (f->fn_state&FN_S_ACCESSED) {
668 f->fn_state &= ~FN_S_ACCESSED;
669 rt_cache_flush(-1);
670 }
671 if (++fib_hash_zombies > 128)
672 fib_flush();
673 }
674
675 return 0;
676 }
677 return -ESRCH;
678}
679
680extern __inline__ int
681fn_flush_list(struct fib_node ** fp, int z, struct fn_hash *table)
682{
683 int found = 0;
684 struct fib_node *f;
685
686 while ((f = *fp) != NULL) {
687 struct fib_info *fi = FIB_INFO(f);
688
689 if (fi && ((f->fn_state&FN_S_ZOMBIE) || (fi->fib_flags&RTNH_F_DEAD))) {
690 *fp = f->fn_next;
691 synchronize_bh();
692
693 fn_free_node(f);
694 found++;
695 continue;
696 }
697 fp = &f->fn_next;
698 }
699 return found;
700}
701
702static int fn_hash_flush(struct fib_table *tb)
703{
704 struct fn_hash *table = (struct fn_hash*)tb->tb_data;
705 struct fn_zone *fz;
706 int found = 0;
707
708 fib_hash_zombies = 0;
709 for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
710 int i;
711 int tmp = 0;
712 for (i=fz->fz_divisor-1; i>=0; i--)
713 tmp += fn_flush_list(&fz->fz_hash[i], fz->fz_order, table);
714 fz->fz_nent -= tmp;
715 found += tmp;
716 }
717 return found;
718}
719
720
721#ifdef CONFIG_PROC_FS
722
723static int fn_hash_get_info(struct fib_table *tb, char *buffer, int first, int count)
724{
725 struct fn_hash *table = (struct fn_hash*)tb->tb_data;
726 struct fn_zone *fz;
727 int pos = 0;
728 int n = 0;
729
730 for (fz=table->fn_zone_list; fz; fz = fz->fz_next) {
731 int i;
732 struct fib_node *f;
733 int maxslot = fz->fz_divisor;
734 struct fib_node **fp = fz->fz_hash;
735
736 if (fz->fz_nent == 0)
737 continue;
738
739 if (pos + fz->fz_nent <= first) {
740 pos += fz->fz_nent;
741 continue;
742 }
743
744 for (i=0; i < maxslot; i++, fp++) {
745 for (f = *fp; f; f = f->fn_next) {
746 if (++pos <= first)
747 continue;
748 fib_node_get_info(f->fn_type,
749 f->fn_state&FN_S_ZOMBIE,
750 FIB_INFO(f),
751 fz_prefix(f->fn_key, fz),
752 FZ_MASK(fz), buffer);
753 buffer += 128;
754 if (++n >= count)
755 return n;
756 }
757 }
758 }
759 return n;
760}
761#endif
762
763
764#ifdef CONFIG_RTNETLINK
765
766extern __inline__ int
767fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
768 struct fib_table *tb,
769 struct fn_zone *fz,
770 struct fib_node *f)
771{
772 int i, s_i;
773
774 s_i = cb->args[3];
775 for (i=0; f; i++, f=f->fn_next) {
776 if (i < s_i) continue;
777 if (f->fn_state&FN_S_ZOMBIE) continue;
778 if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
779 RTM_NEWROUTE,
780 tb->tb_id, (f->fn_state&FN_S_ZOMBIE) ? 0 : f->fn_type, f->fn_scope,
781 &f->fn_key, fz->fz_order, f->fn_tos,
782 f->fn_info) < 0) {
783 cb->args[3] = i;
784 return -1;
785 }
786 }
787 cb->args[3] = i;
788 return skb->len;
789}
790
791extern __inline__ int
792fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb,
793 struct fib_table *tb,
794 struct fn_zone *fz)
795{
796 int h, s_h;
797
798 s_h = cb->args[2];
799 for (h=0; h < fz->fz_divisor; h++) {
800 if (h < s_h) continue;
801 if (h > s_h)
802 memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
803 if (fz->fz_hash == NULL || fz->fz_hash[h] == NULL)
804 continue;
805 if (fn_hash_dump_bucket(skb, cb, tb, fz, fz->fz_hash[h]) < 0) {
806 cb->args[2] = h;
807 return -1;
808 }
809 }
810 cb->args[2] = h;
811 return skb->len;
812}
813
814static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlink_callback *cb)
815{
816 int m, s_m;
817 struct fn_zone *fz;
818 struct fn_hash *table = (struct fn_hash*)tb->tb_data;
819
820 s_m = cb->args[1];
821 for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
822 if (m < s_m) continue;
823 if (m > s_m)
824 memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));
825 if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
826 cb->args[1] = m;
827 return -1;
828 }
829 }
830 cb->args[1] = m;
831 return skb->len;
832}
833
834static void rtmsg_fib(int event, struct fib_node* f, int z, int tb_id,
835 struct nlmsghdr *n, struct netlink_skb_parms *req)
836{
837 struct sk_buff *skb;
838 u32 pid = req ? req->pid : 0;
839 int size = NLMSG_SPACE(sizeof(struct rtmsg)+256);
840
841 skb = alloc_skb(size, GFP_KERNEL);
842 if (!skb)
843 return;
844
845 if (fib_dump_info(skb, pid, n->nlmsg_seq, event, tb_id,
846 f->fn_type, f->fn_scope, &f->fn_key, z, f->fn_tos,
847 FIB_INFO(f)) < 0) {
848 kfree_skb(skb);
849 return;
850 }
851 NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_ROUTE;
852 if (n->nlmsg_flags&NLM_F_ECHO)
853 atomic_inc(&skb->users);
854 netlink_broadcast(rtnl, skb, pid, RTMGRP_IPV4_ROUTE, GFP_KERNEL);
855 if (n->nlmsg_flags&NLM_F_ECHO)
856 netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
857}
858
859#endif
860
861#ifdef CONFIG_IP_MULTIPLE_TABLES
862struct fib_table * fib_hash_init(int id)
863#else
864__initfunc(struct fib_table * fib_hash_init(int id))
865#endif
866{
867 struct fib_table *tb;
868 tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash), GFP_KERNEL);
869 if (tb == NULL)
870 return NULL;
871 tb->tb_id = id;
872 tb->tb_lookup = fn_hash_lookup;
873 tb->tb_insert = fn_hash_insert;
874 tb->tb_delete = fn_hash_delete;
875 tb->tb_flush = fn_hash_flush;
876 tb->tb_select_default = fn_hash_select_default;
877#ifdef CONFIG_RTNETLINK
878 tb->tb_dump = fn_hash_dump;
879#endif
880#ifdef CONFIG_PROC_FS
881 tb->tb_get_info = fn_hash_get_info;
882#endif
883 memset(tb->tb_data, 0, sizeof(struct fn_hash));
884 return tb;
885}
886