From patchwork Fri Jan 12 04:29:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 859490 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="N3KPFPyI"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zHqXy2VHnz9sQm for ; Fri, 12 Jan 2018 15:30:10 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933279AbeALEaD (ORCPT ); Thu, 11 Jan 2018 23:30:03 -0500 Received: from mail-pg0-f67.google.com ([74.125.83.67]:45261 "EHLO mail-pg0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933254AbeALE37 (ORCPT ); Thu, 11 Jan 2018 23:29:59 -0500 Received: by mail-pg0-f67.google.com with SMTP id c194so3792451pga.12 for ; Thu, 11 Jan 2018 20:29:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Gv4ddaWGw95w/1ZZRKS1EFfIvLqCFaTjbkiF82Y1kyo=; b=N3KPFPyIjJ5dfq91BrAmGDu0TICIDUQvRMILmloIw1wjeAhUTGbZqQJpGk6H2rL22c CaUcRTc0/1ah1SB5lozvLKd4iJ0JXdmEV2gC4seeW4CNh10U7sPKbl/PNClnuv8oSiOu +P4YjBa4Hm3EytgtMHVmfGf6X0dcxlDEh+zNiq/M52I4oRvF0mq6jTcL46rl36NDwPmI XTQSOg2OyfTgqnYSTtFn5O94ScEB4mj8jeGNbz6ypNbVsVqqm9Bcb7UglRSaCB0ET2MQ JkD/0GZfg1tFiR7JdCnpLgbMIiM2dfgTL2ZL25z2givgSZe771LtI+pSWlvTPUyLrqJS YCAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Gv4ddaWGw95w/1ZZRKS1EFfIvLqCFaTjbkiF82Y1kyo=; b=Q5SA1oHwyf1LUcWhOfrBGGmP0NJoD6KIfecdDVKe+dfux/EpQT36gQ3DNFRI3HgueA q0YLCNJw9YXgPzCWpzfw42qm5tTNn4hfeyePp62iE0kJg3qzfItfhTukJ2icWfs7JHf1 M0Ybipinu5+XeA2OEIy+dLoCc93vaAzaQkIyc4ZqIO2rIa6Ma0viJ6cCy53fcWV6QcKD MhbPhX2gZDG3Sk0eLxv+XT2g+1k51UWlZhC6WqqmhVSCQ2qP776qpKKn7c0vvrz0TnVv zeJ4xUUu8F2PCI+pcYoaeKJ2RFgSeAU5vn7h5LbJin4UXMuexpBXddvfTi8m/CN7mQKn 6uvA== X-Gm-Message-State: AKGB3mLt5PiHIvldox3vqkRTb9Q0Nma33fhVr53liIOucBV9gVjGuycu VU40hPrWQJTjbvGFt6uK1UpmL9Nr X-Google-Smtp-Source: ACJfBouq8zd9PG+rjth9FlIMYsyRsldbz8LENC0fbduqqALcxGLVRSq3G3kBqeM1XDD0DqViu/aeaw== X-Received: by 10.98.249.7 with SMTP id o7mr22430935pfh.107.1515731398547; Thu, 11 Jan 2018 20:29:58 -0800 (PST) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id e8sm45863875pfk.6.2018.01.11.20.29.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 11 Jan 2018 20:29:58 -0800 (PST) From: Jakub Kicinski To: alexei.starovoitov@gmail.com, daniel@iogearbox.net, davem@davemloft.net Cc: netdev@vger.kernel.org, oss-drivers@netronome.com, tehnerd@fb.com, Jakub Kicinski Subject: [PATCH bpf-next v2 15/15] nfp: bpf: implement bpf map offload Date: Thu, 11 Jan 2018 20:29:17 -0800 Message-Id: <20180112042917.10348-16-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180112042917.10348-1-jakub.kicinski@netronome.com> References: <20180112042917.10348-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Plug in to the stack's map offload callbacks for BPF map offload. Get next call needs some special handling on the FW side, since we can't send a NULL pointer to the FW there is a get first entry FW command. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet --- drivers/net/ethernet/netronome/nfp/bpf/main.c | 1 + drivers/net/ethernet/netronome/nfp/bpf/main.h | 4 + drivers/net/ethernet/netronome/nfp/bpf/offload.c | 104 +++++++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c index 7d5cc59feb7e..8823c8360047 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c @@ -381,6 +381,7 @@ static void nfp_bpf_clean(struct nfp_app *app) WARN_ON(!skb_queue_empty(&bpf->cmsg_replies)); WARN_ON(!list_empty(&bpf->map_list)); + WARN_ON(bpf->maps_in_use || bpf->map_elems_in_use); kfree(bpf); } diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h index 59197535c465..b80e75a8ecda 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/main.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -108,6 +108,8 @@ enum pkt_vec { * @cmsg_wq: work queue for waiting for cmsg replies * * @map_list: list of offloaded maps + * @maps_in_use: number of currently offloaded maps + * @map_elems_in_use: number of elements allocated to offloaded maps * * @adjust_head: adjust head capability * @flags: extra flags for adjust head @@ -138,6 +140,8 @@ struct nfp_app_bpf { struct wait_queue_head cmsg_wq; struct list_head map_list; + unsigned int maps_in_use; + unsigned int map_elems_in_use; struct nfp_bpf_cap_adjust_head { u32 flags; diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index 6590228d3755..e2859b2e9c6a 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -36,6 +36,9 @@ * Netronome network device driver: TC offload functions for PF and VF */ +#define pr_fmt(fmt) "NFP net bpf: " fmt + +#include #include #include #include @@ -153,6 +156,103 @@ static int nfp_bpf_destroy(struct nfp_net *nn, struct bpf_prog *prog) return 0; } +static int +nfp_bpf_map_get_next_key(struct bpf_offloaded_map *offmap, + void *key, void *next_key) +{ + if (!key) + return nfp_bpf_ctrl_getfirst_entry(offmap, next_key); + return nfp_bpf_ctrl_getnext_entry(offmap, key, next_key); +} + +static int +nfp_bpf_map_delete_elem(struct bpf_offloaded_map *offmap, void *key) +{ + return nfp_bpf_ctrl_del_entry(offmap, key); +} + +static const struct bpf_map_dev_ops nfp_bpf_map_ops = { + .map_get_next_key = nfp_bpf_map_get_next_key, + .map_lookup_elem = nfp_bpf_ctrl_lookup_entry, + .map_update_elem = nfp_bpf_ctrl_update_entry, + .map_delete_elem = nfp_bpf_map_delete_elem, +}; + +static int +nfp_bpf_map_alloc(struct nfp_app_bpf *bpf, struct bpf_offloaded_map *offmap) +{ + struct nfp_bpf_map *nfp_map; + long long int res; + + if (!bpf->maps.types) + return -EOPNOTSUPP; + + if (offmap->map.map_flags || + offmap->map.numa_node != NUMA_NO_NODE) { + pr_info("map flags are not supported\n"); + return -EINVAL; + } + + if (!(bpf->maps.types & 1 << offmap->map.map_type)) { + pr_info("map type not supported\n"); + return -EOPNOTSUPP; + } + if (bpf->maps.max_maps == bpf->maps_in_use) { + pr_info("too many maps for a device\n"); + return -ENOMEM; + } + if (bpf->maps.max_elems - bpf->map_elems_in_use < + offmap->map.max_entries) { + pr_info("map with too many elements: %u, left: %u\n", + offmap->map.max_entries, + bpf->maps.max_elems - bpf->map_elems_in_use); + return -ENOMEM; + } + if (offmap->map.key_size > bpf->maps.max_key_sz || + offmap->map.value_size > bpf->maps.max_val_sz || + round_up(offmap->map.key_size, 8) + + round_up(offmap->map.value_size, 8) > bpf->maps.max_elem_sz) { + pr_info("elements don't fit in device constraints\n"); + return -ENOMEM; + } + + nfp_map = kzalloc(sizeof(*nfp_map), GFP_USER); + if (!nfp_map) + return -ENOMEM; + + offmap->dev_priv = nfp_map; + nfp_map->offmap = offmap; + nfp_map->bpf = bpf; + + res = nfp_bpf_ctrl_alloc_map(bpf, &offmap->map); + if (res < 0) { + kfree(nfp_map); + return res; + } + + nfp_map->tid = res; + offmap->dev_ops = &nfp_bpf_map_ops; + bpf->maps_in_use++; + bpf->map_elems_in_use += offmap->map.max_entries; + list_add_tail(&nfp_map->l, &bpf->map_list); + + return 0; +} + +static int +nfp_bpf_map_free(struct nfp_app_bpf *bpf, struct bpf_offloaded_map *offmap) +{ + struct nfp_bpf_map *nfp_map = offmap->dev_priv; + + nfp_bpf_ctrl_free_map(bpf, nfp_map); + list_del_init(&nfp_map->l); + bpf->map_elems_in_use -= offmap->map.max_entries; + bpf->maps_in_use--; + kfree(nfp_map); + + return 0; +} + int nfp_ndo_bpf(struct nfp_app *app, struct nfp_net *nn, struct netdev_bpf *bpf) { switch (bpf->command) { @@ -162,6 +262,10 @@ int nfp_ndo_bpf(struct nfp_app *app, struct nfp_net *nn, struct netdev_bpf *bpf) return nfp_bpf_translate(nn, bpf->offload.prog); case BPF_OFFLOAD_DESTROY: return nfp_bpf_destroy(nn, bpf->offload.prog); + case BPF_OFFLOAD_MAP_ALLOC: + return nfp_bpf_map_alloc(app->priv, bpf->offmap); + case BPF_OFFLOAD_MAP_FREE: + return nfp_bpf_map_free(app->priv, bpf->offmap); default: return -EINVAL; }