aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fib_trie.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/fib_trie.c')
-rw-r--r--net/ipv4/fib_trie.c157
1 files changed, 73 insertions, 84 deletions
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index dea2f80e08c3..7e9031739f06 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -396,8 +396,30 @@ static void put_child(struct tnode *tn, unsigned long i, struct tnode *n)
396 rcu_assign_pointer(tn->child[i], n); 396 rcu_assign_pointer(tn->child[i], n);
397} 397}
398 398
399static void put_child_root(struct tnode *tp, struct trie *t, 399static void update_children(struct tnode *tn)
400 t_key key, struct tnode *n) 400{
401 unsigned long i;
402
403 /* update all of the child parent pointers */
404 for (i = tnode_child_length(tn); i;) {
405 struct tnode *inode = tnode_get_child(tn, --i);
406
407 if (!inode)
408 continue;
409
410 /* Either update the children of a tnode that
411 * already belongs to us or update the child
412 * to point to ourselves.
413 */
414 if (node_parent(inode) == tn)
415 update_children(inode);
416 else
417 node_set_parent(inode, tn);
418 }
419}
420
421static inline void put_child_root(struct tnode *tp, struct trie *t,
422 t_key key, struct tnode *n)
401{ 423{
402 if (tp) 424 if (tp)
403 put_child(tp, get_index(key, tp), n); 425 put_child(tp, get_index(key, tp), n);
@@ -434,10 +456,35 @@ static void tnode_free(struct tnode *tn)
434 } 456 }
435} 457}
436 458
459static void replace(struct trie *t, struct tnode *oldtnode, struct tnode *tn)
460{
461 struct tnode *tp = node_parent(oldtnode);
462 unsigned long i;
463
464 /* setup the parent pointer out of and back into this node */
465 NODE_INIT_PARENT(tn, tp);
466 put_child_root(tp, t, tn->key, tn);
467
468 /* update all of the child parent pointers */
469 update_children(tn);
470
471 /* all pointers should be clean so we are done */
472 tnode_free(oldtnode);
473
474 /* resize children now that oldtnode is freed */
475 for (i = tnode_child_length(tn); i;) {
476 struct tnode *inode = tnode_get_child(tn, --i);
477
478 /* resize child node */
479 if (tnode_full(tn, inode))
480 resize(t, inode);
481 }
482}
483
437static int inflate(struct trie *t, struct tnode *oldtnode) 484static int inflate(struct trie *t, struct tnode *oldtnode)
438{ 485{
439 struct tnode *inode, *node0, *node1, *tn, *tp; 486 struct tnode *tn;
440 unsigned long i, j, k; 487 unsigned long i;
441 t_key m; 488 t_key m;
442 489
443 pr_debug("In inflate\n"); 490 pr_debug("In inflate\n");
@@ -446,13 +493,18 @@ static int inflate(struct trie *t, struct tnode *oldtnode)
446 if (!tn) 493 if (!tn)
447 return -ENOMEM; 494 return -ENOMEM;
448 495
496 /* prepare oldtnode to be freed */
497 tnode_free_init(oldtnode);
498
449 /* Assemble all of the pointers in our cluster, in this case that 499 /* Assemble all of the pointers in our cluster, in this case that
450 * represents all of the pointers out of our allocated nodes that 500 * represents all of the pointers out of our allocated nodes that
451 * point to existing tnodes and the links between our allocated 501 * point to existing tnodes and the links between our allocated
452 * nodes. 502 * nodes.
453 */ 503 */
454 for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) { 504 for (i = tnode_child_length(oldtnode), m = 1u << tn->pos; i;) {
455 inode = tnode_get_child(oldtnode, --i); 505 struct tnode *inode = tnode_get_child(oldtnode, --i);
506 struct tnode *node0, *node1;
507 unsigned long j, k;
456 508
457 /* An empty child */ 509 /* An empty child */
458 if (inode == NULL) 510 if (inode == NULL)
@@ -464,6 +516,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode)
464 continue; 516 continue;
465 } 517 }
466 518
519 /* drop the node in the old tnode free list */
520 tnode_free_append(oldtnode, inode);
521
467 /* An internal node with two children */ 522 /* An internal node with two children */
468 if (inode->bits == 1) { 523 if (inode->bits == 1) {
469 put_child(tn, 2 * i + 1, tnode_get_child(inode, 1)); 524 put_child(tn, 2 * i + 1, tnode_get_child(inode, 1));
@@ -488,9 +543,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode)
488 node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1); 543 node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1);
489 if (!node1) 544 if (!node1)
490 goto nomem; 545 goto nomem;
491 tnode_free_append(tn, node1); 546 node0 = tnode_new(inode->key, inode->pos, inode->bits - 1);
492 547
493 node0 = tnode_new(inode->key & ~m, inode->pos, inode->bits - 1); 548 tnode_free_append(tn, node1);
494 if (!node0) 549 if (!node0)
495 goto nomem; 550 goto nomem;
496 tnode_free_append(tn, node0); 551 tnode_free_append(tn, node0);
@@ -512,53 +567,9 @@ static int inflate(struct trie *t, struct tnode *oldtnode)
512 put_child(tn, 2 * i, node0); 567 put_child(tn, 2 * i, node0);
513 } 568 }
514 569
515 /* setup the parent pointer into and out of this node */ 570 /* setup the parent pointers into and out of this node */
516 tp = node_parent(oldtnode); 571 replace(t, oldtnode, tn);
517 NODE_INIT_PARENT(tn, tp);
518 put_child_root(tp, t, tn->key, tn);
519
520 /* prepare oldtnode to be freed */
521 tnode_free_init(oldtnode);
522
523 /* update all child nodes parent pointers to route to us */
524 for (i = tnode_child_length(oldtnode); i;) {
525 inode = tnode_get_child(oldtnode, --i);
526
527 /* A leaf or an internal node with skipped bits */
528 if (!tnode_full(oldtnode, inode)) {
529 node_set_parent(inode, tn);
530 continue;
531 }
532
533 /* drop the node in the old tnode free list */
534 tnode_free_append(oldtnode, inode);
535
536 /* fetch new nodes */
537 node1 = tnode_get_child(tn, 2 * i + 1);
538 node0 = tnode_get_child(tn, 2 * i);
539 572
540 /* bits == 1 then node0 and node1 represent inode's children */
541 if (inode->bits == 1) {
542 node_set_parent(node1, tn);
543 node_set_parent(node0, tn);
544 continue;
545 }
546
547 /* update parent pointers in child node's children */
548 for (k = tnode_child_length(inode), j = k / 2; j;) {
549 node_set_parent(tnode_get_child(inode, --k), node1);
550 node_set_parent(tnode_get_child(inode, --j), node0);
551 node_set_parent(tnode_get_child(inode, --k), node1);
552 node_set_parent(tnode_get_child(inode, --j), node0);
553 }
554
555 /* resize child nodes */
556 resize(t, node1);
557 resize(t, node0);
558 }
559
560 /* we completed without error, prepare to free old node */
561 tnode_free(oldtnode);
562 return 0; 573 return 0;
563nomem: 574nomem:
564 /* all pointers should be clean so we are done */ 575 /* all pointers should be clean so we are done */
@@ -568,7 +579,7 @@ nomem:
568 579
569static int halve(struct trie *t, struct tnode *oldtnode) 580static int halve(struct trie *t, struct tnode *oldtnode)
570{ 581{
571 struct tnode *tn, *tp, *inode, *node0, *node1; 582 struct tnode *tn;
572 unsigned long i; 583 unsigned long i;
573 584
574 pr_debug("In halve\n"); 585 pr_debug("In halve\n");
@@ -577,14 +588,18 @@ static int halve(struct trie *t, struct tnode *oldtnode)
577 if (!tn) 588 if (!tn)
578 return -ENOMEM; 589 return -ENOMEM;
579 590
591 /* prepare oldtnode to be freed */
592 tnode_free_init(oldtnode);
593
580 /* Assemble all of the pointers in our cluster, in this case that 594 /* Assemble all of the pointers in our cluster, in this case that
581 * represents all of the pointers out of our allocated nodes that 595 * represents all of the pointers out of our allocated nodes that
582 * point to existing tnodes and the links between our allocated 596 * point to existing tnodes and the links between our allocated
583 * nodes. 597 * nodes.
584 */ 598 */
585 for (i = tnode_child_length(oldtnode); i;) { 599 for (i = tnode_child_length(oldtnode); i;) {
586 node1 = tnode_get_child(oldtnode, --i); 600 struct tnode *node1 = tnode_get_child(oldtnode, --i);
587 node0 = tnode_get_child(oldtnode, --i); 601 struct tnode *node0 = tnode_get_child(oldtnode, --i);
602 struct tnode *inode;
588 603
589 /* At least one of the children is empty */ 604 /* At least one of the children is empty */
590 if (!node1 || !node0) { 605 if (!node1 || !node0) {
@@ -609,34 +624,8 @@ static int halve(struct trie *t, struct tnode *oldtnode)
609 put_child(tn, i / 2, inode); 624 put_child(tn, i / 2, inode);
610 } 625 }
611 626
612 /* setup the parent pointer out of and back into this node */ 627 /* setup the parent pointers into and out of this node */
613 tp = node_parent(oldtnode); 628 replace(t, oldtnode, tn);
614 NODE_INIT_PARENT(tn, tp);
615 put_child_root(tp, t, tn->key, tn);
616
617 /* prepare oldtnode to be freed */
618 tnode_free_init(oldtnode);
619
620 /* update all of the child parent pointers */
621 for (i = tnode_child_length(tn); i;) {
622 inode = tnode_get_child(tn, --i);
623
624 /* only new tnodes will be considered "full" nodes */
625 if (!tnode_full(tn, inode)) {
626 node_set_parent(inode, tn);
627 continue;
628 }
629
630 /* Two nonempty children */
631 node_set_parent(tnode_get_child(inode, 1), inode);
632 node_set_parent(tnode_get_child(inode, 0), inode);
633
634 /* resize child node */
635 resize(t, inode);
636 }
637
638 /* all pointers should be clean so we are done */
639 tnode_free(oldtnode);
640 629
641 return 0; 630 return 0;
642} 631}