History

bpf: lpm_trie: check left child of last leftmost node for NULL

If the leftmost parent node of the tree has does not have a child on the left side, then trie_get_next_key (and bpftool map dump) will not look at the child on the right. This leads to the traversal missing elements. Lookup is not affected. Update selftest to handle this case. Reproducer: bpftool map create /sys/fs/bpf/lpm type lpm_trie key 6 \ value 1 entries 256 name test_lpm flags 1 bpftool map update pinned /sys/fs/bpf/lpm key 8 0 0 0 0 0 value 1 bpftool map update pinned /sys/fs/bpf/lpm key 16 0 0 0 0 128 value 2 bpftool map dump pinned /sys/fs/bpf/lpm Returns only 1 element. (2 expected)

Jonathan Lemon committed 7 years ago

Commit da2577f1 parent dce5ccc2 files · +45 −5Browse files

Unified · Split

2 files
  1. kernel/bpf/lpm_trie.c +7 −2
  2. tools/testing/selftests/bpf/test_lpm_map.c +38 −3
kernel/bpf/lpm_trie.c+7−2
@@ -716,9 +716,14 @@ find_leftmost: · 715 unmodified lines
716 * have exact two children, so this function will never return NULL.716 * have exact two children, so this function will never return NULL.
717 */717 */
718 for (node = search_root; node;) {718 for (node = search_root; node;) {
719 if (!(node->flags & LPM_TREE_NODE_FLAG_IM))719 if (node->flags & LPM_TREE_NODE_FLAG_IM) {
720 node = rcu_dereference(node->child[0]);
721 } else {
720 next_node = node;722 next_node = node;
721 node = rcu_dereference(node->child[0]);723 node = rcu_dereference(node->child[0]);
724 if (!node)
725 node = rcu_dereference(next_node->child[1]);
726 }
722 }727 }
723do_copy:728do_copy:
724 next_key->prefixlen = next_node->prefixlen;729 next_key->prefixlen = next_node->prefixlen;
tools/testing/selftests/bpf/test_lpm_map.c+38−3
@@ -573,13 +573,13 @@ static void test_lpm_get_next_key(void) · 572 unmodified lines
573 573
574 /* add one more element (total two) */574 /* add one more element (total two) */
575 key_p->prefixlen = 24;575 key_p->prefixlen = 24;
576 inet_pton(AF_INET, "192.168.0.0", key_p->data);576 inet_pton(AF_INET, "192.168.128.0", key_p->data);
577 assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0);577 assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0);
578 578
579 memset(key_p, 0, key_size);579 memset(key_p, 0, key_size);
580 assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0);580 assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0);
581 assert(key_p->prefixlen == 24 && key_p->data[0] == 192 &&581 assert(key_p->prefixlen == 24 && key_p->data[0] == 192 &&
582 key_p->data[1] == 168 && key_p->data[2] == 0);582 key_p->data[1] == 168 && key_p->data[2] == 128);
583 583
584 memset(next_key_p, 0, key_size);584 memset(next_key_p, 0, key_size);
585 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0);585 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0);
@@ -592,7 +592,7 @@ static void test_lpm_get_next_key(void) · 6 unmodified lines
592 592
593 /* Add one more element (total three) */593 /* Add one more element (total three) */
594 key_p->prefixlen = 24;594 key_p->prefixlen = 24;
595 inet_pton(AF_INET, "192.168.128.0", key_p->data);595 inet_pton(AF_INET, "192.168.0.0", key_p->data);
596 assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0);596 assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0);
597 597
598 memset(key_p, 0, key_size);598 memset(key_p, 0, key_size);
@@ -643,6 +643,41 @@ static void test_lpm_get_next_key(void) · 44 unmodified lines
643 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -1 &&643 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -1 &&
644 errno == ENOENT);644 errno == ENOENT);
645 645
646 /* Add one more element (total five) */
647 key_p->prefixlen = 28;
648 inet_pton(AF_INET, "192.168.1.128", key_p->data);
649 assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0);
650
651 memset(key_p, 0, key_size);
652 assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0);
653 assert(key_p->prefixlen == 24 && key_p->data[0] == 192 &&
654 key_p->data[1] == 168 && key_p->data[2] == 0);
655
656 memset(next_key_p, 0, key_size);
657 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0);
658 assert(next_key_p->prefixlen == 28 && next_key_p->data[0] == 192 &&
659 next_key_p->data[1] == 168 && next_key_p->data[2] == 1 &&
660 next_key_p->data[3] == 128);
661
662 memcpy(key_p, next_key_p, key_size);
663 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0);
664 assert(next_key_p->prefixlen == 24 && next_key_p->data[0] == 192 &&
665 next_key_p->data[1] == 168 && next_key_p->data[2] == 1);
666
667 memcpy(key_p, next_key_p, key_size);
668 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0);
669 assert(next_key_p->prefixlen == 24 && next_key_p->data[0] == 192 &&
670 next_key_p->data[1] == 168 && next_key_p->data[2] == 128);
671
672 memcpy(key_p, next_key_p, key_size);
673 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == 0);
674 assert(next_key_p->prefixlen == 16 && next_key_p->data[0] == 192 &&
675 next_key_p->data[1] == 168);
676
677 memcpy(key_p, next_key_p, key_size);
678 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -1 &&
679 errno == ENOENT);
680
646 /* no exact matching key should return the first one in post order */681 /* no exact matching key should return the first one in post order */
647 key_p->prefixlen = 22;682 key_p->prefixlen = 22;
648 inet_pton(AF_INET, "192.168.1.0", key_p->data);683 inet_pton(AF_INET, "192.168.1.0", key_p->data);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t