]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
bpf: add BPF_PROG_TEST_RUN support for flow dissector
authorStanislav Fomichev <sdf@google.com>
Mon, 28 Jan 2019 16:53:54 +0000 (08:53 -0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Tue, 29 Jan 2019 00:08:29 +0000 (01:08 +0100)
The input is packet data, the output is struct bpf_flow_key. This should
make it easy to test flow dissector programs without elaborate
setup.

Signed-off-by: Stanislav Fomichev <sdf@google.com>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
include/linux/bpf.h
net/bpf/test_run.c
net/core/filter.c

index 3851529062ecb46f984715b5271234ee017b2829..0394f1f9213bf2542eb1de2190420e5047da51c7 100644 (file)
@@ -404,6 +404,9 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
                          union bpf_attr __user *uattr);
 int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
                          union bpf_attr __user *uattr);
+int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
+                                    const union bpf_attr *kattr,
+                                    union bpf_attr __user *uattr);
 
 /* an array of programs to be executed under rcu_lock.
  *
index fa2644d276ef1134bc3b41ce02b70bfdd8a678fa..2c5172b332098ffa91f2ee249db7951106277124 100644 (file)
@@ -240,3 +240,85 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
        kfree(data);
        return ret;
 }
+
+int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
+                                    const union bpf_attr *kattr,
+                                    union bpf_attr __user *uattr)
+{
+       u32 size = kattr->test.data_size_in;
+       u32 repeat = kattr->test.repeat;
+       struct bpf_flow_keys flow_keys;
+       u64 time_start, time_spent = 0;
+       struct bpf_skb_data_end *cb;
+       u32 retval, duration;
+       struct sk_buff *skb;
+       struct sock *sk;
+       void *data;
+       int ret;
+       u32 i;
+
+       if (prog->type != BPF_PROG_TYPE_FLOW_DISSECTOR)
+               return -EINVAL;
+
+       data = bpf_test_init(kattr, size, NET_SKB_PAD + NET_IP_ALIGN,
+                            SKB_DATA_ALIGN(sizeof(struct skb_shared_info)));
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       sk = kzalloc(sizeof(*sk), GFP_USER);
+       if (!sk) {
+               kfree(data);
+               return -ENOMEM;
+       }
+       sock_net_set(sk, current->nsproxy->net_ns);
+       sock_init_data(NULL, sk);
+
+       skb = build_skb(data, 0);
+       if (!skb) {
+               kfree(data);
+               kfree(sk);
+               return -ENOMEM;
+       }
+       skb->sk = sk;
+
+       skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+       __skb_put(skb, size);
+       skb->protocol = eth_type_trans(skb,
+                                      current->nsproxy->net_ns->loopback_dev);
+       skb_reset_network_header(skb);
+
+       cb = (struct bpf_skb_data_end *)skb->cb;
+       cb->qdisc_cb.flow_keys = &flow_keys;
+
+       if (!repeat)
+               repeat = 1;
+
+       time_start = ktime_get_ns();
+       for (i = 0; i < repeat; i++) {
+               preempt_disable();
+               rcu_read_lock();
+               retval = __skb_flow_bpf_dissect(prog, skb,
+                                               &flow_keys_dissector,
+                                               &flow_keys);
+               rcu_read_unlock();
+               preempt_enable();
+
+               if (need_resched()) {
+                       if (signal_pending(current))
+                               break;
+                       time_spent += ktime_get_ns() - time_start;
+                       cond_resched();
+                       time_start = ktime_get_ns();
+               }
+       }
+       time_spent += ktime_get_ns() - time_start;
+       do_div(time_spent, repeat);
+       duration = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;
+
+       ret = bpf_test_finish(kattr, uattr, &flow_keys, sizeof(flow_keys),
+                             retval, duration);
+
+       kfree_skb(skb);
+       kfree(sk);
+       return ret;
+}
index 8e587dd1da200494b900bd14eec7f875f5453773..8ce421796ac6b11867eb5c6a70fcaed6b70144f6 100644 (file)
@@ -7711,6 +7711,7 @@ const struct bpf_verifier_ops flow_dissector_verifier_ops = {
 };
 
 const struct bpf_prog_ops flow_dissector_prog_ops = {
+       .test_run               = bpf_prog_test_run_flow_dissector,
 };
 
 int sk_detach_filter(struct sock *sk)