From: Andrew Morton <[EMAIL PROTECTED]> Date: Wed, 27 Jul 2005 14:38:35 -0700
> Summary: IPSec incompabilty. Linux kernel waits to long to start > using new SA for outbound traffic. I think this is the known bug where we don't notice that a route attached to a socket is obsolete. It was first pointed out to me last year by Kazunori Miyazawa, CC:'d here. The problem is that, when we update IPSEC rules, sockets currently don't have a way to discover that. Traditionally, the route "obsolete" flag served this purpose, and that does work properly for normal route entries. But for IPSEC, we don't have a way to find all of the stacked routes we created that match a particular SA, and thus get them fixed up the next time a socket tries to send a packet. One idea tossed around between Herbert Xu (also CC:'d) and myself is to store a generation counter when we attach a route to a socket, then sk_dst_check() can verify that this generation count matches the current IPSEC flow cache generation count. Something like the following, untested patch, demonstrates the idea. [NET]: Tie obsolete state of routes also to flow cache generation count. This fixes the problem wherein IPSEC SA changes do not get noticed by cached socket routes. Signed-off-by: David S. Miller <[EMAIL PROTECTED]> diff --git a/include/net/sock.h b/include/net/sock.h --- a/include/net/sock.h +++ b/include/net/sock.h @@ -54,6 +54,7 @@ #include <asm/atomic.h> #include <net/dst.h> #include <net/checksum.h> +#include <net/flow.h> /* * This structure really needs to be cleaned up. @@ -193,6 +194,7 @@ struct sock { socket_lock_t sk_lock; wait_queue_head_t *sk_sleep; struct dst_entry *sk_dst_cache; + unsigned int sk_dst_cache_genid; struct xfrm_policy *sk_policy[2]; rwlock_t sk_dst_lock; atomic_t sk_rmem_alloc; @@ -924,6 +926,9 @@ __sk_dst_set(struct sock *sk, struct dst old_dst = sk->sk_dst_cache; sk->sk_dst_cache = dst; +#ifdef CONFIG_XFRM + sk->sk_dst_cache_genid = atomic_read(&flow_cache_genid); +#endif dst_release(old_dst); } @@ -958,7 +963,9 @@ __sk_dst_check(struct sock *sk, u32 cook { struct dst_entry *dst = sk->sk_dst_cache; - if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { + if (dst && + ((dst->obsolete && dst->ops->check(dst, cookie) == NULL) || + (sk->sk_dst_cache_genid != atomic_read(&flow_cache_genid)))) { sk->sk_dst_cache = NULL; dst_release(dst); return NULL; @@ -972,7 +979,9 @@ sk_dst_check(struct sock *sk, u32 cookie { struct dst_entry *dst = sk_dst_get(sk); - if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { + if (dst && + ((dst->obsolete && dst->ops->check(dst, cookie) == NULL) || + (sk->sk_dst_cache_genid != atomic_read(&flow_cache_genid)))) { sk_dst_reset(sk); dst_release(dst); return NULL; - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html