22/* Copyright (c) 2019 Facebook */
33#include <test_progs.h>
44#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+ }
552
653static void test_fexit_bpf2bpf_common (const char * obj_file ,
754 const char * target_obj_file ,
855 int prog_cnt ,
956 const char * * prog_name ,
10- bool run_prog )
57+ bool run_prog ,
58+ test_cb cb )
1159{
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 ;
1561 struct bpf_program * * prog = NULL ;
62+ struct bpf_link * * link = NULL ;
1663 __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 ;
2065
2166 err = bpf_prog_load (target_obj_file , BPF_PROG_TYPE_UNSPEC ,
22- & pkt_obj , & pkt_fd );
67+ & tgt_obj , & tgt_fd );
2368 if (CHECK (err , "tgt_prog_load" , "file %s err %d errno %d\n" ,
2469 target_obj_file , err , errno ))
2570 return ;
2671 DECLARE_LIBBPF_OPTS (bpf_object_open_opts , opts ,
27- .attach_prog_fd = pkt_fd ,
72+ .attach_prog_fd = tgt_fd ,
2873 );
2974
3075 link = calloc (sizeof (struct bpf_link * ), prog_cnt );
3176 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" ))
3578 goto close_prog ;
3679
3780 obj = bpf_object__open_file (obj_file , & opts );
@@ -53,39 +96,33 @@ static void test_fexit_bpf2bpf_common(const char *obj_file,
5396 goto close_prog ;
5497 }
5598
56- if (!run_prog )
57- goto close_prog ;
99+ if (cb ) {
100+ err = cb (obj );
101+ if (err )
102+ goto close_prog ;
103+ }
58104
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 )
61106 goto close_prog ;
62107
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 ),
64109 NULL , NULL , & retval , & duration );
65110 CHECK (err || retval , "ipv6" ,
66111 "err %d errno %d retval %d duration %d\n" ,
67112 err , errno , retval , duration );
68113
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))
72115 goto close_prog ;
73116
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-
79117close_prog :
80118 for (i = 0 ; i < prog_cnt ; i ++ )
81119 if (!IS_ERR_OR_NULL (link [i ]))
82120 bpf_link__destroy (link [i ]);
83121 if (!IS_ERR_OR_NULL (obj ))
84122 bpf_object__close (obj );
85- bpf_object__close (pkt_obj );
123+ bpf_object__close (tgt_obj );
86124 free (link );
87125 free (prog );
88- free (result );
89126}
90127
91128static void test_target_no_callees (void )
@@ -96,7 +133,7 @@ static void test_target_no_callees(void)
96133 test_fexit_bpf2bpf_common ("./fexit_bpf2bpf_simple.o" ,
97134 "./test_pkt_md_access.o" ,
98135 ARRAY_SIZE (prog_name ),
99- prog_name , true);
136+ prog_name , true, NULL );
100137}
101138
102139static void test_target_yes_callees (void )
@@ -110,7 +147,7 @@ static void test_target_yes_callees(void)
110147 test_fexit_bpf2bpf_common ("./fexit_bpf2bpf.o" ,
111148 "./test_pkt_access.o" ,
112149 ARRAY_SIZE (prog_name ),
113- prog_name , true);
150+ prog_name , true, NULL );
114151}
115152
116153static void test_func_replace (void )
@@ -128,7 +165,7 @@ static void test_func_replace(void)
128165 test_fexit_bpf2bpf_common ("./fexit_bpf2bpf.o" ,
129166 "./test_pkt_access.o" ,
130167 ARRAY_SIZE (prog_name ),
131- prog_name , true);
168+ prog_name , true, NULL );
132169}
133170
134171static void test_func_replace_verify (void )
@@ -139,7 +176,61 @@ static void test_func_replace_verify(void)
139176 test_fexit_bpf2bpf_common ("./freplace_connect4.o" ,
140177 "./connect4_prog.o" ,
141178 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+ struct bpf_program * prog = NULL ;
188+ struct bpf_object * tgt_obj ;
189+ __u32 duration = 0 , retval ;
190+ struct bpf_link * link ;
191+ int err = 0 , tgt_fd ;
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+ link = bpf_program__attach_freplace (prog , tgt_fd , tgt_name );
204+ if (CHECK (IS_ERR (link ), "second_link" , "failed to attach second link prog_fd %d tgt_fd %d\n" , bpf_program__fd (prog ), tgt_fd ))
205+ goto out ;
206+
207+ err = bpf_prog_test_run (tgt_fd , 1 , & pkt_v6 , sizeof (pkt_v6 ),
208+ NULL , NULL , & retval , & duration );
209+ if (CHECK (err || retval , "ipv6" ,
210+ "err %d errno %d retval %d duration %d\n" ,
211+ err , errno , retval , duration ))
212+ goto out ;
213+
214+ err = check_data_map (obj , 1 , true);
215+ if (err )
216+ goto out ;
217+
218+ out :
219+ if (!IS_ERR_OR_NULL (link ))
220+ bpf_link__destroy (link );
221+ bpf_object__close (tgt_obj );
222+ return err ;
223+ }
224+
225+ static void test_func_replace_multi (void )
226+ {
227+ const char * prog_name [] = {
228+ "freplace/get_constant" ,
229+ };
230+ test_fexit_bpf2bpf_common ("./freplace_get_constant.o" ,
231+ "./test_pkt_access.o" ,
232+ ARRAY_SIZE (prog_name ),
233+ prog_name , true, test_second_attach );
143234}
144235
145236static void test_func_sockmap_update (void )
@@ -150,7 +241,7 @@ static void test_func_sockmap_update(void)
150241 test_fexit_bpf2bpf_common ("./freplace_cls_redirect.o" ,
151242 "./test_cls_redirect.o" ,
152243 ARRAY_SIZE (prog_name ),
153- prog_name , false);
244+ prog_name , false, NULL );
154245}
155246
156247static void test_obj_load_failure_common (const char * obj_file ,
@@ -222,4 +313,6 @@ void test_fexit_bpf2bpf(void)
222313 test_func_replace_return_code ();
223314 if (test__start_subtest ("func_map_prog_compatibility" ))
224315 test_func_map_prog_compatibility ();
316+ if (test__start_subtest ("func_replace_multi" ))
317+ test_func_replace_multi ();
225318}
0 commit comments