aboutsummaryrefslogtreecommitdiffstats
path: root/net/packet
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-07-05 04:45:05 -0400
committerDavid S. Miller <davem@davemloft.net>2011-07-06 01:34:52 -0400
commitdc99f600698dcac69b8f56dda9a8a00d645c5ffc (patch)
tree81599e4397761610d5020c03e2571eeceaa859b6 /net/packet
parentce06b03e60fc19c680d1bf873e779bf11c2fc518 (diff)
packet: Add fanout support.
Fanouts allow packet capturing to be demuxed to a set of AF_PACKET sockets. Two fanout policies are implemented: 1) Hashing based upon skb->rxhash 2) Pure round-robin An AF_PACKET socket must be fully bound before it tries to add itself to a fanout. All AF_PACKET sockets trying to join the same fanout must all have the same bind settings. Fanouts are identified (within a network namespace) by a 16-bit ID. The first socket to try to add itself to a fanout with a particular ID, creates that fanout. When the last socket leaves the fanout (which happens only when the socket is closed), that fanout is destroyed. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/packet')
-rw-r--r--net/packet/af_packet.c256
1 files changed, 251 insertions, 5 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index bb281bf330aa..3350f1d3c9aa 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -187,9 +187,11 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg);
187 187
188static void packet_flush_mclist(struct sock *sk); 188static void packet_flush_mclist(struct sock *sk);
189 189
190struct packet_fanout;
190struct packet_sock { 191struct packet_sock {
191 /* struct sock has to be the first member of packet_sock */ 192 /* struct sock has to be the first member of packet_sock */
192 struct sock sk; 193 struct sock sk;
194 struct packet_fanout *fanout;
193 struct tpacket_stats stats; 195 struct tpacket_stats stats;
194 struct packet_ring_buffer rx_ring; 196 struct packet_ring_buffer rx_ring;
195 struct packet_ring_buffer tx_ring; 197 struct packet_ring_buffer tx_ring;
@@ -212,6 +214,24 @@ struct packet_sock {
212 struct packet_type prot_hook ____cacheline_aligned_in_smp; 214 struct packet_type prot_hook ____cacheline_aligned_in_smp;
213}; 215};
214 216
217#define PACKET_FANOUT_MAX 256
218
219struct packet_fanout {
220#ifdef CONFIG_NET_NS
221 struct net *net;
222#endif
223 unsigned int num_members;
224 u16 id;
225 u8 type;
226 u8 pad;
227 atomic_t rr_cur;
228 struct list_head list;
229 struct sock *arr[PACKET_FANOUT_MAX];
230 spinlock_t lock;
231 atomic_t sk_ref;
232 struct packet_type prot_hook ____cacheline_aligned_in_smp;
233};
234
215struct packet_skb_cb { 235struct packet_skb_cb {
216 unsigned int origlen; 236 unsigned int origlen;
217 union { 237 union {
@@ -227,6 +247,9 @@ static inline struct packet_sock *pkt_sk(struct sock *sk)
227 return (struct packet_sock *)sk; 247 return (struct packet_sock *)sk;
228} 248}
229 249
250static void __fanout_unlink(struct sock *sk, struct packet_sock *po);
251static void __fanout_link(struct sock *sk, struct packet_sock *po);
252
230/* register_prot_hook must be invoked with the po->bind_lock held, 253/* register_prot_hook must be invoked with the po->bind_lock held,
231 * or from a context in which asynchronous accesses to the packet 254 * or from a context in which asynchronous accesses to the packet
232 * socket is not possible (packet_create()). 255 * socket is not possible (packet_create()).
@@ -235,7 +258,10 @@ static void register_prot_hook(struct sock *sk)
235{ 258{
236 struct packet_sock *po = pkt_sk(sk); 259 struct packet_sock *po = pkt_sk(sk);
237 if (!po->running) { 260 if (!po->running) {
238 dev_add_pack(&po->prot_hook); 261 if (po->fanout)
262 __fanout_link(sk, po);
263 else
264 dev_add_pack(&po->prot_hook);
239 sock_hold(sk); 265 sock_hold(sk);
240 po->running = 1; 266 po->running = 1;
241 } 267 }
@@ -253,7 +279,10 @@ static void __unregister_prot_hook(struct sock *sk, bool sync)
253 struct packet_sock *po = pkt_sk(sk); 279 struct packet_sock *po = pkt_sk(sk);
254 280
255 po->running = 0; 281 po->running = 0;
256 __dev_remove_pack(&po->prot_hook); 282 if (po->fanout)
283 __fanout_unlink(sk, po);
284 else
285 __dev_remove_pack(&po->prot_hook);
257 __sock_put(sk); 286 __sock_put(sk);
258 287
259 if (sync) { 288 if (sync) {
@@ -388,6 +417,201 @@ static void packet_sock_destruct(struct sock *sk)
388 sk_refcnt_debug_dec(sk); 417 sk_refcnt_debug_dec(sk);
389} 418}
390 419
420static int fanout_rr_next(struct packet_fanout *f, unsigned int num)
421{
422 int x = atomic_read(&f->rr_cur) + 1;
423
424 if (x >= num)
425 x = 0;
426
427 return x;
428}
429
430static struct sock *fanout_demux_hash(struct packet_fanout *f, struct sk_buff *skb, unsigned int num)
431{
432 u32 idx, hash = skb->rxhash;
433
434 idx = ((u64)hash * num) >> 32;
435
436 return f->arr[idx];
437}
438
439static struct sock *fanout_demux_lb(struct packet_fanout *f, struct sk_buff *skb, unsigned int num)
440{
441 int cur, old;
442
443 cur = atomic_read(&f->rr_cur);
444 while ((old = atomic_cmpxchg(&f->rr_cur, cur,
445 fanout_rr_next(f, num))) != cur)
446 cur = old;
447 return f->arr[cur];
448}
449
450static int packet_rcv_fanout_hash(struct sk_buff *skb, struct net_device *dev,
451 struct packet_type *pt, struct net_device *orig_dev)
452{
453 struct packet_fanout *f = pt->af_packet_priv;
454 unsigned int num = f->num_members;
455 struct packet_sock *po;
456 struct sock *sk;
457
458 if (!net_eq(dev_net(dev), read_pnet(&f->net)) ||
459 !num) {
460 kfree_skb(skb);
461 return 0;
462 }
463
464 skb_get_rxhash(skb);
465
466 sk = fanout_demux_hash(f, skb, num);
467 po = pkt_sk(sk);
468
469 return po->prot_hook.func(skb, dev, &po->prot_hook, orig_dev);
470}
471
472static int packet_rcv_fanout_lb(struct sk_buff *skb, struct net_device *dev,
473 struct packet_type *pt, struct net_device *orig_dev)
474{
475 struct packet_fanout *f = pt->af_packet_priv;
476 unsigned int num = f->num_members;
477 struct packet_sock *po;
478 struct sock *sk;
479
480 if (!net_eq(dev_net(dev), read_pnet(&f->net)) ||
481 !num) {
482 kfree_skb(skb);
483 return 0;
484 }
485
486 sk = fanout_demux_lb(f, skb, num);
487 po = pkt_sk(sk);
488
489 return po->prot_hook.func(skb, dev, &po->prot_hook, orig_dev);
490}
491
492static DEFINE_MUTEX(fanout_mutex);
493static LIST_HEAD(fanout_list);
494
495static void __fanout_link(struct sock *sk, struct packet_sock *po)
496{
497 struct packet_fanout *f = po->fanout;
498
499 spin_lock(&f->lock);
500 f->arr[f->num_members] = sk;
501 smp_wmb();
502 f->num_members++;
503 spin_unlock(&f->lock);
504}
505
506static void __fanout_unlink(struct sock *sk, struct packet_sock *po)
507{
508 struct packet_fanout *f = po->fanout;
509 int i;
510
511 spin_lock(&f->lock);
512 for (i = 0; i < f->num_members; i++) {
513 if (f->arr[i] == sk)
514 break;
515 }
516 BUG_ON(i >= f->num_members);
517 f->arr[i] = f->arr[f->num_members - 1];
518 f->num_members--;
519 spin_unlock(&f->lock);
520}
521
522static int fanout_add(struct sock *sk, u16 id, u8 type)
523{
524 struct packet_sock *po = pkt_sk(sk);
525 struct packet_fanout *f, *match;
526 int err;
527
528 switch