blob: ac77af58378c89b436aa9d4b12b3a558514166b0 [file] [log] [blame]
Daniel Borkmannd05df682013-10-28 12:35:33 +01001/*
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>
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020017#include <libgen.h>
Daniel Borkmannd05df682013-10-28 12:35:33 +010018#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>
Natanael Copadd9cc0e2014-05-27 07:40:10 +000024#include <limits.h>
Daniel Borkmannd05df682013-10-28 12:35:33 +010025#include <linux/filter.h>
26#include <linux/if.h>
27
28#include "utils.h"
29#include "tc_util.h"
Jiri Pirko1d129d12015-01-19 16:56:29 +010030#include "tc_bpf.h"
Daniel Borkmannd05df682013-10-28 12:35:33 +010031
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020032static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_CLS;
33
Daniel Borkmannd05df682013-10-28 12:35:33 +010034static void explain(void)
35{
36 fprintf(stderr, "Usage: ... bpf ...\n");
37 fprintf(stderr, "\n");
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020038 fprintf(stderr, "BPF use case:\n");
39 fprintf(stderr, " bytecode BPF_BYTECODE\n");
40 fprintf(stderr, " bytecode-file FILE\n");
Daniel Borkmannd05df682013-10-28 12:35:33 +010041 fprintf(stderr, "\n");
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020042 fprintf(stderr, "eBPF use case:\n");
Daniel Borkmannd937a742015-04-28 13:37:42 +020043 fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]");
Daniel Borkmannfaa8a462015-09-25 12:32:41 +020044 fprintf(stderr, " [ verbose ] [ direct-action ]\n");
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020045 fprintf(stderr, "\n");
46 fprintf(stderr, "Common remaining options:\n");
47 fprintf(stderr, " [ action ACTION_SPEC ]\n");
48 fprintf(stderr, " [ classid CLASSID ]\n");
Daniel Borkmannd05df682013-10-28 12:35:33 +010049 fprintf(stderr, "\n");
50 fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020051 fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
52 fprintf(stderr, "\n");
Daniel Borkmann11c39b52015-03-16 19:37:41 +010053 fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string,\n");
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020054 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");
Jamal Hadi Salim863ecb02014-10-06 07:41:21 -040063 fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
Daniel Borkmannd05df682013-10-28 12:35:33 +010064}
65
Daniel Borkmannd05df682013-10-28 12:35:33 +010066static 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);
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020070 const char *bpf_uds_name = NULL;
71 const char *bpf_sec_name = NULL;
Daniel Borkmannfaa8a462015-09-25 12:32:41 +020072 unsigned int bpf_flags = 0;
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020073 char *bpf_obj = NULL;
Daniel Borkmannd05df682013-10-28 12:35:33 +010074 struct rtattr *tail;
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020075 bool seen_run = false;
Daniel Borkmannd05df682013-10-28 12:35:33 +010076 long h = 0;
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020077 int ret = 0;
Daniel Borkmannd05df682013-10-28 12:35:33 +010078
79 if (argc == 0)
80 return 0;
81
82 if (handle) {
83 h = strtol(handle, NULL, 0);
84 if (h == LONG_MIN || h == LONG_MAX) {
85 fprintf(stderr, "Illegal handle \"%s\", must be "
86 "numeric.\n", handle);
87 return -1;
88 }
89 }
90
91 t->tcm_handle = h;
92
Daniel Borkmann6256f8c2015-04-01 17:57:44 +020093 tail = (struct rtattr *)(((void *)n) + NLMSG_ALIGN(n->nlmsg_len));
Daniel Borkmannd05df682013-10-28 12:35:33 +010094 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
95
96 while (argc > 0) {
97 if (matches(*argv, "run") == 0) {
Jiri Pirko1d129d12015-01-19 16:56:29 +010098 struct sock_filter bpf_ops[BPF_MAXINSNS];
Daniel Borkmannd937a742015-04-28 13:37:42 +020099 bool from_file, ebpf, bpf_verbose;
Jiri Pirko1d129d12015-01-19 16:56:29 +0100100 int ret;
101
Daniel Borkmannd05df682013-10-28 12:35:33 +0100102 NEXT_ARG();
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200103opt_bpf:
104 bpf_sec_name = bpf_default_section(bpf_type);
Daniel Borkmannd937a742015-04-28 13:37:42 +0200105 bpf_verbose = false;
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200106 ebpf = false;
107 seen_run = true;
108
109 if (strcmp(*argv, "bytecode-file") == 0 ||
110 strcmp(*argv, "bcf") == 0) {
111 from_file = true;
112 } else if (strcmp(*argv, "bytecode") == 0 ||
113 strcmp(*argv, "bc") == 0) {
Daniel Borkmannd05df682013-10-28 12:35:33 +0100114 from_file = false;
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200115 } else if (strcmp(*argv, "object-file") == 0 ||
116 strcmp(*argv, "obj") == 0) {
Daniel Borkmann11c39b52015-03-16 19:37:41 +0100117 ebpf = true;
Daniel Borkmannd05df682013-10-28 12:35:33 +0100118 } else {
119 fprintf(stderr, "What is \"%s\"?\n", *argv);
120 explain();
121 return -1;
122 }
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200123
Daniel Borkmannd05df682013-10-28 12:35:33 +0100124 NEXT_ARG();
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200125 if (ebpf) {
Nicolas Dichtel611f70b2015-07-23 09:17:41 +0200126 bpf_uds_name = getenv(BPF_ENV_UDS);
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200127 bpf_obj = *argv;
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200128
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200129 NEXT_ARG_FWD();
130
131 if (argc > 0 &&
132 (strcmp(*argv, "section") == 0 ||
133 strcmp(*argv, "sec") == 0)) {
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200134 NEXT_ARG();
135 bpf_sec_name = *argv;
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200136 NEXT_ARG_FWD();
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200137 }
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200138 if (argc > 0 && !bpf_uds_name &&
Daniel Borkmann88eea532015-06-02 23:35:34 +0200139 (strcmp(*argv, "export") == 0 ||
140 strcmp(*argv, "exp") == 0)) {
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200141 NEXT_ARG();
142 bpf_uds_name = *argv;
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200143 NEXT_ARG_FWD();
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200144 }
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200145 if (argc > 0 &&
146 (strcmp(*argv, "verbose") == 0 ||
147 strcmp(*argv, "verb") == 0)) {
Daniel Borkmannd937a742015-04-28 13:37:42 +0200148 bpf_verbose = true;
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200149 NEXT_ARG_FWD();
Daniel Borkmannd937a742015-04-28 13:37:42 +0200150 }
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200151
152 PREV_ARG();
153 }
154
Daniel Borkmannd937a742015-04-28 13:37:42 +0200155 ret = ebpf ? bpf_open_object(bpf_obj, bpf_type, bpf_sec_name,
156 bpf_verbose) :
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200157 bpf_parse_ops(argc, argv, bpf_ops, from_file);
Jiri Pirko1d129d12015-01-19 16:56:29 +0100158 if (ret < 0) {
Daniel Borkmann11c39b52015-03-16 19:37:41 +0100159 fprintf(stderr, "%s\n", ebpf ?
160 "Could not load object" :
161 "Illegal \"bytecode\"");
Daniel Borkmannd05df682013-10-28 12:35:33 +0100162 return -1;
163 }
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200164
Daniel Borkmann11c39b52015-03-16 19:37:41 +0100165 if (ebpf) {
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200166 char bpf_name[256];
167
168 bpf_obj = basename(bpf_obj);
169
170 snprintf(bpf_name, sizeof(bpf_name), "%s:[%s]",
171 bpf_obj, bpf_sec_name);
172
Daniel Borkmann11c39b52015-03-16 19:37:41 +0100173 addattr32(n, MAX_MSG, TCA_BPF_FD, ret);
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200174 addattrstrz(n, MAX_MSG, TCA_BPF_NAME, bpf_name);
Daniel Borkmann11c39b52015-03-16 19:37:41 +0100175 } else {
176 addattr16(n, MAX_MSG, TCA_BPF_OPS_LEN, ret);
177 addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
178 ret * sizeof(struct sock_filter));
179 }
Daniel Borkmannd05df682013-10-28 12:35:33 +0100180 } else if (matches(*argv, "classid") == 0 ||
181 strcmp(*argv, "flowid") == 0) {
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200182 unsigned int handle;
183
Daniel Borkmannd05df682013-10-28 12:35:33 +0100184 NEXT_ARG();
185 if (get_tc_classid(&handle, *argv)) {
186 fprintf(stderr, "Illegal \"classid\"\n");
187 return -1;
188 }
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200189 addattr32(n, MAX_MSG, TCA_BPF_CLASSID, handle);
190 } else if (matches(*argv, "direct-action") == 0 ||
191 matches(*argv, "da") == 0) {
192 bpf_flags |= TCA_BPF_FLAG_ACT_DIRECT;
Daniel Borkmannd05df682013-10-28 12:35:33 +0100193 } else if (matches(*argv, "action") == 0) {
194 NEXT_ARG();
195 if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) {
196 fprintf(stderr, "Illegal \"action\"\n");
197 return -1;
198 }
199 continue;
200 } else if (matches(*argv, "police") == 0) {
201 NEXT_ARG();
202 if (parse_police(&argc, &argv, TCA_BPF_POLICE, n)) {
203 fprintf(stderr, "Illegal \"police\"\n");
204 return -1;
205 }
206 continue;
207 } else if (strcmp(*argv, "help") == 0) {
208 explain();
209 return -1;
210 } else {
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200211 if (!seen_run)
212 goto opt_bpf;
213
Daniel Borkmannd05df682013-10-28 12:35:33 +0100214 fprintf(stderr, "What is \"%s\"?\n", *argv);
215 explain();
216 return -1;
217 }
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200218
219 NEXT_ARG_FWD();
Daniel Borkmannd05df682013-10-28 12:35:33 +0100220 }
221
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200222 if (bpf_obj && bpf_flags)
223 addattr32(n, MAX_MSG, TCA_BPF_FLAGS, bpf_flags);
224
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200225 tail->rta_len = (((void *)n) + n->nlmsg_len) - (void *)tail;
226
227 if (bpf_uds_name)
Daniel Borkmann4bd62442015-04-16 21:20:06 +0200228 ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200229
230 return ret;
Daniel Borkmannd05df682013-10-28 12:35:33 +0100231}
232
233static int bpf_print_opt(struct filter_util *qu, FILE *f,
234 struct rtattr *opt, __u32 handle)
235{
236 struct rtattr *tb[TCA_BPF_MAX + 1];
237
238 if (opt == NULL)
239 return 0;
240
241 parse_rtattr_nested(tb, TCA_BPF_MAX, opt);
242
243 if (handle)
244 fprintf(f, "handle 0x%x ", handle);
245
246 if (tb[TCA_BPF_CLASSID]) {
247 SPRINT_BUF(b1);
248 fprintf(f, "flowid %s ",
249 sprint_tc_classid(rta_getattr_u32(tb[TCA_BPF_CLASSID]), b1));
250 }
251
Daniel Borkmann11c39b52015-03-16 19:37:41 +0100252 if (tb[TCA_BPF_NAME])
253 fprintf(f, "%s ", rta_getattr_str(tb[TCA_BPF_NAME]));
254 else if (tb[TCA_BPF_FD])
255 fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_BPF_FD]));
256
Daniel Borkmannfaa8a462015-09-25 12:32:41 +0200257 if (tb[TCA_BPF_FLAGS]) {
258 unsigned int flags = rta_getattr_u32(tb[TCA_BPF_FLAGS]);
259
260 if (flags & TCA_BPF_FLAG_ACT_DIRECT)
261 fprintf(f, "direct-action ");
262 }
263
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200264 if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN]) {
Daniel Borkmannd05df682013-10-28 12:35:33 +0100265 bpf_print_ops(f, tb[TCA_BPF_OPS],
266 rta_getattr_u16(tb[TCA_BPF_OPS_LEN]));
Daniel Borkmann6256f8c2015-04-01 17:57:44 +0200267 fprintf(f, "\n");
268 }
Daniel Borkmannd05df682013-10-28 12:35:33 +0100269
270 if (tb[TCA_BPF_POLICE]) {
271 fprintf(f, "\n");
272 tc_print_police(f, tb[TCA_BPF_POLICE]);
273 }
274
275 if (tb[TCA_BPF_ACT]) {
276 tc_print_action(f, tb[TCA_BPF_ACT]);
277 }
278
279 return 0;
280}
281
282struct filter_util bpf_filter_util = {
283 .id = "bpf",
284 .parse_fopt = bpf_parse_opt,
285 .print_fopt = bpf_print_opt,
286};