]> git.karo-electronics.de Git - karo-tx-linux.git/commit
IPV6: Fix ipv6 round-robin locking.
authorDavid Miller <davem@davemloft.net>
Tue, 27 Mar 2007 01:56:59 +0000 (18:56 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 6 Apr 2007 10:43:13 +0000 (03:43 -0700)
commit00d3a8023ed6cb6c91004b38b50758a542fac645
tree04abb371463865c12c5d81fab4bd3ce9989f39cd
parent5d50dceccd79e5890d08adb40a538f1ac6dfe89d
IPV6: Fix ipv6 round-robin locking.

[IPV6]: Fix routing round-robin locking.

As per RFC2461, section 6.3.6, item #2, when no routers on the
matching list are known to be reachable or probably reachable we
do round robin on those available routes so that we make sure
to probe as many of them as possible to detect when one becomes
reachable faster.

Each routing table has a rwlock protecting the tree and the linked
list of routes at each leaf.  The round robin code executes during
lookup and thus with the rwlock taken as a reader.  A small local
spinlock tries to provide protection but this does not work at all
for two reasons:

1) The round-robin list manipulation, as coded, goes like this (with
   read lock held):

walk routes finding head and tail

spin_lock();
rotate list using head and tail
spin_unlock();

   While one thread is rotating the list, another thread can
   end up with stale values of head and tail and then proceed
   to corrupt the list when it gets the lock.  This ends up causing
   the OOPS in fib6_add() later onthat many people have been hitting.

2) All the other code paths that run with the rwlock held as
   a reader do not expect the list to change on them, they
   expect it to remain completely fixed while they hold the
   lock in that way.

So, simply stated, it is impossible to implement this correctly using
a manipulation of the list without violating the rwlock locking
semantics.

Reimplement using a per-fib6_node round-robin pointer.  This way we
don't need to manipulate the list at all, and since the round-robin
pointer can only ever point to real existing entries we don't need
to perform any locking on the changing of the round-robin pointer
itself.  We only need to reset the round-robin pointer to NULL when
the entry it is pointing to is removed.

The idea is from Thomas Graf and it is very similar to how this
was implemented before the advanced router selection code when in.

Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip6_fib.h
net/ipv6/ip6_fib.c
net/ipv6/route.c