]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/f_bpf.c
ip neigh: Add support for filtering dumps by master device
[mirror_iproute2.git] / tc / f_bpf.c
CommitLineData
d05df686
DB
1/*
2 * f_bpf.c BPF-based Classifier
3 *
4 * This program is free software; you can distribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Daniel Borkmann <dborkman@redhat.com>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <syslog.h>
16#include <fcntl.h>
6256f8c9 17#include <libgen.h>
d05df686
DB
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <arpa/inet.h>
21#include <string.h>
22#include <stdbool.h>
23#include <errno.h>
dd9cc0ee 24#include <limits.h>
d05df686
DB
25#include <linux/filter.h>
26#include <linux/if.h>
27
28#include "utils.h"
29#include "tc_util.h"
1d129d19 30#include "tc_bpf.h"
d05df686 31
6256f8c9
DB
32static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_CLS;
33
d05df686
DB
34static void explain(void)
35{
36 fprintf(stderr, "Usage: ... bpf ...\n");
37 fprintf(stderr, "\n");
6256f8c9
DB
38 fprintf(stderr, "BPF use case:\n");
39 fprintf(stderr, " bytecode BPF_BYTECODE\n");
40 fprintf(stderr, " bytecode-file FILE\n");
41 fprintf(stderr, "\n");
42 fprintf(stderr, "eBPF use case:\n");
d937a74b
DB
43 fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]");
44 fprintf(stderr, " [ verbose ]\n");
d05df686 45 fprintf(stderr, "\n");
6256f8c9
DB
46 fprintf(stderr, "Common remaining options:\n");
47 fprintf(stderr, " [ action ACTION_SPEC ]\n");
48 fprintf(stderr, " [ classid CLASSID ]\n");
d05df686
DB
49 fprintf(stderr, "\n");
50 fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
6256f8c9
DB
51 fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
52 fprintf(stderr, "\n");
11c39b5e 53 fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string,\n");
6256f8c9
DB
54 fprintf(stderr, "an ELF file containing eBPF map definitions and bytecode.\n");
55 fprintf(stderr, "\n");
56 fprintf(stderr, "Where CLS_NAME refers to the section name containing the\n");
57 fprintf(stderr, "classifier (default \'%s\').\n", bpf_default_section(bpf_type));
58 fprintf(stderr, "\n");
59 fprintf(stderr, "Where UDS_FILE points to a unix domain socket file in order\n");
60 fprintf(stderr, "to hand off control of all created eBPF maps to an agent.\n");
61 fprintf(stderr, "\n");
62 fprintf(stderr, "ACTION_SPEC := ... look at individual actions\n");
863ecb04 63 fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
d05df686
DB
64}
65
d05df686
DB
66static int bpf_parse_opt(struct filter_util *qu, char *handle,
67 int argc, char **argv, struct nlmsghdr *n)
68{
69 struct tcmsg *t = NLMSG_DATA(n);
6256f8c9
DB
70 const char *bpf_uds_name = NULL;
71 const char *bpf_sec_name = NULL;
72 char *bpf_obj = NULL;
d05df686 73 struct rtattr *tail;
6256f8c9 74 bool seen_run = false;
d05df686 75 long h = 0;
6256f8c9 76 int ret = 0;
d05df686
DB
77
78 if (argc == 0)
79 return 0;
80
81 if (handle) {
82 h = strtol(handle, NULL, 0);
83 if (h == LONG_MIN || h == LONG_MAX) {
84 fprintf(stderr, "Illegal handle \"%s\", must be "
85 "numeric.\n", handle);
86 return -1;
87 }
88 }
89
90 t->tcm_handle = h;
91
6256f8c9 92 tail = (struct rtattr *)(((void *)n) + NLMSG_ALIGN(n->nlmsg_len));
d05df686
DB
93 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
94
95 while (argc > 0) {
96 if (matches(*argv, "run") == 0) {
1d129d19 97 struct sock_filter bpf_ops[BPF_MAXINSNS];
d937a74b 98 bool from_file, ebpf, bpf_verbose;
1d129d19
JP
99 int ret;
100
d05df686 101 NEXT_ARG();
6256f8c9
DB
102opt_bpf:
103 bpf_sec_name = bpf_default_section(bpf_type);
d937a74b 104 bpf_verbose = false;
6256f8c9
DB
105 ebpf = false;
106 seen_run = true;
107
108 if (strcmp(*argv, "bytecode-file") == 0 ||
109 strcmp(*argv, "bcf") == 0) {
110 from_file = true;
111 } else if (strcmp(*argv, "bytecode") == 0 ||
112 strcmp(*argv, "bc") == 0) {
d05df686 113 from_file = false;
6256f8c9
DB
114 } else if (strcmp(*argv, "object-file") == 0 ||
115 strcmp(*argv, "obj") == 0) {
11c39b5e 116 ebpf = true;
d05df686
DB
117 } else {
118 fprintf(stderr, "What is \"%s\"?\n", *argv);
119 explain();
120 return -1;
121 }
6256f8c9 122
d05df686 123 NEXT_ARG();
6256f8c9 124 if (ebpf) {
611f70b2 125 bpf_uds_name = getenv(BPF_ENV_UDS);
6256f8c9
DB
126 bpf_obj = *argv;
127 NEXT_ARG();
128
129 if (strcmp(*argv, "section") == 0 ||
130 strcmp(*argv, "sec") == 0) {
131 NEXT_ARG();
132 bpf_sec_name = *argv;
133 NEXT_ARG();
134 }
88eea539
DB
135 if (!bpf_uds_name &&
136 (strcmp(*argv, "export") == 0 ||
137 strcmp(*argv, "exp") == 0)) {
6256f8c9
DB
138 NEXT_ARG();
139 bpf_uds_name = *argv;
140 NEXT_ARG();
141 }
d937a74b
DB
142 if (strcmp(*argv, "verbose") == 0 ||
143 strcmp(*argv, "verb") == 0) {
144 bpf_verbose = true;
145 NEXT_ARG();
146 }
6256f8c9
DB
147
148 PREV_ARG();
149 }
150
d937a74b
DB
151 ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name,
152 bpf_verbose) :
6256f8c9 153 bpf_parse_ops(argc, argv, bpf_ops, from_file);
1d129d19 154 if (ret < 0) {
11c39b5e
DB
155 fprintf(stderr, "%s\n", ebpf ?
156 "Could not load object" :
157 "Illegal \"bytecode\"");
d05df686
DB
158 return -1;
159 }
6256f8c9 160
11c39b5e 161 if (ebpf) {
6256f8c9
DB
162 char bpf_name[256];
163
164 bpf_obj = basename(bpf_obj);
165
166 snprintf(bpf_name, sizeof(bpf_name), "%s:[%s]",
167 bpf_obj, bpf_sec_name);
168
11c39b5e 169 addattr32(n, MAX_MSG, TCA_BPF_FD, ret);
6256f8c9 170 addattrstrz(n, MAX_MSG, TCA_BPF_NAME, bpf_name);
11c39b5e
DB
171 } else {
172 addattr16(n, MAX_MSG, TCA_BPF_OPS_LEN, ret);
173 addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
174 ret * sizeof(struct sock_filter));
175 }
d05df686
DB
176 } else if (matches(*argv, "classid") == 0 ||
177 strcmp(*argv, "flowid") == 0) {
6256f8c9
DB
178 unsigned int handle;
179
d05df686
DB
180 NEXT_ARG();
181 if (get_tc_classid(&handle, *argv)) {
182 fprintf(stderr, "Illegal \"classid\"\n");
183 return -1;
184 }
185 addattr_l(n, MAX_MSG, TCA_BPF_CLASSID, &handle, 4);
186 } else if (matches(*argv, "action") == 0) {
187 NEXT_ARG();
188 if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) {
189 fprintf(stderr, "Illegal \"action\"\n");
190 return -1;
191 }
192 continue;
193 } else if (matches(*argv, "police") == 0) {
194 NEXT_ARG();
195 if (parse_police(&argc, &argv, TCA_BPF_POLICE, n)) {
196 fprintf(stderr, "Illegal \"police\"\n");
197 return -1;
198 }
199 continue;
200 } else if (strcmp(*argv, "help") == 0) {
201 explain();
202 return -1;
203 } else {
6256f8c9
DB
204 if (!seen_run)
205 goto opt_bpf;
206
d05df686
DB
207 fprintf(stderr, "What is \"%s\"?\n", *argv);
208 explain();
209 return -1;
210 }
6256f8c9
DB
211 argc--;
212 argv++;
d05df686
DB
213 }
214
6256f8c9
DB
215 tail->rta_len = (((void *)n) + n->nlmsg_len) - (void *)tail;
216
217 if (bpf_uds_name)
4bd62446 218 ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
6256f8c9
DB
219
220 return ret;
d05df686
DB
221}
222
223static int bpf_print_opt(struct filter_util *qu, FILE *f,
224 struct rtattr *opt, __u32 handle)
225{
226 struct rtattr *tb[TCA_BPF_MAX + 1];
227
228 if (opt == NULL)
229 return 0;
230
231 parse_rtattr_nested(tb, TCA_BPF_MAX, opt);
232
233 if (handle)
234 fprintf(f, "handle 0x%x ", handle);
235
236 if (tb[TCA_BPF_CLASSID]) {
237 SPRINT_BUF(b1);
238 fprintf(f, "flowid %s ",
239 sprint_tc_classid(rta_getattr_u32(tb[TCA_BPF_CLASSID]), b1));
240 }
241
11c39b5e
DB
242 if (tb[TCA_BPF_NAME])
243 fprintf(f, "%s ", rta_getattr_str(tb[TCA_BPF_NAME]));
244 else if (tb[TCA_BPF_FD])
245 fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_BPF_FD]));
246
6256f8c9 247 if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN]) {
d05df686
DB
248 bpf_print_ops(f, tb[TCA_BPF_OPS],
249 rta_getattr_u16(tb[TCA_BPF_OPS_LEN]));
6256f8c9
DB
250 fprintf(f, "\n");
251 }
d05df686
DB
252
253 if (tb[TCA_BPF_POLICE]) {
254 fprintf(f, "\n");
255 tc_print_police(f, tb[TCA_BPF_POLICE]);
256 }
257
258 if (tb[TCA_BPF_ACT]) {
259 tc_print_action(f, tb[TCA_BPF_ACT]);
260 }
261
262 return 0;
263}
264
265struct filter_util bpf_filter_util = {
266 .id = "bpf",
267 .parse_fopt = bpf_parse_opt,
268 .print_fopt = bpf_print_opt,
269};