diff options
author | David Miller <davem@davemloft.net> | 2017-11-28 15:41:01 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-11-30 09:54:27 -0500 |
commit | 5492093dc4160d150890bc848c26ba7f8fff3094 (patch) | |
tree | dc760d6803315b9f62e0b90572c7cb47988b6f56 | |
parent | 8b207e7374c244484d6cb0f0e80ae400ce0ec0cf (diff) |
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>
-rw-r--r-- | net/xfrm/xfrm_policy.c | 56 |
1 files changed, 32 insertions, 24 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index da1b41ee4686..22e3350013b4 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -54,7 +54,7 @@ static struct xfrm_policy_afinfo const __rcu *xfrm_policy_afinfo[AF_INET6 + 1] | |||
54 | static struct kmem_cache *xfrm_dst_cache __read_mostly; | 54 | static struct kmem_cache *xfrm_dst_cache __read_mostly; |
55 | static __read_mostly seqcount_t xfrm_policy_hash_generation; | 55 | static __read_mostly seqcount_t xfrm_policy_hash_generation; |
56 | 56 | ||
57 | static void xfrm_init_pmtu(struct dst_entry *dst); | 57 | static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr); |
58 | static int stale_bundle(struct dst_entry *dst); | 58 | static int stale_bundle(struct dst_entry *dst); |
59 | static int xfrm_bundle_ok(struct xfrm_dst *xdst); | 59 | static int xfrm_bundle_ok(struct xfrm_dst *xdst); |
60 | static void xfrm_policy_queue_process(struct timer_list *t); | 60 | 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 | */ | 1538 | */ |
1539 | 1539 | ||
1540 | static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | 1540 | static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, |
1541 | struct xfrm_state **xfrm, int nx, | 1541 | struct xfrm_state **xfrm, |
1542 | struct xfrm_dst **bundle, | ||
1543 | int nx, | ||
1542 | const struct flowi *fl, | 1544 | const struct flowi *fl, |
1543 | struct dst_entry *dst) | 1545 | struct dst_entry *dst) |
1544 | { | 1546 | { |
@@ -1573,6 +1575,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1573 | goto put_states; | 1575 | goto put_states; |
1574 | } | 1576 | } |
1575 | 1577 | ||
1578 | bundle[i] = xdst; | ||
1576 | if (!xdst_prev) | 1579 | if (!xdst_prev) |
1577 | xdst0 = xdst; | 1580 | xdst0 = xdst; |
1578 | else | 1581 | else |
@@ -1616,7 +1619,6 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1616 | dst1->input = dst_discard; | 1619 | dst1->input = dst_discard; |
1617 | dst1->output = inner_mode->afinfo->output; | 1620 | dst1->output = inner_mode->afinfo->output; |
1618 | 1621 | ||
1619 | dst1->next = &xdst_prev->u.dst; | ||
1620 | xdst_prev = xdst; | 1622 | xdst_prev = xdst; |
1621 | 1623 | ||
1622 | header_len += xfrm[i]->props.header_len; | 1624 | header_len += xfrm[i]->props.header_len; |
@@ -1634,7 +1636,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1634 | goto free_dst; | 1636 | goto free_dst; |
1635 | 1637 | ||
1636 | xfrm_init_path(xdst0, dst, nfheader_len); | 1638 | xfrm_init_path(xdst0, dst, nfheader_len); |
1637 | xfrm_init_pmtu(&xdst_prev->u.dst); | 1639 | xfrm_init_pmtu(bundle, nx); |
1638 | 1640 | ||
1639 | for (xdst_prev = xdst0; xdst_prev != (struct xfrm_dst *)dst; | 1641 | for (xdst_prev = xdst0; xdst_prev != (struct xfrm_dst *)dst; |
1640 | xdst_prev = (struct xfrm_dst *) xfrm_dst_child(&xdst_prev->u.dst)) { | 1642 | 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 | { | 1814 | { |
1813 | struct net *net = xp_net(pols[0]); | 1815 | struct net *net = xp_net(pols[0]); |
1814 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; | 1816 | struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; |
1817 | struct xfrm_dst *bundle[XFRM_MAX_DEPTH]; | ||
1815 | struct xfrm_dst *xdst, *old; | 1818 | struct xfrm_dst *xdst, *old; |
1816 | struct dst_entry *dst; | 1819 | struct dst_entry *dst; |
1817 | int err; | 1820 | int err; |
@@ -1839,7 +1842,7 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, | |||
1839 | 1842 | ||
1840 | old = xdst; | 1843 | old = xdst; |
1841 | 1844 | ||
1842 | dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig); | 1845 | dst = xfrm_bundle_create(pols[0], xfrm, bundle, err, fl, dst_orig); |
1843 | if (IS_ERR(dst)) { | 1846 | if (IS_ERR(dst)) { |
1844 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR); | 1847 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR); |
1845 | return ERR_CAST(dst); | 1848 | return ERR_CAST(dst); |
@@ -2599,12 +2602,14 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) | |||
2599 | return dst; | 2602 | return dst; |
2600 | } | 2603 | } |
2601 | 2604 | ||
2602 | static void xfrm_init_pmtu(struct dst_entry *dst) | 2605 | static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr) |
2603 | { | 2606 | { |
2604 | do { | 2607 | while (nr--) { |
2605 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | 2608 | struct xfrm_dst *xdst = bundle[nr]; |
2606 | u32 pmtu, route_mtu_cached; | 2609 | u32 pmtu, route_mtu_cached; |
2610 | struct dst_entry *dst; | ||
2607 | 2611 | ||
2612 | dst = &xdst->u.dst; | ||
2608 | pmtu = dst_mtu(xfrm_dst_child(dst)); | 2613 | pmtu = dst_mtu(xfrm_dst_child(dst)); |
2609 | xdst->child_mtu_cached = pmtu; | 2614 | xdst->child_mtu_cached = pmtu; |
2610 | 2615 | ||
@@ -2617,7 +2622,7 @@ static void xfrm_init_pmtu(struct dst_entry *dst) | |||
2617 | pmtu = route_mtu_cached; | 2622 | pmtu = route_mtu_cached; |
2618 | 2623 | ||
2619 | dst_metric_set(dst, RTAX_MTU, pmtu); | 2624 | dst_metric_set(dst, RTAX_MTU, pmtu); |
2620 | } while ((dst = dst->next)); | 2625 | } |
2621 | } | 2626 | } |
2622 | 2627 | ||
2623 | /* Check that the bundle accepts the flow and its components are | 2628 | /* 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 | 2631 | ||
2627 | static int xfrm_bundle_ok(struct xfrm_dst *first) | 2632 | static int xfrm_bundle_ok(struct xfrm_dst *first) |
2628 | { | 2633 | { |
2634 | struct xfrm_dst *bundle[XFRM_MAX_DEPTH]; | ||
2629 | struct dst_entry *dst = &first->u.dst; | 2635 | struct dst_entry *dst = &first->u.dst; |
2630 | struct xfrm_dst *last; | 2636 | struct xfrm_dst *xdst; |
2637 | int start_from, nr; | ||
2631 | u32 mtu; | 2638 | u32 mtu; |
2632 | 2639 | ||
2633 | if (!dst_check(xfrm_dst_path(dst), ((struct xfrm_dst *)dst)->path_cookie) || | 2640 | 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 | if (dst->flags & DST_XFRM_QUEUE) | 2644 | if (dst->flags & DST_XFRM_QUEUE) |
2638 | return 1; | 2645 | return 1; |
2639 | 2646 | ||
2640 | last = NULL; | 2647 | start_from = nr = 0; |
2641 | |||
2642 | do { | 2648 | do { |
2643 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | 2649 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
2644 | 2650 | ||
@@ -2650,9 +2656,11 @@ static int xfrm_bundle_ok(struct xfrm_dst *first) | |||
2650 | xdst->policy_genid != atomic_read(&xdst->pols[0]->genid)) | 2656 | xdst->policy_genid != atomic_read(&xdst->pols[0]->genid)) |
2651 | return 0; | 2657 | return 0; |
2652 | 2658 | ||
2659 | bundle[nr++] = xdst; | ||
2660 | |||
2653 | mtu = dst_mtu(xfrm_dst_child(dst)); | 2661 | mtu = dst_mtu(xfrm_dst_child(dst)); |
2654 | if (xdst->child_mtu_cached != mtu) { | 2662 | if (xdst->child_mtu_cached != mtu) { |
2655 | last = xdst; | 2663 | start_from = nr; |
2656 | xdst->child_mtu_cached = mtu; | 2664 | xdst->child_mtu_cached = mtu; |
2657 | } | 2665 | } |
2658 | 2666 | ||
@@ -2660,30 +2668,30 @@ static int xfrm_bundle_ok(struct xfrm_dst *first) | |||
2660 | return 0; | 2668 | return 0; |
2661 | mtu = dst_mtu(xdst->route); | 2669 | mtu = dst_mtu(xdst->route); |
2662 | if (xdst->route_mtu_cached != mtu) { | 2670 | if (xdst->route_mtu_cached != mtu) { |
2663 | last = xdst; | 2671 | start_from = nr; |
2664 | xdst->route_mtu_cached = mtu; | 2672 | xdst->route_mtu_cached = mtu; |
2665 | } | 2673 | } |
2666 | 2674 | ||
2667 | dst = xfrm_dst_child(dst); | 2675 | dst = xfrm_dst_child(dst); |
2668 | } while (dst->xfrm); | 2676 | } while (dst->xfrm); |
2669 | 2677 | ||
2670 | if (likely(!last)) | 2678 | if (likely(!start_from)) |
2671 | return 1; | 2679 | return 1; |
2672 | 2680 | ||
2673 | mtu = last->child_mtu_cached; | 2681 | xdst = bundle[start_from - 1]; |
2674 | for (;;) { | 2682 | mtu = xdst->child_mtu_cached; |
2675 | dst = &last->u.dst; | 2683 | while (start_from--) { |
2684 | dst = &xdst->u.dst; | ||
2676 | 2685 | ||
2677 | mtu = xfrm_state_mtu(dst->xfrm, mtu); | 2686 | mtu = xfrm_state_mtu(dst->xfrm, mtu); |
2678 | if (mtu > last->route_mtu_cached) | 2687 | if (mtu > xdst->route_mtu_cached) |
2679 | mtu = last->route_mtu_cached; | 2688 | mtu = xdst->route_mtu_cached; |
2680 | dst_metric_set(dst, RTAX_MTU, mtu); | 2689 | dst_metric_set(dst, RTAX_MTU, mtu); |
2681 | 2690 | if (!start_from) | |
2682 | if (last == first) | ||
2683 | break; | 2691 | break; |
2684 | 2692 | ||
2685 | last = (struct xfrm_dst *)last->u.dst.next; | 2693 | xdst = bundle[start_from - 1]; |
2686 | last->child_mtu_cached = mtu; | 2694 | xdst->child_mtu_cached = mtu; |
2687 | } | 2695 | } |
2688 | 2696 | ||
2689 | return 1; | 2697 | return 1; |