]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/f_bpf.c
6d765807eed0af91001a6ffb7143ae33ba4b64fc
[mirror_iproute2.git] / tc / f_bpf.c
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>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <arpa/inet.h>
20 #include <string.h>
21 #include <stdbool.h>
22 #include <errno.h>
23 #include <limits.h>
24 #include <linux/filter.h>
25 #include <linux/if.h>
26
27 #include "utils.h"
28 #include "tc_util.h"
29 #include "tc_bpf.h"
30
31 static void explain(void)
32 {
33 fprintf(stderr, "Usage: ... bpf ...\n");
34 fprintf(stderr, "\n");
35 fprintf(stderr, " [inline]: run bytecode BPF_BYTECODE\n");
36 fprintf(stderr, " [from file]: run bytecode-file FILE\n");
37 fprintf(stderr, " [from file]: run object-file FILE\n");
38 fprintf(stderr, "\n");
39 fprintf(stderr, " [ action ACTION_SPEC ]\n");
40 fprintf(stderr, " [ classid CLASSID ]\n");
41 fprintf(stderr, "\n");
42 fprintf(stderr, "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n");
43 fprintf(stderr, " c,t,f,k and s are decimals; s denotes number of 4-tuples\n");
44 fprintf(stderr, "Where FILE points to a file containing the BPF_BYTECODE string,\n");
45 fprintf(stderr, "or an ELF file containing eBPF map definitions and bytecode.\n");
46 fprintf(stderr, "\nACTION_SPEC := ... look at individual actions\n");
47 fprintf(stderr, "NOTE: CLASSID is parsed as hexadecimal input.\n");
48 }
49
50 static int bpf_parse_opt(struct filter_util *qu, char *handle,
51 int argc, char **argv, struct nlmsghdr *n)
52 {
53 struct tcmsg *t = NLMSG_DATA(n);
54 struct rtattr *tail;
55 long h = 0;
56
57 if (argc == 0)
58 return 0;
59
60 if (handle) {
61 h = strtol(handle, NULL, 0);
62 if (h == LONG_MIN || h == LONG_MAX) {
63 fprintf(stderr, "Illegal handle \"%s\", must be "
64 "numeric.\n", handle);
65 return -1;
66 }
67 }
68
69 t->tcm_handle = h;
70
71 tail = (struct rtattr*)(((void*)n)+NLMSG_ALIGN(n->nlmsg_len));
72 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
73
74 while (argc > 0) {
75 if (matches(*argv, "run") == 0) {
76 bool from_file = true, ebpf;
77 struct sock_filter bpf_ops[BPF_MAXINSNS];
78 int ret;
79
80 NEXT_ARG();
81 if (strcmp(*argv, "bytecode-file") == 0) {
82 ebpf = false;
83 } else if (strcmp(*argv, "bytecode") == 0) {
84 from_file = false;
85 ebpf = false;
86 } else if (strcmp(*argv, "object-file") == 0) {
87 ebpf = true;
88 } else {
89 fprintf(stderr, "What is \"%s\"?\n", *argv);
90 explain();
91 return -1;
92 }
93 NEXT_ARG();
94 ret = ebpf ? bpf_open_object(*argv, BPF_PROG_TYPE_SCHED_CLS) :
95 bpf_parse_ops(argc, argv, bpf_ops, from_file);
96 if (ret < 0) {
97 fprintf(stderr, "%s\n", ebpf ?
98 "Could not load object" :
99 "Illegal \"bytecode\"");
100 return -1;
101 }
102 if (ebpf) {
103 addattr32(n, MAX_MSG, TCA_BPF_FD, ret);
104 addattrstrz(n, MAX_MSG, TCA_BPF_NAME, *argv);
105 } else {
106 addattr16(n, MAX_MSG, TCA_BPF_OPS_LEN, ret);
107 addattr_l(n, MAX_MSG, TCA_BPF_OPS, &bpf_ops,
108 ret * sizeof(struct sock_filter));
109 }
110 } else if (matches(*argv, "classid") == 0 ||
111 strcmp(*argv, "flowid") == 0) {
112 unsigned handle;
113 NEXT_ARG();
114 if (get_tc_classid(&handle, *argv)) {
115 fprintf(stderr, "Illegal \"classid\"\n");
116 return -1;
117 }
118 addattr_l(n, MAX_MSG, TCA_BPF_CLASSID, &handle, 4);
119 } else if (matches(*argv, "action") == 0) {
120 NEXT_ARG();
121 if (parse_action(&argc, &argv, TCA_BPF_ACT, n)) {
122 fprintf(stderr, "Illegal \"action\"\n");
123 return -1;
124 }
125 continue;
126 } else if (matches(*argv, "police") == 0) {
127 NEXT_ARG();
128 if (parse_police(&argc, &argv, TCA_BPF_POLICE, n)) {
129 fprintf(stderr, "Illegal \"police\"\n");
130 return -1;
131 }
132 continue;
133 } else if (strcmp(*argv, "help") == 0) {
134 explain();
135 return -1;
136 } else {
137 fprintf(stderr, "What is \"%s\"?\n", *argv);
138 explain();
139 return -1;
140 }
141 argc--; argv++;
142 }
143
144 tail->rta_len = (((void*)n)+n->nlmsg_len) - (void*)tail;
145 return 0;
146 }
147
148 static int bpf_print_opt(struct filter_util *qu, FILE *f,
149 struct rtattr *opt, __u32 handle)
150 {
151 struct rtattr *tb[TCA_BPF_MAX + 1];
152
153 if (opt == NULL)
154 return 0;
155
156 parse_rtattr_nested(tb, TCA_BPF_MAX, opt);
157
158 if (handle)
159 fprintf(f, "handle 0x%x ", handle);
160
161 if (tb[TCA_BPF_CLASSID]) {
162 SPRINT_BUF(b1);
163 fprintf(f, "flowid %s ",
164 sprint_tc_classid(rta_getattr_u32(tb[TCA_BPF_CLASSID]), b1));
165 }
166
167 if (tb[TCA_BPF_NAME])
168 fprintf(f, "%s ", rta_getattr_str(tb[TCA_BPF_NAME]));
169 else if (tb[TCA_BPF_FD])
170 fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_BPF_FD]));
171
172 if (tb[TCA_BPF_OPS] && tb[TCA_BPF_OPS_LEN])
173 bpf_print_ops(f, tb[TCA_BPF_OPS],
174 rta_getattr_u16(tb[TCA_BPF_OPS_LEN]));
175
176 if (tb[TCA_BPF_POLICE]) {
177 fprintf(f, "\n");
178 tc_print_police(f, tb[TCA_BPF_POLICE]);
179 }
180
181 if (tb[TCA_BPF_ACT]) {
182 tc_print_action(f, tb[TCA_BPF_ACT]);
183 }
184
185 return 0;
186 }
187
188 struct filter_util bpf_filter_util = {
189 .id = "bpf",
190 .parse_fopt = bpf_parse_opt,
191 .print_fopt = bpf_print_opt,
192 };