forked from mirrors/linux
		
	bpf: add BPF_PROG_TEST_RUN support for flow dissector
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>
This commit is contained in:
		
							parent
							
								
									c8aa703822
								
							
						
					
					
						commit
						b7a1848e83
					
				
					 3 changed files with 86 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -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.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue