1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * f_bpf.c BPF-based Classifier
3*de1e4e89SAndroid Build Coastguard Worker *
4*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can distribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker * 2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker *
9*de1e4e89SAndroid Build Coastguard Worker * Authors: Daniel Borkmann <[email protected]>
10*de1e4e89SAndroid Build Coastguard Worker */
11*de1e4e89SAndroid Build Coastguard Worker
12*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
14*de1e4e89SAndroid Build Coastguard Worker
15*de1e4e89SAndroid Build Coastguard Worker #include <linux/bpf.h>
16*de1e4e89SAndroid Build Coastguard Worker
17*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
18*de1e4e89SAndroid Build Coastguard Worker
19*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
20*de1e4e89SAndroid Build Coastguard Worker #include "bpf_util.h"
21*de1e4e89SAndroid Build Coastguard Worker
22*de1e4e89SAndroid Build Coastguard Worker static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_CLS;
23*de1e4e89SAndroid Build Coastguard Worker
explain(void)24*de1e4e89SAndroid Build Coastguard Worker static void explain(void)
25*de1e4e89SAndroid Build Coastguard Worker {
26*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Usage: ... bpf ...\n");
27*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
28*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "BPF use case:\n");
29*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " bytecode BPF_BYTECODE\n");
30*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " bytecode-file FILE\n");
31*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
32*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "eBPF use case:\n");
33*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]");
34*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " [ verbose ] [ direct-action ] [ skip_hw | skip_sw ]\n");
35*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " object-pinned FILE [ direct-action ] [ skip_hw | skip_sw ]\n");
36*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
37*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Common remaining options:\n");
38*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " [ action ACTION_SPEC ]\n");
39*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " [ classid CLASSID ]\n");
40*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
41*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
42*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
43*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
44*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string,\n");
45*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "an ELF file containing eBPF map definitions and bytecode, or a\n");
46*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "pinned eBPF program.\n");
47*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
48*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Where CLS_NAME refers to the section name containing the\n");
49*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "classifier (default \'%s\').\n", bpf_prog_to_default_section(bpf_type));
50*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
51*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Where UDS_FILE points to a unix domain socket file in order\n");
52*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "to hand off control of all created eBPF maps to an agent.\n");
53*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\n");
54*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "ACTION_SPEC := ... look at individual actions\n");
55*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
56*de1e4e89SAndroid Build Coastguard Worker }
57*de1e4e89SAndroid Build Coastguard Worker
bpf_cbpf_cb(void * nl,const struct sock_filter * ops,int ops_len)58*de1e4e89SAndroid Build Coastguard Worker static void bpf_cbpf_cb(void *nl, const struct sock_filter *ops, int ops_len)
59*de1e4e89SAndroid Build Coastguard Worker {
60*de1e4e89SAndroid Build Coastguard Worker addattr16(nl, MAX_MSG, TCA_BPF_OPS_LEN, ops_len);
61*de1e4e89SAndroid Build Coastguard Worker addattr_l(nl, MAX_MSG, TCA_BPF_OPS, ops,
62*de1e4e89SAndroid Build Coastguard Worker ops_len * sizeof(struct sock_filter));
63*de1e4e89SAndroid Build Coastguard Worker }
64*de1e4e89SAndroid Build Coastguard Worker
bpf_ebpf_cb(void * nl,int fd,const char * annotation)65*de1e4e89SAndroid Build Coastguard Worker static void bpf_ebpf_cb(void *nl, int fd, const char *annotation)
66*de1e4e89SAndroid Build Coastguard Worker {
67*de1e4e89SAndroid Build Coastguard Worker addattr32(nl, MAX_MSG, TCA_BPF_FD, fd);
68*de1e4e89SAndroid Build Coastguard Worker addattrstrz(nl, MAX_MSG, TCA_BPF_NAME, annotation);
69*de1e4e89SAndroid Build Coastguard Worker }
70*de1e4e89SAndroid Build Coastguard Worker
71*de1e4e89SAndroid Build Coastguard Worker static const struct bpf_cfg_ops bpf_cb_ops = {
72*de1e4e89SAndroid Build Coastguard Worker .cbpf_cb = bpf_cbpf_cb,
73*de1e4e89SAndroid Build Coastguard Worker .ebpf_cb = bpf_ebpf_cb,
74*de1e4e89SAndroid Build Coastguard Worker };
75*de1e4e89SAndroid Build Coastguard Worker
bpf_parse_opt(struct filter_util * qu,char * handle,int argc,char ** argv,struct nlmsghdr * n)76*de1e4e89SAndroid Build Coastguard Worker static int bpf_parse_opt(struct filter_util *qu, char *handle,
77*de1e4e89SAndroid Build Coastguard Worker int argc, char **argv, struct nlmsghdr *n)
78*de1e4e89SAndroid Build Coastguard Worker {
79*de1e4e89SAndroid Build Coastguard Worker const char *bpf_obj = NULL, *bpf_uds_name = NULL;
80*de1e4e89SAndroid Build Coastguard Worker struct tcmsg *t = NLMSG_DATA(n);
81*de1e4e89SAndroid Build Coastguard Worker unsigned int bpf_gen_flags = 0;
82*de1e4e89SAndroid Build Coastguard Worker unsigned int bpf_flags = 0;
83*de1e4e89SAndroid Build Coastguard Worker struct bpf_cfg_in cfg = {};
84*de1e4e89SAndroid Build Coastguard Worker bool seen_run = false;
85*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tail;
86*de1e4e89SAndroid Build Coastguard Worker int ret = 0;
87*de1e4e89SAndroid Build Coastguard Worker
88*de1e4e89SAndroid Build Coastguard Worker if (handle) {
89*de1e4e89SAndroid Build Coastguard Worker if (get_u32(&t->tcm_handle, handle, 0)) {
90*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"handle\"\n");
91*de1e4e89SAndroid Build Coastguard Worker return -1;
92*de1e4e89SAndroid Build Coastguard Worker }
93*de1e4e89SAndroid Build Coastguard Worker }
94*de1e4e89SAndroid Build Coastguard Worker
95*de1e4e89SAndroid Build Coastguard Worker if (argc == 0)
96*de1e4e89SAndroid Build Coastguard Worker return 0;
97*de1e4e89SAndroid Build Coastguard Worker
98*de1e4e89SAndroid Build Coastguard Worker tail = (struct rtattr *)(((void *)n) + NLMSG_ALIGN(n->nlmsg_len));
99*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
100*de1e4e89SAndroid Build Coastguard Worker
101*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
102*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "run") == 0) {
103*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
104*de1e4e89SAndroid Build Coastguard Worker opt_bpf:
105*de1e4e89SAndroid Build Coastguard Worker seen_run = true;
106*de1e4e89SAndroid Build Coastguard Worker cfg.argc = argc;
107*de1e4e89SAndroid Build Coastguard Worker cfg.argv = argv;
108*de1e4e89SAndroid Build Coastguard Worker
109*de1e4e89SAndroid Build Coastguard Worker if (bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, n))
110*de1e4e89SAndroid Build Coastguard Worker return -1;
111*de1e4e89SAndroid Build Coastguard Worker
112*de1e4e89SAndroid Build Coastguard Worker argc = cfg.argc;
113*de1e4e89SAndroid Build Coastguard Worker argv = cfg.argv;
114*de1e4e89SAndroid Build Coastguard Worker
115*de1e4e89SAndroid Build Coastguard Worker bpf_obj = cfg.object;
116*de1e4e89SAndroid Build Coastguard Worker bpf_uds_name = cfg.uds;
117*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "classid") == 0 ||
118*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "flowid") == 0) {
119*de1e4e89SAndroid Build Coastguard Worker unsigned int handle;
120*de1e4e89SAndroid Build Coastguard Worker
121*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
122*de1e4e89SAndroid Build Coastguard Worker if (get_tc_classid(&handle, *argv)) {
123*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"classid\"\n");
124*de1e4e89SAndroid Build Coastguard Worker return -1;
125*de1e4e89SAndroid Build Coastguard Worker }
126*de1e4e89SAndroid Build Coastguard Worker addattr32(n, MAX_MSG, TCA_BPF_CLASSID, handle);
127*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "direct-action") == 0 ||
128*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "da") == 0) {
129*de1e4e89SAndroid Build Coastguard Worker bpf_flags |= TCA_BPF_FLAG_ACT_DIRECT;
130*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "skip_hw") == 0) {
131*de1e4e89SAndroid Build Coastguard Worker bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_HW;
132*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "skip_sw") == 0) {
133*de1e4e89SAndroid Build Coastguard Worker bpf_gen_flags |= TCA_CLS_FLAGS_SKIP_SW;
134*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "action") == 0) {
135*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
136*de1e4e89SAndroid Build Coastguard Worker if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) {
137*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"action\"\n");
138*de1e4e89SAndroid Build Coastguard Worker return -1;
139*de1e4e89SAndroid Build Coastguard Worker }
140*de1e4e89SAndroid Build Coastguard Worker continue;
141*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "police") == 0) {
142*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
143*de1e4e89SAndroid Build Coastguard Worker if (parse_police(&argc, &argv, TCA_BPF_POLICE, n)) {
144*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"police\"\n");
145*de1e4e89SAndroid Build Coastguard Worker return -1;
146*de1e4e89SAndroid Build Coastguard Worker }
147*de1e4e89SAndroid Build Coastguard Worker continue;
148*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "help") == 0) {
149*de1e4e89SAndroid Build Coastguard Worker explain();
150*de1e4e89SAndroid Build Coastguard Worker return -1;
151*de1e4e89SAndroid Build Coastguard Worker } else {
152*de1e4e89SAndroid Build Coastguard Worker if (!seen_run)
153*de1e4e89SAndroid Build Coastguard Worker goto opt_bpf;
154*de1e4e89SAndroid Build Coastguard Worker
155*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "What is \"%s\"?\n", *argv);
156*de1e4e89SAndroid Build Coastguard Worker explain();
157*de1e4e89SAndroid Build Coastguard Worker return -1;
158*de1e4e89SAndroid Build Coastguard Worker }
159*de1e4e89SAndroid Build Coastguard Worker
160*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG_FWD();
161*de1e4e89SAndroid Build Coastguard Worker }
162*de1e4e89SAndroid Build Coastguard Worker
163*de1e4e89SAndroid Build Coastguard Worker if (bpf_gen_flags)
164*de1e4e89SAndroid Build Coastguard Worker addattr32(n, MAX_MSG, TCA_BPF_FLAGS_GEN, bpf_gen_flags);
165*de1e4e89SAndroid Build Coastguard Worker if (bpf_flags)
166*de1e4e89SAndroid Build Coastguard Worker addattr32(n, MAX_MSG, TCA_BPF_FLAGS, bpf_flags);
167*de1e4e89SAndroid Build Coastguard Worker
168*de1e4e89SAndroid Build Coastguard Worker tail->rta_len = (((void *)n) + n->nlmsg_len) - (void *)tail;
169*de1e4e89SAndroid Build Coastguard Worker
170*de1e4e89SAndroid Build Coastguard Worker if (bpf_uds_name)
171*de1e4e89SAndroid Build Coastguard Worker ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
172*de1e4e89SAndroid Build Coastguard Worker
173*de1e4e89SAndroid Build Coastguard Worker return ret;
174*de1e4e89SAndroid Build Coastguard Worker }
175*de1e4e89SAndroid Build Coastguard Worker
bpf_print_opt(struct filter_util * qu,FILE * f,struct rtattr * opt,__u32 handle)176*de1e4e89SAndroid Build Coastguard Worker static int bpf_print_opt(struct filter_util *qu, FILE *f,
177*de1e4e89SAndroid Build Coastguard Worker struct rtattr *opt, __u32 handle)
178*de1e4e89SAndroid Build Coastguard Worker {
179*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[TCA_BPF_MAX + 1];
180*de1e4e89SAndroid Build Coastguard Worker int dump_ok = 0;
181*de1e4e89SAndroid Build Coastguard Worker
182*de1e4e89SAndroid Build Coastguard Worker if (opt == NULL)
183*de1e4e89SAndroid Build Coastguard Worker return 0;
184*de1e4e89SAndroid Build Coastguard Worker
185*de1e4e89SAndroid Build Coastguard Worker parse_rtattr_nested(tb, TCA_BPF_MAX, opt);
186*de1e4e89SAndroid Build Coastguard Worker
187*de1e4e89SAndroid Build Coastguard Worker if (handle)
188*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "handle 0x%x ", handle);
189*de1e4e89SAndroid Build Coastguard Worker
190*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_BPF_CLASSID]) {
191*de1e4e89SAndroid Build Coastguard Worker SPRINT_BUF(b1);
192*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "flowid %s ",
193*de1e4e89SAndroid Build Coastguard Worker sprint_tc_classid(rta_getattr_u32(tb[TCA_BPF_CLASSID]), b1));
194*de1e4e89SAndroid Build Coastguard Worker }
195*de1e4e89SAndroid Build Coastguard Worker
196*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_BPF_NAME])
197*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "%s ", rta_getattr_str(tb[TCA_BPF_NAME]));
198*de1e4e89SAndroid Build Coastguard Worker
199*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_BPF_FLAGS]) {
200*de1e4e89SAndroid Build Coastguard Worker unsigned int flags = rta_getattr_u32(tb[TCA_BPF_FLAGS]);
201*de1e4e89SAndroid Build Coastguard Worker
202*de1e4e89SAndroid Build Coastguard Worker if (flags & TCA_BPF_FLAG_ACT_DIRECT)
203*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "direct-action ");
204*de1e4e89SAndroid Build Coastguard Worker }
205*de1e4e89SAndroid Build Coastguard Worker
206*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_BPF_FLAGS_GEN]) {
207*de1e4e89SAndroid Build Coastguard Worker unsigned int flags =
208*de1e4e89SAndroid Build Coastguard Worker rta_getattr_u32(tb[TCA_BPF_FLAGS_GEN]);
209*de1e4e89SAndroid Build Coastguard Worker
210*de1e4e89SAndroid Build Coastguard Worker if (flags & TCA_CLS_FLAGS_SKIP_HW)
211*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "skip_hw ");
212*de1e4e89SAndroid Build Coastguard Worker if (flags & TCA_CLS_FLAGS_SKIP_SW)
213*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "skip_sw ");
214*de1e4e89SAndroid Build Coastguard Worker
215*de1e4e89SAndroid Build Coastguard Worker if (flags & TCA_CLS_FLAGS_IN_HW)
216*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "in_hw ");
217*de1e4e89SAndroid Build Coastguard Worker else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
218*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "not_in_hw ");
219*de1e4e89SAndroid Build Coastguard Worker }
220*de1e4e89SAndroid Build Coastguard Worker
221*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN])
222*de1e4e89SAndroid Build Coastguard Worker bpf_print_ops(f, tb[TCA_BPF_OPS],
223*de1e4e89SAndroid Build Coastguard Worker rta_getattr_u16(tb[TCA_BPF_OPS_LEN]));
224*de1e4e89SAndroid Build Coastguard Worker
225*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_BPF_ID])
226*de1e4e89SAndroid Build Coastguard Worker dump_ok = bpf_dump_prog_info(f, rta_getattr_u32(tb[TCA_BPF_ID]));
227*de1e4e89SAndroid Build Coastguard Worker if (!dump_ok && tb[TCA_BPF_TAG]) {
228*de1e4e89SAndroid Build Coastguard Worker SPRINT_BUF(b);
229*de1e4e89SAndroid Build Coastguard Worker
230*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "tag %s ",
231*de1e4e89SAndroid Build Coastguard Worker hexstring_n2a(RTA_DATA(tb[TCA_BPF_TAG]),
232*de1e4e89SAndroid Build Coastguard Worker RTA_PAYLOAD(tb[TCA_BPF_TAG]),
233*de1e4e89SAndroid Build Coastguard Worker b, sizeof(b)));
234*de1e4e89SAndroid Build Coastguard Worker }
235*de1e4e89SAndroid Build Coastguard Worker
236*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_BPF_POLICE]) {
237*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n");
238*de1e4e89SAndroid Build Coastguard Worker tc_print_police(f, tb[TCA_BPF_POLICE]);
239*de1e4e89SAndroid Build Coastguard Worker }
240*de1e4e89SAndroid Build Coastguard Worker
241*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_BPF_ACT])
242*de1e4e89SAndroid Build Coastguard Worker tc_print_action(f, tb[TCA_BPF_ACT], 0);
243*de1e4e89SAndroid Build Coastguard Worker
244*de1e4e89SAndroid Build Coastguard Worker return 0;
245*de1e4e89SAndroid Build Coastguard Worker }
246*de1e4e89SAndroid Build Coastguard Worker
247*de1e4e89SAndroid Build Coastguard Worker struct filter_util bpf_filter_util = {
248*de1e4e89SAndroid Build Coastguard Worker .id = "bpf",
249*de1e4e89SAndroid Build Coastguard Worker .parse_fopt = bpf_parse_opt,
250*de1e4e89SAndroid Build Coastguard Worker .print_fopt = bpf_print_opt,
251*de1e4e89SAndroid Build Coastguard Worker };
252