1*1c636b62SHou Tao // SPDX-License-Identifier: GPL-2.0
2*1c636b62SHou Tao /* Copyright (C) 2022. Huawei Technologies Co., Ltd */
3*1c636b62SHou Tao #define _GNU_SOURCE
4*1c636b62SHou Tao #include <sched.h>
5*1c636b62SHou Tao #include <stdbool.h>
6*1c636b62SHou Tao #include <test_progs.h>
7*1c636b62SHou Tao #include "htab_update.skel.h"
8*1c636b62SHou Tao
9*1c636b62SHou Tao struct htab_update_ctx {
10*1c636b62SHou Tao int fd;
11*1c636b62SHou Tao int loop;
12*1c636b62SHou Tao bool stop;
13*1c636b62SHou Tao };
14*1c636b62SHou Tao
test_reenter_update(void)15*1c636b62SHou Tao static void test_reenter_update(void)
16*1c636b62SHou Tao {
17*1c636b62SHou Tao struct htab_update *skel;
18*1c636b62SHou Tao unsigned int key, value;
19*1c636b62SHou Tao int err;
20*1c636b62SHou Tao
21*1c636b62SHou Tao skel = htab_update__open();
22*1c636b62SHou Tao if (!ASSERT_OK_PTR(skel, "htab_update__open"))
23*1c636b62SHou Tao return;
24*1c636b62SHou Tao
25*1c636b62SHou Tao /* lookup_elem_raw() may be inlined and find_kernel_btf_id() will return -ESRCH */
26*1c636b62SHou Tao bpf_program__set_autoload(skel->progs.lookup_elem_raw, true);
27*1c636b62SHou Tao err = htab_update__load(skel);
28*1c636b62SHou Tao if (!ASSERT_TRUE(!err || err == -ESRCH, "htab_update__load") || err)
29*1c636b62SHou Tao goto out;
30*1c636b62SHou Tao
31*1c636b62SHou Tao skel->bss->pid = getpid();
32*1c636b62SHou Tao err = htab_update__attach(skel);
33*1c636b62SHou Tao if (!ASSERT_OK(err, "htab_update__attach"))
34*1c636b62SHou Tao goto out;
35*1c636b62SHou Tao
36*1c636b62SHou Tao /* Will trigger the reentrancy of bpf_map_update_elem() */
37*1c636b62SHou Tao key = 0;
38*1c636b62SHou Tao value = 0;
39*1c636b62SHou Tao err = bpf_map_update_elem(bpf_map__fd(skel->maps.htab), &key, &value, 0);
40*1c636b62SHou Tao if (!ASSERT_OK(err, "add element"))
41*1c636b62SHou Tao goto out;
42*1c636b62SHou Tao
43*1c636b62SHou Tao ASSERT_EQ(skel->bss->update_err, -EBUSY, "no reentrancy");
44*1c636b62SHou Tao out:
45*1c636b62SHou Tao htab_update__destroy(skel);
46*1c636b62SHou Tao }
47*1c636b62SHou Tao
htab_update_thread(void * arg)48*1c636b62SHou Tao static void *htab_update_thread(void *arg)
49*1c636b62SHou Tao {
50*1c636b62SHou Tao struct htab_update_ctx *ctx = arg;
51*1c636b62SHou Tao cpu_set_t cpus;
52*1c636b62SHou Tao int i;
53*1c636b62SHou Tao
54*1c636b62SHou Tao /* Pinned on CPU 0 */
55*1c636b62SHou Tao CPU_ZERO(&cpus);
56*1c636b62SHou Tao CPU_SET(0, &cpus);
57*1c636b62SHou Tao pthread_setaffinity_np(pthread_self(), sizeof(cpus), &cpus);
58*1c636b62SHou Tao
59*1c636b62SHou Tao i = 0;
60*1c636b62SHou Tao while (i++ < ctx->loop && !ctx->stop) {
61*1c636b62SHou Tao unsigned int key = 0, value = 0;
62*1c636b62SHou Tao int err;
63*1c636b62SHou Tao
64*1c636b62SHou Tao err = bpf_map_update_elem(ctx->fd, &key, &value, 0);
65*1c636b62SHou Tao if (err) {
66*1c636b62SHou Tao ctx->stop = true;
67*1c636b62SHou Tao return (void *)(long)err;
68*1c636b62SHou Tao }
69*1c636b62SHou Tao }
70*1c636b62SHou Tao
71*1c636b62SHou Tao return NULL;
72*1c636b62SHou Tao }
73*1c636b62SHou Tao
test_concurrent_update(void)74*1c636b62SHou Tao static void test_concurrent_update(void)
75*1c636b62SHou Tao {
76*1c636b62SHou Tao struct htab_update_ctx ctx;
77*1c636b62SHou Tao struct htab_update *skel;
78*1c636b62SHou Tao unsigned int i, nr;
79*1c636b62SHou Tao pthread_t *tids;
80*1c636b62SHou Tao int err;
81*1c636b62SHou Tao
82*1c636b62SHou Tao skel = htab_update__open_and_load();
83*1c636b62SHou Tao if (!ASSERT_OK_PTR(skel, "htab_update__open_and_load"))
84*1c636b62SHou Tao return;
85*1c636b62SHou Tao
86*1c636b62SHou Tao ctx.fd = bpf_map__fd(skel->maps.htab);
87*1c636b62SHou Tao ctx.loop = 1000;
88*1c636b62SHou Tao ctx.stop = false;
89*1c636b62SHou Tao
90*1c636b62SHou Tao nr = 4;
91*1c636b62SHou Tao tids = calloc(nr, sizeof(*tids));
92*1c636b62SHou Tao if (!ASSERT_NEQ(tids, NULL, "no mem"))
93*1c636b62SHou Tao goto out;
94*1c636b62SHou Tao
95*1c636b62SHou Tao for (i = 0; i < nr; i++) {
96*1c636b62SHou Tao err = pthread_create(&tids[i], NULL, htab_update_thread, &ctx);
97*1c636b62SHou Tao if (!ASSERT_OK(err, "pthread_create")) {
98*1c636b62SHou Tao unsigned int j;
99*1c636b62SHou Tao
100*1c636b62SHou Tao ctx.stop = true;
101*1c636b62SHou Tao for (j = 0; j < i; j++)
102*1c636b62SHou Tao pthread_join(tids[j], NULL);
103*1c636b62SHou Tao goto out;
104*1c636b62SHou Tao }
105*1c636b62SHou Tao }
106*1c636b62SHou Tao
107*1c636b62SHou Tao for (i = 0; i < nr; i++) {
108*1c636b62SHou Tao void *thread_err = NULL;
109*1c636b62SHou Tao
110*1c636b62SHou Tao pthread_join(tids[i], &thread_err);
111*1c636b62SHou Tao ASSERT_EQ(thread_err, NULL, "update error");
112*1c636b62SHou Tao }
113*1c636b62SHou Tao
114*1c636b62SHou Tao out:
115*1c636b62SHou Tao if (tids)
116*1c636b62SHou Tao free(tids);
117*1c636b62SHou Tao htab_update__destroy(skel);
118*1c636b62SHou Tao }
119*1c636b62SHou Tao
test_htab_update(void)120*1c636b62SHou Tao void test_htab_update(void)
121*1c636b62SHou Tao {
122*1c636b62SHou Tao if (test__start_subtest("reenter_update"))
123*1c636b62SHou Tao test_reenter_update();
124*1c636b62SHou Tao if (test__start_subtest("concurrent_update"))
125*1c636b62SHou Tao test_concurrent_update();
126*1c636b62SHou Tao }
127