]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfrm: add SA information to the offloaded packet
authorwangfe <wangfe@google.com>
Thu, 22 Aug 2024 20:02:52 +0000 (13:02 -0700)
committerSteffen Klassert <steffen.klassert@secunet.com>
Tue, 27 Aug 2024 09:28:58 +0000 (11:28 +0200)
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 crucial in setups
with multiple XFRM interfaces where source/destination addresses alone
can't pinpoint the right policy.

Signed-off-by: wangfe <wangfe@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/xfrm/xfrm_output.c

index e5722c95b8bb38c528cc518cdc3a05e08a338264..a12588e7b0605f06ddde5c14a4ec916f62adec85 100644 (file)
@@ -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);
        }