Skip to content

Commit 31ebcce

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

File tree

2 files changed

+164
-39
lines changed

2 files changed

+164
-39
lines changed

basic-solutions/xdp_loader.c

Lines changed: 147 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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,107 @@ static const struct option_wrapper long_options[] = {
7067
const char *pin_basedir = "/sys/fs/bpf";
7168
const 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, 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+
73156
/* 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)
75158
{
76159
char map_filename[PATH_MAX];
160+
char pin_dir[PATH_MAX];
77161
int err, len;
78162

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+
79169
len = snprintf(map_filename, PATH_MAX, "%s/%s/%s",
80-
cfg->pin_dir, cfg->ifname, map_name);
170+
pin_basedir, subdir, map_name);
81171
if (len < 0) {
82172
fprintf(stderr, "ERR: creating map_name\n");
83173
return EXIT_FAIL_OPTION;
@@ -87,22 +177,22 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
87177
if (access(map_filename, F_OK) != -1 ) {
88178
if (verbose)
89179
printf(" - Unpinning (remove) prev maps in %s/\n",
90-
cfg->pin_dir);
180+
pin_dir);
91181

92182
/* 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);
94184
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);
96186
return EXIT_FAIL_BPF;
97187
}
98188
}
99189
if (verbose)
100-
printf(" - Pinning maps in %s/\n", cfg->pin_dir);
190+
printf(" - Pinning maps in %s/\n", pin_dir);
101191

102192
/* 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);
104194
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);
106196
return EXIT_FAIL_BPF;
107197
}
108198

@@ -111,8 +201,11 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
111201

112202
int main(int argc, char **argv)
113203
{
114-
struct xdp_program *program;
115204
int err, len;
205+
struct xdp_program *program;
206+
struct bpf_object *bpf_obj;
207+
bool map_reused = false;
208+
char path[PATH_MAX];
116209

117210
struct config cfg = {
118211
.attach_mode = XDP_MODE_NATIVE,
@@ -131,21 +224,48 @@ int main(int argc, char **argv)
131224
return EXIT_FAIL_OPTION;
132225
}
133226
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;
136255
}
137-
/* return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0); */
256+
257+
printf("Success: Unloaded XDP program\n");
258+
return EXIT_OK;
138259
}
139260

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);
142263
if (len < 0) {
143264
fprintf(stderr, "ERR: creating pin dirname\n");
144265
return EXIT_FAIL_OPTION;
145266
}
146267

147-
148-
program = load_bpf_and_xdp_attach(&cfg);
268+
program = load_bpf_and_xdp_attach_reuse_maps(&cfg, path, &bpf_obj, &map_reused);
149269
if (!program)
150270
return EXIT_FAIL_BPF;
151271

@@ -156,14 +276,17 @@ int main(int argc, char **argv)
156276
cfg.ifname, cfg.ifindex);
157277
}
158278

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);
162282
if (err) {
163283
fprintf(stderr, "ERR: pinning maps\n");
164284
return err;
165285
}
166286
}
167287

288+
xdp_program__close(program);
289+
bpf_object__close(bpf_obj);
290+
168291
return EXIT_OK;
169292
}

basic04-pinning-maps/xdp_loader.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ 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"
2625

2726
static const char *default_filename = "xdp_prog_kern.o";
2827

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

49-
{{"unload", no_argument, NULL, 'U' },
50-
"Unload XDP program instead of loading"},
48+
{{"unload", required_argument, NULL, 'U' },
49+
"Unload XDP program <id> instead of loading", "<id>"},
5150

5251
{{"quiet", no_argument, NULL, 'q' },
5352
"Quiet mode (no output)"},
@@ -89,7 +88,7 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, const char *subdir)
8988
}
9089

9190
/* Existing/previous XDP prog might not have cleaned up */
92-
if (access(map_filename, F_OK ) != -1 ) {
91+
if (access(map_filename, F_OK) != -1 ) {
9392
if (verbose)
9493
printf(" - Unpinning (remove) prev maps in %s/\n",
9594
pin_dir);
@@ -106,16 +105,20 @@ int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, const char *subdir)
106105

107106
/* This will pin all maps in our bpf_object */
108107
err = bpf_object__pin_maps(bpf_obj, pin_dir);
109-
if (err)
108+
if (err) {
109+
fprintf(stderr, "ERR: Pinning maps in %s\n", pin_dir);
110110
return EXIT_FAIL_BPF;
111+
}
111112

112113
return 0;
113114
}
114115

115116
int main(int argc, char **argv)
116117
{
118+
int err, len;
117119
struct xdp_program *program;
118-
int err;
120+
121+
char path[PATH_MAX];
119122

120123
struct config cfg = {
121124
.attach_mode = XDP_MODE_NATIVE,
@@ -135,26 +138,23 @@ int main(int argc, char **argv)
135138
}
136139
if (cfg.do_unload) {
137140
/* unpin the maps */
138-
char map_filename[PATH_MAX];
139-
int len;
140-
141-
len = snprintf(map_filename, PATH_MAX, "%s/%s/%s", pin_basedir,
141+
len = snprintf(path, PATH_MAX, "%s/%s/%s", pin_basedir,
142142
cfg.ifname, map_name);
143143
if (len < 0) {
144144
fprintf(stderr, "ERR: creating map filename for unload\n");
145145
return EXIT_FAIL_OPTION;
146146
}
147147

148-
/* Check if the map file exists and unpin it */
149-
if (access(map_filename, F_OK) == 0) {
148+
/* If the map file exists, unpin it */
149+
if (access(path, F_OK) == 0) {
150150
if (verbose)
151-
printf(" - Unpinning map %s\n", map_filename);
151+
printf(" - Unpinning map %s\n", path);
152152

153153
/* Use unlink to remove the pinned map file */
154-
err = unlink(map_filename);
154+
err = unlink(path);
155155
if (err) {
156156
fprintf(stderr, "ERR: Failed to unpin map %s: %s\n",
157-
map_filename, strerror(errno));
157+
path, strerror(errno));
158158
}
159159
}
160160

@@ -189,5 +189,7 @@ int main(int argc, char **argv)
189189
return err;
190190
}
191191

192+
xdp_program__close(program);
193+
192194
return EXIT_OK;
193195
}

0 commit comments

Comments
 (0)