xref: /openbmc/linux/tools/testing/selftests/bpf/prog_tests/htab_update.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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