From: "Wilfried Weissmann" <wweissmann@gmx.at>
To: linux-kernel@vger.kernel.org, linux-net@vger.kernel.org,
davem@davemloft.net, 282492@bugs.debian.org
Subject: multiple neighbour cache tables for AF_INET
Date: Fri, 28 Jan 2005 14:00:37 +0100 (MET) [thread overview]
Message-ID: <24939.1106917237@www31.gmx.net> (raw)
[-- 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);
next reply other threads:[~2005-01-28 13:00 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-01-28 13:00 Wilfried Weissmann [this message]
2005-01-28 22:19 ` Herbert Xu
2005-01-28 22:46 ` YOSHIFUJI Hideaki / 吉藤英明
2005-01-29 10:06 ` Herbert Xu
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=24939.1106917237@www31.gmx.net \
--to=wweissmann@gmx.at \
--cc=282492@bugs.debian.org \
--cc=davem@davemloft.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-net@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®