diff mbox series

xfrm: add SA information to the offloaded packet

Message ID 20241112192249.341515-1-wangfe@google.com (mailing list archive)
State Awaiting Upstream
Delegated to: Netdev Maintainers
Headers show
Series xfrm: add SA information to the offloaded packet | expand

Checks

Context Check Description
netdev/series_format warning Single patches do not need cover letters; Target tree name not specified in the subject
netdev/tree_selection success Guessed tree name to be net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 3 this patch: 3
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 6 maintainers not CCed: kuba@kernel.org andrew+netdev@lunn.ch horms@kernel.org pabeni@redhat.com edumazet@google.com herbert@gondor.apana.org.au
netdev/build_clang success Errors and warnings before: 3 this patch: 3
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 5 this patch: 5
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 106 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest fail net-next-2024-11-13--00-00 (tests: 784)

Commit Message

Feng Wang Nov. 12, 2024, 7:22 p.m. UTC
From: wangfe <wangfe@google.com>

In packet offload mode, append Security Association (SA) information
to each packet, replicating the crypto offload implementation.
The XFRM_XMIT flag is set to enable packet to be returned immediately
from the validate_xmit_xfrm function, thus aligning with the existing
code path for packet offload mode.

This SA info helps HW offload match packets to their correct security
policies. The XFRM interface ID is included, which is used in setups
with multiple XFRM interfaces where source/destination addresses alone
can't pinpoint the right policy.

Enable packet offload mode on netdevsim and add code to check the XFRM
interface ID.

Signed-off-by: wangfe <wangfe@google.com>
---
v4: https://lore.kernel.org/all/20241104233251.3387719-1-wangfe@google.com/
  - Add offload flag check and only doing check when XFRM interface
    ID is non-zero.
v3: https://lore.kernel.org/all/20240822200252.472298-1-wangfe@google.com/
  - Add XFRM interface ID checking on netdevsim in the packet offload
    mode.
v2:
  - Add why HW offload requires the SA info to the commit message
v1: https://lore.kernel.org/all/20240812182317.1962756-1-wangfe@google.com/
---
---
 drivers/net/netdevsim/ipsec.c     | 32 ++++++++++++++++++++++++++++++-
 drivers/net/netdevsim/netdevsim.h |  1 +
 net/xfrm/xfrm_output.c            | 21 ++++++++++++++++++++
 3 files changed, 53 insertions(+), 1 deletion(-)

Comments

