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 1139ce7a956SJakub Kicinski switch (cls_bpf->command) { 1149ce7a956SJakub Kicinski case TC_CLSBPF_REPLACE: 115e4a91cd5SJakub Kicinski return nfp_net_bpf_offload(nn, cls_bpf->prog, true); 1169ce7a956SJakub Kicinski case TC_CLSBPF_ADD: 117e4a91cd5SJakub Kicinski return nfp_net_bpf_offload(nn, cls_bpf->prog, false); 1189ce7a956SJakub Kicinski case TC_CLSBPF_DESTROY: 119e4a91cd5SJakub Kicinski return nfp_net_bpf_offload(nn, NULL, true); 12090d97315SJiri Pirko default: 12190d97315SJiri Pirko return -EOPNOTSUPP; 12290d97315SJiri Pirko } 12390d97315SJiri Pirko } 12490d97315SJiri Pirko 12590d97315SJiri Pirko static int nfp_bpf_setup_tc_block(struct net_device *netdev, 12690d97315SJiri Pirko struct tc_block_offload *f) 12790d97315SJiri Pirko { 12890d97315SJiri Pirko struct nfp_net *nn = netdev_priv(netdev); 12990d97315SJiri Pirko 13090d97315SJiri Pirko if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS) 13190d97315SJiri Pirko return -EOPNOTSUPP; 13290d97315SJiri Pirko 13390d97315SJiri Pirko switch (f->command) { 13490d97315SJiri Pirko case TC_BLOCK_BIND: 13590d97315SJiri Pirko return tcf_block_cb_register(f->block, 13690d97315SJiri Pirko nfp_bpf_setup_tc_block_cb, 13790d97315SJiri Pirko nn, nn); 13890d97315SJiri Pirko case TC_BLOCK_UNBIND: 13990d97315SJiri Pirko tcf_block_cb_unregister(f->block, 14090d97315SJiri Pirko nfp_bpf_setup_tc_block_cb, 14190d97315SJiri Pirko nn); 14290d97315SJiri Pirko return 0; 14390d97315SJiri Pirko default: 14490d97315SJiri Pirko return -EOPNOTSUPP; 14590d97315SJiri Pirko } 14690d97315SJiri Pirko } 14790d97315SJiri Pirko 14890d97315SJiri Pirko static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev, 14990d97315SJiri Pirko enum tc_setup_type type, void *type_data) 15090d97315SJiri Pirko { 15190d97315SJiri Pirko switch (type) { 15290d97315SJiri Pirko case TC_SETUP_BLOCK: 15390d97315SJiri Pirko return nfp_bpf_setup_tc_block(netdev, type_data); 15490d97315SJiri Pirko default: 15590d97315SJiri Pirko return -EOPNOTSUPP; 15690d97315SJiri Pirko } 157bb45e51cSJakub Kicinski } 158bb45e51cSJakub Kicinski 159bb45e51cSJakub Kicinski static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn) 160bb45e51cSJakub Kicinski { 161bb45e51cSJakub Kicinski return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF; 162bb45e51cSJakub Kicinski } 163bb45e51cSJakub Kicinski 1648aa0cb00SJakub Kicinski const struct nfp_app_type app_bpf = { 1658aa0cb00SJakub Kicinski .id = NFP_APP_BPF_NIC, 1662707d6f1SJakub Kicinski .name = "ebpf", 1678aa0cb00SJakub Kicinski 168bb45e51cSJakub Kicinski .extra_cap = nfp_bpf_extra_cap, 169bb45e51cSJakub Kicinski 170012bb8a8SJakub Kicinski .vnic_alloc = nfp_app_nic_vnic_alloc, 171c496291cSJakub Kicinski .vnic_free = nfp_bpf_vnic_free, 172bb45e51cSJakub Kicinski 173bb45e51cSJakub Kicinski .setup_tc = nfp_bpf_setup_tc, 174bb45e51cSJakub Kicinski .tc_busy = nfp_bpf_tc_busy, 175bb45e51cSJakub Kicinski .xdp_offload = nfp_bpf_xdp_offload, 1768aa0cb00SJakub Kicinski }; 177