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
716716 * have exact two children, so this function will never return NULL.
717717 */
718718 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 {
720722 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+ }
722727 }
723728 do_copy:
724729 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
573573
574574 /* add one more element (total two) */
575575 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);
577577 assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0);
578578
579579 memset(key_p, 0, key_size);
580580 assert(bpf_map_get_next_key(map_fd, NULL, key_p) == 0);
581581 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);
583583
584584 memset(next_key_p, 0, key_size);
585585 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
592592
593593 /* Add one more element (total three) */
594594 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);
596596 assert(bpf_map_update_elem(map_fd, key_p, &value, 0) == 0);
597597
598598 memset(key_p, 0, key_size);
@@ -643,6 +643,41 @@ static void test_lpm_get_next_key(void) · 44 unmodified lines
643643 assert(bpf_map_get_next_key(map_fd, key_p, next_key_p) == -1 &&
644644 errno == ENOENT);
645645
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+
646681 /* no exact matching key should return the first one in post order */
647682 key_p->prefixlen = 22;
648683 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