blob: 7799942ed349ebc8d0acb14309e6865b922ea0e6 [file] [log] [blame]
Jakub Kicinski31d3ad82017-12-01 15:08:59 -08001/*
2 * Copyright (C) 2017 Netronome Systems, Inc.
3 *
4 * This software is licensed under the GNU General License Version 2,
5 * June 1991 as shown in the file COPYING in the top-level directory of this
6 * source tree.
7 *
8 * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
9 * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
10 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11 * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
12 * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
13 * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
14 */
15
16#include <linux/bpf.h>
17#include <linux/bpf_verifier.h>
18#include <linux/debugfs.h>
19#include <linux/kernel.h>
20#include <linux/rtnetlink.h>
21#include <net/pkt_cls.h>
22
23#include "netdevsim.h"
24
25struct nsim_bpf_bound_prog {
26 struct netdevsim *ns;
27 struct bpf_prog *prog;
28 struct dentry *ddir;
29 const char *state;
30 bool is_loaded;
31 struct list_head l;
32};
33
34static int nsim_debugfs_bpf_string_read(struct seq_file *file, void *data)
35{
36 const char **str = file->private;
37
38 if (*str)
39 seq_printf(file, "%s\n", *str);
40
41 return 0;
42}
43
44static int nsim_debugfs_bpf_string_open(struct inode *inode, struct file *f)
45{
46 return single_open(f, nsim_debugfs_bpf_string_read, inode->i_private);
47}
48
49static const struct file_operations nsim_bpf_string_fops = {
50 .owner = THIS_MODULE,
51 .open = nsim_debugfs_bpf_string_open,
52 .release = single_release,
53 .read = seq_read,
54 .llseek = seq_lseek
55};
56
57static int
58nsim_bpf_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn)
59{
60 struct nsim_bpf_bound_prog *state;
61
62 state = env->prog->aux->offload->dev_priv;
63 if (state->ns->bpf_bind_verifier_delay && !insn_idx)
64 msleep(state->ns->bpf_bind_verifier_delay);
65
66 return 0;
67}
68
69static const struct bpf_ext_analyzer_ops nsim_bpf_analyzer_ops = {
70 .insn_hook = nsim_bpf_verify_insn,
71};
72
73static bool nsim_xdp_offload_active(struct netdevsim *ns)
74{
75 return ns->xdp_prog_mode == XDP_ATTACHED_HW;
76}
77
78static void nsim_prog_set_loaded(struct bpf_prog *prog, bool loaded)
79{
80 struct nsim_bpf_bound_prog *state;
81
82 if (!prog || !prog->aux->offload)
83 return;
84
85 state = prog->aux->offload->dev_priv;
86 state->is_loaded = loaded;
87}
88
89static int
90nsim_bpf_offload(struct netdevsim *ns, struct bpf_prog *prog, bool oldprog)
91{
92 nsim_prog_set_loaded(ns->bpf_offloaded, false);
93
94 WARN(!!ns->bpf_offloaded != oldprog,
95 "bad offload state, expected offload %sto be active",
96 oldprog ? "" : "not ");
97 ns->bpf_offloaded = prog;
98 ns->bpf_offloaded_id = prog ? prog->aux->id : 0;
99 nsim_prog_set_loaded(prog, true);
100
101 return 0;
102}
103
104int nsim_bpf_setup_tc_block_cb(enum tc_setup_type type,
105 void *type_data, void *cb_priv)
106{
107 struct tc_cls_bpf_offload *cls_bpf = type_data;
108 struct bpf_prog *prog = cls_bpf->prog;
109 struct netdevsim *ns = cb_priv;
Jakub Kicinski31d3ad82017-12-01 15:08:59 -0800110
111 if (type != TC_SETUP_CLSBPF ||
112 !tc_can_offload(ns->netdev) ||
113 cls_bpf->common.protocol != htons(ETH_P_ALL) ||
114 cls_bpf->common.chain_index)
115 return -EOPNOTSUPP;
116
Jakub Kicinski31d3ad82017-12-01 15:08:59 -0800117 if (nsim_xdp_offload_active(ns))
118 return -EBUSY;
119
120 if (!ns->bpf_tc_accept)
121 return -EOPNOTSUPP;
122 /* Note: progs without skip_sw will probably not be dev bound */
123 if (prog && !prog->aux->offload && !ns->bpf_tc_non_bound_accept)
124 return -EOPNOTSUPP;
125
126 switch (cls_bpf->command) {
127 case TC_CLSBPF_REPLACE:
128 return nsim_bpf_offload(ns, prog, true);
129 case TC_CLSBPF_ADD:
130 return nsim_bpf_offload(ns, prog, false);
131 case TC_CLSBPF_DESTROY:
132 return nsim_bpf_offload(ns, NULL, true);
133 default:
134 return -EOPNOTSUPP;
135 }
136}
137
138int nsim_bpf_disable_tc(struct netdevsim *ns)
139{
140 if (ns->bpf_offloaded && !nsim_xdp_offload_active(ns))
141 return -EBUSY;
142 return 0;
143}
144
145static int nsim_xdp_offload_prog(struct netdevsim *ns, struct netdev_bpf *bpf)
146{
147 if (!nsim_xdp_offload_active(ns) && !bpf->prog)
148 return 0;
149 if (!nsim_xdp_offload_active(ns) && bpf->prog && ns->bpf_offloaded) {
150 NSIM_EA(bpf->extack, "TC program is already loaded");
151 return -EBUSY;
152 }
153
154 return nsim_bpf_offload(ns, bpf->prog, nsim_xdp_offload_active(ns));
155}
156
157static int nsim_xdp_set_prog(struct netdevsim *ns, struct netdev_bpf *bpf)
158{
159 int err;
160
161 if (ns->xdp_prog && (bpf->flags ^ ns->xdp_flags) & XDP_FLAGS_MODES) {
162 NSIM_EA(bpf->extack, "program loaded with different flags");
163 return -EBUSY;
164 }
165
166 if (bpf->command == XDP_SETUP_PROG && !ns->bpf_xdpdrv_accept) {
167 NSIM_EA(bpf->extack, "driver XDP disabled in DebugFS");
168 return -EOPNOTSUPP;
169 }
170 if (bpf->command == XDP_SETUP_PROG_HW && !ns->bpf_xdpoffload_accept) {
171 NSIM_EA(bpf->extack, "XDP offload disabled in DebugFS");
172 return -EOPNOTSUPP;
173 }
174
175 if (bpf->command == XDP_SETUP_PROG_HW) {
176 err = nsim_xdp_offload_prog(ns, bpf);
177 if (err)
178 return err;
179 }
180
181 if (ns->xdp_prog)
182 bpf_prog_put(ns->xdp_prog);
183
184 ns->xdp_prog = bpf->prog;
185 ns->xdp_flags = bpf->flags;
186
187 if (!bpf->prog)
188 ns->xdp_prog_mode = XDP_ATTACHED_NONE;
189 else if (bpf->command == XDP_SETUP_PROG)
190 ns->xdp_prog_mode = XDP_ATTACHED_DRV;
191 else
192 ns->xdp_prog_mode = XDP_ATTACHED_HW;
193
194 return 0;
195}
196
Colin Ian King1dfc2662017-12-04 12:56:09 +0000197static int nsim_bpf_create_prog(struct netdevsim *ns, struct bpf_prog *prog)
Jakub Kicinski31d3ad82017-12-01 15:08:59 -0800198{
199 struct nsim_bpf_bound_prog *state;
200 char name[16];
201 int err;
202
203 state = kzalloc(sizeof(*state), GFP_KERNEL);
204 if (!state)
205 return -ENOMEM;
206
207 state->ns = ns;
208 state->prog = prog;
209 state->state = "verify";
210
211 /* Program id is not populated yet when we create the state. */
212 sprintf(name, "%u", ns->prog_id_gen++);
213 state->ddir = debugfs_create_dir(name, ns->ddir_bpf_bound_progs);
214 if (IS_ERR(state->ddir)) {
215 err = PTR_ERR(state->ddir);
216 kfree(state);
217 return err;
218 }
219
220 debugfs_create_u32("id", 0400, state->ddir, &prog->aux->id);
221 debugfs_create_file("state", 0400, state->ddir,
222 &state->state, &nsim_bpf_string_fops);
223 debugfs_create_bool("loaded", 0400, state->ddir, &state->is_loaded);
224
225 list_add_tail(&state->l, &ns->bpf_bound_progs);
226
227 prog->aux->offload->dev_priv = state;
228
229 return 0;
230}
231
Colin Ian King1dfc2662017-12-04 12:56:09 +0000232static void nsim_bpf_destroy_prog(struct bpf_prog *prog)
Jakub Kicinski31d3ad82017-12-01 15:08:59 -0800233{
234 struct nsim_bpf_bound_prog *state;
235
236 state = prog->aux->offload->dev_priv;
237 WARN(state->is_loaded,
238 "offload state destroyed while program still bound");
239 debugfs_remove_recursive(state->ddir);
240 list_del(&state->l);
241 kfree(state);
242}
243
244static int nsim_setup_prog_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
245{
246 if (bpf->prog && bpf->prog->aux->offload) {
247 NSIM_EA(bpf->extack, "attempt to load offloaded prog to drv");
248 return -EINVAL;
249 }
250 if (ns->netdev->mtu > NSIM_XDP_MAX_MTU) {
251 NSIM_EA(bpf->extack, "MTU too large w/ XDP enabled");
252 return -EINVAL;
253 }
254 if (nsim_xdp_offload_active(ns)) {
255 NSIM_EA(bpf->extack, "xdp offload active, can't load drv prog");
256 return -EBUSY;
257 }
258 return 0;
259}
260
261static int
262nsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
263{
264 struct nsim_bpf_bound_prog *state;
265
266 if (!bpf->prog)
267 return 0;
268
269 if (!bpf->prog->aux->offload) {
270 NSIM_EA(bpf->extack, "xdpoffload of non-bound program");
271 return -EINVAL;
272 }
273 if (bpf->prog->aux->offload->netdev != ns->netdev) {
274 NSIM_EA(bpf->extack, "program bound to different dev");
275 return -EINVAL;
276 }
277
278 state = bpf->prog->aux->offload->dev_priv;
279 if (WARN_ON(strcmp(state->state, "xlated"))) {
280 NSIM_EA(bpf->extack, "offloading program in bad state");
281 return -EINVAL;
282 }
283 return 0;
284}
285
286int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf)
287{
288 struct netdevsim *ns = netdev_priv(dev);
289 struct nsim_bpf_bound_prog *state;
290 int err;
291
292 ASSERT_RTNL();
293
294 switch (bpf->command) {
295 case BPF_OFFLOAD_VERIFIER_PREP:
296 if (!ns->bpf_bind_accept)
297 return -EOPNOTSUPP;
298
299 err = nsim_bpf_create_prog(ns, bpf->verifier.prog);
300 if (err)
301 return err;
302
303 bpf->verifier.ops = &nsim_bpf_analyzer_ops;
304 return 0;
305 case BPF_OFFLOAD_TRANSLATE:
306 state = bpf->offload.prog->aux->offload->dev_priv;
307
308 state->state = "xlated";
309 return 0;
310 case BPF_OFFLOAD_DESTROY:
311 nsim_bpf_destroy_prog(bpf->offload.prog);
312 return 0;
313 case XDP_QUERY_PROG:
314 bpf->prog_attached = ns->xdp_prog_mode;
315 bpf->prog_id = ns->xdp_prog ? ns->xdp_prog->aux->id : 0;
316 bpf->prog_flags = ns->xdp_prog ? ns->xdp_flags : 0;
317 return 0;
318 case XDP_SETUP_PROG:
319 err = nsim_setup_prog_checks(ns, bpf);
320 if (err)
321 return err;
322
323 return nsim_xdp_set_prog(ns, bpf);
324 case XDP_SETUP_PROG_HW:
325 err = nsim_setup_prog_hw_checks(ns, bpf);
326 if (err)
327 return err;
328
329 return nsim_xdp_set_prog(ns, bpf);
330 default:
331 return -EINVAL;
332 }
333}
334
335int nsim_bpf_init(struct netdevsim *ns)
336{
337 INIT_LIST_HEAD(&ns->bpf_bound_progs);
338
339 debugfs_create_u32("bpf_offloaded_id", 0400, ns->ddir,
340 &ns->bpf_offloaded_id);
341
342 ns->bpf_bind_accept = true;
343 debugfs_create_bool("bpf_bind_accept", 0600, ns->ddir,
344 &ns->bpf_bind_accept);
345 debugfs_create_u32("bpf_bind_verifier_delay", 0600, ns->ddir,
346 &ns->bpf_bind_verifier_delay);
347 ns->ddir_bpf_bound_progs =
348 debugfs_create_dir("bpf_bound_progs", ns->ddir);
349
350 ns->bpf_tc_accept = true;
351 debugfs_create_bool("bpf_tc_accept", 0600, ns->ddir,
352 &ns->bpf_tc_accept);
353 debugfs_create_bool("bpf_tc_non_bound_accept", 0600, ns->ddir,
354 &ns->bpf_tc_non_bound_accept);
355 ns->bpf_xdpdrv_accept = true;
356 debugfs_create_bool("bpf_xdpdrv_accept", 0600, ns->ddir,
357 &ns->bpf_xdpdrv_accept);
358 ns->bpf_xdpoffload_accept = true;
359 debugfs_create_bool("bpf_xdpoffload_accept", 0600, ns->ddir,
360 &ns->bpf_xdpoffload_accept);
361
362 return 0;
363}
364
365void nsim_bpf_uninit(struct netdevsim *ns)
366{
367 WARN_ON(!list_empty(&ns->bpf_bound_progs));
368 WARN_ON(ns->xdp_prog);
369 WARN_ON(ns->bpf_offloaded);
370}