linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* multiple neighbour cache tables for AF_INET
@ 2005-01-28 13:00 Wilfried Weissmann
  2005-01-28 22:19 ` Herbert Xu
  0 siblings, 1 reply; 4+ messages in thread
From: Wilfried Weissmann @ 2005-01-28 13:00 UTC (permalink / raw)
  To: linux-kernel, linux-net, davem, 282492

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="us-ascii", Size: 1032 bytes --]

Hi,

The kernels 2.4.28+ and 2.6.9+ with IPv4 and ATM-CLIP enabled have bugs in
the neighbour cache code. neigh_delete() and neigh_add() only work properly
if one cache table per address family exist. After ATM-CLIP installed a
second cache table for AF_INET, neigh_delete() and neigh_add() only examine
the first table (the ATM-CLIP table if IPv4 and ATM-CLIP are compiled into
the kernel). neigh_dump_info() is also affected if the neigh_dump_table()
call fails.

This bug causes "ip neigh flush dev <some ethernet device>" to run into an
infinite loop when the arp cache is already populated (debian bug #282492).
"ip neigh delete ..." commands for non ATM-CLIP entries fail with an EINVAL.
This is because of the IPv4 neighbour table that is installed in arp.c is
never examined when sending delete commands.

I have attached a minimally tested patch for 2.4.28 that fixes this problem.

Greetings,
Wilfried

-- 
10 GB Mailbox, 100 FreeSMS http://www.gmx.net/de/go/topmail
+++ GMX - die erste Adresse für Mail, Message, More +++

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

--- linux-2.4.28/net/core/neighbour.c	Fri Jan 28 14:26:59 2005
+++ linux-2.4.28fix/net/core/neighbour.c	Fri Jan 28 13:22:06 2005
@@ -1351,7 +1351,6 @@ int neigh_delete(struct sk_buff *skb, st
 
 		if (tbl->family != ndm->ndm_family)
 			continue;
-		read_unlock(&neigh_tbl_lock);
 
 		err = -EINVAL;
 		if (nda[NDA_DST-1] == NULL ||
@@ -1360,18 +1359,28 @@ int neigh_delete(struct sk_buff *skb, st
 
 		if (ndm->ndm_flags&NTF_PROXY) {
 			err = pneigh_delete(tbl, RTA_DATA(nda[NDA_DST-1]), dev);
-			goto out;
+			if(err) {
+				continue;	/* maybe in another table */
+			}
+			else {
+				goto out;
+			}
 		}
 
-		if (dev == NULL)
-			return -EINVAL;
+		if (dev == NULL) {
+			goto out;
+		}
 
 		n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev);
 		if (n) {
 			err = neigh_update(n, NULL, NUD_FAILED, 1, 0);
 			neigh_release(n);
 		}
+		else {
+			continue;	/* maybe in another table */
+		}
 out:
+		read_unlock(&neigh_tbl_lock);
 		if (dev)
 			dev_put(dev);
 		return err;
@@ -1390,6 +1399,8 @@ int neigh_add(struct sk_buff *skb, struc
 	struct rtattr **nda = arg;
 	struct neigh_table *tbl;
 	struct net_device *dev = NULL;
+	int err = -EADDRNOTAVAIL;
+	int olderr;
 
 	if (ndm->ndm_ifindex) {
 		if ((dev = dev_get_by_index(ndm->ndm_ifindex)) == NULL)
@@ -1398,35 +1409,47 @@ int neigh_add(struct sk_buff *skb, struc
 
 	read_lock(&neigh_tbl_lock);
 	for (tbl=neigh_tables; tbl; tbl = tbl->next) {
-		int err = 0;
 		int override = 1;
 		struct neighbour *n;
 
 		if (tbl->family != ndm->ndm_family)
 			continue;
-		read_unlock(&neigh_tbl_lock);
 
-		err = -EINVAL;
 		if (nda[NDA_DST-1] == NULL ||
-		    nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len))
+		    nda[NDA_DST-1]->rta_len != RTA_LENGTH(tbl->key_len)) {
+			err = -EINVAL;
 			goto out;
+		}
+
 		if (ndm->ndm_flags&NTF_PROXY) {
 			err = -ENOBUFS;
-			if (pneigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 1))
+			if (pneigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev, 1)) {
 				err = 0;
+				goto out;
+			}
+			else {
+				continue;	/* maybe in another table */
+			}
+		}
+		if (dev == NULL) {
+			err = -EINVAL;
 			goto out;
 		}
-		if (dev == NULL)
-			return -EINVAL;
-		err = -EINVAL;
+
 		if (nda[NDA_LLADDR-1] != NULL &&
-		    nda[NDA_LLADDR-1]->rta_len != RTA_LENGTH(dev->addr_len))
+		    nda[NDA_LLADDR-1]->rta_len != RTA_LENGTH(dev->addr_len)) {
+			err = -EINVAL;
 			goto out;
+		}
+
+		olderr=err;
 		err = 0;
 		n = neigh_lookup(tbl, RTA_DATA(nda[NDA_DST-1]), dev);
 		if (n) {
-			if (nlh->nlmsg_flags&NLM_F_EXCL)
+			if (nlh->nlmsg_flags&NLM_F_EXCL) {
 				err = -EEXIST;
+				goto outneigh;
+			}
 			override = nlh->nlmsg_flags&NLM_F_REPLACE;
 		} else if (!(nlh->nlmsg_flags&NLM_F_CREATE))
 			err = -ENOENT;
@@ -1442,9 +1465,16 @@ int neigh_add(struct sk_buff *skb, struc
 					   ndm->ndm_state,
 					   override, 0);
 		}
+		else {
+			err=olderr;
+			continue;	/* maybe in another table */
+		}
+
+outneigh:
 		if (n)
 			neigh_release(n);
 out:
+		read_unlock(&neigh_tbl_lock);
 		if (dev)
 			dev_put(dev);
 		return err;
@@ -1453,7 +1483,7 @@ out:
 
 	if (dev)
 		dev_put(dev);
-	return -EADDRNOTAVAIL;
+	return err;
 }
 
 
@@ -1547,8 +1577,7 @@ int neigh_dump_info(struct sk_buff *skb,
 			continue;
 		if (t > s_t)
 			memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(cb->args[0]));
-		if (neigh_dump_table(tbl, skb, cb) < 0) 
-			break;
+		neigh_dump_table(tbl, skb, cb);
 	}
 	read_unlock(&neigh_tbl_lock);
 

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: multiple neighbour cache tables for AF_INET
  2005-01-28 13:00 multiple neighbour cache tables for AF_INET Wilfried Weissmann
@ 2005-01-28 22:19 ` Herbert Xu
  2005-01-28 22:46   ` YOSHIFUJI Hideaki / 吉藤英明
  0 siblings, 1 reply; 4+ messages in thread
From: Herbert Xu @ 2005-01-28 22:19 UTC (permalink / raw)
  To: Wilfried Weissmann; +Cc: linux-kernel, linux-net, davem, 282492

Wilfried Weissmann <wweissmann@gmx.at> wrote:
> 
> The kernels 2.4.28+ and 2.6.9+ with IPv4 and ATM-CLIP enabled have bugs in
> the neighbour cache code. neigh_delete() and neigh_add() only work properly
> if one cache table per address family exist. After ATM-CLIP installed a
> second cache table for AF_INET, neigh_delete() and neigh_add() only examine
> the first table (the ATM-CLIP table if IPv4 and ATM-CLIP are compiled into
> the kernel). neigh_dump_info() is also affected if the neigh_dump_table()
> call fails.

Indeed, this has been the case for a very long time.

IMHO you need to give the user a way to specify which table they want
to operate on.  If they don't specify one, then the current behaviour
of choosing the first table found is reasonble.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: multiple neighbour cache tables for AF_INET
  2005-01-28 22:19 ` Herbert Xu
