* [PATCH 1/11] [IPV6]: Only set nfheader_len for top xfrm dst
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 2/11] [IPSEC]: Use dst->header_len when resizing on output Herbert Xu
` (10 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPV6]: Only set nfheader_len for top xfrm dst
We only need to set nfheader_len in the top xfrm dst. This is because
we only ever read the nfheader_len from the top xfrm dst.
It is also easier to count nfheader_len as part of header_len which
then lets us remove the ugly wrapper functions for incrementing and
decrementing header lengths in xfrm6_policy.c.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv6/ip6_output.c | 3 ++-
net/ipv6/xfrm6_policy.c | 26 ++++----------------------
2 files changed, 6 insertions(+), 23 deletions(-)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 13565df..b1647f5 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1096,7 +1096,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
inet->cork.length = 0;
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
- exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0);
+ exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) -
+ rt->u.dst.nfheader_len;
length += exthdrlen;
transhdrlen += exthdrlen;
} else {
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 82e27b8..e5170bc 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -102,24 +102,6 @@ __xfrm6_bundle_addr_local(struct xfrm_state *x, struct in6_addr *addr)
(struct in6_addr*)&x->props.saddr;
}
-static inline void
-__xfrm6_bundle_len_inc(int *len, int *nflen, struct xfrm_state *x)
-{
- if (x->type->flags & XFRM_TYPE_NON_FRAGMENT)
- *nflen += x->props.header_len;
- else
- *len += x->props.header_len;
-}
-
-static inline void
-__xfrm6_bundle_len_dec(int *len, int *nflen, struct xfrm_state *x)
-{
- if (x->type->flags & XFRM_TYPE_NON_FRAGMENT)
- *nflen -= x->props.header_len;
- else
- *len -= x->props.header_len;
-}
-
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
* all the metrics... Shortly, bundle a bundle.
*/
@@ -142,7 +124,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
int i;
int err = 0;
int header_len = 0;
- int nfheader_len = 0;
int trailer_len = 0;
dst = dst_prev = NULL;
@@ -175,7 +156,9 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->next = dst_prev;
dst_prev = dst1;
- __xfrm6_bundle_len_inc(&header_len, &nfheader_len, xfrm[i]);
+ if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
+ dst->nfheader_len += xfrm[i]->props.header_len;
+ header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
@@ -223,7 +206,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
dst_prev->header_len = header_len;
- dst_prev->nfheader_len = nfheader_len;
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
@@ -242,7 +224,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
x->u.rt6.rt6i_src = rt0->rt6i_src;
x->u.rt6.rt6i_idev = rt0->rt6i_idev;
in6_dev_hold(rt0->rt6i_idev);
- __xfrm6_bundle_len_dec(&header_len, &nfheader_len, x->u.dst.xfrm);
+ header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 2/11] [IPSEC]: Use dst->header_len when resizing on output
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
2007-10-23 16:03 ` [PATCH 1/11] [IPV6]: Only set nfheader_len for top xfrm dst Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 3/11] [IPV6]: Move nfheader_len into rt6_info Herbert Xu
` (9 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPSEC]: Use dst->header_len when resizing on output
Currently we use x->props.header_len when resizing on output. However,
if we're resizing at all we might as well go the whole hog and do it
for the whole dst.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/xfrm/xfrm_output.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index f4bfd6c..58d5a74 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -19,7 +19,8 @@
static int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb)
{
- int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev)
+ struct dst_entry *dst = skb->dst;
+ int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev)
- skb_headroom(skb);
if (nhead > 0)
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 3/11] [IPV6]: Move nfheader_len into rt6_info
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
2007-10-23 16:03 ` [PATCH 1/11] [IPV6]: Only set nfheader_len for top xfrm dst Herbert Xu
2007-10-23 16:03 ` [PATCH 2/11] [IPSEC]: Use dst->header_len when resizing on output Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 4/11] [NET]: Eliminate duplicate copies of dst_discard Herbert Xu
` (8 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPV6]: Move nfheader_len into rt6_info
The dst member nfheader_len is only used by IPv6. It's also currently
creating a rather ugly alignment hole in struct dst. Therefore this patch
moves it from there into struct rt6_info.
It also reorders the fields in rt6_info to minimize holes.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/dst.h | 1 -
include/net/ip6_fib.h | 11 ++++++++---
net/ipv4/xfrm4_policy.c | 1 -
net/ipv6/ip6_output.c | 5 +++--
net/ipv6/xfrm6_policy.c | 3 ++-
5 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index e9ff4a4..8f88c52 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -50,7 +50,6 @@ struct dst_entry
unsigned long expires;
unsigned short header_len; /* more space at head required */
- unsigned short nfheader_len; /* more non-fragment space at head required */
unsigned short trailer_len; /* space to reserve at tail */
u32 metrics[RTAX_MAX];
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 8578213..4cefcff 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -99,16 +99,21 @@ struct rt6_info
u32 rt6i_flags;
u32 rt6i_metric;
atomic_t rt6i_ref;
- struct fib6_table *rt6i_table;
- struct rt6key rt6i_dst;
- struct rt6key rt6i_src;
+ /* more non-fragment space at head required */
+ unsigned short nfheader_len;
u8 rt6i_protocol;
+ struct fib6_table *rt6i_table;
+
+ struct rt6key rt6i_dst;
+
#ifdef CONFIG_XFRM
u32 rt6i_flow_cache_genid;
#endif
+
+ struct rt6key rt6i_src;
};
static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index cc86fb1..5ee3a2f 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -161,7 +161,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
dst_prev->header_len = header_len;
- dst_prev->nfheader_len = 0;
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index b1647f5..85c5eb8 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1097,7 +1097,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
sk->sk_sndmsg_page = NULL;
sk->sk_sndmsg_off = 0;
exthdrlen = rt->u.dst.header_len + (opt ? opt->opt_flen : 0) -
- rt->u.dst.nfheader_len;
+ rt->nfheader_len;
length += exthdrlen;
transhdrlen += exthdrlen;
} else {
@@ -1112,7 +1112,8 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
- fragheaderlen = sizeof(struct ipv6hdr) + rt->u.dst.nfheader_len + (opt ? opt->opt_nflen : 0);
+ fragheaderlen = sizeof(struct ipv6hdr) + rt->nfheader_len +
+ (opt ? opt->opt_nflen : 0);
maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr);
if (mtu <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN) {
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index e5170bc..9095dfc 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -157,7 +157,8 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev = dst1;
if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
- dst->nfheader_len += xfrm[i]->props.header_len;
+ ((struct rt6_info *)dst)->nfheader_len +=
+ xfrm[i]->props.header_len;
header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 4/11] [NET]: Eliminate duplicate copies of dst_discard
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (2 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 3/11] [IPV6]: Move nfheader_len into rt6_info Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 5/11] [NET]: Remove unnecessary inclusion of dst.h Herbert Xu
` (7 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[NET]: Eliminate duplicate copies of dst_discard
We have a number of copies of dst_discard scattered around the place which
all do the same thing, namely free a packet on the input or output paths.
This patch deletes all of them except dst_discard and points all the users
to it.
The only non-trivial bit is decnet where it returns an error. However,
conceptually this is identical to the blackhole functions used in IPv4
and IPv6 which do not return errors. So they should either all return
errors or all return zero. For now I've stuck with the majority and
picked zero as the return value.
It doesn't really matter in practice since few if any driver would react
differently depending on a zero return value or NET_RX_DROP.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/dst.h | 1 +
net/core/dst.c | 3 ++-
net/decnet/dn_route.c | 13 +------------
net/ipv4/route.c | 11 +++--------
net/ipv6/exthdrs.c | 13 ++-----------
net/ipv6/route.c | 21 ++++-----------------
6 files changed, 13 insertions(+), 49 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index 8f88c52..4df103b 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -172,6 +172,7 @@ static inline struct dst_entry *dst_pop(struct dst_entry *dst)
return child;
}
+extern int dst_discard(struct sk_buff *skb);
extern void * dst_alloc(struct dst_ops * ops);
extern void __dst_free(struct dst_entry * dst);
extern struct dst_entry *dst_destroy(struct dst_entry * dst);
diff --git a/net/core/dst.c b/net/core/dst.c
index 16958e6..21b1d0f 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -154,11 +154,12 @@ loop:
#endif
}
-static int dst_discard(struct sk_buff *skb)
+int dst_discard(struct sk_buff *skb)
{
kfree_skb(skb);
return 0;
}
+EXPORT_SYMBOL(dst_discard);
void * dst_alloc(struct dst_ops * ops)
{
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 97eee5e..e1f6669 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -769,17 +769,6 @@ drop:
}
/*
- * Drop packet. This is used for endnodes and for
- * when we should not be forwarding packets from
- * this dest.
- */
-static int dn_blackhole(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return NET_RX_DROP;
-}
-
-/*
* Used to catch bugs. This should never normally get
* called.
*/
@@ -1402,7 +1391,7 @@ make_route:
default:
case RTN_UNREACHABLE:
case RTN_BLACKHOLE:
- rt->u.dst.input = dn_blackhole;
+ rt->u.dst.input = dst_discard;
}
rt->rt_flags = flags;
if (rt->u.dst.dev)
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 21b12de..d5cbcee 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -92,6 +92,7 @@
#include <linux/jhash.h>
#include <linux/rcupdate.h>
#include <linux/times.h>
+#include <net/dst.h>
#include <net/net_namespace.h>
#include <net/protocol.h>
#include <net/ip.h>
@@ -2362,12 +2363,6 @@ static struct dst_ops ipv4_dst_blackhole_ops = {
};
-static int ipv4_blackhole_output(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk)
{
struct rtable *ort = *rp;
@@ -2379,8 +2374,8 @@ static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock
atomic_set(&new->__refcnt, 1);
new->__use = 1;
- new->input = ipv4_blackhole_output;
- new->output = ipv4_blackhole_output;
+ new->input = dst_discard;
+ new->output = dst_discard;
memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
new->dev = ort->u.dst.dev;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 1e89efd..cee06b1 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -32,6 +32,7 @@
#include <linux/in6.h>
#include <linux/icmpv6.h>
+#include <net/dst.h>
#include <net/sock.h>
#include <net/snmp.h>
@@ -318,18 +319,8 @@ void __init ipv6_destopt_init(void)
printk(KERN_ERR "ipv6_destopt_init: Could not register protocol\n");
}
-/********************************
- NONE header. No data in packet.
- ********************************/
-
-static int ipv6_nodata_rcv(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
static struct inet6_protocol nodata_protocol = {
- .handler = ipv6_nodata_rcv,
+ .handler = dst_discard,
.flags = INET6_PROTO_NOPOLICY,
};
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 95f8e4a..7db3cdf 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -156,7 +156,6 @@ struct rt6_info ip6_null_entry = {
static int ip6_pkt_prohibit(struct sk_buff *skb);
static int ip6_pkt_prohibit_out(struct sk_buff *skb);
-static int ip6_pkt_blk_hole(struct sk_buff *skb);
struct rt6_info ip6_prohibit_entry = {
.u = {
@@ -185,8 +184,8 @@ struct rt6_info ip6_blk_hole_entry = {
.obsolete = -1,
.error = -EINVAL,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_blk_hole,
- .output = ip6_pkt_blk_hole,
+ .input = dst_discard,
+ .output = dst_discard,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_blk_hole_entry,
}
@@ -785,12 +784,6 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
EXPORT_SYMBOL(ip6_route_output);
-static int ip6_blackhole_output(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl)
{
struct rt6_info *ort = (struct rt6_info *) *dstp;
@@ -803,8 +796,8 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
atomic_set(&new->__refcnt, 1);
new->__use = 1;
- new->input = ip6_blackhole_output;
- new->output = ip6_blackhole_output;
+ new->input = dst_discard;
+ new->output = dst_discard;
memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
new->dev = ort->u.dst.dev;
@@ -1814,12 +1807,6 @@ static int ip6_pkt_prohibit_out(struct sk_buff *skb)
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
}
-static int ip6_pkt_blk_hole(struct sk_buff *skb)
-{
- kfree_skb(skb);
- return 0;
-}
-
#endif
/*
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 5/11] [NET]: Remove unnecessary inclusion of dst.h
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (3 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 4/11] [NET]: Eliminate duplicate copies of dst_discard Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 6/11] [IPSEC]: Only set neighbour on top xfrm dst Herbert Xu
` (6 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[NET]: Remove unnecessary inclusion of dst.h
The file net/netevent.h only refers to struct dst_entry * so it doesn't
need to include dst.h. I've replaced it with a forward declaration.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/netevent.h | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/net/netevent.h b/include/net/netevent.h
index e5d2162..e82b7ba 100644
--- a/include/net/netevent.h
+++ b/include/net/netevent.h
@@ -12,7 +12,7 @@
*/
#ifdef __KERNEL__
-#include <net/dst.h>
+struct dst_entry;
struct netevent_redirect {
struct dst_entry *old;
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 6/11] [IPSEC]: Only set neighbour on top xfrm dst
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (4 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 5/11] [NET]: Remove unnecessary inclusion of dst.h Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 7/11] [IPSEC]: Set dst->input to dst_discard Herbert Xu
` (5 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPSEC]: Only set neighbour on top xfrm dst
The neighbour field is only used by dst_confirm which only ever happens on
the top-most xfrm dst. So it's a waste to duplicate for every other xfrm
dst. This patch moves its setting out of the loop so that only the top one
gets set.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv4/xfrm4_policy.c | 5 +++--
net/ipv6/xfrm6_policy.c | 6 ++++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 5ee3a2f..7d250a1 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -144,6 +144,9 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->child = &rt->u.dst;
dst->path = &rt->u.dst;
+ /* Copy neighbout for reachability confirmation */
+ dst->neighbour = neigh_clone(rt->u.dst.neighbour);
+
*dst_p = dst;
dst = dst_prev;
@@ -164,8 +167,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
- /* Copy neighbout for reachability confirmation */
- dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);
dst_prev->input = rt->u.dst.input;
dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
if (rt0->peer)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 9095dfc..15747f3 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -188,6 +188,10 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->child = &rt->u.dst;
dst->path = &rt->u.dst;
+
+ /* Copy neighbour for reachability confirmation */
+ dst->neighbour = neigh_clone(rt->u.dst.neighbour);
+
if (rt->rt6i_node)
((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum;
@@ -210,8 +214,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
- /* Copy neighbour for reachability confirmation */
- dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);
dst_prev->input = rt->u.dst.input;
dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
/* Sheit... I remember I did this right. Apparently,
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 7/11] [IPSEC]: Set dst->input to dst_discard
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (5 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 6/11] [IPSEC]: Only set neighbour on top xfrm dst Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 8/11] [IPSEC]: Make sure idev is consistent with dev in xfrm_dst Herbert Xu
` (4 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPSEC]: Set dst->input to dst_discard
The input function should never be invoked on IPsec dst objects. This is
because we don't apply IPsec on input until after we've made the routing
decision.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv4/xfrm4_policy.c | 3 ++-
net/ipv6/xfrm6_policy.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 7d250a1..c40a71b 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -10,6 +10,7 @@
#include <linux/compiler.h>
#include <linux/inetdevice.h>
+#include <net/dst.h>
#include <net/xfrm.h>
#include <net/ip.h>
@@ -167,7 +168,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
- dst_prev->input = rt->u.dst.input;
+ dst_prev->input = dst_discard;
dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
if (rt0->peer)
atomic_inc(&rt0->peer->refcnt);
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 15747f3..a1c6b7c 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/netdevice.h>
#include <net/addrconf.h>
+#include <net/dst.h>
#include <net/xfrm.h>
#include <net/ip.h>
#include <net/ipv6.h>
@@ -214,7 +215,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
- dst_prev->input = rt->u.dst.input;
+ dst_prev->input = dst_discard;
dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
/* Sheit... I remember I did this right. Apparently,
* it was magically lost, so this code needs audit */
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 8/11] [IPSEC]: Make sure idev is consistent with dev in xfrm_dst
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (6 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 7/11] [IPSEC]: Set dst->input to dst_discard Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 9/11] [IPSEC]: Replace x->type->{local,remote}_addr with flags Herbert Xu
` (3 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPSEC]: Make sure idev is consistent with dev in xfrm_dst
Previously we took the device from the bottom route and idev from the top
route. This is bad because idev may well point to a different device.
This patch changes it so that we get the idev from the device directly.
It also makes it an error if either dev or idev is NULL. This is consistent
with the rest of the routing code which also treats these cases as errors.
I've removed the err initialisation in xfrm6_policy.c because it achieves
no purpose and hid a bug when an initial version of this patch neglected
to set err to -ENODEV (fortunately the IPv4 version warned about it).
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
net/ipv4/xfrm4_policy.c | 13 +++++++++----
net/ipv6/xfrm6_policy.c | 15 ++++++++++-----
2 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index c40a71b..d903c8b 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -153,14 +153,21 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev = *dst_p;
i = 0;
+ err = -ENODEV;
for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
x->u.rt.fl = *fl;
dst_prev->xfrm = xfrm[i++];
dst_prev->dev = rt->u.dst.dev;
- if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ if (!rt->u.dst.dev)
+ goto error;
+ dev_hold(rt->u.dst.dev);
+
+ x->u.rt.idev = in_dev_get(rt->u.dst.dev);
+ if (!x->u.rt.idev)
+ goto error;
+
dst_prev->obsolete = -1;
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
@@ -181,8 +188,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
x->u.rt.rt_dst = rt0->rt_dst;
x->u.rt.rt_gateway = rt0->rt_gateway;
x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
- x->u.rt.idev = rt0->idev;
- in_dev_hold(rt0->idev);
header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index a1c6b7c..f04e718 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -123,7 +123,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
}
};
int i;
- int err = 0;
+ int err;
int header_len = 0;
int trailer_len = 0;
@@ -201,13 +201,20 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev = *dst_p;
i = 0;
+ err = -ENODEV;
for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
dst_prev->xfrm = xfrm[i++];
dst_prev->dev = rt->u.dst.dev;
- if (rt->u.dst.dev)
- dev_hold(rt->u.dst.dev);
+ if (!rt->u.dst.dev)
+ goto error;
+ dev_hold(rt->u.dst.dev);
+
+ x->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
+ if (!x->u.rt6.rt6i_idev)
+ goto error;
+
dst_prev->obsolete = -1;
dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
@@ -226,8 +233,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway));
x->u.rt6.rt6i_dst = rt0->rt6i_dst;
x->u.rt6.rt6i_src = rt0->rt6i_src;
- x->u.rt6.rt6i_idev = rt0->rt6i_idev;
- in6_dev_hold(rt0->rt6i_idev);
header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 9/11] [IPSEC]: Replace x->type->{local,remote}_addr with flags
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (7 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 8/11] [IPSEC]: Make sure idev is consistent with dev in xfrm_dst Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 10/11] [IPSEC]: Move flow construction into xfrm_dst_lookup Herbert Xu
` (2 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPSEC]: Replace x->type->{local,remote}_addr with flags
The functions local_addr and remote_addr are more than what they're needed
for. The same thing can be done easily with flags on the type object.
This patch does that and simplifies the wrapper functions in xfrm6_policy
accordingly.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/xfrm.h | 4 ++--
net/ipv6/mip6.c | 11 ++---------
net/ipv6/xfrm6_policy.c | 20 ++++++++------------
3 files changed, 12 insertions(+), 23 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 688f6f5..9ca4ae5 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -280,6 +280,8 @@ struct xfrm_type
__u8 flags;
#define XFRM_TYPE_NON_FRAGMENT 1
#define XFRM_TYPE_REPLAY_PROT 2
+#define XFRM_TYPE_LOCAL_COADDR 4
+#define XFRM_TYPE_REMOTE_COADDR 8
int (*init_state)(struct xfrm_state *x);
void (*destructor)(struct xfrm_state *);
@@ -287,8 +289,6 @@ struct xfrm_type
int (*output)(struct xfrm_state *, struct sk_buff *pskb);
int (*reject)(struct xfrm_state *, struct sk_buff *, struct flowi *);
int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **);
- xfrm_address_t *(*local_addr)(struct xfrm_state *, xfrm_address_t *);
- xfrm_address_t *(*remote_addr)(struct xfrm_state *, xfrm_address_t *);
/* Estimate maximal size of result of transformation of a dgram */
u32 (*get_mtu)(struct xfrm_state *, int size);
};
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 7fd841d..edfd9cd 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -34,11 +34,6 @@
#include <net/xfrm.h>
#include <net/mip6.h>
-static xfrm_address_t *mip6_xfrm_addr(struct xfrm_state *x, xfrm_address_t *addr)
-{
- return x->coaddr;
-}
-
static inline unsigned int calc_padlen(unsigned int len, unsigned int n)
{
return (n - len + 16) & 0x7;
@@ -337,14 +332,13 @@ static struct xfrm_type mip6_destopt_type =
.description = "MIP6DESTOPT",
.owner = THIS_MODULE,
.proto = IPPROTO_DSTOPTS,
- .flags = XFRM_TYPE_NON_FRAGMENT,
+ .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_LOCAL_COADDR,
.init_state = mip6_destopt_init_state,
.destructor = mip6_destopt_destroy,
.input = mip6_destopt_input,
.output = mip6_destopt_output,
.reject = mip6_destopt_reject,
.hdr_offset = mip6_destopt_offset,
- .local_addr = mip6_xfrm_addr,
};
static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
@@ -467,13 +461,12 @@ static struct xfrm_type mip6_rthdr_type =
.description = "MIP6RT",
.owner = THIS_MODULE,
.proto = IPPROTO_ROUTING,
- .flags = XFRM_TYPE_NON_FRAGMENT,
+ .flags = XFRM_TYPE_NON_FRAGMENT | XFRM_TYPE_REMOTE_COADDR,
.init_state = mip6_rthdr_init_state,
.destructor = mip6_rthdr_destroy,
.input = mip6_rthdr_input,
.output = mip6_rthdr_output,
.hdr_offset = mip6_rthdr_offset,
- .remote_addr = mip6_xfrm_addr,
};
static int __init mip6_init(void)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index f04e718..ed29bef 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -87,20 +87,16 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
return dst;
}
-static inline struct in6_addr*
-__xfrm6_bundle_addr_remote(struct xfrm_state *x, struct in6_addr *addr)
+static inline xfrm_address_t *__xfrm6_bundle_addr_remote(struct xfrm_state *x)
{
- return (x->type->remote_addr) ?
- (struct in6_addr*)x->type->remote_addr(x, (xfrm_address_t *)addr) :
- (struct in6_addr*)&x->id.daddr;
+ return (x->type->flags & XFRM_TYPE_REMOTE_COADDR) ? x->coaddr :
+ &x->id.daddr;
}
-static inline struct in6_addr*
-__xfrm6_bundle_addr_local(struct xfrm_state *x, struct in6_addr *addr)
+static inline xfrm_address_t *__xfrm6_bundle_addr_local(struct xfrm_state *x)
{
- return (x->type->local_addr) ?
- (struct in6_addr*)x->type->local_addr(x, (xfrm_address_t *)addr) :
- (struct in6_addr*)&x->props.saddr;
+ return (x->type->flags & XFRM_TYPE_LOCAL_COADDR) ? x->coaddr :
+ &x->props.saddr;
}
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
@@ -171,9 +167,9 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
break;
case AF_INET6:
- ipv6_addr_copy(&fl_tunnel.fl6_dst, __xfrm6_bundle_addr_remote(xfrm[i], &fl->fl6_dst));
+ ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr *)__xfrm6_bundle_addr_remote(xfrm[i]));
- ipv6_addr_copy(&fl_tunnel.fl6_src, __xfrm6_bundle_addr_local(xfrm[i], &fl->fl6_src));
+ ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr *)__xfrm6_bundle_addr_local(xfrm[i]));
break;
default:
BUG_ON(1);
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 10/11] [IPSEC]: Move flow construction into xfrm_dst_lookup
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (8 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 9/11] [IPSEC]: Replace x->type->{local,remote}_addr with flags Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-23 16:03 ` [PATCH 11/11] [IPSEC]: Merge common code into xfrm_bundle_create Herbert Xu
2007-10-30 5:06 ` [0/11] Merge bundle creation and other misc fixes/clean-ups David Miller
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPSEC]: Move flow construction into xfrm_dst_lookup
This patch moves the flow construction from the callers of xfrm_dst_lookup
into that function. It also changes xfrm_dst_lookup so that it takes an
xfrm state as its argument instead of explicit addresses.
This removes any address-specific logic from the callers of xfrm_dst_lookup
which is needed to correctly support inter-family transforms.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/xfrm.h | 10 +---
net/ipv4/xfrm4_policy.c | 80 ++++++++++++++++++---------------------
net/ipv6/xfrm6_policy.c | 97 +++++++++++++++++-------------------------------
net/xfrm/xfrm_policy.c | 25 +++++++-----
4 files changed, 91 insertions(+), 121 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 9ca4ae5..206c6f6 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -231,7 +231,8 @@ struct xfrm_policy_afinfo {
unsigned short family;
struct dst_ops *dst_ops;
void (*garbage_collect)(void);
- int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl);
+ struct dst_entry *(*dst_lookup)(int tos, xfrm_address_t *saddr,
+ xfrm_address_t *daddr);
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,
@@ -1077,7 +1078,6 @@ extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
#ifdef CONFIG_XFRM
extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen);
-extern int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family);
#else
static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen)
{
@@ -1090,13 +1090,9 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
kfree_skb(skb);
return 0;
}
-
-static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family)
-{
- return -EINVAL;
-}
#endif
+extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos);
struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index d903c8b..cebc847 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -8,7 +8,8 @@
*
*/
-#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
#include <linux/inetdevice.h>
#include <net/dst.h>
#include <net/xfrm.h>
@@ -17,28 +18,44 @@
static struct dst_ops xfrm4_dst_ops;
static struct xfrm_policy_afinfo xfrm4_policy_afinfo;
-static int xfrm4_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
+static struct dst_entry *xfrm4_dst_lookup(int tos, xfrm_address_t *saddr,
+ xfrm_address_t *daddr)
{
- 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 = {
+ struct flowi fl = {
.nl_u = {
.ip4_u = {
+ .tos = tos,
.daddr = daddr->a4,
},
},
};
+ struct dst_entry *dst;
+ struct rtable *rt;
+ int err;
- if (!xfrm4_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) {
- saddr->a4 = rt->rt_src;
- dst_release(&rt->u.dst);
- return 0;
- }
- return -EHOSTUNREACH;
+ if (saddr)
+ fl.fl4_src = saddr->a4;
+
+ err = __ip_route_output_key(&rt, &fl);
+ dst = &rt->u.dst;
+ if (err)
+ dst = ERR_PTR(err);
+ return dst;
+}
+
+static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr)
+{
+ struct dst_entry *dst;
+ struct rtable *rt;
+
+ dst = xfrm4_dst_lookup(0, NULL, daddr);
+ if (IS_ERR(dst))
+ return -EHOSTUNREACH;
+
+ rt = (struct rtable *)dst;
+ saddr->a4 = rt->rt_src;
+ dst_release(dst);
+ return 0;
}
static struct dst_entry *
@@ -73,15 +90,7 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct dst_entry *dst, *dst_prev;
struct rtable *rt0 = (struct rtable*)(*dst_p);
struct rtable *rt = rt0;
- struct flowi fl_tunnel = {
- .nl_u = {
- .ip4_u = {
- .saddr = fl->fl4_src,
- .daddr = fl->fl4_dst,
- .tos = fl->fl4_tos
- }
- }
- };
+ int tos = fl->fl4_tos;
int i;
int err;
int header_len = 0;
@@ -119,25 +128,12 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
trailer_len += xfrm[i]->props.trailer_len;
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- unsigned short encap_family = xfrm[i]->props.family;
- switch (encap_family) {
- case AF_INET:
- fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
- fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
- break;
-#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
- case AF_INET6:
- ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr*)&xfrm[i]->id.daddr.a6);
- ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr*)&xfrm[i]->props.saddr.a6);
- break;
-#endif
- default:
- BUG_ON(1);
- }
- err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
- &fl_tunnel, encap_family);
- if (err)
+ dst1 = xfrm_dst_lookup(xfrm[i], tos);
+ err = PTR_ERR(dst1);
+ if (IS_ERR(dst1))
goto error;
+
+ rt = (struct rtable *)dst1;
} else
dst_hold(&rt->u.dst);
}
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index ed29bef..864258f 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -11,7 +11,8 @@
*
*/
-#include <linux/compiler.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <net/addrconf.h>
#include <net/dst.h>
@@ -26,35 +27,40 @@
static struct dst_ops xfrm6_dst_ops;
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
-static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl)
+static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr,
+ xfrm_address_t *daddr)
{
- struct dst_entry *dst = ip6_route_output(NULL, fl);
- int err = dst->error;
- if (!err)
- *xdst = (struct xfrm_dst *) dst;
- else
+ struct flowi fl = {};
+ struct dst_entry *dst;
+ int err;
+
+ memcpy(&fl.fl6_dst, daddr, sizeof(fl.fl6_dst));
+ if (saddr)
+ memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src));
+
+ dst = ip6_route_output(NULL, &fl);
+
+ err = dst->error;
+ if (dst->error) {
dst_release(dst);
- return err;
+ dst = ERR_PTR(err);
+ }
+
+ return dst;
}
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;
+ struct dst_entry *dst;
+
+ dst = xfrm6_dst_lookup(0, NULL, daddr);
+ if (IS_ERR(dst))
+ return -EHOSTUNREACH;
+
+ ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6,
+ (struct in6_addr *)&saddr->a6);
+ dst_release(dst);
+ return 0;
}
static struct dst_entry *
@@ -87,18 +93,6 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
return dst;
}
-static inline xfrm_address_t *__xfrm6_bundle_addr_remote(struct xfrm_state *x)
-{
- return (x->type->flags & XFRM_TYPE_REMOTE_COADDR) ? x->coaddr :
- &x->id.daddr;
-}
-
-static inline xfrm_address_t *__xfrm6_bundle_addr_local(struct xfrm_state *x)
-{
- return (x->type->flags & XFRM_TYPE_LOCAL_COADDR) ? x->coaddr :
- &x->props.saddr;
-}
-
/* Allocate chain of dst_entry's, attach known xfrm's, calculate
* all the metrics... Shortly, bundle a bundle.
*/
@@ -110,14 +104,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct dst_entry *dst, *dst_prev;
struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
struct rt6_info *rt = rt0;
- struct flowi fl_tunnel = {
- .nl_u = {
- .ip6_u = {
- .saddr = fl->fl6_src,
- .daddr = fl->fl6_dst,
- }
- }
- };
int i;
int err;
int header_len = 0;
@@ -160,25 +146,12 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
trailer_len += xfrm[i]->props.trailer_len;
if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- unsigned short encap_family = xfrm[i]->props.family;
- switch(encap_family) {
- case AF_INET:
- fl_tunnel.fl4_dst = xfrm[i]->id.daddr.a4;
- fl_tunnel.fl4_src = xfrm[i]->props.saddr.a4;
- break;
- case AF_INET6:
- ipv6_addr_copy(&fl_tunnel.fl6_dst, (struct in6_addr *)__xfrm6_bundle_addr_remote(xfrm[i]));
-
- ipv6_addr_copy(&fl_tunnel.fl6_src, (struct in6_addr *)__xfrm6_bundle_addr_local(xfrm[i]));
- break;
- default:
- BUG_ON(1);
- }
-
- err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
- &fl_tunnel, encap_family);
- if (err)
+ dst1 = xfrm_dst_lookup(xfrm[i], 0);
+ err = PTR_ERR(dst1);
+ if (IS_ERR(dst1))
goto error;
+
+ rt = (struct rt6_info *)dst1;
} else
dst_hold(&rt->u.dst);
}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b702bd8..6168341 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -13,6 +13,7 @@
*
*/
+#include <linux/err.h>
#include <linux/slab.h>
#include <linux/kmod.h>
#include <linux/list.h>
@@ -84,21 +85,25 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
return 0;
}
-int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,
- unsigned short family)
+struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
{
- struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
- int err = 0;
+ xfrm_address_t *saddr = &x->props.saddr;
+ xfrm_address_t *daddr = &x->id.daddr;
+ struct xfrm_policy_afinfo *afinfo;
+ struct dst_entry *dst;
+ if (x->type->flags & XFRM_TYPE_LOCAL_COADDR)
+ saddr = x->coaddr;
+ if (x->type->flags & XFRM_TYPE_REMOTE_COADDR)
+ daddr = x->coaddr;
+
+ afinfo = xfrm_policy_get_afinfo(x->props.family);
if (unlikely(afinfo == NULL))
- return -EAFNOSUPPORT;
+ return ERR_PTR(-EAFNOSUPPORT);
- if (likely(afinfo->dst_lookup != NULL))
- err = afinfo->dst_lookup(dst, fl);
- else
- err = -EINVAL;
+ dst = afinfo->dst_lookup(tos, saddr, daddr);
xfrm_policy_put_afinfo(afinfo);
- return err;
+ return dst;
}
EXPORT_SYMBOL(xfrm_dst_lookup);
^ permalink raw reply related [flat|nested] 14+ messages in thread* [PATCH 11/11] [IPSEC]: Merge common code into xfrm_bundle_create
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (9 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 10/11] [IPSEC]: Move flow construction into xfrm_dst_lookup Herbert Xu
@ 2007-10-23 16:03 ` Herbert Xu
2007-10-30 5:06 ` [0/11] Merge bundle creation and other misc fixes/clean-ups David Miller
11 siblings, 0 replies; 14+ messages in thread
From: Herbert Xu @ 2007-10-23 16:03 UTC (permalink / raw)
To: David S. Miller, YOSHIFUJI Hideaki, netdev
[IPSEC]: Merge common code into xfrm_bundle_create
Half of the code in xfrm4_bundle_create and xfrm6_bundle_create are common.
This patch extracts that logic and puts it into xfrm_bundle_create. The
rest of it are then accessed through afinfo.
As a result this fixes the problem with inter-family transforms where we
treat every xfrm dst in the bundle as if it belongs to the top family.
This patch also fixes a long-standing error-path bug where we may free the
xfrm states twice.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
include/net/xfrm.h | 11 +-
net/ipv4/xfrm4_policy.c | 134 ++++++-----------------------------
net/ipv6/xfrm6_policy.c | 143 ++++++-------------------------------
net/xfrm/xfrm_policy.c | 183 +++++++++++++++++++++++++++++++++++++++++-------
4 files changed, 215 insertions(+), 256 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 206c6f6..2da5ac5 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -225,6 +225,7 @@ struct km_event
u32 event;
};
+struct net_device;
struct xfrm_type;
struct xfrm_dst;
struct xfrm_policy_afinfo {
@@ -235,13 +236,11 @@ struct xfrm_policy_afinfo {
xfrm_address_t *daddr);
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,
- int nx,
- struct flowi *fl,
- struct dst_entry **dst_p);
void (*decode_session)(struct sk_buff *skb,
struct flowi *fl);
+ int (*get_tos)(struct flowi *fl);
+ int (*fill_dst)(struct xfrm_dst *xdst,
+ struct net_device *dev);
};
extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo);
@@ -1092,7 +1091,6 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
}
#endif
-extern struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos);
struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
@@ -1111,7 +1109,6 @@ extern int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,
struct flowi *fl, int family, int strict);
-extern void xfrm_init_pmtu(struct dst_entry *dst);
#ifdef CONFIG_XFRM_MIGRATE
extern int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index cebc847..1d75243 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -79,122 +79,39 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
return dst;
}
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
-
-static int
-__xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
- struct flowi *fl, struct dst_entry **dst_p)
+static int xfrm4_get_tos(struct flowi *fl)
{
- struct dst_entry *dst, *dst_prev;
- struct rtable *rt0 = (struct rtable*)(*dst_p);
- struct rtable *rt = rt0;
- int tos = fl->fl4_tos;
- int i;
- int err;
- int header_len = 0;
- int trailer_len = 0;
-
- dst = dst_prev = NULL;
- dst_hold(&rt->u.dst);
-
- for (i = 0; i < nx; i++) {
- struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
- struct xfrm_dst *xdst;
-
- if (unlikely(dst1 == NULL)) {
- err = -ENOBUFS;
- dst_release(&rt->u.dst);
- goto error;
- }
+ return fl->fl4_tos;
+}
- if (!dst)
- dst = dst1;
- else {
- dst_prev->child = dst1;
- dst1->flags |= DST_NOHASH;
- dst_clone(dst1);
- }
+static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+ struct rtable *rt = (struct rtable *)xdst->route;
- xdst = (struct xfrm_dst *)dst1;
- xdst->route = &rt->u.dst;
- xdst->genid = xfrm[i]->genid;
+ xdst->u.rt.fl = rt->fl;
- dst1->next = dst_prev;
- dst_prev = dst1;
+ xdst->u.dst.dev = dev;
+ dev_hold(dev);
- header_len += xfrm[i]->props.header_len;
- trailer_len += xfrm[i]->props.trailer_len;
+ xdst->u.rt.idev = in_dev_get(dev);
+ if (!xdst->u.rt.idev)
+ return -ENODEV;
- if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- dst1 = xfrm_dst_lookup(xfrm[i], tos);
- err = PTR_ERR(dst1);
- if (IS_ERR(dst1))
- goto error;
+ xdst->u.rt.peer = rt->peer;
+ if (rt->peer)
+ atomic_inc(&rt->peer->refcnt);
- rt = (struct rtable *)dst1;
- } else
- dst_hold(&rt->u.dst);
- }
+ /* Sheit... I remember I did this right. Apparently,
+ * it was magically lost, so this code needs audit */
+ xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST |
+ RTCF_LOCAL);
+ xdst->u.rt.rt_type = rt->rt_type;
+ xdst->u.rt.rt_src = rt->rt_src;
+ xdst->u.rt.rt_dst = rt->rt_dst;
+ xdst->u.rt.rt_gateway = rt->rt_gateway;
+ xdst->u.rt.rt_spec_dst = rt->rt_spec_dst;
- dst_prev->child = &rt->u.dst;
- dst->path = &rt->u.dst;
-
- /* Copy neighbout for reachability confirmation */
- dst->neighbour = neigh_clone(rt->u.dst.neighbour);
-
- *dst_p = dst;
- dst = dst_prev;
-
- dst_prev = *dst_p;
- i = 0;
- err = -ENODEV;
- for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
- struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
- x->u.rt.fl = *fl;
-
- dst_prev->xfrm = xfrm[i++];
- dst_prev->dev = rt->u.dst.dev;
- if (!rt->u.dst.dev)
- goto error;
- dev_hold(rt->u.dst.dev);
-
- x->u.rt.idev = in_dev_get(rt->u.dst.dev);
- if (!x->u.rt.idev)
- goto error;
-
- dst_prev->obsolete = -1;
- dst_prev->flags |= DST_HOST;
- dst_prev->lastuse = jiffies;
- dst_prev->header_len = header_len;
- dst_prev->trailer_len = trailer_len;
- memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
-
- dst_prev->input = dst_discard;
- dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
- if (rt0->peer)
- atomic_inc(&rt0->peer->refcnt);
- x->u.rt.peer = rt0->peer;
- /* Sheit... I remember I did this right. Apparently,
- * it was magically lost, so this code needs audit */
- x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
- x->u.rt.rt_type = rt0->rt_type;
- x->u.rt.rt_src = rt0->rt_src;
- x->u.rt.rt_dst = rt0->rt_dst;
- x->u.rt.rt_gateway = rt0->rt_gateway;
- x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
- header_len -= x->u.dst.xfrm->props.header_len;
- trailer_len -= x->u.dst.xfrm->props.trailer_len;
- }
-
- xfrm_init_pmtu(dst);
return 0;
-
-error:
- if (dst)
- dst_free(dst);
- return err;
}
static void
@@ -330,8 +247,9 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
.dst_lookup = xfrm4_dst_lookup,
.get_saddr = xfrm4_get_saddr,
.find_bundle = __xfrm4_find_bundle,
- .bundle_create = __xfrm4_bundle_create,
.decode_session = _decode_session4,
+ .get_tos = xfrm4_get_tos,
+ .fill_dst = xfrm4_fill_dst,
};
static void __init xfrm4_policy_init(void)
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 864258f..50a3841 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -93,126 +93,34 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
return dst;
}
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
-
-static int
-__xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
- struct flowi *fl, struct dst_entry **dst_p)
+static int xfrm6_get_tos(struct flowi *fl)
{
- struct dst_entry *dst, *dst_prev;
- struct rt6_info *rt0 = (struct rt6_info*)(*dst_p);
- struct rt6_info *rt = rt0;
- int i;
- int err;
- int header_len = 0;
- int trailer_len = 0;
-
- dst = dst_prev = NULL;
- dst_hold(&rt->u.dst);
-
- for (i = 0; i < nx; i++) {
- struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
- struct xfrm_dst *xdst;
-
- if (unlikely(dst1 == NULL)) {
- err = -ENOBUFS;
- dst_release(&rt->u.dst);
- goto error;
- }
-
- if (!dst)
- dst = dst1;
- else {
- dst_prev->child = dst1;
- dst1->flags |= DST_NOHASH;
- dst_clone(dst1);
- }
-
- xdst = (struct xfrm_dst *)dst1;
- xdst->route = &rt->u.dst;
- xdst->genid = xfrm[i]->genid;
- if (rt->rt6i_node)
- xdst->route_cookie = rt->rt6i_node->fn_sernum;
-
- dst1->next = dst_prev;
- dst_prev = dst1;
-
- if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT)
- ((struct rt6_info *)dst)->nfheader_len +=
- xfrm[i]->props.header_len;
- header_len += xfrm[i]->props.header_len;
- trailer_len += xfrm[i]->props.trailer_len;
-
- if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
- dst1 = xfrm_dst_lookup(xfrm[i], 0);
- err = PTR_ERR(dst1);
- if (IS_ERR(dst1))
- goto error;
-
- rt = (struct rt6_info *)dst1;
- } else
- dst_hold(&rt->u.dst);
- }
+ return 0;
+}
- dst_prev->child = &rt->u.dst;
- dst->path = &rt->u.dst;
-
- /* Copy neighbour for reachability confirmation */
- dst->neighbour = neigh_clone(rt->u.dst.neighbour);
-
- if (rt->rt6i_node)
- ((struct xfrm_dst *)dst)->path_cookie = rt->rt6i_node->fn_sernum;
-
- *dst_p = dst;
- dst = dst_prev;
-
- dst_prev = *dst_p;
- i = 0;
- err = -ENODEV;
- for (; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
- struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
-
- dst_prev->xfrm = xfrm[i++];
- dst_prev->dev = rt->u.dst.dev;
- if (!rt->u.dst.dev)
- goto error;
- dev_hold(rt->u.dst.dev);
-
- x->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
- if (!x->u.rt6.rt6i_idev)
- goto error;
-
- dst_prev->obsolete = -1;
- dst_prev->flags |= DST_HOST;
- dst_prev->lastuse = jiffies;
- dst_prev->header_len = header_len;
- dst_prev->trailer_len = trailer_len;
- memcpy(&dst_prev->metrics, &x->route->metrics, sizeof(dst_prev->metrics));
-
- dst_prev->input = dst_discard;
- dst_prev->output = dst_prev->xfrm->outer_mode->afinfo->output;
- /* Sheit... I remember I did this right. Apparently,
- * it was magically lost, so this code needs audit */
- x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
- x->u.rt6.rt6i_metric = rt0->rt6i_metric;
- x->u.rt6.rt6i_node = rt0->rt6i_node;
- x->u.rt6.rt6i_gateway = rt0->rt6i_gateway;
- memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway));
- x->u.rt6.rt6i_dst = rt0->rt6i_dst;
- x->u.rt6.rt6i_src = rt0->rt6i_src;
- header_len -= x->u.dst.xfrm->props.header_len;
- trailer_len -= x->u.dst.xfrm->props.trailer_len;
- }
+static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+ struct rt6_info *rt = (struct rt6_info*)xdst->route;
+
+ xdst->u.dst.dev = dev;
+ dev_hold(dev);
+
+ xdst->u.rt6.rt6i_idev = in6_dev_get(rt->u.dst.dev);
+ if (!xdst->u.rt6.rt6i_idev)
+ return -ENODEV;
+
+ /* Sheit... I remember I did this right. Apparently,
+ * it was magically lost, so this code needs audit */
+ xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTCF_BROADCAST |
+ RTCF_MULTICAST |
+ RTCF_LOCAL);
+ xdst->u.rt6.rt6i_metric = rt->rt6i_metric;
+ xdst->u.rt6.rt6i_node = rt->rt6i_node;
+ xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
+ xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
+ xdst->u.rt6.rt6i_src = rt->rt6i_src;
- xfrm_init_pmtu(dst);
return 0;
-
-error:
- if (dst)
- dst_free(dst);
- return err;
}
static inline void
@@ -355,8 +263,9 @@ static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
.dst_lookup = xfrm6_dst_lookup,
.get_saddr = xfrm6_get_saddr,
.find_bundle = __xfrm6_find_bundle,
- .bundle_create = __xfrm6_bundle_create,
.decode_session = _decode_session6,
+ .get_tos = xfrm6_get_tos,
+ .fill_dst = xfrm6_fill_dst,
};
static void __init xfrm6_policy_init(void)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 6168341..5a03612 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -24,6 +24,7 @@
#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/cache.h>
+#include <net/dst.h>
#include <net/xfrm.h>
#include <net/ip.h>
@@ -50,6 +51,7 @@ static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
+static void xfrm_init_pmtu(struct dst_entry *dst);
static inline int
__xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl)
@@ -85,7 +87,8 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
return 0;
}
-struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
+static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
+ int family)
{
xfrm_address_t *saddr = &x->props.saddr;
xfrm_address_t *daddr = &x->id.daddr;
@@ -97,7 +100,7 @@ struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
if (x->type->flags & XFRM_TYPE_REMOTE_COADDR)
daddr = x->coaddr;
- afinfo = xfrm_policy_get_afinfo(x->props.family);
+ afinfo = xfrm_policy_get_afinfo(family);
if (unlikely(afinfo == NULL))
return ERR_PTR(-EAFNOSUPPORT);
@@ -105,7 +108,6 @@ struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos)
xfrm_policy_put_afinfo(afinfo);
return dst;
}
-EXPORT_SYMBOL(xfrm_dst_lookup);
static inline unsigned long make_jiffies(long secs)
{
@@ -1235,24 +1237,164 @@ xfrm_find_bundle(struct flowi *fl, struct xfrm_policy *policy, unsigned short fa
return x;
}
-/* Allocate chain of dst_entry's, attach known xfrm's, calculate
- * all the metrics... Shortly, bundle a bundle.
- */
+static inline int xfrm_get_tos(struct flowi *fl, int family)
+{
+ struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
+ int tos;
-static int
-xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
- struct flowi *fl, struct dst_entry **dst_p,
- unsigned short family)
+ if (!afinfo)
+ return -EINVAL;
+
+ tos = afinfo->get_tos(fl);
+
+ xfrm_policy_put_afinfo(afinfo);
+
+ return tos;
+}
+
+static inline struct xfrm_dst *xfrm_alloc_dst(int family)
{
- int err;
struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
- if (unlikely(afinfo == NULL))
+ struct xfrm_dst *xdst;
+
+ if (!afinfo)
+ return ERR_PTR(-EINVAL);
+
+ xdst = dst_alloc(afinfo->dst_ops) ?: ERR_PTR(-ENOBUFS);
+
+ xfrm_policy_put_afinfo(afinfo);
+
+ return xdst;
+}
+
+static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev)
+{
+ struct xfrm_policy_afinfo *afinfo =
+ xfrm_policy_get_afinfo(xdst->u.dst.ops->family);
+ int err;
+
+ if (!afinfo)
return -EINVAL;
- err = afinfo->bundle_create(policy, xfrm, nx, fl, dst_p);
+
+ err = afinfo->fill_dst(xdst, dev);
+
xfrm_policy_put_afinfo(afinfo);
+
return err;
}
+/* Allocate chain of dst_entry's, attach known xfrm's, calculate
+ * all the metrics... Shortly, bundle a bundle.
+ */
+
+static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
+ struct xfrm_state **xfrm, int nx,
+ struct flowi *fl,
+ struct dst_entry *dst)
+{
+ unsigned long now = jiffies;
+ struct net_device *dev;
+ struct dst_entry *dst_prev = NULL;
+ struct dst_entry *dst0 = NULL;
+ int i = 0;
+ int err;
+ int header_len = 0;
+ int trailer_len = 0;
+ int tos;
+ int family = policy->selector.family;
+
+ tos = xfrm_get_tos(fl, family);
+ err = tos;
+ if (tos < 0)
+ goto put_states;
+
+ dst_hold(dst);
+
+ for (; i < nx; i++) {
+ struct xfrm_dst *xdst = xfrm_alloc_dst(family);
+ struct dst_entry *dst1 = &xdst->u.dst;
+
+ err = PTR_ERR(xdst);
+ if (IS_ERR(xdst)) {
+ dst_release(dst);
+ goto put_states;
+ }
+
+ if (!dst_prev)
+ dst0 = dst1;
+ else {
+ dst_prev->child = dst_clone(dst1);
+ dst1->flags |= DST_NOHASH;
+ }
+
+ xdst->route = dst;
+ memcpy(&dst1->metrics, &dst->metrics, sizeof(dst->metrics));
+
+ if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
+ family = xfrm[i]->props.family;
+ dst = xfrm_dst_lookup(xfrm[i], tos, family);
+ err = PTR_ERR(dst);
+ if (IS_ERR(dst))
+ goto put_states;
+ } else
+ dst_hold(dst);
+
+ dst1->xfrm = xfrm[i];
+ xdst->genid = xfrm[i]->genid;
+
+ dst1->obsolete = -1;
+ dst1->flags |= DST_HOST;
+ dst1->lastuse = now;
+
+ dst1->input = dst_discard;
+ dst1->output = xfrm[i]->outer_mode->afinfo->output;
+
+ dst1->next = dst_prev;
+ dst_prev = dst1;
+
+ header_len += xfrm[i]->props.header_len;
+ trailer_len += xfrm[i]->props.trailer_len;
+ }
+
+ dst_prev->child = dst;
+ dst0->path = dst;
+
+ err = -ENODEV;
+ dev = dst->dev;
+ if (!dev)
+ goto free_dst;
+
+ /* Copy neighbout for reachability confirmation */
+ dst0->neighbour = neigh_clone(dst->neighbour);
+
+ xfrm_init_pmtu(dst_prev);
+
+ for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) {
+ struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev;
+
+ err = xfrm_fill_dst(xdst, dev);
+ if (err)
+ goto free_dst;
+
+ dst_prev->header_len = header_len;
+ dst_prev->trailer_len = trailer_len;
+ header_len -= xdst->u.dst.xfrm->props.header_len;
+ trailer_len -= xdst->u.dst.xfrm->props.trailer_len;
+ }
+
+out:
+ return dst0;
+
+put_states:
+ for (; i < nx; i++)
+ xfrm_state_put(xfrm[i]);
+free_dst:
+ if (dst0)
+ dst_free(dst0);
+ dst0 = ERR_PTR(err);
+ goto out;
+}
+
static int inline
xfrm_dst_alloc_copy(void **target, void *src, int size)
{
@@ -1452,15 +1594,10 @@ restart:
return 0;
}
- dst = dst_orig;
- err = xfrm_bundle_create(policy, xfrm, nx, fl, &dst, family);
-
- if (unlikely(err)) {
- int i;
- for (i=0; i<nx; i++)
- xfrm_state_put(xfrm[i]);
+ dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig);
+ err = PTR_ERR(dst);
+ if (IS_ERR(dst))
goto error;
- }
for (pi = 0; pi < npols; pi++) {
read_lock_bh(&pols[pi]->lock);
@@ -1883,7 +2020,7 @@ static int xfrm_flush_bundles(void)
return 0;
}
-void xfrm_init_pmtu(struct dst_entry *dst)
+static void xfrm_init_pmtu(struct dst_entry *dst)
{
do {
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
@@ -1904,8 +2041,6 @@ void xfrm_init_pmtu(struct dst_entry *dst)
} while ((dst = dst->next));
}
-EXPORT_SYMBOL(xfrm_init_pmtu);
-
/* Check that the bundle accepts the flow and its components are
* still valid.
*/
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [0/11] Merge bundle creation and other misc fixes/clean-ups
2007-10-23 16:02 [0/11] Merge bundle creation and other misc fixes/clean-ups Herbert Xu
` (10 preceding siblings ...)
2007-10-23 16:03 ` [PATCH 11/11] [IPSEC]: Merge common code into xfrm_bundle_create Herbert Xu
@ 2007-10-30 5:06 ` David Miller
2007-10-30 5:49 ` Herbert Xu
11 siblings, 1 reply; 14+ messages in thread
From: David Miller @ 2007-10-30 5:06 UTC (permalink / raw)
To: herbert; +Cc: yoshfuji, netdev
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Wed, 24 Oct 2007 00:02:17 +0800
> This series of patches fixes the bug where the bundle creation
> code treats IPv6 routes as IPv4 or vice versa.
>
> I think this is suitable for 2.6.25.
>
> They do fix bugs but I don't think any of them are serious enough
> for inclusion in 2.6.24.
I did a review of these patches and these look fine.
Please resubmit this and the 3-patch input interfamily
fix set when I open up the net-2.6.25 tree.
I'll probably open up net-2.6.25 approximately one week
from now.
^ permalink raw reply [flat|nested] 14+ messages in thread