2 * m_bpf.c BPF based action module
4 * This program is free software; you can redistribute 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.
9 * Authors: Jiri Pirko <jiri@resnulli.us>
10 * Daniel Borkmann <daniel@iogearbox.net>
19 #include <linux/bpf.h>
20 #include <linux/tc_act/tc_bpf.h>
27 static const enum bpf_prog_type bpf_type
= BPF_PROG_TYPE_SCHED_ACT
;
29 static void explain(void)
31 fprintf(stderr
, "Usage: ... bpf ... [ index INDEX ]\n");
32 fprintf(stderr
, "\n");
33 fprintf(stderr
, "BPF use case:\n");
34 fprintf(stderr
, " bytecode BPF_BYTECODE\n");
35 fprintf(stderr
, " bytecode-file FILE\n");
36 fprintf(stderr
, "\n");
37 fprintf(stderr
, "eBPF use case:\n");
38 fprintf(stderr
, " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]");
39 fprintf(stderr
, " [ verbose ]\n");
40 fprintf(stderr
, "\n");
41 fprintf(stderr
, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
42 fprintf(stderr
, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
43 fprintf(stderr
, "\n");
44 fprintf(stderr
, "Where FILE points to a file containing the BPF_BYTECODE string,\n");
45 fprintf(stderr
, "an ELF file containing eBPF map definitions and bytecode.\n");
46 fprintf(stderr
, "\n");
47 fprintf(stderr
, "Where ACT_NAME refers to the section name containing the\n");
48 fprintf(stderr
, "action (default \'%s\').\n", bpf_default_section(bpf_type
));
49 fprintf(stderr
, "\n");
50 fprintf(stderr
, "Where UDS_FILE points to a unix domain socket file in order\n");
51 fprintf(stderr
, "to hand off control of all created eBPF maps to an agent.\n");
52 fprintf(stderr
, "\n");
53 fprintf(stderr
, "Where optionally INDEX points to an existing action, or\n");
54 fprintf(stderr
, "explicitly specifies an action index upon creation.\n");
57 static void usage(void)
63 static int parse_bpf(struct action_util
*a
, int *argc_p
, char ***argv_p
,
64 int tca_id
, struct nlmsghdr
*n
)
66 char **argv
= *argv_p
, bpf_name
[256];
68 struct tc_act_bpf parm
= { 0 };
69 struct sock_filter bpf_ops
[BPF_MAXINSNS
];
70 bool ebpf_fill
= false, bpf_fill
= false;
71 bool ebpf
= false, seen_run
= false;
72 const char *bpf_uds_name
= NULL
;
73 const char *bpf_sec_name
= NULL
;
75 int argc
= *argc_p
, ret
= 0;
79 if (matches(*argv
, "bpf") != 0)
85 if (matches(*argv
, "run") == 0) {
86 bool from_file
, bpf_verbose
;
91 bpf_sec_name
= bpf_default_section(bpf_type
);
95 if (strcmp(*argv
, "bytecode-file") == 0 ||
96 strcmp(*argv
, "bcf") == 0) {
98 } else if (strcmp(*argv
, "bytecode") == 0 ||
99 strcmp(*argv
, "bc") == 0) {
101 } else if (strcmp(*argv
, "object-file") == 0 ||
102 strcmp(*argv
, "obj") == 0) {
105 fprintf(stderr
, "unexpected \"%s\"\n", *argv
);
112 bpf_uds_name
= getenv(BPF_ENV_UDS
);
116 if (strcmp(*argv
, "section") == 0 ||
117 strcmp(*argv
, "sec") == 0) {
119 bpf_sec_name
= *argv
;
123 (strcmp(*argv
, "export") == 0 ||
124 strcmp(*argv
, "exp") == 0)) {
126 bpf_uds_name
= *argv
;
129 if (strcmp(*argv
, "verbose") == 0 ||
130 strcmp(*argv
, "verb") == 0) {
138 ret
= ebpf
? bpf_open_object(bpf_obj
, bpf_type
, bpf_sec_name
,
140 bpf_parse_ops(argc
, argv
, bpf_ops
, from_file
);
142 fprintf(stderr
, "%s\n", ebpf
?
143 "Could not load object" :
144 "Illegal \"bytecode\"");
149 bpf_obj
= basename(bpf_obj
);
151 snprintf(bpf_name
, sizeof(bpf_name
), "%s:[%s]",
152 bpf_obj
, bpf_sec_name
);
160 } else if (matches(*argv
, "help") == 0) {
162 } else if (matches(*argv
, "index") == 0) {
173 parm
.action
= TC_ACT_PIPE
;
175 if (matches(*argv
, "reclassify") == 0) {
176 parm
.action
= TC_ACT_RECLASSIFY
;
179 } else if (matches(*argv
, "pipe") == 0) {
180 parm
.action
= TC_ACT_PIPE
;
183 } else if (matches(*argv
, "drop") == 0 ||
184 matches(*argv
, "shot") == 0) {
185 parm
.action
= TC_ACT_SHOT
;
188 } else if (matches(*argv
, "continue") == 0) {
189 parm
.action
= TC_ACT_UNSPEC
;
192 } else if (matches(*argv
, "pass") == 0) {
193 parm
.action
= TC_ACT_OK
;
200 if (matches(*argv
, "index") == 0) {
202 if (get_u32(&parm
.index
, *argv
, 10)) {
203 fprintf(stderr
, "bpf: Illegal \"index\"\n");
211 tail
= NLMSG_TAIL(n
);
213 addattr_l(n
, MAX_MSG
, tca_id
, NULL
, 0);
214 addattr_l(n
, MAX_MSG
, TCA_ACT_BPF_PARMS
, &parm
, sizeof(parm
));
217 addattr32(n
, MAX_MSG
, TCA_ACT_BPF_FD
, bpf_fd
);
218 addattrstrz(n
, MAX_MSG
, TCA_ACT_BPF_NAME
, bpf_name
);
219 } else if (bpf_fill
) {
220 addattr16(n
, MAX_MSG
, TCA_ACT_BPF_OPS_LEN
, bpf_len
);
221 addattr_l(n
, MAX_MSG
, TCA_ACT_BPF_OPS
, &bpf_ops
,
222 bpf_len
* sizeof(struct sock_filter
));
225 tail
->rta_len
= (char *)NLMSG_TAIL(n
) - (char *)tail
;
231 ret
= bpf_send_map_fds(bpf_uds_name
, bpf_obj
);
236 static int print_bpf(struct action_util
*au
, FILE *f
, struct rtattr
*arg
)
238 struct rtattr
*tb
[TCA_ACT_BPF_MAX
+ 1];
239 struct tc_act_bpf
*parm
;
240 SPRINT_BUF(action_buf
);
245 parse_rtattr_nested(tb
, TCA_ACT_BPF_MAX
, arg
);
247 if (!tb
[TCA_ACT_BPF_PARMS
]) {
248 fprintf(f
, "[NULL bpf parameters]");
252 parm
= RTA_DATA(tb
[TCA_ACT_BPF_PARMS
]);
256 if (tb
[TCA_ACT_BPF_NAME
])
257 fprintf(f
, "%s ", rta_getattr_str(tb
[TCA_ACT_BPF_NAME
]));
258 else if (tb
[TCA_ACT_BPF_FD
])
259 fprintf(f
, "pfd %u ", rta_getattr_u32(tb
[TCA_ACT_BPF_FD
]));
261 if (tb
[TCA_ACT_BPF_OPS
] && tb
[TCA_ACT_BPF_OPS_LEN
]) {
262 bpf_print_ops(f
, tb
[TCA_ACT_BPF_OPS
],
263 rta_getattr_u16(tb
[TCA_ACT_BPF_OPS_LEN
]));
267 fprintf(f
, "default-action %s\n", action_n2a(parm
->action
, action_buf
,
268 sizeof(action_buf
)));
269 fprintf(f
, "\tindex %d ref %d bind %d", parm
->index
, parm
->refcnt
,
273 if (tb
[TCA_ACT_BPF_TM
]) {
274 struct tcf_t
*tm
= RTA_DATA(tb
[TCA_ACT_BPF_TM
]);
284 struct action_util bpf_action_util
= {
286 .parse_aopt
= parse_bpf
,
287 .print_aopt
= print_bpf
,