Message ID | af1b9df0b22d7a9f208e093356412f8976cc1bc2.1738780166.git.leon@kernel.org (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | [RFC,ipsec-next] xfrm: fix tunnel mode TX datapath in packet offload mode | expand |
On Wed, Feb 05, 2025 at 08:41:02PM +0200, Leon Romanovsky wrote: > From: Alexandre Cassen <acassen@corp.free.fr> > > +static int xfrm_dev_direct_output(struct sock *sk, struct xfrm_state *x, > + struct sk_buff *skb) > +{ > + struct dst_entry *dst = skb_dst(skb); > + struct net *net = xs_net(x); > + int err; > + > + dst = skb_dst_pop(skb); > + if (!dst) { > + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); > + kfree_skb(skb); > + return -EHOSTUNREACH; > + } > + skb_dst_set(skb, dst); > + nf_reset_ct(skb); > + > + err = skb_dst(skb)->ops->local_out(net, sk, skb); > + if (unlikely(err != 1)) { > + kfree_skb(skb); > + return err; > + } > + > + /* In transport mode, network destination is > + * directly reachable, while in tunnel mode, > + * inner packet network may not be. In packet > + * offload type, HW is responsible for hard > + * header packet mangling so directly xmit skb > + * to netdevice. > + */ > + skb->dev = x->xso.dev; > + __skb_push(skb, skb->dev->hard_header_len); > + return dev_queue_xmit(skb); I think this is absolutely the right thing for tunnel mode, but on transport mode we might bypass some valid netfilter rules.
On Fri, Feb 14, 2025 at 10:34:58AM +0100, Steffen Klassert wrote: > On Wed, Feb 05, 2025 at 08:41:02PM +0200, Leon Romanovsky wrote: > > From: Alexandre Cassen <acassen@corp.free.fr> > > > > +static int xfrm_dev_direct_output(struct sock *sk, struct xfrm_state *x, > > + struct sk_buff *skb) > > +{ > > + struct dst_entry *dst = skb_dst(skb); > > + struct net *net = xs_net(x); > > + int err; > > + > > + dst = skb_dst_pop(skb); > > + if (!dst) { > > + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); > > + kfree_skb(skb); > > + return -EHOSTUNREACH; > > + } > > + skb_dst_set(skb, dst); > > + nf_reset_ct(skb); > > + > > + err = skb_dst(skb)->ops->local_out(net, sk, skb); > > + if (unlikely(err != 1)) { > > + kfree_skb(skb); > > + return err; > > + } > > + > > + /* In transport mode, network destination is > > + * directly reachable, while in tunnel mode, > > + * inner packet network may not be. In packet > > + * offload type, HW is responsible for hard > > + * header packet mangling so directly xmit skb > > + * to netdevice. > > + */ > > + skb->dev = x->xso.dev; > > + __skb_push(skb, skb->dev->hard_header_len); > > + return dev_queue_xmit(skb); > > I think this is absolutely the right thing for tunnel mode, > but on transport mode we might bypass some valid netfilter > rules. Thanks for the acknowledge. We will prepare proper patch.
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 34c8e266641c..4ad83b9ea0e9 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -495,7 +495,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err) struct xfrm_state *x = dst->xfrm; struct net *net = xs_net(x); - if (err <= 0 || x->xso.type == XFRM_DEV_OFFLOAD_PACKET) + if (err <= 0) goto resume; do { @@ -612,6 +612,40 @@ int xfrm_output_resume(struct sock *sk, struct sk_buff *skb, int err) } EXPORT_SYMBOL_GPL(xfrm_output_resume); +static int xfrm_dev_direct_output(struct sock *sk, struct xfrm_state *x, + struct sk_buff *skb) +{ + struct dst_entry *dst = skb_dst(skb); + struct net *net = xs_net(x); + int err; + + dst = skb_dst_pop(skb); + if (!dst) { + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); + kfree_skb(skb); + return -EHOSTUNREACH; + } + skb_dst_set(skb, dst); + nf_reset_ct(skb); + + err = skb_dst(skb)->ops->local_out(net, sk, skb); + if (unlikely(err != 1)) { + kfree_skb(skb); + return err; + } + + /* In transport mode, network destination is + * directly reachable, while in tunnel mode, + * inner packet network may not be. In packet + * offload type, HW is responsible for hard + * header packet mangling so directly xmit skb + * to netdevice. + */ + skb->dev = x->xso.dev; + __skb_push(skb, skb->dev->hard_header_len); + return dev_queue_xmit(skb); +} + static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb) { return xfrm_output_resume(sk, skb, 1); @@ -735,7 +769,7 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb) return -EHOSTUNREACH; } - return xfrm_output_resume(sk, skb, 0); + return xfrm_dev_direct_output(sk, x, skb); } secpath_reset(skb);