Leon Romanovsky Nov. 14, 2024, 10:27 a.m. UTC | #1
On Tue, Nov 12, 2024 at 11:22:49AM -0800, Feng Wang wrote:
> From: wangfe <wangfe@google.com>
> 
> In packet offload mode, append Security Association (SA) information
> to each packet, replicating the crypto offload implementation.
> The XFRM_XMIT flag is set to enable packet to be returned immediately
> from the validate_xmit_xfrm function, thus aligning with the existing
> code path for packet offload mode.
> 
> This SA info helps HW offload match packets to their correct security
> policies. The XFRM interface ID is included, which is used in setups
> with multiple XFRM interfaces where source/destination addresses alone
> can't pinpoint the right policy.
> 
> Enable packet offload mode on netdevsim and add code to check the XFRM
> interface ID.
> 
> Signed-off-by: wangfe <wangfe@google.com>
> ---
> v4: https://lore.kernel.org/all/20241104233251.3387719-1-wangfe@google.com/
>   - Add offload flag check and only doing check when XFRM interface
>     ID is non-zero.
> v3: https://lore.kernel.org/all/20240822200252.472298-1-wangfe@google.com/
>   - Add XFRM interface ID checking on netdevsim in the packet offload
>     mode.
> v2:
>   - Add why HW offload requires the SA info to the commit message
> v1: https://lore.kernel.org/all/20240812182317.1962756-1-wangfe@google.com/
> ---
> ---
>  drivers/net/netdevsim/ipsec.c     | 32 ++++++++++++++++++++++++++++++-
>  drivers/net/netdevsim/netdevsim.h |  1 +
>  net/xfrm/xfrm_output.c            | 21 ++++++++++++++++++++
>  3 files changed, 53 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
> index f0d58092e7e9..afd2005bf7a8 100644
> --- a/drivers/net/netdevsim/ipsec.c
> +++ b/drivers/net/netdevsim/ipsec.c
> @@ -149,7 +149,8 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs,
>  		return -EINVAL;
>  	}
>  
> -	if (xs->xso.type != XFRM_DEV_OFFLOAD_CRYPTO) {
> +	if (xs->xso.type != XFRM_DEV_OFFLOAD_CRYPTO &&
> +	    xs->xso.type != XFRM_DEV_OFFLOAD_PACKET) {
>  		NL_SET_ERR_MSG_MOD(extack, "Unsupported ipsec offload type");
>  		return -EINVAL;
>  	}
> @@ -165,6 +166,7 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs,
>  	memset(&sa, 0, sizeof(sa));
>  	sa.used = true;
>  	sa.xs = xs;
> +	sa.if_id = xs->if_id;
>  
>  	if (sa.xs->id.proto & IPPROTO_ESP)
>  		sa.crypt = xs->ealg || xs->aead;
> @@ -224,10 +226,24 @@ static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
>  	return true;
>  }
>  
> +static int nsim_ipsec_add_policy(struct xfrm_policy *policy,
> +				 struct netlink_ext_ack *extack)
> +{
> +	return 0;
> +}
> +
> +static void nsim_ipsec_del_policy(struct xfrm_policy *policy)
> +{
> +}
> +
>  static const struct xfrmdev_ops nsim_xfrmdev_ops = {
>  	.xdo_dev_state_add	= nsim_ipsec_add_sa,
>  	.xdo_dev_state_delete	= nsim_ipsec_del_sa,
>  	.xdo_dev_offload_ok	= nsim_ipsec_offload_ok,
> +
> +	.xdo_dev_policy_add     = nsim_ipsec_add_policy,
> +	.xdo_dev_policy_delete  = nsim_ipsec_del_policy,
> +
>  };
>  
>  bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
> @@ -237,6 +253,7 @@ bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
>  	struct xfrm_state *xs;
>  	struct nsim_sa *tsa;
>  	u32 sa_idx;
> +	struct xfrm_offload *xo;
>  
>  	/* do we even need to check this packet? */
>  	if (!sp)
> @@ -272,6 +289,19 @@ bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
>  		return false;
>  	}
>  
> +	if (xs->if_id) {

If you are checking this, you will need to make sure that XFRM_XMIT is
set when if_id != 0. It is not how it is implemented now.

> +		if (xs->if_id != tsa->if_id) {
> +			netdev_err(ns->netdev, "unmatched if_id %d %d\n",
> +				   xs->if_id, tsa->if_id);
> +			return false;
> +		}
> +		xo = xfrm_offload(skb);
> +		if (!xo || !(xo->flags & XFRM_XMIT)) {
> +			netdev_err(ns->netdev, "offload flag missing or wrong\n");
> +			return false;
> +		}
> +	}
> +
>  	ipsec->tx++;
>  
>  	return true;
> diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
> index bf02efa10956..4941b6e46d0a 100644
> --- a/drivers/net/netdevsim/netdevsim.h
> +++ b/drivers/net/netdevsim/netdevsim.h
> @@ -41,6 +41,7 @@ struct nsim_sa {
>  	__be32 ipaddr[4];
>  	u32 key[4];
>  	u32 salt;
> +	u32 if_id;
>  	bool used;
>  	bool crypt;
>  	bool rx;
> diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
> index e5722c95b8bb..a12588e7b060 100644
> --- a/net/xfrm/xfrm_output.c
> +++ b/net/xfrm/xfrm_output.c
> @@ -706,6 +706,8 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
>  	struct xfrm_state *x = skb_dst(skb)->xfrm;
>  	int family;
>  	int err;
> +	struct xfrm_offload *xo;
> +	struct sec_path *sp;
>  
>  	family = (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) ? x->outer_mode.family
>  		: skb_dst(skb)->ops->family;
> @@ -728,6 +730,25 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
>  			kfree_skb(skb);
>  			return -EHOSTUNREACH;
>  		}
> +		sp = secpath_set(skb);
> +		if (!sp) {
> +			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
> +			kfree_skb(skb);
> +			return -ENOMEM;
> +		}
> +
> +		sp->olen++;
> +		sp->xvec[sp->len++] = x;
> +		xfrm_state_hold(x);

