aboutsummaryrefslogtreecommitdiffstats
path: root/net/decnet/dn_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/decnet/dn_table.c')
-rw-r--r--net/decnet/dn_table.c175
1 files changed, 114 insertions, 61 deletions
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index 0ebc46af1bdd..317904bb5896 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -12,7 +12,6 @@
12 * Changes: 12 * Changes:
13 * 13 *
14 */ 14 */
15#include <linux/config.h>
16#include <linux/string.h> 15#include <linux/string.h>
17#include <linux/net.h> 16#include <linux/net.h>
18#include <linux/socket.h> 17#include <linux/socket.h>
@@ -31,6 +30,7 @@
31#include <net/neighbour.h> 30#include <net/neighbour.h>
32#include <net/dst.h> 31#include <net/dst.h>
33#include <net/flow.h> 32#include <net/flow.h>
33#include <net/fib_rules.h>
34#include <net/dn.h> 34#include <net/dn.h>
35#include <net/dn_route.h> 35#include <net/dn_route.h>
36#include <net/dn_fib.h> 36#include <net/dn_fib.h>
@@ -75,9 +75,9 @@ for( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
75for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next) 75for( ; ((f) = *(fp)) != NULL && dn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
76 76
77#define RT_TABLE_MIN 1 77#define RT_TABLE_MIN 1
78 78#define DN_FIB_TABLE_HASHSZ 256
79static struct hlist_head dn_fib_table_hash[DN_FIB_TABLE_HASHSZ];
79static DEFINE_RWLOCK(dn_fib_tables_lock); 80static DEFINE_RWLOCK(dn_fib_tables_lock);
80struct dn_fib_table *dn_fib_tables[RT_TABLE_MAX + 1];
81 81
82static kmem_cache_t *dn_hash_kmem __read_mostly; 82static kmem_cache_t *dn_hash_kmem __read_mostly;
83static int dn_fib_hash_zombies; 83static int dn_fib_hash_zombies;
@@ -159,12 +159,10 @@ static void dn_rehash_zone(struct dn_zone *dz)
159 break; 159 break;
160 } 160 }
161 161
162 ht = kmalloc(new_divisor*sizeof(struct dn_fib_node*), GFP_KERNEL); 162 ht = kcalloc(new_divisor, sizeof(struct dn_fib_node*), GFP_KERNEL);
163
164 if (ht == NULL) 163 if (ht == NULL)
165 return; 164 return;
166 165
167 memset(ht, 0, new_divisor*sizeof(struct dn_fib_node *));
168 write_lock_bh(&dn_fib_tables_lock); 166 write_lock_bh(&dn_fib_tables_lock);
169 old_ht = dz->dz_hash; 167 old_ht = dz->dz_hash;
170 dz->dz_hash = ht; 168 dz->dz_hash = ht;
@@ -185,11 +183,10 @@ static void dn_free_node(struct dn_fib_node *f)
185static struct dn_zone *dn_new_zone(struct dn_hash *table, int z) 183static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
186{ 184{
187 int i; 185 int i;
188 struct dn_zone *dz = kmalloc(sizeof(struct dn_zone), GFP_KERNEL); 186 struct dn_zone *dz = kzalloc(sizeof(struct dn_zone), GFP_KERNEL);
189 if (!dz) 187 if (!dz)
190 return NULL; 188 return NULL;
191 189
192 memset(dz, 0, sizeof(struct dn_zone));
193 if (z) { 190 if (z) {
194 dz->dz_divisor = 16; 191 dz->dz_divisor = 16;
195 dz->dz_hashmask = 0x0F; 192 dz->dz_hashmask = 0x0F;
@@ -198,14 +195,12 @@ static struct dn_zone *dn_new_zone(struct dn_hash *table, int z)
198 dz->dz_hashmask = 0; 195 dz->dz_hashmask = 0;
199 } 196 }
200 197
201 dz->dz_hash = kmalloc(dz->dz_divisor*sizeof(struct dn_fib_node *), GFP_KERNEL); 198 dz->dz_hash = kcalloc(dz->dz_divisor, sizeof(struct dn_fib_node *), GFP_KERNEL);
202
203 if (!dz->dz_hash) { 199 if (!dz->dz_hash) {
204 kfree(dz); 200 kfree(dz);
205 return NULL; 201 return NULL;
206 } 202 }
207 203
208 memset(dz->dz_hash, 0, dz->dz_divisor*sizeof(struct dn_fib_node*));
209 dz->dz_order = z; 204 dz->dz_order = z;
210 dz->dz_mask = dnet_make_mask(z); 205 dz->dz_mask = dnet_make_mask(z);
211 206
@@ -269,7 +264,7 @@ static int dn_fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct dn_kern
269} 264}
270 265
271static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, 266static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
272 u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, 267 u32 tb_id, u8 type, u8 scope, void *dst, int dst_len,
273 struct dn_fib_info *fi, unsigned int flags) 268 struct dn_fib_info *fi, unsigned int flags)
274{ 269{
275 struct rtmsg *rtm; 270 struct rtmsg *rtm;
@@ -283,6 +278,7 @@ static int dn_fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
283 rtm->rtm_src_len = 0; 278 rtm->rtm_src_len = 0;
284 rtm->rtm_tos = 0; 279 rtm->rtm_tos = 0;
285 rtm->rtm_table = tb_id; 280 rtm->rtm_table = tb_id;
281 RTA_PUT_U32(skb, RTA_TABLE, tb_id);
286 rtm->rtm_flags = fi->fib_flags; 282 rtm->rtm_flags = fi->fib_flags;
287 rtm->rtm_scope = scope; 283 rtm->rtm_scope = scope;
288 rtm->rtm_type = type; 284 rtm->rtm_type = type;
@@ -332,29 +328,29 @@ rtattr_failure:
332} 328}
333 329
334 330
335static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, int tb_id, 331static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
336 struct nlmsghdr *nlh, struct netlink_skb_parms *req) 332 struct nlmsghdr *nlh, struct netlink_skb_parms *req)
337{ 333{
338 struct sk_buff *skb; 334 struct sk_buff *skb;
339 u32 pid = req ? req->pid : 0; 335 u32 pid = req ? req->pid : 0;
340 int size = NLMSG_SPACE(sizeof(struct rtmsg) + 256); 336 int err = -ENOBUFS;
341 337
342 skb = alloc_skb(size, GFP_KERNEL); 338 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
343 if (!skb) 339 if (skb == NULL)
344 return; 340 goto errout;
345 341
346 if (dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id, 342 err = dn_fib_dump_info(skb, pid, nlh->nlmsg_seq, event, tb_id,
347 f->fn_type, f->fn_scope, &f->fn_key, z, 343 f->fn_type, f->fn_scope, &f->fn_key, z,
348 DN_FIB_INFO(f), 0) < 0) { 344 DN_FIB_INFO(f), 0);
345 if (err < 0) {
349 kfree_skb(skb); 346 kfree_skb(skb);
350 return; 347 goto errout;
351 } 348 }
352 NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_ROUTE; 349
353 if (nlh->nlmsg_flags & NLM_F_ECHO) 350 err = rtnl_notify(skb, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
354 atomic_inc(&skb->users); 351errout:
355 netlink_broadcast(rtnl, skb, pid, RTNLGRP_DECnet_ROUTE, GFP_KERNEL); 352 if (err < 0)
356 if (nlh->nlmsg_flags & NLM_F_ECHO) 353 rtnl_set_sk_err(RTNLGRP_DECnet_ROUTE, err);
357 netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
358} 354}
359 355
360static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb, 356static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
@@ -365,7 +361,7 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
365{ 361{
366 int i, s_i; 362 int i, s_i;
367 363
368 s_i = cb->args[3]; 364 s_i = cb->args[4];
369 for(i = 0; f; i++, f = f->fn_next) { 365 for(i = 0; f; i++, f = f->fn_next) {
370 if (i < s_i) 366 if (i < s_i)
371 continue; 367 continue;
@@ -378,11 +374,11 @@ static __inline__ int dn_hash_dump_bucket(struct sk_buff *skb,
378 (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type, 374 (f->fn_state & DN_S_ZOMBIE) ? 0 : f->fn_type,
379 f->fn_scope, &f->fn_key, dz->dz_order, 375 f->fn_scope, &f->fn_key, dz->dz_order,
380 f->fn_info, NLM_F_MULTI) < 0) { 376 f->fn_info, NLM_F_MULTI) < 0) {
381 cb->args[3] = i; 377 cb->args[4] = i;
382 return -1; 378 return -1;
383 } 379 }
384 } 380 }
385 cb->args[3] = i; 381 cb->args[4] = i;
386 return skb->len; 382 return skb->len;
387} 383}
388 384
@@ -393,20 +389,20 @@ static __inline__ int dn_hash_dump_zone(struct sk_buff *skb,
393{ 389{
394 int h, s_h; 390 int h, s_h;
395 391
396 s_h = cb->args[2]; 392 s_h = cb->args[3];
397 for(h = 0; h < dz->dz_divisor; h++) { 393 for(h = 0; h < dz->dz_divisor; h++) {
398 if (h < s_h) 394 if (h < s_h)
399 continue; 395 continue;
400 if (h > s_h) 396 if (h > s_h)
401 memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0])); 397 memset(&cb->args[4], 0, sizeof(cb->args) - 4*sizeof(cb->args[0]));
402 if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL) 398 if (dz->dz_hash == NULL || dz->dz_hash[h] == NULL)
403 continue; 399 continue;
404 if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) { 400 if (dn_hash_dump_bucket(skb, cb, tb, dz, dz->dz_hash[h]) < 0) {
405 cb->args[2] = h; 401 cb->args[3] = h;
406 return -1; 402 return -1;
407 } 403 }
408 } 404 }
409 cb->args[2] = h; 405 cb->args[3] = h;
410 return skb->len; 406 return skb->len;
411} 407}
412 408
@@ -417,26 +413,63 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb,
417 struct dn_zone *dz; 413 struct dn_zone *dz;
418 struct dn_hash *table = (struct dn_hash *)tb->data; 414 struct dn_hash *table = (struct dn_hash *)tb->data;
419 415
420 s_m = cb->args[1]; 416 s_m = cb->args[2];
421 read_lock(&dn_fib_tables_lock); 417 read_lock(&dn_fib_tables_lock);
422 for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) { 418 for(dz = table->dh_zone_list, m = 0; dz; dz = dz->dz_next, m++) {
423 if (m < s_m) 419 if (m < s_m)
424 continue; 420 continue;
425 if (m > s_m) 421 if (m > s_m)
426 memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0])); 422 memset(&cb->args[3], 0, sizeof(cb->args) - 3*sizeof(cb->args[0]));
427 423
428 if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) { 424 if (dn_hash_dump_zone(skb, cb, tb, dz) < 0) {
429 cb->args[1] = m; 425 cb->args[2] = m;
430 read_unlock(&dn_fib_tables_lock); 426 read_unlock(&dn_fib_tables_lock);
431 return -1; 427 return -1;
432 } 428 }
433 } 429 }
434 read_unlock(&dn_fib_tables_lock); 430 read_unlock(&dn_fib_tables_lock);
435 cb->args[1] = m; 431 cb->args[2] = m;
436 432
437 return skb->len; 433 return skb->len;
438} 434}
439 435
436int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
437{
438 unsigned int h, s_h;
439 unsigned int e = 0, s_e;
440 struct dn_fib_table *tb;
441 struct hlist_node *node;
442 int dumped = 0;
443
444 if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
445 ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
446 return dn_cache_dump(skb, cb);
447
448 s_h = cb->args[0];
449 s_e = cb->args[1];
450
451 for (h = s_h; h < DN_FIB_TABLE_HASHSZ; h++, s_h = 0) {
452 e = 0;
453 hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist) {
454 if (e < s_e)
455 goto next;
456 if (dumped)
457 memset(&cb->args[2], 0, sizeof(cb->args) -
458 2 * sizeof(cb->args[0]));
459 if (tb->dump(tb, skb, cb) < 0)
460 goto out;
461 dumped = 1;
462next:
463 e++;
464 }
465 }
466out:
467 cb->args[1] = e;
468 cb->args[0] = h;
469
470 return skb->len;
471}
472
440static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req) 473static int dn_fib_table_insert(struct dn_fib_table *tb, struct rtmsg *r, struct dn_kern_rta *rta, struct nlmsghdr *n, struct netlink_skb_parms *req)
441{ 474{
442 struct dn_hash *table = (struct dn_hash *)tb->data; 475 struct dn_hash *table = (struct dn_hash *)tb->data;
@@ -745,9 +778,11 @@ out:
745} 778}
746 779
747 780
748struct dn_fib_table *dn_fib_get_table(int n, int create) 781struct dn_fib_table *dn_fib_get_table(u32 n, int create)
749{ 782{
750 struct dn_fib_table *t; 783 struct dn_fib_table *t;
784 struct hlist_node *node;
785 unsigned int h;
751 786
752 if (n < RT_TABLE_MIN) 787 if (n < RT_TABLE_MIN)
753 return NULL; 788 return NULL;
@@ -755,8 +790,15 @@ struct dn_fib_table *dn_fib_get_table(int n, int create)
755 if (n > RT_TABLE_MAX) 790 if (n > RT_TABLE_MAX)
756 return NULL; 791 return NULL;
757 792
758 if (dn_fib_tables[n]) 793 h = n & (DN_FIB_TABLE_HASHSZ - 1);
759 return dn_fib_tables[n]; 794 rcu_read_lock();
795 hlist_for_each_entry_rcu(t, node, &dn_fib_table_hash[h], hlist) {
796 if (t->n == n) {
797 rcu_read_unlock();
798 return t;
799 }
800 }
801 rcu_read_unlock();
760 802
761 if (!create) 803 if (!create)
762 return NULL; 804 return NULL;
@@ -777,33 +819,37 @@ struct dn_fib_table *dn_fib_get_table(int n, int create)
777 t->flush = dn_fib_table_flush; 819 t->flush = dn_fib_table_flush;
778 t->dump = dn_fib_table_dump; 820 t->dump = dn_fib_table_dump;
779 memset(t->data, 0, sizeof(struct dn_hash)); 821 memset(t->data, 0, sizeof(struct dn_hash));
780 dn_fib_tables[n] = t; 822 hlist_add_head_rcu(&t->hlist, &dn_fib_table_hash[h]);
781 823
782 return t; 824 return t;
783} 825}
784 826
785static void dn_fib_del_tree(int n)
786{
787 struct dn_fib_table *t;
788
789 write_lock(&dn_fib_tables_lock);
790 t = dn_fib_tables[n];
791 dn_fib_tables[n] = NULL;
792 write_unlock(&dn_fib_tables_lock);
793
794 kfree(t);
795}
796
797struct dn_fib_table *dn_fib_empty_table(void) 827struct dn_fib_table *dn_fib_empty_table(void)
798{ 828{
799 int id; 829 u32 id;
800 830
801 for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++) 831 for(id = RT_TABLE_MIN; id <= RT_TABLE_MAX; id++)
802 if (dn_fib_tables[id] == NULL) 832 if (dn_fib_get_table(id, 0) == NULL)
803 return dn_fib_get_table(id, 1); 833 return dn_fib_get_table(id, 1);
804 return NULL; 834 return NULL;
805} 835}
806 836
837void dn_fib_flush(void)
838{
839 int flushed = 0;
840 struct dn_fib_table *tb;
841 struct hlist_node *node;
842 unsigned int h;
843
844 for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
845 hlist_for_each_entry(tb, node, &dn_fib_table_hash[h], hlist)
846 flushed += tb->flush(tb);
847 }
848
849 if (flushed)
850 dn_rt_cache_flush(-1);
851}
852
807void __init dn_fib_table_init(void) 853void __init dn_fib_table_init(void)
808{ 854{
809 dn_hash_kmem = kmem_cache_create("dn_fib_info_cache", 855 dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
@@ -814,10 +860,17 @@ void __init dn_fib_table_init(void)
814 860
815void __exit dn_fib_table_cleanup(void) 861void __exit dn_fib_table_cleanup(void)
816{ 862{
817 int i; 863 struct dn_fib_table *t;
818 864 struct hlist_node *node, *next;
819 for (i = RT_TABLE_MIN; i <= RT_TABLE_MAX; ++i) 865 unsigned int h;
820 dn_fib_del_tree(i);
821 866
822 return; 867 write_lock(&dn_fib_tables_lock);
868 for (h = 0; h < DN_FIB_TABLE_HASHSZ; h++) {
869 hlist_for_each_entry_safe(t, node, next, &dn_fib_table_hash[h],
870 hlist) {
871 hlist_del(&t->hlist);
872 kfree(t);
873 }
874 }
875 write_unlock(&dn_fib_tables_lock);
823} 876}