@@ -126,3 +126,176 @@ void test_libbpf_probe_helpers(void)
126
126
ASSERT_EQ (res , d -> supported , buf );
127
127
}
128
128
}
129
+
130
+ static int module_btf_fd (char * module )
131
+ {
132
+ int fd , err ;
133
+ __u32 id = 0 , len ;
134
+ struct bpf_btf_info info ;
135
+ char name [64 ];
136
+
137
+ while (true) {
138
+ err = bpf_btf_get_next_id (id , & id );
139
+ if (err )
140
+ return -1 ;
141
+
142
+ fd = bpf_btf_get_fd_by_id (id );
143
+ if (fd < 0 ) {
144
+ if (errno == ENOENT )
145
+ continue ;
146
+ return -1 ;
147
+ }
148
+ len = sizeof (info );
149
+ memset (& info , 0 , sizeof (info ));
150
+ info .name = ptr_to_u64 (name );
151
+ info .name_len = sizeof (name );
152
+ err = bpf_btf_get_info_by_fd (fd , & info , & len );
153
+ if (err ) {
154
+ close (fd );
155
+ return -1 ;
156
+ }
157
+ /* find target module BTF */
158
+ if (!strcmp (name , module ))
159
+ break ;
160
+
161
+ close (fd );
162
+ }
163
+
164
+ return fd ;
165
+ }
166
+
167
+ void test_libbpf_probe_kfuncs (void )
168
+ {
169
+ int ret , kfunc_id , fd ;
170
+ char * kfunc = "bpf_cpumask_create" ;
171
+ struct btf * vmlinux_btf = NULL ;
172
+ struct btf * module_btf = NULL ;
173
+
174
+ vmlinux_btf = btf__parse ("/sys/kernel/btf/vmlinux" , NULL );
175
+ if (!ASSERT_OK_PTR (vmlinux_btf , "btf_parse" ))
176
+ return ;
177
+
178
+ kfunc_id = btf__find_by_name_kind (vmlinux_btf , kfunc , BTF_KIND_FUNC );
179
+ if (!ASSERT_GT (kfunc_id , 0 , kfunc ))
180
+ goto cleanup ;
181
+
182
+ /* prog BPF_PROG_TYPE_SYSCALL supports kfunc bpf_cpumask_create */
183
+ ret = libbpf_probe_bpf_kfunc (BPF_PROG_TYPE_SYSCALL , kfunc_id , -1 , NULL );
184
+ if (!ASSERT_EQ (ret , 1 , "kfunc in vmlinux support" ))
185
+ goto cleanup ;
186
+
187
+ /* prog BPF_PROG_TYPE_KPROBE does not support kfunc bpf_cpumask_create */
188
+ ret = libbpf_probe_bpf_kfunc (BPF_PROG_TYPE_KPROBE , kfunc_id , -1 , NULL );
189
+ if (!ASSERT_EQ (ret , 0 , "kfunc in vmlinux not suuport" ))
190
+ goto cleanup ;
191
+
192
+ ret = libbpf_probe_bpf_kfunc (BPF_PROG_TYPE_KPROBE , -1 , -1 , NULL );
193
+ if (!ASSERT_EQ (ret , 0 , "invalid kfunc id:-1" ))
194
+ goto cleanup ;
195
+
196
+ ret = libbpf_probe_bpf_kfunc (100000 , kfunc_id , -1 , NULL );
197
+ if (!ASSERT_ERR (ret , "invalid prog type:100000" ))
198
+ goto cleanup ;
199
+
200
+ if (!env .has_testmod )
201
+ goto cleanup ;
202
+
203
+ module_btf = btf__load_module_btf ("bpf_testmod" , vmlinux_btf );
204
+ if (!ASSERT_OK_PTR (module_btf , "load module BTF" ))
205
+ goto cleanup ;
206
+
207
+ kfunc_id = btf__find_by_name (module_btf , "bpf_kfunc_call_test1" );
208
+ if (!ASSERT_GT (kfunc_id , 0 , "func not found" ))
209
+ goto cleanup ;
210
+
211
+ fd = module_btf_fd ("bpf_testmod" );
212
+ if (!ASSERT_GE (fd , 0 , "module BTF fd" ))
213
+ goto cleanup ;
214
+
215
+ /* prog BPF_PROG_TYPE_SYSCALL supports kfunc bpf_kfunc_call_test1 in bpf_testmod */
216
+ ret = libbpf_probe_bpf_kfunc (BPF_PROG_TYPE_SYSCALL , kfunc_id , fd , NULL );
217
+ if (!ASSERT_EQ (ret , 1 , "kfunc in module BTF support" ))
218
+ goto cleanup_fd ;
219
+
220
+ /* prog BPF_PROG_TYPE_KPROBE does not support kfunc bpf_kfunc_call_test1
221
+ * in bpf_testmod
222
+ */
223
+ ret = libbpf_probe_bpf_kfunc (BPF_PROG_TYPE_KPROBE , kfunc_id , fd , NULL );
224
+ if (!ASSERT_EQ (ret , 0 , "kfunc in module BTF not support" ))
225
+ goto cleanup_fd ;
226
+
227
+ ret = libbpf_probe_bpf_kfunc (BPF_PROG_TYPE_SYSCALL , -1 , fd , NULL );
228
+ if (!ASSERT_EQ (ret , 0 , "invalid kfunc id in module BTF" ))
229
+ goto cleanup_fd ;
230
+
231
+ ret = libbpf_probe_bpf_kfunc (BPF_PROG_TYPE_SYSCALL , kfunc_id , 100 , NULL );
232
+ ASSERT_EQ (ret , 0 , "invalid BTF fd in module BTF" );
233
+
234
+ cleanup_fd :
235
+ close (fd );
236
+ cleanup :
237
+ btf__free (vmlinux_btf );
238
+ btf__free (module_btf );
239
+ }
240
+
241
+ static const struct {
242
+ const char * name ;
243
+ int code ;
244
+ } program_types [] = {
245
+ #define _T (n ) { #n , BPF_PROG_TYPE_##n }
246
+ _T (KPROBE ),
247
+ _T (XDP ),
248
+ _T (SYSCALL ),
249
+ _T (SCHED_CLS ),
250
+ _T (SCHED_ACT ),
251
+ _T (SK_SKB ),
252
+ _T (SOCKET_FILTER ),
253
+ _T (CGROUP_SKB ),
254
+ _T (LWT_OUT ),
255
+ _T (LWT_IN ),
256
+ _T (LWT_XMIT ),
257
+ _T (LWT_SEG6LOCAL ),
258
+ _T (NETFILTER ),
259
+ _T (CGROUP_SOCK_ADDR ),
260
+ _T (SCHED_ACT )
261
+ #undef _T
262
+ };
263
+
264
+ void test_libbpf_probe_kfuncs_many (void )
265
+ {
266
+ int i , kfunc_id , ret , id ;
267
+ const struct btf_type * t ;
268
+ struct btf * btf = NULL ;
269
+ const char * kfunc ;
270
+ const char * tag ;
271
+
272
+ btf = btf__parse ("/sys/kernel/btf/vmlinux" , NULL );
273
+ if (!ASSERT_OK_PTR (btf , "btf_parse" ))
274
+ return ;
275
+ for (id = 0 ; id < btf__type_cnt (btf ); ++ id ) {
276
+ t = btf__type_by_id (btf , id );
277
+ if (!t )
278
+ continue ;
279
+ if (!btf_is_decl_tag (t ))
280
+ continue ;
281
+ tag = btf__name_by_offset (btf , t -> name_off );
282
+ if (strcmp (tag , "bpf_kfunc" ) != 0 )
283
+ continue ;
284
+ kfunc_id = t -> type ;
285
+ t = btf__type_by_id (btf , kfunc_id );
286
+ if (!btf_is_func (t ))
287
+ continue ;
288
+ kfunc = btf__name_by_offset (btf , t -> name_off );
289
+ for (i = 0 ; i < ARRAY_SIZE (program_types ); ++ i ) {
290
+ ret = libbpf_probe_bpf_kfunc (program_types [i ].code ,
291
+ kfunc_id , -1 , NULL );
292
+ if (ret < 0 ) {
293
+ ASSERT_FAIL ("kfunc:%s use prog type:%d" ,
294
+ kfunc , program_types [i ].code );
295
+ goto cleanup ;
296
+ }
297
+ }
298
+ }
299
+ cleanup :
300
+ btf__free (btf );
301
+ }
0 commit comments