aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-07-18 10:08:27 -0400
committerPatrick McHardy <kaber@trash.net>2011-07-18 10:08:27 -0400
commit84a797dd0b9f7130357b70577fcbda8e638c71a7 (patch)
tree6d093dba184228f689873b7171d63933f0676e0d /net
parent6b75e3e8d664a9a1b99d31a7f4976ae70d1d090a (diff)
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: Eric Dumazet <eric.dumazet@gmail.com> CC: Florian Westphal <fw@strlen.de> CC: Eric Leblond <eric@regit.org> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nfnetlink_queue.c41
1 files changed, 12 insertions, 29 deletions
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index b83123f12b42..c645b87915b8 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -619,39 +619,26 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
619 struct nfqnl_instance *queue; 619 struct nfqnl_instance *queue;
620 unsigned int verdict; 620 unsigned int verdict;
621 struct nf_queue_entry *entry; 621 struct nf_queue_entry *entry;
622 int err;
623 622
624 rcu_read_lock();
625 queue = instance_lookup(queue_num); 623 queue = instance_lookup(queue_num);
626 if (!queue) { 624 if (!queue)
627 err = -ENODEV; 625 return -ENODEV;
628 goto err_out_unlock;
629 }
630 626
631 if (queue->peer_pid != NETLINK_CB(skb).pid) { 627 if (queue->peer_pid != NETLINK_CB(skb).pid)
632 err = -EPERM; 628 return -EPERM;
633 goto err_out_unlock;
634 }
635 629
636 if (!nfqa[NFQA_VERDICT_HDR]) { 630 if (!nfqa[NFQA_VERDICT_HDR])
637 err = -EINVAL; 631 return -EINVAL;
638 goto err_out_unlock;
639 }
640 632
641 vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]); 633 vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
642 verdict = ntohl(vhdr->verdict); 634 verdict = ntohl(vhdr->verdict);
643 635
644 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT) { 636 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)
645 err = -EINVAL; 637 return -EINVAL;
646 goto err_out_unlock;
647 }
648 638
649 entry = find_dequeue_entry(queue, ntohl(vhdr->id)); 639 entry = find_dequeue_entry(queue, ntohl(vhdr->id));
650 if (entry == NULL) { 640 if (entry == NULL)
651 err = -ENOENT; 641 return -ENOENT;
652 goto err_out_unlock;
653 }
654 rcu_read_unlock();
655 642
656 if (nfqa[NFQA_PAYLOAD]) { 643 if (nfqa[NFQA_PAYLOAD]) {
657 if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]), 644 if (nfqnl_mangle(nla_data(nfqa[NFQA_PAYLOAD]),
@@ -664,10 +651,6 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
664 651
665 nf_reinject(entry, verdict); 652 nf_reinject(entry, verdict);
666 return 0; 653 return 0;
667
668err_out_unlock:
669 rcu_read_unlock();
670 return err;
671} 654}
672 655
673static int 656static int
@@ -780,9 +763,9 @@ err_out_unlock:
780} 763}
781 764
782static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = { 765static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
783 [NFQNL_MSG_PACKET] = { .call = nfqnl_recv_unsupp, 766 [NFQNL_MSG_PACKET] = { .call_rcu = nfqnl_recv_unsupp,
784 .attr_count = NFQA_MAX, }, 767 .attr_count = NFQA_MAX, },
785 [NFQNL_MSG_VERDICT] = { .call = nfqnl_recv_verdict, 768 [NFQNL_MSG_VERDICT] = { .call_rcu = nfqnl_recv_verdict,
786 .attr_count = NFQA_MAX, 769 .attr_count = NFQA_MAX,
787 .policy = nfqa_verdict_policy }, 770 .policy = nfqa_verdict_policy },
788 [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, 771 [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,