bpf/flow_dissector: support flags in BPF_PROG_TEST_RUN
authorStanislav Fomichev <sdf@google.com>
Thu, 25 Jul 2019 22:52:27 +0000 (15:52 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 26 Jul 2019 01:00:41 +0000 (18:00 -0700)
This will allow us to write tests for those flags.

v2:
* Swap kfree(data) and kfree(user_ctx) (Song Liu)

Acked-by: Petar Penkov <ppenkov@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Acked-by: Song Liu <songliubraving@fb.com>
Cc: Song Liu <songliubraving@fb.com>
Cc: Willem de Bruijn <willemb@google.com>
Cc: Petar Penkov <ppenkov@google.com>
Signed-off-by: Stanislav Fomichev <sdf@google.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
net/bpf/test_run.c

index 4e41d15a10986e3e9c79179d22d3cd7ebab0e4d7..1153bbcdff721de951a7ebfe23e83ddb9cc43ae1 100644 (file)
@@ -377,6 +377,22 @@ out:
        return ret;
 }
 
+static int verify_user_bpf_flow_keys(struct bpf_flow_keys *ctx)
+{
+       /* make sure the fields we don't use are zeroed */
+       if (!range_is_zero(ctx, 0, offsetof(struct bpf_flow_keys, flags)))
+               return -EINVAL;
+
+       /* flags is allowed */
+
+       if (!range_is_zero(ctx, offsetof(struct bpf_flow_keys, flags) +
+                          FIELD_SIZEOF(struct bpf_flow_keys, flags),
+                          sizeof(struct bpf_flow_keys)))
+               return -EINVAL;
+
+       return 0;
+}
+
 int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
                                     const union bpf_attr *kattr,
                                     union bpf_attr __user *uattr)
@@ -384,9 +400,11 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
        u32 size = kattr->test.data_size_in;
        struct bpf_flow_dissector ctx = {};
        u32 repeat = kattr->test.repeat;
+       struct bpf_flow_keys *user_ctx;
        struct bpf_flow_keys flow_keys;
        u64 time_start, time_spent = 0;
        const struct ethhdr *eth;
+       unsigned int flags = 0;
        u32 retval, duration;
        void *data;
        int ret;
@@ -395,9 +413,6 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
        if (prog->type != BPF_PROG_TYPE_FLOW_DISSECTOR)
                return -EINVAL;
 
-       if (kattr->test.ctx_in || kattr->test.ctx_out)
-               return -EINVAL;
-
        if (size < ETH_HLEN)
                return -EINVAL;
 
@@ -410,6 +425,18 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
        if (!repeat)
                repeat = 1;
 
+       user_ctx = bpf_ctx_init(kattr, sizeof(struct bpf_flow_keys));
+       if (IS_ERR(user_ctx)) {
+               kfree(data);
+               return PTR_ERR(user_ctx);
+       }
+       if (user_ctx) {
+               ret = verify_user_bpf_flow_keys(user_ctx);
+               if (ret)
+                       goto out;
+               flags = user_ctx->flags;
+       }
+
        ctx.flow_keys = &flow_keys;
        ctx.data = data;
        ctx.data_end = (__u8 *)data + size;
@@ -419,7 +446,7 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
        time_start = ktime_get_ns();
        for (i = 0; i < repeat; i++) {
                retval = bpf_flow_dissect(prog, &ctx, eth->h_proto, ETH_HLEN,
-                                         size, 0);
+                                         size, flags);
 
                if (signal_pending(current)) {
                        preempt_enable();
@@ -450,8 +477,12 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
 
        ret = bpf_test_finish(kattr, uattr, &flow_keys, sizeof(flow_keys),
                              retval, duration);
+       if (!ret)
+               ret = bpf_ctx_finish(kattr, uattr, user_ctx,
+                                    sizeof(struct bpf_flow_keys));
 
 out:
+       kfree(user_ctx);
        kfree(data);
        return ret;
 }