Skip to content

Commit 508e14b

Browse files
Daniel Borkmanndavem330
authored andcommitted
netpoll: allow execution of multiple rx_hooks per interface
Signed-off-by: Daniel Borkmann <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e1d5a01 commit 508e14b

File tree

2 files changed

+114
-66
lines changed

2 files changed

+114
-66
lines changed

include/linux/netpoll.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,20 @@ struct netpoll {
2121
__be32 local_ip, remote_ip;
2222
u16 local_port, remote_port;
2323
u8 remote_mac[ETH_ALEN];
24+
25+
struct list_head rx; /* rx_np list element */
2426
};
2527

2628
struct netpoll_info {
2729
atomic_t refcnt;
30+
2831
int rx_flags;
2932
spinlock_t rx_lock;
30-
struct netpoll *rx_np; /* netpoll that registered an rx_hook */
33+
struct list_head rx_np; /* netpolls that registered an rx_hook */
34+
3135
struct sk_buff_head arp_tx; /* list of arp requests to reply to */
3236
struct sk_buff_head txq;
37+
3338
struct delayed_work tx_work;
3439
};
3540

@@ -51,7 +56,7 @@ static inline int netpoll_rx(struct sk_buff *skb)
5156
unsigned long flags;
5257
int ret = 0;
5358

54-
if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags))
59+
if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
5560
return 0;
5661

5762
spin_lock_irqsave(&npinfo->rx_lock, flags);
@@ -67,7 +72,7 @@ static inline int netpoll_rx_on(struct sk_buff *skb)
6772
{
6873
struct netpoll_info *npinfo = skb->dev->npinfo;
6974

70-
return npinfo && (npinfo->rx_np || npinfo->rx_flags);
75+
return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
7176
}
7277

7378
static inline int netpoll_receive_skb(struct sk_buff *skb)

net/core/netpoll.c

Lines changed: 106 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -407,11 +407,24 @@ static void arp_reply(struct sk_buff *skb)
407407
__be32 sip, tip;
408408
unsigned char *sha;
409409
struct sk_buff *send_skb;
410-
struct netpoll *np = NULL;
410+
struct netpoll *np, *tmp;
411+
unsigned long flags;
412+
int hits = 0;
413+
414+
if (list_empty(&npinfo->rx_np))
415+
return;
416+
417+
/* Before checking the packet, we do some early
418+
inspection whether this is interesting at all */
419+
spin_lock_irqsave(&npinfo->rx_lock, flags);
420+
list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
421+
if (np->dev == skb->dev)
422+
hits++;
423+
}
424+
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
411425

412-
if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev)
413-
np = npinfo->rx_np;
414-
if (!np)
426+
/* No netpoll struct is using this dev */
427+
if (!hits)
415428
return;
416429

417430
/* No arp on this interface */
@@ -437,77 +450,91 @@ static void arp_reply(struct sk_buff *skb)
437450
arp_ptr += skb->dev->addr_len;
438451
memcpy(&sip, arp_ptr, 4);
439452
arp_ptr += 4;
440-
/* if we actually cared about dst hw addr, it would get copied here */
453+
/* If we actually cared about dst hw addr,
454+
it would get copied here */
441455
arp_ptr += skb->dev->addr_len;
442456
memcpy(&tip, arp_ptr, 4);
443457

444458
/* Should we ignore arp? */
445-
if (tip != np->local_ip ||
446-
ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
459+
if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
447460
return;
448461

449462
size = arp_hdr_len(skb->dev);
450-
send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
451-
LL_RESERVED_SPACE(np->dev));
452463

453-
if (!send_skb)
454-
return;
455-
456-
skb_reset_network_header(send_skb);
457-
arp = (struct arphdr *) skb_put(send_skb, size);
458-
send_skb->dev = skb->dev;
459-
send_skb->protocol = htons(ETH_P_ARP);
464+
spin_lock_irqsave(&npinfo->rx_lock, flags);
465+
list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
466+
if (tip != np->local_ip)
467+
continue;
460468

461-
/* Fill the device header for the ARP frame */
462-
if (dev_hard_header(send_skb, skb->dev, ptype,
463-
sha, np->dev->dev_addr,
464-
send_skb->len) < 0) {
465-
kfree_skb(send_skb);
466-
return;
467-
}
469+
send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
470+
LL_RESERVED_SPACE(np->dev));
471+
if (!send_skb)
472+
continue;
468473

469-
/*
470-
* Fill out the arp protocol part.
471-
*
472-
* we only support ethernet device type,
473-
* which (according to RFC 1390) should always equal 1 (Ethernet).
474-
*/
474+
skb_reset_network_header(send_skb);
475+
arp = (struct arphdr *) skb_put(send_skb, size);
476+
send_skb->dev = skb->dev;
477+
send_skb->protocol = htons(ETH_P_ARP);
475478

476-
arp->ar_hrd = htons(np->dev->type);
477-
arp->ar_pro = htons(ETH_P_IP);
478-
arp->ar_hln = np->dev->addr_len;
479-
arp->ar_pln = 4;
480-
arp->ar_op = htons(type);
479+
/* Fill the device header for the ARP frame */
480+
if (dev_hard_header(send_skb, skb->dev, ptype,
481+
sha, np->dev->dev_addr,
482+
send_skb->len) < 0) {
483+
kfree_skb(send_skb);
484+
continue;
485+
}
481486

482-
arp_ptr=(unsigned char *)(arp + 1);
483-
memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
484-
arp_ptr += np->dev->addr_len;
485-
memcpy(arp_ptr, &tip, 4);
486-
arp_ptr += 4;
487-
memcpy(arp_ptr, sha, np->dev->addr_len);
488-
arp_ptr += np->dev->addr_len;
489-
memcpy(arp_ptr, &sip, 4);
487+
/*
488+
* Fill out the arp protocol part.
489+
*
490+
* we only support ethernet device type,
491+
* which (according to RFC 1390) should
492+
* always equal 1 (Ethernet).
493+
*/
490494

