diff options
Diffstat (limited to 'net/bpf/test_run.c')
| -rw-r--r-- | net/bpf/test_run.c | 141 | 
1 files changed, 120 insertions, 21 deletions
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index fa2644d276ef..da7051d62727 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -13,27 +13,13 @@  #include <net/sock.h>  #include <net/tcp.h> -static __always_inline u32 bpf_test_run_one(struct bpf_prog *prog, void *ctx, -		struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE]) -{ -	u32 ret; - -	preempt_disable(); -	rcu_read_lock(); -	bpf_cgroup_storage_set(storage); -	ret = BPF_PROG_RUN(prog, ctx); -	rcu_read_unlock(); -	preempt_enable(); - -	return ret; -} - -static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *ret, -			u32 *time) +static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, +			u32 *retval, u32 *time)  {  	struct bpf_cgroup_storage *storage[MAX_BPF_CGROUP_STORAGE_TYPE] = { 0 };  	enum bpf_cgroup_storage_type stype;  	u64 time_start, time_spent = 0; +	int ret = 0;  	u32 i;  	for_each_cgroup_storage_type(stype) { @@ -48,25 +34,42 @@ static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, u32 *ret,  	if (!repeat)  		repeat = 1; + +	rcu_read_lock(); +	preempt_disable();  	time_start = ktime_get_ns();  	for (i = 0; i < repeat; i++) { -		*ret = bpf_test_run_one(prog, ctx, storage); +		bpf_cgroup_storage_set(storage); +		*retval = BPF_PROG_RUN(prog, ctx); + +		if (signal_pending(current)) { +			ret = -EINTR; +			break; +		} +  		if (need_resched()) { -			if (signal_pending(current)) -				break;  			time_spent += ktime_get_ns() - time_start; +			preempt_enable(); +			rcu_read_unlock(); +  			cond_resched(); + +			rcu_read_lock(); +			preempt_disable();  			time_start = ktime_get_ns();  		}  	}  	time_spent += ktime_get_ns() - time_start; +	preempt_enable(); +	rcu_read_unlock(); +  	do_div(time_spent, repeat);  	*time = time_spent > U32_MAX ? U32_MAX : (u32)time_spent;  	for_each_cgroup_storage_type(stype)  		bpf_cgroup_storage_free(storage[stype]); -	return 0; +	return ret;  }  static int bpf_test_finish(const union bpf_attr *kattr, @@ -240,3 +243,99 @@ out:  	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; + +	rcu_read_lock(); +	preempt_disable(); +	time_start = ktime_get_ns(); +	for (i = 0; i < repeat; i++) { +		retval = __skb_flow_bpf_dissect(prog, skb, +						&flow_keys_dissector, +						&flow_keys); + +		if (signal_pending(current)) { +			preempt_enable(); +			rcu_read_unlock(); + +			ret = -EINTR; +			goto out; +		} + +		if (need_resched()) { +			time_spent += ktime_get_ns() - time_start; +			preempt_enable(); +			rcu_read_unlock(); + +			cond_resched(); + +			rcu_read_lock(); +			preempt_disable(); +			time_start = ktime_get_ns(); +		} +	} +	time_spent += ktime_get_ns() - time_start; +	preempt_enable(); +	rcu_read_unlock(); + +	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); + +out: +	kfree_skb(skb); +	kfree(sk); +	return ret; +}  |