151a0e301SMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0 251a0e301SMartin KaFai Lau /* Copyright (c) 2019 Facebook */ 351a0e301SMartin KaFai Lau #include <linux/compiler.h> 451a0e301SMartin KaFai Lau #include <linux/err.h> 551a0e301SMartin KaFai Lau 651a0e301SMartin KaFai Lau #include <sys/resource.h> 751a0e301SMartin KaFai Lau #include <sys/socket.h> 851a0e301SMartin KaFai Lau #include <sys/types.h> 951a0e301SMartin KaFai Lau #include <linux/btf.h> 1051a0e301SMartin KaFai Lau #include <unistd.h> 1151a0e301SMartin KaFai Lau #include <signal.h> 1251a0e301SMartin KaFai Lau #include <errno.h> 1351a0e301SMartin KaFai Lau #include <string.h> 1451a0e301SMartin KaFai Lau #include <pthread.h> 1551a0e301SMartin KaFai Lau 1651a0e301SMartin KaFai Lau #include <bpf/bpf.h> 1751a0e301SMartin KaFai Lau #include <bpf/libbpf.h> 1851a0e301SMartin KaFai Lau 1951a0e301SMartin KaFai Lau #include <test_btf.h> 2051a0e301SMartin KaFai Lau #include <test_maps.h> 2151a0e301SMartin KaFai Lau 2251a0e301SMartin KaFai Lau static struct bpf_create_map_attr xattr = { 2351a0e301SMartin KaFai Lau .name = "sk_storage_map", 2451a0e301SMartin KaFai Lau .map_type = BPF_MAP_TYPE_SK_STORAGE, 2551a0e301SMartin KaFai Lau .map_flags = BPF_F_NO_PREALLOC, 2651a0e301SMartin KaFai Lau .max_entries = 0, 2751a0e301SMartin KaFai Lau .key_size = 4, 2851a0e301SMartin KaFai Lau .value_size = 8, 2951a0e301SMartin KaFai Lau .btf_key_type_id = 1, 3051a0e301SMartin KaFai Lau .btf_value_type_id = 3, 3151a0e301SMartin KaFai Lau .btf_fd = -1, 3251a0e301SMartin KaFai Lau }; 3351a0e301SMartin KaFai Lau 3451a0e301SMartin KaFai Lau static unsigned int nr_sk_threads_done; 3551a0e301SMartin KaFai Lau static unsigned int nr_sk_threads_err; 3651a0e301SMartin KaFai Lau static unsigned int nr_sk_per_thread = 4096; 3751a0e301SMartin KaFai Lau static unsigned int nr_sk_threads = 4; 3851a0e301SMartin KaFai Lau static int sk_storage_map = -1; 3951a0e301SMartin KaFai Lau static unsigned int stop; 4051a0e301SMartin KaFai Lau static int runtime_s = 5; 4151a0e301SMartin KaFai Lau 4251a0e301SMartin KaFai Lau static bool is_stopped(void) 4351a0e301SMartin KaFai Lau { 4451a0e301SMartin KaFai Lau return READ_ONCE(stop); 4551a0e301SMartin KaFai Lau } 4651a0e301SMartin KaFai Lau 4751a0e301SMartin KaFai Lau static unsigned int threads_err(void) 4851a0e301SMartin KaFai Lau { 4951a0e301SMartin KaFai Lau return READ_ONCE(nr_sk_threads_err); 5051a0e301SMartin KaFai Lau } 5151a0e301SMartin KaFai Lau 5251a0e301SMartin KaFai Lau static void notify_thread_err(void) 5351a0e301SMartin KaFai Lau { 5451a0e301SMartin KaFai Lau __sync_add_and_fetch(&nr_sk_threads_err, 1); 5551a0e301SMartin KaFai Lau } 5651a0e301SMartin KaFai Lau 5751a0e301SMartin KaFai Lau static bool wait_for_threads_err(void) 5851a0e301SMartin KaFai Lau { 5951a0e301SMartin KaFai Lau while (!is_stopped() && !threads_err()) 6051a0e301SMartin KaFai Lau usleep(500); 6151a0e301SMartin KaFai Lau 6251a0e301SMartin KaFai Lau return !is_stopped(); 6351a0e301SMartin KaFai Lau } 6451a0e301SMartin KaFai Lau 6551a0e301SMartin KaFai Lau static unsigned int threads_done(void) 6651a0e301SMartin KaFai Lau { 6751a0e301SMartin KaFai Lau return READ_ONCE(nr_sk_threads_done); 6851a0e301SMartin KaFai Lau } 6951a0e301SMartin KaFai Lau 7051a0e301SMartin KaFai Lau static void notify_thread_done(void) 7151a0e301SMartin KaFai Lau { 7251a0e301SMartin KaFai Lau __sync_add_and_fetch(&nr_sk_threads_done, 1); 7351a0e301SMartin KaFai Lau } 7451a0e301SMartin KaFai Lau 7551a0e301SMartin KaFai Lau static void notify_thread_redo(void) 7651a0e301SMartin KaFai Lau { 7751a0e301SMartin KaFai Lau __sync_sub_and_fetch(&nr_sk_threads_done, 1); 7851a0e301SMartin KaFai Lau } 7951a0e301SMartin KaFai Lau 8051a0e301SMartin KaFai Lau static bool wait_for_threads_done(void) 8151a0e301SMartin KaFai Lau { 8251a0e301SMartin KaFai Lau while (threads_done() != nr_sk_threads && !is_stopped() && 8351a0e301SMartin KaFai Lau !threads_err()) 8451a0e301SMartin KaFai Lau usleep(50); 8551a0e301SMartin KaFai Lau 8651a0e301SMartin KaFai Lau return !is_stopped() && !threads_err(); 8751a0e301SMartin KaFai Lau } 8851a0e301SMartin KaFai Lau 8951a0e301SMartin KaFai Lau static bool wait_for_threads_redo(void) 9051a0e301SMartin KaFai Lau { 9151a0e301SMartin KaFai Lau while (threads_done() && !is_stopped() && !threads_err()) 9251a0e301SMartin KaFai Lau usleep(50); 9351a0e301SMartin KaFai Lau 9451a0e301SMartin KaFai Lau return !is_stopped() && !threads_err(); 9551a0e301SMartin KaFai Lau } 9651a0e301SMartin KaFai Lau 9751a0e301SMartin KaFai Lau static bool wait_for_map(void) 9851a0e301SMartin KaFai Lau { 9951a0e301SMartin KaFai Lau while (READ_ONCE(sk_storage_map) == -1 && !is_stopped()) 10051a0e301SMartin KaFai Lau usleep(50); 10151a0e301SMartin KaFai Lau 10251a0e301SMartin KaFai Lau return !is_stopped(); 10351a0e301SMartin KaFai Lau } 10451a0e301SMartin KaFai Lau 10551a0e301SMartin KaFai Lau static bool wait_for_map_close(void) 10651a0e301SMartin KaFai Lau { 10751a0e301SMartin KaFai Lau while (READ_ONCE(sk_storage_map) != -1 && !is_stopped()) 10851a0e301SMartin KaFai Lau ; 10951a0e301SMartin KaFai Lau 11051a0e301SMartin KaFai Lau return !is_stopped(); 11151a0e301SMartin KaFai Lau } 11251a0e301SMartin KaFai Lau 11351a0e301SMartin KaFai Lau static int load_btf(void) 11451a0e301SMartin KaFai Lau { 11551a0e301SMartin KaFai Lau const char btf_str_sec[] = "\0bpf_spin_lock\0val\0cnt\0l"; 11651a0e301SMartin KaFai Lau __u32 btf_raw_types[] = { 11751a0e301SMartin KaFai Lau /* int */ 11851a0e301SMartin KaFai Lau BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ 11951a0e301SMartin KaFai Lau /* struct bpf_spin_lock */ /* [2] */ 12051a0e301SMartin KaFai Lau BTF_TYPE_ENC(1, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 4), 12151a0e301SMartin KaFai Lau BTF_MEMBER_ENC(15, 1, 0), /* int val; */ 12251a0e301SMartin KaFai Lau /* struct val */ /* [3] */ 12351a0e301SMartin KaFai Lau BTF_TYPE_ENC(15, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8), 12451a0e301SMartin KaFai Lau BTF_MEMBER_ENC(19, 1, 0), /* int cnt; */ 12551a0e301SMartin KaFai Lau BTF_MEMBER_ENC(23, 2, 32),/* struct bpf_spin_lock l; */ 12651a0e301SMartin KaFai Lau }; 12751a0e301SMartin KaFai Lau struct btf_header btf_hdr = { 12851a0e301SMartin KaFai Lau .magic = BTF_MAGIC, 12951a0e301SMartin KaFai Lau .version = BTF_VERSION, 13051a0e301SMartin KaFai Lau .hdr_len = sizeof(struct btf_header), 13151a0e301SMartin KaFai Lau .type_len = sizeof(btf_raw_types), 13251a0e301SMartin KaFai Lau .str_off = sizeof(btf_raw_types), 13351a0e301SMartin KaFai Lau .str_len = sizeof(btf_str_sec), 13451a0e301SMartin KaFai Lau }; 13551a0e301SMartin KaFai Lau __u8 raw_btf[sizeof(struct btf_header) + sizeof(btf_raw_types) + 13651a0e301SMartin KaFai Lau sizeof(btf_str_sec)]; 13751a0e301SMartin KaFai Lau 13851a0e301SMartin KaFai Lau memcpy(raw_btf, &btf_hdr, sizeof(btf_hdr)); 13951a0e301SMartin KaFai Lau memcpy(raw_btf + sizeof(btf_hdr), btf_raw_types, sizeof(btf_raw_types)); 14051a0e301SMartin KaFai Lau memcpy(raw_btf + sizeof(btf_hdr) + sizeof(btf_raw_types), 14151a0e301SMartin KaFai Lau btf_str_sec, sizeof(btf_str_sec)); 14251a0e301SMartin KaFai Lau 14351a0e301SMartin KaFai Lau return bpf_load_btf(raw_btf, sizeof(raw_btf), 0, 0, 0); 14451a0e301SMartin KaFai Lau } 14551a0e301SMartin KaFai Lau 14651a0e301SMartin KaFai Lau static int create_sk_storage_map(void) 14751a0e301SMartin KaFai Lau { 14851a0e301SMartin KaFai Lau int btf_fd, map_fd; 14951a0e301SMartin KaFai Lau 15051a0e301SMartin KaFai Lau btf_fd = load_btf(); 15151a0e301SMartin KaFai Lau CHECK(btf_fd == -1, "bpf_load_btf", "btf_fd:%d errno:%d\n", 15251a0e301SMartin KaFai Lau btf_fd, errno); 15351a0e301SMartin KaFai Lau xattr.btf_fd = btf_fd; 15451a0e301SMartin KaFai Lau 15551a0e301SMartin KaFai Lau map_fd = bpf_create_map_xattr(&xattr); 15651a0e301SMartin KaFai Lau xattr.btf_fd = -1; 15751a0e301SMartin KaFai Lau close(btf_fd); 15851a0e301SMartin KaFai Lau CHECK(map_fd == -1, 15951a0e301SMartin KaFai Lau "bpf_create_map_xattr()", "errno:%d\n", errno); 16051a0e301SMartin KaFai Lau 16151a0e301SMartin KaFai Lau return map_fd; 16251a0e301SMartin KaFai Lau } 16351a0e301SMartin KaFai Lau 16451a0e301SMartin KaFai Lau static void *insert_close_thread(void *arg) 16551a0e301SMartin KaFai Lau { 16651a0e301SMartin KaFai Lau struct { 16751a0e301SMartin KaFai Lau int cnt; 16851a0e301SMartin KaFai Lau int lock; 16951a0e301SMartin KaFai Lau } value = { .cnt = 0xeB9F, .lock = 0, }; 17051a0e301SMartin KaFai Lau int i, map_fd, err, *sk_fds; 17151a0e301SMartin KaFai Lau 17251a0e301SMartin KaFai Lau sk_fds = malloc(sizeof(*sk_fds) * nr_sk_per_thread); 17351a0e301SMartin KaFai Lau if (!sk_fds) { 17451a0e301SMartin KaFai Lau notify_thread_err(); 17551a0e301SMartin KaFai Lau return ERR_PTR(-ENOMEM); 17651a0e301SMartin KaFai Lau } 17751a0e301SMartin KaFai Lau 17851a0e301SMartin KaFai Lau for (i = 0; i < nr_sk_per_thread; i++) 17951a0e301SMartin KaFai Lau sk_fds[i] = -1; 18051a0e301SMartin KaFai Lau 18151a0e301SMartin KaFai Lau while (!is_stopped()) { 18251a0e301SMartin KaFai Lau if (!wait_for_map()) 18351a0e301SMartin KaFai Lau goto close_all; 18451a0e301SMartin KaFai Lau 18551a0e301SMartin KaFai Lau map_fd = READ_ONCE(sk_storage_map); 18651a0e301SMartin KaFai Lau for (i = 0; i < nr_sk_per_thread && !is_stopped(); i++) { 18751a0e301SMartin KaFai Lau sk_fds[i] = socket(AF_INET6, SOCK_STREAM, 0); 18851a0e301SMartin KaFai Lau if (sk_fds[i] == -1) { 18951a0e301SMartin KaFai Lau err = -errno; 19051a0e301SMartin KaFai Lau fprintf(stderr, "socket(): errno:%d\n", errno); 19151a0e301SMartin KaFai Lau goto errout; 19251a0e301SMartin KaFai Lau } 19351a0e301SMartin KaFai Lau err = bpf_map_update_elem(map_fd, &sk_fds[i], &value, 19451a0e301SMartin KaFai Lau BPF_NOEXIST); 19551a0e301SMartin KaFai Lau if (err) { 19651a0e301SMartin KaFai Lau err = -errno; 19751a0e301SMartin KaFai Lau fprintf(stderr, 19851a0e301SMartin KaFai Lau "bpf_map_update_elem(): errno:%d\n", 19951a0e301SMartin KaFai Lau errno); 20051a0e301SMartin KaFai Lau goto errout; 20151a0e301SMartin KaFai Lau } 20251a0e301SMartin KaFai Lau } 20351a0e301SMartin KaFai Lau 20451a0e301SMartin KaFai Lau notify_thread_done(); 20551a0e301SMartin KaFai Lau wait_for_map_close(); 20651a0e301SMartin KaFai Lau 20751a0e301SMartin KaFai Lau close_all: 20851a0e301SMartin KaFai Lau for (i = 0; i < nr_sk_per_thread; i++) { 20951a0e301SMartin KaFai Lau close(sk_fds[i]); 21051a0e301SMartin KaFai Lau sk_fds[i] = -1; 21151a0e301SMartin KaFai Lau } 21251a0e301SMartin KaFai Lau 21351a0e301SMartin KaFai Lau notify_thread_redo(); 21451a0e301SMartin KaFai Lau } 21551a0e301SMartin KaFai Lau 21651a0e301SMartin KaFai Lau free(sk_fds); 21751a0e301SMartin KaFai Lau return NULL; 21851a0e301SMartin KaFai Lau 21951a0e301SMartin KaFai Lau errout: 22051a0e301SMartin KaFai Lau for (i = 0; i < nr_sk_per_thread && sk_fds[i] != -1; i++) 22151a0e301SMartin KaFai Lau close(sk_fds[i]); 22251a0e301SMartin KaFai Lau free(sk_fds); 22351a0e301SMartin KaFai Lau notify_thread_err(); 22451a0e301SMartin KaFai Lau return ERR_PTR(err); 22551a0e301SMartin KaFai Lau } 22651a0e301SMartin KaFai Lau 22751a0e301SMartin KaFai Lau static int do_sk_storage_map_stress_free(void) 22851a0e301SMartin KaFai Lau { 22951a0e301SMartin KaFai Lau int i, map_fd = -1, err = 0, nr_threads_created = 0; 23051a0e301SMartin KaFai Lau pthread_t *sk_thread_ids; 23151a0e301SMartin KaFai Lau void *thread_ret; 23251a0e301SMartin KaFai Lau 23351a0e301SMartin KaFai Lau sk_thread_ids = malloc(sizeof(pthread_t) * nr_sk_threads); 23451a0e301SMartin KaFai Lau if (!sk_thread_ids) { 23551a0e301SMartin KaFai Lau fprintf(stderr, "malloc(sk_threads): NULL\n"); 23651a0e301SMartin KaFai Lau return -ENOMEM; 23751a0e301SMartin KaFai Lau } 23851a0e301SMartin KaFai Lau 23951a0e301SMartin KaFai Lau for (i = 0; i < nr_sk_threads; i++) { 24051a0e301SMartin KaFai Lau err = pthread_create(&sk_thread_ids[i], NULL, 24151a0e301SMartin KaFai Lau insert_close_thread, NULL); 24251a0e301SMartin KaFai Lau if (err) { 24351a0e301SMartin KaFai Lau err = -errno; 24451a0e301SMartin KaFai Lau goto done; 24551a0e301SMartin KaFai Lau } 24651a0e301SMartin KaFai Lau nr_threads_created++; 24751a0e301SMartin KaFai Lau } 24851a0e301SMartin KaFai Lau 24951a0e301SMartin KaFai Lau while (!is_stopped()) { 25051a0e301SMartin KaFai Lau map_fd = create_sk_storage_map(); 25151a0e301SMartin KaFai Lau WRITE_ONCE(sk_storage_map, map_fd); 25251a0e301SMartin KaFai Lau 25351a0e301SMartin KaFai Lau if (!wait_for_threads_done()) 25451a0e301SMartin KaFai Lau break; 25551a0e301SMartin KaFai Lau 25651a0e301SMartin KaFai Lau WRITE_ONCE(sk_storage_map, -1); 25751a0e301SMartin KaFai Lau close(map_fd); 25851a0e301SMartin KaFai Lau map_fd = -1; 25951a0e301SMartin KaFai Lau 26051a0e301SMartin KaFai Lau if (!wait_for_threads_redo()) 26151a0e301SMartin KaFai Lau break; 26251a0e301SMartin KaFai Lau } 26351a0e301SMartin KaFai Lau 26451a0e301SMartin KaFai Lau done: 26551a0e301SMartin KaFai Lau WRITE_ONCE(stop, 1); 26651a0e301SMartin KaFai Lau for (i = 0; i < nr_threads_created; i++) { 26751a0e301SMartin KaFai Lau pthread_join(sk_thread_ids[i], &thread_ret); 26851a0e301SMartin KaFai Lau if (IS_ERR(thread_ret) && !err) { 26951a0e301SMartin KaFai Lau err = PTR_ERR(thread_ret); 27051a0e301SMartin KaFai Lau fprintf(stderr, "threads#%u: err:%d\n", i, err); 27151a0e301SMartin KaFai Lau } 27251a0e301SMartin KaFai Lau } 27351a0e301SMartin KaFai Lau free(sk_thread_ids); 27451a0e301SMartin KaFai Lau 27551a0e301SMartin KaFai Lau if (map_fd != -1) 27651a0e301SMartin KaFai Lau close(map_fd); 27751a0e301SMartin KaFai Lau 27851a0e301SMartin KaFai Lau return err; 27951a0e301SMartin KaFai Lau } 28051a0e301SMartin KaFai Lau 28151a0e301SMartin KaFai Lau static void *update_thread(void *arg) 28251a0e301SMartin KaFai Lau { 28351a0e301SMartin KaFai Lau struct { 28451a0e301SMartin KaFai Lau int cnt; 28551a0e301SMartin KaFai Lau int lock; 28651a0e301SMartin KaFai Lau } value = { .cnt = 0xeB9F, .lock = 0, }; 28751a0e301SMartin KaFai Lau int map_fd = READ_ONCE(sk_storage_map); 28851a0e301SMartin KaFai Lau int sk_fd = *(int *)arg; 28951a0e301SMartin KaFai Lau int err = 0; /* Suppress compiler false alarm */ 29051a0e301SMartin KaFai Lau 29151a0e301SMartin KaFai Lau while (!is_stopped()) { 29251a0e301SMartin KaFai Lau err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0); 29351a0e301SMartin KaFai Lau if (err && errno != EAGAIN) { 29451a0e301SMartin KaFai Lau err = -errno; 29551a0e301SMartin KaFai Lau fprintf(stderr, "bpf_map_update_elem: %d %d\n", 29651a0e301SMartin KaFai Lau err, errno); 29751a0e301SMartin KaFai Lau break; 29851a0e301SMartin KaFai Lau } 29951a0e301SMartin KaFai Lau } 30051a0e301SMartin KaFai Lau 30151a0e301SMartin KaFai Lau if (!is_stopped()) { 30251a0e301SMartin KaFai Lau notify_thread_err(); 30351a0e301SMartin KaFai Lau return ERR_PTR(err); 30451a0e301SMartin KaFai Lau } 30551a0e301SMartin KaFai Lau 30651a0e301SMartin KaFai Lau return NULL; 30751a0e301SMartin KaFai Lau } 30851a0e301SMartin KaFai Lau 30951a0e301SMartin KaFai Lau static void *delete_thread(void *arg) 31051a0e301SMartin KaFai Lau { 31151a0e301SMartin KaFai Lau int map_fd = READ_ONCE(sk_storage_map); 31251a0e301SMartin KaFai Lau int sk_fd = *(int *)arg; 31351a0e301SMartin KaFai Lau int err = 0; /* Suppress compiler false alarm */ 31451a0e301SMartin KaFai Lau 31551a0e301SMartin KaFai Lau while (!is_stopped()) { 31651a0e301SMartin KaFai Lau err = bpf_map_delete_elem(map_fd, &sk_fd); 31751a0e301SMartin KaFai Lau if (err && errno != ENOENT) { 31851a0e301SMartin KaFai Lau err = -errno; 31951a0e301SMartin KaFai Lau fprintf(stderr, "bpf_map_delete_elem: %d %d\n", 32051a0e301SMartin KaFai Lau err, errno); 32151a0e301SMartin KaFai Lau break; 32251a0e301SMartin KaFai Lau } 32351a0e301SMartin KaFai Lau } 32451a0e301SMartin KaFai Lau 32551a0e301SMartin KaFai Lau if (!is_stopped()) { 32651a0e301SMartin KaFai Lau notify_thread_err(); 32751a0e301SMartin KaFai Lau return ERR_PTR(err); 32851a0e301SMartin KaFai Lau } 32951a0e301SMartin KaFai Lau 33051a0e301SMartin KaFai Lau return NULL; 33151a0e301SMartin KaFai Lau } 33251a0e301SMartin KaFai Lau 33351a0e301SMartin KaFai Lau static int do_sk_storage_map_stress_change(void) 33451a0e301SMartin KaFai Lau { 33551a0e301SMartin KaFai Lau int i, sk_fd, map_fd = -1, err = 0, nr_threads_created = 0; 33651a0e301SMartin KaFai Lau pthread_t *sk_thread_ids; 33751a0e301SMartin KaFai Lau void *thread_ret; 33851a0e301SMartin KaFai Lau 33951a0e301SMartin KaFai Lau sk_thread_ids = malloc(sizeof(pthread_t) * nr_sk_threads); 34051a0e301SMartin KaFai Lau if (!sk_thread_ids) { 34151a0e301SMartin KaFai Lau fprintf(stderr, "malloc(sk_threads): NULL\n"); 34251a0e301SMartin KaFai Lau return -ENOMEM; 34351a0e301SMartin KaFai Lau } 34451a0e301SMartin KaFai Lau 34551a0e301SMartin KaFai Lau sk_fd = socket(AF_INET6, SOCK_STREAM, 0); 34651a0e301SMartin KaFai Lau if (sk_fd == -1) { 34751a0e301SMartin KaFai Lau err = -errno; 34851a0e301SMartin KaFai Lau goto done; 34951a0e301SMartin KaFai Lau } 35051a0e301SMartin KaFai Lau 35151a0e301SMartin KaFai Lau map_fd = create_sk_storage_map(); 35251a0e301SMartin KaFai Lau WRITE_ONCE(sk_storage_map, map_fd); 35351a0e301SMartin KaFai Lau 35451a0e301SMartin KaFai Lau for (i = 0; i < nr_sk_threads; i++) { 35551a0e301SMartin KaFai Lau if (i & 0x1) 35651a0e301SMartin KaFai Lau err = pthread_create(&sk_thread_ids[i], NULL, 35751a0e301SMartin KaFai Lau update_thread, &sk_fd); 35851a0e301SMartin KaFai Lau else 35951a0e301SMartin KaFai Lau err = pthread_create(&sk_thread_ids[i], NULL, 36051a0e301SMartin KaFai Lau delete_thread, &sk_fd); 36151a0e301SMartin KaFai Lau if (err) { 36251a0e301SMartin KaFai Lau err = -errno; 36351a0e301SMartin KaFai Lau goto done; 36451a0e301SMartin KaFai Lau } 36551a0e301SMartin KaFai Lau nr_threads_created++; 36651a0e301SMartin KaFai Lau } 36751a0e301SMartin KaFai Lau 36851a0e301SMartin KaFai Lau wait_for_threads_err(); 36951a0e301SMartin KaFai Lau 37051a0e301SMartin KaFai Lau done: 37151a0e301SMartin KaFai Lau WRITE_ONCE(stop, 1); 37251a0e301SMartin KaFai Lau for (i = 0; i < nr_threads_created; i++) { 37351a0e301SMartin KaFai Lau pthread_join(sk_thread_ids[i], &thread_ret); 37451a0e301SMartin KaFai Lau if (IS_ERR(thread_ret) && !err) { 37551a0e301SMartin KaFai Lau err = PTR_ERR(thread_ret); 37651a0e301SMartin KaFai Lau fprintf(stderr, "threads#%u: err:%d\n", i, err); 37751a0e301SMartin KaFai Lau } 37851a0e301SMartin KaFai Lau } 37951a0e301SMartin KaFai Lau free(sk_thread_ids); 38051a0e301SMartin KaFai Lau 38151a0e301SMartin KaFai Lau if (sk_fd != -1) 38251a0e301SMartin KaFai Lau close(sk_fd); 38351a0e301SMartin KaFai Lau close(map_fd); 38451a0e301SMartin KaFai Lau 38551a0e301SMartin KaFai Lau return err; 38651a0e301SMartin KaFai Lau } 38751a0e301SMartin KaFai Lau 38851a0e301SMartin KaFai Lau static void stop_handler(int signum) 38951a0e301SMartin KaFai Lau { 39051a0e301SMartin KaFai Lau if (signum != SIGALRM) 39151a0e301SMartin KaFai Lau printf("stopping...\n"); 39251a0e301SMartin KaFai Lau WRITE_ONCE(stop, 1); 39351a0e301SMartin KaFai Lau } 39451a0e301SMartin KaFai Lau 39551a0e301SMartin KaFai Lau #define BPF_SK_STORAGE_MAP_TEST_NR_THREADS "BPF_SK_STORAGE_MAP_TEST_NR_THREADS" 39651a0e301SMartin KaFai Lau #define BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD "BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD" 39751a0e301SMartin KaFai Lau #define BPF_SK_STORAGE_MAP_TEST_RUNTIME_S "BPF_SK_STORAGE_MAP_TEST_RUNTIME_S" 39851a0e301SMartin KaFai Lau #define BPF_SK_STORAGE_MAP_TEST_NAME "BPF_SK_STORAGE_MAP_TEST_NAME" 39951a0e301SMartin KaFai Lau 40051a0e301SMartin KaFai Lau static void test_sk_storage_map_stress_free(void) 40151a0e301SMartin KaFai Lau { 40251a0e301SMartin KaFai Lau struct rlimit rlim_old, rlim_new = {}; 40351a0e301SMartin KaFai Lau int err; 40451a0e301SMartin KaFai Lau 40551a0e301SMartin KaFai Lau getrlimit(RLIMIT_NOFILE, &rlim_old); 40651a0e301SMartin KaFai Lau 40751a0e301SMartin KaFai Lau signal(SIGTERM, stop_handler); 40851a0e301SMartin KaFai Lau signal(SIGINT, stop_handler); 40951a0e301SMartin KaFai Lau if (runtime_s > 0) { 41051a0e301SMartin KaFai Lau signal(SIGALRM, stop_handler); 41151a0e301SMartin KaFai Lau alarm(runtime_s); 41251a0e301SMartin KaFai Lau } 41351a0e301SMartin KaFai Lau 41451a0e301SMartin KaFai Lau if (rlim_old.rlim_cur < nr_sk_threads * nr_sk_per_thread) { 41551a0e301SMartin KaFai Lau rlim_new.rlim_cur = nr_sk_threads * nr_sk_per_thread + 128; 41651a0e301SMartin KaFai Lau rlim_new.rlim_max = rlim_new.rlim_cur + 128; 41751a0e301SMartin KaFai Lau err = setrlimit(RLIMIT_NOFILE, &rlim_new); 41851a0e301SMartin KaFai Lau CHECK(err, "setrlimit(RLIMIT_NOFILE)", "rlim_new:%lu errno:%d", 41951a0e301SMartin KaFai Lau rlim_new.rlim_cur, errno); 42051a0e301SMartin KaFai Lau } 42151a0e301SMartin KaFai Lau 42251a0e301SMartin KaFai Lau err = do_sk_storage_map_stress_free(); 42351a0e301SMartin KaFai Lau 42451a0e301SMartin KaFai Lau signal(SIGTERM, SIG_DFL); 42551a0e301SMartin KaFai Lau signal(SIGINT, SIG_DFL); 42651a0e301SMartin KaFai Lau if (runtime_s > 0) { 42751a0e301SMartin KaFai Lau signal(SIGALRM, SIG_DFL); 42851a0e301SMartin KaFai Lau alarm(0); 42951a0e301SMartin KaFai Lau } 43051a0e301SMartin KaFai Lau 43151a0e301SMartin KaFai Lau if (rlim_new.rlim_cur) 43251a0e301SMartin KaFai Lau setrlimit(RLIMIT_NOFILE, &rlim_old); 43351a0e301SMartin KaFai Lau 43451a0e301SMartin KaFai Lau CHECK(err, "test_sk_storage_map_stress_free", "err:%d\n", err); 43551a0e301SMartin KaFai Lau } 43651a0e301SMartin KaFai Lau 43751a0e301SMartin KaFai Lau static void test_sk_storage_map_stress_change(void) 43851a0e301SMartin KaFai Lau { 43951a0e301SMartin KaFai Lau int err; 44051a0e301SMartin KaFai Lau 44151a0e301SMartin KaFai Lau signal(SIGTERM, stop_handler); 44251a0e301SMartin KaFai Lau signal(SIGINT, stop_handler); 44351a0e301SMartin KaFai Lau if (runtime_s > 0) { 44451a0e301SMartin KaFai Lau signal(SIGALRM, stop_handler); 44551a0e301SMartin KaFai Lau alarm(runtime_s); 44651a0e301SMartin KaFai Lau } 44751a0e301SMartin KaFai Lau 44851a0e301SMartin KaFai Lau err = do_sk_storage_map_stress_change(); 44951a0e301SMartin KaFai Lau 45051a0e301SMartin KaFai Lau signal(SIGTERM, SIG_DFL); 45151a0e301SMartin KaFai Lau signal(SIGINT, SIG_DFL); 45251a0e301SMartin KaFai Lau if (runtime_s > 0) { 45351a0e301SMartin KaFai Lau signal(SIGALRM, SIG_DFL); 45451a0e301SMartin KaFai Lau alarm(0); 45551a0e301SMartin KaFai Lau } 45651a0e301SMartin KaFai Lau 45751a0e301SMartin KaFai Lau CHECK(err, "test_sk_storage_map_stress_change", "err:%d\n", err); 45851a0e301SMartin KaFai Lau } 45951a0e301SMartin KaFai Lau 46051a0e301SMartin KaFai Lau static void test_sk_storage_map_basic(void) 46151a0e301SMartin KaFai Lau { 46251a0e301SMartin KaFai Lau struct { 46351a0e301SMartin KaFai Lau int cnt; 46451a0e301SMartin KaFai Lau int lock; 46551a0e301SMartin KaFai Lau } value = { .cnt = 0xeB9f, .lock = 0, }, lookup_value; 46651a0e301SMartin KaFai Lau struct bpf_create_map_attr bad_xattr; 46751a0e301SMartin KaFai Lau int btf_fd, map_fd, sk_fd, err; 46851a0e301SMartin KaFai Lau 46951a0e301SMartin KaFai Lau btf_fd = load_btf(); 47051a0e301SMartin KaFai Lau CHECK(btf_fd == -1, "bpf_load_btf", "btf_fd:%d errno:%d\n", 47151a0e301SMartin KaFai Lau btf_fd, errno); 47251a0e301SMartin KaFai Lau xattr.btf_fd = btf_fd; 47351a0e301SMartin KaFai Lau 47451a0e301SMartin KaFai Lau sk_fd = socket(AF_INET6, SOCK_STREAM, 0); 47551a0e301SMartin KaFai Lau CHECK(sk_fd == -1, "socket()", "sk_fd:%d errno:%d\n", 47651a0e301SMartin KaFai Lau sk_fd, errno); 47751a0e301SMartin KaFai Lau 47851a0e301SMartin KaFai Lau map_fd = bpf_create_map_xattr(&xattr); 47951a0e301SMartin KaFai Lau CHECK(map_fd == -1, "bpf_create_map_xattr(good_xattr)", 48051a0e301SMartin KaFai Lau "map_fd:%d errno:%d\n", map_fd, errno); 48151a0e301SMartin KaFai Lau 48251a0e301SMartin KaFai Lau /* Add new elem */ 48351a0e301SMartin KaFai Lau memcpy(&lookup_value, &value, sizeof(value)); 48451a0e301SMartin KaFai Lau err = bpf_map_update_elem(map_fd, &sk_fd, &value, 48551a0e301SMartin KaFai Lau BPF_NOEXIST | BPF_F_LOCK); 48651a0e301SMartin KaFai Lau CHECK(err, "bpf_map_update_elem(BPF_NOEXIST|BPF_F_LOCK)", 48751a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 48851a0e301SMartin KaFai Lau err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value, 48951a0e301SMartin KaFai Lau BPF_F_LOCK); 49051a0e301SMartin KaFai Lau CHECK(err || lookup_value.cnt != value.cnt, 49151a0e301SMartin KaFai Lau "bpf_map_lookup_elem_flags(BPF_F_LOCK)", 49251a0e301SMartin KaFai Lau "err:%d errno:%d cnt:%x(%x)\n", 49351a0e301SMartin KaFai Lau err, errno, lookup_value.cnt, value.cnt); 49451a0e301SMartin KaFai Lau 49551a0e301SMartin KaFai Lau /* Bump the cnt and update with BPF_EXIST | BPF_F_LOCK */ 49651a0e301SMartin KaFai Lau value.cnt += 1; 49751a0e301SMartin KaFai Lau err = bpf_map_update_elem(map_fd, &sk_fd, &value, 49851a0e301SMartin KaFai Lau BPF_EXIST | BPF_F_LOCK); 49951a0e301SMartin KaFai Lau CHECK(err, "bpf_map_update_elem(BPF_EXIST|BPF_F_LOCK)", 50051a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 50151a0e301SMartin KaFai Lau err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value, 50251a0e301SMartin KaFai Lau BPF_F_LOCK); 50351a0e301SMartin KaFai Lau CHECK(err || lookup_value.cnt != value.cnt, 50451a0e301SMartin KaFai Lau "bpf_map_lookup_elem_flags(BPF_F_LOCK)", 50551a0e301SMartin KaFai Lau "err:%d errno:%d cnt:%x(%x)\n", 50651a0e301SMartin KaFai Lau err, errno, lookup_value.cnt, value.cnt); 50751a0e301SMartin KaFai Lau 50851a0e301SMartin KaFai Lau /* Bump the cnt and update with BPF_EXIST */ 50951a0e301SMartin KaFai Lau value.cnt += 1; 51051a0e301SMartin KaFai Lau err = bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_EXIST); 51151a0e301SMartin KaFai Lau CHECK(err, "bpf_map_update_elem(BPF_EXIST)", 51251a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 51351a0e301SMartin KaFai Lau err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value, 51451a0e301SMartin KaFai Lau BPF_F_LOCK); 51551a0e301SMartin KaFai Lau CHECK(err || lookup_value.cnt != value.cnt, 51651a0e301SMartin KaFai Lau "bpf_map_lookup_elem_flags(BPF_F_LOCK)", 51751a0e301SMartin KaFai Lau "err:%d errno:%d cnt:%x(%x)\n", 51851a0e301SMartin KaFai Lau err, errno, lookup_value.cnt, value.cnt); 51951a0e301SMartin KaFai Lau 52051a0e301SMartin KaFai Lau /* Update with BPF_NOEXIST */ 52151a0e301SMartin KaFai Lau value.cnt += 1; 52251a0e301SMartin KaFai Lau err = bpf_map_update_elem(map_fd, &sk_fd, &value, 52351a0e301SMartin KaFai Lau BPF_NOEXIST | BPF_F_LOCK); 52451a0e301SMartin KaFai Lau CHECK(!err || errno != EEXIST, 52551a0e301SMartin KaFai Lau "bpf_map_update_elem(BPF_NOEXIST|BPF_F_LOCK)", 52651a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 52751a0e301SMartin KaFai Lau err = bpf_map_update_elem(map_fd, &sk_fd, &value, BPF_NOEXIST); 52851a0e301SMartin KaFai Lau CHECK(!err || errno != EEXIST, "bpf_map_update_elem(BPF_NOEXIST)", 52951a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 53051a0e301SMartin KaFai Lau value.cnt -= 1; 53151a0e301SMartin KaFai Lau err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value, 53251a0e301SMartin KaFai Lau BPF_F_LOCK); 53351a0e301SMartin KaFai Lau CHECK(err || lookup_value.cnt != value.cnt, 53451a0e301SMartin KaFai Lau "bpf_map_lookup_elem_flags(BPF_F_LOCK)", 53551a0e301SMartin KaFai Lau "err:%d errno:%d cnt:%x(%x)\n", 53651a0e301SMartin KaFai Lau err, errno, lookup_value.cnt, value.cnt); 53751a0e301SMartin KaFai Lau 53851a0e301SMartin KaFai Lau /* Bump the cnt again and update with map_flags == 0 */ 53951a0e301SMartin KaFai Lau value.cnt += 1; 54051a0e301SMartin KaFai Lau err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0); 54151a0e301SMartin KaFai Lau CHECK(err, "bpf_map_update_elem()", "err:%d errno:%d\n", 54251a0e301SMartin KaFai Lau err, errno); 54351a0e301SMartin KaFai Lau err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value, 54451a0e301SMartin KaFai Lau BPF_F_LOCK); 54551a0e301SMartin KaFai Lau CHECK(err || lookup_value.cnt != value.cnt, 54651a0e301SMartin KaFai Lau "bpf_map_lookup_elem_flags(BPF_F_LOCK)", 54751a0e301SMartin KaFai Lau "err:%d errno:%d cnt:%x(%x)\n", 54851a0e301SMartin KaFai Lau err, errno, lookup_value.cnt, value.cnt); 54951a0e301SMartin KaFai Lau 55051a0e301SMartin KaFai Lau /* Test delete elem */ 55151a0e301SMartin KaFai Lau err = bpf_map_delete_elem(map_fd, &sk_fd); 55251a0e301SMartin KaFai Lau CHECK(err, "bpf_map_delete_elem()", "err:%d errno:%d\n", 55351a0e301SMartin KaFai Lau err, errno); 55451a0e301SMartin KaFai Lau err = bpf_map_lookup_elem_flags(map_fd, &sk_fd, &lookup_value, 55551a0e301SMartin KaFai Lau BPF_F_LOCK); 55651a0e301SMartin KaFai Lau CHECK(!err || errno != ENOENT, 55751a0e301SMartin KaFai Lau "bpf_map_lookup_elem_flags(BPF_F_LOCK)", 55851a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 55951a0e301SMartin KaFai Lau err = bpf_map_delete_elem(map_fd, &sk_fd); 56051a0e301SMartin KaFai Lau CHECK(!err || errno != ENOENT, "bpf_map_delete_elem()", 56151a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 56251a0e301SMartin KaFai Lau 56351a0e301SMartin KaFai Lau memcpy(&bad_xattr, &xattr, sizeof(xattr)); 56451a0e301SMartin KaFai Lau bad_xattr.btf_key_type_id = 0; 56551a0e301SMartin KaFai Lau err = bpf_create_map_xattr(&bad_xattr); 56651a0e301SMartin KaFai Lau CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)", 56751a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 56851a0e301SMartin KaFai Lau 56951a0e301SMartin KaFai Lau memcpy(&bad_xattr, &xattr, sizeof(xattr)); 57051a0e301SMartin KaFai Lau bad_xattr.btf_key_type_id = 3; 57151a0e301SMartin KaFai Lau err = bpf_create_map_xattr(&bad_xattr); 57251a0e301SMartin KaFai Lau CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)", 57351a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 57451a0e301SMartin KaFai Lau 57551a0e301SMartin KaFai Lau memcpy(&bad_xattr, &xattr, sizeof(xattr)); 57651a0e301SMartin KaFai Lau bad_xattr.max_entries = 1; 57751a0e301SMartin KaFai Lau err = bpf_create_map_xattr(&bad_xattr); 57851a0e301SMartin KaFai Lau CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)", 57951a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 58051a0e301SMartin KaFai Lau 58151a0e301SMartin KaFai Lau memcpy(&bad_xattr, &xattr, sizeof(xattr)); 58251a0e301SMartin KaFai Lau bad_xattr.map_flags = 0; 58351a0e301SMartin KaFai Lau err = bpf_create_map_xattr(&bad_xattr); 58451a0e301SMartin KaFai Lau CHECK(!err || errno != EINVAL, "bap_create_map_xattr(bad_xattr)", 58551a0e301SMartin KaFai Lau "err:%d errno:%d\n", err, errno); 58651a0e301SMartin KaFai Lau 58751a0e301SMartin KaFai Lau xattr.btf_fd = -1; 58851a0e301SMartin KaFai Lau close(btf_fd); 58951a0e301SMartin KaFai Lau close(map_fd); 59051a0e301SMartin KaFai Lau close(sk_fd); 59151a0e301SMartin KaFai Lau } 59251a0e301SMartin KaFai Lau 59351a0e301SMartin KaFai Lau void test_sk_storage_map(void) 59451a0e301SMartin KaFai Lau { 59551a0e301SMartin KaFai Lau const char *test_name, *env_opt; 59651a0e301SMartin KaFai Lau bool test_ran = false; 59751a0e301SMartin KaFai Lau 59851a0e301SMartin KaFai Lau test_name = getenv(BPF_SK_STORAGE_MAP_TEST_NAME); 59951a0e301SMartin KaFai Lau 60051a0e301SMartin KaFai Lau env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_NR_THREADS); 60151a0e301SMartin KaFai Lau if (env_opt) 60251a0e301SMartin KaFai Lau nr_sk_threads = atoi(env_opt); 60351a0e301SMartin KaFai Lau 60451a0e301SMartin KaFai Lau env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_SK_PER_THREAD); 60551a0e301SMartin KaFai Lau if (env_opt) 60651a0e301SMartin KaFai Lau nr_sk_per_thread = atoi(env_opt); 60751a0e301SMartin KaFai Lau 60851a0e301SMartin KaFai Lau env_opt = getenv(BPF_SK_STORAGE_MAP_TEST_RUNTIME_S); 60951a0e301SMartin KaFai Lau if (env_opt) 61051a0e301SMartin KaFai Lau runtime_s = atoi(env_opt); 61151a0e301SMartin KaFai Lau 61251a0e301SMartin KaFai Lau if (!test_name || !strcmp(test_name, "basic")) { 61351a0e301SMartin KaFai Lau test_sk_storage_map_basic(); 61451a0e301SMartin KaFai Lau test_ran = true; 61551a0e301SMartin KaFai Lau } 61651a0e301SMartin KaFai Lau if (!test_name || !strcmp(test_name, "stress_free")) { 61751a0e301SMartin KaFai Lau test_sk_storage_map_stress_free(); 61851a0e301SMartin KaFai Lau test_ran = true; 61951a0e301SMartin KaFai Lau } 62051a0e301SMartin KaFai Lau if (!test_name || !strcmp(test_name, "stress_change")) { 62151a0e301SMartin KaFai Lau test_sk_storage_map_stress_change(); 62251a0e301SMartin KaFai Lau test_ran = true; 62351a0e301SMartin KaFai Lau } 62451a0e301SMartin KaFai Lau 62551a0e301SMartin KaFai Lau if (test_ran) 62651a0e301SMartin KaFai Lau printf("%s:PASS\n", __func__); 62751a0e301SMartin KaFai Lau else 62851a0e301SMartin KaFai Lau CHECK(1, "Invalid test_name", "%s\n", test_name); 62951a0e301SMartin KaFai Lau } 630