Skip to content

Commit c955311

Browse files
Alexandre CassenSasha Levin
authored andcommitted
xfrm: fix tunnel mode TX datapath in packet offload mode
[ Upstream commit 5eddd76 ] Packets that match the output xfrm policy are delivered to the netstack. In IPsec packet mode for tunnel mode, the HW is responsible for building the hard header and outer IP header. In such a situation, the inner header may refer to a network that is not directly reachable by the host, resulting in a failed neighbor resolution. The packet is then dropped. xfrm policy defines the netdevice to use for xmit so we can send packets directly to it. Makes direct xmit exclusive to tunnel mode, since some rules may apply in transport mode. Fixes: f8a70af ("xfrm: add TX datapath support for IPsec packet offload mode") Signed-off-by: Alexandre Cassen <acassen@corp.free.fr> Signed-off-by: Leon Romanovsky <leonro@nvidia.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 9418e08 commit c955311

1 file changed

Lines changed: 41 additions & 0 deletions

File tree

net/xfrm/xfrm_output.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,40 @@ int xfrm_output_resume(struct sock *sk, struct sk_buff *skb, int err)
610610
}
611611
EXPORT_SYMBOL_GPL(xfrm_output_resume);
612612

613+
static int xfrm_dev_direct_output(struct sock *sk, struct xfrm_state *x,
614+
struct sk_buff *skb)
615+
{
616+
struct dst_entry *dst = skb_dst(skb);
617+
struct net *net = xs_net(x);
618+
int err;
619+
620+
dst = skb_dst_pop(skb);
621+
if (!dst) {
622+
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
623+
kfree_skb(skb);
624+
return -EHOSTUNREACH;
625+
}
626+
skb_dst_set(skb, dst);
627+
nf_reset_ct(skb);
628+
629+
err = skb_dst(skb)->ops->local_out(net, sk, skb);
630+
if (unlikely(err != 1)) {
631+
kfree_skb(skb);
632+
return err;
633+
}
634+
635+
/* In transport mode, network destination is
636+
* directly reachable, while in tunnel mode,
637+
* inner packet network may not be. In packet
638+
* offload type, HW is responsible for hard
639+
* header packet mangling so directly xmit skb
640+
* to netdevice.
641+
*/
642+
skb->dev = x->xso.dev;
643+
__skb_push(skb, skb->dev->hard_header_len);
644+
return dev_queue_xmit(skb);
645+
}
646+
613647
static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
614648
{
615649
return xfrm_output_resume(sk, skb, 1);
@@ -729,6 +763,13 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
729763
return -EHOSTUNREACH;
730764
}
731765

766+
/* Exclusive direct xmit for tunnel mode, as
767+
* some filtering or matching rules may apply
768+
* in transport mode.
769+
*/
770+
if (x->props.mode == XFRM_MODE_TUNNEL)
771+
return xfrm_dev_direct_output(sk, x, skb);
772+
732773
return xfrm_output_resume(sk, skb, 0);
733774
}
734775

0 commit comments

Comments
 (0)