aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2019-05-13 19:18:57 -0400
committerAlexei Starovoitov <ast@kernel.org>2019-05-14 13:47:29 -0400
commitd2baab62a1434d3f81ce83e82cbc53e7f2843bbc (patch)
tree18e46b9920b1807e4146e9ea2a273e3f3c4dcba4 /tools
parent50b045a8c0ccf44f76640ac3eea8d80ca53979a3 (diff)
bpf: test ref bit from data path and add new tests for syscall path
The test_lru_map is relying on marking the LRU map entry via regular BPF map lookup from system call side. This is basically for simplicity reasons. Given we fixed marking entries in that case, the test needs to be fixed as well. Here we add a small drop-in replacement to retain existing behavior for the tests by marking out of the BPF program and transferring the retrieved value out via temporary map. This also adds new test cases to track the new behavior where two elements are marked, one via system call side and one via program side, where the next update then evicts the key looked up only from system call side. # ./test_lru_map nr_cpus:8 test_lru_sanity0 (map_type:9 map_flags:0x0): Pass test_lru_sanity1 (map_type:9 map_flags:0x0): Pass test_lru_sanity2 (map_type:9 map_flags:0x0): Pass test_lru_sanity3 (map_type:9 map_flags:0x0): Pass test_lru_sanity4 (map_type:9 map_flags:0x0): Pass test_lru_sanity5 (map_type:9 map_flags:0x0): Pass test_lru_sanity7 (map_type:9 map_flags:0x0): Pass test_lru_sanity8 (map_type:9 map_flags:0x0): Pass test_lru_sanity0 (map_type:10 map_flags:0x0): Pass test_lru_sanity1 (map_type:10 map_flags:0x0): Pass test_lru_sanity2 (map_type:10 map_flags:0x0): Pass test_lru_sanity3 (map_type:10 map_flags:0x0): Pass test_lru_sanity4 (map_type:10 map_flags:0x0): Pass test_lru_sanity5 (map_type:10 map_flags:0x0): Pass test_lru_sanity7 (map_type:10 map_flags:0x0): Pass test_lru_sanity8 (map_type:10 map_flags:0x0): Pass test_lru_sanity0 (map_type:9 map_flags:0x2): Pass test_lru_sanity4 (map_type:9 map_flags:0x2): Pass test_lru_sanity6 (map_type:9 map_flags:0x2): Pass test_lru_sanity7 (map_type:9 map_flags:0x2): Pass test_lru_sanity8 (map_type:9 map_flags:0x2): Pass test_lru_sanity0 (map_type:10 map_flags:0x2): Pass test_lru_sanity4 (map_type:10 map_flags:0x2): Pass test_lru_sanity6 (map_type:10 map_flags:0x2): Pass test_lru_sanity7 (map_type:10 map_flags:0x2): Pass test_lru_sanity8 (map_type:10 map_flags:0x2): Pass Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/testing/selftests/bpf/test_lru_map.c288
1 files changed, 274 insertions, 14 deletions
diff --git a/tools/testing/selftests/bpf/test_lru_map.c b/tools/testing/selftests/bpf/test_lru_map.c
index 781c7de343be..1b25a7e348dc 100644
--- a/tools/testing/selftests/bpf/test_lru_map.c
+++ b/tools/testing/selftests/bpf/test_lru_map.c
@@ -18,9 +18,11 @@
18#include <sys/wait.h> 18#include <sys/wait.h>
19 19
20#include <bpf/bpf.h> 20#include <bpf/bpf.h>
21#include <bpf/libbpf.h>
21 22
22#include "bpf_util.h" 23#include "bpf_util.h"
23#include "bpf_rlimit.h" 24#include "bpf_rlimit.h"
25#include "../../../include/linux/filter.h"
24 26
25#define LOCAL_FREE_TARGET (128) 27#define LOCAL_FREE_TARGET (128)
26#define PERCPU_FREE_TARGET (4) 28#define PERCPU_FREE_TARGET (4)
@@ -40,6 +42,68 @@ static int create_map(int map_type, int map_flags, unsigned int size)
40 return map_fd; 42 return map_fd;
41} 43}
42 44
45static int bpf_map_lookup_elem_with_ref_bit(int fd, unsigned long long key,
46 void *value)
47{
48 struct bpf_load_program_attr prog;
49 struct bpf_create_map_attr map;
50 struct bpf_insn insns[] = {
51 BPF_LD_MAP_VALUE(BPF_REG_9, 0, 0),
52 BPF_LD_MAP_FD(BPF_REG_1, fd),
53 BPF_LD_IMM64(BPF_REG_3, key),
54 BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
55 BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
56 BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0),
57 BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
58 BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
59 BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
60 BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_1, 0),
61 BPF_MOV64_IMM(BPF_REG_0, 42),
62 BPF_JMP_IMM(BPF_JA, 0, 0, 1),
63 BPF_MOV64_IMM(BPF_REG_0, 1),
64 BPF_EXIT_INSN(),
65 };
66 __u8 data[64] = {};
67 int mfd, pfd, ret, zero = 0;
68 __u32 retval = 0;
69
70 memset(&map, 0, sizeof(map));
71 map.map_type = BPF_MAP_TYPE_ARRAY;
72 map.key_size = sizeof(int);
73 map.value_size = sizeof(unsigned long long);
74 map.max_entries = 1;
75
76 mfd = bpf_create_map_xattr(&map);
77 if (mfd < 0)
78 return -1;
79
80 insns[0].imm = mfd;
81
82 memset(&prog, 0, sizeof(prog));
83 prog.prog_type = BPF_PROG_TYPE_SCHED_CLS;
84 prog.insns = insns;
85 prog.insns_cnt = ARRAY_SIZE(insns);
86 prog.license = "GPL";
87
88 pfd = bpf_load_program_xattr(&prog, NULL, 0);
89 if (pfd < 0) {
90 close(mfd);
91 return -1;
92 }
93
94 ret = bpf_prog_test_run(pfd, 1, data, sizeof(data),
95 NULL, NULL, &retval, NULL);
96 if (ret < 0 || retval != 42) {
97 ret = -1;
98 } else {
99 assert(!bpf_map_lookup_elem(mfd, &zero, value));
100 ret = 0;
101 }
102 close(pfd);
103 close(mfd);
104 return ret;
105}
106
43static int map_subset(int map0, int map1) 107static int map_subset(int map0, int map1)
44{ 108{
45 unsigned long long next_key = 0; 109 unsigned long long next_key = 0;
@@ -87,7 +151,7 @@ static int sched_next_online(int pid, int *next_to_try)
87 return ret; 151 return ret;
88} 152}
89 153
90/* Size of the LRU amp is 2 154/* Size of the LRU map is 2
91 * Add key=1 (+1 key) 155 * Add key=1 (+1 key)
92 * Add key=2 (+1 key) 156 * Add key=2 (+1 key)
93 * Lookup Key=1 157 * Lookup Key=1
@@ -157,7 +221,7 @@ static void test_lru_sanity0(int map_type, int map_flags)
157 * stop LRU from removing key=1 221 * stop LRU from removing key=1
158 */ 222 */
159 key = 1; 223 key = 1;
160 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 224 assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
161 assert(value[0] == 1234); 225 assert(value[0] == 1234);
162 226
163 key = 3; 227 key = 3;
@@ -167,7 +231,8 @@ static void test_lru_sanity0(int map_type, int map_flags)
167 231
168 /* key=2 has been removed from the LRU */ 232 /* key=2 has been removed from the LRU */
169 key = 2; 233 key = 2;
170 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1); 234 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
235 errno == ENOENT);
171 236
172 assert(map_equal(lru_map_fd, expected_map_fd)); 237 assert(map_equal(lru_map_fd, expected_map_fd));
173 238
@@ -221,7 +286,7 @@ static void test_lru_sanity1(int map_type, int map_flags, unsigned int tgt_free)
221 /* Lookup 1 to tgt_free/2 */ 286 /* Lookup 1 to tgt_free/2 */
222 end_key = 1 + batch_size; 287 end_key = 1 + batch_size;
223 for (key = 1; key < end_key; key++) { 288 for (key = 1; key < end_key; key++) {
224 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 289 assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
225 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 290 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
226 BPF_NOEXIST)); 291 BPF_NOEXIST));
227 } 292 }
@@ -322,10 +387,11 @@ static void test_lru_sanity2(int map_type, int map_flags, unsigned int tgt_free)
322 end_key = 1 + batch_size; 387 end_key = 1 + batch_size;
323 value[0] = 4321; 388 value[0] = 4321;
324 for (key = 1; key < end_key; key++) { 389 for (key = 1; key < end_key; key++) {
325 assert(bpf_map_lookup_elem(lru_map_fd, &key, value)); 390 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
391 errno == ENOENT);
326 assert(!bpf_map_update_elem(lru_map_fd, &key, value, 392 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
327 BPF_NOEXIST)); 393 BPF_NOEXIST));
328 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 394 assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
329 assert(value[0] == 4321); 395 assert(value[0] == 4321);
330 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 396 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
331 BPF_NOEXIST)); 397 BPF_NOEXIST));
@@ -404,7 +470,7 @@ static void test_lru_sanity3(int map_type, int map_flags, unsigned int tgt_free)
404 /* Lookup key 1 to tgt_free*3/2 */ 470 /* Lookup key 1 to tgt_free*3/2 */
405 end_key = tgt_free + batch_size; 471 end_key = tgt_free + batch_size;
406 for (key = 1; key < end_key; key++) { 472 for (key = 1; key < end_key; key++) {
407 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 473 assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
408 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 474 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
409 BPF_NOEXIST)); 475 BPF_NOEXIST));
410 } 476 }
@@ -463,7 +529,7 @@ static void test_lru_sanity4(int map_type, int map_flags, unsigned int tgt_free)
463 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST)); 529 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
464 530
465 for (key = 1; key <= tgt_free; key++) { 531 for (key = 1; key <= tgt_free; key++) {
466 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value)); 532 assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
467 assert(!bpf_map_update_elem(expected_map_fd, &key, value, 533 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
468 BPF_NOEXIST)); 534 BPF_NOEXIST));
469 } 535 }
@@ -494,16 +560,16 @@ static void do_test_lru_sanity5(unsigned long long last_key, int map_fd)
494 unsigned long long key, value[nr_cpus]; 560 unsigned long long key, value[nr_cpus];
495 561
496 /* Ensure the last key inserted by previous CPU can be found */ 562 /* Ensure the last key inserted by previous CPU can be found */
497 assert(!bpf_map_lookup_elem(map_fd, &last_key, value)); 563 assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, last_key, value));
498
499 value[0] = 1234; 564 value[0] = 1234;
500 565
501 key = last_key + 1; 566 key = last_key + 1;
502 assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST)); 567 assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
503 assert(!bpf_map_lookup_elem(map_fd, &key, value)); 568 assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, key, value));
504 569
505 /* Cannot find the last key because it was removed by LRU */ 570 /* Cannot find the last key because it was removed by LRU */
506 assert(bpf_map_lookup_elem(map_fd, &last_key, value)); 571 assert(bpf_map_lookup_elem(map_fd, &last_key, value) == -1 &&
572 errno == ENOENT);
507} 573}
508 574
509/* Test map with only one element */ 575/* Test map with only one element */
@@ -590,8 +656,8 @@ static void test_lru_sanity6(int map_type, int map_flags, int tgt_free)
590 /* Make ref bit sticky for key: [1, tgt_free] */ 656 /* Make ref bit sticky for key: [1, tgt_free] */
591 for (stable_key = 1; stable_key <= tgt_free; stable_key++) { 657 for (stable_key = 1; stable_key <= tgt_free; stable_key++) {
592 /* Mark the ref bit */ 658 /* Mark the ref bit */
593 assert(!bpf_map_lookup_elem(lru_map_fd, &stable_key, 659 assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd,
594 value)); 660 stable_key, value));
595 } 661 }
596 assert(!bpf_map_update_elem(lru_map_fd, &key, value, 662 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
597 BPF_NOEXIST)); 663 BPF_NOEXIST));
@@ -612,6 +678,198 @@ static void test_lru_sanity6(int map_type, int map_flags, int tgt_free)
612 printf("Pass\n"); 678 printf("Pass\n");
613} 679}
614 680
681/* Size of the LRU map is 2
682 * Add key=1 (+1 key)
683 * Add key=2 (+1 key)
684 * Lookup Key=1 (datapath)
685 * Lookup Key=2 (syscall)
686 * Add Key=3
687 * => Key=2 will be removed by LRU
688 * Iterate map. Only found key=1 and key=3
689 */
690static void test_lru_sanity7(int map_type, int map_flags)
691{
692 unsigned long long key, value[nr_cpus];
693 int lru_map_fd, expected_map_fd;
694 int next_cpu = 0;
695
696 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
697 map_flags);
698
699 assert(sched_next_online(0, &next_cpu) != -1);
700
701 if (map_flags & BPF_F_NO_COMMON_LRU)
702 lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
703 else
704 lru_map_fd = create_map(map_type, map_flags, 2);
705 assert(lru_map_fd != -1);
706
707 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
708 assert(expected_map_fd != -1);
709
710 value[0] = 1234;
711
712 /* insert key=1 element */
713
714 key = 1;
715 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
716 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
717 BPF_NOEXIST));
718
719 /* BPF_NOEXIST means: add new element if it doesn't exist */
720 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1
721 /* key=1 already exists */
722 && errno == EEXIST);
723
724 /* insert key=2 element */
725
726 /* check that key=2 is not found */
727 key = 2;
728 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
729 errno == ENOENT);
730
731 /* BPF_EXIST means: update existing element */
732 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 &&
733 /* key=2 is not there */
734 errno == ENOENT);
735
736 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
737
738 /* insert key=3 element */
739
740 /* check that key=3 is not found */
741 key = 3;
742 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
743 errno == ENOENT);
744
745 /* check that key=1 can be found and mark the ref bit to
746 * stop LRU from removing key=1
747 */
748 key = 1;
749 assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
750 assert(value[0] == 1234);
751
752 /* check that key=2 can be found and do _not_ mark ref bit.
753 * this will be evicted on next update.
754 */
755 key = 2;
756 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
757 assert(value[0] == 1234);
758
759 key = 3;
760 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
761 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
762 BPF_NOEXIST));
763
764 /* key=2 has been removed from the LRU */
765 key = 2;
766 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
767 errno == ENOENT);
768
769 assert(map_equal(lru_map_fd, expected_map_fd));
770
771 close(expected_map_fd);
772 close(lru_map_fd);
773
774 printf("Pass\n");
775}
776
777/* Size of the LRU map is 2
778 * Add key=1 (+1 key)
779 * Add key=2 (+1 key)
780 * Lookup Key=1 (syscall)
781 * Lookup Key=2 (datapath)
782 * Add Key=3
783 * => Key=1 will be removed by LRU
784 * Iterate map. Only found key=2 and key=3
785 */
786static void test_lru_sanity8(int map_type, int map_flags)
787{
788 unsigned long long key, value[nr_cpus];
789 int lru_map_fd, expected_map_fd;
790 int next_cpu = 0;
791
792 printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
793 map_flags);
794
795 assert(sched_next_online(0, &next_cpu) != -1);
796
797 if (map_flags & BPF_F_NO_COMMON_LRU)
798 lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
799 else
800 lru_map_fd = create_map(map_type, map_flags, 2);
801 assert(lru_map_fd != -1);
802
803 expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
804 assert(expected_map_fd != -1);
805
806 value[0] = 1234;
807
808 /* insert key=1 element */
809
810 key = 1;
811 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
812
813 /* BPF_NOEXIST means: add new element if it doesn't exist */
814 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1
815 /* key=1 already exists */
816 && errno == EEXIST);
817
818 /* insert key=2 element */
819
820 /* check that key=2 is not found */
821 key = 2;
822 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
823 errno == ENOENT);
824
825 /* BPF_EXIST means: update existing element */
826 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 &&
827 /* key=2 is not there */
828 errno == ENOENT);
829
830 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
831 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
832 BPF_NOEXIST));
833
834 /* insert key=3 element */
835
836 /* check that key=3 is not found */
837 key = 3;
838 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
839 errno == ENOENT);
840
841 /* check that key=1 can be found and do _not_ mark ref bit.
842 * this will be evicted on next update.
843 */
844 key = 1;
845 assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
846 assert(value[0] == 1234);
847
848 /* check that key=2 can be found and mark the ref bit to
849 * stop LRU from removing key=2
850 */
851 key = 2;
852 assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
853 assert(value[0] == 1234);
854
855 key = 3;
856 assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
857 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
858 BPF_NOEXIST));
859
860 /* key=1 has been removed from the LRU */
861 key = 1;
862 assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
863 errno == ENOENT);
864
865 assert(map_equal(lru_map_fd, expected_map_fd));
866
867 close(expected_map_fd);
868 close(lru_map_fd);
869
870 printf("Pass\n");
871}
872
615int main(int argc, char **argv) 873int main(int argc, char **argv)
616{ 874{
617 int map_types[] = {BPF_MAP_TYPE_LRU_HASH, 875 int map_types[] = {BPF_MAP_TYPE_LRU_HASH,
@@ -637,6 +895,8 @@ int main(int argc, char **argv)
637 test_lru_sanity4(map_types[t], map_flags[f], tgt_free); 895 test_lru_sanity4(map_types[t], map_flags[f], tgt_free);
638 test_lru_sanity5(map_types[t], map_flags[f]); 896 test_lru_sanity5(map_types[t], map_flags[f]);
639 test_lru_sanity6(map_types[t], map_flags[f], tgt_free); 897 test_lru_sanity6(map_types[t], map_flags[f], tgt_free);
898 test_lru_sanity7(map_types[t], map_flags[f]);
899 test_lru_sanity8(map_types[t], map_flags[f]);
640 900
641 printf("\n"); 901 printf("\n");
642 } 902 }