Not an expert and just looked how XFRM_XMIT is assigned in other places,
and simple skb_ext_add(skb, SKB_EXT_SEC_PATH) is used, why is it
different here?

The additional issue is that you are adding extension and flag to all
offloaded packets, which makes me wonder what to do with this check in
validate_xmit_xfrm():

  136         /* The packet was sent to HW IPsec packet offload engine,
  137          * but to wrong device. Drop the packet, so it won't skip
  138          * XFRM stack.
  139          */
  140         if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET && x->xso.dev != dev) {
  141                 kfree_skb(skb);
  142                 dev_core_stats_tx_dropped_inc(dev);
  143                 return NULL;
  144         }

Also because you are adding it to all packets, you are adding extra
overhead for all users, even these who didn't ask this if_id thing.

And again, you should block creation of SAs with if_id != 0 for already
existing in-kernel IPsec implementations.

Thanks

> +
> +		xo = xfrm_offload(skb);
> +		if (!xo) {
> +			secpath_reset(skb);
> +			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
> +			kfree_skb(skb);
> +			return -EINVAL;
> +		}
> +		xo->flags |= XFRM_XMIT;
>  
>  		return xfrm_output_resume(sk, skb, 0);
>  	}
> -- 
> 2.47.0.277.g8800431eea-goog
> 
>
Feng Wang Nov. 18, 2024, 7:28 p.m. UTC | #2
Hi Leon,

If you are concerned about the case when if_id is 0,   I can make the
change to add the SA only when if_id is non-zero in the .  When the
XFRM_XMIT flag is set,  validate_xmit_xfrm will return immediately,
there is no need to check extension and flag. Are you ok with that?

Thanks,

Feng
Leon Romanovsky Nov. 19, 2024, 12:51 p.m. UTC | #3
On Mon, Nov 18, 2024 at 11:28:01AM -0800, Feng Wang wrote:
> Hi Leon,
> 
> If you are concerned about the case when if_id is 0,   I can make the
> change to add the SA only when if_id is non-zero in the .  When the
> XFRM_XMIT flag is set,  validate_xmit_xfrm will return immediately,
> there is no need to check extension and flag. Are you ok with that?
> 
> Thanks,
> 
> Feng

Hi, 

You was already asked to respect mailing list email etiquette and don't
respond in top-post format. I would like to add to that request, please
reply in-line and don't trim whole message as it is impossible to keep
context in your emails.

For now, I will just ignore your emails.

Thanks

>
Feng Wang Nov. 19, 2024, 7:15 p.m. UTC | #4
Hi Leon,

Sorry about the format issue,  I thought I used the correct format.
Now I try to do it again, if it still has an issue, please let me
know.
I will create a new patch based on your comments.

Thanks,

Feng

