xfrm: Make the policy hold queue work with VTI.
authorSteffen Klassert <steffen.klassert@secunet.com>
Fri, 17 Jul 2020 08:35:32 +0000 (10:35 +0200)
committerSteffen Klassert <steffen.klassert@secunet.com>
Tue, 21 Jul 2020 06:34:44 +0000 (08:34 +0200)
We forgot to support the xfrm policy hold queue when
VTI was implemented. This patch adds everything we
need so that we can use the policy hold queue together
with VTI interfaces.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/ipv4/ip_vti.c
net/ipv6/ip6_vti.c
net/xfrm/xfrm_policy.c

index 3e5d54517145305a1acfef262351eb8ac354620c..8b962eac9ed89e0eff5238c2b0db992ea20109e4 100644 (file)
@@ -218,12 +218,15 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
        }
 
        dst_hold(dst);
-       dst = xfrm_lookup(tunnel->net, dst, fl, NULL, 0);
+       dst = xfrm_lookup_route(tunnel->net, dst, fl, NULL, 0);
        if (IS_ERR(dst)) {
                dev->stats.tx_carrier_errors++;
                goto tx_error_icmp;
        }
 
+       if (dst->flags & DST_XFRM_QUEUE)
+               goto queued;
+
        if (!vti_state_check(dst->xfrm, parms->iph.daddr, parms->iph.saddr)) {
                dev->stats.tx_carrier_errors++;
                dst_release(dst);
@@ -255,6 +258,7 @@ static netdev_tx_t vti_xmit(struct sk_buff *skb, struct net_device *dev,
                goto tx_error;
        }
 
+queued:
        skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(dev)));
        skb_dst_set(skb, dst);
        skb->dev = skb_dst(skb)->dev;
index 53f12b40528eb91b23cad69b340ead10bc7fd228..f5a4c4a6492bbd2751aaa289a0d3ba52fd6d6d73 100644 (file)
@@ -491,13 +491,16 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
        }
 
        dst_hold(dst);
-       dst = xfrm_lookup(t->net, dst, fl, NULL, 0);
+       dst = xfrm_lookup_route(t->net, dst, fl, NULL, 0);
        if (IS_ERR(dst)) {
                err = PTR_ERR(dst);
                dst = NULL;
                goto tx_err_link_failure;
        }
 
+       if (dst->flags & DST_XFRM_QUEUE)
+               goto queued;
+
        x = dst->xfrm;
        if (!vti6_state_check(x, &t->parms.raddr, &t->parms.laddr))
                goto tx_err_link_failure;
@@ -533,6 +536,7 @@ vti6_xmit(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
                goto tx_err_dst_release;
        }
 
+queued:
        skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev)));
        skb_dst_set(skb, dst);
        skb->dev = skb_dst(skb)->dev;
index 564aa6492e7c397312f51e350a84b2063c5ed616..be150475b28bbcdeb921e0dc61f863559e6c73a0 100644 (file)
@@ -2758,6 +2758,7 @@ static void xfrm_policy_queue_process(struct timer_list *t)
        struct xfrm_policy_queue *pq = &pol->polq;
        struct flowi fl;
        struct sk_buff_head list;
+       __u32 skb_mark;
 
        spin_lock(&pq->hold_queue.lock);
        skb = skb_peek(&pq->hold_queue);
@@ -2767,7 +2768,12 @@ static void xfrm_policy_queue_process(struct timer_list *t)
        }
        dst = skb_dst(skb);
        sk = skb->sk;
+
+       /* Fixup the mark to support VTI. */
+       skb_mark = skb->mark;
+       skb->mark = pol->mark.v;
        xfrm_decode_session(skb, &fl, dst->ops->family);
+       skb->mark = skb_mark;
        spin_unlock(&pq->hold_queue.lock);
 
        dst_hold(xfrm_dst_path(dst));
@@ -2799,7 +2805,12 @@ static void xfrm_policy_queue_process(struct timer_list *t)
        while (!skb_queue_empty(&list)) {
                skb = __skb_dequeue(&list);
 
+               /* Fixup the mark to support VTI. */
+               skb_mark = skb->mark;
+               skb->mark = pol->mark.v;
                xfrm_decode_session(skb, &fl, skb_dst(skb)->ops->family);
+               skb->mark = skb_mark;
+
                dst_hold(xfrm_dst_path(skb_dst(skb)));
                dst = xfrm_lookup(net, xfrm_dst_path(skb_dst(skb)), &fl, skb->sk, 0);
                if (IS_ERR(dst)) {