xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/bpf/main.c (revision c127f98ba9aba1818a6ca3a1da5a24653a10d966)
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 "../nfp_app.h"
38 #include "../nfp_main.h"
39 #include "../nfp_net.h"
40 #include "../nfp_port.h"
41 #include "main.h"
42 
43 static bool nfp_net_ebpf_capable(struct nfp_net *nn)
44 {
45 #ifdef __LITTLE_ENDIAN
46 	if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
47 	    nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
48 		return true;
49 #endif
50 	return false;
51 }
52 
53 static int
54 nfp_bpf_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
55 		    struct bpf_prog *prog)
56 {
57 	bool running, xdp_running;
58 	int ret;
59 
60 	if (!nfp_net_ebpf_capable(nn))
61 		return -EINVAL;
62 
63 	running = nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
64 	xdp_running = running && nn->dp.bpf_offload_xdp;
65 
66 	if (!prog && !xdp_running)
67 		return 0;
68 	if (prog && running && !xdp_running)
69 		return -EBUSY;
70 
71 	ret = nfp_net_bpf_offload(nn, prog, running);
72 	/* Stop offload if replace not possible */
73 	if (ret && prog)
74 		nfp_bpf_xdp_offload(app, nn, NULL);
75 
76 	nn->dp.bpf_offload_xdp = prog && !ret;
77 	return ret;
78 }
79 
80 static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
81 {
82 	return nfp_net_ebpf_capable(nn) ? "BPF" : "";
83 }
84 
85 static int
86 nfp_bpf_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
87 {
88 	int err;
89 
90 	nn->app_priv = kzalloc(sizeof(struct nfp_bpf_vnic), GFP_KERNEL);
91 	if (!nn->app_priv)
92 		return -ENOMEM;
93 
94 	err = nfp_app_nic_vnic_alloc(app, nn, id);
95 	if (err)
96 		goto err_free_priv;
97 
98 	return 0;
99 err_free_priv:
100 	kfree(nn->app_priv);
101 	return err;
102 }
103 
104 static void nfp_bpf_vnic_free(struct nfp_app *app, struct nfp_net *nn)
105 {
106 	struct nfp_bpf_vnic *bv = nn->app_priv;
107 
108 	if (nn->dp.bpf_offload_xdp)
109 		nfp_bpf_xdp_offload(app, nn, NULL);
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 const struct nfp_app_type app_bpf = {
198 	.id		= NFP_APP_BPF_NIC,
199 	.name		= "ebpf",
200 
201 	.extra_cap	= nfp_bpf_extra_cap,
202 
203 	.vnic_alloc	= nfp_bpf_vnic_alloc,
204 	.vnic_free	= nfp_bpf_vnic_free,
205 
206 	.setup_tc	= nfp_bpf_setup_tc,
207 	.tc_busy	= nfp_bpf_tc_busy,
208 	.xdp_offload	= nfp_bpf_xdp_offload,
209 
210 	.bpf_verifier_prep	= nfp_bpf_verifier_prep,
211 	.bpf_translate		= nfp_bpf_translate,
212 	.bpf_destroy		= nfp_bpf_destroy,
213 };
214