]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ipv6: sr: Prepare HMAC key ahead of time
authorEric Biggers <ebiggers@kernel.org>
Sun, 24 Aug 2025 01:36:44 +0000 (21:36 -0400)
committerJakub Kicinski <kuba@kernel.org>
Wed, 27 Aug 2025 01:11:29 +0000 (18:11 -0700)
Prepare the HMAC key when it is added to the kernel, instead of
preparing it implicitly for every packet.  This significantly improves
the performance of seg6_hmac_compute().  A microbenchmark on x86_64
shows seg6_hmac_compute() (with HMAC-SHA256) dropping from ~1978 cycles
to ~1419 cycles, a 28% improvement.

The size of 'struct seg6_hmac_info' increases by 128 bytes, but that
should be fine, since there should not be a massive number of keys.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Link: https://patch.msgid.link/20250824013644.71928-3-ebiggers@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/seg6_hmac.h
net/ipv6/seg6_hmac.c

index 3fe4123dbbf0aa5db8e090de53ace01fe2ef5acc..e9f41725933e44ad24d3b75ff160ffa25db7d3cd 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef _NET_SEG6_HMAC_H
 #define _NET_SEG6_HMAC_H
 
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
 #include <net/flow.h>
 #include <net/ip6_fib.h>
 #include <net/sock.h>
@@ -26,9 +28,15 @@ struct seg6_hmac_info {
        struct rcu_head rcu;
 
        u32 hmackeyid;
+       /* The raw key, kept only so it can be returned back to userspace */
        char secret[SEG6_HMAC_SECRET_LEN];
        u8 slen;
        u8 alg_id;
+       /* The prepared key, which the calculations actually use */
+       union {
+               struct hmac_sha1_key sha1;
+               struct hmac_sha256_key sha256;
+       } key;
 };
 
 extern int seg6_hmac_compute(struct seg6_hmac_info *hinfo,
index 61f6019df55b67fadfc9dec057f9d3491a7df70b..ee6bac0160aceafdc4eed57b34014eded9e8a9a1 100644 (file)
@@ -148,19 +148,18 @@ int seg6_hmac_compute(struct seg6_hmac_info *hinfo, struct ipv6_sr_hdr *hdr,
 
        switch (hinfo->alg_id) {
        case SEG6_HMAC_ALGO_SHA1:
-               hmac_sha1_usingrawkey(hinfo->secret, hinfo->slen, ring, plen,
-                                     output);
+               hmac_sha1(&hinfo->key.sha1, ring, plen, output);
                static_assert(SEG6_HMAC_FIELD_LEN > SHA1_DIGEST_SIZE);
                memset(&output[SHA1_DIGEST_SIZE], 0,
                       SEG6_HMAC_FIELD_LEN - SHA1_DIGEST_SIZE);
                break;
        case SEG6_HMAC_ALGO_SHA256:
-               hmac_sha256_usingrawkey(hinfo->secret, hinfo->slen, ring, plen,
-                                       output);
+               hmac_sha256(&hinfo->key.sha256, ring, plen, output);
                static_assert(SEG6_HMAC_FIELD_LEN == SHA256_DIGEST_SIZE);
                break;
        default:
-               ret = -ENOENT;
+               WARN_ON_ONCE(1);
+               ret = -EINVAL;
                break;
        }
        local_unlock_nested_bh(&hmac_storage.bh_lock);
@@ -238,7 +237,12 @@ int seg6_hmac_info_add(struct net *net, u32 key, struct seg6_hmac_info *hinfo)
 
        switch (hinfo->alg_id) {
        case SEG6_HMAC_ALGO_SHA1:
+               hmac_sha1_preparekey(&hinfo->key.sha1,
+                                    hinfo->secret, hinfo->slen);
+               break;
        case SEG6_HMAC_ALGO_SHA256:
+               hmac_sha256_preparekey(&hinfo->key.sha256,
+                                      hinfo->secret, hinfo->slen);
                break;
        default:
                return -EINVAL;