@@ -22,6 +22,7 @@ static const char *__doc__ = "XDP loader\n"
22
22
#include "../common/common_params.h"
23
23
#include "../common/common_user_bpf_xdp.h"
24
24
#include "../common/common_libbpf.h"
25
+ #include "common_kern_user.h"
25
26
26
27
static const char * default_filename = "xdp_prog_kern.o" ;
27
28
@@ -45,11 +46,8 @@ static const struct option_wrapper long_options[] = {
45
46
{{"force" , no_argument , NULL , 'F' },
46
47
"Force install, replacing existing program on interface" },
47
48
48
- {{"unload" , no_argument , NULL , 'U' },
49
- "Unload XDP program instead of loading" },
50
-
51
- {{"reuse-maps" , no_argument , NULL , 'M' },
52
- "Reuse pinned maps" },
49
+ {{"unload" , required_argument , NULL , 'U' },
50
+ "Unload XDP program <id> instead of loading" , "<id>" },
53
51
54
52
{{"quiet" , no_argument , NULL , 'q' },
55
53
"Quiet mode (no output)" },
@@ -70,14 +68,98 @@ static const struct option_wrapper long_options[] = {
70
68
const char * pin_basedir = "/sys/fs/bpf" ;
71
69
const char * map_name = "xdp_stats_map" ;
72
70
71
+
72
+ /* Load BPF and XDP program with map reuse using libxdp */
73
+ struct xdp_program * load_bpf_and_xdp_attach_reuse_maps (struct config * cfg , const char * pin_dir , bool * map_reused )
74
+ {
75
+ int err = 0 ;
76
+
77
+ if (!cfg || !cfg -> filename [0 ] || !cfg -> progname [0 ] || !pin_dir || !map_reused ) {
78
+ fprintf (stderr , "ERR: invalid arguments\n" );
79
+ return NULL ;
80
+ }
81
+
82
+ * map_reused = false;
83
+
84
+ /* 1) First, try to reuse maps by opening object and reusing before libxdp creates it */
85
+ struct bpf_object * obj = NULL ;
86
+ DECLARE_LIBBPF_OPTS (bpf_object_open_opts , open_opts );
87
+ obj = bpf_object__open_file (cfg -> filename , & open_opts );
88
+ if (libbpf_get_error (obj )) {
89
+ err = - libbpf_get_error (obj );
90
+ fprintf (stderr , "ERR: bpf_object__open_file(%s): %s\n" ,
91
+ cfg -> filename , strerror (- err ));
92
+ return NULL ;
93
+ }
94
+
95
+ /* 2) Try to reuse the specific map */
96
+ struct bpf_map * map = bpf_object__find_map_by_name (obj , map_name );
97
+ if (map ) {
98
+ char map_path [PATH_MAX ];
99
+ int len = snprintf (map_path , PATH_MAX , "%s/%s" , pin_dir , map_name );
100
+ if (len < 0 || len >= PATH_MAX ) {
101
+ fprintf (stderr , "ERR: map path too long\n" );
102
+ bpf_object__close (obj );
103
+ return NULL ;
104
+ }
105
+
106
+ int pinned_map_fd = bpf_obj_get (map_path );
107
+ if (pinned_map_fd >= 0 ) {
108
+ err = bpf_map__reuse_fd (map , pinned_map_fd );
109
+ if (err ) {
110
+ close (pinned_map_fd );
111
+ fprintf (stderr , "ERR: bpf_map__reuse_fd: %s\n" , strerror (- err ));
112
+ bpf_object__close (obj );
113
+ return NULL ;
114
+ }
115
+ * map_reused = true;
116
+ if (verbose )
117
+ printf (" - Reusing pinned map: %s\n" , map_path );
118
+ }
119
+ }
120
+
121
+ /* 3) Now use libxdp with the pre-opened object */
122
+ DECLARE_LIBXDP_OPTS (xdp_program_opts , xdp_opts , 0 );
123
+ /* Use our object with reused maps */
124
+ xdp_opts .obj = obj ;
125
+ xdp_opts .prog_name = cfg -> progname ;
126
+
127
+ struct xdp_program * prog = xdp_program__create (& xdp_opts );
128
+ err = libxdp_get_error (prog );
129
+ if (err ) {
130
+ char errmsg [1024 ];
131
+ libxdp_strerror (err , errmsg , sizeof (errmsg ));
132
+ fprintf (stderr , "ERR: loading program: %s\n" , errmsg );
133
+ bpf_object__close (obj );
134
+ return NULL ;
135
+ }
136
+
137
+ /* 4) Attach using libxdp */
138
+ err = xdp_program__attach (prog , cfg -> ifindex , cfg -> attach_mode , 0 );
139
+ if (err ) {
140
+ fprintf (stderr , "ERR: xdp_program__attach: %s\n" , strerror (- err ));
141
+ xdp_program__close (prog );
142
+ return NULL ;
143
+ }
144
+
145
+ return prog ;
146
+ }
147
+
73
148
/* Pinning maps under /sys/fs/bpf in subdir */
74
- int pin_maps_in_bpf_object (struct bpf_object * bpf_obj , struct config * cfg )
149
+ int pin_maps_in_bpf_object (struct bpf_object * bpf_obj , const char * subdir )
75
150
{
76
151
char map_filename [PATH_MAX ];
152
+ char pin_dir [PATH_MAX ];
77
153
int err , len ;
78
154
155
+ len = snprintf (pin_dir , PATH_MAX , "%s/%s" , pin_basedir , subdir );
156
+ if (len < 0 ) {
157
+ fprintf (stderr , "ERR: creating pin dirname\n" );
158
+ return EXIT_FAIL_OPTION ;
159
+ }
160
+
79
161
len = snprintf (map_filename , PATH_MAX , "%s/%s/%s" ,
80
- cfg -> pin_dir , cfg -> ifname , map_name );
162
+ pin_basedir , subdir , map_name );
81
163
if (len < 0 ) {
82
164
fprintf (stderr , "ERR: creating map_name\n" );
83
165
return EXIT_FAIL_OPTION ;
@@ -87,38 +169,39 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
87
169
if (access (map_filename , F_OK ) != -1 ) {
88
170
if (verbose )
89
171
printf (" - Unpinning (remove) prev maps in %s/\n" ,
90
- cfg -> pin_dir );
172
+ pin_dir );
91
173
92
174
/* Basically calls unlink(3) on map_filename */
93
- err = bpf_object__unpin_maps (bpf_obj , cfg -> pin_dir );
175
+ err = bpf_object__unpin_maps (bpf_obj , pin_dir );
94
176
if (err ) {
95
- fprintf (stderr , "ERR: UNpinning maps in %s\n" , cfg -> pin_dir );
177
+ fprintf (stderr , "ERR: UNpinning maps in %s\n" , pin_dir );
96
178
return EXIT_FAIL_BPF ;
97
179
}
98
180
}
99
181
if (verbose )
100
- printf (" - Pinning maps in %s/\n" , cfg -> pin_dir );
182
+ printf (" - Pinning maps in %s/\n" , pin_dir );
101
183
102
184
/* This will pin all maps in our bpf_object */
103
- err = bpf_object__pin_maps (bpf_obj , cfg -> pin_dir );
104
- if (err ) {
105
- fprintf (stderr , "ERR: Pinning maps in %s\n" , cfg -> pin_dir );
185
+ err = bpf_object__pin_maps (bpf_obj , pin_dir );
186
+ if (err )
106
187
return EXIT_FAIL_BPF ;
107
- }
108
188
109
189
return 0 ;
110
190
}
111
191
112
192
int main (int argc , char * * argv )
113
193
{
114
- struct xdp_program * program ;
115
194
int err , len ;
195
+ struct xdp_program * program ;
196
+ bool map_reused = false;
197
+ char path [PATH_MAX ];
116
198
117
199
struct config cfg = {
118
200
.attach_mode = XDP_MODE_NATIVE ,
119
201
.ifindex = -1 ,
120
202
.do_unload = false,
121
203
};
204
+
122
205
/* Set default BPF-ELF object file and BPF program name */
123
206
strncpy (cfg .filename , default_filename , sizeof (cfg .filename ));
124
207
/* Cmdline options can change progname */
@@ -131,23 +214,51 @@ int main(int argc, char **argv)
131
214
return EXIT_FAIL_OPTION ;
132
215
}
133
216
if (cfg .do_unload ) {
134
- if (!cfg .reuse_maps ) {
135
- /* TODO: Miss unpin of maps on unload */
217
+ /* unpin the maps */
218
+ len = snprintf (path , PATH_MAX , "%s/%s/%s" , pin_basedir ,
219
+ cfg .ifname , map_name );
220
+ if (len < 0 ) {
221
+ fprintf (stderr , "ERR: creating map filename for unload\n" );
222
+ return EXIT_FAIL_OPTION ;
223
+ }
224
+
225
+ /* If the map file exists, unpin it */
226
+ if (access (path , F_OK ) == 0 ) {
227
+ if (verbose )
228
+ printf (" - Unpinning map %s\n" , path );
229
+
230
+ /* Use unlink to remove the pinned map file */
231
+ err = unlink (path );
232
+ if (err ) {
233
+ fprintf (stderr , "ERR: Failed to unpin map %s: %s\n" ,
234
+ path , strerror (errno ));
235
+ }
236
+ }
237
+
238
+ /* unload the program */
239
+ err = do_unload (& cfg );
240
+ if (err ) {
241
+ char errmsg [1024 ];
242
+ libxdp_strerror (err , errmsg , sizeof (errmsg ));
243
+ fprintf (stderr , "Couldn't unload XDP program: %s\n" , errmsg );
244
+ return err ;
136
245
}
137
- /* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */
246
+
247
+ printf ("Success: Unloaded XDP program\n" );
248
+ return EXIT_OK ;
138
249
}
139
250
140
- /* Initialize the pin_dir configuration */
141
- len = snprintf (cfg . pin_dir , 512 , "%s/%s" , pin_basedir , cfg .ifname );
251
+ /* Try to reuse existing pinned maps before loading */
252
+ len = snprintf (path , PATH_MAX , "%s/%s" , pin_basedir , cfg .ifname );
142
253
if (len < 0 ) {
143
254
fprintf (stderr , "ERR: creating pin dirname\n" );
144
255
return EXIT_FAIL_OPTION ;
145
256
}
146
257
147
-
148
- program = load_bpf_and_xdp_attach (& cfg );
149
- if (!program )
258
+ program = load_bpf_and_xdp_attach_reuse_maps (& cfg , path , & map_reused );
259
+ if (!program ) {
150
260
return EXIT_FAIL_BPF ;
261
+ }
151
262
152
263
if (verbose ) {
153
264
printf ("Success: Loaded BPF-object(%s) and used program(%s)\n" ,
@@ -156,9 +267,9 @@ int main(int argc, char **argv)
156
267
cfg .ifname , cfg .ifindex );
157
268
}
158
269
159
- /* Use the --dev name as subdir for exporting/pinning maps */
160
- if (! cfg . reuse_maps ) {
161
- err = pin_maps_in_bpf_object (xdp_program__bpf_obj (program ), & cfg );
270
+ if (! map_reused ) {
271
+ /* Use the --dev name as subdir for exporting/pinning maps */
272
+ err = pin_maps_in_bpf_object (xdp_program__bpf_obj (program ), cfg . ifname );
162
273
if (err ) {
163
274
fprintf (stderr , "ERR: pinning maps\n" );
164
275
return err ;
0 commit comments