xref: /openbmc/linux/drivers/net/netdevsim/bpf.c (revision 9dae47aba0a055f761176d9297371d5bb24289ec)
1 /*
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 
25 struct 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 
34 static 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 
44 static 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 
49 static 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 
57 static int
58 nsim_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 
69 static const struct bpf_prog_offload_ops nsim_bpf_analyzer_ops = {
70 	.insn_hook = nsim_bpf_verify_insn,
71 };
72 
73 static bool nsim_xdp_offload_active(struct netdevsim *ns)
74 {
75 	return ns->xdp_prog_mode == XDP_ATTACHED_HW;
76 }
77 
78 static 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 
89 static int
90 nsim_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 
104 int 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;
110 	struct bpf_prog *oldprog;
111 
112 	if (type != TC_SETUP_CLSBPF ||
113 	    !tc_can_offload(ns->netdev) ||
114 	    cls_bpf->common.protocol != htons(ETH_P_ALL) ||
115 	    cls_bpf->common.chain_index)
116 		return -EOPNOTSUPP;
117 
118 	if (!ns->bpf_tc_accept)
119 		return -EOPNOTSUPP;
120 	/* Note: progs without skip_sw will probably not be dev bound */
121 	if (prog && !prog->aux->offload && !ns->bpf_tc_non_bound_accept)
122 		return -EOPNOTSUPP;
123 
124 	if (cls_bpf->command != TC_CLSBPF_OFFLOAD)
125 		return -EOPNOTSUPP;
126 
127 	oldprog = cls_bpf->oldprog;
128 
129 	/* Don't remove if oldprog doesn't match driver's state */
130 	if (ns->bpf_offloaded != oldprog) {
131 		oldprog = NULL;
132 		if (!cls_bpf->prog)
133 			return 0;
134 		if (ns->bpf_offloaded)
135 			return -EBUSY;
136 	}
137 
138 	return nsim_bpf_offload(ns, cls_bpf->prog, oldprog);
139 }
140 
141 int nsim_bpf_disable_tc(struct netdevsim *ns)
142 {
143 	if (ns->bpf_offloaded && !nsim_xdp_offload_active(ns))
144 		return -EBUSY;
145 	return 0;
146 }
147 
148 static int nsim_xdp_offload_prog(struct netdevsim *ns, struct netdev_bpf *bpf)
149 {
150 	if (!nsim_xdp_offload_active(ns) && !bpf->prog)
151 		return 0;
152 	if (!nsim_xdp_offload_active(ns) && bpf->prog && ns->bpf_offloaded) {
153 		NSIM_EA(bpf->extack, "TC program is already loaded");
154 		return -EBUSY;
155 	}
156 
157 	return nsim_bpf_offload(ns, bpf->prog, nsim_xdp_offload_active(ns));
158 }
159 
160 static int nsim_xdp_set_prog(struct netdevsim *ns, struct netdev_bpf *bpf)
161 {
162 	int err;
163 
164 	if (ns->xdp_prog && (bpf->flags ^ ns->xdp_flags) & XDP_FLAGS_MODES) {
165 		NSIM_EA(bpf->extack, "program loaded with different flags");
166 		return -EBUSY;
167 	}
168 
169 	if (bpf->command == XDP_SETUP_PROG && !ns->bpf_xdpdrv_accept) {
170 		NSIM_EA(bpf->extack, "driver XDP disabled in DebugFS");
171 		return -EOPNOTSUPP;
172 	}
173 	if (bpf->command == XDP_SETUP_PROG_HW && !ns->bpf_xdpoffload_accept) {
174 		NSIM_EA(bpf->extack, "XDP offload disabled in DebugFS");
175 		return -EOPNOTSUPP;
176 	}
177 
178 	if (bpf->command == XDP_SETUP_PROG_HW) {
179 		err = nsim_xdp_offload_prog(ns, bpf);
180 		if (err)
181 			return err;
182 	}
183 
184 	if (ns->xdp_prog)
185 		bpf_prog_put(ns->xdp_prog);
186 
187 	ns->xdp_prog = bpf->prog;
188 	ns->xdp_flags = bpf->flags;
189 
190 	if (!bpf->prog)
191 		ns->xdp_prog_mode = XDP_ATTACHED_NONE;
192 	else if (bpf->command == XDP_SETUP_PROG)
193 		ns->xdp_prog_mode = XDP_ATTACHED_DRV;
194 	else
195 		ns->xdp_prog_mode = XDP_ATTACHED_HW;
196 
197 	return 0;
198 }
199 
200 static int nsim_bpf_create_prog(struct netdevsim *ns, struct bpf_prog *prog)
201 {
202 	struct nsim_bpf_bound_prog *state;
203 	char name[16];
204 
205 	state = kzalloc(sizeof(*state), GFP_KERNEL);
206 	if (!state)
207 		return -ENOMEM;
208 
209 	state->ns = ns;
210 	state->prog = prog;
211 	state->state = "verify";
212 
213 	/* Program id is not populated yet when we create the state. */
214 	sprintf(name, "%u", ns->prog_id_gen++);
215 	state->ddir = debugfs_create_dir(name, ns->ddir_bpf_bound_progs);
216 	if (IS_ERR_OR_NULL(state->ddir)) {
217 		kfree(state);
218 		return -ENOMEM;
219 	}
220 
221 	debugfs_create_u32("id", 0400, state->ddir, &prog->aux->id);
222 	debugfs_create_file("state", 0400, state->ddir,
223 			    &state->state, &nsim_bpf_string_fops);
224 	debugfs_create_bool("loaded", 0400, state->ddir, &state->is_loaded);
225 
226 	list_add_tail(&state->l, &ns->bpf_bound_progs);
227 
228 	prog->aux->offload->dev_priv = state;
229 
230 	return 0;
231 }
232 
233 static void nsim_bpf_destroy_prog(struct bpf_prog *prog)
234 {
235 	struct nsim_bpf_bound_prog *state;
236 
237 	state = prog->aux->offload->dev_priv;
238 	WARN(state->is_loaded,
239 	     "offload state destroyed while program still bound");
240 	debugfs_remove_recursive(state->ddir);
241 	list_del(&state->l);
242 	kfree(state);
243 }
244 
245 static int nsim_setup_prog_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
246 {
247 	if (bpf->prog && bpf->prog->aux->offload) {
248 		NSIM_EA(bpf->extack, "attempt to load offloaded prog to drv");
249 		return -EINVAL;
250 	}
251 	if (ns->netdev->mtu > NSIM_XDP_MAX_MTU) {
252 		NSIM_EA(bpf->extack, "MTU too large w/ XDP enabled");
253 		return -EINVAL;
254 	}
255 	if (nsim_xdp_offload_active(ns)) {
256 		NSIM_EA(bpf->extack, "xdp offload active, can't load drv prog");
257 		return -EBUSY;
258 	}
259 	return 0;
260 }
261 
262 static int
263 nsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
264 {
265 	struct nsim_bpf_bound_prog *state;
266 
267 	if (!bpf->prog)
268 		return 0;
269 
270 	if (!bpf->prog->aux->offload) {
271 		NSIM_EA(bpf->extack, "xdpoffload of non-bound program");
272 		return -EINVAL;
273 	}
274 	if (bpf->prog->aux->offload->netdev != ns->netdev) {
275 		NSIM_EA(bpf->extack, "program bound to different dev");
276 		return -EINVAL;
277 	}
278 
279 	state = bpf->prog->aux->offload->dev_priv;
280 	if (WARN_ON(strcmp(state->state, "xlated"))) {
281 		NSIM_EA(bpf->extack, "offloading program in bad state");
282 		return -EINVAL;
283 	}
284 	return 0;
285 }
286 
287 int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf)
288 {
289 	struct netdevsim *ns = netdev_priv(dev);
290 	struct nsim_bpf_bound_prog *state;
291 	int err;
292 
293 	ASSERT_RTNL();
294 
295 	switch (bpf->command) {
296 	case BPF_OFFLOAD_VERIFIER_PREP:
297 		if (!ns->bpf_bind_accept)
298 			return -EOPNOTSUPP;
299 
300 		err = nsim_bpf_create_prog(ns, bpf->verifier.prog);
301 		if (err)
302 			return err;
303 
304 		bpf->verifier.ops = &nsim_bpf_analyzer_ops;
305 		return 0;
306 	case BPF_OFFLOAD_TRANSLATE:
307 		state = bpf->offload.prog->aux->offload->dev_priv;
308 
309 		state->state = "xlated";
310 		return 0;
311 	case BPF_OFFLOAD_DESTROY:
312 		nsim_bpf_destroy_prog(bpf->offload.prog);
313 		return 0;
314 	case XDP_QUERY_PROG:
315 		bpf->prog_attached = ns->xdp_prog_mode;
316 		bpf->prog_id = ns->xdp_prog ? ns->xdp_prog->aux->id : 0;
317 		bpf->prog_flags = ns->xdp_prog ? ns->xdp_flags : 0;
318 		return 0;
319 	case XDP_SETUP_PROG:
320 		err = nsim_setup_prog_checks(ns, bpf);
321 		if (err)
322 			return err;
323 
324 		return nsim_xdp_set_prog(ns, bpf);
325 	case XDP_SETUP_PROG_HW:
326 		err = nsim_setup_prog_hw_checks(ns, bpf);
327 		if (err)
328 			return err;
329 
330 		return nsim_xdp_set_prog(ns, bpf);
331 	default:
332 		return -EINVAL;
333 	}
334 }
335 
336 int nsim_bpf_init(struct netdevsim *ns)
337 {
338 	INIT_LIST_HEAD(&ns->bpf_bound_progs);
339 
340 	debugfs_create_u32("bpf_offloaded_id", 0400, ns->ddir,
341 			   &ns->bpf_offloaded_id);
342 
343 	ns->bpf_bind_accept = true;
344 	debugfs_create_bool("bpf_bind_accept", 0600, ns->ddir,
345 			    &ns->bpf_bind_accept);
346 	debugfs_create_u32("bpf_bind_verifier_delay", 0600, ns->ddir,
347 			   &ns->bpf_bind_verifier_delay);
348 	ns->ddir_bpf_bound_progs =
349 		debugfs_create_dir("bpf_bound_progs", ns->ddir);
350 	if (IS_ERR_OR_NULL(ns->ddir_bpf_bound_progs))
351 		return -ENOMEM;
352 
353 	ns->bpf_tc_accept = true;
354 	debugfs_create_bool("bpf_tc_accept", 0600, ns->ddir,
355 			    &ns->bpf_tc_accept);
356 	debugfs_create_bool("bpf_tc_non_bound_accept", 0600, ns->ddir,
357 			    &ns->bpf_tc_non_bound_accept);
358 	ns->bpf_xdpdrv_accept = true;
359 	debugfs_create_bool("bpf_xdpdrv_accept", 0600, ns->ddir,
360 			    &ns->bpf_xdpdrv_accept);
361 	ns->bpf_xdpoffload_accept = true;
362 	debugfs_create_bool("bpf_xdpoffload_accept", 0600, ns->ddir,
363 			    &ns->bpf_xdpoffload_accept);
364 
365 	return 0;
366 }
367 
368 void nsim_bpf_uninit(struct netdevsim *ns)
369 {
370 	WARN_ON(!list_empty(&ns->bpf_bound_progs));
371 	WARN_ON(ns->xdp_prog);
372 	WARN_ON(ns->bpf_offloaded);
373 }
374