Skip to content

Commit 1da7dbb

Browse files
committed
basic04: add a solution for assignment 2
Add a solution for the second assignment of the basic04 lesson. Namely, copy the xdp_loader program from the basic04 to basic-solutions and add a new flag, -M or --reuse-maps, which lets the user to reuse existing maps when reloading the program. Signed-off-by: Anton Protopopov <a.s.protopopov@gmail.com>
1 parent 39be10c commit 1da7dbb

File tree

6 files changed

+288
-4
lines changed

6 files changed

+288
-4
lines changed

basic-solutions/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
22

3-
USER_TARGETS := xdp_stats
3+
USER_TARGETS := xdp_stats xdp_loader
44

55
LIBBPF_DIR = ../libbpf/src/
66
COMMON_DIR = ../common/

basic-solutions/README.org

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,4 @@ See the [[file:xdp_stats.c][xdp_stats.c]] program in this directory.
6767

6868
*** Assignment 2: (xdp_loader.c) reuse pinned map
6969

70-
TBD
70+
See the [[file:xdp_loader.c][xdp_loader.c]] program in this directory.

basic-solutions/xdp_loader.c

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
static const char *__doc__ = "XDP loader\n"
3+
" - Allows selecting BPF section --progsec name to XDP-attach to --dev\n";
4+
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <string.h>
8+
#include <errno.h>
9+
#include <getopt.h>
10+
11+
#include <locale.h>
12+
#include <unistd.h>
13+
#include <time.h>
14+
15+
#include <bpf/bpf.h>
16+
#include <bpf/libbpf.h>
17+
18+
#include <net/if.h>
19+
#include <linux/if_link.h> /* depend on kernel-headers installed */
20+
21+
#include "../common/common_params.h"
22+
#include "../common/common_user_bpf_xdp.h"
23+
#include "../common/common_libbpf.h"
24+
25+
static const char *default_filename = "xdp_prog_kern.o";
26+
27+
static const struct option_wrapper long_options[] = {
28+
29+
{{"help", no_argument, NULL, 'h' },
30+
"Show help", false},
31+
32+
{{"dev", required_argument, NULL, 'd' },
33+
"Operate on device <ifname>", "<ifname>", true},
34+
35+
{{"skb-mode", no_argument, NULL, 'S' },
36+
"Install XDP program in SKB (AKA generic) mode"},
37+
38+
{{"native-mode", no_argument, NULL, 'N' },
39+
"Install XDP program in native mode"},
40+
41+
{{"auto-mode", no_argument, NULL, 'A' },
42+
"Auto-detect SKB or native mode"},
43+
44+
{{"force", no_argument, NULL, 'F' },
45+
"Force install, replacing existing program on interface"},
46+
47+
{{"unload", no_argument, NULL, 'U' },
48+
"Unload XDP program instead of loading"},
49+
50+
{{"reuse-maps", no_argument, NULL, 'M' },
51+
"Reuse pinned maps"},
52+
53+
{{"quiet", no_argument, NULL, 'q' },
54+
"Quiet mode (no output)"},
55+
56+
{{"filename", required_argument, NULL, 1 },
57+
"Load program from <file>", "<file>"},
58+
59+
{{"progsec", required_argument, NULL, 2 },
60+
"Load program in <section> of the ELF file", "<section>"},
61+
62+
{{0, 0, NULL, 0 }, NULL, false}
63+
};
64+
65+
#ifndef PATH_MAX
66+
#define PATH_MAX 4096
67+
#endif
68+
69+
const char *pin_basedir = "/sys/fs/bpf";
70+
const char *map_name = "xdp_stats_map";
71+
72+
/* Pinning maps under /sys/fs/bpf in subdir */
73+
int pin_maps_in_bpf_object(struct bpf_object *bpf_obj, struct config *cfg)
74+
{
75+
char map_filename[PATH_MAX];
76+
int err, len;
77+
78+
len = snprintf(map_filename, PATH_MAX, "%s/%s/%s",
79+
pin_basedir, cfg->ifname, map_name);
80+
if (len < 0) {
81+
fprintf(stderr, "ERR: creating map_name\n");
82+
return EXIT_FAIL_OPTION;
83+
}
84+
85+
/* Existing/previous XDP prog might not have cleaned up */
86+
if (access(map_filename, F_OK ) != -1 ) {
87+
if (verbose)
88+
printf(" - Unpinning (remove) prev maps in %s/\n",
89+
cfg->pin_dir);
90+
91+
/* Basically calls unlink(3) on map_filename */
92+
err = bpf_object__unpin_maps(bpf_obj, cfg->pin_dir);
93+
if (err) {
94+
fprintf(stderr, "ERR: UNpinning maps in %s\n", cfg->pin_dir);
95+
return EXIT_FAIL_BPF;
96+
}
97+
}
98+
if (verbose)
99+
printf(" - Pinning maps in %s/\n", cfg->pin_dir);
100+
101+
/* This will pin all maps in our bpf_object */
102+
err = bpf_object__pin_maps(bpf_obj, cfg->pin_dir);
103+
if (err)
104+
return EXIT_FAIL_BPF;
105+
106+
return 0;
107+
}
108+
109+
int main(int argc, char **argv)
110+
{
111+
struct bpf_object *bpf_obj;
112+
int err, len;
113+
114+
struct config cfg = {
115+
.xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_DRV_MODE,
116+
.ifindex = -1,
117+
.do_unload = false,
118+
};
119+
/* Set default BPF-ELF object file and BPF program name */
120+
strncpy(cfg.filename, default_filename, sizeof(cfg.filename));
121+
/* Cmdline options can change progsec */
122+
parse_cmdline_args(argc, argv, long_options, &cfg, __doc__);
123+
124+
/* Required option */
125+
if (cfg.ifindex == -1) {
126+
fprintf(stderr, "ERR: required option --dev missing\n\n");
127+
usage(argv[0], __doc__, long_options, (argc == 1));
128+
return EXIT_FAIL_OPTION;
129+
}
130+
if (cfg.do_unload) {
131+
if (!cfg.reuse_maps) {
132+
/* TODO: Miss unpin of maps on unload */
133+
}
134+
return xdp_link_detach(cfg.ifindex, cfg.xdp_flags, 0);
135+
}
136+
137+
len = snprintf(cfg.pin_dir, PATH_MAX, "%s/%s", pin_basedir, cfg.ifname);
138+
if (len < 0) {
139+
fprintf(stderr, "ERR: creating pin dirname\n");
140+
return EXIT_FAIL_OPTION;
141+
}
142+
143+
144+
bpf_obj = load_bpf_and_xdp_attach(&cfg);
145+
if (!bpf_obj)
146+
return EXIT_FAIL_BPF;
147+
148+
if (verbose) {
149+
printf("Success: Loaded BPF-object(%s) and used section(%s)\n",
150+
cfg.filename, cfg.progsec);
151+
printf(" - XDP prog attached on device:%s(ifindex:%d)\n",
152+
cfg.ifname, cfg.ifindex);
153+
}
154+
155+
/* Use the --dev name as subdir for exporting/pinning maps */
156+
if (!cfg.reuse_maps) {
157+
err = pin_maps_in_bpf_object(bpf_obj, &cfg);
158+
if (err) {
159+
fprintf(stderr, "ERR: pinning maps\n");
160+
return err;
161+
}
162+
}
163+
164+
return EXIT_OK;
165+
}

