|
1 | 1 | // SPDX-License-Identifier: GPL-2.0
|
| 2 | +#include <unistd.h> |
2 | 3 | #include <test_progs.h>
|
3 | 4 | #include <network_helpers.h>
|
| 5 | +#include "tailcall_poke.skel.h" |
| 6 | + |
4 | 7 |
|
5 | 8 | /* test_tailcall_1 checks basic functionality by patching multiple locations
|
6 | 9 | * in a single program for a single tail call slot with nop->jmp, jmp->nop
|
@@ -1105,6 +1108,85 @@ static void test_tailcall_bpf2bpf_fentry_entry(void)
|
1105 | 1108 | bpf_object__close(tgt_obj);
|
1106 | 1109 | }
|
1107 | 1110 |
|
| 1111 | +#define JMP_TABLE "/sys/fs/bpf/jmp_table" |
| 1112 | + |
| 1113 | +static int poke_thread_exit; |
| 1114 | + |
| 1115 | +static void *poke_update(void *arg) |
| 1116 | +{ |
| 1117 | + __u32 zero = 0, prog1_fd, prog2_fd, map_fd; |
| 1118 | + struct tailcall_poke *call = arg; |
| 1119 | + |
| 1120 | + map_fd = bpf_map__fd(call->maps.jmp_table); |
| 1121 | + prog1_fd = bpf_program__fd(call->progs.call1); |
| 1122 | + prog2_fd = bpf_program__fd(call->progs.call2); |
| 1123 | + |
| 1124 | + while (!poke_thread_exit) { |
| 1125 | + bpf_map_update_elem(map_fd, &zero, &prog1_fd, BPF_ANY); |
| 1126 | + bpf_map_update_elem(map_fd, &zero, &prog2_fd, BPF_ANY); |
| 1127 | + } |
| 1128 | + |
| 1129 | + return NULL; |
| 1130 | +} |
| 1131 | + |
| 1132 | +/* |
| 1133 | + * We are trying to hit prog array update during another program load |
| 1134 | + * that shares the same prog array map. |
| 1135 | + * |
| 1136 | + * For that we share the jmp_table map between two skeleton instances |
| 1137 | + * by pinning the jmp_table to same path. Then first skeleton instance |
| 1138 | + * periodically updates jmp_table in 'poke update' thread while we load |
| 1139 | + * the second skeleton instance in the main thread. |
| 1140 | + */ |
| 1141 | +static void test_tailcall_poke(void) |
| 1142 | +{ |
| 1143 | + struct tailcall_poke *call, *test; |
| 1144 | + int err, cnt = 10; |
| 1145 | + pthread_t thread; |
| 1146 | + |
| 1147 | + unlink(JMP_TABLE); |
| 1148 | + |
| 1149 | + call = tailcall_poke__open_and_load(); |
| 1150 | + if (!ASSERT_OK_PTR(call, "tailcall_poke__open")) |
| 1151 | + return; |
| 1152 | + |
| 1153 | + err = bpf_map__pin(call->maps.jmp_table, JMP_TABLE); |
| 1154 | + if (!ASSERT_OK(err, "bpf_map__pin")) |
| 1155 | + goto out; |
| 1156 | + |
| 1157 | + err = pthread_create(&thread, NULL, poke_update, call); |
| 1158 | + if (!ASSERT_OK(err, "new toggler")) |
| 1159 | + goto out; |
| 1160 | + |
| 1161 | + while (cnt--) { |
| 1162 | + test = tailcall_poke__open(); |
| 1163 | + if (!ASSERT_OK_PTR(test, "tailcall_poke__open")) |
| 1164 | + break; |
| 1165 | + |
| 1166 | + err = bpf_map__set_pin_path(test->maps.jmp_table, JMP_TABLE); |
| 1167 | + if (!ASSERT_OK(err, "bpf_map__pin")) { |
| 1168 | + tailcall_poke__destroy(test); |
| 1169 | + break; |
| 1170 | + } |
| 1171 | + |
| 1172 | + bpf_program__set_autoload(test->progs.test, true); |
| 1173 | + bpf_program__set_autoload(test->progs.call1, false); |
| 1174 | + bpf_program__set_autoload(test->progs.call2, false); |
| 1175 | + |
| 1176 | + err = tailcall_poke__load(test); |
| 1177 | + tailcall_poke__destroy(test); |
| 1178 | + if (!ASSERT_OK(err, "tailcall_poke__load")) |
| 1179 | + break; |
| 1180 | + } |
| 1181 | + |
| 1182 | + poke_thread_exit = 1; |
| 1183 | + ASSERT_OK(pthread_join(thread, NULL), "pthread_join"); |
| 1184 | + |
| 1185 | +out: |
| 1186 | + bpf_map__unpin(call->maps.jmp_table, JMP_TABLE); |
| 1187 | + tailcall_poke__destroy(call); |
| 1188 | +} |
| 1189 | + |
1108 | 1190 | void test_tailcalls(void)
|
1109 | 1191 | {
|
1110 | 1192 | if (test__start_subtest("tailcall_1"))
|
@@ -1139,4 +1221,6 @@ void test_tailcalls(void)
|
1139 | 1221 | test_tailcall_bpf2bpf_fentry_fexit();
|
1140 | 1222 | if (test__start_subtest("tailcall_bpf2bpf_fentry_entry"))
|
1141 | 1223 | test_tailcall_bpf2bpf_fentry_entry();
|
| 1224 | + if (test__start_subtest("tailcall_poke")) |
| 1225 | + test_tailcall_poke(); |
1142 | 1226 | }
|
0 commit comments