aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/cmsg.c16
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/fw.h20
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/jit.c76
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.c28
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.h24
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/offload.c172
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/verifier.c78
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_app.c2
8 files changed, 385 insertions, 31 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
index 7e298148ca26..cb87fccb9f6a 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2017 Netronome Systems, Inc. 2 * Copyright (C) 2017-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 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 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -102,6 +102,15 @@ nfp_bpf_cmsg_map_req_alloc(struct nfp_app_bpf *bpf, unsigned int n)
102 return nfp_bpf_cmsg_alloc(bpf, size); 102 return nfp_bpf_cmsg_alloc(bpf, size);
103} 103}
104 104
105static u8 nfp_bpf_cmsg_get_type(struct sk_buff *skb)
106{
107 struct cmsg_hdr *hdr;
108
109 hdr = (struct cmsg_hdr *)skb->data;
110
111 return hdr->type;
112}
113
105static unsigned int nfp_bpf_cmsg_get_tag(struct sk_buff *skb) 114static unsigned int nfp_bpf_cmsg_get_tag(struct sk_buff *skb)
106{ 115{
107 struct cmsg_hdr *hdr; 116 struct cmsg_hdr *hdr;
@@ -431,6 +440,11 @@ void nfp_bpf_ctrl_msg_rx(struct nfp_app *app, struct sk_buff *skb)
431 goto err_free; 440 goto err_free;
432 } 441 }
433 442
443 if (nfp_bpf_cmsg_get_type(skb) == CMSG_TYPE_BPF_EVENT) {
444 nfp_bpf_event_output(bpf, skb);
445 return;
446 }
447
434 nfp_ctrl_lock(bpf->app->ctrl); 448 nfp_ctrl_lock(bpf->app->ctrl);
435 449
436 tag = nfp_bpf_cmsg_get_tag(skb); 450 tag = nfp_bpf_cmsg_get_tag(skb);
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/fw.h b/drivers/net/ethernet/netronome/nfp/bpf/fw.h
index 39639ac28b01..3dbc21653ce5 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/fw.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/fw.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2017 Netronome Systems, Inc. 2 * Copyright (C) 2017-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 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 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -37,6 +37,14 @@
37#include <linux/bitops.h> 37#include <linux/bitops.h>
38#include <linux/types.h> 38#include <linux/types.h>
39 39
40/* Kernel's enum bpf_reg_type is not uABI so people may change it breaking
41 * our FW ABI. In that case we will do translation in the driver.
42 */
43#define NFP_BPF_SCALAR_VALUE 1
44#define NFP_BPF_MAP_VALUE 4
45#define NFP_BPF_STACK 6
46#define NFP_BPF_PACKET_DATA 8
47
40enum bpf_cap_tlv_type { 48enum bpf_cap_tlv_type {
41 NFP_BPF_CAP_TYPE_FUNC = 1, 49 NFP_BPF_CAP_TYPE_FUNC = 1,
42 NFP_BPF_CAP_TYPE_ADJUST_HEAD = 2, 50 NFP_BPF_CAP_TYPE_ADJUST_HEAD = 2,
@@ -81,6 +89,7 @@ enum nfp_bpf_cmsg_type {
81 CMSG_TYPE_MAP_DELETE = 5, 89 CMSG_TYPE_MAP_DELETE = 5,
82 CMSG_TYPE_MAP_GETNEXT = 6, 90 CMSG_TYPE_MAP_GETNEXT = 6,
83 CMSG_TYPE_MAP_GETFIRST = 7, 91 CMSG_TYPE_MAP_GETFIRST = 7,
92 CMSG_TYPE_BPF_EVENT = 8,
84 __CMSG_TYPE_MAP_MAX, 93 __CMSG_TYPE_MAP_MAX,
85}; 94};
86 95
@@ -155,4 +164,13 @@ struct cmsg_reply_map_op {
155 __be32 resv; 164 __be32 resv;
156 struct cmsg_key_value_pair elem[0]; 165 struct cmsg_key_value_pair elem[0];
157}; 166};
167
168struct cmsg_bpf_event {
169 struct cmsg_hdr hdr;
170 __be32 cpu_id;
171 __be64 map_ptr;
172 __be32 data_size;
173 __be32 pkt_size;
174 u8 data[0];
175};
158#endif 176#endif
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
index 65f0791cae0c..326a2085d650 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/jit.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2016-2017 Netronome Systems, Inc. 2 * Copyright (C) 2016-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 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 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -1395,15 +1395,9 @@ static int adjust_head(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
1395static int 1395static int
1396map_call_stack_common(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) 1396map_call_stack_common(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
1397{ 1397{
1398 struct bpf_offloaded_map *offmap;
1399 struct nfp_bpf_map *nfp_map;
1400 bool load_lm_ptr; 1398 bool load_lm_ptr;
1401 u32 ret_tgt; 1399 u32 ret_tgt;
1402 s64 lm_off; 1400 s64 lm_off;
1403 swreg tid;
1404
1405 offmap = (struct bpf_offloaded_map *)meta->arg1.map_ptr;
1406 nfp_map = offmap->dev_priv;
1407 1401
1408 /* We only have to reload LM0 if the key is not at start of stack */ 1402 /* We only have to reload LM0 if the key is not at start of stack */
1409 lm_off = nfp_prog->stack_depth; 1403 lm_off = nfp_prog->stack_depth;
@@ -1416,17 +1410,12 @@ map_call_stack_common(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
1416 if (meta->func_id == BPF_FUNC_map_update_elem) 1410 if (meta->func_id == BPF_FUNC_map_update_elem)
1417 emit_csr_wr(nfp_prog, reg_b(3 * 2), NFP_CSR_ACT_LM_ADDR2); 1411 emit_csr_wr(nfp_prog, reg_b(3 * 2), NFP_CSR_ACT_LM_ADDR2);
1418 1412
1419 /* Load map ID into a register, it should actually fit as an immediate
1420 * but in case it doesn't deal with it here, not in the delay slots.
1421 */
1422 tid = ur_load_imm_any(nfp_prog, nfp_map->tid, imm_a(nfp_prog));
1423
1424 emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO + meta->func_id, 1413 emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO + meta->func_id,
1425 2, RELO_BR_HELPER); 1414 2, RELO_BR_HELPER);
1426 ret_tgt = nfp_prog_current_offset(nfp_prog) + 2; 1415 ret_tgt = nfp_prog_current_offset(nfp_prog) + 2;
1427 1416
1428 /* Load map ID into A0 */ 1417 /* Load map ID into A0 */
1429 wrp_mov(nfp_prog, reg_a(0), tid); 1418 wrp_mov(nfp_prog, reg_a(0), reg_a(2));
1430 1419
1431 /* Load the return address into B0 */ 1420 /* Load the return address into B0 */
1432 wrp_immed_relo(nfp_prog, reg_b(0), ret_tgt, RELO_IMMED_REL); 1421 wrp_immed_relo(nfp_prog, reg_b(0), ret_tgt, RELO_IMMED_REL);
@@ -1456,6 +1445,31 @@ nfp_get_prandom_u32(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
1456 return 0; 1445 return 0;
1457} 1446}
1458 1447
1448static int
1449nfp_perf_event_output(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
1450{
1451 swreg ptr_type;
1452 u32 ret_tgt;
1453
1454 ptr_type = ur_load_imm_any(nfp_prog, meta->arg1.type, imm_a(nfp_prog));
1455
1456 ret_tgt = nfp_prog_current_offset(nfp_prog) + 3;
1457
1458 emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO + meta->func_id,
1459 2, RELO_BR_HELPER);
1460
1461 /* Load ptr type into A1 */
1462 wrp_mov(nfp_prog, reg_a(1), ptr_type);
1463
1464 /* Load the return address into B0 */
1465 wrp_immed_relo(nfp_prog, reg_b(0), ret_tgt, RELO_IMMED_REL);
1466
1467 if (!nfp_prog_confirm_current_offset(nfp_prog, ret_tgt))
1468 return -EINVAL;
1469
1470 return 0;
1471}
1472
1459/* --- Callbacks --- */ 1473/* --- Callbacks --- */
1460static int mov_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) 1474static int mov_reg64(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
1461{ 1475{
@@ -2411,6 +2425,8 @@ static int call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
2411 return map_call_stack_common(nfp_prog, meta); 2425 return map_call_stack_common(nfp_prog, meta);
2412 case BPF_FUNC_get_prandom_u32: 2426 case BPF_FUNC_get_prandom_u32:
2413 return nfp_get_prandom_u32(nfp_prog, meta); 2427 return nfp_get_prandom_u32(nfp_prog, meta);
2428 case BPF_FUNC_perf_event_output:
2429 return nfp_perf_event_output(nfp_prog, meta);
2414 default: 2430 default:
2415 WARN_ONCE(1, "verifier allowed unsupported function\n"); 2431 WARN_ONCE(1, "verifier allowed unsupported function\n");
2416 return -EOPNOTSUPP; 2432 return -EOPNOTSUPP;
@@ -3227,6 +3243,33 @@ static int nfp_bpf_optimize(struct nfp_prog *nfp_prog)
3227 return 0; 3243 return 0;
3228} 3244}
3229 3245
3246static int nfp_bpf_replace_map_ptrs(struct nfp_prog *nfp_prog)
3247{
3248 struct nfp_insn_meta *meta1, *meta2;
3249 struct nfp_bpf_map *nfp_map;
3250 struct bpf_map *map;
3251
3252 nfp_for_each_insn_walk2(nfp_prog, meta1, meta2) {
3253 if (meta1->skip || meta2->skip)
3254 continue;
3255
3256 if (meta1->insn.code != (BPF_LD | BPF_IMM | BPF_DW) ||
3257 meta1->insn.src_reg != BPF_PSEUDO_MAP_FD)
3258 continue;
3259
3260 map = (void *)(unsigned long)((u32)meta1->insn.imm |
3261 (u64)meta2->insn.imm << 32);
3262 if (bpf_map_offload_neutral(map))
3263 continue;
3264 nfp_map = map_to_offmap(map)->dev_priv;
3265
3266 meta1->insn.imm = nfp_map->tid;
3267 meta2->insn.imm = 0;
3268 }
3269
3270 return 0;
3271}
3272
3230static int nfp_bpf_ustore_calc(u64 *prog, unsigned int len) 3273static int nfp_bpf_ustore_calc(u64 *prog, unsigned int len)
3231{ 3274{
3232 __le64 *ustore = (__force __le64 *)prog; 3275 __le64 *ustore = (__force __le64 *)prog;
@@ -3263,6 +3306,10 @@ int nfp_bpf_jit(struct nfp_prog *nfp_prog)
3263{ 3306{
3264 int ret; 3307 int ret;
3265 3308
3309 ret = nfp_bpf_replace_map_ptrs(nfp_prog);
3310 if (ret)
3311 return ret;
3312
3266 ret = nfp_bpf_optimize(nfp_prog); 3313 ret = nfp_bpf_optimize(nfp_prog);
3267 if (ret) 3314 if (ret)
3268 return ret; 3315 return ret;
@@ -3353,6 +3400,9 @@ void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv)
3353 case BPF_FUNC_map_delete_elem: 3400 case BPF_FUNC_map_delete_elem:
3354 val = nfp_prog->bpf->helpers.map_delete; 3401 val = nfp_prog->bpf->helpers.map_delete;
3355 break; 3402 break;
3403 case BPF_FUNC_perf_event_output:
3404 val = nfp_prog->bpf->helpers.perf_event_output;
3405 break;
3356 default: 3406 default:
3357 pr_err("relocation of unknown helper %d\n", 3407 pr_err("relocation of unknown helper %d\n",
3358 val); 3408 val);
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
index 1dc424685f4e..d72f9e7f42da 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2017 Netronome Systems, Inc. 2 * Copyright (C) 2017-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 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 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -43,6 +43,14 @@
43#include "fw.h" 43#include "fw.h"
44#include "main.h" 44#include "main.h"
45 45
46const struct rhashtable_params nfp_bpf_maps_neutral_params = {
47 .nelem_hint = 4,
48 .key_len = FIELD_SIZEOF(struct nfp_bpf_neutral_map, ptr),
49 .key_offset = offsetof(struct nfp_bpf_neutral_map, ptr),
50 .head_offset = offsetof(struct nfp_bpf_neutral_map, l),
51 .automatic_shrinking = true,
52};
53
46static bool nfp_net_ebpf_capable(struct nfp_net *nn) 54static bool nfp_net_ebpf_capable(struct nfp_net *nn)
47{ 55{
48#ifdef __LITTLE_ENDIAN 56#ifdef __LITTLE_ENDIAN
@@ -290,6 +298,9 @@ nfp_bpf_parse_cap_func(struct nfp_app_bpf *bpf, void __iomem *value, u32 length)
290 case BPF_FUNC_map_delete_elem: 298 case BPF_FUNC_map_delete_elem:
291 bpf->helpers.map_delete = readl(&cap->func_addr); 299 bpf->helpers.map_delete = readl(&cap->func_addr);
292 break; 300 break;
301 case BPF_FUNC_perf_event_output:
302 bpf->helpers.perf_event_output = readl(&cap->func_addr);
303 break;
293 } 304 }
294 305
295 return 0; 306 return 0;
@@ -401,17 +412,28 @@ static int nfp_bpf_init(struct nfp_app *app)
401 init_waitqueue_head(&bpf->cmsg_wq); 412 init_waitqueue_head(&bpf->cmsg_wq);
402 INIT_LIST_HEAD(&bpf->map_list); 413 INIT_LIST_HEAD(&bpf->map_list);
403 414
404 err = nfp_bpf_parse_capabilities(app); 415 err = rhashtable_init(&bpf->maps_neutral, &nfp_bpf_maps_neutral_params);
405 if (err) 416 if (err)
406 goto err_free_bpf; 417 goto err_free_bpf;
407 418
419 err = nfp_bpf_parse_capabilities(app);
420 if (err)
421 goto err_free_neutral_maps;
422
408 return 0; 423 return 0;
409 424
425err_free_neutral_maps:
426 rhashtable_destroy(&bpf->maps_neutral);
410err_free_bpf: 427err_free_bpf:
411 kfree(bpf); 428 kfree(bpf);
412 return err; 429 return err;
413} 430}
414 431
432static void nfp_check_rhashtable_empty(void *ptr, void *arg)
433{
434 WARN_ON_ONCE(1);
435}
436
415static void nfp_bpf_clean(struct nfp_app *app) 437static void nfp_bpf_clean(struct nfp_app *app)
416{ 438{
417 struct nfp_app_bpf *bpf = app->priv; 439 struct nfp_app_bpf *bpf = app->priv;
@@ -419,6 +441,8 @@ static void nfp_bpf_clean(struct nfp_app *app)
419 WARN_ON(!skb_queue_empty(&bpf->cmsg_replies)); 441 WARN_ON(!skb_queue_empty(&bpf->cmsg_replies));
420 WARN_ON(!list_empty(&bpf->map_list)); 442 WARN_ON(!list_empty(&bpf->map_list));
421 WARN_ON(bpf->maps_in_use || bpf->map_elems_in_use); 443 WARN_ON(bpf->maps_in_use || bpf->map_elems_in_use);
444 rhashtable_free_and_destroy(&bpf->maps_neutral,
445 nfp_check_rhashtable_empty, NULL);
422 kfree(bpf); 446 kfree(bpf);
423} 447}
424 448
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index 68b5d326483d..82682378d57f 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2016-2017 Netronome Systems, Inc. 2 * Copyright (C) 2016-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 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 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -39,6 +39,7 @@
39#include <linux/bpf_verifier.h> 39#include <linux/bpf_verifier.h>
40#include <linux/kernel.h> 40#include <linux/kernel.h>
41#include <linux/list.h> 41#include <linux/list.h>
42#include <linux/rhashtable.h>
42#include <linux/skbuff.h> 43#include <linux/skbuff.h>
43#include <linux/types.h> 44#include <linux/types.h>
44#include <linux/wait.h> 45#include <linux/wait.h>
@@ -114,6 +115,8 @@ enum pkt_vec {
114 * @maps_in_use: number of currently offloaded maps 115 * @maps_in_use: number of currently offloaded maps
115 * @map_elems_in_use: number of elements allocated to offloaded maps 116 * @map_elems_in_use: number of elements allocated to offloaded maps
116 * 117 *
118 * @maps_neutral: hash table of offload-neutral maps (on pointer)
119 *
117 * @adjust_head: adjust head capability 120 * @adjust_head: adjust head capability
118 * @adjust_head.flags: extra flags for adjust head 121 * @adjust_head.flags: extra flags for adjust head
119 * @adjust_head.off_min: minimal packet offset within buffer required 122 * @adjust_head.off_min: minimal packet offset within buffer required
@@ -133,6 +136,7 @@ enum pkt_vec {
133 * @helpers.map_lookup: map lookup helper address 136 * @helpers.map_lookup: map lookup helper address
134 * @helpers.map_update: map update helper address 137 * @helpers.map_update: map update helper address
135 * @helpers.map_delete: map delete helper address 138 * @helpers.map_delete: map delete helper address
139 * @helpers.perf_event_output: output perf event to a ring buffer
136 * 140 *
137 * @pseudo_random: FW initialized the pseudo-random machinery (CSRs) 141 * @pseudo_random: FW initialized the pseudo-random machinery (CSRs)
138 */ 142 */
@@ -150,6 +154,8 @@ struct nfp_app_bpf {
150 unsigned int maps_in_use; 154 unsigned int maps_in_use;
151 unsigned int map_elems_in_use; 155 unsigned int map_elems_in_use;
152 156
157 struct rhashtable maps_neutral;
158
153 struct nfp_bpf_cap_adjust_head { 159 struct nfp_bpf_cap_adjust_head {
154 u32 flags; 160 u32 flags;
155 int off_min; 161 int off_min;
@@ -171,6 +177,7 @@ struct nfp_app_bpf {
171 u32 map_lookup; 177 u32 map_lookup;
172 u32 map_update; 178 u32 map_update;
173 u32 map_delete; 179 u32 map_delete;
180 u32 perf_event_output;
174 } helpers; 181 } helpers;
175 182
176 bool pseudo_random; 183 bool pseudo_random;
@@ -199,6 +206,14 @@ struct nfp_bpf_map {
199 enum nfp_bpf_map_use use_map[]; 206 enum nfp_bpf_map_use use_map[];
200}; 207};
201 208
209struct nfp_bpf_neutral_map {
210 struct rhash_head l;
211 struct bpf_map *ptr;
212 u32 count;
213};
214
215extern const struct rhashtable_params nfp_bpf_maps_neutral_params;
216
202struct nfp_prog; 217struct nfp_prog;
203struct nfp_insn_meta; 218struct nfp_insn_meta;
204typedef int (*instr_cb_t)(struct nfp_prog *, struct nfp_insn_meta *); 219typedef int (*instr_cb_t)(struct nfp_prog *, struct nfp_insn_meta *);
@@ -367,6 +382,8 @@ static inline bool is_mbpf_xadd(const struct nfp_insn_meta *meta)
367 * @error: error code if something went wrong 382 * @error: error code if something went wrong
368 * @stack_depth: max stack depth from the verifier 383 * @stack_depth: max stack depth from the verifier
369 * @adjust_head_location: if program has single adjust head call - the insn no. 384 * @adjust_head_location: if program has single adjust head call - the insn no.
385 * @map_records_cnt: the number of map pointers recorded for this prog
386 * @map_records: the map record pointers from bpf->maps_neutral
370 * @insns: list of BPF instruction wrappers (struct nfp_insn_meta) 387 * @insns: list of BPF instruction wrappers (struct nfp_insn_meta)
371 */ 388 */
372struct nfp_prog { 389struct nfp_prog {
@@ -390,6 +407,9 @@ struct nfp_prog {
390 unsigned int stack_depth; 407 unsigned int stack_depth;
391 unsigned int adjust_head_location; 408 unsigned int adjust_head_location;
392 409
410 unsigned int map_records_cnt;
411 struct nfp_bpf_neutral_map **map_records;
412
393 struct list_head insns; 413 struct list_head insns;
394}; 414};
395 415
@@ -440,5 +460,7 @@ int nfp_bpf_ctrl_lookup_entry(struct bpf_offloaded_map *offmap,
440int nfp_bpf_ctrl_getnext_entry(struct bpf_offloaded_map *offmap, 460int nfp_bpf_ctrl_getnext_entry(struct bpf_offloaded_map *offmap,
441 void *key, void *next_key); 461 void *key, void *next_key);
442 462
463int nfp_bpf_event_output(struct nfp_app_bpf *bpf, struct sk_buff *skb);
464
443void nfp_bpf_ctrl_msg_rx(struct nfp_app *app, struct sk_buff *skb); 465void nfp_bpf_ctrl_msg_rx(struct nfp_app *app, struct sk_buff *skb);
444#endif 466#endif
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c
index 42d98792bd25..4db0ac1e42a8 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2016-2017 Netronome Systems, Inc. 2 * Copyright (C) 2016-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 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 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -57,6 +57,126 @@
57#include "../nfp_net.h" 57#include "../nfp_net.h"
58 58
59static int 59static int
60nfp_map_ptr_record(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog,
61 struct bpf_map *map)
62{
63 struct nfp_bpf_neutral_map *record;
64 int err;
65
66 /* Map record paths are entered via ndo, update side is protected. */
67 ASSERT_RTNL();
68
69 /* Reuse path - other offloaded program is already tracking this map. */
70 record = rhashtable_lookup_fast(&bpf->maps_neutral, &map,
71 nfp_bpf_maps_neutral_params);
72 if (record) {
73 nfp_prog->map_records[nfp_prog->map_records_cnt++] = record;
74 record->count++;
75 return 0;
76 }
77
78 /* Grab a single ref to the map for our record. The prog destroy ndo
79 * happens after free_used_maps().
80 */
81 map = bpf_map_inc(map, false);
82 if (IS_ERR(map))
83 return PTR_ERR(map);
84
85 record = kmalloc(sizeof(*record), GFP_KERNEL);
86 if (!record) {
87 err = -ENOMEM;
88 goto err_map_put;
89 }
90
91 record->ptr = map;
92 record->count = 1;
93
94 err = rhashtable_insert_fast(&bpf->maps_neutral, &record->l,
95 nfp_bpf_maps_neutral_params);
96 if (err)
97 goto err_free_rec;
98
99 nfp_prog->map_records[nfp_prog->map_records_cnt++] = record;
100
101 return 0;
102
103err_free_rec:
104 kfree(record);
105err_map_put:
106 bpf_map_put(map);
107 return err;
108}
109
110static void
111nfp_map_ptrs_forget(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog)
112{
113 bool freed = false;
114 int i;
115
116 ASSERT_RTNL();
117
118 for (i = 0; i < nfp_prog->map_records_cnt; i++) {
119 if (--nfp_prog->map_records[i]->count) {
120 nfp_prog->map_records[i] = NULL;
121 continue;
122 }
123
124 WARN_ON(rhashtable_remove_fast(&bpf->maps_neutral,
125 &nfp_prog->map_records[i]->l,
126 nfp_bpf_maps_neutral_params));
127 freed = true;
128 }
129
130 if (freed) {
131 synchronize_rcu();
132
133 for (i = 0; i < nfp_prog->map_records_cnt; i++)
134 if (nfp_prog->map_records[i]) {
135 bpf_map_put(nfp_prog->map_records[i]->ptr);
136 kfree(nfp_prog->map_records[i]);
137 }
138 }
139
140 kfree(nfp_prog->map_records);
141 nfp_prog->map_records = NULL;
142 nfp_prog->map_records_cnt = 0;
143}
144
145static int
146nfp_map_ptrs_record(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog,
147 struct bpf_prog *prog)
148{
149 int i, cnt, err;
150
151 /* Quickly count the maps we will have to remember */
152 cnt = 0;
153 for (i = 0; i < prog->aux->used_map_cnt; i++)
154 if (bpf_map_offload_neutral(prog->aux->used_maps[i]))
155 cnt++;
156 if (!cnt)
157 return 0;
158
159 nfp_prog->map_records = kmalloc_array(cnt,
160 sizeof(nfp_prog->map_records[0]),
161 GFP_KERNEL);
162 if (!nfp_prog->map_records)
163 return -ENOMEM;
164
165 for (i = 0; i < prog->aux->used_map_cnt; i++)
166 if (bpf_map_offload_neutral(prog->aux->used_maps[i])) {
167 err = nfp_map_ptr_record(bpf, nfp_prog,
168 prog->aux->used_maps[i]);
169 if (err) {
170 nfp_map_ptrs_forget(bpf, nfp_prog);
171 return err;
172 }
173 }
174 WARN_ON(cnt != nfp_prog->map_records_cnt);
175
176 return 0;
177}
178
179static int
60nfp_prog_prepare(struct nfp_prog *nfp_prog, const struct bpf_insn *prog, 180nfp_prog_prepare(struct nfp_prog *nfp_prog, const struct bpf_insn *prog,
61 unsigned int cnt) 181 unsigned int cnt)
62{ 182{
@@ -151,7 +271,7 @@ static int nfp_bpf_translate(struct nfp_net *nn, struct bpf_prog *prog)
151 prog->aux->offload->jited_len = nfp_prog->prog_len * sizeof(u64); 271 prog->aux->offload->jited_len = nfp_prog->prog_len * sizeof(u64);
152 prog->aux->offload->jited_image = nfp_prog->prog; 272 prog->aux->offload->jited_image = nfp_prog->prog;
153 273
154 return 0; 274 return nfp_map_ptrs_record(nfp_prog->bpf, nfp_prog, prog);
155} 275}
156 276
157static int nfp_bpf_destroy(struct nfp_net *nn, struct bpf_prog *prog) 277static int nfp_bpf_destroy(struct nfp_net *nn, struct bpf_prog *prog)
@@ -159,6 +279,7 @@ static int nfp_bpf_destroy(struct nfp_net *nn, struct bpf_prog *prog)
159 struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv; 279 struct nfp_prog *nfp_prog = prog->aux->offload->dev_priv;
160 280
161 kvfree(nfp_prog->prog); 281 kvfree(nfp_prog->prog);
282 nfp_map_ptrs_forget(nfp_prog->bpf, nfp_prog);
162 nfp_prog_free(nfp_prog); 283 nfp_prog_free(nfp_prog);
163 284
164 return 0; 285 return 0;
@@ -320,6 +441,53 @@ int nfp_ndo_bpf(struct nfp_app *app, struct nfp_net *nn, struct netdev_bpf *bpf)
320 } 441 }
321} 442}
322 443
444static unsigned long
445nfp_bpf_perf_event_copy(void *dst, const void *src,
446 unsigned long off, unsigned long len)
447{
448 memcpy(dst, src + off, len);
449 return 0;
450}
451
452int nfp_bpf_event_output(struct nfp_app_bpf *bpf, struct sk_buff *skb)
453{
454 struct cmsg_bpf_event *cbe = (void *)skb->data;
455 u32 pkt_size, data_size;
456 struct bpf_map *map;
457
458 if (skb->len < sizeof(struct cmsg_bpf_event))
459 goto err_drop;
460
461 pkt_size = be32_to_cpu(cbe->pkt_size);
462 data_size = be32_to_cpu(cbe->data_size);
463 map = (void *)(unsigned long)be64_to_cpu(cbe->map_ptr);
464
465 if (skb->len < sizeof(struct cmsg_bpf_event) + pkt_size + data_size)
466 goto err_drop;
467 if (cbe->hdr.ver != CMSG_MAP_ABI_VERSION)
468 goto err_drop;
469
470 rcu_read_lock();
471 if (!rhashtable_lookup_fast(&bpf->maps_neutral, &map,
472 nfp_bpf_maps_neutral_params)) {
473 rcu_read_unlock();
474 pr_warn("perf event: dest map pointer %px not recognized, dropping event\n",
475 map);
476 goto err_drop;
477 }
478
479 bpf_event_output(map, be32_to_cpu(cbe->cpu_id),
480 &cbe->data[round_up(pkt_size, 4)], data_size,
481 cbe->data, pkt_size, nfp_bpf_perf_event_copy);
482 rcu_read_unlock();
483
484 dev_consume_skb_any(skb);
485 return 0;
486err_drop:
487 dev_kfree_skb_any(skb);
488 return -EINVAL;
489}
490
323static int 491static int
324nfp_net_bpf_load(struct nfp_net *nn, struct bpf_prog *prog, 492nfp_net_bpf_load(struct nfp_net *nn, struct bpf_prog *prog,
325 struct netlink_ext_ack *extack) 493 struct netlink_ext_ack *extack)
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
index 06ad53ce4ad9..e163f3cfa47d 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2016-2017 Netronome Systems, Inc. 2 * Copyright (C) 2016-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 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 5 * June 1991 as shown in the file COPYING in the top-level directory of this
@@ -36,6 +36,8 @@
36#include <linux/kernel.h> 36#include <linux/kernel.h>
37#include <linux/pkt_cls.h> 37#include <linux/pkt_cls.h>
38 38
39#include "../nfp_app.h"
40#include "../nfp_main.h"
39#include "fw.h" 41#include "fw.h"
40#include "main.h" 42#include "main.h"
41 43
@@ -149,15 +151,6 @@ nfp_bpf_map_call_ok(const char *fname, struct bpf_verifier_env *env,
149 return false; 151 return false;
150 } 152 }
151 153
152 /* Rest of the checks is only if we re-parse the same insn */
153 if (!meta->func_id)
154 return true;
155
156 if (meta->arg1.map_ptr != reg1->map_ptr) {
157 pr_vlog(env, "%s: called for different map\n", fname);
158 return false;
159 }
160
161 return true; 154 return true;
162} 155}
163 156
@@ -216,6 +209,71 @@ nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct bpf_verifier_env *env,
216 pr_vlog(env, "bpf_get_prandom_u32(): FW doesn't support random number generation\n"); 209 pr_vlog(env, "bpf_get_prandom_u32(): FW doesn't support random number generation\n");
217 return -EOPNOTSUPP; 210 return -EOPNOTSUPP;
218 211
212 case BPF_FUNC_perf_event_output:
213 BUILD_BUG_ON(NFP_BPF_SCALAR_VALUE != SCALAR_VALUE ||
214 NFP_BPF_MAP_VALUE != PTR_TO_MAP_VALUE ||
215 NFP_BPF_STACK != PTR_TO_STACK ||
216 NFP_BPF_PACKET_DATA != PTR_TO_PACKET);
217
218 if (!bpf->helpers.perf_event_output) {
219 pr_vlog(env, "event_output: not supported by FW\n");
220 return -EOPNOTSUPP;
221 }
222
223 /* Force current CPU to make sure we can report the event
224 * wherever we get the control message from FW.
225 */
226 if (reg3->var_off.mask & BPF_F_INDEX_MASK ||
227 (reg3->var_off.value & BPF_F_INDEX_MASK) !=
228 BPF_F_CURRENT_CPU) {
229 char tn_buf[48];
230
231 tnum_strn(tn_buf, sizeof(tn_buf), reg3->var_off);
232 pr_vlog(env, "event_output: must use BPF_F_CURRENT_CPU, var_off: %s\n",
233 tn_buf);
234 return -EOPNOTSUPP;
235 }
236
237 /* Save space in meta, we don't care about arguments other
238 * than 4th meta, shove it into arg1.
239 */
240 reg1 = cur_regs(env) + BPF_REG_4;
241
242 if (reg1->type != SCALAR_VALUE /* NULL ptr */ &&
243 reg1->type != PTR_TO_STACK &&
244 reg1->type != PTR_TO_MAP_VALUE &&
245 reg1->type != PTR_TO_PACKET) {
246 pr_vlog(env, "event_output: unsupported ptr type: %d\n",
247 reg1->type);
248 return -EOPNOTSUPP;
249 }
250
251 if (reg1->type == PTR_TO_STACK &&
252 !nfp_bpf_stack_arg_ok("event_output", env, reg1, NULL))
253 return -EOPNOTSUPP;
254
255 /* Warn user that on offload NFP may return success even if map
256 * is not going to accept the event, since the event output is
257 * fully async and device won't know the state of the map.
258 * There is also FW limitation on the event length.
259 *
260 * Lost events will not show up on the perf ring, driver
261 * won't see them at all. Events may also get reordered.
262 */
263 dev_warn_once(&nfp_prog->bpf->app->pf->pdev->dev,
264 "bpf: note: return codes and behavior of bpf_event_output() helper differs for offloaded programs!\n");
265 pr_vlog(env, "warning: return codes and behavior of event_output helper differ for offload!\n");
266
267 if (!meta->func_id)
268 break;
269
270 if (reg1->type != meta->arg1.type) {
271 pr_vlog(env, "event_output: ptr type changed: %d %d\n",
272 meta->arg1.type, reg1->type);
273 return -EINVAL;
274 }
275 break;
276
219 default: 277 default:
220 pr_vlog(env, "unsupported function id: %d\n", func_id); 278 pr_vlog(env, "unsupported function id: %d\n", func_id);
221 return -EOPNOTSUPP; 279 return -EOPNOTSUPP;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c
index 6aedef0ad433..0e0253c7e17b 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_app.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2017 Netronome Systems, Inc. 2 * Copyright (C) 2017-2018 Netronome Systems, Inc.
3 * 3 *
4 * This software is dual licensed under the GNU General License Version 2, 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 5 * June 1991 as shown in the file COPYING in the top-level directory of this