xref: /linux/drivers/net/ethernet/netronome/nfp/bpf/main.c (revision d3f89b98)
18aa0cb00SJakub Kicinski /*
28aa0cb00SJakub Kicinski  * Copyright (C) 2017 Netronome Systems, Inc.
38aa0cb00SJakub Kicinski  *
48aa0cb00SJakub Kicinski  * This software is dual licensed under the GNU General License Version 2,
58aa0cb00SJakub Kicinski  * June 1991 as shown in the file COPYING in the top-level directory of this
68aa0cb00SJakub Kicinski  * source tree or the BSD 2-Clause License provided below.  You have the
78aa0cb00SJakub Kicinski  * option to license this software under the complete terms of either license.
88aa0cb00SJakub Kicinski  *
98aa0cb00SJakub Kicinski  * The BSD 2-Clause License:
108aa0cb00SJakub Kicinski  *
118aa0cb00SJakub Kicinski  *     Redistribution and use in source and binary forms, with or
128aa0cb00SJakub Kicinski  *     without modification, are permitted provided that the following
138aa0cb00SJakub Kicinski  *     conditions are met:
148aa0cb00SJakub Kicinski  *
158aa0cb00SJakub Kicinski  *      1. Redistributions of source code must retain the above
168aa0cb00SJakub Kicinski  *         copyright notice, this list of conditions and the following
178aa0cb00SJakub Kicinski  *         disclaimer.
188aa0cb00SJakub Kicinski  *
198aa0cb00SJakub Kicinski  *      2. Redistributions in binary form must reproduce the above
208aa0cb00SJakub Kicinski  *         copyright notice, this list of conditions and the following
218aa0cb00SJakub Kicinski  *         disclaimer in the documentation and/or other materials
228aa0cb00SJakub Kicinski  *         provided with the distribution.
238aa0cb00SJakub Kicinski  *
248aa0cb00SJakub Kicinski  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
258aa0cb00SJakub Kicinski  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
268aa0cb00SJakub Kicinski  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
278aa0cb00SJakub Kicinski  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
288aa0cb00SJakub Kicinski  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
298aa0cb00SJakub Kicinski  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
308aa0cb00SJakub Kicinski  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
318aa0cb00SJakub Kicinski  * SOFTWARE.
328aa0cb00SJakub Kicinski  */
338aa0cb00SJakub Kicinski 
34bb45e51cSJakub Kicinski #include <net/pkt_cls.h>
35bb45e51cSJakub Kicinski 
368aa0cb00SJakub Kicinski #include "../nfpcore/nfp_cpp.h"
378aa0cb00SJakub Kicinski #include "../nfp_app.h"
388aa0cb00SJakub Kicinski #include "../nfp_main.h"
398aa0cb00SJakub Kicinski #include "../nfp_net.h"
408aa0cb00SJakub Kicinski #include "../nfp_port.h"
41bb45e51cSJakub Kicinski #include "main.h"
42bb45e51cSJakub Kicinski 
43bb45e51cSJakub Kicinski static bool nfp_net_ebpf_capable(struct nfp_net *nn)
44bb45e51cSJakub Kicinski {
450f6cf4ddSJakub Kicinski #ifdef __LITTLE_ENDIAN
46bb45e51cSJakub Kicinski 	if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
47bb45e51cSJakub Kicinski 	    nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
48bb45e51cSJakub Kicinski 		return true;
490f6cf4ddSJakub Kicinski #endif
50bb45e51cSJakub Kicinski 	return false;
51bb45e51cSJakub Kicinski }
52bb45e51cSJakub Kicinski 
53bb45e51cSJakub Kicinski static int
54bb45e51cSJakub Kicinski nfp_bpf_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
55bb45e51cSJakub Kicinski 		    struct bpf_prog *prog)
56bb45e51cSJakub Kicinski {
579ce7a956SJakub Kicinski 	bool running, xdp_running;
58bb45e51cSJakub Kicinski 	int ret;
59bb45e51cSJakub Kicinski 
60bb45e51cSJakub Kicinski 	if (!nfp_net_ebpf_capable(nn))
61bb45e51cSJakub Kicinski 		return -EINVAL;
62bb45e51cSJakub Kicinski 
639ce7a956SJakub Kicinski 	running = nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
649ce7a956SJakub Kicinski 	xdp_running = running && nn->dp.bpf_offload_xdp;
65bb45e51cSJakub Kicinski 
669ce7a956SJakub Kicinski 	if (!prog && !xdp_running)
679ce7a956SJakub Kicinski 		return 0;
689ce7a956SJakub Kicinski 	if (prog && running && !xdp_running)
699ce7a956SJakub Kicinski 		return -EBUSY;
709ce7a956SJakub Kicinski 
71e4a91cd5SJakub Kicinski 	ret = nfp_net_bpf_offload(nn, prog, running);
72bb45e51cSJakub Kicinski 	/* Stop offload if replace not possible */
739ce7a956SJakub Kicinski 	if (ret && prog)
74bb45e51cSJakub Kicinski 		nfp_bpf_xdp_offload(app, nn, NULL);
759ce7a956SJakub Kicinski 
76bb45e51cSJakub Kicinski 	nn->dp.bpf_offload_xdp = prog && !ret;
77bb45e51cSJakub Kicinski 	return ret;
78bb45e51cSJakub Kicinski }
79bb45e51cSJakub Kicinski 
80bb45e51cSJakub Kicinski static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
81bb45e51cSJakub Kicinski {
82bb45e51cSJakub Kicinski 	return nfp_net_ebpf_capable(nn) ? "BPF" : "";
83bb45e51cSJakub Kicinski }
848aa0cb00SJakub Kicinski 
85*d3f89b98SJakub Kicinski static int
86*d3f89b98SJakub Kicinski nfp_bpf_vnic_alloc(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
87*d3f89b98SJakub Kicinski {
88*d3f89b98SJakub Kicinski 	int err;
89*d3f89b98SJakub Kicinski 
90*d3f89b98SJakub Kicinski 	nn->app_priv = kzalloc(sizeof(struct nfp_bpf_vnic), GFP_KERNEL);
91*d3f89b98SJakub Kicinski 	if (!nn->app_priv)
92*d3f89b98SJakub Kicinski 		return -ENOMEM;
93*d3f89b98SJakub Kicinski 
94*d3f89b98SJakub Kicinski 	err = nfp_app_nic_vnic_alloc(app, nn, id);
95*d3f89b98SJakub Kicinski 	if (err)
96*d3f89b98SJakub Kicinski 		goto err_free_priv;
97*d3f89b98SJakub Kicinski 
98*d3f89b98SJakub Kicinski 	return 0;
99*d3f89b98SJakub Kicinski err_free_priv:
100*d3f89b98SJakub Kicinski 	kfree(nn->app_priv);
101*d3f89b98SJakub Kicinski 	return err;
102*d3f89b98SJakub Kicinski }
103*d3f89b98SJakub Kicinski 
104c496291cSJakub Kicinski static void nfp_bpf_vnic_free(struct nfp_app *app, struct nfp_net *nn)
105bb45e51cSJakub Kicinski {
106*d3f89b98SJakub Kicinski 	struct nfp_bpf_vnic *bv = nn->app_priv;
107*d3f89b98SJakub Kicinski 
108bb45e51cSJakub Kicinski 	if (nn->dp.bpf_offload_xdp)
109bb45e51cSJakub Kicinski 		nfp_bpf_xdp_offload(app, nn, NULL);
110*d3f89b98SJakub Kicinski 	WARN_ON(bv->tc_prog);
111*d3f89b98SJakub Kicinski 	kfree(bv);
112bb45e51cSJakub Kicinski }
113bb45e51cSJakub Kicinski 
11490d97315SJiri Pirko static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
11590d97315SJiri Pirko 				     void *type_data, void *cb_priv)
116bb45e51cSJakub Kicinski {
117de4784caSJiri Pirko 	struct tc_cls_bpf_offload *cls_bpf = type_data;
11890d97315SJiri Pirko 	struct nfp_net *nn = cb_priv;
119*d3f89b98SJakub Kicinski 	struct bpf_prog *oldprog;
120*d3f89b98SJakub Kicinski 	struct nfp_bpf_vnic *bv;
121*d3f89b98SJakub Kicinski 	int err;
122bb45e51cSJakub Kicinski 
1239ce7a956SJakub Kicinski 	if (type != TC_SETUP_CLSBPF ||
1249ce7a956SJakub Kicinski 	    !tc_can_offload(nn->dp.netdev) ||
1259ce7a956SJakub Kicinski 	    !nfp_net_ebpf_capable(nn) ||
1265fd9fc4eSJiri Pirko 	    cls_bpf->common.protocol != htons(ETH_P_ALL) ||
1275fd9fc4eSJiri Pirko 	    cls_bpf->common.chain_index)
128bb45e51cSJakub Kicinski 		return -EOPNOTSUPP;
129f449657fSJakub Kicinski 
130012bb8a8SJakub Kicinski 	/* Only support TC direct action */
131012bb8a8SJakub Kicinski 	if (!cls_bpf->exts_integrated ||
132012bb8a8SJakub Kicinski 	    tcf_exts_has_actions(cls_bpf->exts)) {
133012bb8a8SJakub Kicinski 		nn_err(nn, "only direct action with no legacy actions supported\n");
134012bb8a8SJakub Kicinski 		return -EOPNOTSUPP;
135012bb8a8SJakub Kicinski 	}
136012bb8a8SJakub Kicinski 
137102740bdSJakub Kicinski 	if (cls_bpf->command != TC_CLSBPF_OFFLOAD)
13890d97315SJiri Pirko 		return -EOPNOTSUPP;
139102740bdSJakub Kicinski 
140*d3f89b98SJakub Kicinski 	bv = nn->app_priv;
141*d3f89b98SJakub Kicinski 	oldprog = cls_bpf->oldprog;
142*d3f89b98SJakub Kicinski 
143*d3f89b98SJakub Kicinski 	/* Don't remove if oldprog doesn't match driver's state */
144*d3f89b98SJakub Kicinski 	if (bv->tc_prog != oldprog) {
145*d3f89b98SJakub Kicinski 		oldprog = NULL;
146*d3f89b98SJakub Kicinski 		if (!cls_bpf->prog)
147*d3f89b98SJakub Kicinski 			return 0;
148*d3f89b98SJakub Kicinski 	}
149*d3f89b98SJakub Kicinski 
150*d3f89b98SJakub Kicinski 	err = nfp_net_bpf_offload(nn, cls_bpf->prog, oldprog);
151*d3f89b98SJakub Kicinski 	if (err)
152*d3f89b98SJakub Kicinski 		return err;
153*d3f89b98SJakub Kicinski 
154*d3f89b98SJakub Kicinski 	bv->tc_prog = cls_bpf->prog;
155*d3f89b98SJakub Kicinski 	return 0;
15690d97315SJiri Pirko }
15790d97315SJiri Pirko 
15890d97315SJiri Pirko static int nfp_bpf_setup_tc_block(struct net_device *netdev,
15990d97315SJiri Pirko 				  struct tc_block_offload *f)
16090d97315SJiri Pirko {
16190d97315SJiri Pirko 	struct nfp_net *nn = netdev_priv(netdev);
16290d97315SJiri Pirko 
16390d97315SJiri Pirko 	if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
16490d97315SJiri Pirko 		return -EOPNOTSUPP;
16590d97315SJiri Pirko 
16690d97315SJiri Pirko 	switch (f->command) {
16790d97315SJiri Pirko 	case TC_BLOCK_BIND:
16890d97315SJiri Pirko 		return tcf_block_cb_register(f->block,
16990d97315SJiri Pirko 					     nfp_bpf_setup_tc_block_cb,
17090d97315SJiri Pirko 					     nn, nn);
17190d97315SJiri Pirko 	case TC_BLOCK_UNBIND:
17290d97315SJiri Pirko 		tcf_block_cb_unregister(f->block,
17390d97315SJiri Pirko 					nfp_bpf_setup_tc_block_cb,
17490d97315SJiri Pirko 					nn);
17590d97315SJiri Pirko 		return 0;
17690d97315SJiri Pirko 	default:
17790d97315SJiri Pirko 		return -EOPNOTSUPP;
17890d97315SJiri Pirko 	}
17990d97315SJiri Pirko }
18090d97315SJiri Pirko 
18190d97315SJiri Pirko static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
18290d97315SJiri Pirko 			    enum tc_setup_type type, void *type_data)
18390d97315SJiri Pirko {
18490d97315SJiri Pirko 	switch (type) {
18590d97315SJiri Pirko 	case TC_SETUP_BLOCK:
18690d97315SJiri Pirko 		return nfp_bpf_setup_tc_block(netdev, type_data);
18790d97315SJiri Pirko 	default:
18890d97315SJiri Pirko 		return -EOPNOTSUPP;
18990d97315SJiri Pirko 	}
190bb45e51cSJakub Kicinski }
191bb45e51cSJakub Kicinski 
192bb45e51cSJakub Kicinski static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn)
193bb45e51cSJakub Kicinski {
194bb45e51cSJakub Kicinski 	return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
195bb45e51cSJakub Kicinski }
196bb45e51cSJakub Kicinski 
1978aa0cb00SJakub Kicinski const struct nfp_app_type app_bpf = {
1988aa0cb00SJakub Kicinski 	.id		= NFP_APP_BPF_NIC,
1992707d6f1SJakub Kicinski 	.name		= "ebpf",
2008aa0cb00SJakub Kicinski 
201bb45e51cSJakub Kicinski 	.extra_cap	= nfp_bpf_extra_cap,
202bb45e51cSJakub Kicinski 
203*d3f89b98SJakub Kicinski 	.vnic_alloc	= nfp_bpf_vnic_alloc,
204c496291cSJakub Kicinski 	.vnic_free	= nfp_bpf_vnic_free,
205bb45e51cSJakub Kicinski 
206bb45e51cSJakub Kicinski 	.setup_tc	= nfp_bpf_setup_tc,
207bb45e51cSJakub Kicinski 	.tc_busy	= nfp_bpf_tc_busy,
208bb45e51cSJakub Kicinski 	.xdp_offload	= nfp_bpf_xdp_offload,
209c6c580d7SJakub Kicinski 
210c6c580d7SJakub Kicinski 	.bpf_verifier_prep	= nfp_bpf_verifier_prep,
211c6c580d7SJakub Kicinski 	.bpf_translate		= nfp_bpf_translate,
212c6c580d7SJakub Kicinski 	.bpf_destroy		= nfp_bpf_destroy,
2138aa0cb00SJakub Kicinski };
214