PROBLEM: 2.4.37.9 destroying an Ethernet interface with permanent NUD leaves the kernels with undestroyable interfaces when ATM is compiled in

From: Sylvain Rochet
Date: Wed Apr 07 2010 - 16:23:50 EST


Hi,

When ATM and Ethernet are compiled in, ATM and Ethernet create their
NEIGH/ARP tables, they are both assigned to family AF_INET.


int neigh_add(....) {

...
for (tbl=neigh_tables; tbl; tbl = tbl->next) {
if (tbl->family != ndm->ndm_family)
continue;
...
}


As ATM table is created before Ethernet(main?) table,
net/core/neighbour.c::neigh_add() function add all permanent IP ARP
Ethernet NUD to the IP ATM table, which is wrong.

Therefore, when net/core/neighbour.c::neigh_ifdown() is called ARP
entries are not cleared, leaving dev->refcnt to a value that will never
be able to reach 0 anymore.

So, when net/core/dev.c::unregister_netdevice() is called it stalls
without being able to destroy the interface leaving the system with no
network tools working anymore.


This is really easy to reproduce:

openvpn --mktun --dev tap10
ip addr add 10.20.30.20/24 dev tap10
ip link set up dev tap10
ip neighbour add 10.20.30.40 lladdr 01:02:03:04:05:06 nud permanent dev tap10
ip link set down dev tap10
openvpn --rmtun --dev tap10

and then kernel log starts being filled by:

unregister_netdevice: waiting for tap10 to become free. Usage count = 2
unregister_netdevice: waiting for tap10 to become free. Usage count = 2
unregister_netdevice: waiting for tap10 to become free. Usage count = 2
unregister_netdevice: waiting for tap10 to become free. Usage count = 2


I changed the family of the ATM table to AF_ATMPVC, of course it fixes
the issue but I guess this is the wrong way to fix that.


Best regard,
Sylvain
diff -Nru linux-2.4.36.6.a/net/atm/clip.c linux-2.4.36.6.b/net/atm/clip.c
--- linux-2.4.36.6.a/net/atm/clip.c 2008-06-06 18:25:34.000000000 +0200
+++ linux-2.4.36.6.b/net/atm/clip.c 2010-04-07 21:33:38.000000000 +0200
@@ -277,7 +277,7 @@


static struct neigh_ops clip_neigh_ops = {
- family: AF_INET,
+ family: AF_ATMPVC,
destructor: clip_neigh_destroy,
solicit: clip_neigh_solicit,
error_report: clip_neigh_error,
@@ -316,7 +316,7 @@

static struct neigh_table clip_tbl = {
NULL, /* next */
- AF_INET, /* family */
+ AF_ATMPVC, /* family */
sizeof(struct neighbour)+sizeof(struct atmarp_entry), /* entry_size */
4, /* key_len */
clip_hash,

Attachment: signature.asc
Description: Digital signature