hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/tools/testing/selftests/bpf/test_lru_map.c
....@@ -1,9 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (c) 2016 Facebook
3
- *
4
- * This program is free software; you can redistribute it and/or
5
- * modify it under the terms of version 2 of the GNU General Public
6
- * License as published by the Free Software Foundation.
74 */
85 #define _GNU_SOURCE
96 #include <stdio.h>
....@@ -18,9 +15,11 @@
1815 #include <sys/wait.h>
1916
2017 #include <bpf/bpf.h>
18
+#include <bpf/libbpf.h>
2119
2220 #include "bpf_util.h"
2321 #include "bpf_rlimit.h"
22
+#include "../../../include/linux/filter.h"
2423
2524 #define LOCAL_FREE_TARGET (128)
2625 #define PERCPU_FREE_TARGET (4)
....@@ -38,6 +37,68 @@
3837 perror("bpf_create_map");
3938
4039 return map_fd;
40
+}
41
+
42
+static int bpf_map_lookup_elem_with_ref_bit(int fd, unsigned long long key,
43
+ void *value)
44
+{
45
+ struct bpf_load_program_attr prog;
46
+ struct bpf_create_map_attr map;
47
+ struct bpf_insn insns[] = {
48
+ BPF_LD_MAP_VALUE(BPF_REG_9, 0, 0),
49
+ BPF_LD_MAP_FD(BPF_REG_1, fd),
50
+ BPF_LD_IMM64(BPF_REG_3, key),
51
+ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
52
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
53
+ BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_3, 0),
54
+ BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
55
+ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 4),
56
+ BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_0, 0),
57
+ BPF_STX_MEM(BPF_DW, BPF_REG_9, BPF_REG_1, 0),
58
+ BPF_MOV64_IMM(BPF_REG_0, 42),
59
+ BPF_JMP_IMM(BPF_JA, 0, 0, 1),
60
+ BPF_MOV64_IMM(BPF_REG_0, 1),
61
+ BPF_EXIT_INSN(),
62
+ };
63
+ __u8 data[64] = {};
64
+ int mfd, pfd, ret, zero = 0;
65
+ __u32 retval = 0;
66
+
67
+ memset(&map, 0, sizeof(map));
68
+ map.map_type = BPF_MAP_TYPE_ARRAY;
69
+ map.key_size = sizeof(int);
70
+ map.value_size = sizeof(unsigned long long);
71
+ map.max_entries = 1;
72
+
73
+ mfd = bpf_create_map_xattr(&map);
74
+ if (mfd < 0)
75
+ return -1;
76
+
77
+ insns[0].imm = mfd;
78
+
79
+ memset(&prog, 0, sizeof(prog));
80
+ prog.prog_type = BPF_PROG_TYPE_SCHED_CLS;
81
+ prog.insns = insns;
82
+ prog.insns_cnt = ARRAY_SIZE(insns);
83
+ prog.license = "GPL";
84
+
85
+ pfd = bpf_load_program_xattr(&prog, NULL, 0);
86
+ if (pfd < 0) {
87
+ close(mfd);
88
+ return -1;
89
+ }
90
+
91
+ ret = bpf_prog_test_run(pfd, 1, data, sizeof(data),
92
+ NULL, NULL, &retval, NULL);
93
+ if (ret < 0 || retval != 42) {
94
+ ret = -1;
95
+ } else {
96
+ assert(!bpf_map_lookup_elem(mfd, &zero, value));
97
+ ret = 0;
98
+ }
99
+ close(pfd);
100
+ close(mfd);
101
+ return ret;
41102 }
42103
43104 static int map_subset(int map0, int map1)
....@@ -87,7 +148,7 @@
87148 return ret;
88149 }
89150
90
-/* Size of the LRU amp is 2
151
+/* Size of the LRU map is 2
91152 * Add key=1 (+1 key)
92153 * Add key=2 (+1 key)
93154 * Lookup Key=1
....@@ -157,7 +218,7 @@
157218 * stop LRU from removing key=1
158219 */
159220 key = 1;
160
- assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
221
+ assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
161222 assert(value[0] == 1234);
162223
163224 key = 3;
....@@ -167,7 +228,8 @@
167228
168229 /* key=2 has been removed from the LRU */
169230 key = 2;
170
- assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1);
231
+ assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
232
+ errno == ENOENT);
171233
172234 assert(map_equal(lru_map_fd, expected_map_fd));
173235
....@@ -221,7 +283,7 @@
221283 /* Lookup 1 to tgt_free/2 */
222284 end_key = 1 + batch_size;
223285 for (key = 1; key < end_key; key++) {
224
- assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
286
+ assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
225287 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
226288 BPF_NOEXIST));
227289 }
....@@ -322,10 +384,11 @@
322384 end_key = 1 + batch_size;
323385 value[0] = 4321;
324386 for (key = 1; key < end_key; key++) {
325
- assert(bpf_map_lookup_elem(lru_map_fd, &key, value));
387
+ assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
388
+ errno == ENOENT);
326389 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
327390 BPF_NOEXIST));
328
- assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
391
+ assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
329392 assert(value[0] == 4321);
330393 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
331394 BPF_NOEXIST));
....@@ -404,7 +467,7 @@
404467 /* Lookup key 1 to tgt_free*3/2 */
405468 end_key = tgt_free + batch_size;
406469 for (key = 1; key < end_key; key++) {
407
- assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
470
+ assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
408471 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
409472 BPF_NOEXIST));
410473 }
....@@ -463,7 +526,7 @@
463526 assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
464527
465528 for (key = 1; key <= tgt_free; key++) {
466
- assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
529
+ assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
467530 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
468531 BPF_NOEXIST));
469532 }
....@@ -494,16 +557,16 @@
494557 unsigned long long key, value[nr_cpus];
495558
496559 /* Ensure the last key inserted by previous CPU can be found */
497
- assert(!bpf_map_lookup_elem(map_fd, &last_key, value));
498
-
560
+ assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, last_key, value));
499561 value[0] = 1234;
500562
501563 key = last_key + 1;
502564 assert(!bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST));
503
- assert(!bpf_map_lookup_elem(map_fd, &key, value));
565
+ assert(!bpf_map_lookup_elem_with_ref_bit(map_fd, key, value));
504566
505567 /* Cannot find the last key because it was removed by LRU */
506
- assert(bpf_map_lookup_elem(map_fd, &last_key, value));
568
+ assert(bpf_map_lookup_elem(map_fd, &last_key, value) == -1 &&
569
+ errno == ENOENT);
507570 }
508571
509572 /* Test map with only one element */
....@@ -590,8 +653,8 @@
590653 /* Make ref bit sticky for key: [1, tgt_free] */
591654 for (stable_key = 1; stable_key <= tgt_free; stable_key++) {
592655 /* Mark the ref bit */
593
- assert(!bpf_map_lookup_elem(lru_map_fd, &stable_key,
594
- value));
656
+ assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd,
657
+ stable_key, value));
595658 }
596659 assert(!bpf_map_update_elem(lru_map_fd, &key, value,
597660 BPF_NOEXIST));
....@@ -603,6 +666,198 @@
603666 assert(!bpf_map_update_elem(expected_map_fd, &key, value,
604667 BPF_NOEXIST));
605668 }
669
+
670
+ assert(map_equal(lru_map_fd, expected_map_fd));
671
+
672
+ close(expected_map_fd);
673
+ close(lru_map_fd);
674
+
675
+ printf("Pass\n");
676
+}
677
+
678
+/* Size of the LRU map is 2
679
+ * Add key=1 (+1 key)
680
+ * Add key=2 (+1 key)
681
+ * Lookup Key=1 (datapath)
682
+ * Lookup Key=2 (syscall)
683
+ * Add Key=3
684
+ * => Key=2 will be removed by LRU
685
+ * Iterate map. Only found key=1 and key=3
686
+ */
687
+static void test_lru_sanity7(int map_type, int map_flags)
688
+{
689
+ unsigned long long key, value[nr_cpus];
690
+ int lru_map_fd, expected_map_fd;
691
+ int next_cpu = 0;
692
+
693
+ printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
694
+ map_flags);
695
+
696
+ assert(sched_next_online(0, &next_cpu) != -1);
697
+
698
+ if (map_flags & BPF_F_NO_COMMON_LRU)
699
+ lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
700
+ else
701
+ lru_map_fd = create_map(map_type, map_flags, 2);
702
+ assert(lru_map_fd != -1);
703
+
704
+ expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
705
+ assert(expected_map_fd != -1);
706
+
707
+ value[0] = 1234;
708
+
709
+ /* insert key=1 element */
710
+
711
+ key = 1;
712
+ assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
713
+ assert(!bpf_map_update_elem(expected_map_fd, &key, value,
714
+ BPF_NOEXIST));
715
+
716
+ /* BPF_NOEXIST means: add new element if it doesn't exist */
717
+ assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1
718
+ /* key=1 already exists */
719
+ && errno == EEXIST);
720
+
721
+ /* insert key=2 element */
722
+
723
+ /* check that key=2 is not found */
724
+ key = 2;
725
+ assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
726
+ errno == ENOENT);
727
+
728
+ /* BPF_EXIST means: update existing element */
729
+ assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 &&
730
+ /* key=2 is not there */
731
+ errno == ENOENT);
732
+
733
+ assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
734
+
735
+ /* insert key=3 element */
736
+
737
+ /* check that key=3 is not found */
738
+ key = 3;
739
+ assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
740
+ errno == ENOENT);
741
+
742
+ /* check that key=1 can be found and mark the ref bit to
743
+ * stop LRU from removing key=1
744
+ */
745
+ key = 1;
746
+ assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
747
+ assert(value[0] == 1234);
748
+
749
+ /* check that key=2 can be found and do _not_ mark ref bit.
750
+ * this will be evicted on next update.
751
+ */
752
+ key = 2;
753
+ assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
754
+ assert(value[0] == 1234);
755
+
756
+ key = 3;
757
+ assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
758
+ assert(!bpf_map_update_elem(expected_map_fd, &key, value,
759
+ BPF_NOEXIST));
760
+
761
+ /* key=2 has been removed from the LRU */
762
+ key = 2;
763
+ assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
764
+ errno == ENOENT);
765
+
766
+ assert(map_equal(lru_map_fd, expected_map_fd));
767
+
768
+ close(expected_map_fd);
769
+ close(lru_map_fd);
770
+
771
+ printf("Pass\n");
772
+}
773
+
774
+/* Size of the LRU map is 2
775
+ * Add key=1 (+1 key)
776
+ * Add key=2 (+1 key)
777
+ * Lookup Key=1 (syscall)
778
+ * Lookup Key=2 (datapath)
779
+ * Add Key=3
780
+ * => Key=1 will be removed by LRU
781
+ * Iterate map. Only found key=2 and key=3
782
+ */
783
+static void test_lru_sanity8(int map_type, int map_flags)
784
+{
785
+ unsigned long long key, value[nr_cpus];
786
+ int lru_map_fd, expected_map_fd;
787
+ int next_cpu = 0;
788
+
789
+ printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
790
+ map_flags);
791
+
792
+ assert(sched_next_online(0, &next_cpu) != -1);
793
+
794
+ if (map_flags & BPF_F_NO_COMMON_LRU)
795
+ lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
796
+ else
797
+ lru_map_fd = create_map(map_type, map_flags, 2);
798
+ assert(lru_map_fd != -1);
799
+
800
+ expected_map_fd = create_map(BPF_MAP_TYPE_HASH, 0, 2);
801
+ assert(expected_map_fd != -1);
802
+
803
+ value[0] = 1234;
804
+
805
+ /* insert key=1 element */
806
+
807
+ key = 1;
808
+ assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
809
+
810
+ /* BPF_NOEXIST means: add new element if it doesn't exist */
811
+ assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST) == -1
812
+ /* key=1 already exists */
813
+ && errno == EEXIST);
814
+
815
+ /* insert key=2 element */
816
+
817
+ /* check that key=2 is not found */
818
+ key = 2;
819
+ assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
820
+ errno == ENOENT);
821
+
822
+ /* BPF_EXIST means: update existing element */
823
+ assert(bpf_map_update_elem(lru_map_fd, &key, value, BPF_EXIST) == -1 &&
824
+ /* key=2 is not there */
825
+ errno == ENOENT);
826
+
827
+ assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
828
+ assert(!bpf_map_update_elem(expected_map_fd, &key, value,
829
+ BPF_NOEXIST));
830
+
831
+ /* insert key=3 element */
832
+
833
+ /* check that key=3 is not found */
834
+ key = 3;
835
+ assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
836
+ errno == ENOENT);
837
+
838
+ /* check that key=1 can be found and do _not_ mark ref bit.
839
+ * this will be evicted on next update.
840
+ */
841
+ key = 1;
842
+ assert(!bpf_map_lookup_elem(lru_map_fd, &key, value));
843
+ assert(value[0] == 1234);
844
+
845
+ /* check that key=2 can be found and mark the ref bit to
846
+ * stop LRU from removing key=2
847
+ */
848
+ key = 2;
849
+ assert(!bpf_map_lookup_elem_with_ref_bit(lru_map_fd, key, value));
850
+ assert(value[0] == 1234);
851
+
852
+ key = 3;
853
+ assert(!bpf_map_update_elem(lru_map_fd, &key, value, BPF_NOEXIST));
854
+ assert(!bpf_map_update_elem(expected_map_fd, &key, value,
855
+ BPF_NOEXIST));
856
+
857
+ /* key=1 has been removed from the LRU */
858
+ key = 1;
859
+ assert(bpf_map_lookup_elem(lru_map_fd, &key, value) == -1 &&
860
+ errno == ENOENT);
606861
607862 assert(map_equal(lru_map_fd, expected_map_fd));
608863
....@@ -637,6 +892,8 @@
637892 test_lru_sanity4(map_types[t], map_flags[f], tgt_free);
638893 test_lru_sanity5(map_types[t], map_flags[f]);
639894 test_lru_sanity6(map_types[t], map_flags[f], tgt_free);
895
+ test_lru_sanity7(map_types[t], map_flags[f]);
896
+ test_lru_sanity8(map_types[t], map_flags[f]);
640897
641898 printf("\n");
642899 }