aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-07-19 05:44:17 -0400
committerPatrick McHardy <kaber@trash.net>2011-07-19 05:44:17 -0400
commit5863702a3421b0d2a63a473cf96afeb9fe09070d (patch)
treed462b775b7702a4ae44ec50ec28a2217d5ab2338 /net
parent84a797dd0b9f7130357b70577fcbda8e638c71a7 (diff)
netfilter: nfnetlink_queue: assert monotonic packet ids
Packet identifier is currently setup in nfqnl_build_packet_message(), using one atomic_inc_return(). Problem is that since several cpus might concurrently call nfqnl_enqueue_packet() for the same queue, we can deliver packets to consumer in non monotonic way (packet N+1 being delivered after packet N) This patch moves the packet id setup from nfqnl_build_packet_message() to nfqnl_enqueue_packet() to guarantee correct delivery order. This also removes one atomic operation. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Florian Westphal <fw@strlen.de> CC: Pablo Neira Ayuso <pablo@netfilter.org> 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.c26
1 files changed, 15 insertions, 11 deletions
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index c645b87915b8..3b2af8cb7de9 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -58,7 +58,7 @@ struct nfqnl_instance {
58 */ 58 */
59 spinlock_t lock; 59 spinlock_t lock;
60 unsigned int queue_total; 60 unsigned int queue_total;
61 atomic_t id_sequence; /* 'sequence' of pkt ids */ 61 unsigned int id_sequence; /* 'sequence' of pkt ids */
62 struct list_head queue_list; /* packets in queue */ 62 struct list_head queue_list; /* packets in queue */
63}; 63};
64 64
@@ -213,13 +213,15 @@ nfqnl_flush(struct nfqnl_instance *queue, nfqnl_cmpfn cmpfn, unsigned long data)
213 213
214static struct sk_buff * 214static struct sk_buff *
215nfqnl_build_packet_message(struct nfqnl_instance *queue, 215nfqnl_build_packet_message(struct nfqnl_instance *queue,
216 struct nf_queue_entry *entry) 216 struct nf_queue_entry *entry,
217 __be32 **packet_id_ptr)
217{ 218{
218 sk_buff_data_t old_tail; 219 sk_buff_data_t old_tail;
219 size_t size; 220 size_t size;
220 size_t data_len = 0; 221 size_t data_len = 0;
221 struct sk_buff *skb; 222 struct sk_buff *skb;
222 struct nfqnl_msg_packet_hdr pmsg; 223 struct nlattr *nla;
224 struct nfqnl_msg_packet_hdr *pmsg;
223 struct nlmsghdr *nlh; 225 struct nlmsghdr *nlh;
224 struct nfgenmsg *nfmsg; 226 struct nfgenmsg *nfmsg;
225 struct sk_buff *entskb = entry->skb; 227 struct sk_buff *entskb = entry->skb;
@@ -272,12 +274,11 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
272 nfmsg->version = NFNETLINK_V0; 274 nfmsg->version = NFNETLINK_V0;
273 nfmsg->res_id = htons(queue->queue_num); 275 nfmsg->res_id = htons(queue->queue_num);
274 276
275 entry->id = atomic_inc_return(&queue->id_sequence); 277 nla = __nla_reserve(skb, NFQA_PACKET_HDR, sizeof(*pmsg));
276 pmsg.packet_id = htonl(entry->id); 278 pmsg = nla_data(nla);
277 pmsg.hw_protocol = entskb->protocol; 279 pmsg->hw_protocol = entskb->protocol;
278 pmsg.hook = entry->hook; 280 pmsg->hook = entry->hook;
279 281 *packet_id_ptr = &pmsg->packet_id;
280 NLA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg);
281 282
282 indev = entry->indev; 283 indev = entry->indev;
283 if (indev) { 284 if (indev) {
@@ -388,6 +389,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
388 struct sk_buff *nskb; 389 struct sk_buff *nskb;
389 struct nfqnl_instance *queue; 390 struct nfqnl_instance *queue;
390 int err = -ENOBUFS; 391 int err = -ENOBUFS;
392 __be32 *packet_id_ptr;
391 393
392 /* rcu_read_lock()ed by nf_hook_slow() */ 394 /* rcu_read_lock()ed by nf_hook_slow() */
393 queue = instance_lookup(queuenum); 395 queue = instance_lookup(queuenum);
@@ -401,7 +403,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
401 goto err_out; 403 goto err_out;
402 } 404 }
403 405
404 nskb = nfqnl_build_packet_message(queue, entry); 406 nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr);
405 if (nskb == NULL) { 407 if (nskb == NULL) {
406 err = -ENOMEM; 408 err = -ENOMEM;
407 goto err_out; 409 goto err_out;
@@ -420,6 +422,8 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
420 queue->queue_total); 422 queue->queue_total);
421 goto err_out_free_nskb; 423 goto err_out_free_nskb;
422 } 424 }
425 entry->id = ++queue->id_sequence;
426 *packet_id_ptr = htonl(entry->id);
423 427
424 /* nfnetlink_unicast will either free the nskb or add it to a socket */ 428 /* nfnetlink_unicast will either free the nskb or add it to a socket */
425 err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); 429 err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
@@ -852,7 +856,7 @@ static int seq_show(struct seq_file *s, void *v)
852 inst->peer_pid, inst->queue_total, 856 inst->peer_pid, inst->queue_total,
853 inst->copy_mode, inst->copy_range, 857 inst->copy_mode, inst->copy_range,
854 inst->queue_dropped, inst->queue_user_dropped, 858 inst->queue_dropped, inst->queue_user_dropped,
855 atomic_read(&inst->id_sequence), 1); 859 inst->id_sequence, 1);
856} 860}
857 861
858static const struct seq_operations nfqnl_seq_ops = { 862static const struct seq_operations nfqnl_seq_ops = {