On Sat, Nov 16, 2024 at 10:22 PM Leon Romanovsky <leonro@nvidia.com> wrote:
>
> On Tue, Nov 12, 2024 at 11:22:49AM -0800, Feng Wang wrote:
> > From: wangfe <wangfe@google.com>
> >
> > In packet offload mode, append Security Association (SA) information
> > to each packet, replicating the crypto offload implementation.
> > The XFRM_XMIT flag is set to enable packet to be returned immediately
> > from the validate_xmit_xfrm function, thus aligning with the existing
> > code path for packet offload mode.
> >
> > This SA info helps HW offload match packets to their correct security
> > policies. The XFRM interface ID is included, which is used in setups
> > with multiple XFRM interfaces where source/destination addresses alone
> > can't pinpoint the right policy.
> >
> > Enable packet offload mode on netdevsim and add code to check the XFRM
> > interface ID.
> >
> > Signed-off-by: wangfe <wangfe@google.com>
> > ---
> > v4: https://lore.kernel.org/all/20241104233251.3387719-1-wangfe@google.com/
> >   - Add offload flag check and only doing check when XFRM interface
> >     ID is non-zero.
> > v3: https://lore.kernel.org/all/20240822200252.472298-1-wangfe@google.com/
> >   - Add XFRM interface ID checking on netdevsim in the packet offload
> >     mode.
> > v2:
> >   - Add why HW offload requires the SA info to the commit message
> > v1: https://lore.kernel.org/all/20240812182317.1962756-1-wangfe@google.com/
> > ---
> > ---
> >  drivers/net/netdevsim/ipsec.c     | 32 ++++++++++++++++++++++++++++++-
> >  drivers/net/netdevsim/netdevsim.h |  1 +
> >  net/xfrm/xfrm_output.c            | 21 ++++++++++++++++++++
> >  3 files changed, 53 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
> > index f0d58092e7e9..afd2005bf7a8 100644
> > --- a/drivers/net/netdevsim/ipsec.c
> > +++ b/drivers/net/netdevsim/ipsec.c
> > @@ -149,7 +149,8 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs,
> >               return -EINVAL;
> >       }
> >
> > -     if (xs->xso.type != XFRM_DEV_OFFLOAD_CRYPTO) {
> > +     if (xs->xso.type != XFRM_DEV_OFFLOAD_CRYPTO &&
> > +         xs->xso.type != XFRM_DEV_OFFLOAD_PACKET) {
> >               NL_SET_ERR_MSG_MOD(extack, "Unsupported ipsec offload type");
> >               return -EINVAL;
> >       }
> > @@ -165,6 +166,7 @@ static int nsim_ipsec_add_sa(struct xfrm_state *xs,
> >       memset(&sa, 0, sizeof(sa));
> >       sa.used = true;
> >       sa.xs = xs;
> > +     sa.if_id = xs->if_id;
> >
> >       if (sa.xs->id.proto & IPPROTO_ESP)
> >               sa.crypt = xs->ealg || xs->aead;
> > @@ -224,10 +226,24 @@ static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
> >       return true;
> >  }
> >
> > +static int nsim_ipsec_add_policy(struct xfrm_policy *policy,
> > +                              struct netlink_ext_ack *extack)
> > +{
> > +     return 0;
> > +}
> > +
> > +static void nsim_ipsec_del_policy(struct xfrm_policy *policy)
> > +{
> > +}
> > +
> >  static const struct xfrmdev_ops nsim_xfrmdev_ops = {
> >       .xdo_dev_state_add      = nsim_ipsec_add_sa,
> >       .xdo_dev_state_delete   = nsim_ipsec_del_sa,
> >       .xdo_dev_offload_ok     = nsim_ipsec_offload_ok,
> > +
> > +     .xdo_dev_policy_add     = nsim_ipsec_add_policy,
> > +     .xdo_dev_policy_delete  = nsim_ipsec_del_policy,
> > +
> >  };
> >
> >  bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
> > @@ -237,6 +253,7 @@ bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
> >       struct xfrm_state *xs;
> >       struct nsim_sa *tsa;
> >       u32 sa_idx;
> > +     struct xfrm_offload *xo;
> >
> >       /* do we even need to check this packet? */
> >       if (!sp)
> > @@ -272,6 +289,19 @@ bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
> >               return false;
> >       }
> >
> > +     if (xs->if_id) {
>
> If you are checking this, you will need to make sure that XFRM_XMIT is
> set when if_id != 0. It is not how it is implemented now.
>
I will change the code to add the SA only when if_id is non-zero,
then it will make sense.

> > +             if (xs->if_id != tsa->if_id) {
> > +                     netdev_err(ns->netdev, "unmatched if_id %d %d\n",
> > +                                xs->if_id, tsa->if_id);
> > +                     return false;
> > +             }
> > +             xo = xfrm_offload(skb);
> > +             if (!xo || !(xo->flags & XFRM_XMIT)) {
> > +                     netdev_err(ns->netdev, "offload flag missing or wrong\n");
> > +                     return false;
> > +             }
> > +     }
> > +
> >       ipsec->tx++;
> >
> >       return true;
> > diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
> > index bf02efa10956..4941b6e46d0a 100644
> > --- a/drivers/net/netdevsim/netdevsim.h
> > +++ b/drivers/net/netdevsim/netdevsim.h
> > @@ -41,6 +41,7 @@ struct nsim_sa {
> >       __be32 ipaddr[4];
> >       u32 key[4];
> >       u32 salt;
> > +     u32 if_id;
> >       bool used;
> >       bool crypt;
> >       bool rx;
> > diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
> > index e5722c95b8bb..a12588e7b060 100644
> > --- a/net/xfrm/xfrm_output.c
> > +++ b/net/xfrm/xfrm_output.c
> > @@ -706,6 +706,8 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
> >       struct xfrm_state *x = skb_dst(skb)->xfrm;
> >       int family;
> >       int err;
> > +     struct xfrm_offload *xo;
> > +     struct sec_path *sp;
> >
> >       family = (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) ? x->outer_mode.family
> >               : skb_dst(skb)->ops->family;
> > @@ -728,6 +730,25 @@ int xfrm_output(struct sock *sk, struct sk_buff *skb)
> >                       kfree_skb(skb);
> >                       return -EHOSTUNREACH;
> >               }
> > +             sp = secpath_set(skb);
> > +             if (!sp) {
> > +                     XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
> > +                     kfree_skb(skb);
> > +                     return -ENOMEM;
> > +             }
> > +
> > +             sp->olen++;
> > +             sp->xvec[sp->len++] = x;
> > +             xfrm_state_hold(x);
>
> Not an expert and just looked how XFRM_XMIT is assigned in other places,
> and simple skb_ext_add(skb, SKB_EXT_SEC_PATH) is used, why is it
> different here?
>
> The additional issue is that you are adding extension and flag to all
> offloaded packets, which makes me wonder what to do with this check in
> validate_xmit_xfrm():
>
Set the XFRM_XMIT flag makes validate_xmit_xfrm returns immediately
without need to do any further check.

