Loading include/linux/netpoll.h +8 −3 Original line number Diff line number Diff line Loading @@ -21,15 +21,20 @@ struct netpoll { __be32 local_ip, remote_ip; u16 local_port, remote_port; u8 remote_mac[ETH_ALEN]; struct list_head rx; /* rx_np list element */ }; struct netpoll_info { atomic_t refcnt; int rx_flags; spinlock_t rx_lock; struct netpoll *rx_np; /* netpoll that registered an rx_hook */ struct list_head rx_np; /* netpolls that registered an rx_hook */ struct sk_buff_head arp_tx; /* list of arp requests to reply to */ struct sk_buff_head txq; struct delayed_work tx_work; }; Loading @@ -51,7 +56,7 @@ static inline int netpoll_rx(struct sk_buff *skb) unsigned long flags; int ret = 0; if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags)) if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags)) return 0; spin_lock_irqsave(&npinfo->rx_lock, flags); Loading @@ -67,7 +72,7 @@ static inline int netpoll_rx_on(struct sk_buff *skb) { struct netpoll_info *npinfo = skb->dev->npinfo; return npinfo && (npinfo->rx_np || npinfo->rx_flags); return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags); } static inline int netpoll_receive_skb(struct sk_buff *skb) Loading net/core/netpoll.c +106 −63 Original line number Diff line number Diff line Loading @@ -407,11 +407,24 @@ static void arp_reply(struct sk_buff *skb) __be32 sip, tip; unsigned char *sha; struct sk_buff *send_skb; struct netpoll *np = NULL; struct netpoll *np, *tmp; unsigned long flags; int hits = 0; if (list_empty(&npinfo->rx_np)) return; /* Before checking the packet, we do some early inspection whether this is interesting at all */ spin_lock_irqsave(&npinfo->rx_lock, flags); list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { if (np->dev == skb->dev) hits++; } spin_unlock_irqrestore(&npinfo->rx_lock, flags); if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev) np = npinfo->rx_np; if (!np) /* No netpoll struct is using this dev */ if (!hits) return; /* No arp on this interface */ Loading @@ -437,21 +450,26 @@ static void arp_reply(struct sk_buff *skb) arp_ptr += skb->dev->addr_len; memcpy(&sip, arp_ptr, 4); arp_ptr += 4; /* if we actually cared about dst hw addr, it would get copied here */ /* If we actually cared about dst hw addr, it would get copied here */ arp_ptr += skb->dev->addr_len; memcpy(&tip, arp_ptr, 4); /* Should we ignore arp? */ if (tip != np->local_ip || ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) return; size = arp_hdr_len(skb->dev); spin_lock_irqsave(&npinfo->rx_lock, flags); list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { if (tip != np->local_ip) continue; send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev), LL_RESERVED_SPACE(np->dev)); if (!send_skb) return; continue; skb_reset_network_header(send_skb); arp = (struct arphdr *) skb_put(send_skb, size); Loading @@ -463,14 +481,15 @@ static void arp_reply(struct sk_buff *skb) sha, np->dev->dev_addr, send_skb->len) < 0) { kfree_skb(send_skb); return; continue; } /* * Fill out the arp protocol part. * * we only support ethernet device type, * which (according to RFC 1390) should always equal 1 (Ethernet). * which (according to RFC 1390) should * always equal 1 (Ethernet). */ arp->ar_hrd = htons(np->dev->type); Loading @@ -489,25 +508,33 @@ static void arp_reply(struct sk_buff *skb) memcpy(arp_ptr, &sip, 4); netpoll_send_skb(np, send_skb); /* If there are several rx_hooks for the same address, we're fine by sending a single reply */ break; } spin_unlock_irqrestore(&npinfo->rx_lock, flags); } int __netpoll_rx(struct sk_buff *skb) { int proto, len, ulen; int hits = 0; struct iphdr *iph; struct udphdr *uh; struct netpoll_info *npi = skb->dev->npinfo; struct netpoll *np = npi->rx_np; struct netpoll_info *npinfo = skb->dev->npinfo; struct netpoll *np, *tmp; if (!np) if (list_empty(&npinfo->rx_np)) goto out; if (skb->dev->type != ARPHRD_ETHER) goto out; /* check if netpoll clients need ARP */ if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) { skb_queue_tail(&npi->arp_tx, skb); skb_queue_tail(&npinfo->arp_tx, skb); return 1; } Loading Loading @@ -551,16 +578,23 @@ int __netpoll_rx(struct sk_buff *skb) goto out; if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) goto out; list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { if (np->local_ip && np->local_ip != iph->daddr) goto out; continue; if (np->remote_ip && np->remote_ip != iph->saddr) goto out; continue; if (np->local_port && np->local_port != ntohs(uh->dest)) goto out; continue; np->rx_hook(np, ntohs(uh->source), (char *)(uh+1), ulen - sizeof(struct udphdr)); hits++; } if (!hits) goto out; kfree_skb(skb); return 1; Loading Loading @@ -684,6 +718,7 @@ int netpoll_setup(struct netpoll *np) struct net_device *ndev = NULL; struct in_device *in_dev; struct netpoll_info *npinfo; struct netpoll *npe, *tmp; unsigned long flags; int err; Loading @@ -704,7 +739,7 @@ int netpoll_setup(struct netpoll *np) } npinfo->rx_flags = 0; npinfo->rx_np = NULL; INIT_LIST_HEAD(&npinfo->rx_np); spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); Loading Loading @@ -785,7 +820,7 @@ int netpoll_setup(struct netpoll *np) if (np->rx_hook) { spin_lock_irqsave(&npinfo->rx_lock, flags); npinfo->rx_flags |= NETPOLL_RX_ENABLED; npinfo->rx_np = np; list_add_tail(&np->rx, &npinfo->rx_np); spin_unlock_irqrestore(&npinfo->rx_lock, flags); } Loading @@ -801,9 +836,16 @@ int netpoll_setup(struct netpoll *np) return 0; release: if (!ndev->npinfo) if (!ndev->npinfo) { spin_lock_irqsave(&npinfo->rx_lock, flags); list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) { npe->dev = NULL; } spin_unlock_irqrestore(&npinfo->rx_lock, flags); kfree(npinfo); np->dev = NULL; } dev_put(ndev); return err; } Loading @@ -823,9 +865,10 @@ void netpoll_cleanup(struct netpoll *np) if (np->dev) { npinfo = np->dev->npinfo; if (npinfo) { if (npinfo->rx_np == np) { if (!list_empty(&npinfo->rx_np)) { spin_lock_irqsave(&npinfo->rx_lock, flags); npinfo->rx_np = NULL; list_del(&np->rx); if (list_empty(&npinfo->rx_np)) npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; spin_unlock_irqrestore(&npinfo->rx_lock, flags); } Loading Loading
include/linux/netpoll.h +8 −3 Original line number Diff line number Diff line Loading @@ -21,15 +21,20 @@ struct netpoll { __be32 local_ip, remote_ip; u16 local_port, remote_port; u8 remote_mac[ETH_ALEN]; struct list_head rx; /* rx_np list element */ }; struct netpoll_info { atomic_t refcnt; int rx_flags; spinlock_t rx_lock; struct netpoll *rx_np; /* netpoll that registered an rx_hook */ struct list_head rx_np; /* netpolls that registered an rx_hook */ struct sk_buff_head arp_tx; /* list of arp requests to reply to */ struct sk_buff_head txq; struct delayed_work tx_work; }; Loading @@ -51,7 +56,7 @@ static inline int netpoll_rx(struct sk_buff *skb) unsigned long flags; int ret = 0; if (!npinfo || (!npinfo->rx_np && !npinfo->rx_flags)) if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags)) return 0; spin_lock_irqsave(&npinfo->rx_lock, flags); Loading @@ -67,7 +72,7 @@ static inline int netpoll_rx_on(struct sk_buff *skb) { struct netpoll_info *npinfo = skb->dev->npinfo; return npinfo && (npinfo->rx_np || npinfo->rx_flags); return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags); } static inline int netpoll_receive_skb(struct sk_buff *skb) Loading
net/core/netpoll.c +106 −63 Original line number Diff line number Diff line Loading @@ -407,11 +407,24 @@ static void arp_reply(struct sk_buff *skb) __be32 sip, tip; unsigned char *sha; struct sk_buff *send_skb; struct netpoll *np = NULL; struct netpoll *np, *tmp; unsigned long flags; int hits = 0; if (list_empty(&npinfo->rx_np)) return; /* Before checking the packet, we do some early inspection whether this is interesting at all */ spin_lock_irqsave(&npinfo->rx_lock, flags); list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { if (np->dev == skb->dev) hits++; } spin_unlock_irqrestore(&npinfo->rx_lock, flags); if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev) np = npinfo->rx_np; if (!np) /* No netpoll struct is using this dev */ if (!hits) return; /* No arp on this interface */ Loading @@ -437,21 +450,26 @@ static void arp_reply(struct sk_buff *skb) arp_ptr += skb->dev->addr_len; memcpy(&sip, arp_ptr, 4); arp_ptr += 4; /* if we actually cared about dst hw addr, it would get copied here */ /* If we actually cared about dst hw addr, it would get copied here */ arp_ptr += skb->dev->addr_len; memcpy(&tip, arp_ptr, 4); /* Should we ignore arp? */ if (tip != np->local_ip || ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) return; size = arp_hdr_len(skb->dev); spin_lock_irqsave(&npinfo->rx_lock, flags); list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { if (tip != np->local_ip) continue; send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev), LL_RESERVED_SPACE(np->dev)); if (!send_skb) return; continue; skb_reset_network_header(send_skb); arp = (struct arphdr *) skb_put(send_skb, size); Loading @@ -463,14 +481,15 @@ static void arp_reply(struct sk_buff *skb) sha, np->dev->dev_addr, send_skb->len) < 0) { kfree_skb(send_skb); return; continue; } /* * Fill out the arp protocol part. * * we only support ethernet device type, * which (according to RFC 1390) should always equal 1 (Ethernet). * which (according to RFC 1390) should * always equal 1 (Ethernet). */ arp->ar_hrd = htons(np->dev->type); Loading @@ -489,25 +508,33 @@ static void arp_reply(struct sk_buff *skb) memcpy(arp_ptr, &sip, 4); netpoll_send_skb(np, send_skb); /* If there are several rx_hooks for the same address, we're fine by sending a single reply */ break; } spin_unlock_irqrestore(&npinfo->rx_lock, flags); } int __netpoll_rx(struct sk_buff *skb) { int proto, len, ulen; int hits = 0; struct iphdr *iph; struct udphdr *uh; struct netpoll_info *npi = skb->dev->npinfo; struct netpoll *np = npi->rx_np; struct netpoll_info *npinfo = skb->dev->npinfo; struct netpoll *np, *tmp; if (!np) if (list_empty(&npinfo->rx_np)) goto out; if (skb->dev->type != ARPHRD_ETHER) goto out; /* check if netpoll clients need ARP */ if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) { skb_queue_tail(&npi->arp_tx, skb); skb_queue_tail(&npinfo->arp_tx, skb); return 1; } Loading Loading @@ -551,16 +578,23 @@ int __netpoll_rx(struct sk_buff *skb) goto out; if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr)) goto out; list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { if (np->local_ip && np->local_ip != iph->daddr) goto out; continue; if (np->remote_ip && np->remote_ip != iph->saddr) goto out; continue; if (np->local_port && np->local_port != ntohs(uh->dest)) goto out; continue; np->rx_hook(np, ntohs(uh->source), (char *)(uh+1), ulen - sizeof(struct udphdr)); hits++; } if (!hits) goto out; kfree_skb(skb); return 1; Loading Loading @@ -684,6 +718,7 @@ int netpoll_setup(struct netpoll *np) struct net_device *ndev = NULL; struct in_device *in_dev; struct netpoll_info *npinfo; struct netpoll *npe, *tmp; unsigned long flags; int err; Loading @@ -704,7 +739,7 @@ int netpoll_setup(struct netpoll *np) } npinfo->rx_flags = 0; npinfo->rx_np = NULL; INIT_LIST_HEAD(&npinfo->rx_np); spin_lock_init(&npinfo->rx_lock); skb_queue_head_init(&npinfo->arp_tx); Loading Loading @@ -785,7 +820,7 @@ int netpoll_setup(struct netpoll *np) if (np->rx_hook) { spin_lock_irqsave(&npinfo->rx_lock, flags); npinfo->rx_flags |= NETPOLL_RX_ENABLED; npinfo->rx_np = np; list_add_tail(&np->rx, &npinfo->rx_np); spin_unlock_irqrestore(&npinfo->rx_lock, flags); } Loading @@ -801,9 +836,16 @@ int netpoll_setup(struct netpoll *np) return 0; release: if (!ndev->npinfo) if (!ndev->npinfo) { spin_lock_irqsave(&npinfo->rx_lock, flags); list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) { npe->dev = NULL; } spin_unlock_irqrestore(&npinfo->rx_lock, flags); kfree(npinfo); np->dev = NULL; } dev_put(ndev); return err; } Loading @@ -823,9 +865,10 @@ void netpoll_cleanup(struct netpoll *np) if (np->dev) { npinfo = np->dev->npinfo; if (npinfo) { if (npinfo->rx_np == np) { if (!list_empty(&npinfo->rx_np)) { spin_lock_irqsave(&npinfo->rx_lock, flags); npinfo->rx_np = NULL; list_del(&np->rx); if (list_empty(&npinfo->rx_np)) npinfo->rx_flags &= ~NETPOLL_RX_ENABLED; spin_unlock_irqrestore(&npinfo->rx_lock, flags); } Loading