@@ -45,8 +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" },
48
+ {{"unload" , required_argument , NULL , 'U' },
49
+ "Unload XDP program <id> instead of loading" , "<id> " },
50
50
51
51
{{"reuse-maps" , no_argument , NULL , 'M' },
52
52
"Reuse pinned maps" },
@@ -70,21 +70,95 @@ static const struct option_wrapper long_options[] = {
70
70
const char * pin_basedir = "/sys/fs/bpf" ;
71
71
const char * map_name = "xdp_stats_map" ;
72
72
73
- /* Pinning maps under /sys/fs/bpf in subdir */
73
+
74
+ /* Load BPF and XDP program with map reuse using libxdp */
75
+ struct xdp_program * load_bpf_and_xdp_attach_reuse_maps (struct config * cfg , bool * map_reused )
76
+ {
77
+ struct xdp_program * prog ;
78
+ struct bpf_map * map ;
79
+ char map_path [PATH_MAX ];
80
+ int len , pinned_map_fd ;
81
+ int err ;
82
+
83
+ if (!cfg || !cfg -> filename [0 ] || !cfg -> progname [0 ] || !map_reused ) {
84
+ fprintf (stderr , "ERR: invalid arguments\n" );
85
+ return NULL ;
86
+ }
87
+
88
+ * map_reused = false;
89
+
90
+ /* 1) Create XDP program through libxdp */
91
+ DECLARE_LIBXDP_OPTS (xdp_program_opts , xdp_opts ,
92
+ .prog_name = cfg -> progname ,
93
+ .open_filename = cfg -> filename );
94
+
95
+ prog = xdp_program__create (& xdp_opts );
96
+ if (!prog ) {
97
+ err = errno ;
98
+ fprintf (stderr , "ERR: xdp_program__create: %s\n" , strerror (err ));
99
+ goto out ;
100
+ }
101
+
102
+ /* 2) Get BPF object from xdp_program and reuse the specific map
103
+ * At this point: BPF object and maps have not been loaded into the kernel
104
+ */
105
+ if (cfg -> reuse_maps ) {
106
+ map = bpf_object__find_map_by_name (xdp_program__bpf_obj (prog ), map_name );
107
+ if (!map ) {
108
+ fprintf (stderr , "ERR: Map %s not found!\n" , map_name );
109
+ goto out ;
110
+ }
111
+
112
+ len = snprintf (map_path , PATH_MAX , "%s/%s" , cfg -> pin_dir , map_name );
113
+ if (len < 0 || len >= PATH_MAX ) {
114
+ fprintf (stderr , "ERR: map path too long\n" );
115
+ goto out ;
116
+ }
117
+
118
+ pinned_map_fd = bpf_obj_get (map_path );
119
+ if (pinned_map_fd >= 0 ) {
120
+ err = bpf_map__reuse_fd (map , pinned_map_fd );
121
+ if (err ) {
122
+ close (pinned_map_fd );
123
+ fprintf (stderr , "ERR: bpf_map__reuse_fd: %s\n" , strerror (- err ));
124
+ goto out ;
125
+ }
126
+ * map_reused = true;
127
+ if (verbose )
128
+ printf (" - Reusing pinned map: %s\n" , map_path );
129
+ }
130
+ }
131
+
132
+ /* 3) Attach XDP program to interface
133
+ * BPF object will be loaded into the kernel as part of XDP attachment
134
+ */
135
+ err = xdp_program__attach (prog , cfg -> ifindex , cfg -> attach_mode , 0 );
136
+ if (err ) {
137
+ fprintf (stderr , "ERR: xdp_program__attach: %s\n" , strerror (- err ));
138
+ goto out ;
139
+ }
140
+
141
+ return prog ;
142
+
143
+ out :
144
+ xdp_program__close (prog );
145
+ return NULL ;
146
+ }
147
+
148
+ /* Pinning maps under /sys/fs/bpf */
74
149
int pin_maps_in_bpf_object (struct bpf_object * bpf_obj , struct config * cfg )
75
150
{
76
151
char map_filename [PATH_MAX ];
77
152
int err , len ;
78
153
79
- len = snprintf (map_filename , PATH_MAX , "%s/%s/%s" ,
80
- cfg -> pin_dir , cfg -> ifname , map_name );
154
+ len = snprintf (map_filename , PATH_MAX , "%s/%s" , cfg -> pin_dir , map_name );
81
155
if (len < 0 ) {
82
156
fprintf (stderr , "ERR: creating map_name\n" );
83
157
return EXIT_FAIL_OPTION ;
84
158
}
85
159
86
160
/* Existing/previous XDP prog might not have cleaned up */
87
- if (access (map_filename , F_OK ) != -1 ) {
161
+ if (access (map_filename , F_OK ) != -1 ) {
88
162
if (verbose )
89
163
printf (" - Unpinning (remove) prev maps in %s/\n" ,
90
164
cfg -> pin_dir );
@@ -109,10 +183,36 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
109
183
return 0 ;
110
184
}
111
185
186
+ /* Unpinning map under /sys/fs/bpf */
187
+ void unpin_map (struct config * cfg )
188
+ {
189
+ char map_path [PATH_MAX ];
190
+ int len ;
191
+
192
+ len = snprintf (map_path , PATH_MAX , "%s/%s" , cfg -> pin_dir , map_name );
193
+ if (len < 0 ) {
194
+ fprintf (stderr , "ERR: creating map filename for unpin\n" );
195
+ return ;
196
+ }
197
+
198
+ /* If the map file exists, unpin it */
199
+ if (access (map_path , F_OK ) == 0 ) {
200
+ if (verbose )
201
+ printf (" - Unpinning map %s\n" , map_path );
202
+
203
+ /* Use unlink to remove the pinned map file */
204
+ if (unlink (map_path )) {
205
+ fprintf (stderr , "ERR: Failed to unpin map %s: %s\n" ,
206
+ map_path , strerror (errno ));
207
+ }
208
+ }
209
+ }
210
+
112
211
int main (int argc , char * * argv )
113
212
{
114
213
struct xdp_program * program ;
115
214
int err , len ;
215
+ bool map_reused = false;
116
216
117
217
struct config cfg = {
118
218
.attach_mode = XDP_MODE_NATIVE ,
@@ -130,12 +230,6 @@ int main(int argc, char **argv)
130
230
usage (argv [0 ], __doc__ , long_options , (argc == 1 ));
131
231
return EXIT_FAIL_OPTION ;
132
232
}
133
- if (cfg .do_unload ) {
134
- if (!cfg .reuse_maps ) {
135
- /* TODO: Miss unpin of maps on unload */
136
- }
137
- /* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */
138
- }
139
233
140
234
/* Initialize the pin_dir configuration */
141
235
len = snprintf (cfg .pin_dir , 512 , "%s/%s" , pin_basedir , cfg .ifname );
@@ -144,10 +238,30 @@ int main(int argc, char **argv)
144
238
return EXIT_FAIL_OPTION ;
145
239
}
146
240
241
+ if (cfg .do_unload ) {
242
+ if (!cfg .reuse_maps ) {
243
+ unpin_map (& cfg );
244
+ }
245
+
246
+ /* unload the program */
247
+ err = do_unload (& cfg );
248
+ if (err ) {
249
+ char errmsg [1024 ];
250
+ libxdp_strerror (err , errmsg , sizeof (errmsg ));
251
+ fprintf (stderr , "Couldn't unload XDP program: %s\n" , errmsg );
252
+ return err ;
253
+ }
254
+
255
+ printf ("Success: Unloaded XDP program\n" );
256
+ return EXIT_OK ;
257
+ }
147
258
148
- program = load_bpf_and_xdp_attach (& cfg );
149
- if (!program )
150
- return EXIT_FAIL_BPF ;
259
+ /* Try to reuse existing pinned maps before loading */
260
+ program = load_bpf_and_xdp_attach_reuse_maps (& cfg , & map_reused );
261
+ if (!program ) {
262
+ err = EXIT_FAIL_BPF ;
263
+ goto out ;
264
+ }
151
265
152
266
if (verbose ) {
153
267
printf ("Success: Loaded BPF-object(%s) and used program(%s)\n" ,
@@ -156,14 +270,18 @@ int main(int argc, char **argv)
156
270
cfg .ifname , cfg .ifindex );
157
271
}
158
272
159
- /* Use the --dev name as subdir for exporting/pinning maps */
160
- if (! cfg . reuse_maps ) {
273
+ if ( cfg . reuse_maps && ! map_reused ) {
274
+ /* Use the --dev name as subdir for exporting/pinning maps */
161
275
err = pin_maps_in_bpf_object (xdp_program__bpf_obj (program ), & cfg );
162
276
if (err ) {
163
277
fprintf (stderr , "ERR: pinning maps\n" );
164
- return err ;
278
+ goto out ;
165
279
}
166
280
}
167
281
168
- return EXIT_OK ;
282
+ err = EXIT_OK ;
283
+
284
+ out :
285
+ xdp_program__close (program );
286
+ return err ;
169
287
}
0 commit comments