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 ...@@ -511,6 +511,7 @@ struct xfrm_dst
struct rtable rt; struct rtable rt;
struct rt6_info rt6; struct rt6_info rt6;
} u; } u;
struct dst_entry *route;
}; };
/* Decapsulation state, used by the input to store data during /* 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 ...@@ -55,18 +55,29 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct rtable *rt = rt0; struct rtable *rt = rt0;
u32 remote = fl->fl4_dst; u32 remote = fl->fl4_dst;
u32 local = fl->fl4_src; u32 local = fl->fl4_src;
struct flowi fl_tunnel = {
.nl_u = {
.ip4_u = {
.saddr = local,
.daddr = remote
}
}
};
int i; int i;
int err; int err;
int header_len = 0; int header_len = 0;
int trailer_len = 0; int trailer_len = 0;
dst = dst_prev = NULL; dst = dst_prev = NULL;
dst_hold(&rt->u.dst);
for (i = 0; i < nx; i++) { for (i = 0; i < nx; i++) {
struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops); struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
struct xfrm_dst *xdst;
if (unlikely(dst1 == NULL)) { if (unlikely(dst1 == NULL)) {
err = -ENOBUFS; err = -ENOBUFS;
dst_release(&rt->u.dst);
goto error; goto error;
} }
...@@ -77,6 +88,11 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int ...@@ -77,6 +88,11 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->flags |= DST_NOHASH; dst1->flags |= DST_NOHASH;
dst_clone(dst1); dst_clone(dst1);
} }
xdst = (struct xfrm_dst *)dst1;
xdst->route = &rt->u.dst;
dst1->next = dst_prev;
dst_prev = dst1; dst_prev = dst1;
if (xfrm[i]->props.mode) { if (xfrm[i]->props.mode) {
remote = xfrm[i]->id.daddr.a4; remote = xfrm[i]->id.daddr.a4;
...@@ -84,23 +100,27 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int ...@@ -84,23 +100,27 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
} }
header_len += xfrm[i]->props.header_len; header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len; trailer_len += xfrm[i]->props.trailer_len;
}
if (remote != fl->fl4_dst) { if (remote != fl_tunnel.fl4_dst) {
struct flowi fl_tunnel = { .nl_u = { .ip4_u = fl_tunnel.fl4_src = local;
{ .daddr = remote, fl_tunnel.fl4_dst = remote;
.saddr = local } err = xfrm_dst_lookup((struct xfrm_dst **)&rt,
} &fl_tunnel, AF_INET);
}; if (err)
err = xfrm_dst_lookup((struct xfrm_dst**)&rt, &fl_tunnel, AF_INET); goto error;
if (err) } else
goto error; dst_hold(&rt->u.dst);
} else {
dst_hold(&rt->u.dst);
} }
dst_prev->child = &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; 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; struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
x->u.rt.fl = *fl; x->u.rt.fl = *fl;
...@@ -114,7 +134,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int ...@@ -114,7 +134,6 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->header_len = header_len; dst_prev->header_len = header_len;
dst_prev->trailer_len = trailer_len; dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics)); memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
dst_prev->path = &rt->u.dst;
/* Copy neighbout for reachability confirmation */ /* Copy neighbout for reachability confirmation */
dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); 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 ...@@ -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; header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len; trailer_len -= x->u.dst.xfrm->props.trailer_len;
} }
*dst_p = dst;
return 0; return 0;
error: error:
......
...@@ -72,18 +72,29 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int ...@@ -72,18 +72,29 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
struct rt6_info *rt = rt0; struct rt6_info *rt = rt0;
struct in6_addr *remote = &fl->fl6_dst; struct in6_addr *remote = &fl->fl6_dst;
struct in6_addr *local = &fl->fl6_src; struct in6_addr *local = &fl->fl6_src;
struct flowi fl_tunnel = {
.nl_u = {
.ip6_u = {
.saddr = *local,
.daddr = *remote
}
}
};
int i; int i;
int err = 0; int err = 0;
int header_len = 0; int header_len = 0;
int trailer_len = 0; int trailer_len = 0;
dst = dst_prev = NULL; dst = dst_prev = NULL;
dst_hold(&rt->u.dst);
for (i = 0; i < nx; i++) { for (i = 0; i < nx; i++) {
struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops); struct dst_entry *dst1 = dst_alloc(&xfrm6_dst_ops);
struct xfrm_dst *xdst;
if (unlikely(dst1 == NULL)) { if (unlikely(dst1 == NULL)) {
err = -ENOBUFS; err = -ENOBUFS;
dst_release(&rt->u.dst);
goto error; goto error;
} }
...@@ -94,6 +105,11 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int ...@@ -94,6 +105,11 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst1->flags |= DST_NOHASH; dst1->flags |= DST_NOHASH;
dst_clone(dst1); dst_clone(dst1);
} }
xdst = (struct xfrm_dst *)dst1;
xdst->route = &rt->u.dst;
dst1->next = dst_prev;
dst_prev = dst1; dst_prev = dst1;
if (xfrm[i]->props.mode) { if (xfrm[i]->props.mode) {
remote = (struct in6_addr*)&xfrm[i]->id.daddr; remote = (struct in6_addr*)&xfrm[i]->id.daddr;
...@@ -101,25 +117,27 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int ...@@ -101,25 +117,27 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
} }
header_len += xfrm[i]->props.header_len; header_len += xfrm[i]->props.header_len;
trailer_len += xfrm[i]->props.trailer_len; trailer_len += xfrm[i]->props.trailer_len;
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
dst_hold(&rt->u.dst);
} }
if (!ipv6_addr_equal(remote, &fl->fl6_dst)) { dst_prev->child = &rt->u.dst;
struct flowi fl_tunnel; dst->path = &rt->u.dst;
memset(&fl_tunnel, 0, sizeof(fl_tunnel)); *dst_p = dst;
ipv6_addr_copy(&fl_tunnel.fl6_dst, remote); dst = dst_prev;
ipv6_addr_copy(&fl_tunnel.fl6_src, local);
err = xfrm_dst_lookup((struct xfrm_dst **) &rt, dst_prev = *dst_p;
&fl_tunnel, AF_INET6);
if (err)
goto error;
} else {
dst_hold(&rt->u.dst);
}
dst_prev->child = &rt->u.dst;
i = 0; 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; struct xfrm_dst *x = (struct xfrm_dst*)dst_prev;
dst_prev->xfrm = xfrm[i++]; dst_prev->xfrm = xfrm[i++];
...@@ -132,7 +150,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int ...@@ -132,7 +150,6 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->header_len = header_len; dst_prev->header_len = header_len;
dst_prev->trailer_len = trailer_len; dst_prev->trailer_len = trailer_len;
memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics)); memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
dst_prev->path = &rt->u.dst;
/* Copy neighbour for reachability confirmation */ /* Copy neighbour for reachability confirmation */
dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); 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 ...@@ -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; header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len; trailer_len -= x->u.dst.xfrm->props.trailer_len;
} }
*dst_p = dst;
return 0; return 0;
error: error:
......
...@@ -1026,6 +1026,11 @@ static int stale_bundle(struct dst_entry *dst) ...@@ -1026,6 +1026,11 @@ static int stale_bundle(struct dst_entry *dst)
static void xfrm_dst_destroy(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) if (!dst->xfrm)
return; return;
xfrm_state_put(dst->xfrm); 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