xfrm: Stop using dst->next in bundle construction.
While building ipsec bundles, blocks of xfrm dsts are linked together using dst->next from bottom to the top. The only thing this is used for is initializing the pmtu values of the xfrm stack, and for updating the mtu values at xfrm_bundle_ok() time. The bundle pmtu entries must be processed in this order so that pmtu values lower in the stack of routes can propagate up to the higher ones. Avoid using dst->next by simply maintaining an array of dst pointers as we already do for the xfrm_state objects when building the bundle. Signed-off-by: David S. Miller <davem@davemloft.net> Reviewed-by: Eric Dumazet <edumazet@google.com>
This commit is contained in:
parent
8b207e7374
commit
5492093dc4
|
@ -54,7 +54,7 @@ static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1]
|
||||||
static struct kmem_cache *xfrm_dst_cache __read_mostly;
|
static struct kmem_cache *xfrm_dst_cache __read_mostly;
|
||||||
static __read_mostly seqcount_t xfrm_policy_hash_generation;
|
static __read_mostly seqcount_t xfrm_policy_hash_generation;
|
||||||
|
|
||||||
static void xfrm_init_pmtu(struct dst_entry *dst);
|
static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr);
|
||||||
static int stale_bundle(struct dst_entry *dst);
|
static int stale_bundle(struct dst_entry *dst);
|
||||||
static int xfrm_bundle_ok(struct xfrm_dst *xdst);
|
static int xfrm_bundle_ok(struct xfrm_dst *xdst);
|
||||||
static void xfrm_policy_queue_process(struct timer_list *t);
|
static void xfrm_policy_queue_process(struct timer_list *t);
|
||||||
|
@ -1538,7 +1538,9 @@ static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
||||||
struct xfrm_state **xfrm, int nx,
|
struct xfrm_state **xfrm,
|
||||||
|
struct xfrm_dst **bundle,
|
||||||
|
int nx,
|
||||||
const struct flowi *fl,
|
const struct flowi *fl,
|
||||||
struct dst_entry *dst)
|
struct dst_entry *dst)
|
||||||
{
|
{
|
||||||
|
@ -1573,6 +1575,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
||||||
goto put_states;
|
goto put_states;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bundle[i] = xdst;
|
||||||
if (!xdst_prev)
|
if (!xdst_prev)
|
||||||
xdst0 = xdst;
|
xdst0 = xdst;
|
||||||
else
|
else
|
||||||
|
@ -1616,7 +1619,6 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
||||||
dst1->input = dst_discard;
|
dst1->input = dst_discard;
|
||||||
dst1->output = inner_mode->afinfo->output;
|
dst1->output = inner_mode->afinfo->output;
|
||||||
|
|
||||||
dst1->next = &xdst_prev->u.dst;
|
|
||||||
xdst_prev = xdst;
|
xdst_prev = xdst;
|
||||||
|
|
||||||
header_len += xfrm[i]->props.header_len;
|
header_len += xfrm[i]->props.header_len;
|
||||||
|
@ -1634,7 +1636,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
||||||
goto free_dst;
|
goto free_dst;
|
||||||
|
|
||||||
xfrm_init_path(xdst0, dst, nfheader_len);
|
xfrm_init_path(xdst0, dst, nfheader_len);
|
||||||
xfrm_init_pmtu(&xdst_prev->u.dst);
|
xfrm_init_pmtu(bundle, nx);
|
||||||
|
|
||||||
for (xdst_prev = xdst0; xdst_prev != (struct xfrm_dst *)dst;
|
for (xdst_prev = xdst0; xdst_prev != (struct xfrm_dst *)dst;
|
||||||
xdst_prev = (struct xfrm_dst *) xfrm_dst_child(&xdst_prev->u.dst)) {
|
xdst_prev = (struct xfrm_dst *) xfrm_dst_child(&xdst_prev->u.dst)) {
|
||||||
|
@ -1812,6 +1814,7 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
|
||||||
{
|
{
|
||||||
struct net *net = xp_net(pols[0]);
|
struct net *net = xp_net(pols[0]);
|
||||||
struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
|
struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
|
||||||
|
struct xfrm_dst *bundle[XFRM_MAX_DEPTH];
|
||||||
struct xfrm_dst *xdst, *old;
|
struct xfrm_dst *xdst, *old;
|
||||||
struct dst_entry *dst;
|
struct dst_entry *dst;
|
||||||
int err;
|
int err;
|
||||||
|
@ -1839,7 +1842,7 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols,
|
||||||
|
|
||||||
old = xdst;
|
old = xdst;
|
||||||
|
|
||||||
dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig);
|
dst = xfrm_bundle_create(pols[0], xfrm, bundle, err, fl, dst_orig);
|
||||||
if (IS_ERR(dst)) {
|
if (IS_ERR(dst)) {
|
||||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
|
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR);
|
||||||
return ERR_CAST(dst);
|
return ERR_CAST(dst);
|
||||||
|
@ -2599,12 +2602,14 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xfrm_init_pmtu(struct dst_entry *dst)
|
static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr)
|
||||||
{
|
{
|
||||||
do {
|
while (nr--) {
|
||||||
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
|
struct xfrm_dst *xdst = bundle[nr];
|
||||||
u32 pmtu, route_mtu_cached;
|
u32 pmtu, route_mtu_cached;
|
||||||
|
struct dst_entry *dst;
|
||||||
|
|
||||||
|
dst = &xdst->u.dst;
|
||||||
pmtu = dst_mtu(xfrm_dst_child(dst));
|
pmtu = dst_mtu(xfrm_dst_child(dst));
|
||||||
xdst->child_mtu_cached = pmtu;
|
xdst->child_mtu_cached = pmtu;
|
||||||
|
|
||||||
|
@ -2617,7 +2622,7 @@ static void xfrm_init_pmtu(struct dst_entry *dst)
|
||||||
pmtu = route_mtu_cached;
|
pmtu = route_mtu_cached;
|
||||||
|
|
||||||
dst_metric_set(dst, RTAX_MTU, pmtu);
|
dst_metric_set(dst, RTAX_MTU, pmtu);
|
||||||
} while ((dst = dst->next));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the bundle accepts the flow and its components are
|
/* Check that the bundle accepts the flow and its components are
|
||||||
|
@ -2626,8 +2631,10 @@ static void xfrm_init_pmtu(struct dst_entry *dst)
|
||||||
|
|
||||||
static int xfrm_bundle_ok(struct xfrm_dst *first)
|
static int xfrm_bundle_ok(struct xfrm_dst *first)
|
||||||
{
|
{
|
||||||
|
struct xfrm_dst *bundle[XFRM_MAX_DEPTH];
|
||||||
struct dst_entry *dst = &first->u.dst;
|
struct dst_entry *dst = &first->u.dst;
|
||||||
struct xfrm_dst *last;
|
struct xfrm_dst *xdst;
|
||||||
|
int start_from, nr;
|
||||||
u32 mtu;
|
u32 mtu;
|
||||||
|
|
||||||
if (!dst_check(xfrm_dst_path(dst), ((struct xfrm_dst *)dst)->path_cookie) ||
|
if (!dst_check(xfrm_dst_path(dst), ((struct xfrm_dst *)dst)->path_cookie) ||
|
||||||
|
@ -2637,8 +2644,7 @@ static int xfrm_bundle_ok(struct xfrm_dst *first)
|
||||||
if (dst->flags & DST_XFRM_QUEUE)
|
if (dst->flags & DST_XFRM_QUEUE)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
last = NULL;
|
start_from = nr = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
|
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
|
||||||
|
|
||||||
|
@ -2650,9 +2656,11 @@ static int xfrm_bundle_ok(struct xfrm_dst *first)
|
||||||
xdst->policy_genid != atomic_read(&xdst->pols[0]->genid))
|
xdst->policy_genid != atomic_read(&xdst->pols[0]->genid))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
bundle[nr++] = xdst;
|
||||||
|
|
||||||
mtu = dst_mtu(xfrm_dst_child(dst));
|
mtu = dst_mtu(xfrm_dst_child(dst));
|
||||||
if (xdst->child_mtu_cached != mtu) {
|
if (xdst->child_mtu_cached != mtu) {
|
||||||
last = xdst;
|
start_from = nr;
|
||||||
xdst->child_mtu_cached = mtu;
|
xdst->child_mtu_cached = mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2660,30 +2668,30 @@ static int xfrm_bundle_ok(struct xfrm_dst *first)
|
||||||
return 0;
|
return 0;
|
||||||
mtu = dst_mtu(xdst->route);
|
mtu = dst_mtu(xdst->route);
|
||||||
if (xdst->route_mtu_cached != mtu) {
|
if (xdst->route_mtu_cached != mtu) {
|
||||||
last = xdst;
|
start_from = nr;
|
||||||
xdst->route_mtu_cached = mtu;
|
xdst->route_mtu_cached = mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
dst = xfrm_dst_child(dst);
|
dst = xfrm_dst_child(dst);
|
||||||
} while (dst->xfrm);
|
} while (dst->xfrm);
|
||||||
|
|
||||||
if (likely(!last))
|
if (likely(!start_from))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
mtu = last->child_mtu_cached;
|
xdst = bundle[start_from - 1];
|
||||||
for (;;) {
|
mtu = xdst->child_mtu_cached;
|
||||||
dst = &last->u.dst;
|
while (start_from--) {
|
||||||
|
dst = &xdst->u.dst;
|
||||||
|
|
||||||
mtu = xfrm_state_mtu(dst->xfrm, mtu);
|
mtu = xfrm_state_mtu(dst->xfrm, mtu);
|
||||||
if (mtu > last->route_mtu_cached)
|
if (mtu > xdst->route_mtu_cached)
|
||||||
mtu = last->route_mtu_cached;
|
mtu = xdst->route_mtu_cached;
|
||||||
dst_metric_set(dst, RTAX_MTU, mtu);
|
dst_metric_set(dst, RTAX_MTU, mtu);
|
||||||
|
if (!start_from)
|
||||||
if (last == first)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
last = (struct xfrm_dst *)last->u.dst.next;
|
xdst = bundle[start_from - 1];
|
||||||
last->child_mtu_cached = mtu;
|
xdst->child_mtu_cached = mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
Loading…
Reference in New Issue