2 * f_bpf.c BPF-based Classifier
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.
9 * Authors: Daniel Borkmann <dborkman@redhat.com>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
25 #include <linux/filter.h>
32 static const enum bpf_prog_type bpf_type
= BPF_PROG_TYPE_SCHED_CLS
;
34 static void explain(void)
36 fprintf(stderr
, "Usage: ... bpf ...\n");
37 fprintf(stderr
, "\n");
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");
43 fprintf(stderr
, " object-file FILE [ section CLS_NAME ] [ export UDS_FILE ]");
44 fprintf(stderr
, " [ verbose ] [ direct-action ]\n");
45 fprintf(stderr
, "\n");
46 fprintf(stderr
, "Common remaining options:\n");
47 fprintf(stderr
, " [ action ACTION_SPEC ]\n");
48 fprintf(stderr
, " [ classid CLASSID ]\n");
49 fprintf(stderr
, "\n");
50 fprintf(stderr
, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
51 fprintf(stderr
, "c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
52 fprintf(stderr
, "\n");
53 fprintf(stderr
, "Where FILE points to a file containing the BPF_BYTECODE string,\n");
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");
63 fprintf(stderr
, "NOTE: CLASSID is parsed as hexadecimal input.\n");
66 static int bpf_parse_opt(struct filter_util
*qu
, char *handle
,
67 int argc
, char **argv
, struct nlmsghdr
*n
)
69 struct tcmsg
*t
= NLMSG_DATA(n
);
70 const char *bpf_uds_name
= NULL
;
71 const char *bpf_sec_name
= NULL
;
72 unsigned int bpf_flags
= 0;
75 bool seen_run
= false;
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
);
93 tail
= (struct rtattr
*)(((void *)n
) + NLMSG_ALIGN(n
->nlmsg_len
));
94 addattr_l(n
, MAX_MSG
, TCA_OPTIONS
, NULL
, 0);
97 if (matches(*argv
, "run") == 0) {
98 struct sock_filter bpf_ops
[BPF_MAXINSNS
];
99 bool from_file
, ebpf
, bpf_verbose
;
104 bpf_sec_name
= bpf_default_section(bpf_type
);
109 if (strcmp(*argv
, "bytecode-file") == 0 ||
110 strcmp(*argv
, "bcf") == 0) {
112 } else if (strcmp(*argv
, "bytecode") == 0 ||
113 strcmp(*argv
, "bc") == 0) {
115 } else if (strcmp(*argv
, "object-file") == 0 ||
116 strcmp(*argv
, "obj") == 0) {
119 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
126 bpf_uds_name
= getenv(BPF_ENV_UDS
);
132 (strcmp(*argv
, "section") == 0 ||
133 strcmp(*argv
, "sec") == 0)) {
135 bpf_sec_name
= *argv
;
138 if (argc
> 0 && !bpf_uds_name
&&
139 (strcmp(*argv
, "export") == 0 ||
140 strcmp(*argv
, "exp") == 0)) {
142 bpf_uds_name
= *argv
;
146 (strcmp(*argv
, "verbose") == 0 ||
147 strcmp(*argv
, "verb") == 0)) {
155 ret
= ebpf
? bpf_open_object(bpf_obj
, bpf_type
, bpf_sec_name
,
157 bpf_parse_ops(argc
, argv
, bpf_ops
, from_file
);
159 fprintf(stderr
, "%s\n", ebpf
?
160 "Could not load object" :
161 "Illegal \"bytecode\"");
168 bpf_obj
= basename(bpf_obj
);
170 snprintf(bpf_name
, sizeof(bpf_name
), "%s:[%s]",
171 bpf_obj
, bpf_sec_name
);
173 addattr32(n
, MAX_MSG
, TCA_BPF_FD
, ret
);
174 addattrstrz(n
, MAX_MSG
, TCA_BPF_NAME
, bpf_name
);
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
));
180 } else if (matches(*argv
, "classid") == 0 ||
181 strcmp(*argv
, "flowid") == 0) {
185 if (get_tc_classid(&handle
, *argv
)) {
186 fprintf(stderr
, "Illegal \"classid\"\n");
189 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
;
193 } else if (matches(*argv
, "action") == 0) {
195 if (parse_action(&argc
, &argv
, TCA_BPF_ACT
, n
)) {
196 fprintf(stderr
, "Illegal \"action\"\n");
200 } else if (matches(*argv
, "police") == 0) {
202 if (parse_police(&argc
, &argv
, TCA_BPF_POLICE
, n
)) {
203 fprintf(stderr
, "Illegal \"police\"\n");
207 } else if (strcmp(*argv
, "help") == 0) {
214 fprintf(stderr
, "What is \"%s\"?\n", *argv
);
222 if (bpf_obj
&& bpf_flags
)
223 addattr32(n
, MAX_MSG
, TCA_BPF_FLAGS
, bpf_flags
);
225 tail
->rta_len
= (((void *)n
) + n
->nlmsg_len
) - (void *)tail
;
228 ret
= bpf_send_map_fds(bpf_uds_name
, bpf_obj
);
233 static int bpf_print_opt(struct filter_util
*qu
, FILE *f
,
234 struct rtattr
*opt
, __u32 handle
)
236 struct rtattr
*tb
[TCA_BPF_MAX
+ 1];
241 parse_rtattr_nested(tb
, TCA_BPF_MAX
, opt
);
244 fprintf(f
, "handle 0x%x ", handle
);
246 if (tb
[TCA_BPF_CLASSID
]) {
248 fprintf(f
, "flowid %s ",
249 sprint_tc_classid(rta_getattr_u32(tb
[TCA_BPF_CLASSID
]), b1
));
252 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
]));
257 if (tb
[TCA_BPF_FLAGS
]) {
258 unsigned int flags
= rta_getattr_u32(tb
[TCA_BPF_FLAGS
]);
260 if (flags
& TCA_BPF_FLAG_ACT_DIRECT
)
261 fprintf(f
, "direct-action ");
264 if (tb
[TCA_BPF_OPS
] && tb
[TCA_BPF_OPS_LEN
]) {
265 bpf_print_ops(f
, tb
[TCA_BPF_OPS
],
266 rta_getattr_u16(tb
[TCA_BPF_OPS_LEN
]));
270 if (tb
[TCA_BPF_POLICE
]) {
272 tc_print_police(f
, tb
[TCA_BPF_POLICE
]);
275 if (tb
[TCA_BPF_ACT
]) {
276 tc_print_action(f
, tb
[TCA_BPF_ACT
]);
282 struct filter_util bpf_filter_util
= {
284 .parse_fopt
= bpf_parse_opt
,
285 .print_fopt
= bpf_print_opt
,