diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/fib_trie.c | 177 |
1 files changed, 145 insertions, 32 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 9038b914b4b1..4be234c7d8c3 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -43,7 +43,7 @@ | |||
43 | * 2 of the License, or (at your option) any later version. | 43 | * 2 of the License, or (at your option) any later version. |
44 | */ | 44 | */ |
45 | 45 | ||
46 | #define VERSION "0.324" | 46 | #define VERSION "0.325" |
47 | 47 | ||
48 | #include <linux/config.h> | 48 | #include <linux/config.h> |
49 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
@@ -136,6 +136,7 @@ struct trie_use_stats { | |||
136 | unsigned int semantic_match_passed; | 136 | unsigned int semantic_match_passed; |
137 | unsigned int semantic_match_miss; | 137 | unsigned int semantic_match_miss; |
138 | unsigned int null_node_hit; | 138 | unsigned int null_node_hit; |
139 | unsigned int resize_node_skipped; | ||
139 | }; | 140 | }; |
140 | #endif | 141 | #endif |
141 | 142 | ||
@@ -164,8 +165,8 @@ static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n); | |||
164 | static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull); | 165 | static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull); |
165 | static int tnode_child_length(struct tnode *tn); | 166 | static int tnode_child_length(struct tnode *tn); |
166 | static struct node *resize(struct trie *t, struct tnode *tn); | 167 | static struct node *resize(struct trie *t, struct tnode *tn); |
167 | static struct tnode *inflate(struct trie *t, struct tnode *tn); | 168 | static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err); |
168 | static struct tnode *halve(struct trie *t, struct tnode *tn); | 169 | static struct tnode *halve(struct trie *t, struct tnode *tn, int *err); |
169 | static void tnode_free(struct tnode *tn); | 170 | static void tnode_free(struct tnode *tn); |
170 | static void trie_dump_seq(struct seq_file *seq, struct trie *t); | 171 | static void trie_dump_seq(struct seq_file *seq, struct trie *t); |
171 | extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); | 172 | extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio); |
@@ -481,6 +482,7 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int w | |||
481 | static struct node *resize(struct trie *t, struct tnode *tn) | 482 | static struct node *resize(struct trie *t, struct tnode *tn) |
482 | { | 483 | { |
483 | int i; | 484 | int i; |
485 | int err = 0; | ||
484 | 486 | ||
485 | if (!tn) | 487 | if (!tn) |
486 | return NULL; | 488 | return NULL; |
@@ -577,12 +579,20 @@ static struct node *resize(struct trie *t, struct tnode *tn) | |||
577 | */ | 579 | */ |
578 | 580 | ||
579 | check_tnode(tn); | 581 | check_tnode(tn); |
580 | 582 | ||
583 | err = 0; | ||
581 | while ((tn->full_children > 0 && | 584 | while ((tn->full_children > 0 && |
582 | 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >= | 585 | 50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >= |
583 | inflate_threshold * tnode_child_length(tn))) { | 586 | inflate_threshold * tnode_child_length(tn))) { |
584 | 587 | ||
585 | tn = inflate(t, tn); | 588 | tn = inflate(t, tn, &err); |
589 | |||
590 | if(err) { | ||
591 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
592 | t->stats.resize_node_skipped++; | ||
593 | #endif | ||
594 | break; | ||
595 | } | ||
586 | } | 596 | } |
587 | 597 | ||
588 | check_tnode(tn); | 598 | check_tnode(tn); |
@@ -591,11 +601,22 @@ static struct node *resize(struct trie *t, struct tnode *tn) | |||
591 | * Halve as long as the number of empty children in this | 601 | * Halve as long as the number of empty children in this |
592 | * node is above threshold. | 602 | * node is above threshold. |
593 | */ | 603 | */ |
604 | |||
605 | err = 0; | ||
594 | while (tn->bits > 1 && | 606 | while (tn->bits > 1 && |
595 | 100 * (tnode_child_length(tn) - tn->empty_children) < | 607 | 100 * (tnode_child_length(tn) - tn->empty_children) < |
596 | halve_threshold * tnode_child_length(tn)) | 608 | halve_threshold * tnode_child_length(tn)) { |
609 | |||
610 | tn = halve(t, tn, &err); | ||
611 | |||
612 | if(err) { | ||
613 | #ifdef CONFIG_IP_FIB_TRIE_STATS | ||
614 | t->stats.resize_node_skipped++; | ||
615 | #endif | ||
616 | break; | ||
617 | } | ||
618 | } | ||
597 | 619 | ||
598 | tn = halve(t, tn); | ||
599 | 620 | ||
600 | /* Only one child remains */ | 621 | /* Only one child remains */ |
601 | 622 | ||
@@ -620,7 +641,7 @@ static struct node *resize(struct trie *t, struct tnode *tn) | |||
620 | return (struct node *) tn; | 641 | return (struct node *) tn; |
621 | } | 642 | } |
622 | 643 | ||
623 | static struct tnode *inflate(struct trie *t, struct tnode *tn) | 644 | static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err) |
624 | { | 645 | { |
625 | struct tnode *inode; | 646 | struct tnode *inode; |
626 | struct tnode *oldtnode = tn; | 647 | struct tnode *oldtnode = tn; |
@@ -632,8 +653,63 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) | |||
632 | 653 | ||
633 | tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1); | 654 | tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1); |
634 | 655 | ||
635 | if (!tn) | 656 | if (!tn) { |
636 | trie_bug("tnode_new failed"); | 657 | *err = -ENOMEM; |
658 | return oldtnode; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * Preallocate and store tnodes before the actual work so we | ||
663 | * don't get into an inconsistent state if memory allocation | ||
664 | * fails. In case of failure we return the oldnode and inflate | ||
665 | * of tnode is ignored. | ||
666 | */ | ||
667 | |||
668 | for(i = 0; i < olen; i++) { | ||
669 | struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i); | ||
670 | |||
671 | if (inode && | ||
672 | IS_TNODE(inode) && | ||
673 | inode->pos == oldtnode->pos + oldtnode->bits && | ||
674 | inode->bits > 1) { | ||
675 | struct tnode *left, *right; | ||
676 | |||
677 | t_key m = TKEY_GET_MASK(inode->pos, 1); | ||
678 | |||
679 | left = tnode_new(inode->key&(~m), inode->pos + 1, | ||
680 | inode->bits - 1); | ||
681 | |||
682 | if(!left) { | ||
683 | *err = -ENOMEM; | ||
684 | break; | ||
685 | } | ||
686 | |||
687 | right = tnode_new(inode->key|m, inode->pos + 1, | ||
688 | inode->bits - 1); | ||
689 | |||
690 | if(!right) { | ||
691 | *err = -ENOMEM; | ||
692 | break; | ||
693 | } | ||
694 | |||
695 | put_child(t, tn, 2*i, (struct node *) left); | ||
696 | put_child(t, tn, 2*i+1, (struct node *) right); | ||
697 | } | ||
698 | } | ||
699 | |||
700 | if(*err) { | ||
701 | int size = tnode_child_length(tn); | ||
702 | int j; | ||
703 | |||
704 | for(j = 0; j < size; j++) | ||
705 | if( tn->child[j]) | ||
706 | tnode_free((struct tnode *)tn->child[j]); | ||
707 | |||
708 | tnode_free(tn); | ||
709 | |||
710 | *err = -ENOMEM; | ||
711 | return oldtnode; | ||
712 | } | ||
637 | 713 | ||
638 | for(i = 0; i < olen; i++) { | 714 | for(i = 0; i < olen; i++) { |
639 | struct node *node = tnode_get_child(oldtnode, i); | 715 | struct node *node = tnode_get_child(oldtnode, i); |
@@ -646,7 +722,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) | |||
646 | 722 | ||
647 | if(IS_LEAF(node) || ((struct tnode *) node)->pos > | 723 | if(IS_LEAF(node) || ((struct tnode *) node)->pos > |
648 | tn->pos + tn->bits - 1) { | 724 | tn->pos + tn->bits - 1) { |
649 | if(tkey_extract_bits(node->key, tn->pos + tn->bits - 1, | 725 | if(tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits, |
650 | 1) == 0) | 726 | 1) == 0) |
651 | put_child(t, tn, 2*i, node); | 727 | put_child(t, tn, 2*i, node); |
652 | else | 728 | else |
@@ -686,27 +762,22 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) | |||
686 | * the position (inode->pos) | 762 | * the position (inode->pos) |
687 | */ | 763 | */ |
688 | 764 | ||
689 | t_key m = TKEY_GET_MASK(inode->pos, 1); | ||
690 | |||
691 | /* Use the old key, but set the new significant | 765 | /* Use the old key, but set the new significant |
692 | * bit to zero. | 766 | * bit to zero. |
693 | */ | 767 | */ |
694 | left = tnode_new(inode->key&(~m), inode->pos + 1, | ||
695 | inode->bits - 1); | ||
696 | 768 | ||
697 | if(!left) | 769 | left = (struct tnode *) tnode_get_child(tn, 2*i); |
698 | trie_bug("tnode_new failed"); | 770 | put_child(t, tn, 2*i, NULL); |
699 | 771 | ||
700 | 772 | if(!left) | |
701 | /* Use the old key, but set the new significant | 773 | BUG(); |
702 | * bit to one. | 774 | |
703 | */ | 775 | right = (struct tnode *) tnode_get_child(tn, 2*i+1); |
704 | right = tnode_new(inode->key|m, inode->pos + 1, | 776 | put_child(t, tn, 2*i+1, NULL); |
705 | inode->bits - 1); | 777 | |
778 | if(!right) | ||
779 | BUG(); | ||
706 | 780 | ||
707 | if(!right) | ||
708 | trie_bug("tnode_new failed"); | ||
709 | |||
710 | size = tnode_child_length(left); | 781 | size = tnode_child_length(left); |
711 | for(j = 0; j < size; j++) { | 782 | for(j = 0; j < size; j++) { |
712 | put_child(t, left, j, inode->child[j]); | 783 | put_child(t, left, j, inode->child[j]); |
@@ -722,7 +793,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn) | |||
722 | return tn; | 793 | return tn; |
723 | } | 794 | } |
724 | 795 | ||
725 | static struct tnode *halve(struct trie *t, struct tnode *tn) | 796 | static struct tnode *halve(struct trie *t, struct tnode *tn, int *err) |
726 | { | 797 | { |
727 | struct tnode *oldtnode = tn; | 798 | struct tnode *oldtnode = tn; |
728 | struct node *left, *right; | 799 | struct node *left, *right; |
@@ -733,8 +804,48 @@ static struct tnode *halve(struct trie *t, struct tnode *tn) | |||
733 | 804 | ||
734 | tn=tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1); | 805 | tn=tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1); |
735 | 806 | ||
736 | if(!tn) | 807 | if (!tn) { |
737 | trie_bug("tnode_new failed"); | 808 | *err = -ENOMEM; |
809 | return oldtnode; | ||
810 | } | ||
811 | |||
812 | /* | ||
813 | * Preallocate and store tnodes before the actual work so we | ||
814 | * don't get into an inconsistent state if memory allocation | ||
815 | * fails. In case of failure we return the oldnode and halve | ||
816 | * of tnode is ignored. | ||
817 | */ | ||
818 | |||
819 | for(i = 0; i < olen; i += 2) { | ||
820 | left = tnode_get_child(oldtnode, i); | ||
821 | right = tnode_get_child(oldtnode, i+1); | ||
822 | |||
823 | /* Two nonempty children */ | ||
824 | if( left && right) { | ||
825 | struct tnode *newBinNode = | ||
826 | tnode_new(left->key, tn->pos + tn->bits, 1); | ||
827 | |||
828 | if(!newBinNode) { | ||
829 | *err = -ENOMEM; | ||
830 | break; | ||
831 | } | ||
832 | put_child(t, tn, i/2, (struct node *)newBinNode); | ||
833 | } | ||
834 | } | ||
835 | |||
836 | if(*err) { | ||
837 | int size = tnode_child_length(tn); | ||
838 | int j; | ||
839 | |||
840 | for(j = 0; j < size; j++) | ||
841 | if( tn->child[j]) | ||
842 | tnode_free((struct tnode *)tn->child[j]); | ||
843 | |||
844 | tnode_free(tn); | ||
845 | |||
846 | *err = -ENOMEM; | ||
847 | return oldtnode; | ||
848 | } | ||
738 | 849 | ||
739 | for(i = 0; i < olen; i += 2) { | 850 | for(i = 0; i < olen; i += 2) { |
740 | left = tnode_get_child(oldtnode, i); | 851 | left = tnode_get_child(oldtnode, i); |
@@ -751,10 +862,11 @@ static struct tnode *halve(struct trie *t, struct tnode *tn) | |||
751 | /* Two nonempty children */ | 862 | /* Two nonempty children */ |
752 | else { | 863 | else { |
753 | struct tnode *newBinNode = | 864 | struct tnode *newBinNode = |
754 | tnode_new(left->key, tn->pos + tn->bits, 1); | 865 | (struct tnode *) tnode_get_child(tn, i/2); |
866 | put_child(t, tn, i/2, NULL); | ||
755 | 867 | ||
756 | if(!newBinNode) | 868 | if(!newBinNode) |
757 | trie_bug("tnode_new failed"); | 869 | BUG(); |
758 | 870 | ||
759 | put_child(t, newBinNode, 0, left); | 871 | put_child(t, newBinNode, 0, left); |
760 | put_child(t, newBinNode, 1, right); | 872 | put_child(t, newBinNode, 1, right); |
@@ -2322,6 +2434,7 @@ static void collect_and_show(struct trie *t, struct seq_file *seq) | |||
2322 | seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed); | 2434 | seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed); |
2323 | seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss); | 2435 | seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss); |
2324 | seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit); | 2436 | seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit); |
2437 | seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped); | ||
2325 | #ifdef CLEAR_STATS | 2438 | #ifdef CLEAR_STATS |
2326 | memset(&(t->stats), 0, sizeof(t->stats)); | 2439 | memset(&(t->stats), 0, sizeof(t->stats)); |
2327 | #endif | 2440 | #endif |