Commit 5492093d authored by David Miller's avatar David Miller Committed by David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
parent 8b207e73
...@@ -54,7 +54,7 @@ static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1] ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
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