2
2
/* Copyright (c) 2019 Facebook */
3
3
#include <test_progs.h>
4
4
#include <network_helpers.h>
5
+ #include <bpf/btf.h>
6
+
7
+ typedef int (* test_cb )(struct bpf_object * obj );
8
+
9
+ static int check_data_map (struct bpf_object * obj , int prog_cnt , bool reset )
10
+ {
11
+ struct bpf_map * data_map = NULL , * map ;
12
+ __u64 * result = NULL ;
13
+ const int zero = 0 ;
14
+ __u32 duration = 0 ;
15
+ int ret = -1 , i ;
16
+
17
+ result = malloc ((prog_cnt + 32 /* spare */ ) * sizeof (__u64 ));
18
+ if (CHECK (!result , "alloc_memory" , "failed to alloc memory" ))
19
+ return - ENOMEM ;
20
+
21
+ bpf_object__for_each_map (map , obj )
22
+ if (bpf_map__is_internal (map )) {
23
+ data_map = map ;
24
+ break ;
25
+ }
26
+ if (CHECK (!data_map , "find_data_map" , "data map not found\n" ))
27
+ goto out ;
28
+
29
+ ret = bpf_map_lookup_elem (bpf_map__fd (data_map ), & zero , result );
30
+ if (CHECK (ret , "get_result" ,
31
+ "failed to get output data: %d\n" , ret ))
32
+ goto out ;
33
+
34
+ for (i = 0 ; i < prog_cnt ; i ++ ) {
35
+ if (CHECK (result [i ] != 1 , "result" ,
36
+ "fexit_bpf2bpf result[%d] failed err %llu\n" ,
37
+ i , result [i ]))
38
+ goto out ;
39
+ result [i ] = 0 ;
40
+ }
41
+ if (reset ) {
42
+ ret = bpf_map_update_elem (bpf_map__fd (data_map ), & zero , result , 0 );
43
+ if (CHECK (ret , "reset_result" , "failed to reset result\n" ))
44
+ goto out ;
45
+ }
46
+
47
+ ret = 0 ;
48
+ out :
49
+ free (result );
50
+ return ret ;
51
+ }
5
52
6
53
static void test_fexit_bpf2bpf_common (const char * obj_file ,
7
54
const char * target_obj_file ,
8
55
int prog_cnt ,
9
56
const char * * prog_name ,
10
- bool run_prog )
57
+ bool run_prog ,
58
+ test_cb cb )
11
59
{
12
- struct bpf_object * obj = NULL , * pkt_obj ;
13
- int err , pkt_fd , i ;
14
- struct bpf_link * * link = NULL ;
60
+ struct bpf_object * obj = NULL , * tgt_obj ;
15
61
struct bpf_program * * prog = NULL ;
62
+ struct bpf_link * * link = NULL ;
16
63
__u32 duration = 0 , retval ;
17
- struct bpf_map * data_map ;
18
- const int zero = 0 ;
19
- __u64 * result = NULL ;
64
+ int err , tgt_fd , i ;
20
65
21
66
err = bpf_prog_load (target_obj_file , BPF_PROG_TYPE_UNSPEC ,
22
- & pkt_obj , & pkt_fd );
67
+ & tgt_obj , & tgt_fd );
23
68
if (CHECK (err , "tgt_prog_load" , "file %s err %d errno %d\n" ,
24
69
target_obj_file , err , errno ))
25
70
return ;
26
71
DECLARE_LIBBPF_OPTS (bpf_object_open_opts , opts ,
27
- .attach_prog_fd = pkt_fd ,
72
+ .attach_prog_fd = tgt_fd ,
28
73
);
29
74
30
75
link = calloc (sizeof (struct bpf_link * ), prog_cnt );
31
76
prog = calloc (sizeof (struct bpf_program * ), prog_cnt );
32
- result = malloc ((prog_cnt + 32 /* spare */ ) * sizeof (__u64 ));
33
- if (CHECK (!link || !prog || !result , "alloc_memory" ,
34
- "failed to alloc memory" ))
77
+ if (CHECK (!link || !prog , "alloc_memory" , "failed to alloc memory" ))
35
78
goto close_prog ;
36
79
37
80
obj = bpf_object__open_file (obj_file , & opts );
@@ -53,39 +96,33 @@ static void test_fexit_bpf2bpf_common(const char *obj_file,
53
96
goto close_prog ;
54
97
}
55
98
56
- if (!run_prog )
57
- goto close_prog ;
99
+ if (cb ) {
100
+ err = cb (obj );
101
+ if (err )
102
+ goto close_prog ;
103
+ }
58
104
59
- data_map = bpf_object__find_map_by_name (obj , "fexit_bp.bss" );
60
- if (CHECK (!data_map , "find_data_map" , "data map not found\n" ))
105
+ if (!run_prog )
61
106
goto close_prog ;
62
107
63
- err = bpf_prog_test_run (pkt_fd , 1 , & pkt_v6 , sizeof (pkt_v6 ),
108
+ err = bpf_prog_test_run (tgt_fd , 1 , & pkt_v6 , sizeof (pkt_v6 ),
64
109
NULL , NULL , & retval , & duration );
65
110
CHECK (err || retval , "ipv6" ,
66
111
"err %d errno %d retval %d duration %d\n" ,
67
112
err , errno , retval , duration );
68
113
69
- err = bpf_map_lookup_elem (bpf_map__fd (data_map ), & zero , result );
70
- if (CHECK (err , "get_result" ,
71
- "failed to get output data: %d\n" , err ))
114
+ if (check_data_map (obj , prog_cnt , false))
72
115
goto close_prog ;
73
116
74
- for (i = 0 ; i < prog_cnt ; i ++ )
75
- if (CHECK (result [i ] != 1 , "result" , "fexit_bpf2bpf failed err %llu\n" ,
76
- result [i ]))
77
- goto close_prog ;
78
-
79
117
close_prog :
80
118
for (i = 0 ; i < prog_cnt ; i ++ )
81
119
if (!IS_ERR_OR_NULL (link [i ]))
82
120
bpf_link__destroy (link [i ]);
83
121
if (!IS_ERR_OR_NULL (obj ))
84
122
bpf_object__close (obj );
85
- bpf_object__close (pkt_obj );
123
+ bpf_object__close (tgt_obj );
86
124
free (link );
87
125
free (prog );
88
- free (result );
89
126
}
90
127
91
128
static void test_target_no_callees (void )
@@ -96,7 +133,7 @@ static void test_target_no_callees(void)
96
133
test_fexit_bpf2bpf_common ("./fexit_bpf2bpf_simple.o" ,
97
134
"./test_pkt_md_access.o" ,
98
135
ARRAY_SIZE (prog_name ),
99
- prog_name , true);
136
+ prog_name , true, NULL );
100
137
}
101
138
102
139
static void test_target_yes_callees (void )
@@ -110,7 +147,7 @@ static void test_target_yes_callees(void)
110
147
test_fexit_bpf2bpf_common ("./fexit_bpf2bpf.o" ,
111
148
"./test_pkt_access.o" ,
112
149
ARRAY_SIZE (prog_name ),
113
- prog_name , true);
150
+ prog_name , true, NULL );
114
151
}
115
152
116
153
static void test_func_replace (void )
@@ -128,7 +165,7 @@ static void test_func_replace(void)
128
165
test_fexit_bpf2bpf_common ("./fexit_bpf2bpf.o" ,
129
166
"./test_pkt_access.o" ,
130
167
ARRAY_SIZE (prog_name ),
131
- prog_name , true);
168
+ prog_name , true, NULL );
132
169
}
133
170
134
171
static void test_func_replace_verify (void )
@@ -139,7 +176,75 @@ static void test_func_replace_verify(void)
139
176
test_fexit_bpf2bpf_common ("./freplace_connect4.o" ,
140
177
"./connect4_prog.o" ,
141
178
ARRAY_SIZE (prog_name ),
142
- prog_name , false);
179
+ prog_name , false, NULL );
180
+ }
181
+
182
+ static int test_second_attach (struct bpf_object * obj )
183
+ {
184
+ const char * prog_name = "freplace/get_constant" ;
185
+ const char * tgt_name = prog_name + 9 ; /* cut off freplace/ */
186
+ const char * tgt_obj_file = "./test_pkt_access.o" ;
187
+ int err = 0 , tgt_fd , tgt_btf_id , link_fd = -1 ;
188
+ struct bpf_program * prog = NULL ;
189
+ struct bpf_object * tgt_obj ;
190
+ __u32 duration = 0 , retval ;
191
+ struct btf * btf ;
192
+
193
+ prog = bpf_object__find_program_by_title (obj , prog_name );
194
+ if (CHECK (!prog , "find_prog" , "prog %s not found\n" , prog_name ))
195
+ return - ENOENT ;
196
+
197
+ err = bpf_prog_load (tgt_obj_file , BPF_PROG_TYPE_UNSPEC ,
198
+ & tgt_obj , & tgt_fd );
199
+ if (CHECK (err , "second_prog_load" , "file %s err %d errno %d\n" ,
200
+ tgt_obj_file , err , errno ))
201
+ return err ;
202
+
203
+ btf = bpf_object__btf (tgt_obj );
204
+ tgt_btf_id = btf__find_by_name_kind (btf , tgt_name , BTF_KIND_FUNC );
205
+ if (CHECK (tgt_btf_id < 0 , "find_btf" , "no BTF ID found for func %s\n" , prog_name )) {
206
+ err = - ENOENT ;
207
+ goto out ;
208
+ }
209
+
210
+ DECLARE_LIBBPF_OPTS (bpf_raw_tracepoint_opts , opts ,
211
+ .tgt_prog_fd = tgt_fd ,
212
+ .tgt_btf_id = tgt_btf_id ,
213
+ );
214
+ link_fd = bpf_raw_tracepoint_open_opts (NULL , bpf_program__fd (prog ), & opts );
215
+ if (CHECK (link_fd < 0 , "second_link" , "err %d errno %d" ,
216
+ link_fd , errno )) {
217
+ err = link_fd ;
218
+ goto out ;
219
+ }
220
+
221
+ err = bpf_prog_test_run (tgt_fd , 1 , & pkt_v6 , sizeof (pkt_v6 ),
222
+ NULL , NULL , & retval , & duration );
223
+ if (CHECK (err || retval , "ipv6" ,
224
+ "err %d errno %d retval %d duration %d\n" ,
225
+ err , errno , retval , duration ))
226
+ goto out ;
227
+
228
+ err = check_data_map (obj , 1 , true);
229
+ if (err )
230
+ goto out ;
231
+
232
+ out :
233
+ if (link_fd >= 0 )
234
+ close (link_fd );
235
+ bpf_object__close (tgt_obj );
236
+ return err ;
237
+ }
238
+
239
+ static void test_func_replace_multi (void )
240
+ {
241
+ const char * prog_name [] = {
242
+ "freplace/get_constant" ,
243
+ };
244
+ test_fexit_bpf2bpf_common ("./freplace_get_constant.o" ,
245
+ "./test_pkt_access.o" ,
246
+ ARRAY_SIZE (prog_name ),
247
+ prog_name , true, test_second_attach );
143
248
}
144
249
145
250
static void test_func_sockmap_update (void )
@@ -150,7 +255,7 @@ static void test_func_sockmap_update(void)
150
255
test_fexit_bpf2bpf_common ("./freplace_cls_redirect.o" ,
151
256
"./test_cls_redirect.o" ,
152
257
ARRAY_SIZE (prog_name ),
153
- prog_name , false);
258
+ prog_name , false, NULL );
154
259
}
155
260
156
261
static void test_obj_load_failure_common (const char * obj_file ,
@@ -222,4 +327,6 @@ void test_fexit_bpf2bpf(void)
222
327
test_func_replace_return_code ();
223
328
if (test__start_subtest ("func_map_prog_compatibility" ))
224
329
test_func_map_prog_compatibility ();
330
+ if (test__start_subtest ("func_replace_multi" ))
331
+ test_func_replace_multi ();
225
332
}
0 commit comments