All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Borkmann <danborkmann@googlemail.com>
To: linux-kernel@vger.kernel.org
Cc: Jeff Moyer <jmoyer@redhat.com>,
	netdev@vger.kernel.org, netdev@oss.sgi.com,
	David Miller <davem@davemloft.net>
Subject: [PATCH] netpoll: allow execution of multiple rx_hooks per interface
Date: Wed, 06 Jan 2010 21:54:45 +0100	[thread overview]
Message-ID: <4B44F895.9080205@gmail.com> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 578 bytes --]

Hi,

this patch allows the registration and _execution_ of multiple netpoll
rx_hooks per interface. Currently, it is possible to register multiple
netpoll structures to one interface, _but_ only one single rx_hook (from
the netpoll struct that has been registered last) can be executed, which
was an oversight in the implementation [1].
So, this patch fixes it. I've sucessfully tested it within 2.6.32.2 with
the registration of multiple rx_hook clients for several times. I'd
appreciate comments / feedback.

Thanks,
Daniel

[1] http://lwn.net/Articles/140852/

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: netpoll_multiple_rx_hooks.patch --]
[-- Type: text/x-patch; name="netpoll_multiple_rx_hooks.patch", Size: 4264 bytes --]

Signed-off-by: Daniel Borkmann <danborkmann@googlemail.com>

diff -Nur a/include/linux/netpoll.h b/include/linux/netpoll.h
--- a/include/linux/netpoll.h	2010-01-05 23:52:58.000000000 +0100
+++ b/include/linux/netpoll.h	2010-01-06 00:12:54.000000000 +0100
@@ -21,6 +21,7 @@
 	__be32 local_ip, remote_ip;
 	u16 local_port, remote_port;
 	u8 remote_mac[ETH_ALEN];
+	struct netpoll *next; /* rx list for net device */
 };
 
 struct netpoll_info {
diff -Nur a/net/core/netpoll.c b/net/core/netpoll.c
--- a/net/core/netpoll.c	2010-01-05 23:53:07.000000000 +0100
+++ b/net/core/netpoll.c	2010-01-06 20:44:59.000000000 +0100
@@ -493,13 +493,13 @@
 
 int __netpoll_rx(struct sk_buff *skb)
 {
-	int proto, len, ulen;
+	int proto, len, ulen, hits;
 	struct iphdr *iph;
 	struct udphdr *uh;
 	struct netpoll_info *npi = skb->dev->npinfo;
-	struct netpoll *np = npi->rx_np;
+	struct netpoll **np = &npi->rx_np;
 
-	if (!np)
+	if (!(*np))
 		goto out;
 	if (skb->dev->type != ARPHRD_ETHER)
 		goto out;
@@ -551,16 +551,23 @@
 		goto out;
 	if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
 		goto out;
-	if (np->local_ip && np->local_ip != iph->daddr)
-		goto out;
-	if (np->remote_ip && np->remote_ip != iph->saddr)
-		goto out;
-	if (np->local_port && np->local_port != ntohs(uh->dest))
-		goto out;
 
-	np->rx_hook(np, ntohs(uh->source),
-		    (char *)(uh+1),
-		    ulen - sizeof(struct udphdr));
+	for (hits = 0; (*np) != NULL; np = &((*np)->next)) {
+		if ((*np)->local_ip && (*np)->local_ip != iph->daddr)
+			continue;
+		if ((*np)->remote_ip && (*np)->remote_ip != iph->saddr)
+			continue;
+		if ((*np)->local_port && (*np)->local_port != ntohs(uh->dest))
+			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;
@@ -679,6 +686,45 @@
 	return -1;
 }
 
+static int netpoll_rx_list_register(struct netpoll **np_head,
+				    struct netpoll *np)
+{
+	while ((*np_head) != NULL) {
+		if ((*np_head) == np)
+			return -EEXIST;
+		np_head = &((*np_head)->next);
+	}
+
+	np->next = *np_head;
+	rcu_assign_pointer(*np_head, np);
+	return 0;
+}
+
+static int netpoll_rx_list_unregister(struct netpoll **np_head,
+				      struct netpoll *np)
+{
+	while ((*np_head) != NULL) {
+		if ((*np_head) == np) {
+			rcu_assign_pointer(*np_head, np->next);
+			return 0;
+		}
+		np_head = &((*np_head)->next);
+	}
+	return -ENOENT;
+}
+
+static void netpoll_rx_list_nullify(struct netpoll **np_head)
+{
+	struct netpoll *np = NULL;
+
+	while ((*np_head) != NULL) {
+		np = (*np_head);
+		np_head = &((*np_head)->next);
+		np->dev = NULL;
+		np->next = NULL;
+	}
+}
+
 int netpoll_setup(struct netpoll *np)
 {
 	struct net_device *ndev = NULL;
@@ -695,6 +741,7 @@
 		return -ENODEV;
 	}
 
+	np->next = NULL;
 	np->dev = ndev;
 	if (!ndev->npinfo) {
 		npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
@@ -785,7 +832,7 @@
 	if (np->rx_hook) {
 		spin_lock_irqsave(&npinfo->rx_lock, flags);
 		npinfo->rx_flags |= NETPOLL_RX_ENABLED;
-		npinfo->rx_np = np;
+		netpoll_rx_list_register(&npinfo->rx_np, np);
 		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 	}
 
@@ -801,9 +848,14 @@
 	return 0;
 
  release:
-	if (!ndev->npinfo)
+	if (!ndev->npinfo) {
+		spin_lock_irqsave(&npinfo->rx_lock, flags);
+		netpoll_rx_list_nullify(&npinfo->rx_np);
+		spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+
 		kfree(npinfo);
-	np->dev = NULL;
+	}
+
 	dev_put(ndev);
 	return err;
 }
@@ -823,10 +875,11 @@
 	if (np->dev) {
 		npinfo = np->dev->npinfo;
 		if (npinfo) {
-			if (npinfo->rx_np == np) {
+			if (npinfo->rx_np) {
 				spin_lock_irqsave(&npinfo->rx_lock, flags);
-				npinfo->rx_np = NULL;
-				npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
+				netpoll_rx_list_unregister(&npinfo->rx_np, np);
+				if (!npinfo->rx_np)
+					npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
 				spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 			}
 
@@ -845,7 +898,10 @@
 		dev_put(np->dev);
 	}
 
+	np->next = NULL;
 	np->dev = NULL;
+
+	synchronize_rcu();
 }
 
 int netpoll_trap(void)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 261 bytes --]

             reply	other threads:[~2010-01-06 20:55 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-01-06 20:54 Daniel Borkmann [this message]
2010-01-07  3:54 ` [PATCH] netpoll: allow execution of multiple rx_hooks per interface Matt Mackall
2010-01-07  9:02   ` David Miller
2010-01-07 19:06     ` Daniel Borkmann
2010-01-08  0:20       ` Daniel Borkmann
2010-01-11 23:21         ` Matt Mackall
2010-01-11 23:59           ` David Miller
2010-01-12  0:03             ` Matt Mackall
2010-01-12  0:09               ` Daniel Borkmann
2010-01-13  0:27                 ` Daniel Borkmann
2010-01-13 13:57                   ` Jeff Moyer
2010-01-13 16:53                     ` Daniel Borkmann
2010-01-13 16:53                       ` Daniel Borkmann
2010-01-14  4:41                   ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B44F895.9080205@gmail.com \
    --to=danborkmann@googlemail.com \
    --cc=davem@davemloft.net \
    --cc=jmoyer@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@oss.sgi.com \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.