bpf: add verifier callback to get stack usage info for offloaded progs
authorQuentin Monnet <quentin.monnet@netronome.com>
Sun, 7 Oct 2018 11:56:47 +0000 (12:56 +0100)
committerDaniel Borkmann <daniel@iogearbox.net>
Mon, 8 Oct 2018 08:24:12 +0000 (10:24 +0200)
In preparation for BPF-to-BPF calls in offloaded programs, add a new
function attribute to the struct bpf_prog_offload_ops so that drivers
supporting eBPF offload can hook at the end of program verification, and
potentially extract information collected by the verifier.

Implement a minimal callback (returning 0) in the drivers providing the
structs, namely netdevsim and nfp.

This will be useful in the nfp driver, in later commits, to extract the
number of subprograms as well as the stack depth for those subprograms.

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

index a6e9248669e141d4d19f0536eed52adf6ef78d90..e470489021e3e388a2b2932f96f321d6896acdfe 100644 (file)
@@ -640,6 +640,12 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx)
        return 0;
 }
 
+static int nfp_bpf_finalize(struct bpf_verifier_env *env)
+{
+       return 0;
+}
+
 const struct bpf_prog_offload_ops nfp_bpf_analyzer_ops = {
-       .insn_hook = nfp_verify_insn,
+       .insn_hook      = nfp_verify_insn,
+       .finalize       = nfp_bpf_finalize,
 };
index 81444208b2162126d515dc0948db09e936079a3f..cb3518474f0e4248967b5c5710c3137288cf23d7 100644 (file)
@@ -86,8 +86,14 @@ nsim_bpf_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn)
        return 0;
 }
 
+static int nsim_bpf_finalize(struct bpf_verifier_env *env)
+{
+       return 0;
+}
+
 static const struct bpf_prog_offload_ops nsim_bpf_analyzer_ops = {
-       .insn_hook = nsim_bpf_verify_insn,
+       .insn_hook      = nsim_bpf_verify_insn,
+       .finalize       = nsim_bpf_finalize,
 };
 
 static bool nsim_xdp_offload_active(struct netdevsim *ns)
index 027697b6a22f44e37c5826f2468d3d2bb1173998..9b558713447fd005613f66d4eff2ac935aa84f45 100644 (file)
@@ -263,6 +263,7 @@ struct bpf_verifier_ops {
 struct bpf_prog_offload_ops {
        int (*insn_hook)(struct bpf_verifier_env *env,
                         int insn_idx, int prev_insn_idx);
+       int (*finalize)(struct bpf_verifier_env *env);
 };
 
 struct bpf_prog_offload {
index 7b6fd2ab3263ffdcc3567514c7dd51be46cf02e8..9e8056ec20faab8c3ffd4e99843a166ace95a0a1 100644 (file)
@@ -245,5 +245,6 @@ static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env)
 int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env);
 int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env,
                                 int insn_idx, int prev_insn_idx);
+int bpf_prog_offload_finalize(struct bpf_verifier_env *env);
 
 #endif /* _LINUX_BPF_VERIFIER_H */
index 177a524363942e0c66079cf51b0f760c98bf8031..8e93c47f0779617c7fca6158170f1b66dc100d66 100644 (file)
@@ -172,6 +172,24 @@ int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env,
        return ret;
 }
 
+int bpf_prog_offload_finalize(struct bpf_verifier_env *env)
+{
+       struct bpf_prog_offload *offload;
+       int ret = -ENODEV;
+
+       down_read(&bpf_devs_lock);
+       offload = env->prog->aux->offload;
+       if (offload) {
+               if (offload->dev_ops->finalize)
+                       ret = offload->dev_ops->finalize(env);
+               else
+                       ret = 0;
+       }
+       up_read(&bpf_devs_lock);
+
+       return ret;
+}
+
 static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
 {
        struct bpf_prog_offload *offload = prog->aux->offload;
index 73c81bef6ae83c3e6c1393f01a998af0f399b318..a0454cb299bae0e38937206618acc41aadfd6317 100644 (file)
@@ -6309,6 +6309,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
                env->cur_state = NULL;
        }
 
+       if (ret == 0 && bpf_prog_is_dev_bound(env->prog->aux))
+               ret = bpf_prog_offload_finalize(env);
+
 skip_full_check:
        while (!pop_stack(env, NULL, NULL));
        free_states(env);