>   136         /* The packet was sent to HW IPsec packet offload engine,
>   137          * but to wrong device. Drop the packet, so it won't skip
>   138          * XFRM stack.
>   139          */
>   140         if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET && x->xso.dev != dev) {
>   141                 kfree_skb(skb);
>   142                 dev_core_stats_tx_dropped_inc(dev);
>   143                 return NULL;
>   144         }
>
> Also because you are adding it to all packets, you are adding extra
> overhead for all users, even these who didn't ask this if_id thing.
>
> And again, you should block creation of SAs with if_id != 0 for already
> existing in-kernel IPsec implementations.
>
> Thanks
>
I will add SA information only when id is non-zero,  thus no overhead
for other uses, and no need to block creating of SAs with if_id is 0,

> > +
> > +             xo = xfrm_offload(skb);
> > +             if (!xo) {
> > +                     secpath_reset(skb);
> > +                     XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
> > +                     kfree_skb(skb);
> > +                     return -EINVAL;
> > +             }
> > +             xo->flags |= XFRM_XMIT;
> >
> >               return xfrm_output_resume(sk, skb, 0);
> >       }
> > --
> > 2.47.0.277.g8800431eea-goog
> >
> >
diff mbox series

Patch

diff --git a/drivers/net/netdevsim/ipsec.c b/drivers/net/netdevsim/ipsec.c
index f0d58092e7e9..afd2005bf7a8 100644
--- a/drivers/net/netdevsim/ipsec.c
+++ b/drivers/net/netdevsim/ipsec.c
@@ -149,7 +149,8 @@  static int nsim_ipsec_add_sa(struct xfrm_state *xs,
 		return -EINVAL;
 	}
 
