1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2025. Huawei Technologies Co., Ltd */ 3 #define _GNU_SOURCE 4 #include <stdbool.h> 5 #include <test_progs.h> 6 #include "fd_htab_lookup.skel.h" 7 8 struct htab_op_ctx { 9 int fd; 10 int loop; 11 unsigned int entries; 12 bool stop; 13 }; 14 15 #define ERR_TO_RETVAL(where, err) ((void *)(long)(((where) << 12) | (-err))) 16 17 static void *htab_lookup_fn(void *arg) 18 { 19 struct htab_op_ctx *ctx = arg; 20 int i = 0; 21 22 while (i++ < ctx->loop && !ctx->stop) { 23 unsigned int j; 24 25 for (j = 0; j < ctx->entries; j++) { 26 unsigned int key = j, zero = 0, value; 27 int inner_fd, err; 28 29 err = bpf_map_lookup_elem(ctx->fd, &key, &value); 30 if (err) { 31 ctx->stop = true; 32 return ERR_TO_RETVAL(1, err); 33 } 34 35 inner_fd = bpf_map_get_fd_by_id(value); 36 if (inner_fd < 0) { 37 /* The old map has been freed */ 38 if (inner_fd == -ENOENT) 39 continue; 40 ctx->stop = true; 41 return ERR_TO_RETVAL(2, inner_fd); 42 } 43 44 err = bpf_map_lookup_elem(inner_fd, &zero, &value); 45 if (err) { 46 close(inner_fd); 47 ctx->stop = true; 48 return ERR_TO_RETVAL(3, err); 49 } 50 close(inner_fd); 51 52 if (value != key) { 53 ctx->stop = true; 54 return ERR_TO_RETVAL(4, -EINVAL); 55 } 56 } 57 } 58 59 return NULL; 60 } 61 62 static void *htab_update_fn(void *arg) 63 { 64 struct htab_op_ctx *ctx = arg; 65 int i = 0; 66 67 while (i++ < ctx->loop && !ctx->stop) { 68 unsigned int j; 69 70 for (j = 0; j < ctx->entries; j++) { 71 unsigned int key = j, zero = 0; 72 int inner_fd, err; 73 74 inner_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 4, 1, NULL); 75 if (inner_fd < 0) { 76 ctx->stop = true; 77 return ERR_TO_RETVAL(1, inner_fd); 78 } 79 80 err = bpf_map_update_elem(inner_fd, &zero, &key, 0); 81 if (err) { 82 close(inner_fd); 83 ctx->stop = true; 84 return ERR_TO_RETVAL(2, err); 85 } 86 87 err = bpf_map_update_elem(ctx->fd, &key, &inner_fd, BPF_EXIST); 88 if (err) { 89 close(inner_fd); 90 ctx->stop = true; 91 return ERR_TO_RETVAL(3, err); 92 } 93 close(inner_fd); 94 } 95 } 96 97 return NULL; 98 } 99 100 static int setup_htab(int fd, unsigned int entries) 101 { 102 unsigned int i; 103 104 for (i = 0; i < entries; i++) { 105 unsigned int key = i, zero = 0; 106 int inner_fd, err; 107 108 inner_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, 4, 4, 1, NULL); 109 if (!ASSERT_OK_FD(inner_fd, "new array")) 110 return -1; 111 112 err = bpf_map_update_elem(inner_fd, &zero, &key, 0); 113 if (!ASSERT_OK(err, "init array")) { 114 close(inner_fd); 115 return -1; 116 } 117 118 err = bpf_map_update_elem(fd, &key, &inner_fd, 0); 119 if (!ASSERT_OK(err, "init outer")) { 120 close(inner_fd); 121 return -1; 122 } 123 close(inner_fd); 124 } 125 126 return 0; 127 } 128 129 static int get_int_from_env(const char *name, int dft) 130 { 131 const char *value; 132 133 value = getenv(name); 134 if (!value) 135 return dft; 136 137 return atoi(value); 138 } 139 140 void test_fd_htab_lookup(void) 141 { 142 unsigned int i, wr_nr = 8, rd_nr = 16; 143 pthread_t tids[wr_nr + rd_nr]; 144 struct fd_htab_lookup *skel; 145 struct htab_op_ctx ctx; 146 int err; 147 148 skel = fd_htab_lookup__open_and_load(); 149 if (!ASSERT_OK_PTR(skel, "fd_htab_lookup__open_and_load")) 150 return; 151 152 ctx.fd = bpf_map__fd(skel->maps.outer_map); 153 ctx.loop = get_int_from_env("FD_HTAB_LOOP_NR", 5); 154 ctx.stop = false; 155 ctx.entries = 8; 156 157 err = setup_htab(ctx.fd, ctx.entries); 158 if (err) 159 goto destroy; 160 161 memset(tids, 0, sizeof(tids)); 162 for (i = 0; i < wr_nr; i++) { 163 err = pthread_create(&tids[i], NULL, htab_update_fn, &ctx); 164 if (!ASSERT_OK(err, "pthread_create")) { 165 ctx.stop = true; 166 goto reap; 167 } 168 } 169 for (i = 0; i < rd_nr; i++) { 170 err = pthread_create(&tids[i + wr_nr], NULL, htab_lookup_fn, &ctx); 171 if (!ASSERT_OK(err, "pthread_create")) { 172 ctx.stop = true; 173 goto reap; 174 } 175 } 176 177 reap: 178 for (i = 0; i < wr_nr + rd_nr; i++) { 179 void *ret = NULL; 180 char desc[32]; 181 182 if (!tids[i]) 183 continue; 184 185 snprintf(desc, sizeof(desc), "thread %u", i + 1); 186 err = pthread_join(tids[i], &ret); 187 ASSERT_OK(err, desc); 188 ASSERT_EQ(ret, NULL, desc); 189 } 190 destroy: 191 fd_htab_lookup__destroy(skel); 192 } 193