@ 2005-01-28 22:46   ` YOSHIFUJI Hideaki / 吉藤英明
  2005-01-29 10:06     ` Herbert Xu
  0 siblings, 1 reply; 4+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2005-01-28 22:46 UTC (permalink / raw)
  To: herbert; +Cc: wweissmann, linux-kernel, linux-net, davem, 282492, yoshfuji

In article <E1CueSz-0000lz-00@gondolin.me.apana.org.au> (at Sat, 29 Jan 2005 09:19:49 +1100), Herbert Xu <herbert@gondor.apana.org.au> says:

> IMHO you need to give the user a way to specify which table they want
> to operate on.  If they don't specify one, then the current behaviour
> of choosing the first table found is reasonble.

We have dev. Isn't is sufficient?

--yoshfuji

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: multiple neighbour cache tables for AF_INET
  2005-01-28 22:46   ` YOSHIFUJI Hideaki / 吉藤英明
@ 2005-01-29 10:06     ` Herbert Xu
  0 siblings, 0 replies; 4+ messages in thread
From: Herbert Xu @ 2005-01-29 10:06 UTC (permalink / raw)
  To: YOSHIFUJI Hideaki / ?$B5HF#1QL@
  Cc: wweissmann, linux-kernel, linux-net, davem, 282492

On Sat, Jan 29, 2005 at 07:46:05AM +0900, YOSHIFUJI Hideaki / ?$B5HF#1QL@ wrote:
> In article <E1CueSz-0000lz-00@gondolin.me.apana.org.au> (at Sat, 29 Jan 2005 09:19:49 +1100), Herbert Xu <herbert@gondor.apana.org.au> says:
> 
> > IMHO you need to give the user a way to specify which table they want
> > to operate on.  If they don't specify one, then the current behaviour
> > of choosing the first table found is reasonble.
> 
> We have dev. Isn't is sufficient?

It could be used for neigh_add/neigh_delete.  We'll need to add a way
to query whether a given table is the right one for a device.

For dump it isn't the same.  However, perhaps it's not too important
to query a specific table.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2005-01-29 10:10 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-01-28 13:00 multiple neighbour cache tables for AF_INET Wilfried Weissmann
2005-01-28 22:19 ` Herbert Xu
2005-01-28 22:46   ` YOSHIFUJI Hideaki / 吉藤英明
2005-01-29 10:06     ` Herbert Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).