// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */ #include #include #include #include #include "bpf_misc.h" #define ENOENT 2 #define EEXIST 17 char _license[] SEC("license") = "GPL"; int err; struct elem { char arr[128]; int val; }; struct { __uint(type, BPF_MAP_TYPE_RHASH); __uint(map_flags, BPF_F_NO_PREALLOC); __uint(max_entries, 128); __type(key, int); __type(value, struct elem); } rhmap SEC(".maps"); SEC("syscall") int test_rhash_lookup_update(void *ctx) { int key = 5; struct elem empty = {.val = 3, .arr = {0}}; struct elem *e; err = 1; e = bpf_map_lookup_elem(&rhmap, &key); if (e) return 1; err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST); if (err) return 1; e = bpf_map_lookup_elem(&rhmap, &key); if (!e || e->val != empty.val) { err = 2; return 2; } err = 0; return 0; } SEC("syscall") int test_rhash_update_delete(void *ctx) { int key = 6; struct elem empty = {.val = 4, .arr = {0}}; struct elem *e; err = 1; e = bpf_map_lookup_elem(&rhmap, &key); if (e) return 1; err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST); if (err) return 2; err = bpf_map_delete_elem(&rhmap, &key); if (err) return 3; e = bpf_map_lookup_elem(&rhmap, &key); if (e) { err = 4; return 4; } err = 0; return 0; } SEC("syscall") int test_rhash_update_elements(void *ctx) { int key = 0; struct elem empty = {.val = 4, .arr = {0}}; struct elem *e; int i; err = 1; for (i = 0; i < 128; ++i) { key = i; e = bpf_map_lookup_elem(&rhmap, &key); if (e) return 1; empty.val = key; err = bpf_map_update_elem(&rhmap, &key, &empty, BPF_NOEXIST); if (err) return 2; e = bpf_map_lookup_elem(&rhmap, &key); if (!e || e->val != key) { err = 4; return 4; } } for (i = 0; i < 128; ++i) { key = i; err = bpf_map_delete_elem(&rhmap, &key); if (err) return 3; e = bpf_map_lookup_elem(&rhmap, &key); if (e) { err = 5; return 5; } } err = 0; return 0; } SEC("syscall") int test_rhash_update_exist(void *ctx) { int key = 10; struct elem val1 = {.val = 100, .arr = {0}}; struct elem val2 = {.val = 200, .arr = {0}}; struct elem *e; int ret; err = 1; /* BPF_EXIST on non-existent key should fail with -ENOENT */ ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_EXIST); if (ret != -ENOENT) return 1; /* Insert element first */ ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_NOEXIST); if (ret) return 2; /* Verify initial value */ e = bpf_map_lookup_elem(&rhmap, &key); if (!e || e->val != 100) return 3; /* BPF_EXIST on existing key should succeed and update value */ ret = bpf_map_update_elem(&rhmap, &key, &val2, BPF_EXIST); if (ret) return 4; /* Verify value was updated */ e = bpf_map_lookup_elem(&rhmap, &key); if (!e || e->val != 200) return 5; /* Cleanup */ bpf_map_delete_elem(&rhmap, &key); err = 0; return 0; } SEC("syscall") int test_rhash_update_any(void *ctx) { int key = 11; struct elem val1 = {.val = 111, .arr = {0}}; struct elem val2 = {.val = 222, .arr = {0}}; struct elem *e; int ret; err = 1; /* BPF_ANY on non-existent key should insert */ ret = bpf_map_update_elem(&rhmap, &key, &val1, BPF_ANY); if (ret) return 1; e = bpf_map_lookup_elem(&rhmap, &key); if (!e || e->val != 111) return 2; /* BPF_ANY on existing key should update */ ret = bpf_map_update_elem(&rhmap, &key, &val2, BPF_ANY); if (ret) return 3; e = bpf_map_lookup_elem(&rhmap, &key); if (!e || e->val != 222) return 4; /* Cleanup */ bpf_map_delete_elem(&rhmap, &key); err = 0; return 0; } SEC("syscall") int test_rhash_noexist_duplicate(void *ctx) { int key = 12; struct elem val = {.val = 600, .arr = {0}}; int ret; err = 1; /* Insert element */ ret = bpf_map_update_elem(&rhmap, &key, &val, BPF_NOEXIST); if (ret) return 1; /* Try to insert again with BPF_NOEXIST - should fail with -EEXIST */ ret = bpf_map_update_elem(&rhmap, &key, &val, BPF_NOEXIST); if (ret != -EEXIST) return 2; /* Cleanup */ bpf_map_delete_elem(&rhmap, &key); err = 0; return 0; } SEC("syscall") int test_rhash_delete_nonexistent(void *ctx) { int key = 99999; int ret; err = 1; /* Delete non-existent key should return -ENOENT */ ret = bpf_map_delete_elem(&rhmap, &key); if (ret != -ENOENT) return 1; err = 0; return 0; }