xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/bpf/main.c (revision 9dae47aba0a055f761176d9297371d5bb24289ec)
1 /*
2  * Copyright (C) 2017 Netronome Systems, Inc.
3  *
4  * This software is dual 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 or the BSD 2-Clause License provided below.  You have the
7  * option to license this software under the complete terms of either license.
8  *
9  * The BSD 2-Clause License:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      1. Redistributions of source code must retain the above
16  *         copyright notice, this list of conditions and the following
17  *         disclaimer.
18  *
19  *      2. Redistributions in binary form must reproduce the above
20  *         copyright notice, this list of conditions and the following
21  *         disclaimer in the documentation and/or other materials
22  *         provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33 
34 #include <net/pkt_cls.h>
35 
36 #include "../nfpcore/nfp_cpp.h"
37 #include "../nfpcore/nfp_nffw.h"
38 #include "../nfp_app.h"
39 #include "../nfp_main.h"
40 #include "../nfp_net.h"
41 #include "../nfp_port.h"
42 #include "fw.h"
43 #include "main.h"
44 
45 static bool nfp_net_ebpf_capable(struct nfp_net *nn)
46 {
47 #ifdef __LITTLE_ENDIAN
48 	if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
49 	    nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
50 		return true;
51 #endif
52 	return false;
53 }
54 
55 static int
56 nfp_bpf_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
57 		    struct bpf_prog *prog)
58 {
59 	bool running, xdp_running;
60 	int ret;
61 
62 	if (!nfp_net_ebpf_capable(nn))
63 		return -EINVAL;
64 
65 	running = nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
66 	xdp_running = running && nn->dp.bpf_offload_xdp;
67 
68 	if (!prog && !xdp_running)
69 		return 0;
70 	if (prog && running && !xdp_running)
71 		return -EBUSY;
72 
73 	ret = nfp_net_bpf_offload(nn, prog, running);
74 	/* Stop offload if replace not possible */
75 	if (ret && prog)
76 		nfp_bpf_xdp_offload(app, nn, NULL);
77 
78 	nn->dp.bpf_offload_xdp = prog && !ret;
79 	return ret;
80 }
81 
82 static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
83 {
84 	return nfp_net_ebpf_capable(nn) ? "BPF" : "";
85 }
86 
87 static int
88 nfp_bpf_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
89 {
90 	int err;
91 
92 	nn->app_priv = kzalloc(sizeof(struct nfp_bpf_vnic), GFP_KERNEL);
93 	if (!nn->app_priv)
94 		return -ENOMEM;
95 
96 	err = nfp_app_nic_vnic_alloc(app, nn, id);
97 	if (err)
98 		goto err_free_priv;
99 
100 	return 0;
101 err_free_priv:
102 	kfree(nn->app_priv);
103 	return err;
104 }
105 
106 static void nfp_bpf_vnic_free(struct nfp_app *app, struct nfp_net *nn)
107 {
108 	struct nfp_bpf_vnic *bv = nn->app_priv;
109 
110 	WARN_ON(bv->tc_prog);
111 	kfree(bv);
112 }
113 
114 static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
115 				     void *type_data, void *cb_priv)
116 {
117 	struct tc_cls_bpf_offload *cls_bpf = type_data;
118 	struct nfp_net *nn = cb_priv;
119 	struct bpf_prog *oldprog;
120 	struct nfp_bpf_vnic *bv;
121 	int err;
122 
123 	if (type != TC_SETUP_CLSBPF ||
124 	    !tc_can_offload(nn->dp.netdev) ||
125 	    !nfp_net_ebpf_capable(nn) ||
126 	    cls_bpf->common.protocol != htons(ETH_P_ALL) ||
127 	    cls_bpf->common.chain_index)
128 		return -EOPNOTSUPP;
129 
130 	/* Only support TC direct action */
131 	if (!cls_bpf->exts_integrated ||
132 	    tcf_exts_has_actions(cls_bpf->exts)) {
133 		nn_err(nn, "only direct action with no legacy actions supported\n");
134 		return -EOPNOTSUPP;
135 	}
136 
137 	if (cls_bpf->command != TC_CLSBPF_OFFLOAD)
138 		return -EOPNOTSUPP;
139 
140 	bv = nn->app_priv;
141 	oldprog = cls_bpf->oldprog;
142 
143 	/* Don't remove if oldprog doesn't match driver's state */
144 	if (bv->tc_prog != oldprog) {
145 		oldprog = NULL;
146 		if (!cls_bpf->prog)
147 			return 0;
148 	}
149 
150 	err = nfp_net_bpf_offload(nn, cls_bpf->prog, oldprog);
151 	if (err)
152 		return err;
153 
154 	bv->tc_prog = cls_bpf->prog;
155 	return 0;
156 }
157 
158 static int nfp_bpf_setup_tc_block(struct net_device *netdev,
159 				  struct tc_block_offload *f)
160 {
161 	struct nfp_net *nn = netdev_priv(netdev);
162 
163 	if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
164 		return -EOPNOTSUPP;
165 
166 	switch (f->command) {
167 	case TC_BLOCK_BIND:
168 		return tcf_block_cb_register(f->block,
169 					     nfp_bpf_setup_tc_block_cb,
170 					     nn, nn);
171 	case TC_BLOCK_UNBIND:
172 		tcf_block_cb_unregister(f->block,
173 					nfp_bpf_setup_tc_block_cb,
174 					nn);
175 		return 0;
176 	default:
177 		return -EOPNOTSUPP;
178 	}
179 }
180 
181 static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
182 			    enum tc_setup_type type, void *type_data)
183 {
184 	switch (type) {
185 	case TC_SETUP_BLOCK:
186 		return nfp_bpf_setup_tc_block(netdev, type_data);
187 	default:
188 		return -EOPNOTSUPP;
189 	}
190 }
191 
192 static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn)
193 {
194 	return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
195 }
196 
197 static int
198 nfp_bpf_parse_cap_adjust_head(struct nfp_app_bpf *bpf, void __iomem *value,
199 			      u32 length)
200 {
201 	struct nfp_bpf_cap_tlv_adjust_head __iomem *cap = value;
202 	struct nfp_cpp *cpp = bpf->app->pf->cpp;
203 
204 	if (length < sizeof(*cap)) {
205 		nfp_err(cpp, "truncated adjust_head TLV: %d\n", length);
206 		return -EINVAL;
207 	}
208 
209 	bpf->adjust_head.flags = readl(&cap->flags);
210 	bpf->adjust_head.off_min = readl(&cap->off_min);
211 	bpf->adjust_head.off_max = readl(&cap->off_max);
212 	bpf->adjust_head.guaranteed_sub = readl(&cap->guaranteed_sub);
213 	bpf->adjust_head.guaranteed_add = readl(&cap->guaranteed_add);
214 
215 	if (bpf->adjust_head.off_min > bpf->adjust_head.off_max) {
216 		nfp_err(cpp, "invalid adjust_head TLV: min > max\n");
217 		return -EINVAL;
218 	}
219 	if (!FIELD_FIT(UR_REG_IMM_MAX, bpf->adjust_head.off_min) ||
220 	    !FIELD_FIT(UR_REG_IMM_MAX, bpf->adjust_head.off_max)) {
221 		nfp_warn(cpp, "disabling adjust_head - driver expects min/max to fit in as immediates\n");
222 		memset(&bpf->adjust_head, 0, sizeof(bpf->adjust_head));
223 		return 0;
224 	}
225 
226 	return 0;
227 }
228 
229 static int nfp_bpf_parse_capabilities(struct nfp_app *app)
230 {
231 	struct nfp_cpp *cpp = app->pf->cpp;
232 	struct nfp_cpp_area *area;
233 	u8 __iomem *mem, *start;
234 
235 	mem = nfp_rtsym_map(app->pf->rtbl, "_abi_bpf_capabilities", "bpf.cap",
236 			    8, &area);
237 	if (IS_ERR(mem))
238 		return PTR_ERR(mem) == -ENOENT ? 0 : PTR_ERR(mem);
239 
240 	start = mem;
241 	while (mem - start + 8 < nfp_cpp_area_size(area)) {
242 		u8 __iomem *value;
243 		u32 type, length;
244 
245 		type = readl(mem);
246 		length = readl(mem + 4);
247 		value = mem + 8;
248 
249 		mem += 8 + length;
250 		if (mem - start > nfp_cpp_area_size(area))
251 			goto err_release_free;
252 
253 		switch (type) {
254 		case NFP_BPF_CAP_TYPE_ADJUST_HEAD:
255 			if (nfp_bpf_parse_cap_adjust_head(app->priv, value,
256 							  length))
257 				goto err_release_free;
258 			break;
259 		default:
260 			nfp_dbg(cpp, "unknown BPF capability: %d\n", type);
261 			break;
262 		}
263 	}
264 	if (mem - start != nfp_cpp_area_size(area)) {
265 		nfp_err(cpp, "BPF capabilities left after parsing, parsed:%zd total length:%zu\n",
266 			mem - start, nfp_cpp_area_size(area));
267 		goto err_release_free;
268 	}
269 
270 	nfp_cpp_area_release_free(area);
271 
272 	return 0;
273 
274 err_release_free:
275 	nfp_err(cpp, "invalid BPF capabilities at offset:%zd\n", mem - start);
276 	nfp_cpp_area_release_free(area);
277 	return -EINVAL;
278 }
279 
280 static int nfp_bpf_init(struct nfp_app *app)
281 {
282 	struct nfp_app_bpf *bpf;
283 	int err;
284 
285 	bpf = kzalloc(sizeof(*bpf), GFP_KERNEL);
286 	if (!bpf)
287 		return -ENOMEM;
288 	bpf->app = app;
289 	app->priv = bpf;
290 
291 	err = nfp_bpf_parse_capabilities(app);
292 	if (err)
293 		goto err_free_bpf;
294 
295 	return 0;
296 
297 err_free_bpf:
298 	kfree(bpf);
299 	return err;
300 }
301 
302 static void nfp_bpf_clean(struct nfp_app *app)
303 {
304 	kfree(app->priv);
305 }
306 
307 const struct nfp_app_type app_bpf = {
308 	.id		= NFP_APP_BPF_NIC,
309 	.name		= "ebpf",
310 
311 	.init		= nfp_bpf_init,
312 	.clean		= nfp_bpf_clean,
313 
314 	.extra_cap	= nfp_bpf_extra_cap,
315 
316 	.vnic_alloc	= nfp_bpf_vnic_alloc,
317 	.vnic_free	= nfp_bpf_vnic_free,
318 
319 	.setup_tc	= nfp_bpf_setup_tc,
320 	.tc_busy	= nfp_bpf_tc_busy,
321 	.xdp_offload	= nfp_bpf_xdp_offload,
322 
323 	.bpf_verifier_prep	= nfp_bpf_verifier_prep,
324 	.bpf_translate		= nfp_bpf_translate,
325 	.bpf_destroy		= nfp_bpf_destroy,
326 };
327