-	if (xs->xso.type != XFRM_DEV_OFFLOAD_CRYPTO) {
+	if (xs->xso.type != XFRM_DEV_OFFLOAD_CRYPTO &&
+	    xs->xso.type != XFRM_DEV_OFFLOAD_PACKET) {
 		NL_SET_ERR_MSG_MOD(extack, "Unsupported ipsec offload type");
 		return -EINVAL;
 	}
@@ -165,6 +166,7 @@  static int nsim_ipsec_add_sa(struct xfrm_state *xs,
 	memset(&sa, 0, sizeof(sa));
 	sa.used = true;
 	sa.xs = xs;
+	sa.if_id = xs->if_id;
 
 	if (sa.xs->id.proto & IPPROTO_ESP)
 		sa.crypt = xs->ealg || xs->aead;
@@ -224,10 +226,24 @@  static bool nsim_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs)
 	return true;
 }
 
+static int nsim_ipsec_add_policy(struct xfrm_policy *policy,
+				 struct netlink_ext_ack *extack)
+{
+	return 0;
+}
+
+static void nsim_ipsec_del_policy(struct xfrm_policy *policy)
+{
+}
+
 static const struct xfrmdev_ops nsim_xfrmdev_ops = {
 	.xdo_dev_state_add	= nsim_ipsec_add_sa,
 	.xdo_dev_state_delete	= nsim_ipsec_del_sa,
 	.xdo_dev_offload_ok	= nsim_ipsec_offload_ok,
+
+	.xdo_dev_policy_add     = nsim_ipsec_add_policy,
+	.xdo_dev_policy_delete  = nsim_ipsec_del_policy,
+
 };
 
 bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
@@ -237,6 +253,7 @@  bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
 	struct xfrm_state *xs;
 	struct nsim_sa *tsa;
 	u32 sa_idx;
+	struct xfrm_offload *xo;
 
 	/* do we even need to check this packet? */
 	if (!sp)
@@ -272,6 +289,19 @@  bool nsim_ipsec_tx(struct netdevsim *ns, struct sk_buff *skb)
 		return false;
 	}
 
+	if (xs->if_id) {
+		if (xs->if_id != tsa->if_id) {
+			netdev_err(ns->netdev, "unmatched if_id %d %d\n",
+				   xs->if_id, tsa->if_id);
+			return false;
+		}
+		xo = xfrm_offload(skb);
+		if (!xo || !(xo->flags & XFRM_XMIT)) {
+			netdev_err(ns->netdev, "offload flag missing or wrong\n");
+			return false;
+		}
+	}
+
 	ipsec->tx++;
 
 	return true;
diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h
index bf02efa10956..4941b6e46d0a 100644
--- a/drivers/net/netdevsim/netdevsim.h
+++ b/drivers/net/netdevsim/netdevsim.h
@@ -41,6 +41,7 @@  struct nsim_sa {
 	__be32 ipaddr[4];
 	u32 key[4];
 	u32 salt;
+	u32 if_id;
 	bool used;
 	bool crypt;
 	bool rx;
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index e5722c95b8bb..a12588e7b060 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -706,6 +706,8 @@  int xfrm_output(struct sock *sk, struct sk_buff *skb)
 	struct xfrm_state *x = skb_dst(skb)->xfrm;
 	int family;
 	int err;
+	struct xfrm_offload *xo;
+	struct sec_path *sp;
 
 	family = (x->xso.type != XFRM_DEV_OFFLOAD_PACKET) ? x->outer_mode.family
 		: skb_dst(skb)->ops->family;
@@ -728,6 +730,25 @@  int xfrm_output(struct sock *sk, struct sk_buff *skb)
 			kfree_skb(skb);
 			return -EHOSTUNREACH;
 		}
+		sp = secpath_set(skb);
+		if (!sp) {
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
+			kfree_skb(skb);
+			return -ENOMEM;
+		}
+
+		sp->olen++;
+		sp->xvec[sp->len++] = x;
+		xfrm_state_hold(x);
+
+		xo = xfrm_offload(skb);
+		if (!xo) {
+			secpath_reset(skb);
+			XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
+			kfree_skb(skb);
+			return -EINVAL;
+		}
+		xo->flags |= XFRM_XMIT;
 
 		return xfrm_output_resume(sk, skb, 0);
 	}