@@ -45,11 +45,8 @@ static const struct option_wrapper long_options[] = {
45
45
{{"force" , no_argument , NULL , 'F' },
46
46
"Force install, replacing existing program on interface" },
47
47
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" },
48
+ {{"unload" , required_argument , NULL , 'U' },
49
+ "Unload XDP program <id> instead of loading" , "<id>" },
53
50
54
51
{{"quiet" , no_argument , NULL , 'q' },
55
52
"Quiet mode (no output)" },
@@ -70,14 +67,107 @@ static const struct option_wrapper long_options[] = {
70
67
const char * pin_basedir = "/sys/fs/bpf" ;
71
68
const char * map_name = "xdp_stats_map" ;
72
69
70
+
71
+ /* Load BPF and XDP program with map reuse using libxdp */
72
+ struct xdp_program * load_bpf_and_xdp_attach_reuse_maps (struct config * cfg , const char * pin_dir , struct bpf_object * * bpf_obj , bool * map_reused )
73
+ {
74
+ int err = 0 ;
75
+ struct bpf_object * obj ;
76
+ struct xdp_program * prog ;
77
+
78
+ if (!cfg || !cfg -> filename [0 ] || !cfg -> progname [0 ] || !pin_dir || !map_reused || !bpf_obj ) {
79
+ fprintf (stderr , "ERR: invalid arguments\n" );
80
+ return NULL ;
81
+ }
82
+
83
+ * map_reused = false;
84
+
85
+ /* 1) Open BPF object */
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) 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) Create XDP program with the pre-opened BPF object */
122
+ DECLARE_LIBXDP_OPTS (xdp_program_opts , xdp_opts , 0 );
123
+
124
+ /* libxdp does not take the ownership of the bpf_object.
125
+ * But it keeps a reference to the original bpf_object.
126
+ */
127
+ xdp_opts .obj = obj ;
128
+ xdp_opts .prog_name = cfg -> progname ;
129
+
130
+ prog = xdp_program__create (& xdp_opts );
131
+ err = libxdp_get_error (prog );
132
+ if (err ) {
133
+ char errmsg [1024 ];
134
+ libxdp_strerror (err , errmsg , sizeof (errmsg ));
135
+ fprintf (stderr , "ERR: loading program: %s\n" , errmsg );
136
+ bpf_object__close (obj );
137
+ return NULL ;
138
+ }
139
+
140
+ /* 4) Attach XDP program to interface */
141
+ err = xdp_program__attach (prog , cfg -> ifindex , cfg -> attach_mode , 0 );
142
+ if (err ) {
143
+ fprintf (stderr , "ERR: xdp_program__attach: %s\n" , strerror (- err ));
144
+ xdp_program__close (prog );
145
+ return NULL ;
146
+ }
147
+
148
+ /* We will leave the responsibility of freeing the bpf_object to the
149
+ * caller of this function.
150
+ */
151
+ * bpf_obj = obj ;
152
+
153
+ return prog ;
154
+ }
155
+
73
156
/* Pinning maps under /sys/fs/bpf in subdir */
74
- int pin_maps_in_bpf_object (struct bpf_object * bpf_obj , struct config * cfg )
157
+ int pin_maps_in_bpf_object (struct bpf_object * bpf_obj , const char * subdir )
75
158
{
76
159
char map_filename [PATH_MAX ];
160
+ char pin_dir [PATH_MAX ];
77
161
int err , len ;
78
162
163
+ len = snprintf (pin_dir , PATH_MAX , "%s/%s" , pin_basedir , subdir );
164
+ if (len < 0 ) {
165
+ fprintf (stderr , "ERR: creating pin dirname\n" );
166
+ return EXIT_FAIL_OPTION ;
167
+ }
168
+
79
169
len = snprintf (map_filename , PATH_MAX , "%s/%s/%s" ,
80
- cfg -> pin_dir , cfg -> ifname , map_name );
170
+ pin_basedir , subdir , map_name );
81
171
if (len < 0 ) {
82
172
fprintf (stderr , "ERR: creating map_name\n" );
83
173
return EXIT_FAIL_OPTION ;
@@ -87,22 +177,22 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
87
177
if (access (map_filename , F_OK ) != -1 ) {
88
178
if (verbose )
89
179
printf (" - Unpinning (remove) prev maps in %s/\n" ,
90
- cfg -> pin_dir );
180
+ pin_dir );
91
181
92
182
/* Basically calls unlink(3) on map_filename */
93
- err = bpf_object__unpin_maps (bpf_obj , cfg -> pin_dir );
183
+ err = bpf_object__unpin_maps (bpf_obj , pin_dir );
94
184
if (err ) {
95
- fprintf (stderr , "ERR: UNpinning maps in %s\n" , cfg -> pin_dir );
185
+ fprintf (stderr , "ERR: UNpinning maps in %s\n" , pin_dir );
96
186
return EXIT_FAIL_BPF ;
97
187
}
98
188
}
99
189
if (verbose )
100
- printf (" - Pinning maps in %s/\n" , cfg -> pin_dir );
190
+ printf (" - Pinning maps in %s/\n" , pin_dir );
101
191
102
192
/* This will pin all maps in our bpf_object */
103
- err = bpf_object__pin_maps (bpf_obj , cfg -> pin_dir );
193
+ err = bpf_object__pin_maps (bpf_obj , pin_dir );
104
194
if (err ) {
105
- fprintf (stderr , "ERR: Pinning maps in %s\n" , cfg -> pin_dir );
195
+ fprintf (stderr , "ERR: Pinning maps in %s\n" , pin_dir );
106
196
return EXIT_FAIL_BPF ;
107
197
}
108
198
@@ -111,8 +201,11 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
111
201
112
202
int main (int argc , char * * argv )
113
203
{
114
- struct xdp_program * program ;
115
204
int err , len ;
205
+ struct xdp_program * program ;
206
+ struct bpf_object * bpf_obj ;
207
+ bool map_reused = false;
208
+ char path [PATH_MAX ];
116
209
117
210
struct config cfg = {
118
211
.attach_mode = XDP_MODE_NATIVE ,
@@ -131,21 +224,48 @@ int main(int argc, char **argv)
131
224
return EXIT_FAIL_OPTION ;
132
225
}
133
226
if (cfg .do_unload ) {
134
- if (!cfg .reuse_maps ) {
135
- /* TODO: Miss unpin of maps on unload */
227
+ /* unpin the maps */
228
+ len = snprintf (path , PATH_MAX , "%s/%s/%s" , pin_basedir ,
229
+ cfg .ifname , map_name );
230
+ if (len < 0 ) {
231
+ fprintf (stderr , "ERR: creating map filename for unload\n" );
232
+ return EXIT_FAIL_OPTION ;
233
+ }
234
+
235
+ /* If the map file exists, unpin it */
236
+ if (access (path , F_OK ) == 0 ) {
237
+ if (verbose )
238
+ printf (" - Unpinning map %s\n" , path );
239
+
240
+ /* Use unlink to remove the pinned map file */
241
+ err = unlink (path );
242
+ if (err ) {
243
+ fprintf (stderr , "ERR: Failed to unpin map %s: %s\n" ,
244
+ path , strerror (errno ));
245
+ }
246
+ }
247
+
248
+ /* unload the program */
249
+ err = do_unload (& cfg );
250
+ if (err ) {
251
+ char errmsg [1024 ];
252
+ libxdp_strerror (err , errmsg , sizeof (errmsg ));
253
+ fprintf (stderr , "Couldn't unload XDP program: %s\n" , errmsg );
254
+ return err ;
136
255
}
137
- /* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */
256
+
257
+ printf ("Success: Unloaded XDP program\n" );
258
+ return EXIT_OK ;
138
259
}
139
260
140
- /* Initialize the pin_dir configuration */
141
- len = snprintf (cfg . pin_dir , 512 , "%s/%s" , pin_basedir , cfg .ifname );
261
+ /* Try to reuse existing pinned maps before loading */
262
+ len = snprintf (path , PATH_MAX , "%s/%s" , pin_basedir , cfg .ifname );
142
263
if (len < 0 ) {
143
264
fprintf (stderr , "ERR: creating pin dirname\n" );
144
265
return EXIT_FAIL_OPTION ;
145
266
}
146
267
147
-
148
- program = load_bpf_and_xdp_attach (& cfg );
268
+ program = load_bpf_and_xdp_attach_reuse_maps (& cfg , path , & bpf_obj , & map_reused );
149
269
if (!program )
150
270
return EXIT_FAIL_BPF ;
151
271
@@ -156,14 +276,17 @@ int main(int argc, char **argv)
156
276
cfg .ifname , cfg .ifindex );
157
277
}
158
278
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 );
279
+ if (! map_reused ) {
280
+ /* Use the --dev name as subdir for exporting/pinning maps */
281
+ err = pin_maps_in_bpf_object (xdp_program__bpf_obj (program ), cfg . ifname );
162
282
if (err ) {
163
283
fprintf (stderr , "ERR: pinning maps\n" );
164
284
return err ;
165
285
}
166
286
}
167
287
288
+ xdp_program__close (program );
289
+ bpf_object__close (bpf_obj );
290
+
168
291
return EXIT_OK ;
169
292
}
0 commit comments