@@ -45,11 +45,8 @@ static const struct option_wrapper long_options[] = {
4545 {{"force" , no_argument , NULL , 'F' },
4646 "Force install, replacing existing program on interface" },
4747
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>" },
5350
5451 {{"quiet" , no_argument , NULL , 'q' },
5552 "Quiet mode (no output)" },
@@ -70,14 +67,94 @@ static const struct option_wrapper long_options[] = {
7067const char * pin_basedir = "/sys/fs/bpf" ;
7168const char * map_name = "xdp_stats_map" ;
7269
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 , bool * map_reused )
73+ {
74+ struct xdp_program * prog = NULL ;
75+ struct bpf_map * map ;
76+ char map_path [PATH_MAX ];
77+ int len , pinned_map_fd ;
78+ int err ;
79+
80+ if (!cfg || !cfg -> filename [0 ] || !cfg -> progname [0 ] || !pin_dir || !map_reused ) {
81+ fprintf (stderr , "ERR: invalid arguments\n" );
82+ return NULL ;
83+ }
84+
85+ * map_reused = false;
86+
87+ /* 1) Create XDP program through libxdp */
88+ DECLARE_LIBXDP_OPTS (xdp_program_opts , xdp_opts ,
89+ .prog_name = cfg -> progname ,
90+ .open_filename = cfg -> filename );
91+
92+ prog = xdp_program__create (& xdp_opts );
93+ if (!prog ) {
94+ err = errno ;
95+ fprintf (stderr , "ERR: xdp_program__create: %s\n" , strerror (err ));
96+ return NULL ;
97+ }
98+
99+ /* 2) Get BPF object from xdp_program and reuse the specific map
100+ * At this point: BPF object and maps have not been loaded into the kernel
101+ */
102+ map = bpf_object__find_map_by_name (xdp_program__bpf_obj (prog ), map_name );
103+ if (!map ) {
104+ fprintf (stderr , "ERR: Map %s not found!\n" , map_name );
105+ goto out ;
106+ }
107+
108+ len = snprintf (map_path , PATH_MAX , "%s/%s" , pin_dir , map_name );
109+ if (len < 0 || len >= PATH_MAX ) {
110+ fprintf (stderr , "ERR: map path too long\n" );
111+ goto out ;
112+ }
113+
114+ pinned_map_fd = bpf_obj_get (map_path );
115+ if (pinned_map_fd >= 0 ) {
116+ err = bpf_map__reuse_fd (map , pinned_map_fd );
117+ if (err ) {
118+ close (pinned_map_fd );
119+ fprintf (stderr , "ERR: bpf_map__reuse_fd: %s\n" , strerror (- err ));
120+ goto out ;
121+ }
122+ * map_reused = true;
123+ if (verbose )
124+ printf (" - Reusing pinned map: %s\n" , map_path );
125+ }
126+
127+ /* 3) Attach XDP program to interface
128+ * BPF object will be loaded into the kernel as part of XDP attachment
129+ */
130+ err = xdp_program__attach (prog , cfg -> ifindex , cfg -> attach_mode , 0 );
131+ if (err ) {
132+ fprintf (stderr , "ERR: xdp_program__attach: %s\n" , strerror (- err ));
133+ goto out ;
134+ }
135+
136+ return prog ;
137+
138+ out :
139+ xdp_program__close (prog );
140+ return NULL ;
141+ }
142+
73143/* Pinning maps under /sys/fs/bpf in subdir */
74- int pin_maps_in_bpf_object (struct bpf_object * bpf_obj , struct config * cfg )
144+ int pin_maps_in_bpf_object (struct bpf_object * bpf_obj , const char * subdir )
75145{
76146 char map_filename [PATH_MAX ];
147+ char pin_dir [PATH_MAX ];
77148 int err , len ;
78149
150+ len = snprintf (pin_dir , PATH_MAX , "%s/%s" , pin_basedir , subdir );
151+ if (len < 0 ) {
152+ fprintf (stderr , "ERR: creating pin dirname\n" );
153+ return EXIT_FAIL_OPTION ;
154+ }
155+
79156 len = snprintf (map_filename , PATH_MAX , "%s/%s/%s" ,
80- cfg -> pin_dir , cfg -> ifname , map_name );
157+ pin_basedir , subdir , map_name );
81158 if (len < 0 ) {
82159 fprintf (stderr , "ERR: creating map_name\n" );
83160 return EXIT_FAIL_OPTION ;
@@ -87,22 +164,22 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
87164 if (access (map_filename , F_OK ) != -1 ) {
88165 if (verbose )
89166 printf (" - Unpinning (remove) prev maps in %s/\n" ,
90- cfg -> pin_dir );
167+ pin_dir );
91168
92169 /* Basically calls unlink(3) on map_filename */
93- err = bpf_object__unpin_maps (bpf_obj , cfg -> pin_dir );
170+ err = bpf_object__unpin_maps (bpf_obj , pin_dir );
94171 if (err ) {
95- fprintf (stderr , "ERR: UNpinning maps in %s\n" , cfg -> pin_dir );
172+ fprintf (stderr , "ERR: UNpinning maps in %s\n" , pin_dir );
96173 return EXIT_FAIL_BPF ;
97174 }
98175 }
99176 if (verbose )
100- printf (" - Pinning maps in %s/\n" , cfg -> pin_dir );
177+ printf (" - Pinning maps in %s/\n" , pin_dir );
101178
102179 /* This will pin all maps in our bpf_object */
103- err = bpf_object__pin_maps (bpf_obj , cfg -> pin_dir );
180+ err = bpf_object__pin_maps (bpf_obj , pin_dir );
104181 if (err ) {
105- fprintf (stderr , "ERR: Pinning maps in %s\n" , cfg -> pin_dir );
182+ fprintf (stderr , "ERR: Pinning maps in %s\n" , pin_dir );
106183 return EXIT_FAIL_BPF ;
107184 }
108185
@@ -111,8 +188,10 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
111188
112189int main (int argc , char * * argv )
113190{
114- struct xdp_program * program ;
115191 int err , len ;
192+ struct xdp_program * program ;
193+ bool map_reused = false;
194+ char path [PATH_MAX ];
116195
117196 struct config cfg = {
118197 .attach_mode = XDP_MODE_NATIVE ,
@@ -131,23 +210,52 @@ int main(int argc, char **argv)
131210 return EXIT_FAIL_OPTION ;
132211 }
133212 if (cfg .do_unload ) {
134- if (!cfg .reuse_maps ) {
135- /* TODO: Miss unpin of maps on unload */
213+ /* unpin the maps */
214+ len = snprintf (path , PATH_MAX , "%s/%s/%s" , pin_basedir ,
215+ cfg .ifname , map_name );
216+ if (len < 0 ) {
217+ fprintf (stderr , "ERR: creating map filename for unload\n" );
218+ return EXIT_FAIL_OPTION ;
219+ }
220+
221+ /* If the map file exists, unpin it */
222+ if (access (path , F_OK ) == 0 ) {
223+ if (verbose )
224+ printf (" - Unpinning map %s\n" , path );
225+
226+ /* Use unlink to remove the pinned map file */
227+ err = unlink (path );
228+ if (err ) {
229+ fprintf (stderr , "ERR: Failed to unpin map %s: %s\n" ,
230+ path , strerror (errno ));
231+ }
136232 }
137- /* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */
233+
234+ /* unload the program */
235+ err = do_unload (& cfg );
236+ if (err ) {
237+ char errmsg [1024 ];
238+ libxdp_strerror (err , errmsg , sizeof (errmsg ));
239+ fprintf (stderr , "Couldn't unload XDP program: %s\n" , errmsg );
240+ return err ;
241+ }
242+
243+ printf ("Success: Unloaded XDP program\n" );
244+ return EXIT_OK ;
138245 }
139246
140- /* Initialize the pin_dir configuration */
141- len = snprintf (cfg . pin_dir , 512 , "%s/%s" , pin_basedir , cfg .ifname );
247+ /* Try to reuse existing pinned maps before loading */
248+ len = snprintf (path , PATH_MAX , "%s/%s" , pin_basedir , cfg .ifname );
142249 if (len < 0 ) {
143250 fprintf (stderr , "ERR: creating pin dirname\n" );
144251 return EXIT_FAIL_OPTION ;
145252 }
146253
147-
148- program = load_bpf_and_xdp_attach (& cfg );
149- if (!program )
150- return EXIT_FAIL_BPF ;
254+ program = load_bpf_and_xdp_attach_reuse_maps (& cfg , path , & map_reused );
255+ if (!program ) {
256+ err = EXIT_FAIL_BPF ;
257+ goto out ;
258+ }
151259
152260 if (verbose ) {
153261 printf ("Success: Loaded BPF-object(%s) and used program(%s)\n" ,
@@ -156,14 +264,18 @@ int main(int argc, char **argv)
156264 cfg .ifname , cfg .ifindex );
157265 }
158266
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 );
267+ if (! map_reused ) {
268+ /* Use the --dev name as subdir for exporting/pinning maps */
269+ err = pin_maps_in_bpf_object (xdp_program__bpf_obj (program ), cfg . ifname );
162270 if (err ) {
163271 fprintf (stderr , "ERR: pinning maps\n" );
164- return err ;
272+ goto out ;
165273 }
166274 }
167275
168- return EXIT_OK ;
276+ err = EXIT_OK ;
277+
278+ out :
279+ xdp_program__close (program );
280+ return err ;
169281}
0 commit comments