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