-
Notifications
You must be signed in to change notification settings - Fork 595
/
Copy pathxdp_loader.c
163 lines (133 loc) · 4.83 KB
/
xdp_loader.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/* SPDX-License-Identifier: GPL-2.0 */
static const char *__doc__ = "XDP loader\n"
" - Specify BPF-object --filename to load \n"
" - and select BPF program --progname name to XDP-attach to --dev\n";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <xdp/libxdp.h>
#include <net/if.h>
#include <linux/if_link.h> /* depend on kernel-headers installed */
#include "../common/common_params.h"
#include "../common/common_user_bpf_xdp.h"
static const char *default_filename = "xdp_prog_kern.o";
static const char *default_progname = "xdp_pass_func";
static const struct option_wrapper long_options[] = {
{{"help", no_argument, NULL, 'h' },
"Show help", false},
{{"dev", required_argument, NULL, 'd' },
"Operate on device <ifname>", "<ifname>", true},
{{"skb-mode", no_argument, NULL, 'S' },
"Install XDP program in SKB (AKA generic) mode"},
{{"native-mode", no_argument, NULL, 'N' },
"Install XDP program in native mode"},
{{"auto-mode", no_argument, NULL, 'A' },
"Auto-detect SKB or native mode"},
{{"offload-mode",no_argument, NULL, 3 },
"Hardware offload XDP program to NIC"},
{{"unload", required_argument, NULL, 'U' },
"Unload XDP program <id> instead of loading", "<id>"},
{{"unload-all", no_argument, NULL, 4 },
"Unload all XDP programs on device"},
{{"quiet", no_argument, NULL, 'q' },
"Quiet mode (no output)"},
{{"filename", required_argument, NULL, 1 },
"Load program from <file>", "<file>"},
{{"progname", required_argument, NULL, 2 },
"Load program from function <name> in the ELF file", "<name>"},
{{0, 0, NULL, 0 }, NULL, false}
};
static void list_avail_progs(struct bpf_object *obj)
{
struct bpf_program *pos;
printf("BPF object (%s) listing available XDP functions\n",
bpf_object__name(obj));
bpf_object__for_each_program(pos, obj) {
if (bpf_program__type(pos) == BPF_PROG_TYPE_XDP)
printf(" %s\n", bpf_program__name(pos));
}
}
/* Lesson#1: This is a central piece of this lesson:
* - Notice how BPF-ELF obj can have several programs
* - Find by program name via: xdp_program__create
*/
int main(int argc, char **argv)
{
struct config cfg = {
.attach_mode = XDP_MODE_NATIVE,
.ifindex = -1,
.do_unload = false,
};
struct bpf_object *obj;
char errmsg[1024];
int err;
/* Set default BPF-ELF object file and BPF program name */
strncpy(cfg.filename, default_filename, sizeof(cfg.filename));
strncpy(cfg.progname, default_progname, sizeof(cfg.progname));
/* Cmdline options can change these */
parse_cmdline_args(argc, argv, long_options, &cfg, __doc__);
/* Required option */
if (cfg.ifindex == -1) {
fprintf(stderr, "ERR: required option --dev missing\n");
usage(argv[0], __doc__, long_options, (argc == 1));
return EXIT_FAIL_OPTION;
}
/* Unload a program by prog_id, or
* unload all programs on net device
*/
if (cfg.do_unload || cfg.unload_all) {
err = do_unload(&cfg);
if (err) {
libxdp_strerror(err, errmsg, sizeof(errmsg));
fprintf(stderr, "Couldn't unload XDP program %s: %s\n",
cfg.progname, errmsg);
return err;
}
printf("Success: Unloading XDP prog name: %s\n", cfg.progname);
return EXIT_OK;
}
/* Open a BPF object file */
DECLARE_LIBBPF_OPTS(bpf_object_open_opts, bpf_opts);
obj = bpf_object__open_file(cfg.filename, &bpf_opts);
err = libbpf_get_error(obj);
if (err) {
libxdp_strerror(err, errmsg, sizeof(errmsg));
fprintf(stderr, "Couldn't open BPF object file %s: %s\n",
cfg.filename, errmsg);
return err;
}
/* List available programs */
if (verbose)
list_avail_progs(obj);
DECLARE_LIBXDP_OPTS(xdp_program_opts, xdp_opts,
.obj = obj,
.prog_name = cfg.progname);
struct xdp_program *prog = xdp_program__create(&xdp_opts);
err = libxdp_get_error(prog);
if (err) {
libxdp_strerror(err, errmsg, sizeof(errmsg));
fprintf(stderr, "ERR: loading program %s: %s\n", cfg.progname, errmsg);
exit(EXIT_FAIL_BPF);
}
/* At this point: BPF-progs are (only) loaded by the kernel, and prog
* is our selected program handle. Next step is attaching this prog
* to a kernel hook point, in this case XDP net_device link-level hook.
*/
err = xdp_program__attach(prog, cfg.ifindex, cfg.attach_mode, 0);
if (err) {
perror("xdp_program__attach");
exit(err);
}
if (verbose) {
printf("Success: Loaded BPF-object(%s) and used program(%s)\n",
cfg.filename, cfg.progname);
printf(" - XDP prog id:%d attached on device:%s(ifindex:%d)\n",
xdp_program__id(prog), cfg.ifname, cfg.ifindex);
}
/* Other BPF programs from ELF file will get freed on exit */
return EXIT_OK;
}