Skip to content

Commit a26a87b

Browse files
author
Xun Gu
committed
basic-solutions: Implement basic04 Assignment 2
Signed-off-by: Xun Gu <xugu@redhat.com>
1 parent 77b90a7 commit a26a87b

File tree

1 file changed

+138
-27
lines changed

1 file changed

+138
-27
lines changed

basic-solutions/xdp_loader.c

Lines changed: 138 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ static const char *__doc__ = "XDP loader\n"
2222
#include "../common/common_params.h"
2323
#include "../common/common_user_bpf_xdp.h"
2424
#include "../common/common_libbpf.h"
25+
#include "common_kern_user.h"
2526

2627
static const char *default_filename = "xdp_prog_kern.o";
2728

@@ -45,11 +46,8 @@ static const struct option_wrapper long_options[] = {
4546
{{"force", no_argument, NULL, 'F' },
4647
"Force install, replacing existing program on interface"},
4748

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>"},
5351

5452
{{"quiet", no_argument, NULL, 'q' },
5553
"Quiet mode (no output)"},
@@ -70,14 +68,98 @@ static const struct option_wrapper long_options[] = {
7068
const char *pin_basedir = "/sys/fs/bpf";
7169
const char *map_name = "xdp_stats_map";
7270

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+
73148
/* 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)
75150
{
76151
char map_filename[PATH_MAX];
152+
char pin_dir[PATH_MAX];
77153
int err, len;
78154

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+
79161
len = snprintf(map_filename, PATH_MAX, "%s/%s/%s",
80-
cfg->pin_dir, cfg->ifname, map_name);
162+
pin_basedir, subdir, map_name);
81163
if (len < 0) {
82164
fprintf(stderr, "ERR: creating map_name\n");
83165
return EXIT_FAIL_OPTION;
@@ -87,38 +169,39 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
87169
if (access(map_filename, F_OK) != -1 ) {
88170
if (verbose)
89171
printf(" - Unpinning (remove) prev maps in %s/\n",
90-
cfg->pin_dir);
172+
pin_dir);
91173

92174
/* 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);
94176
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);
96178
return EXIT_FAIL_BPF;
97179
}
98180
}
99181
if (verbose)
100-
printf(" - Pinning maps in %s/\n", cfg->pin_dir);
182+
printf(" - Pinning maps in %s/\n", pin_dir);
101183

102184
/* 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)
106187
return EXIT_FAIL_BPF;
107-
}
108188

109189
return 0;
110190
}
111191

112192
int main(int argc, char **argv)
113193
{
114-
struct xdp_program *program;
115194
int err, len;
195+
struct xdp_program *program;
196+
bool map_reused = false;
197+
char path[PATH_MAX];
116198

117199
struct config cfg = {
118200
.attach_mode = XDP_MODE_NATIVE,
119201
.ifindex = -1,
120202
.do_unload = false,
121203
};
204+
122205
/* Set default BPF-ELF object file and BPF program name */
123206
strncpy(cfg.filename, default_filename, sizeof(cfg.filename));
124207
/* Cmdline options can change progname */
@@ -131,23 +214,51 @@ int main(int argc, char **argv)
131214
return EXIT_FAIL_OPTION;
132215
}
133216
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;
136245
}
137-
/* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */
246+
247+
printf("Success: Unloaded XDP program\n");
248+
return EXIT_OK;
138249
}
139250

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);
142253
if (len < 0) {
143254
fprintf(stderr, "ERR: creating pin dirname\n");
144255
return EXIT_FAIL_OPTION;
145256
}
146257

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) {
150260
return EXIT_FAIL_BPF;
261+
}
151262

152263
if (verbose) {
153264
printf("Success: Loaded BPF-object(%s) and used program(%s)\n",
@@ -156,9 +267,9 @@ int main(int argc, char **argv)
156267
cfg.ifname, cfg.ifindex);
157268
}
158269

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);
162273
if (err) {
163274
fprintf(stderr, "ERR: pinning maps\n");
164275
return err;

0 commit comments

Comments
 (0)