]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/m_bpf.c
Merge branch 'main' into next
[mirror_iproute2.git] / tc / m_bpf.c
1 /*
2 * m_bpf.c BPF based action module
3 *
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.
8 *
9 * Authors: Jiri Pirko <jiri@resnulli.us>
10 * Daniel Borkmann <daniel@iogearbox.net>
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15
16 #include <linux/bpf.h>
17 #include <linux/tc_act/tc_bpf.h>
18
19 #include "utils.h"
20
21 #include "tc_util.h"
22 #include "bpf_util.h"
23
24 static const enum bpf_prog_type bpf_type = BPF_PROG_TYPE_SCHED_ACT;
25
26 static void explain(void)
27 {
28 fprintf(stderr,
29 "Usage: ... bpf ... [ index INDEX ]\n"
30 "\n"
31 "BPF use case:\n"
32 " bytecode BPF_BYTECODE\n"
33 " bytecode-file FILE\n"
34 "\n"
35 "eBPF use case:\n"
36 " object-file FILE [ section ACT_NAME ] [ export UDS_FILE ]"
37 " [ verbose ]\n"
38 " object-pinned FILE\n"
39 "\n"
40 "Where BPF_BYTECODE := \'s,c t f k,c t f k,c t f k,...\'\n"
41 "c,t,f,k and s are decimals; s denotes number of 4-tuples\n"
42 "\n"
43 "Where FILE points to a file containing the BPF_BYTECODE string,\n"
44 "an ELF file containing eBPF map definitions and bytecode, or a\n"
45 "pinned eBPF program.\n"
46 "\n"
47 "Where ACT_NAME refers to the section name containing the\n"
48 "action (default \'%s\').\n"
49 "\n"
50 "Where UDS_FILE points to a unix domain socket file in order\n"
51 "to hand off control of all created eBPF maps to an agent.\n"
52 "\n"
53 "Where optionally INDEX points to an existing action, or\n"
54 "explicitly specifies an action index upon creation.\n",
55 bpf_prog_to_default_section(bpf_type));
56 }
57
58 static void bpf_cbpf_cb(void *nl, const struct sock_filter *ops, int ops_len)
59 {
60 addattr16(nl, MAX_MSG, TCA_ACT_BPF_OPS_LEN, ops_len);
61 addattr_l(nl, MAX_MSG, TCA_ACT_BPF_OPS, ops,
62 ops_len * sizeof(struct sock_filter));
63 }
64
65 static void bpf_ebpf_cb(void *nl, int fd, const char *annotation)
66 {
67 addattr32(nl, MAX_MSG, TCA_ACT_BPF_FD, fd);
68 addattrstrz(nl, MAX_MSG, TCA_ACT_BPF_NAME, annotation);
69 }
70
71 static const struct bpf_cfg_ops bpf_cb_ops = {
72 .cbpf_cb = bpf_cbpf_cb,
73 .ebpf_cb = bpf_ebpf_cb,
74 };
75
76 static int bpf_parse_opt(struct action_util *a, int *ptr_argc, char ***ptr_argv,
77 int tca_id, struct nlmsghdr *n)
78 {
79 const char *bpf_obj = NULL, *bpf_uds_name = NULL;
80 struct tc_act_bpf parm = {};
81 struct bpf_cfg_in cfg = {};
82 bool seen_run = false;
83 struct rtattr *tail;
84 int argc, ret = 0;
85 char **argv;
86
87 argv = *ptr_argv;
88 argc = *ptr_argc;
89
90 if (matches(*argv, "bpf") != 0)
91 return -1;
92
93 NEXT_ARG();
94
95 tail = addattr_nest(n, MAX_MSG, tca_id);
96
97 while (argc > 0) {
98 if (matches(*argv, "run") == 0) {
99 NEXT_ARG();
100
101 if (seen_run)
102 duparg("run", *argv);
103 opt_bpf:
104 seen_run = true;
105 cfg.type = bpf_type;
106 cfg.argc = argc;
107 cfg.argv = argv;
108
109 if (bpf_parse_and_load_common(&cfg, &bpf_cb_ops, n))
110 return -1;
111
112 argc = cfg.argc;
113 argv = cfg.argv;
114
115 bpf_obj = cfg.object;
116 bpf_uds_name = cfg.uds;
117 } else if (matches(*argv, "help") == 0) {
118 explain();
119 return -1;
120 } else if (matches(*argv, "index") == 0) {
121 break;
122 } else {
123 if (!seen_run)
124 goto opt_bpf;
125 break;
126 }
127
128 NEXT_ARG_FWD();
129 }
130
131 parse_action_control_dflt(&argc, &argv, &parm.action,
132 false, TC_ACT_PIPE);
133
134 if (argc) {
135 if (matches(*argv, "index") == 0) {
136 NEXT_ARG();
137 if (get_u32(&parm.index, *argv, 10)) {
138 fprintf(stderr, "bpf: Illegal \"index\"\n");
139 return -1;
140 }
141
142 NEXT_ARG_FWD();
143 }
144 }
145
146 addattr_l(n, MAX_MSG, TCA_ACT_BPF_PARMS, &parm, sizeof(parm));
147 addattr_nest_end(n, tail);
148
149 if (bpf_uds_name)
150 ret = bpf_send_map_fds(bpf_uds_name, bpf_obj);
151
152 *ptr_argc = argc;
153 *ptr_argv = argv;
154
155 return ret;
156 }
157
158 static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
159 {
160 struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
161 struct tc_act_bpf *parm;
162 int d_ok = 0;
163
164 print_string(PRINT_ANY, "kind", "%s ", "bpf");
165 if (arg == NULL)
166 return 0;
167
168 parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);
169
170 if (!tb[TCA_ACT_BPF_PARMS]) {
171 fprintf(stderr, "Missing bpf parameters\n");
172 return -1;
173 }
174
175 parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
176
177 if (tb[TCA_ACT_BPF_NAME])
178 print_string(PRINT_ANY, "bpf_name", "%s ",
179 rta_getattr_str(tb[TCA_ACT_BPF_NAME]));
180 if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) {
181 bpf_print_ops(tb[TCA_ACT_BPF_OPS],
182 rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
183 print_string(PRINT_FP, NULL, "%s", " ");
184 }
185
186 if (tb[TCA_ACT_BPF_ID])
187 d_ok = bpf_dump_prog_info(f,
188 rta_getattr_u32(tb[TCA_ACT_BPF_ID]));
189 if (!d_ok && tb[TCA_ACT_BPF_TAG]) {
190 SPRINT_BUF(b);
191
192 print_string(PRINT_ANY, "tag", "tag %s ",
193 hexstring_n2a(RTA_DATA(tb[TCA_ACT_BPF_TAG]),
194 RTA_PAYLOAD(tb[TCA_ACT_BPF_TAG]),
195 b, sizeof(b)));
196 }
197
198 print_action_control(f, "default-action ", parm->action, _SL_);
199 print_uint(PRINT_ANY, "index", "\t index %u", parm->index);
200 print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt);
201 print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt);
202
203 if (show_stats) {
204 if (tb[TCA_ACT_BPF_TM]) {
205 struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);
206
207 print_tm(f, tm);
208 }
209 }
210
211 fprintf(f, "\n ");
212 return 0;
213 }
214
215 struct action_util bpf_action_util = {
216 .id = "bpf",
217 .parse_aopt = bpf_parse_opt,
218 .print_aopt = bpf_print_opt,
219 };