1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ 3 4 #include <vmlinux.h> 5 #include <stdbool.h> 6 #include <bpf/bpf_helpers.h> 7 #include <bpf/bpf_tracing.h> 8 #include "bpf_misc.h" 9 10 #define ENOENT 2 11 #define EEXIST 17 12 13 char _license[] SEC("license") = "GPL"; 14 15 int err; 16 17 struct elem { 18 char arr[128]; 19 int val; 20 }; 21 22 struct { 23 __uint(type, BPF_MAP_TYPE_RHASH); 24 __uint(map_flags, BPF_F_NO_PREALLOC); 25 __uint(max_entries, 128); 26 __type(key, int); 27 __type(value, struct elem); 28 } rhmap SEC(".maps"); 29 30 SEC("syscall") 31 int test_rhash_lookup_update(void *ctx) 32 { 33 int key = 5; 34 struct elem empty = {.val = 3, .arr = {0}}; 35 struct elem *e; 36 37 err = 1; 38 e = bpf_map_lookup_elem(&rhmap, &key); 39 if (e) 40 return 1; 41 42 err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST); 43 if (err) 44 return 1; 45 46 e = bpf_map_lookup_elem(&rhmap, &key); 47 if (!e || e->val != empty.val) { 48 err = 2; 49 return 2; 50 } 51 52 err = 0; 53 return 0; 54 } 55 56 SEC("syscall") 57 int test_rhash_update_delete(void *ctx) 58 { 59 int key = 6; 60 struct elem empty = {.val = 4, .arr = {0}}; 61 struct elem *e; 62 63 err = 1; 64 e = bpf_map_lookup_elem(&rhmap, &key); 65 if (e) 66 return 1; 67 68 err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST); 69 if (err) 70 return 2; 71 72 err = bpf_map_delete_elem(&rhmap, &key); 73 if (err) 74 return 3; 75 76 e = bpf_map_lookup_elem(&rhmap, &key); 77 if (e) { 78 err = 4; 79 return 4; 80 } 81 82 err = 0; 83 return 0; 84 } 85 86 SEC("syscall") 87 int test_rhash_update_elements(void *ctx) 88 { 89 int key = 0; 90 struct elem empty = {.val = 4, .arr = {0}}; 91 struct elem *e; 92 int i; 93 94 err = 1; 95 96 for (i = 0; i < 128; ++i) { 97 key = i; 98 e = bpf_map_lookup_elem(&rhmap, &key); 99 if (e) 100 return 1; 101 102 empty.val = key; 103 err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST); 104 if (err) 105 return 2; 106 107 e = bpf_map_lookup_elem(&rhmap, &key); 108 if (!e || e->val != key) { 109 err = 4; 110 return 4; 111 } 112 } 113 114 for (i = 0; i < 128; ++i) { 115 key = i; 116 err = bpf_map_delete_elem(&rhmap, &key); 117 if (err) 118 return 3; 119 120 e = bpf_map_lookup_elem(&rhmap, &key); 121 if (e) { 122 err = 5; 123 return 5; 124 } 125 } 126 127 err = 0; 128 return 0; 129 } 130 131 SEC("syscall") 132 int test_rhash_update_exist(void *ctx) 133 { 134 int key = 10; 135 struct elem val1 = {.val = 100, .arr = {0}}; 136 struct elem val2 = {.val = 200, .arr = {0}}; 137 struct elem *e; 138 int ret; 139 140 err = 1; 141 142 /* BPF_EXIST on non-existent key should fail with -ENOENT */ 143 ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_EXIST); 144 if (ret != -ENOENT) 145 return 1; 146 147 /* Insert element first */ 148 ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_NOEXIST); 149 if (ret) 150 return 2; 151 152 /* Verify initial value */ 153 e = bpf_map_lookup_elem(&rhmap, &key); 154 if (!e || e->val != 100) 155 return 3; 156 157 /* BPF_EXIST on existing key should succeed and update value */ 158 ret = bpf_map_update_elem(&rhmap, &key, &val2, BPF_EXIST); 159 if (ret) 160 return 4; 161 162 /* Verify value was updated */ 163 e = bpf_map_lookup_elem(&rhmap, &key); 164 if (!e || e->val != 200) 165 return 5; 166 167 /* Cleanup */ 168 bpf_map_delete_elem(&rhmap, &key); 169 err = 0; 170 return 0; 171 } 172 173 SEC("syscall") 174 int test_rhash_update_any(void *ctx) 175 { 176 int key = 11; 177 struct elem val1 = {.val = 111, .arr = {0}}; 178 struct elem val2 = {.val = 222, .arr = {0}}; 179 struct elem *e; 180 int ret; 181 182 err = 1; 183 184 /* BPF_ANY on non-existent key should insert */ 185 ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_ANY); 186 if (ret) 187 return 1; 188 189 e = bpf_map_lookup_elem(&rhmap, &key); 190 if (!e || e->val != 111) 191 return 2; 192 193 /* BPF_ANY on existing key should update */ 194 ret = bpf_map_update_elem(&rhmap, &key, &val2, BPF_ANY); 195 if (ret) 196 return 3; 197 198 e = bpf_map_lookup_elem(&rhmap, &key); 199 if (!e || e->val != 222) 200 return 4; 201 202 /* Cleanup */ 203 bpf_map_delete_elem(&rhmap, &key); 204 err = 0; 205 return 0; 206 } 207 208 SEC("syscall") 209 int test_rhash_noexist_duplicate(void *ctx) 210 { 211 int key = 12; 212 struct elem val = {.val = 600, .arr = {0}}; 213 int ret; 214 215 err = 1; 216 217 /* Insert element */ 218 ret = bpf_map_update_elem(&rhmap, &key, &val, BPF_NOEXIST); 219 if (ret) 220 return 1; 221 222 /* Try to insert again with BPF_NOEXIST - should fail with -EEXIST */ 223 ret = bpf_map_update_elem(&rhmap, &key, &val, BPF_NOEXIST); 224 if (ret != -EEXIST) 225 return 2; 226 227 /* Cleanup */ 228 bpf_map_delete_elem(&rhmap, &key); 229 err = 0; 230 return 0; 231 } 232 233 SEC("syscall") 234 int test_rhash_delete_nonexistent(void *ctx) 235 { 236 int key = 99999; 237 int ret; 238 239 err = 1; 240 241 /* Delete non-existent key should return -ENOENT */ 242 ret = bpf_map_delete_elem(&rhmap, &key); 243 if (ret != -ENOENT) 244 return 1; 245 246 err = 0; 247 return 0; 248 } 249