Commit 1ffd2743 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[IPSEC]: Add route element to xfrm_dst

This patch adds a pointer to the route corresponding to the specific
flow over the SA of an xfrm_dst that's being used.

It also sets the next pointer of each xfrm_dst to the one above it.
This allows to traverse the list upwards from the bottom.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b08e2fc8
......@@ -511,6 +511,7 @@ struct xfrm_dst
struct rtable rt;
struct rt6_info rt6;
} u;
struct dst_entry *route;
};
/* Decapsulation state, used by the input to store data during
......
......@@ -55,18 +55,29 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct rtable *rt = rt0;
u32 remote = fl->fl4_dst;
u32 local = fl->fl4_src;
struct flowi fl_tunnel = {
.nl_u = {
.ip4_u = {
.saddr = local,
.daddr = remote
}
}
};
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;
}
......@@ -77,6 +88,11 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->flags |= DST_NOHASH;
dst_clone(dst1);
}
xdst = (struct xfrm_dst *)dst1;
xdst->route = &rt->u.dst;
dst1->next = dst_prev;
dst_prev = dst1;
if (xfrm[i]->props.mode) {
remote = xfrm[i]->id.daddr.a4;
......@@ -84,23 +100,27 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
}
header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
}
if (remote != fl->fl4_dst) {
struct flowi fl_tunnel = { .nl_u = { .ip4_u =
{ .daddr = remote,
.saddr = local }
}
};
err = xfrm_dst_lookup((struct xfrm_dst**)&rt, &fl_tunnel, AF_INET);
if (remote != fl_tunnel.fl4_dst) {
fl_tunnel.fl4_src = local;
fl_tunnel.fl4_dst = remote;
err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
&fl_tunnel, AF_INET);
if (err)
goto error;
} else {
} else
dst_hold(&rt->u.dst);
}
dst_prev->child = &rt->u.dst;
dst->path = &rt->u.dst;
*dst_p = dst;
dst = dst_prev;
dst_prev = *dst_p;
i = 0;
for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
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;
......@@ -114,7 +134,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->header_len = header_len;
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
dst_prev->path = &rt->u.dst;
/* Copy neighbout for reachability confirmation */
dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);
......@@ -134,7 +153,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
*dst_p = dst;
return 0;
error:
......
......@@ -72,18 +72,29 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct rt6_info *rt = rt0;
struct in6_addr *remote = &fl->fl6_dst;
struct in6_addr *local = &fl->fl6_src;
struct flowi fl_tunnel = {
.nl_u = {
.ip6_u = {
.saddr = *local,
.daddr = *remote
}
}
};
int i;
int err = 0;
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;
}
......@@ -94,6 +105,11 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->flags |= DST_NOHASH;
dst_clone(dst1);
}
xdst = (struct xfrm_dst *)dst1;
xdst->route = &rt->u.dst;
dst1->next = dst_prev;
dst_prev = dst1;
if (xfrm[i]->props.mode) {
remote = (struct in6_addr*)&xfrm[i]->id.daddr;
......@@ -101,25 +117,27 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
}
header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len;
}
if (!ipv6_addr_equal(remote, &fl->fl6_dst)) {
struct flowi fl_tunnel;
memset(&fl_tunnel, 0, sizeof(fl_tunnel));
if (!ipv6_addr_equal(remote, &fl_tunnel.fl6_dst)) {
ipv6_addr_copy(&fl_tunnel.fl6_dst, remote);
ipv6_addr_copy(&fl_tunnel.fl6_src, local);
err = xfrm_dst_lookup((struct xfrm_dst **) &rt,
&fl_tunnel, AF_INET6);
if (err)
goto error;
} else {
} else
dst_hold(&rt->u.dst);
}
dst_prev->child = &rt->u.dst;
dst->path = &rt->u.dst;
*dst_p = dst;
dst = dst_prev;
dst_prev = *dst_p;
i = 0;
for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
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++];
......@@ -132,7 +150,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->header_len = header_len;
dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
dst_prev->path = &rt->u.dst;
/* Copy neighbour for reachability confirmation */
dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour);
......@@ -150,7 +167,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
*dst_p = dst;
return 0;
error:
......
......@@ -1026,6 +1026,11 @@ static int stale_bundle(struct dst_entry *dst)
static void xfrm_dst_destroy(struct dst_entry *dst)
{
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
if (xdst->route)
dst_release(xdst->route);
if (!dst->xfrm)
return;
xfrm_state_put(dst->xfrm);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment