@@ -126,3 +126,176 @@ void test_libbpf_probe_helpers(void)
126126 ASSERT_EQ (res , d -> supported , buf );
127127 }
128128}
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