diff options
author | Jakub Kicinski | 2017-12-15 06:29:19 +0100 |
---|---|---|
committer | Daniel Borkmann | 2017-12-15 14:18:18 +0100 |
commit | 8231f8444110c346a7d28756abbca11c956d5803 (patch) | |
tree | 6d28e0c7a5cb126f044cf45b9d1b6dff876fc53f /drivers/net/ethernet/netronome/nfp/bpf/verifier.c | |
parent | nfp: bpf: add basic support for adjust head call (diff) | |
download | kernel-qcow2-linux-8231f8444110c346a7d28756abbca11c956d5803.tar.gz kernel-qcow2-linux-8231f8444110c346a7d28756abbca11c956d5803.tar.xz kernel-qcow2-linux-8231f8444110c346a7d28756abbca11c956d5803.zip |
nfp: bpf: optimize the adjust_head calls in trivial cases
If the program is simple and has only one adjust head call
with constant parameters, we can check that the call will
always succeed at translation time. We need to track the
location of the call and make sure parameters are always
the same. We also have to check the parameters against
datapath constraints and ETH_HLEN.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Diffstat (limited to 'drivers/net/ethernet/netronome/nfp/bpf/verifier.c')
-rw-r--r-- | drivers/net/ethernet/netronome/nfp/bpf/verifier.c | 46 |
1 files changed, 44 insertions, 2 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c index 0a457d98666c..9c2608445bd8 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c @@ -69,9 +69,47 @@ nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta, return meta; } +static void +nfp_record_adjust_head(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog, + struct nfp_insn_meta *meta, + const struct bpf_reg_state *reg2) +{ + unsigned int location = UINT_MAX; + int imm; + + /* Datapath usually can give us guarantees on how much adjust head + * can be done without the need for any checks. Optimize the simple + * case where there is only one adjust head by a constant. + */ + if (reg2->type != SCALAR_VALUE || !tnum_is_const(reg2->var_off)) + goto exit_set_location; + imm = reg2->var_off.value; + /* Translator will skip all checks, we need to guarantee min pkt len */ + if (imm > ETH_ZLEN - ETH_HLEN) + goto exit_set_location; + if (imm > (int)bpf->adjust_head.guaranteed_add || + imm < -bpf->adjust_head.guaranteed_sub) + goto exit_set_location; + + if (nfp_prog->adjust_head_location) { + /* Only one call per program allowed */ + if (nfp_prog->adjust_head_location != meta->n) + goto exit_set_location; + + if (meta->arg2.var_off.value != imm) + goto exit_set_location; + } + + location = meta->n; +exit_set_location: + nfp_prog->adjust_head_location = location; +} + static int -nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) +nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct bpf_verifier_env *env, + struct nfp_insn_meta *meta) { + const struct bpf_reg_state *reg2 = cur_regs(env) + BPF_REG_2; struct nfp_app_bpf *bpf = nfp_prog->bpf; u32 func_id = meta->insn.imm; @@ -85,12 +123,16 @@ nfp_bpf_check_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) pr_warn("adjust_head: FW requires shifting metadata, not supported by the driver\n"); return -EOPNOTSUPP; } + + nfp_record_adjust_head(bpf, nfp_prog, meta, reg2); break; default: pr_warn("unsupported function id: %d\n", func_id); return -EOPNOTSUPP; } + meta->arg2 = *reg2; + return 0; } @@ -204,7 +246,7 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx) } if (meta->insn.code == (BPF_JMP | BPF_CALL)) - return nfp_bpf_check_call(nfp_prog, meta); + return nfp_bpf_check_call(nfp_prog, env, meta); if (meta->insn.code == (BPF_JMP | BPF_EXIT)) return nfp_bpf_check_exit(nfp_prog, env); |