[NEIGH]: Fix IP-over-ATM and ARP interaction.
The classical IP over ATM code maintains its own IPv4 <-> <ATM stuff> ARP table, using the standard neighbour-table code. The neigh_table_init function adds this neighbour table to a linked list of all neighbor tables which is used by the functions neigh_delete() neigh_add() and neightbl_set(), all called by the netlink code. Once the ATM neighbour table is added to the list, there are two tables with family == AF_INET there, and ARP entries sent via netlink go into the first table with matching family. This is indeterminate and often wrong. To see the bug, on a kernel with CLIP enabled, create a standard IPv4 ARP entry by pinging an unused address on a local subnet. Then attempt to complete that entry by doing ip neigh replace <ip address> lladdr <some mac address> nud reachable Looking at the ARP tables by using ip neigh show will reveal two ARP entries for the same address. One of these can be found in /proc/net/arp, and the other in /proc/net/atm/arp. This patch adds a new function, neigh_table_init_no_netlink() which does everything the neigh_table_init() does, except add the table to the netlink all-arp-tables chain. In addition neigh_table_init() has a check that all tables on the chain have a distinct address family. The init call in clip.c is changed to call neigh_table_init_no_netlink(). Since ATM ARP tables are rather more complicated than can currently be handled by the available rtattrs in the netlink protocol, no functionality is lost by this patch, and non-ATM ARP manipulation via netlink is rescued. A more complete solution would involve a rtattr for ATM ARP entries and some way for the netlink code to give neigh_add and friends more information than just address family with which to find the correct ARP table. [ I've changed the assertion checking in neigh_table_init() to not use BUG_ON() while holding neigh_tbl_lock. Instead we remember that we found an existing tbl with the same family, and after dropping the lock we'll give a diagnostic kernel log message and a stack dump. -DaveM ] Signed-off-by: Simon Kelley <simon@thekelleys.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
ef34814426
Коммит
bd89efc532
|
@ -211,6 +211,7 @@ struct neigh_table
|
|||
#define NEIGH_UPDATE_F_ADMIN 0x80000000
|
||||
|
||||
extern void neigh_table_init(struct neigh_table *tbl);
|
||||
extern void neigh_table_init_no_netlink(struct neigh_table *tbl);
|
||||
extern int neigh_table_clear(struct neigh_table *tbl);
|
||||
extern struct neighbour * neigh_lookup(struct neigh_table *tbl,
|
||||
const void *pkey,
|
||||
|
|
|
@ -963,7 +963,7 @@ static struct file_operations arp_seq_fops = {
|
|||
static int __init atm_clip_init(void)
|
||||
{
|
||||
struct proc_dir_entry *p;
|
||||
neigh_table_init(&clip_tbl);
|
||||
neigh_table_init_no_netlink(&clip_tbl);
|
||||
|
||||
clip_tbl_hook = &clip_tbl;
|
||||
register_atm_ioctl(&clip_ioctl_ops);
|
||||
|
|
|
@ -1326,8 +1326,7 @@ void neigh_parms_destroy(struct neigh_parms *parms)
|
|||
kfree(parms);
|
||||
}
|
||||
|
||||
|
||||
void neigh_table_init(struct neigh_table *tbl)
|
||||
void neigh_table_init_no_netlink(struct neigh_table *tbl)
|
||||
{
|
||||
unsigned long now = jiffies;
|
||||
unsigned long phsize;
|
||||
|
@ -1383,10 +1382,27 @@ void neigh_table_init(struct neigh_table *tbl)
|
|||
|
||||
tbl->last_flush = now;
|
||||
tbl->last_rand = now + tbl->parms.reachable_time * 20;
|
||||
}
|
||||
|
||||
void neigh_table_init(struct neigh_table *tbl)
|
||||
{
|
||||
struct neigh_table *tmp;
|
||||
|
||||
neigh_table_init_no_netlink(tbl);
|
||||
write_lock(&neigh_tbl_lock);
|
||||
for (tmp = neigh_tables; tmp; tmp = tmp->next) {
|
||||
if (tmp->family == tbl->family)
|
||||
break;
|
||||
}
|
||||
tbl->next = neigh_tables;
|
||||
neigh_tables = tbl;
|
||||
write_unlock(&neigh_tbl_lock);
|
||||
|
||||
if (unlikely(tmp)) {
|
||||
printk(KERN_ERR "NEIGH: Registering multiple tables for "
|
||||
"family %d\n", tbl->family);
|
||||
dump_stack();
|
||||
}
|
||||
}
|
||||
|
||||
int neigh_table_clear(struct neigh_table *tbl)
|
||||
|
@ -2657,6 +2673,7 @@ EXPORT_SYMBOL(neigh_rand_reach_time);
|
|||
EXPORT_SYMBOL(neigh_resolve_output);
|
||||
EXPORT_SYMBOL(neigh_table_clear);
|
||||
EXPORT_SYMBOL(neigh_table_init);
|
||||
EXPORT_SYMBOL(neigh_table_init_no_netlink);
|
||||
EXPORT_SYMBOL(neigh_update);
|
||||
EXPORT_SYMBOL(neigh_update_hhs);
|
||||
EXPORT_SYMBOL(pneigh_enqueue);
|
||||
|
|
Загрузка…
Ссылка в новой задаче