* XFRM state hash value @ 2009-03-10 9:46 Nicolas Dichtel 2009-03-10 11:20 ` David Miller 0 siblings, 1 reply; 4+ messages in thread From: Nicolas Dichtel @ 2009-03-10 9:46 UTC (permalink / raw) To: netdev, David S. Miller Hi guys, this commit: [XFRM]: Hash xfrm_state objects by source address too. (http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=commitdiff;h=c1969f294e624d5b642fc8e6ab9468b7c7791fa8) introduces src address in hash for state. But in some cases, source address is a wildcard when state is inserted. For example, we can have something like this: # setkey -c add :: ff02::9 ah 0x100 -m transport -A hmac-md5 "cle3goldorakcle3"; In this case, __xfrm_state_insert() will calculate the hash value with src address set to 0, but xfrm_state_find() will use the real source address to calculate this hash. At the end, no state will be found. The most simple way to resolve this pb is to revert the previous patch, but maybe someone has a better idea... Regards, Nicolas ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: XFRM state hash value 2009-03-10 9:46 XFRM state hash value Nicolas Dichtel @ 2009-03-10 11:20 ` David Miller 2009-03-10 14:08 ` Nicolas Dichtel 0 siblings, 1 reply; 4+ messages in thread From: David Miller @ 2009-03-10 11:20 UTC (permalink / raw) To: nicolas.dichtel; +Cc: netdev From: Nicolas Dichtel <nicolas.dichtel@dev.6wind.com> Date: Tue, 10 Mar 2009 10:46:03 +0100 > this commit: [XFRM]: Hash xfrm_state objects by source address too. (http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=commitdiff;h=c1969f294e624d5b642fc8e6ab9468b7c7791fa8) > introduces src address in hash for state. > But in some cases, source address is a wildcard when state is inserted. For example, we can have something like this: > # setkey -c > add :: ff02::9 ah 0x100 -m transport -A hmac-md5 "cle3goldorakcle3"; > > In this case, __xfrm_state_insert() will calculate the hash value with src address set to 0, but xfrm_state_find() will use the real source address to calculate this hash. At the end, no state will be found. > The most simple way to resolve this pb is to revert the previous patch, but maybe someone has a better idea... > Please try this patch: diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index e25ff62..86b9078 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -748,12 +748,51 @@ static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) schedule_work(&net->xfrm.state_hash_work); } +static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, + struct flowi *fl, unsigned short family, + xfrm_address_t *daddr, xfrm_address_t *saddr, + struct xfrm_state **best, int *acq_in_progress, + int *error) +{ + /* Resolution logic: + * 1. There is a valid state with matching selector. Done. + * 2. Valid state with inappropriate selector. Skip. + * + * Entering area of "sysdeps". + * + * 3. If state is not valid, selector is temporary, it selects + * only session which triggered previous resolution. Key + * manager will do something to install a state with proper + * selector. + */ + if (x->km.state == XFRM_STATE_VALID) { + if ((x->sel.family && + !xfrm_selector_match(&x->sel, fl, x->sel.family)) || + !security_xfrm_state_pol_flow_match(x, pol, fl)) + return; + + if (!*best || + (*best)->km.dying > x->km.dying || + ((*best)->km.dying == x->km.dying && + (*best)->curlft.add_time < x->curlft.add_time)) + *best = x; + } else if (x->km.state == XFRM_STATE_ACQ) { + *acq_in_progress = 1; + } else if (x->km.state == XFRM_STATE_ERROR || + x->km.state == XFRM_STATE_EXPIRED) { + if (xfrm_selector_match(&x->sel, fl, x->sel.family) && + security_xfrm_state_pol_flow_match(x, pol, fl)) + *error = -ESRCH; + } +} + struct xfrm_state * xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, struct flowi *fl, struct xfrm_tmpl *tmpl, struct xfrm_policy *pol, int *err, unsigned short family) { + static xfrm_address_t saddr_wildcard = { }; struct net *net = xp_net(pol); unsigned int h; struct hlist_node *entry; @@ -773,38 +812,21 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, xfrm_state_addr_check(x, daddr, saddr, family) && tmpl->mode == x->props.mode && tmpl->id.proto == x->id.proto && - (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) { - /* Resolution logic: - 1. There is a valid state with matching selector. - Done. - 2. Valid state with inappropriate selector. Skip. - - Entering area of "sysdeps". - - 3. If state is not valid, selector is temporary, - it selects only session which triggered - previous resolution. Key manager will do - something to install a state with proper - selector. - */ - if (x->km.state == XFRM_STATE_VALID) { - if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) || - !security_xfrm_state_pol_flow_match(x, pol, fl)) - continue; - if (!best || - best->km.dying > x->km.dying || - (best->km.dying == x->km.dying && - best->curlft.add_time < x->curlft.add_time)) - best = x; - } else if (x->km.state == XFRM_STATE_ACQ) { - acquire_in_progress = 1; - } else if (x->km.state == XFRM_STATE_ERROR || - x->km.state == XFRM_STATE_EXPIRED) { - if (xfrm_selector_match(&x->sel, fl, x->sel.family) && - security_xfrm_state_pol_flow_match(x, pol, fl)) - error = -ESRCH; - } - } + (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) + xfrm_state_look_at(pol, x, fl, family, daddr, saddr, + &best, &acquire_in_progress, &error); + } + h = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family); + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { + if (x->props.family == family && + x->props.reqid == tmpl->reqid && + !(x->props.flags & XFRM_STATE_WILDRECV) && + xfrm_state_addr_check(x, daddr, saddr, family) && + tmpl->mode == x->props.mode && + tmpl->id.proto == x->id.proto && + (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) + xfrm_state_look_at(pol, x, fl, family, daddr, saddr, + &best, &acquire_in_progress, &error); } x = best; ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: XFRM state hash value 2009-03-10 11:20 ` David Miller @ 2009-03-10 14:08 ` Nicolas Dichtel 2009-03-10 14:18 ` David Miller 0 siblings, 1 reply; 4+ messages in thread From: Nicolas Dichtel @ 2009-03-10 14:08 UTC (permalink / raw) To: David Miller; +Cc: netdev This patch is ok with my test case. I'm asking me if we should perform the step with saddr_wildcard if we have already found one. The state with a src address may have an higher priority than the state with a wildcare address, no? Nicolas Le 10.03.2009 12:20, David Miller a écrit : > From: Nicolas Dichtel <nicolas.dichtel@dev.6wind.com> > Date: Tue, 10 Mar 2009 10:46:03 +0100 > >> this commit: [XFRM]: Hash xfrm_state objects by source address too. (http://git.kernel.org/?p=linux/kernel/git/davem/net-2.6.git;a=commitdiff;h=c1969f294e624d5b642fc8e6ab9468b7c7791fa8) >> introduces src address in hash for state. >> But in some cases, source address is a wildcard when state is inserted. For example, we can have something like this: >> # setkey -c >> add :: ff02::9 ah 0x100 -m transport -A hmac-md5 "cle3goldorakcle3"; >> >> In this case, __xfrm_state_insert() will calculate the hash value with src address set to 0, but xfrm_state_find() will use the real source address to calculate this hash. At the end, no state will be found. >> The most simple way to resolve this pb is to revert the previous patch, but maybe someone has a better idea... >> > > Please try this patch: > > diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c > index e25ff62..86b9078 100644 > --- a/net/xfrm/xfrm_state.c > +++ b/net/xfrm/xfrm_state.c > @@ -748,12 +748,51 @@ static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) > schedule_work(&net->xfrm.state_hash_work); > } > > +static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, > + struct flowi *fl, unsigned short family, > + xfrm_address_t *daddr, xfrm_address_t *saddr, > + struct xfrm_state **best, int *acq_in_progress, > + int *error) > +{ > + /* Resolution logic: > + * 1. There is a valid state with matching selector. Done. > + * 2. Valid state with inappropriate selector. Skip. > + * > + * Entering area of "sysdeps". > + * > + * 3. If state is not valid, selector is temporary, it selects > + * only session which triggered previous resolution. Key > + * manager will do something to install a state with proper > + * selector. > + */ > + if (x->km.state == XFRM_STATE_VALID) { > + if ((x->sel.family && > + !xfrm_selector_match(&x->sel, fl, x->sel.family)) || > + !security_xfrm_state_pol_flow_match(x, pol, fl)) > + return; > + > + if (!*best || > + (*best)->km.dying > x->km.dying || > + ((*best)->km.dying == x->km.dying && > + (*best)->curlft.add_time < x->curlft.add_time)) > + *best = x; > + } else if (x->km.state == XFRM_STATE_ACQ) { > + *acq_in_progress = 1; > + } else if (x->km.state == XFRM_STATE_ERROR || > + x->km.state == XFRM_STATE_EXPIRED) { > + if (xfrm_selector_match(&x->sel, fl, x->sel.family) && > + security_xfrm_state_pol_flow_match(x, pol, fl)) > + *error = -ESRCH; > + } > +} > + > struct xfrm_state * > xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, > struct flowi *fl, struct xfrm_tmpl *tmpl, > struct xfrm_policy *pol, int *err, > unsigned short family) > { > + static xfrm_address_t saddr_wildcard = { }; > struct net *net = xp_net(pol); > unsigned int h; > struct hlist_node *entry; > @@ -773,38 +812,21 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, > xfrm_state_addr_check(x, daddr, saddr, family) && > tmpl->mode == x->props.mode && > tmpl->id.proto == x->id.proto && > - (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) { > - /* Resolution logic: > - 1. There is a valid state with matching selector. > - Done. > - 2. Valid state with inappropriate selector. Skip. > - > - Entering area of "sysdeps". > - > - 3. If state is not valid, selector is temporary, > - it selects only session which triggered > - previous resolution. Key manager will do > - something to install a state with proper > - selector. > - */ > - if (x->km.state == XFRM_STATE_VALID) { > - if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) || > - !security_xfrm_state_pol_flow_match(x, pol, fl)) > - continue; > - if (!best || > - best->km.dying > x->km.dying || > - (best->km.dying == x->km.dying && > - best->curlft.add_time < x->curlft.add_time)) > - best = x; > - } else if (x->km.state == XFRM_STATE_ACQ) { > - acquire_in_progress = 1; > - } else if (x->km.state == XFRM_STATE_ERROR || > - x->km.state == XFRM_STATE_EXPIRED) { > - if (xfrm_selector_match(&x->sel, fl, x->sel.family) && > - security_xfrm_state_pol_flow_match(x, pol, fl)) > - error = -ESRCH; > - } > - } > + (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) > + xfrm_state_look_at(pol, x, fl, family, daddr, saddr, > + &best, &acquire_in_progress, &error); > + } > + h = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family); > + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { > + if (x->props.family == family && > + x->props.reqid == tmpl->reqid && > + !(x->props.flags & XFRM_STATE_WILDRECV) && > + xfrm_state_addr_check(x, daddr, saddr, family) && > + tmpl->mode == x->props.mode && > + tmpl->id.proto == x->id.proto && > + (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) > + xfrm_state_look_at(pol, x, fl, family, daddr, saddr, > + &best, &acquire_in_progress, &error); > } > > x = best; ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: XFRM state hash value 2009-03-10 14:08 ` Nicolas Dichtel @ 2009-03-10 14:18 ` David Miller 0 siblings, 0 replies; 4+ messages in thread From: David Miller @ 2009-03-10 14:18 UTC (permalink / raw) To: nicolas.dichtel; +Cc: netdev From: Nicolas Dichtel <nicolas.dichtel@dev.6wind.com> Date: Tue, 10 Mar 2009 15:08:16 +0100 > This patch is ok with my test case. > I'm asking me if we should perform the step with saddr_wildcard if we have already found one. The state with a src address may have an higher priority than the state with a wildcare address, no? Good point, I'll think about the semantics and update my patch as necessary. ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2009-03-10 14:18 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-03-10 9:46 XFRM state hash value Nicolas Dichtel 2009-03-10 11:20 ` David Miller 2009-03-10 14:08 ` Nicolas Dichtel 2009-03-10 14:18 ` David Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).