* [XFRM]: Fix wildcard as tunnel source
@ 2006-09-02 14:46 Patrick McHardy
2006-09-18 7:19 ` David Miller
0 siblings, 1 reply; 6+ messages in thread
From: Patrick McHardy @ 2006-09-02 14:46 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
[-- Attachment #1: Type: text/plain, Size: 0 bytes --]
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 4008 bytes --]
[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 <kaber@trash.net>
---
commit 19f7b6f33c0e9fbdf23a33506c2dfc0706b0c731
tree bca60eb94c50fcd66673bd87823fd38364b45b55
parent 6ddbd02eb61532f9af4f28912a09717ab8c71d8a
author Patrick McHardy <kaber@gw.localnet> Sat, 02 Sep 2006 16:43:39 +0200
committer Patrick McHardy <kaber@gw.localnet> 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(-)
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index d3abb0b..deb18ce 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -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;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 9f63edd..0c26a1f 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -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 hl
hlist_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(str
struct 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;
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [XFRM]: Fix wildcard as tunnel source
2006-09-02 14:46 [XFRM]: Fix wildcard as tunnel source Patrick McHardy
@ 2006-09-18 7:19 ` David Miller
2006-09-18 7:51 ` Patrick McHardy
0 siblings, 1 reply; 6+ messages in thread
From: David Miller @ 2006-09-18 7:19 UTC (permalink / raw)
To: kaber; +Cc: netdev
From: Patrick McHardy <kaber@trash.net>
Date: Sat, 02 Sep 2006 16:46:44 +0200
> [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 <kaber@trash.net>
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.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [XFRM]: Fix wildcard as tunnel source
2006-09-18 7:19 ` David Miller
@ 2006-09-18 7:51 ` Patrick McHardy
2006-09-18 9:39 ` Patrick McHardy
0 siblings, 1 reply; 6+ messages in thread
From: Patrick McHardy @ 2006-09-18 7:51 UTC (permalink / raw)
To: David Miller; +Cc: netdev
David Miller wrote:
> 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.
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.
> 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.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [XFRM]: Fix wildcard as tunnel source
2006-09-18 7:51 ` Patrick McHardy
@ 2006-09-18 9:39 ` Patrick McHardy
2006-09-18 9:43 ` Patrick McHardy
0 siblings, 1 reply; 6+ messages in thread
From: Patrick McHardy @ 2006-09-18 9:39 UTC (permalink / raw)
To: David Miller; +Cc: netdev
[-- Attachment #1: Type: text/plain, Size: 897 bytes --]
Patrick McHardy wrote:
> David Miller wrote:
>
>>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.
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.
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 7137 bytes --]
[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.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit f3307c3183e50959247f28c773590b5d7902097f
tree 78ddff768dc25145110767f182408ed6993828c5
parent c2cb1937e1054380c49699188810b9c6e04c8e21
author Patrick McHardy <kaber@trash.net> Mon, 18 Sep 2006 11:34:25 +0200
committer Patrick McHardy <kaber@trash.net> 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(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index bf8e2df..c6fac69 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -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 &&
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 4795985..eabcd27 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -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,
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 6a2a4ab..fe20344 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -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;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 9391c4c..6a252e2 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -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,
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index d88cd92..711bfaf 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -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;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 537854f..b6e2e79 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -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_policy
int 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_policy
if (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);
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [XFRM]: Fix wildcard as tunnel source
2006-09-18 9:39 ` Patrick McHardy
@ 2006-09-18 9:43 ` Patrick McHardy
2006-09-19 19:57 ` David Miller
0 siblings, 1 reply; 6+ messages in thread
From: Patrick McHardy @ 2006-09-18 9:43 UTC (permalink / raw)
To: David Miller; +Cc: netdev
[-- Attachment #1: Type: text/plain, Size: 582 bytes --]
Patrick McHardy wrote:
> [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
> +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.
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 7139 bytes --]
[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.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit f3307c3183e50959247f28c773590b5d7902097f
tree 78ddff768dc25145110767f182408ed6993828c5
parent c2cb1937e1054380c49699188810b9c6e04c8e21
author Patrick McHardy <kaber@trash.net> Mon, 18 Sep 2006 11:34:25 +0200
committer Patrick McHardy <kaber@trash.net> 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(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index bf8e2df..c6fac69 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -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 &&
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 4795985..eabcd27 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -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,
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index 6a2a4ab..fe20344 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -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;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 9391c4c..6a252e2 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -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,
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index d88cd92..711bfaf 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -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;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 537854f..b6e2e79 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -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_policy
int 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_policy
if (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);
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2006-09-19 19:57 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-09-02 14:46 [XFRM]: Fix wildcard as tunnel source Patrick McHardy
2006-09-18 7:19 ` David Miller
2006-09-18 7:51 ` Patrick McHardy
2006-09-18 9:39 ` Patrick McHardy
2006-09-18 9:43 ` Patrick McHardy
2006-09-19 19:57 ` 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).