491-
netpoll_send_skb(np, send_skb);
495+
arp->ar_hrd = htons(np->dev->type);
496+
arp->ar_pro = htons(ETH_P_IP);
497+
arp->ar_hln = np->dev->addr_len;
498+
arp->ar_pln = 4;
499+
arp->ar_op = htons(type);
500+
501+
arp_ptr = (unsigned char *)(arp + 1);
502+
memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
503+
arp_ptr += np->dev->addr_len;
504+
memcpy(arp_ptr, &tip, 4);
505+
arp_ptr += 4;
506+
memcpy(arp_ptr, sha, np->dev->addr_len);
507+
arp_ptr += np->dev->addr_len;
508+
memcpy(arp_ptr, &sip, 4);
509+
510+
netpoll_send_skb(np, send_skb);
511+
512+
/* If there are several rx_hooks for the same address,
513+
we're fine by sending a single reply */
514+
break;
515+
}
516+
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
492517
}
493518

494519
int __netpoll_rx(struct sk_buff *skb)
495520
{
496521
int proto, len, ulen;
522+
int hits = 0;
497523
struct iphdr *iph;
498524
struct udphdr *uh;
499-
struct netpoll_info *npi = skb->dev->npinfo;
500-
struct netpoll *np = npi->rx_np;
525+
struct netpoll_info *npinfo = skb->dev->npinfo;
526+
struct netpoll *np, *tmp;
501527

502-
if (!np)
528+
if (list_empty(&npinfo->rx_np))
503529
goto out;
530+
504531
if (skb->dev->type != ARPHRD_ETHER)
505532
goto out;
506533

507534
/* check if netpoll clients need ARP */
508535
if (skb->protocol == htons(ETH_P_ARP) &&
509536
atomic_read(&trapped)) {
510-
skb_queue_tail(&npi->arp_tx, skb);
537+
skb_queue_tail(&npinfo->arp_tx, skb);
511538
return 1;
512539
}
513540

@@ -551,16 +578,23 @@ int __netpoll_rx(struct sk_buff *skb)
551578
goto out;
552579
if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
553580
goto out;
554-
if (np->local_ip && np->local_ip != iph->daddr)
555-
goto out;
556-
if (np->remote_ip && np->remote_ip != iph->saddr)
557-
goto out;
558-
if (np->local_port && np->local_port != ntohs(uh->dest))
559-
goto out;
560581

561-
np->rx_hook(np, ntohs(uh->source),
562-
(char *)(uh+1),
563-
ulen - sizeof(struct udphdr));
582+
list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
583+
if (np->local_ip && np->local_ip != iph->daddr)
584+
continue;
585+
if (np->remote_ip && np->remote_ip != iph->saddr)
586+
continue;
587+
if (np->local_port && np->local_port != ntohs(uh->dest))
588+
continue;
589+
590+
np->rx_hook(np, ntohs(uh->source),
591+
(char *)(uh+1),
592+
ulen - sizeof(struct udphdr));
593+
hits++;
594+
}
595+
596+
if (!hits)
597+
goto out;
564598

565599
kfree_skb(skb);
566600
return 1;
@@ -684,6 +718,7 @@ int netpoll_setup(struct netpoll *np)
684718
struct net_device *ndev = NULL;
685719
struct in_device *in_dev;
686720
struct netpoll_info *npinfo;
721+
struct netpoll *npe, *tmp;
687722
unsigned long flags;
688723
int err;
689724

@@ -704,7 +739,7 @@ int netpoll_setup(struct netpoll *np)
704739
}
705740

706741
npinfo->rx_flags = 0;
707-
npinfo->rx_np = NULL;
742+
INIT_LIST_HEAD(&npinfo->rx_np);
708743

709744
spin_lock_init(&npinfo->rx_lock);
710745
skb_queue_head_init(&npinfo->arp_tx);
@@ -785,7 +820,7 @@ int netpoll_setup(struct netpoll *np)
785820
if (np->rx_hook) {
786821
spin_lock_irqsave(&npinfo->rx_lock, flags);
787822
npinfo->rx_flags |= NETPOLL_RX_ENABLED;
788-
npinfo->rx_np = np;
823+
list_add_tail(&np->rx, &npinfo->rx_np);
789824
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
790825
}
791826

@@ -801,9 +836,16 @@ int netpoll_setup(struct netpoll *np)
801836
return 0;
802837

803838
release:
804-
if (!ndev->npinfo)
839+
if (!ndev->npinfo) {
840+
spin_lock_irqsave(&npinfo->rx_lock, flags);
841+
list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) {
842+
npe->dev = NULL;
843+
}
844+
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
845+
805846
kfree(npinfo);
806-
np->dev = NULL;
847+
}
848+
807849
dev_put(ndev);
808850
return err;
809851
}
@@ -823,10 +865,11 @@ void netpoll_cleanup(struct netpoll *np)
823865
if (np->dev) {
824866
npinfo = np->dev->npinfo;
825867
if (npinfo) {
826-
if (npinfo->rx_np == np) {
868+
if (!list_empty(&npinfo->rx_np)) {
827869
spin_lock_irqsave(&npinfo->rx_lock, flags);
828-
npinfo->rx_np = NULL;
829-
npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
870+
list_del(&np->rx);
871+
if (list_empty(&npinfo->rx_np))
872+
npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
830873
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
831874
}
832875

0 commit comments

Comments
 (0)