nfp: bpf: rewrite map pointers with NFP TIDs
authorJakub Kicinski <jakub.kicinski@netronome.com>
Fri, 4 May 2018 01:37:13 +0000 (18:37 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 4 May 2018 21:41:03 +0000 (23:41 +0200)
Kernel will now replace map fds with actual pointer before
calling the offload prepare.  We can identify those pointers
and replace them with NFP table IDs instead of loading the
table ID in code generated for CALL instruction.

This allows us to support having the same CALL being used with
different maps.

Since we don't want to change the FW ABI we still need to
move the TID from R1 to portion of R0 before the jump.

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
drivers/net/ethernet/netronome/nfp/bpf/jit.c
drivers/net/ethernet/netronome/nfp/bpf/verifier.c

index 2127cf1548ddaf729b1ba63d7c7b04f4ef85f2ba..326a2085d650e0e634f21c7ed0e160203c54908b 100644 (file)
@@ -1395,15 +1395,9 @@ static int adjust_head(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
 static int
 map_call_stack_common(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
 {
-       struct bpf_offloaded_map *offmap;
-       struct nfp_bpf_map *nfp_map;
        bool load_lm_ptr;
        u32 ret_tgt;
        s64 lm_off;
-       swreg tid;
-
-       offmap = (struct bpf_offloaded_map *)meta->arg1.map_ptr;
-       nfp_map = offmap->dev_priv;
 
        /* We only have to reload LM0 if the key is not at start of stack */
        lm_off = nfp_prog->stack_depth;
@@ -1416,17 +1410,12 @@ map_call_stack_common(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
        if (meta->func_id == BPF_FUNC_map_update_elem)
                emit_csr_wr(nfp_prog, reg_b(3 * 2), NFP_CSR_ACT_LM_ADDR2);
 
-       /* Load map ID into a register, it should actually fit as an immediate
-        * but in case it doesn't deal with it here, not in the delay slots.
-        */
-       tid = ur_load_imm_any(nfp_prog, nfp_map->tid, imm_a(nfp_prog));
-
        emit_br_relo(nfp_prog, BR_UNC, BR_OFF_RELO + meta->func_id,
                     2, RELO_BR_HELPER);
        ret_tgt = nfp_prog_current_offset(nfp_prog) + 2;
 
        /* Load map ID into A0 */
-       wrp_mov(nfp_prog, reg_a(0), tid);
+       wrp_mov(nfp_prog, reg_a(0), reg_a(2));
 
        /* Load the return address into B0 */
        wrp_immed_relo(nfp_prog, reg_b(0), ret_tgt, RELO_IMMED_REL);
@@ -3254,6 +3243,33 @@ static int nfp_bpf_optimize(struct nfp_prog *nfp_prog)
        return 0;
 }
 
+static int nfp_bpf_replace_map_ptrs(struct nfp_prog *nfp_prog)
+{
+       struct nfp_insn_meta *meta1, *meta2;
+       struct nfp_bpf_map *nfp_map;
+       struct bpf_map *map;
+
+       nfp_for_each_insn_walk2(nfp_prog, meta1, meta2) {
+               if (meta1->skip || meta2->skip)
+                       continue;
+
+               if (meta1->insn.code != (BPF_LD | BPF_IMM | BPF_DW) ||
+                   meta1->insn.src_reg != BPF_PSEUDO_MAP_FD)
+                       continue;
+
+               map = (void *)(unsigned long)((u32)meta1->insn.imm |
+                                             (u64)meta2->insn.imm << 32);
+               if (bpf_map_offload_neutral(map))
+                       continue;
+               nfp_map = map_to_offmap(map)->dev_priv;
+
+               meta1->insn.imm = nfp_map->tid;
+               meta2->insn.imm = 0;
+       }
+
+       return 0;
+}
+
 static int nfp_bpf_ustore_calc(u64 *prog, unsigned int len)
 {
        __le64 *ustore = (__force __le64 *)prog;
@@ -3290,6 +3306,10 @@ int nfp_bpf_jit(struct nfp_prog *nfp_prog)
 {
        int ret;
 
+       ret = nfp_bpf_replace_map_ptrs(nfp_prog);
+       if (ret)
+               return ret;
+
        ret = nfp_bpf_optimize(nfp_prog);
        if (ret)
                return ret;
index c76b622743ae3ed1d38d36534342207e5b7d8685..e163f3cfa47db5220a89fceedab2a8d790cc9b11 100644 (file)
@@ -151,15 +151,6 @@ nfp_bpf_map_call_ok(const char *fname, struct bpf_verifier_env *env,
                return false;
        }
 
-       /* Rest of the checks is only if we re-parse the same insn */
-       if (!meta->func_id)
-               return true;
-
-       if (meta->arg1.map_ptr != reg1->map_ptr) {
-               pr_vlog(env, "%s: called for different map\n", fname);
-               return false;
-       }
-
        return true;
 }