Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 84a797dd authored by Eric Dumazet's avatar Eric Dumazet Committed by Patrick McHardy
Browse files

netfilter: nfnetlink_queue: provide rcu enabled callbacks



nenetlink_queue operations on SMP are not efficent if several queues are
used, because of nfnl_mutex contention when applications give packet
verdict.

Use new call_rcu field in struct nfnl_callback to advertize a callback
that is called under rcu_read_lock instead of nfnl_mutex.

On my 2x4x2 machine, I was able to reach 2.000.000 pps going through
user land returning NF_ACCEPT verdicts without losses, instead of less
than 500.000 pps before patch.

Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
CC: Florian Westphal <fw@strlen.de>
CC: Eric Leblond <eric@regit.org>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent 6b75e3e8
Loading
Loading
Loading
Loading
+12 −29
Original line number Original line Diff line number Diff line
@@ -619,39 +619,26 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
	struct nfqnl_instance *queue;
	struct nfqnl_instance *queue;
	unsigned int verdict;
	unsigned int verdict;
	struct nf_queue_entry *entry;
	struct nf_queue_entry *entry;
	int err;


	rcu_read_lock();
	queue = instance_lookup(queue_num);
	queue = instance_lookup(queue_num);
	if (!queue) {
	if (!queue)
		err = -ENODEV;
		return -ENODEV;
		goto err_out_unlock;
	}


	if (queue->peer_pid != NETLINK_CB(skb).pid) {
	if (queue->peer_pid != NETLINK_CB(skb).pid)
		err = -EPERM;
		return -EPERM;
		goto err_out_unlock;
	}


	if (!nfqa[NFQA_VERDICT_HDR]) {
	if (!nfqa[NFQA_VERDICT_HDR])
		err = -EINVAL;
		return -EINVAL;
		goto err_out_unlock;
	}


	vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
	vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
	verdict = ntohl(vhdr->verdict);
	verdict = ntohl(vhdr->verdict);


	if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) {
	if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)
		err = -EINVAL;
		return -EINVAL;
		goto err_out_unlock;
	}


	entry = find_dequeue_entry(queue, ntohl(vhdr->id));
	entry = find_dequeue_entry(queue, ntohl(vhdr->id));
	if (entry == NULL) {
	if (entry == NULL)
		err = -ENOENT;
		return -ENOENT;
		goto err_out_unlock;
	}
	rcu_read_unlock();


	if (nfqa[NFQA_PAYLOAD]) {
	if (nfqa[NFQA_PAYLOAD]) {
		if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
		if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
@@ -664,10 +651,6 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,


	nf_reinject(entry, verdict);
	nf_reinject(entry, verdict);
	return 0;
	return 0;

err_out_unlock:
	rcu_read_unlock();
	return err;
}
}


static int
static int
@@ -780,9 +763,9 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
}
}


static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
	[NFQNL_MSG_PACKET]	= { .call = nfqnl_recv_unsupp,
	[NFQNL_MSG_PACKET]	= { .call_rcu = nfqnl_recv_unsupp,
				    .attr_count = NFQA_MAX, },
				    .attr_count = NFQA_MAX, },
	[NFQNL_MSG_VERDICT]	= { .call = nfqnl_recv_verdict,
	[NFQNL_MSG_VERDICT]	= { .call_rcu = nfqnl_recv_verdict,
				    .attr_count = NFQA_MAX,
				    .attr_count = NFQA_MAX,
				    .policy = nfqa_verdict_policy },
				    .policy = nfqa_verdict_policy },
	[NFQNL_MSG_CONFIG]	= { .call = nfqnl_recv_config,
	[NFQNL_MSG_CONFIG]	= { .call = nfqnl_recv_config,