aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2011-07-19 05:46:33 -0400
committerPatrick McHardy <kaber@trash.net>2011-07-19 05:46:33 -0400
commit97d32cf9440d2111a12471740446d4d63231b79a (patch)
tree13b33df5f7a3faf8e765761b823620d234317937 /net
parent5863702a3421b0d2a63a473cf96afeb9fe09070d (diff)
netfilter: nfnetlink_queue: batch verdict support
Introduces a new nfnetlink type that applies a given verdict to all queued packets with an id <= the id in the verdict message. If a mark is provided it is applied to all matched packets. This reduces the number of verdicts that have to be sent. Applications that make use of this feature need to maintain a timeout to send a batchverdict periodically to avoid starvation. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nfnetlink_queue.c115
1 files changed, 103 insertions, 12 deletions
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 3b2af8cb7de9..fbfcd834140b 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -171,6 +171,13 @@ __enqueue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
171 queue->queue_total++; 171 queue->queue_total++;
172} 172}
173 173
174static void
175__dequeue_entry(struct nfqnl_instance *queue, struct nf_queue_entry *entry)
176{
177 list_del(&entry->list);
178 queue->queue_total--;
179}
180
174static struct nf_queue_entry * 181static struct nf_queue_entry *
175find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id) 182find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
176{ 183{
@@ -185,10 +192,8 @@ find_dequeue_entry(struct nfqnl_instance *queue, unsigned int id)
185 } 192 }
186 } 193 }
187 194
188 if (entry) { 195 if (entry)
189 list_del(&entry->list); 196 __dequeue_entry(queue, entry);
190 queue->queue_total--;
191 }
192 197
193 spin_unlock_bh(&queue->lock); 198 spin_unlock_bh(&queue->lock);
194 199
@@ -611,6 +616,92 @@ static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
611 [NFQA_PAYLOAD] = { .type = NLA_UNSPEC }, 616 [NFQA_PAYLOAD] = { .type = NLA_UNSPEC },
612}; 617};
613 618
619static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
620 [NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
621 [NFQA_MARK] = { .type = NLA_U32 },
622};
623
624static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid)
625{
626 struct nfqnl_instance *queue;
627
628 queue = instance_lookup(queue_num);
629 if (!queue)
630 return ERR_PTR(-ENODEV);
631
632 if (queue->peer_pid != nlpid)
633 return ERR_PTR(-EPERM);
634
635 return queue;
636}
637
638static struct nfqnl_msg_verdict_hdr*
639verdicthdr_get(const struct nlattr * const nfqa[])
640{
641 struct nfqnl_msg_verdict_hdr *vhdr;
642 unsigned int verdict;
643
644 if (!nfqa[NFQA_VERDICT_HDR])
645 return NULL;
646
647 vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
648 verdict = ntohl(vhdr->verdict);
649 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)
650 return NULL;
651 return vhdr;
652}
653
654static int nfq_id_after(unsigned int id, unsigned int max)
655{
656 return (int)(id - max) > 0;
657}
658
659static int
660nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
661 const struct nlmsghdr *nlh,
662 const struct nlattr * const nfqa[])
663{
664 struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
665 struct nf_queue_entry *entry, *tmp;
666 unsigned int verdict, maxid;
667 struct nfqnl_msg_verdict_hdr *vhdr;
668 struct nfqnl_instance *queue;
669 LIST_HEAD(batch_list);
670 u16 queue_num = ntohs(nfmsg->res_id);
671
672 queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
673 if (IS_ERR(queue))
674 return PTR_ERR(queue);
675
676 vhdr = verdicthdr_get(nfqa);
677 if (!vhdr)
678 return -EINVAL;
679
680 verdict = ntohl(vhdr->verdict);
681 maxid = ntohl(vhdr->id);
682
683 spin_lock_bh(&queue->lock);
684
685 list_for_each_entry_safe(entry, tmp, &queue->queue_list, list) {
686 if (nfq_id_after(entry->id, maxid))
687 break;
688 __dequeue_entry(queue, entry);
689 list_add_tail(&entry->list, &batch_list);
690 }
691
692 spin_unlock_bh(&queue->lock);
693
694 if (list_empty(&batch_list))
695 return -ENOENT;
696
697 list_for_each_entry_safe(entry, tmp, &batch_list, list) {
698 if (nfqa[NFQA_MARK])
699 entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
700 nf_reinject(entry, verdict);
701 }
702 return 0;
703}
704
614static int 705static int
615nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, 706nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
616 const struct nlmsghdr *nlh, 707 const struct nlmsghdr *nlh,
@@ -626,20 +717,17 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
626 717
627 queue = instance_lookup(queue_num); 718 queue = instance_lookup(queue_num);
628 if (!queue) 719 if (!queue)
629 return -ENODEV;
630 720
631 if (queue->peer_pid != NETLINK_CB(skb).pid) 721 queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
632 return -EPERM; 722 if (IS_ERR(queue))
723 return PTR_ERR(queue);
633 724
634 if (!nfqa[NFQA_VERDICT_HDR]) 725 vhdr = verdicthdr_get(nfqa);
726 if (!vhdr)
635 return -EINVAL; 727 return -EINVAL;
636 728
637 vhdr = nla_data(nfqa[NFQA_VERDICT_HDR]);
638 verdict = ntohl(vhdr->verdict); 729 verdict = ntohl(vhdr->verdict);
639 730
640 if ((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)
641 return -EINVAL;
642
643 entry = find_dequeue_entry(queue, ntohl(vhdr->id)); 731 entry = find_dequeue_entry(queue, ntohl(vhdr->id));
644 if (entry == NULL) 732 if (entry == NULL)
645 return -ENOENT; 733 return -ENOENT;
@@ -775,6 +863,9 @@ static const struct nfnl_callback nfqnl_cb[NFQNL_MSG_MAX] = {
775 [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config, 863 [NFQNL_MSG_CONFIG] = { .call = nfqnl_recv_config,
776 .attr_count = NFQA_CFG_MAX, 864 .attr_count = NFQA_CFG_MAX,
777 .policy = nfqa_cfg_policy }, 865 .policy = nfqa_cfg_policy },
866 [NFQNL_MSG_VERDICT_BATCH]={ .call_rcu = nfqnl_recv_verdict_batch,
867 .attr_count = NFQA_MAX,
868 .policy = nfqa_verdict_batch_policy },
778}; 869};
779 870
780static const struct nfnetlink_subsystem nfqnl_subsys = { 871static const struct nfnetlink_subsystem nfqnl_subsys = {