common/common_defines.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ struct config {
1414
char *redirect_ifname;
1515
char redirect_ifname_buf[IF_NAMESIZE];
1616
bool do_unload;
17+
bool reuse_maps;
18+
char pin_dir[512];
1719
char filename[512];
1820
char progsec[32];
1921
char src_mac[18];

common/common_params.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ void parse_cmdline_args(int argc, char **argv,
9191
}
9292

9393
/* Parse commands line args */
94-
while ((opt = getopt_long(argc, argv, "hd:r:L:R:ASNFUq",
94+
while ((opt = getopt_long(argc, argv, "hd:r:L:R:ASNFUMq",
9595
long_options, &longindex)) != -1) {
9696
switch (opt) {
9797
case 'd':
@@ -142,6 +142,9 @@ void parse_cmdline_args(int argc, char **argv,
142142
case 'F':
143143
cfg->xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
144144
break;
145+
case 'M':
146+
cfg->reuse_maps = true;
147+
break;
145148
case 'U':
146149
cfg->do_unload = true;
147150
break;

common/common_user_bpf_xdp.c

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@
88
#include <bpf/libbpf.h>
99

1010
#include <linux/if_link.h> /* Need XDP flags */
11+
#include <linux/err.h>
1112

1213
#include "common_defines.h"
1314

15+
#ifndef PATH_MAX
16+
#define PATH_MAX 4096
17+
#endif
18+
1419
int xdp_link_attach(int ifindex, __u32 xdp_flags, int prog_fd)
1520
{
1621
int err;
@@ -124,6 +129,110 @@ struct bpf_object *load_bpf_object_file(const char *filename, int ifindex)
124129
return obj;
125130
}
126131

132+
static struct bpf_object *open_bpf_object(const char *file, int ifindex)
133+
{
134+
int err;
135+
struct bpf_object *obj;
136+
struct bpf_map *map;
137+
struct bpf_program *prog, *first_prog = NULL;
138+
139+
struct bpf_object_open_attr open_attr = {
140+
.file = file,
141+
.prog_type = BPF_PROG_TYPE_XDP,
142+
};
143+
144+
obj = bpf_object__open_xattr(&open_attr);
145+
if (IS_ERR_OR_NULL(obj)) {
146+
err = -PTR_ERR(obj);
147+
fprintf(stderr, "ERR: opening BPF-OBJ file(%s) (%d): %s\n",
148+
file, err, strerror(-err));
149+
return NULL;
150+
}
151+
152+
bpf_object__for_each_program(prog, obj) {
153+
bpf_program__set_type(prog, BPF_PROG_TYPE_XDP);
154+
bpf_program__set_ifindex(prog, ifindex);
155+
if (!first_prog)
156+
first_prog = prog;
157+
}
158+
159+
bpf_object__for_each_map(map, obj) {
160+
if (!bpf_map__is_offload_neutral(map))
161+
bpf_map__set_ifindex(map, ifindex);
162+
}
163+
164+
if (!first_prog) {
165+
fprintf(stderr, "ERR: file %s contains no programs\n", file);
166+
return NULL;
167+
}
168+
169+
return obj;
170+
}
171+
172+
static int reuse_maps(struct bpf_object *obj, const char *path)
173+
{
174+
struct bpf_map *map;
175+
176+
if (!obj)
177+
return -ENOENT;
178+
179+
if (!path)
180+
return -EINVAL;
181+
182+
bpf_object__for_each_map(map, obj) {
183+
int len, err;
184+
int pinned_map_fd;
185+
char buf[PATH_MAX];
186+
187+
len = snprintf(buf, PATH_MAX, "%s/%s", path, bpf_map__name(map));
188+
if (len < 0) {
189+
return -EINVAL;
190+
} else if (len >= PATH_MAX) {
191+
return -ENAMETOOLONG;
192+
}
193+
194+
pinned_map_fd = bpf_obj_get(buf);
195+
if (pinned_map_fd < 0)
196+
return pinned_map_fd;
197+
198+
err = bpf_map__reuse_fd(map, pinned_map_fd);
199+
if (err)
200+
return err;
201+
}
202+
203+
return 0;
204+
}
205+
206+
struct bpf_object *load_bpf_object_file_reuse_maps(const char *file,
207+
int ifindex,
208+
const char *pin_dir)
209+
{
210+
int err;
211+
struct bpf_object *obj;
212+
213+
obj = open_bpf_object(file, ifindex);
214+
if (!obj) {
215+
fprintf(stderr, "ERR: failed to open object %s\n", file);
216+
return NULL;
217+
}
218+
219+
err = reuse_maps(obj, pin_dir);
220+
if (err) {
221+
fprintf(stderr, "ERR: failed to reuse maps for object %s, pin_dir=%s\n",
222+
file, pin_dir);
223+
return NULL;
224+
}
225+
226+
err = bpf_object__load(obj);
227+
if (err) {
228+
fprintf(stderr, "ERR: loading BPF-OBJ file(%s) (%d): %s\n",
229+
file, err, strerror(-err));
230+
return NULL;
231+
}
232+
233+
return obj;
234+
}
235+
127236
struct bpf_object *load_bpf_and_xdp_attach(struct config *cfg)
128237
{
129238
struct bpf_program *bpf_prog;
@@ -137,7 +246,12 @@ struct bpf_object *load_bpf_and_xdp_attach(struct config *cfg)
137246
offload_ifindex = cfg->ifindex;
138247

139248
/* Load the BPF-ELF object file and get back libbpf bpf_object */
140-
bpf_obj = load_bpf_object_file(cfg->filename, offload_ifindex);
249+
if (cfg->reuse_maps)
250+
bpf_obj = load_bpf_object_file_reuse_maps(cfg->filename,
251+
offload_ifindex,
252+
cfg->pin_dir);
253+
else
254+
bpf_obj = load_bpf_object_file(cfg->filename, offload_ifindex);
141255
if (!bpf_obj) {
142256
fprintf(stderr, "ERR: loading file: %s\n", cfg->filename);
143257
exit(EXIT_FAIL_BPF);

0 commit comments

Comments
 (0)