Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv6: sr: Use HMAC-SHA1 and HMAC-SHA256 library functions

Use the HMAC-SHA1 and HMAC-SHA256 library functions instead of
crypto_shash. This is simpler and faster. Pre-allocating per-CPU hash
transformation objects and descriptors is no longer needed, and a
microbenchmark on x86_64 shows seg6_hmac_compute() (with HMAC-SHA256)
dropping from ~2494 cycles to ~1978 cycles, a 20% improvement.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Link: https://patch.msgid.link/20250824013644.71928-2-ebiggers@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Eric Biggers and committed by
Jakub Kicinski
095928e7 f19434dd

+30 -203
-12
include/net/seg6_hmac.h
··· 19 19 #include <linux/seg6_hmac.h> 20 20 #include <linux/rhashtable-types.h> 21 21 22 - #define SEG6_HMAC_MAX_DIGESTSIZE 160 23 22 #define SEG6_HMAC_RING_SIZE 256 24 23 25 24 struct seg6_hmac_info { ··· 29 30 char secret[SEG6_HMAC_SECRET_LEN]; 30 31 u8 slen; 31 32 u8 alg_id; 32 - }; 33 - 34 - struct seg6_hmac_algo { 35 - u8 alg_id; 36 - char name[64]; 37 - struct crypto_shash * __percpu *tfms; 38 - struct shash_desc * __percpu *shashs; 39 33 }; 40 34 41 35 extern int seg6_hmac_compute(struct seg6_hmac_info *hinfo, ··· 42 50 struct ipv6_sr_hdr *srh); 43 51 extern bool seg6_hmac_validate_skb(struct sk_buff *skb); 44 52 #ifdef CONFIG_IPV6_SEG6_HMAC 45 - extern int seg6_hmac_init(void); 46 - extern void seg6_hmac_exit(void); 47 53 extern int seg6_hmac_net_init(struct net *net); 48 54 extern void seg6_hmac_net_exit(struct net *net); 49 55 #else 50 - static inline int seg6_hmac_init(void) { return 0; } 51 - static inline void seg6_hmac_exit(void) {} 52 56 static inline int seg6_hmac_net_init(struct net *net) { return 0; } 53 57 static inline void seg6_hmac_net_exit(struct net *net) {} 54 58 #endif
+3 -4
net/ipv6/Kconfig
··· 304 304 config IPV6_SEG6_HMAC 305 305 bool "IPv6: Segment Routing HMAC support" 306 306 depends on IPV6 307 - select CRYPTO 308 - select CRYPTO_HMAC 309 - select CRYPTO_SHA1 310 - select CRYPTO_SHA256 307 + select CRYPTO_LIB_SHA1 308 + select CRYPTO_LIB_SHA256 309 + select CRYPTO_LIB_UTILS 311 310 help 312 311 Support for HMAC signature generation and verification 313 312 of SR-enabled packets.
-7
net/ipv6/seg6.c
··· 522 522 if (err) 523 523 goto out_unregister_iptun; 524 524 525 - err = seg6_hmac_init(); 526 - if (err) 527 - goto out_unregister_seg6; 528 - 529 525 pr_info("Segment Routing with IPv6\n"); 530 526 531 527 out: 532 528 return err; 533 - out_unregister_seg6: 534 - seg6_local_exit(); 535 529 out_unregister_iptun: 536 530 seg6_iptunnel_exit(); 537 531 out_unregister_genl: ··· 537 543 538 544 void seg6_exit(void) 539 545 { 540 - seg6_hmac_exit(); 541 546 seg6_local_exit(); 542 547 seg6_iptunnel_exit(); 543 548 genl_unregister_family(&seg6_genl_family);
+27 -180
net/ipv6/seg6_hmac.c
··· 16 16 #include <linux/in6.h> 17 17 #include <linux/icmpv6.h> 18 18 #include <linux/mroute6.h> 19 - #include <linux/slab.h> 20 19 #include <linux/rhashtable.h> 21 20 22 21 #include <linux/netfilter.h> ··· 33 34 #include <net/addrconf.h> 34 35 #include <net/xfrm.h> 35 36 36 - #include <crypto/hash.h> 37 + #include <crypto/sha1.h> 38 + #include <crypto/sha2.h> 37 39 #include <crypto/utils.h> 38 40 #include <net/seg6.h> 39 41 #include <net/genetlink.h> ··· 78 78 .obj_cmpfn = seg6_hmac_cmpfn, 79 79 }; 80 80 81 - static struct seg6_hmac_algo hmac_algos[] = { 82 - { 83 - .alg_id = SEG6_HMAC_ALGO_SHA1, 84 - .name = "hmac(sha1)", 85 - }, 86 - { 87 - .alg_id = SEG6_HMAC_ALGO_SHA256, 88 - .name = "hmac(sha256)", 89 - }, 90 - }; 91 - 92 81 static struct sr6_tlv_hmac *seg6_get_tlv_hmac(struct ipv6_sr_hdr *srh) 93 82 { 94 83 struct sr6_tlv_hmac *tlv; ··· 97 108 return tlv; 98 109 } 99 110 100 - static struct seg6_hmac_algo *__hmac_get_algo(u8 alg_id) 101 - { 102 - struct seg6_hmac_algo *algo; 103 - int i, alg_count; 104 - 105 - alg_count = ARRAY_SIZE(hmac_algos); 106 - for (i = 0; i < alg_count; i++) { 107 - algo = &hmac_algos[i]; 108 - if (algo->alg_id == alg_id) 109 - return algo; 110 - } 111 - 112 - return NULL; 113 - } 114 - 115 - static int __do_hmac(struct seg6_hmac_info *hinfo, const char *text, u8 psize, 116 - u8 *output, int outlen) 117 - { 118 - struct seg6_hmac_algo *algo; 119 - struct crypto_shash *tfm; 120 - struct shash_desc *shash; 121 - int ret, dgsize; 122 - 123 - algo = __hmac_get_algo(hinfo->alg_id); 124 - if (!algo) 125 - return -ENOENT; 126 - 127 - tfm = *this_cpu_ptr(algo->tfms); 128 - 129 - dgsize = crypto_shash_digestsize(tfm); 130 - if (dgsize > outlen) { 131 - pr_debug("sr-ipv6: __do_hmac: digest size too big (%d / %d)\n", 132 - dgsize, outlen); 133 - return -ENOMEM; 134 - } 135 - 136 - ret = crypto_shash_setkey(tfm, hinfo->secret, hinfo->slen); 137 - if (ret < 0) { 138 - pr_debug("sr-ipv6: crypto_shash_setkey failed: err %d\n", ret); 139 - goto failed; 140 - } 141 - 142 - shash = *this_cpu_ptr(algo->shashs); 143 - shash->tfm = tfm; 144 - 145 - ret = crypto_shash_digest(shash, text, psize, output); 146 - if (ret < 0) { 147 - pr_debug("sr-ipv6: crypto_shash_digest failed: err %d\n", ret); 148 - goto failed; 149 - } 150 - 151 - return dgsize; 152 - 153 - failed: 154 - return ret; 155 - } 156 - 157 111 int seg6_hmac_compute(struct seg6_hmac_info *hinfo, struct ipv6_sr_hdr *hdr, 158 112 struct in6_addr *saddr, u8 *output) 159 113 { 160 114 __be32 hmackeyid = cpu_to_be32(hinfo->hmackeyid); 161 - u8 tmp_out[SEG6_HMAC_MAX_DIGESTSIZE]; 162 - int plen, i, dgsize, wrsize; 115 + int plen, i, ret = 0; 163 116 char *ring, *off; 164 - 165 - /* a 160-byte buffer for digest output allows to store highest known 166 - * hash function (RadioGatun) with up to 1216 bits 167 - */ 168 117 169 118 /* saddr(16) + first_seg(1) + flags(1) + keyid(4) + seglist(16n) */ 170 119 plen = 16 + 1 + 1 + 4 + (hdr->first_segment + 1) * 16; ··· 146 219 off += 16; 147 220 } 148 221 149 - dgsize = __do_hmac(hinfo, ring, plen, tmp_out, 150 - SEG6_HMAC_MAX_DIGESTSIZE); 222 + switch (hinfo->alg_id) { 223 + case SEG6_HMAC_ALGO_SHA1: 224 + hmac_sha1_usingrawkey(hinfo->secret, hinfo->slen, ring, plen, 225 + output); 226 + static_assert(SEG6_HMAC_FIELD_LEN > SHA1_DIGEST_SIZE); 227 + memset(&output[SHA1_DIGEST_SIZE], 0, 228 + SEG6_HMAC_FIELD_LEN - SHA1_DIGEST_SIZE); 229 + break; 230 + case SEG6_HMAC_ALGO_SHA256: 231 + hmac_sha256_usingrawkey(hinfo->secret, hinfo->slen, ring, plen, 232 + output); 233 + static_assert(SEG6_HMAC_FIELD_LEN == SHA256_DIGEST_SIZE); 234 + break; 235 + default: 236 + ret = -ENOENT; 237 + break; 238 + } 151 239 local_unlock_nested_bh(&hmac_storage.bh_lock); 152 240 local_bh_enable(); 153 - 154 - if (dgsize < 0) 155 - return dgsize; 156 - 157 - wrsize = SEG6_HMAC_FIELD_LEN; 158 - if (wrsize > dgsize) 159 - wrsize = dgsize; 160 - 161 - memset(output, 0, SEG6_HMAC_FIELD_LEN); 162 - memcpy(output, tmp_out, wrsize); 163 - 164 - return 0; 241 + return ret; 165 242 } 166 243 EXPORT_SYMBOL(seg6_hmac_compute); 167 244 ··· 236 305 struct seg6_pernet_data *sdata = seg6_pernet(net); 237 306 int err; 238 307 239 - if (!__hmac_get_algo(hinfo->alg_id)) 308 + switch (hinfo->alg_id) { 309 + case SEG6_HMAC_ALGO_SHA1: 310 + case SEG6_HMAC_ALGO_SHA256: 311 + break; 312 + default: 240 313 return -EINVAL; 314 + } 241 315 242 316 err = rhashtable_lookup_insert_fast(&sdata->hmac_infos, &hinfo->node, 243 317 rht_params); ··· 299 363 } 300 364 EXPORT_SYMBOL(seg6_push_hmac); 301 365 302 - static int seg6_hmac_init_algo(void) 303 - { 304 - struct seg6_hmac_algo *algo; 305 - struct crypto_shash *tfm; 306 - struct shash_desc *shash; 307 - int i, alg_count, cpu; 308 - int ret = -ENOMEM; 309 - 310 - alg_count = ARRAY_SIZE(hmac_algos); 311 - 312 - for (i = 0; i < alg_count; i++) { 313 - struct crypto_shash **p_tfm; 314 - int shsize; 315 - 316 - algo = &hmac_algos[i]; 317 - algo->tfms = alloc_percpu(struct crypto_shash *); 318 - if (!algo->tfms) 319 - goto error_out; 320 - 321 - for_each_possible_cpu(cpu) { 322 - tfm = crypto_alloc_shash(algo->name, 0, 0); 323 - if (IS_ERR(tfm)) { 324 - ret = PTR_ERR(tfm); 325 - goto error_out; 326 - } 327 - p_tfm = per_cpu_ptr(algo->tfms, cpu); 328 - *p_tfm = tfm; 329 - } 330 - 331 - p_tfm = raw_cpu_ptr(algo->tfms); 332 - tfm = *p_tfm; 333 - 334 - shsize = sizeof(*shash) + crypto_shash_descsize(tfm); 335 - 336 - algo->shashs = alloc_percpu(struct shash_desc *); 337 - if (!algo->shashs) 338 - goto error_out; 339 - 340 - for_each_possible_cpu(cpu) { 341 - shash = kzalloc_node(shsize, GFP_KERNEL, 342 - cpu_to_node(cpu)); 343 - if (!shash) 344 - goto error_out; 345 - *per_cpu_ptr(algo->shashs, cpu) = shash; 346 - } 347 - } 348 - 349 - return 0; 350 - 351 - error_out: 352 - seg6_hmac_exit(); 353 - return ret; 354 - } 355 - 356 - int __init seg6_hmac_init(void) 357 - { 358 - return seg6_hmac_init_algo(); 359 - } 360 - 361 366 int __net_init seg6_hmac_net_init(struct net *net) 362 367 { 363 368 struct seg6_pernet_data *sdata = seg6_pernet(net); 364 369 365 370 return rhashtable_init(&sdata->hmac_infos, &rht_params); 366 371 } 367 - 368 - void seg6_hmac_exit(void) 369 - { 370 - struct seg6_hmac_algo *algo = NULL; 371 - struct crypto_shash *tfm; 372 - struct shash_desc *shash; 373 - int i, alg_count, cpu; 374 - 375 - alg_count = ARRAY_SIZE(hmac_algos); 376 - for (i = 0; i < alg_count; i++) { 377 - algo = &hmac_algos[i]; 378 - 379 - if (algo->shashs) { 380 - for_each_possible_cpu(cpu) { 381 - shash = *per_cpu_ptr(algo->shashs, cpu); 382 - kfree(shash); 383 - } 384 - free_percpu(algo->shashs); 385 - } 386 - 387 - if (algo->tfms) { 388 - for_each_possible_cpu(cpu) { 389 - tfm = *per_cpu_ptr(algo->tfms, cpu); 390 - crypto_free_shash(tfm); 391 - } 392 - free_percpu(algo->tfms); 393 - } 394 - } 395 - } 396 - EXPORT_SYMBOL(seg6_hmac_exit); 397 372 398 373 void __net_exit seg6_hmac_net_exit(struct net *net) 399 374 {