aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Miller <davem@davemloft.net>2017-11-28 15:41:01 -0500
committerDavid S. Miller <davem@davemloft.net>2017-11-30 09:54:27 -0500
commit5492093dc4160d150890bc848c26ba7f8fff3094 (patch)
treedc760d6803315b9f62e0b90572c7cb47988b6f56
parent8b207e7374c244484d6cb0f0e80ae400ce0ec0cf (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.c56
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]
54static struct kmem_cache *xfrm_dst_cache __read_mostly; 54static struct kmem_cache *xfrm_dst_cache __read_mostly;
55static __read_mostly seqcount_t xfrm_policy_hash_generation; 55static __read_mostly seqcount_t xfrm_policy_hash_generation;
56 56
57static void xfrm_init_pmtu(struct dst_entry *dst); 57static void xfrm_init_pmtu(struct xfrm_dst **bundle, int nr);
58static int stale_bundle(struct dst_entry *dst); 58static int stale_bundle(struct dst_entry *dst);
59static int xfrm_bundle_ok(struct xfrm_dst *xdst); 59static int xfrm_bundle_ok(struct xfrm_dst *xdst);
60static void xfrm_policy_queue_process(struct timer_list *t); 60static 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
1540static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, 1540static 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
2602static void xfrm_init_pmtu(struct dst_entry *dst) 2605static 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
2627static int xfrm_bundle_ok(struct xfrm_dst *first) 2632static 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;