: Fix wildcard as tunnel source
Subsystems (3)
[XFRM]: Fix wildcard as tunnel source
Hashing SAs by source address breaks templates with wildcards as tunnel source. Remove saddr from the hash key.
---
commit 19f7b6f33c0e9fbdf23a33506c2dfc0706b0c731
tree bca60eb94c50fcd66673bd87823fd38364b45b55
parent 6ddbd02eb61532f9af4f28912a09717ab8c71d8a
author Patrick McHardy <[email protected]> Sat, 02 Sep 2006 16:43:39 +0200 committer Patrick McHardy <[email protected]> Sat, 02 Sep 2006 16:43:39 +0200
net/xfrm/xfrm_hash.h | 8 ++++---- net/xfrm/xfrm_state.c | 17 +++++++---------- 2 files changed, 11 insertions(+), 14 deletions(-)
net/xfrm/xfrm_hash.h +4 -4
@@ -25,17 +25,17 @@ static inline unsigned int __xfrm6_daddr saddr->a6[2] ^ saddr->a6[3]); } -static inline unsigned int __xfrm_dst_hash (xfrm_address_t *daddr,xfrm_address_t *saddr, -u32 reqid,unsigned short family, +static inline unsigned int __xfrm_dst_hash (xfrm_address_t *daddr,u32 reqid, +unsigned short family,unsigned int hmask) {unsigned int h = family ^ reqid;switch (family) {case AF_INET : - h ^=__xfrm4_daddr_saddr_hash (daddr, saddr); + h ^=__xfrm4_addr_hash (daddr);break ;case AF_INET6 : - h ^=__xfrm6_daddr_saddr_hash (daddr, saddr); + h ^=__xfrm6_addr_hash (daddr);break ; }return (h ^ (h >>16 )) & hmask;
net/xfrm/xfrm_state.c +7 -10
@@ -56,11 +56,10 @@ static unsigned int xfrm_state_num;static unsigned int xfrm_state_genid;static inline unsigned int xfrm_dst_hash (xfrm_address_t *daddr, -xfrm_address_t *saddr,u32 reqid,unsigned short family) { -return __xfrm_dst_hash (daddr, saddr, reqid, family, xfrm_state_hmask); +return __xfrm_dst_hash (daddr, reqid, family, xfrm_state_hmask); } static inline unsigned int xfrm_src_hash(xfrm_address_t *addr,
@@ -87,9 +86,8 @@ static void xfrm_hash_transfer(struct hlhlist_for_each_entry_safe (x, entry, tmp, list, bydst) {unsigned int h; - h =__xfrm_dst_hash (&x->id.daddr, &x->props.saddr, - x->props.reqid, x->props.family, - nhashmask); + h =__xfrm_dst_hash (&x->id.daddr, x->props.reqid, + x->props.family, nhashmask);hlist_add_head (&x->bydst, ndsttable+h); h = __xfrm_src_hash(&x->props.saddr, x->props.family,
@@ -506,7 +504,7 @@ xfrm_state_find(xfrm_address_t *daddr, x struct xfrm_policy *pol, int *err, unsigned short family) { - unsigned int h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); + unsigned int h = xfrm_dst_hash(daddr, tmpl->reqid, family);struct hlist_node *entry;struct xfrm_state *x, *x0;int acquire_in_progress =0 ;
@@ -615,8 +613,7 @@ static void __xfrm_state_insert(struct x x->genid = ++xfrm_state_genid; - h =xfrm_dst_hash (&x->id.daddr, &x->props.saddr, - x->props.reqid, x->props.family); + h =xfrm_dst_hash (&x->id.daddr, x->props.reqid, x->props.family);hlist_add_head (&x->bydst, xfrm_state_bydst+h); h =xfrm_src_hash (&x->props.saddr, x->props.family);
@@ -652,7 +649,7 @@ static void __xfrm_state_bump_genids(strstruct hlist_node *entry;unsigned int h; - h =xfrm_dst_hash (&xnew->id.daddr, &xnew->props.saddr, reqid, family); + h =xfrm_dst_hash (&xnew->id.daddr, reqid, family);hlist_for_each_entry (x, entry, xfrm_state_bydst+h, bydst) { if (x->props.family == family && x->props.reqid == reqid &&
@@ -674,7 +671,7 @@ EXPORT_SYMBOL(xfrm_state_insert);/* 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); +unsigned int h =xfrm_dst_hash (daddr, reqid, family);struct hlist_node *entry;struct xfrm_state *x;
David Miller
maintainerFrom: Patrick McHardy <[email protected]>
Date: Sat, 02 Sep 2006 16:46:44 +0200
Quoted 6 lines
[XFRM]: Fix wildcard as tunnel source
Hashing SAs by source address breaks templates with wildcards as tunnel source. Remove saddr from the hash key.
Signed-off-by Patrick McHardy <[email protected]>
Unfortunately, this break scalability of the xfrm state layer when the source is equally as varying as the destination. In such setups you have an enormous number of entries with destination being the local system and only the source address changing.
BTW, how can the source be specified as wildcard? There is no prefix component, it is simply an xfrm_address_t. And there are several macros which check for x->props.saddr equality directly with no special prefixing or wildcard logic.
I really don't want to remove this as it's fairly critical performance wise for the scalability problems all my changes were meant to address. I hope I really don't have to do something like what was needed for the policy layer, having a linked list and a hash table to handle the two cases.
Quoted 9 lines · David Miller
Unfortunately, this break scalability of the xfrm state layer when the source is equally as varying as the destination. In such setups you have an enormous number of entries with destination being the local system and only the source address changing.
BTW, how can the source be specified as wildcard? There is no prefix component, it is simply an
xfrm_address_t. And there are several macros which check forx->props.saddrequality directly with no special prefixing or wildcard logic.
The tunnel endpoint in the template (either source or destination, depending on the direction) is set to 0.0.0.0. For outbound SAs, the address is compared using xfrm_state_addr_check(), which interprets 0.0.0.0 as wildcard. When no matching SA is present, the address is resolved using routing and filled in the ACQ SA. The keying daemon will then install SAs with the proper source. For inbound SAs the tunnel destination from the template is ignored.
Quoted 5 lines
I really don't want to remove this as it's fairly critical performance wise for the scalability problems all my changes were meant to address. I hope I really don't have to do something like what was needed for the policy layer, having a linked list and a hash table to handle the two cases.
We could query the address before the SA lookup. It will cost an additional route lookup in case a matching SA is already present, but I guess thats still better than removing the source from the hash. I'll try if it works and send a new patch.
Quoted 9 lines · Patrick McHardy
Quoted 5 lines · David Miller
I really don't want to remove this as it's fairly critical performance wise for the scalability problems all my changes were meant to address. I hope I really don't have to do something like what was needed for the policy layer, having a linked list and a hash table to handle the two cases.
Quoted 4 lines
We could query the address before the SA lookup. It will cost an additional route lookup in case a matching SA is already present, but I guess thats still better than removing the source from the hash. I'll try if it works and send a new patch.
I've tested this patch and it works fine. I'm wondering if something else might be affected by the hash change though, xfrm_state_addr_check treated 0.0.0.0 as wildcard even before the introduction of wildcards in tunnel templates, but I can't see in which other case it would be zero.
[XFRM]: Fix wildcard as tunnel source
Hashing SAs by source address breaks templates with wildcards as tunnel source since the source address used for hashing/lookup is still 0/0. Move source address lookup to xfrm_tmpl_resolve_one() so we can use the real address in the lookup.
---
commit f3307c3183e50959247f28c773590b5d7902097f
tree 78ddff768dc25145110767f182408ed6993828c5
parent c2cb1937e1054380c49699188810b9c6e04c8e21
author Patrick McHardy <[email protected]> Mon, 18 Sep 2006 11:34:25 +0200 committer Patrick McHardy <[email protected]> Mon, 18 Sep 2006 11:34:25 +0200
include/net/xfrm.h | 13 +++++++++++++ net/ipv4/xfrm4_policy.c | 20 ++++++++++++++++++++ net/ipv4/xfrm4_state.c | 15 --------------- net/ipv6/xfrm6_policy.c | 21 +++++++++++++++++++++ net/ipv6/xfrm6_state.c | 16 ---------------- net/xfrm/xfrm_policy.c | 21 +++++++++++++++++++++ 6 files changed, 75 insertions(+), 31 deletions(-)
include/net/xfrm.h +13 -0
@@ -223,6 +223,7 @@ struct xfrm_policy_afinfo {struct dst_ops *dst_ops;void (*garbage_collect)(void );int (*dst_lookup)(struct xfrm_dst **dst,struct flowi *fl); +int (*get_saddr)(xfrm_address_t *saddr,xfrm_address_t *daddr);struct dst_entry *(*find_bundle)(struct flowi *fl,struct xfrm_policy *policy); int (*bundle_create)(struct xfrm_policy *policy, struct xfrm_state **xfrm,
@@ -632,6 +633,18 @@ #endif }static inline int +xfrm_addr_any (xfrm_address_t *addr,unsigned short family) +{ +switch (family) { +case AF_INET : +return addr->a4 ==0 ; +case AF_INET6 : +return ipv6_addr_any ((struct in6_addr *)addr->a6); + } +return 0 ; +} + +static inline int __xfrm4_state_addr_cmp (struct xfrm_tmpl *tmpl,struct xfrm_state *x) { return (tmpl->saddr.a4 &&
net/ipv4/xfrm4_policy.c +20 -0
@@ -21,6 +21,25 @@ static int xfrm4_dst_lookup(struct xfrm_return __ip_route_output_key ((struct rtable **)dst, fl); } +static int xfrm4_get_saddr (xfrm_address_t *saddr,xfrm_address_t *daddr) +{ +struct rtable *rt; +struct flowi fl_tunnel = { + .nl_u = { + .ip4_u = { + .daddr = daddr->a4, + }, + }, + }; + +if (!xfrm4_dst_lookup ((struct xfrm_dst **)&rt, &fl_tunnel)) { + saddr->a4 = rt->rt_src; +dst_release (&rt->u.dst); +return 0 ; + } +return -EHOSTUNREACH ; +} +static struct dst_entry *__xfrm4_find_bundle (struct flowi *fl,struct xfrm_policy *policy) {
@@ -298,6 +317,7 @@ static struct xfrm_policy_afinfo xfrm4_p .family = AF_INET, .dst_ops = &xfrm4_dst_ops, .dst_lookup = xfrm4_dst_lookup, + .get_saddr = xfrm4_get_saddr, .find_bundle = __xfrm4_find_bundle, .bundle_create = __xfrm4_bundle_create, .decode_session = _decode_session4,
net/ipv4/xfrm4_state.c +0 -15
@@ -42,21 +42,6 @@ __xfrm4_init_tempsel(struct xfrm_state * x->props.saddr = tmpl->saddr;if (x->props.saddr.a4 ==0 ) x->props.saddr.a4 = saddr->a4; -if (tmpl->mode ==XFRM_MODE_TUNNEL && x->props.saddr.a4 ==0 ) { -struct rtable *rt; -struct flowi fl_tunnel = { - .nl_u = { - .ip4_u = { - .daddr = x->id.daddr.a4, - } - } - }; -if (!xfrm_dst_lookup ((struct xfrm_dst **)&rt, - &fl_tunnel,AF_INET )) { - x->props.saddr.a4 = rt->rt_src; -dst_release (&rt->u.dst); - } - } x->props.mode = tmpl->mode; x->props.reqid = tmpl->reqid; x->props.family =AF_INET ;
net/ipv6/xfrm6_policy.c +21 -0
@@ -34,6 +34,26 @@ static int xfrm6_dst_lookup(struct xfrm_return err; } +static int xfrm6_get_saddr (xfrm_address_t *saddr,xfrm_address_t *daddr) +{ +struct rt6_info *rt; +struct flowi fl_tunnel = { + .nl_u = { + .ip6_u = { + .daddr = *(struct in6_addr *)&daddr->a6, + }, + }, + }; + +if (!xfrm6_dst_lookup ((struct xfrm_dst **)&rt, &fl_tunnel)) { +ipv6_get_saddr (&rt->u.dst, (struct in6_addr *)&daddr->a6, + (struct in6_addr *)&saddr->a6); +dst_release (&rt->u.dst); +return 0 ; + } +return -EHOSTUNREACH ; +} +static struct dst_entry *__xfrm6_find_bundle (struct flowi *fl,struct xfrm_policy *policy) {
@@ -362,6 +382,7 @@ static struct xfrm_policy_afinfo xfrm6_p .family = AF_INET6, .dst_ops = &xfrm6_dst_ops, .dst_lookup = xfrm6_dst_lookup, + .get_saddr = xfrm6_get_saddr, .find_bundle = __xfrm6_find_bundle, .bundle_create = __xfrm6_bundle_create, .decode_session = _decode_session6,
net/ipv6/xfrm6_state.c +0 -16
@@ -42,22 +42,6 @@ __xfrm6_init_tempsel(struct xfrm_state *memcpy (&x->props.saddr, &tmpl->saddr,sizeof (x->props.saddr));if (ipv6_addr_any ((struct in6_addr *)&x->props.saddr))memcpy (&x->props.saddr, saddr,sizeof (x->props.saddr)); -if (tmpl->mode ==XFRM_MODE_TUNNEL &&ipv6_addr_any ((struct in6_addr *)&x->props.saddr)) { -struct rt6_info *rt; -struct flowi fl_tunnel = { - .nl_u = { - .ip6_u = { - .daddr = *(struct in6_addr *)daddr, - } - } - }; -if (!xfrm_dst_lookup ((struct xfrm_dst **)&rt, - &fl_tunnel,AF_INET6 )) { -ipv6_get_saddr (&rt->u.dst, (struct in6_addr *)daddr, - (struct in6_addr *)&x->props.saddr); -dst_release (&rt->u.dst); - } - } x->props.mode = tmpl->mode; x->props.reqid = tmpl->reqid; x->props.family =AF_INET6 ;
net/xfrm/xfrm_policy.c +21 -0
@@ -1107,6 +1107,20 @@ int __xfrm_sk_clone_policy(struct sock *return 0 ; } +static int +xfrm_get_saddr (xfrm_address_t *local,xfrm_address_t *remote, +unsigned short family) +{ +int err; +struct xfrm_policy_afinfo *afinfo =xfrm_policy_get_afinfo (family); + +if (unlikely (afinfo ==NULL )) +return -EINVAL ; + err = afinfo->get_saddr (local, remote); +xfrm_policy_put_afinfo (afinfo); +return err; +} +/* Resolve list of templates for the flow, given policy. */ static int
@@ -1118,6 +1132,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policyint i, error;xfrm_address_t *daddr =xfrm_flowi_daddr (fl, family);xfrm_address_t *saddr =xfrm_flowi_saddr (fl, family); +xfrm_address_t tmp;for (nx=0 , i =0 ; i < policy->xfrm_nr; i++) {struct xfrm_state *x;
@@ -1128,6 +1143,12 @@ xfrm_tmpl_resolve_one(struct xfrm_policyif (tmpl->mode ==XFRM_MODE_TUNNEL ) { remote = &tmpl->id.daddr; local = &tmpl->saddr; +if (xfrm_addr_any (local, family)) { + error =xfrm_get_saddr (&tmp, remote, family); +if (error) + goto fail; + local = &tmp; + } } x =xfrm_state_find (remote, local, fl, tmpl, policy, &error, family);
Quoted 9 lines · Patrick McHardy
[XFRM]: Fix wildcard as tunnel source
Hashing SAs by source address breaks templates with wildcards as tunnel source since the source address used for hashing/lookup is still 0/0. Move source address lookup to
xfrm_tmpl_resolve_one()so we can use the real address in the lookup.static inline int
Review
Quoted 7 lines
(quoted diff) +7
-0+xfrm_addr_any(xfrm_address_t *addr, unsigned short family) +{ + switch (family) { + case AF_INET: + return addr->a4 == 0; + case AF_INET6: + return ipv6_addr_any((struct in6_addr*)addr->a6);
D'oh. Fixed patch attached.
[XFRM]: Fix wildcard as tunnel source
Hashing SAs by source address breaks templates with wildcards as tunnel source since the source address used for hashing/lookup is still 0/0. Move source address lookup to xfrm_tmpl_resolve_one() so we can use the real address in the lookup.
---
commit f3307c3183e50959247f28c773590b5d7902097f
tree 78ddff768dc25145110767f182408ed6993828c5
parent c2cb1937e1054380c49699188810b9c6e04c8e21
author Patrick McHardy <[email protected]> Mon, 18 Sep 2006 11:34:25 +0200 committer Patrick McHardy <[email protected]> Mon, 18 Sep 2006 11:34:25 +0200
include/net/xfrm.h | 13 +++++++++++++ net/ipv4/xfrm4_policy.c | 20 ++++++++++++++++++++ net/ipv4/xfrm4_state.c | 15 --------------- net/ipv6/xfrm6_policy.c | 21 +++++++++++++++++++++ net/ipv6/xfrm6_state.c | 16 ---------------- net/xfrm/xfrm_policy.c | 21 +++++++++++++++++++++ 6 files changed, 75 insertions(+), 31 deletions(-)
include/net/xfrm.h +13 -0
@@ -223,6 +223,7 @@ struct xfrm_policy_afinfo {struct dst_ops *dst_ops;void (*garbage_collect)(void );int (*dst_lookup)(struct xfrm_dst **dst,struct flowi *fl); +int (*get_saddr)(xfrm_address_t *saddr,xfrm_address_t *daddr);struct dst_entry *(*find_bundle)(struct flowi *fl,struct xfrm_policy *policy); int (*bundle_create)(struct xfrm_policy *policy, struct xfrm_state **xfrm,
@@ -632,6 +633,18 @@ #endif }static inline int +xfrm_addr_any (xfrm_address_t *addr,unsigned short family) +{ +switch (family) { +case AF_INET : +return addr->a4 ==0 ; +case AF_INET6 : +return ipv6_addr_any ((struct in6_addr *)&addr->a6); + } +return 0 ; +} + +static inline int __xfrm4_state_addr_cmp (struct xfrm_tmpl *tmpl,struct xfrm_state *x) { return (tmpl->saddr.a4 &&
net/ipv4/xfrm4_policy.c +20 -0
@@ -21,6 +21,25 @@ static int xfrm4_dst_lookup(struct xfrm_return __ip_route_output_key ((struct rtable **)dst, fl); } +static int xfrm4_get_saddr (xfrm_address_t *saddr,xfrm_address_t *daddr) +{ +struct rtable *rt; +struct flowi fl_tunnel = { + .nl_u = { + .ip4_u = { + .daddr = daddr->a4, + }, + }, + }; + +if (!xfrm4_dst_lookup ((struct xfrm_dst **)&rt, &fl_tunnel)) { + saddr->a4 = rt->rt_src; +dst_release (&rt->u.dst); +return 0 ; + } +return -EHOSTUNREACH ; +} +static struct dst_entry *__xfrm4_find_bundle (struct flowi *fl,struct xfrm_policy *policy) {
@@ -298,6 +317,7 @@ static struct xfrm_policy_afinfo xfrm4_p .family = AF_INET, .dst_ops = &xfrm4_dst_ops, .dst_lookup = xfrm4_dst_lookup, + .get_saddr = xfrm4_get_saddr, .find_bundle = __xfrm4_find_bundle, .bundle_create = __xfrm4_bundle_create, .decode_session = _decode_session4,
net/ipv4/xfrm4_state.c +0 -15
@@ -42,21 +42,6 @@ __xfrm4_init_tempsel(struct xfrm_state * x->props.saddr = tmpl->saddr;if (x->props.saddr.a4 ==0 ) x->props.saddr.a4 = saddr->a4; -if (tmpl->mode ==XFRM_MODE_TUNNEL && x->props.saddr.a4 ==0 ) { -struct rtable *rt; -struct flowi fl_tunnel = { - .nl_u = { - .ip4_u = { - .daddr = x->id.daddr.a4, - } - } - }; -if (!xfrm_dst_lookup ((struct xfrm_dst **)&rt, - &fl_tunnel,AF_INET )) { - x->props.saddr.a4 = rt->rt_src; -dst_release (&rt->u.dst); - } - } x->props.mode = tmpl->mode; x->props.reqid = tmpl->reqid; x->props.family =AF_INET ;
net/ipv6/xfrm6_policy.c +21 -0
@@ -34,6 +34,26 @@ static int xfrm6_dst_lookup(struct xfrm_return err; } +static int xfrm6_get_saddr (xfrm_address_t *saddr,xfrm_address_t *daddr) +{ +struct rt6_info *rt; +struct flowi fl_tunnel = { + .nl_u = { + .ip6_u = { + .daddr = *(struct in6_addr *)&daddr->a6, + }, + }, + }; + +if (!xfrm6_dst_lookup ((struct xfrm_dst **)&rt, &fl_tunnel)) { +ipv6_get_saddr (&rt->u.dst, (struct in6_addr *)&daddr->a6, + (struct in6_addr *)&saddr->a6); +dst_release (&rt->u.dst); +return 0 ; + } +return -EHOSTUNREACH ; +} +static struct dst_entry *__xfrm6_find_bundle (struct flowi *fl,struct xfrm_policy *policy) {
@@ -362,6 +382,7 @@ static struct xfrm_policy_afinfo xfrm6_p .family = AF_INET6, .dst_ops = &xfrm6_dst_ops, .dst_lookup = xfrm6_dst_lookup, + .get_saddr = xfrm6_get_saddr, .find_bundle = __xfrm6_find_bundle, .bundle_create = __xfrm6_bundle_create, .decode_session = _decode_session6,
net/ipv6/xfrm6_state.c +0 -16
@@ -42,22 +42,6 @@ __xfrm6_init_tempsel(struct xfrm_state *memcpy (&x->props.saddr, &tmpl->saddr,sizeof (x->props.saddr));if (ipv6_addr_any ((struct in6_addr *)&x->props.saddr))memcpy (&x->props.saddr, saddr,sizeof (x->props.saddr)); -if (tmpl->mode ==XFRM_MODE_TUNNEL &&ipv6_addr_any ((struct in6_addr *)&x->props.saddr)) { -struct rt6_info *rt; -struct flowi fl_tunnel = { - .nl_u = { - .ip6_u = { - .daddr = *(struct in6_addr *)daddr, - } - } - }; -if (!xfrm_dst_lookup ((struct xfrm_dst **)&rt, - &fl_tunnel,AF_INET6 )) { -ipv6_get_saddr (&rt->u.dst, (struct in6_addr *)daddr, - (struct in6_addr *)&x->props.saddr); -dst_release (&rt->u.dst); - } - } x->props.mode = tmpl->mode; x->props.reqid = tmpl->reqid; x->props.family =AF_INET6 ;
net/xfrm/xfrm_policy.c +21 -0
@@ -1107,6 +1107,20 @@ int __xfrm_sk_clone_policy(struct sock *return 0 ; } +static int +xfrm_get_saddr (xfrm_address_t *local,xfrm_address_t *remote, +unsigned short family) +{ +int err; +struct xfrm_policy_afinfo *afinfo =xfrm_policy_get_afinfo (family); + +if (unlikely (afinfo ==NULL )) +return -EINVAL ; + err = afinfo->get_saddr (local, remote); +xfrm_policy_put_afinfo (afinfo); +return err; +} +/* Resolve list of templates for the flow, given policy. */ static int
@@ -1118,6 +1132,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policyint i, error;xfrm_address_t *daddr =xfrm_flowi_daddr (fl, family);xfrm_address_t *saddr =xfrm_flowi_saddr (fl, family); +xfrm_address_t tmp;for (nx=0 , i =0 ; i < policy->xfrm_nr; i++) {struct xfrm_state *x;
@@ -1128,6 +1143,12 @@ xfrm_tmpl_resolve_one(struct xfrm_policyif (tmpl->mode ==XFRM_MODE_TUNNEL ) { remote = &tmpl->id.daddr; local = &tmpl->saddr; +if (xfrm_addr_any (local, family)) { + error =xfrm_get_saddr (&tmp, remote, family); +if (error) + goto fail; + local = &tmp; + } } x =xfrm_state_find (remote, local, fl, tmpl, policy, &error, family);
David Miller
maintainerFrom: Patrick McHardy <[email protected]>
Date: Mon, 18 Sep 2006 11:43:49 +0200
Quoted 1 line
D'oh. Fixed patch attached.
Looks good Patrick, applied.
Thanks.