Last Friday I proposed creating larval SAs to act as placeholders to prevent a second acquire resulting in double SAs being created. I tried this and so far I have not seen any double SAs being created. I also plan to run some stress tests over the weekend.
Please let me know what improvements I can make to this patch or if there is a better way to do this. > A while back I reported that I sometimes saw double and triple > SAs being created. The patch to check for protocol when deleting > larval SA removed one obstacle in that I no longer see triple SAs. > Now, once in a while double SAs. I think I have figured out the > second obstacle. > > The initiator installs his SAs into the kernel before the responder. > As soon as they are installed, the blocked packet (which started > the ACQUIRE) is sent. By this time the responder has installed his > inbound SA(s) and so the newly arrived ipsec packet can be processed. > In the case of tcp connections and a ping, a response may be > warranted, and thus an outgoing packet results. > > >From what I can tell of the log file below, sometimes, this > might happen before the responder has completed installing > the outbound SAs. In the log file, the outbound AH has been added, > but not the outbound ESP, which is the one the outgoing packet > looks for first. Thus resulting in a second acquire. > > I think this becomes more problematic when using both AH AND ESP, > rather than just using ESP with authentication. With the latter, > only one SA needed thus reducing the latency in installing the > SAs before incoming packet arrives. > > So far, the only solution I can think of besides mandating all > userspace key daemons do SA maintenance is to perhaps add larval > SAs for both directions when adding the SPI. Currently, responder > does GETSPI for one way and initiator for opposite. When GETSPI is > called, larval SA is created containing the SPI, but it is only > for one direction. Perhaps we can add a larval SA (no SPI) for > opposite direction to act as a placeholder indicating ACQUIRE > occurring, since SAs are created for both directions during an ACQUIRE. > The initiator may have larval SA from GETSPI and larval SA from the > ACQUIRE depending that GETSPI is in opposite direction of ACQUIRE. > Calling __find_acq_core() should ensure we don't create duplicate > larval SAs. Also, should IKE negotiations return error, larval SAs > should expire. They also should be removed when we do the > xfrm_state_add() and xfrm_state_update() to add the new SAs. > Joy This patch is against linux-2.6.21-rc4-git5 Signed-off-by: Joy Latten<[EMAIL PROTECTED]> diff -urpN linux-2.6.20.orig/net/xfrm/xfrm_state.c linux-2.6.20/net/xfrm/xfrm_state.c --- linux-2.6.20.orig/net/xfrm/xfrm_state.c 2007-03-20 22:39:15.000000000 -0500 +++ linux-2.6.20/net/xfrm/xfrm_state.c 2007-03-23 16:38:37.000000000 -0500 @@ -692,12 +692,15 @@ void xfrm_state_insert(struct xfrm_state } EXPORT_SYMBOL(xfrm_state_insert); +static struct xfrm_state *create_larval_sa(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr); + /* xfrm_state_lock is held */ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) { unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); struct hlist_node *entry; - struct xfrm_state *x; + struct xfrm_state *x, *x1; + int track_opposite = 0; hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { if (x->props.reqid != reqid || @@ -710,11 +713,20 @@ static struct xfrm_state *__find_acq_cor switch (family) { case AF_INET: + if (x->id.daddr.a4 == saddr->a4 && + x->props.saddr.a4 == daddr->a4) + track_opposite = 1; if (x->id.daddr.a4 != daddr->a4 || x->props.saddr.a4 != saddr->a4) continue; break; case AF_INET6: + if (ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6, + (struct in6_addr *)saddr) || + ipv6_addr_equal((struct in6_addr *) + x->props.saddr.a6, + (struct in6_addr *)daddr)) + track_opposite = 1; if (!ipv6_addr_equal((struct in6_addr *)x->id.daddr.a6, (struct in6_addr *)daddr) || !ipv6_addr_equal((struct in6_addr *) @@ -731,6 +743,27 @@ static struct xfrm_state *__find_acq_cor if (!create) return NULL; + x = create_larval_sa(family, mode, reqid, proto, daddr, saddr); + + /* create a larval SA for opposite direction to act as a + placeholder duing the ACQUIRE. This prevents any additional + packets from creating additional ACQUIRES for same traffic + stream. + */ + + if (!track_opposite) + x1 = create_larval_sa(family, mode, reqid, proto, saddr, daddr); + + wake_up(&km_waitq); + return x; +} + +/* xfrm_state_lock is held */ +static struct xfrm_state *create_larval_sa(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr) +{ + struct xfrm_state *x; + unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); + x = xfrm_state_alloc(); if (likely(x)) { switch (family) { @@ -769,15 +802,14 @@ static struct xfrm_state *__find_acq_cor hlist_add_head(&x->bydst, xfrm_state_bydst+h); h = xfrm_src_hash(daddr, saddr, family); hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); - wake_up(&km_waitq); xfrm_state_num++; xfrm_hash_grow_check(x->bydst.next != NULL); - } - return x; -} + }; + return x; +}; static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); - 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