diff options
Diffstat (limited to 'net/ipv4/fib_hash.c')
-rw-r--r-- | net/ipv4/fib_hash.c | 126 |
1 files changed, 60 insertions, 66 deletions
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 72c633b357cf..88133b383dc5 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c | |||
@@ -379,42 +379,39 @@ static struct fib_node *fib_find_node(struct fn_zone *fz, u32 key) | |||
379 | return NULL; | 379 | return NULL; |
380 | } | 380 | } |
381 | 381 | ||
382 | static int | 382 | static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg) |
383 | fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | ||
384 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
385 | { | 383 | { |
386 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; | 384 | struct fn_hash *table = (struct fn_hash *) tb->tb_data; |
387 | struct fib_node *new_f, *f; | 385 | struct fib_node *new_f, *f; |
388 | struct fib_alias *fa, *new_fa; | 386 | struct fib_alias *fa, *new_fa; |
389 | struct fn_zone *fz; | 387 | struct fn_zone *fz; |
390 | struct fib_info *fi; | 388 | struct fib_info *fi; |
391 | int z = r->rtm_dst_len; | 389 | u8 tos = cfg->fc_tos; |
392 | int type = r->rtm_type; | ||
393 | u8 tos = r->rtm_tos; | ||
394 | u32 key; | 390 | u32 key; |
395 | int err; | 391 | int err; |
396 | 392 | ||
397 | if (z > 32) | 393 | if (cfg->fc_dst_len > 32) |
398 | return -EINVAL; | 394 | return -EINVAL; |
399 | fz = table->fn_zones[z]; | 395 | |
400 | if (!fz && !(fz = fn_new_zone(table, z))) | 396 | fz = table->fn_zones[cfg->fc_dst_len]; |
397 | if (!fz && !(fz = fn_new_zone(table, cfg->fc_dst_len))) | ||
401 | return -ENOBUFS; | 398 | return -ENOBUFS; |
402 | 399 | ||
403 | key = 0; | 400 | key = 0; |
404 | if (rta->rta_dst) { | 401 | if (cfg->fc_dst) { |
405 | u32 dst; | 402 | if (cfg->fc_dst & ~FZ_MASK(fz)) |
406 | memcpy(&dst, rta->rta_dst, 4); | ||
407 | if (dst & ~FZ_MASK(fz)) | ||
408 | return -EINVAL; | 403 | return -EINVAL; |
409 | key = fz_key(dst, fz); | 404 | key = fz_key(cfg->fc_dst, fz); |
410 | } | 405 | } |
411 | 406 | ||
412 | if ((fi = fib_create_info(r, rta, n, &err)) == NULL) | 407 | fi = fib_create_info(cfg); |
413 | return err; | 408 | if (IS_ERR(fi)) |
409 | return PTR_ERR(fi); | ||
414 | 410 | ||
415 | if (fz->fz_nent > (fz->fz_divisor<<1) && | 411 | if (fz->fz_nent > (fz->fz_divisor<<1) && |
416 | fz->fz_divisor < FZ_MAX_DIVISOR && | 412 | fz->fz_divisor < FZ_MAX_DIVISOR && |
417 | (z==32 || (1<<z) > fz->fz_divisor)) | 413 | (cfg->fc_dst_len == 32 || |
414 | (1 << cfg->fc_dst_len) > fz->fz_divisor)) | ||
418 | fn_rehash_zone(fz); | 415 | fn_rehash_zone(fz); |
419 | 416 | ||
420 | f = fib_find_node(fz, key); | 417 | f = fib_find_node(fz, key); |
@@ -440,18 +437,18 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
440 | struct fib_alias *fa_orig; | 437 | struct fib_alias *fa_orig; |
441 | 438 | ||
442 | err = -EEXIST; | 439 | err = -EEXIST; |
443 | if (n->nlmsg_flags & NLM_F_EXCL) | 440 | if (cfg->fc_nlflags & NLM_F_EXCL) |
444 | goto out; | 441 | goto out; |
445 | 442 | ||
446 | if (n->nlmsg_flags & NLM_F_REPLACE) { | 443 | if (cfg->fc_nlflags & NLM_F_REPLACE) { |
447 | struct fib_info *fi_drop; | 444 | struct fib_info *fi_drop; |
448 | u8 state; | 445 | u8 state; |
449 | 446 | ||
450 | write_lock_bh(&fib_hash_lock); | 447 | write_lock_bh(&fib_hash_lock); |
451 | fi_drop = fa->fa_info; | 448 | fi_drop = fa->fa_info; |
452 | fa->fa_info = fi; | 449 | fa->fa_info = fi; |
453 | fa->fa_type = type; | 450 | fa->fa_type = cfg->fc_type; |
454 | fa->fa_scope = r->rtm_scope; | 451 | fa->fa_scope = cfg->fc_scope; |
455 | state = fa->fa_state; | 452 | state = fa->fa_state; |
456 | fa->fa_state &= ~FA_S_ACCESSED; | 453 | fa->fa_state &= ~FA_S_ACCESSED; |
457 | fib_hash_genid++; | 454 | fib_hash_genid++; |
@@ -474,17 +471,17 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
474 | break; | 471 | break; |
475 | if (fa->fa_info->fib_priority != fi->fib_priority) | 472 | if (fa->fa_info->fib_priority != fi->fib_priority) |
476 | break; | 473 | break; |
477 | if (fa->fa_type == type && | 474 | if (fa->fa_type == cfg->fc_type && |
478 | fa->fa_scope == r->rtm_scope && | 475 | fa->fa_scope == cfg->fc_scope && |
479 | fa->fa_info == fi) | 476 | fa->fa_info == fi) |
480 | goto out; | 477 | goto out; |
481 | } | 478 | } |
482 | if (!(n->nlmsg_flags & NLM_F_APPEND)) | 479 | if (!(cfg->fc_nlflags & NLM_F_APPEND)) |
483 | fa = fa_orig; | 480 | fa = fa_orig; |
484 | } | 481 | } |
485 | 482 | ||
486 | err = -ENOENT; | 483 | err = -ENOENT; |
487 | if (!(n->nlmsg_flags&NLM_F_CREATE)) | 484 | if (!(cfg->fc_nlflags & NLM_F_CREATE)) |
488 | goto out; | 485 | goto out; |
489 | 486 | ||
490 | err = -ENOBUFS; | 487 | err = -ENOBUFS; |
@@ -506,8 +503,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
506 | 503 | ||
507 | new_fa->fa_info = fi; | 504 | new_fa->fa_info = fi; |
508 | new_fa->fa_tos = tos; | 505 | new_fa->fa_tos = tos; |
509 | new_fa->fa_type = type; | 506 | new_fa->fa_type = cfg->fc_type; |
510 | new_fa->fa_scope = r->rtm_scope; | 507 | new_fa->fa_scope = cfg->fc_scope; |
511 | new_fa->fa_state = 0; | 508 | new_fa->fa_state = 0; |
512 | 509 | ||
513 | /* | 510 | /* |
@@ -526,7 +523,8 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
526 | fz->fz_nent++; | 523 | fz->fz_nent++; |
527 | rt_cache_flush(-1); | 524 | rt_cache_flush(-1); |
528 | 525 | ||
529 | rtmsg_fib(RTM_NEWROUTE, key, new_fa, z, tb->tb_id, n, req); | 526 | rtmsg_fib(RTM_NEWROUTE, key, new_fa, cfg->fc_dst_len, tb->tb_id, |
527 | &cfg->fc_nlinfo); | ||
530 | return 0; | 528 | return 0; |
531 | 529 | ||
532 | out_free_new_fa: | 530 | out_free_new_fa: |
@@ -537,30 +535,25 @@ out: | |||
537 | } | 535 | } |
538 | 536 | ||
539 | 537 | ||
540 | static int | 538 | static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg) |
541 | fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | ||
542 | struct nlmsghdr *n, struct netlink_skb_parms *req) | ||
543 | { | 539 | { |
544 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; | 540 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; |
545 | struct fib_node *f; | 541 | struct fib_node *f; |
546 | struct fib_alias *fa, *fa_to_delete; | 542 | struct fib_alias *fa, *fa_to_delete; |
547 | int z = r->rtm_dst_len; | ||
548 | struct fn_zone *fz; | 543 | struct fn_zone *fz; |
549 | u32 key; | 544 | u32 key; |
550 | u8 tos = r->rtm_tos; | ||
551 | 545 | ||
552 | if (z > 32) | 546 | if (cfg->fc_dst_len > 32) |
553 | return -EINVAL; | 547 | return -EINVAL; |
554 | if ((fz = table->fn_zones[z]) == NULL) | 548 | |
549 | if ((fz = table->fn_zones[cfg->fc_dst_len]) == NULL) | ||
555 | return -ESRCH; | 550 | return -ESRCH; |
556 | 551 | ||
557 | key = 0; | 552 | key = 0; |
558 | if (rta->rta_dst) { | 553 | if (cfg->fc_dst) { |
559 | u32 dst; | 554 | if (cfg->fc_dst & ~FZ_MASK(fz)) |
560 | memcpy(&dst, rta->rta_dst, 4); | ||
561 | if (dst & ~FZ_MASK(fz)) | ||
562 | return -EINVAL; | 555 | return -EINVAL; |
563 | key = fz_key(dst, fz); | 556 | key = fz_key(cfg->fc_dst, fz); |
564 | } | 557 | } |
565 | 558 | ||
566 | f = fib_find_node(fz, key); | 559 | f = fib_find_node(fz, key); |
@@ -568,7 +561,7 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
568 | if (!f) | 561 | if (!f) |
569 | fa = NULL; | 562 | fa = NULL; |
570 | else | 563 | else |
571 | fa = fib_find_alias(&f->fn_alias, tos, 0); | 564 | fa = fib_find_alias(&f->fn_alias, cfg->fc_tos, 0); |
572 | if (!fa) | 565 | if (!fa) |
573 | return -ESRCH; | 566 | return -ESRCH; |
574 | 567 | ||
@@ -577,16 +570,16 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
577 | list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { | 570 | list_for_each_entry_continue(fa, &f->fn_alias, fa_list) { |
578 | struct fib_info *fi = fa->fa_info; | 571 | struct fib_info *fi = fa->fa_info; |
579 | 572 | ||
580 | if (fa->fa_tos != tos) | 573 | if (fa->fa_tos != cfg->fc_tos) |
581 | break; | 574 | break; |
582 | 575 | ||
583 | if ((!r->rtm_type || | 576 | if ((!cfg->fc_type || |
584 | fa->fa_type == r->rtm_type) && | 577 | fa->fa_type == cfg->fc_type) && |
585 | (r->rtm_scope == RT_SCOPE_NOWHERE || | 578 | (cfg->fc_scope == RT_SCOPE_NOWHERE || |
586 | fa->fa_scope == r->rtm_scope) && | 579 | fa->fa_scope == cfg->fc_scope) && |
587 | (!r->rtm_protocol || | 580 | (!cfg->fc_protocol || |
588 | fi->fib_protocol == r->rtm_protocol) && | 581 | fi->fib_protocol == cfg->fc_protocol) && |
589 | fib_nh_match(r, n, rta, fi) == 0) { | 582 | fib_nh_match(cfg, fi) == 0) { |
590 | fa_to_delete = fa; | 583 | fa_to_delete = fa; |
591 | break; | 584 | break; |
592 | } | 585 | } |
@@ -596,7 +589,8 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, | |||
596 | int kill_fn; | 589 | int kill_fn; |
597 | 590 | ||
598 | fa = fa_to_delete; | 591 | fa = fa_to_delete; |
599 | rtmsg_fib(RTM_DELROUTE, key, fa, z, tb->tb_id, n, req); | 592 | rtmsg_fib(RTM_DELROUTE, key, fa, cfg->fc_dst_len, |
593 | tb->tb_id, &cfg->fc_nlinfo); | ||
600 | 594 | ||
601 | kill_fn = 0; | 595 | kill_fn = 0; |
602 | write_lock_bh(&fib_hash_lock); | 596 | write_lock_bh(&fib_hash_lock); |
@@ -684,7 +678,7 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb, | |||
684 | struct fib_node *f; | 678 | struct fib_node *f; |
685 | int i, s_i; | 679 | int i, s_i; |
686 | 680 | ||
687 | s_i = cb->args[3]; | 681 | s_i = cb->args[4]; |
688 | i = 0; | 682 | i = 0; |
689 | hlist_for_each_entry(f, node, head, fn_hash) { | 683 | hlist_for_each_entry(f, node, head, fn_hash) { |
690 | struct fib_alias *fa; | 684 | struct fib_alias *fa; |
@@ -699,19 +693,19 @@ fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb, | |||
699 | tb->tb_id, | 693 | tb->tb_id, |
700 | fa->fa_type, | 694 | fa->fa_type, |
701 | fa->fa_scope, | 695 | fa->fa_scope, |
702 | &f->fn_key, | 696 | f->fn_key, |
703 | fz->fz_order, | 697 | fz->fz_order, |
704 | fa->fa_tos, | 698 | fa->fa_tos, |
705 | fa->fa_info, | 699 | fa->fa_info, |
706 | NLM_F_MULTI) < 0) { | 700 | NLM_F_MULTI) < 0) { |
707 | cb->args[3] = i; | 701 | cb->args[4] = i; |
708 | return -1; | 702 | return -1; |
709 | } | 703 | } |
710 | next: | 704 | next: |
711 | i++; | 705 | i++; |
712 | } | 706 | } |
713 | } | 707 | } |
714 | cb->args[3] = i; | 708 | cb->args[4] = i; |
715 | return skb->len; | 709 | return skb->len; |
716 | } | 710 | } |
717 | 711 | ||
@@ -722,21 +716,21 @@ fn_hash_dump_zone(struct sk_buff *skb, struct netlink_callback *cb, | |||
722 | { | 716 | { |
723 | int h, s_h; | 717 | int h, s_h; |
724 | 718 | ||
725 | s_h = cb->args[2]; | 719 | s_h = cb->args[3]; |
726 | for (h=0; h < fz->fz_divisor; h++) { | 720 | for (h=0; h < fz->fz_divisor; h++) { |
727 | if (h < s_h) continue; | 721 | if (h < s_h) continue; |
728 | if (h > s_h) | 722 | if (h > s_h) |
729 | memset(&cb->args[3], 0, | 723 | memset(&cb->args[4], 0, |
730 | sizeof(cb->args) - 3*sizeof(cb->args[0])); | 724 | sizeof(cb->args) - 4*sizeof(cb->args[0])); |
731 | if (fz->fz_hash == NULL || | 725 | if (fz->fz_hash == NULL || |
732 | hlist_empty(&fz->fz_hash[h])) | 726 | hlist_empty(&fz->fz_hash[h])) |
733 | continue; | 727 | continue; |
734 | if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) { | 728 | if (fn_hash_dump_bucket(skb, cb, tb, fz, &fz->fz_hash[h])<0) { |
735 | cb->args[2] = h; | 729 | cb->args[3] = h; |
736 | return -1; | 730 | return -1; |
737 | } | 731 | } |
738 | } | 732 | } |
739 | cb->args[2] = h; | 733 | cb->args[3] = h; |
740 | return skb->len; | 734 | return skb->len; |
741 | } | 735 | } |
742 | 736 | ||
@@ -746,28 +740,28 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin | |||
746 | struct fn_zone *fz; | 740 | struct fn_zone *fz; |
747 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; | 741 | struct fn_hash *table = (struct fn_hash*)tb->tb_data; |
748 | 742 | ||
749 | s_m = cb->args[1]; | 743 | s_m = cb->args[2]; |
750 | read_lock(&fib_hash_lock); | 744 | read_lock(&fib_hash_lock); |
751 | for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { | 745 | for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) { |
752 | if (m < s_m) continue; | 746 | if (m < s_m) continue; |
753 | if (m > s_m) | 747 | if (m > s_m) |
754 | memset(&cb->args[2], 0, | 748 | memset(&cb->args[3], 0, |
755 | sizeof(cb->args) - 2*sizeof(cb->args[0])); | 749 | sizeof(cb->args) - 3*sizeof(cb->args[0])); |
756 | if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { | 750 | if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) { |
757 | cb->args[1] = m; | 751 | cb->args[2] = m; |
758 | read_unlock(&fib_hash_lock); | 752 | read_unlock(&fib_hash_lock); |
759 | return -1; | 753 | return -1; |
760 | } | 754 | } |
761 | } | 755 | } |
762 | read_unlock(&fib_hash_lock); | 756 | read_unlock(&fib_hash_lock); |
763 | cb->args[1] = m; | 757 | cb->args[2] = m; |
764 | return skb->len; | 758 | return skb->len; |
765 | } | 759 | } |
766 | 760 | ||
767 | #ifdef CONFIG_IP_MULTIPLE_TABLES | 761 | #ifdef CONFIG_IP_MULTIPLE_TABLES |
768 | struct fib_table * fib_hash_init(int id) | 762 | struct fib_table * fib_hash_init(u32 id) |
769 | #else | 763 | #else |
770 | struct fib_table * __init fib_hash_init(int id) | 764 | struct fib_table * __init fib_hash_init(u32 id) |
771 | #endif | 765 | #endif |
772 | { | 766 | { |
773 | struct fib_table *tb; | 767 | struct fib_table *tb; |