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 
85c496291cSJakub Kicinski static void nfp_bpf_vnic_free(struct nfp_app *app, struct nfp_net *nn)
86bb45e51cSJakub Kicinski {
87bb45e51cSJakub Kicinski 	if (nn->dp.bpf_offload_xdp)
88bb45e51cSJakub Kicinski 		nfp_bpf_xdp_offload(app, nn, NULL);
89bb45e51cSJakub Kicinski }
90bb45e51cSJakub Kicinski 
9190d97315SJiri Pirko static int nfp_bpf_setup_tc_block_cb(enum tc_setup_type type,
9290d97315SJiri Pirko 				     void *type_data, void *cb_priv)
93bb45e51cSJakub Kicinski {
94de4784caSJiri Pirko 	struct tc_cls_bpf_offload *cls_bpf = type_data;
9590d97315SJiri Pirko 	struct nfp_net *nn = cb_priv;
96bb45e51cSJakub Kicinski 
979ce7a956SJakub Kicinski 	if (type != TC_SETUP_CLSBPF ||
989ce7a956SJakub Kicinski 	    !tc_can_offload(nn->dp.netdev) ||
999ce7a956SJakub Kicinski 	    !nfp_net_ebpf_capable(nn) ||
1005fd9fc4eSJiri Pirko 	    cls_bpf->common.protocol != htons(ETH_P_ALL) ||
1015fd9fc4eSJiri Pirko 	    cls_bpf->common.chain_index)
102bb45e51cSJakub Kicinski 		return -EOPNOTSUPP;
103f449657fSJakub Kicinski 	if (nn->dp.bpf_offload_xdp)
104f449657fSJakub Kicinski 		return -EBUSY;
105f449657fSJakub Kicinski 
106012bb8a8SJakub Kicinski 	/* Only support TC direct action */
107012bb8a8SJakub Kicinski 	if (!cls_bpf->exts_integrated ||
108012bb8a8SJakub Kicinski 	    tcf_exts_has_actions(cls_bpf->exts)) {
109012bb8a8SJakub Kicinski 		nn_err(nn, "only direct action with no legacy actions supported\n");
110012bb8a8SJakub Kicinski 		return -EOPNOTSUPP;
111012bb8a8SJakub Kicinski 	}
112012bb8a8SJakub Kicinski 
113102740bdSJakub Kicinski 	if (cls_bpf->command != TC_CLSBPF_OFFLOAD)
11490d97315SJiri Pirko 		return -EOPNOTSUPP;
115102740bdSJakub Kicinski 
116102740bdSJakub Kicinski 	return nfp_net_bpf_offload(nn, cls_bpf->prog, cls_bpf->oldprog);
11790d97315SJiri Pirko }
11890d97315SJiri Pirko 
11990d97315SJiri Pirko static int nfp_bpf_setup_tc_block(struct net_device *netdev,
12090d97315SJiri Pirko 				  struct tc_block_offload *f)
12190d97315SJiri Pirko {
12290d97315SJiri Pirko 	struct nfp_net *nn = netdev_priv(netdev);
12390d97315SJiri Pirko 
12490d97315SJiri Pirko 	if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
12590d97315SJiri Pirko 		return -EOPNOTSUPP;
12690d97315SJiri Pirko 
12790d97315SJiri Pirko 	switch (f->command) {
12890d97315SJiri Pirko 	case TC_BLOCK_BIND:
12990d97315SJiri Pirko 		return tcf_block_cb_register(f->block,
13090d97315SJiri Pirko 					     nfp_bpf_setup_tc_block_cb,
13190d97315SJiri Pirko 					     nn, nn);
13290d97315SJiri Pirko 	case TC_BLOCK_UNBIND:
13390d97315SJiri Pirko 		tcf_block_cb_unregister(f->block,
13490d97315SJiri Pirko 					nfp_bpf_setup_tc_block_cb,
13590d97315SJiri Pirko 					nn);
13690d97315SJiri Pirko 		return 0;
13790d97315SJiri Pirko 	default:
13890d97315SJiri Pirko 		return -EOPNOTSUPP;
13990d97315SJiri Pirko 	}
14090d97315SJiri Pirko }
14190d97315SJiri Pirko 
14290d97315SJiri Pirko static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
14390d97315SJiri Pirko 			    enum tc_setup_type type, void *type_data)
14490d97315SJiri Pirko {
14590d97315SJiri Pirko 	switch (type) {
14690d97315SJiri Pirko 	case TC_SETUP_BLOCK:
14790d97315SJiri Pirko 		return nfp_bpf_setup_tc_block(netdev, type_data);
14890d97315SJiri Pirko 	default:
14990d97315SJiri Pirko 		return -EOPNOTSUPP;
15090d97315SJiri Pirko 	}
151bb45e51cSJakub Kicinski }
152bb45e51cSJakub Kicinski 
153bb45e51cSJakub Kicinski static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn)
154bb45e51cSJakub Kicinski {
155bb45e51cSJakub Kicinski 	return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
156bb45e51cSJakub Kicinski }
157bb45e51cSJakub Kicinski 
1588aa0cb00SJakub Kicinski const struct nfp_app_type app_bpf = {
1598aa0cb00SJakub Kicinski 	.id		= NFP_APP_BPF_NIC,
1602707d6f1SJakub Kicinski 	.name		= "ebpf",
1618aa0cb00SJakub Kicinski 
162bb45e51cSJakub Kicinski 	.extra_cap	= nfp_bpf_extra_cap,
163bb45e51cSJakub Kicinski 
164012bb8a8SJakub Kicinski 	.vnic_alloc	= nfp_app_nic_vnic_alloc,
165c496291cSJakub Kicinski 	.vnic_free	= nfp_bpf_vnic_free,
166bb45e51cSJakub Kicinski 
167bb45e51cSJakub Kicinski 	.setup_tc	= nfp_bpf_setup_tc,
168bb45e51cSJakub Kicinski 	.tc_busy	= nfp_bpf_tc_busy,
169bb45e51cSJakub Kicinski 	.xdp_offload	= nfp_bpf_xdp_offload,
170c6c580d7SJakub Kicinski 
171c6c580d7SJakub Kicinski 	.bpf_verifier_prep	= nfp_bpf_verifier_prep,
172c6c580d7SJakub Kicinski 	.bpf_translate		= nfp_bpf_translate,
173c6c580d7SJakub Kicinski 	.bpf_destroy		= nfp_bpf_destroy,
1748aa0cb00SJakub Kicinski };
175