1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016-2017 Intel Corporation 3 */ 4 5 /* 6 * Security Associations 7 */ 8 #include <sys/types.h> 9 #include <netinet/in.h> 10 #include <netinet/ip.h> 11 #include <netinet/ip6.h> 12 13 #include <rte_memzone.h> 14 #include <rte_crypto.h> 15 #include <rte_security.h> 16 #include <rte_cryptodev.h> 17 #include <rte_byteorder.h> 18 #include <rte_errno.h> 19 #include <rte_ip.h> 20 #include <rte_random.h> 21 #include <rte_ethdev.h> 22 23 #include "ipsec.h" 24 #include "esp.h" 25 #include "parser.h" 26 27 #define IPDEFTTL 64 28 29 struct supported_cipher_algo { 30 const char *keyword; 31 enum rte_crypto_cipher_algorithm algo; 32 uint16_t iv_len; 33 uint16_t block_size; 34 uint16_t key_len; 35 }; 36 37 struct supported_auth_algo { 38 const char *keyword; 39 enum rte_crypto_auth_algorithm algo; 40 uint16_t digest_len; 41 uint16_t key_len; 42 uint8_t key_not_req; 43 }; 44 45 struct supported_aead_algo { 46 const char *keyword; 47 enum rte_crypto_aead_algorithm algo; 48 uint16_t iv_len; 49 uint16_t block_size; 50 uint16_t digest_len; 51 uint16_t key_len; 52 uint8_t aad_len; 53 }; 54 55 56 const struct supported_cipher_algo cipher_algos[] = { 57 { 58 .keyword = "null", 59 .algo = RTE_CRYPTO_CIPHER_NULL, 60 .iv_len = 0, 61 .block_size = 4, 62 .key_len = 0 63 }, 64 { 65 .keyword = "aes-128-cbc", 66 .algo = RTE_CRYPTO_CIPHER_AES_CBC, 67 .iv_len = 16, 68 .block_size = 16, 69 .key_len = 16 70 }, 71 { 72 .keyword = "aes-256-cbc", 73 .algo = RTE_CRYPTO_CIPHER_AES_CBC, 74 .iv_len = 16, 75 .block_size = 16, 76 .key_len = 32 77 }, 78 { 79 .keyword = "aes-128-ctr", 80 .algo = RTE_CRYPTO_CIPHER_AES_CTR, 81 .iv_len = 8, 82 .block_size = 4, 83 .key_len = 20 84 }, 85 { 86 .keyword = "3des-cbc", 87 .algo = RTE_CRYPTO_CIPHER_3DES_CBC, 88 .iv_len = 8, 89 .block_size = 8, 90 .key_len = 24 91 } 92 }; 93 94 const struct supported_auth_algo auth_algos[] = { 95 { 96 .keyword = "null", 97 .algo = RTE_CRYPTO_AUTH_NULL, 98 .digest_len = 0, 99 .key_len = 0, 100 .key_not_req = 1 101 }, 102 { 103 .keyword = "sha1-hmac", 104 .algo = RTE_CRYPTO_AUTH_SHA1_HMAC, 105 .digest_len = 12, 106 .key_len = 20 107 }, 108 { 109 .keyword = "sha256-hmac", 110 .algo = RTE_CRYPTO_AUTH_SHA256_HMAC, 111 .digest_len = 12, 112 .key_len = 32 113 } 114 }; 115 116 const struct supported_aead_algo aead_algos[] = { 117 { 118 .keyword = "aes-128-gcm", 119 .algo = RTE_CRYPTO_AEAD_AES_GCM, 120 .iv_len = 8, 121 .block_size = 4, 122 .key_len = 20, 123 .digest_len = 16, 124 .aad_len = 8, 125 } 126 }; 127 128 static struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES]; 129 static uint32_t nb_sa_out; 130 131 static struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES]; 132 static uint32_t nb_sa_in; 133 134 static const struct supported_cipher_algo * 135 find_match_cipher_algo(const char *cipher_keyword) 136 { 137 size_t i; 138 139 for (i = 0; i < RTE_DIM(cipher_algos); i++) { 140 const struct supported_cipher_algo *algo = 141 &cipher_algos[i]; 142 143 if (strcmp(cipher_keyword, algo->keyword) == 0) 144 return algo; 145 } 146 147 return NULL; 148 } 149 150 static const struct supported_auth_algo * 151 find_match_auth_algo(const char *auth_keyword) 152 { 153 size_t i; 154 155 for (i = 0; i < RTE_DIM(auth_algos); i++) { 156 const struct supported_auth_algo *algo = 157 &auth_algos[i]; 158 159 if (strcmp(auth_keyword, algo->keyword) == 0) 160 return algo; 161 } 162 163 return NULL; 164 } 165 166 static const struct supported_aead_algo * 167 find_match_aead_algo(const char *aead_keyword) 168 { 169 size_t i; 170 171 for (i = 0; i < RTE_DIM(aead_algos); i++) { 172 const struct supported_aead_algo *algo = 173 &aead_algos[i]; 174 175 if (strcmp(aead_keyword, algo->keyword) == 0) 176 return algo; 177 } 178 179 return NULL; 180 } 181 182 /** parse_key_string 183 * parse x:x:x:x.... hex number key string into uint8_t *key 184 * return: 185 * > 0: number of bytes parsed 186 * 0: failed 187 */ 188 static uint32_t 189 parse_key_string(const char *key_str, uint8_t *key) 190 { 191 const char *pt_start = key_str, *pt_end = key_str; 192 uint32_t nb_bytes = 0; 193 194 while (pt_end != NULL) { 195 char sub_str[3] = {0}; 196 197 pt_end = strchr(pt_start, ':'); 198 199 if (pt_end == NULL) { 200 if (strlen(pt_start) > 2) 201 return 0; 202 strncpy(sub_str, pt_start, 2); 203 } else { 204 if (pt_end - pt_start > 2) 205 return 0; 206 207 strncpy(sub_str, pt_start, pt_end - pt_start); 208 pt_start = pt_end + 1; 209 } 210 211 key[nb_bytes++] = strtol(sub_str, NULL, 16); 212 } 213 214 return nb_bytes; 215 } 216 217 void 218 parse_sa_tokens(char **tokens, uint32_t n_tokens, 219 struct parse_status *status) 220 { 221 struct ipsec_sa *rule = NULL; 222 uint32_t ti; /*token index*/ 223 uint32_t *ri /*rule index*/; 224 uint32_t cipher_algo_p = 0; 225 uint32_t auth_algo_p = 0; 226 uint32_t aead_algo_p = 0; 227 uint32_t src_p = 0; 228 uint32_t dst_p = 0; 229 uint32_t mode_p = 0; 230 uint32_t type_p = 0; 231 uint32_t portid_p = 0; 232 233 if (strcmp(tokens[0], "in") == 0) { 234 ri = &nb_sa_in; 235 236 APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status, 237 "too many sa rules, abort insertion\n"); 238 if (status->status < 0) 239 return; 240 241 rule = &sa_in[*ri]; 242 } else { 243 ri = &nb_sa_out; 244 245 APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status, 246 "too many sa rules, abort insertion\n"); 247 if (status->status < 0) 248 return; 249 250 rule = &sa_out[*ri]; 251 } 252 253 /* spi number */ 254 APP_CHECK_TOKEN_IS_NUM(tokens, 1, status); 255 if (status->status < 0) 256 return; 257 if (atoi(tokens[1]) == INVALID_SPI) 258 return; 259 rule->spi = atoi(tokens[1]); 260 261 for (ti = 2; ti < n_tokens; ti++) { 262 if (strcmp(tokens[ti], "mode") == 0) { 263 APP_CHECK_PRESENCE(mode_p, tokens[ti], status); 264 if (status->status < 0) 265 return; 266 267 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 268 if (status->status < 0) 269 return; 270 271 if (strcmp(tokens[ti], "ipv4-tunnel") == 0) 272 rule->flags = IP4_TUNNEL; 273 else if (strcmp(tokens[ti], "ipv6-tunnel") == 0) 274 rule->flags = IP6_TUNNEL; 275 else if (strcmp(tokens[ti], "transport") == 0) 276 rule->flags = TRANSPORT; 277 else { 278 APP_CHECK(0, status, "unrecognized " 279 "input \"%s\"", tokens[ti]); 280 return; 281 } 282 283 mode_p = 1; 284 continue; 285 } 286 287 if (strcmp(tokens[ti], "cipher_algo") == 0) { 288 const struct supported_cipher_algo *algo; 289 uint32_t key_len; 290 291 APP_CHECK_PRESENCE(cipher_algo_p, tokens[ti], 292 status); 293 if (status->status < 0) 294 return; 295 296 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 297 if (status->status < 0) 298 return; 299 300 algo = find_match_cipher_algo(tokens[ti]); 301 302 APP_CHECK(algo != NULL, status, "unrecognized " 303 "input \"%s\"", tokens[ti]); 304 305 rule->cipher_algo = algo->algo; 306 rule->block_size = algo->block_size; 307 rule->iv_len = algo->iv_len; 308 rule->cipher_key_len = algo->key_len; 309 310 /* for NULL algorithm, no cipher key required */ 311 if (rule->cipher_algo == RTE_CRYPTO_CIPHER_NULL) { 312 cipher_algo_p = 1; 313 continue; 314 } 315 316 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 317 if (status->status < 0) 318 return; 319 320 APP_CHECK(strcmp(tokens[ti], "cipher_key") == 0, 321 status, "unrecognized input \"%s\", " 322 "expect \"cipher_key\"", tokens[ti]); 323 if (status->status < 0) 324 return; 325 326 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 327 if (status->status < 0) 328 return; 329 330 key_len = parse_key_string(tokens[ti], 331 rule->cipher_key); 332 APP_CHECK(key_len == rule->cipher_key_len, status, 333 "unrecognized input \"%s\"", tokens[ti]); 334 if (status->status < 0) 335 return; 336 337 if (algo->algo == RTE_CRYPTO_CIPHER_AES_CBC || 338 algo->algo == RTE_CRYPTO_CIPHER_3DES_CBC) 339 rule->salt = (uint32_t)rte_rand(); 340 341 if (algo->algo == RTE_CRYPTO_CIPHER_AES_CTR) { 342 key_len -= 4; 343 rule->cipher_key_len = key_len; 344 memcpy(&rule->salt, 345 &rule->cipher_key[key_len], 4); 346 } 347 348 cipher_algo_p = 1; 349 continue; 350 } 351 352 if (strcmp(tokens[ti], "auth_algo") == 0) { 353 const struct supported_auth_algo *algo; 354 uint32_t key_len; 355 356 APP_CHECK_PRESENCE(auth_algo_p, tokens[ti], 357 status); 358 if (status->status < 0) 359 return; 360 361 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 362 if (status->status < 0) 363 return; 364 365 algo = find_match_auth_algo(tokens[ti]); 366 APP_CHECK(algo != NULL, status, "unrecognized " 367 "input \"%s\"", tokens[ti]); 368 369 rule->auth_algo = algo->algo; 370 rule->auth_key_len = algo->key_len; 371 rule->digest_len = algo->digest_len; 372 373 /* NULL algorithm and combined algos do not 374 * require auth key 375 */ 376 if (algo->key_not_req) { 377 auth_algo_p = 1; 378 continue; 379 } 380 381 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 382 if (status->status < 0) 383 return; 384 385 APP_CHECK(strcmp(tokens[ti], "auth_key") == 0, 386 status, "unrecognized input \"%s\", " 387 "expect \"auth_key\"", tokens[ti]); 388 if (status->status < 0) 389 return; 390 391 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 392 if (status->status < 0) 393 return; 394 395 key_len = parse_key_string(tokens[ti], 396 rule->auth_key); 397 APP_CHECK(key_len == rule->auth_key_len, status, 398 "unrecognized input \"%s\"", tokens[ti]); 399 if (status->status < 0) 400 return; 401 402 auth_algo_p = 1; 403 continue; 404 } 405 406 if (strcmp(tokens[ti], "aead_algo") == 0) { 407 const struct supported_aead_algo *algo; 408 uint32_t key_len; 409 410 APP_CHECK_PRESENCE(aead_algo_p, tokens[ti], 411 status); 412 if (status->status < 0) 413 return; 414 415 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 416 if (status->status < 0) 417 return; 418 419 algo = find_match_aead_algo(tokens[ti]); 420 421 APP_CHECK(algo != NULL, status, "unrecognized " 422 "input \"%s\"", tokens[ti]); 423 424 rule->aead_algo = algo->algo; 425 rule->cipher_key_len = algo->key_len; 426 rule->digest_len = algo->digest_len; 427 rule->aad_len = algo->aad_len; 428 rule->block_size = algo->block_size; 429 rule->iv_len = algo->iv_len; 430 431 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 432 if (status->status < 0) 433 return; 434 435 APP_CHECK(strcmp(tokens[ti], "aead_key") == 0, 436 status, "unrecognized input \"%s\", " 437 "expect \"aead_key\"", tokens[ti]); 438 if (status->status < 0) 439 return; 440 441 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 442 if (status->status < 0) 443 return; 444 445 key_len = parse_key_string(tokens[ti], 446 rule->cipher_key); 447 APP_CHECK(key_len == rule->cipher_key_len, status, 448 "unrecognized input \"%s\"", tokens[ti]); 449 if (status->status < 0) 450 return; 451 452 key_len -= 4; 453 rule->cipher_key_len = key_len; 454 memcpy(&rule->salt, 455 &rule->cipher_key[key_len], 4); 456 457 aead_algo_p = 1; 458 continue; 459 } 460 461 if (strcmp(tokens[ti], "src") == 0) { 462 APP_CHECK_PRESENCE(src_p, tokens[ti], status); 463 if (status->status < 0) 464 return; 465 466 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 467 if (status->status < 0) 468 return; 469 470 if (rule->flags == IP4_TUNNEL) { 471 struct in_addr ip; 472 473 APP_CHECK(parse_ipv4_addr(tokens[ti], 474 &ip, NULL) == 0, status, 475 "unrecognized input \"%s\", " 476 "expect valid ipv4 addr", 477 tokens[ti]); 478 if (status->status < 0) 479 return; 480 rule->src.ip.ip4 = rte_bswap32( 481 (uint32_t)ip.s_addr); 482 } else if (rule->flags == IP6_TUNNEL) { 483 struct in6_addr ip; 484 485 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip, 486 NULL) == 0, status, 487 "unrecognized input \"%s\", " 488 "expect valid ipv6 addr", 489 tokens[ti]); 490 if (status->status < 0) 491 return; 492 memcpy(rule->src.ip.ip6.ip6_b, 493 ip.s6_addr, 16); 494 } else if (rule->flags == TRANSPORT) { 495 APP_CHECK(0, status, "unrecognized input " 496 "\"%s\"", tokens[ti]); 497 return; 498 } 499 500 src_p = 1; 501 continue; 502 } 503 504 if (strcmp(tokens[ti], "dst") == 0) { 505 APP_CHECK_PRESENCE(dst_p, tokens[ti], status); 506 if (status->status < 0) 507 return; 508 509 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 510 if (status->status < 0) 511 return; 512 513 if (rule->flags == IP4_TUNNEL) { 514 struct in_addr ip; 515 516 APP_CHECK(parse_ipv4_addr(tokens[ti], 517 &ip, NULL) == 0, status, 518 "unrecognized input \"%s\", " 519 "expect valid ipv4 addr", 520 tokens[ti]); 521 if (status->status < 0) 522 return; 523 rule->dst.ip.ip4 = rte_bswap32( 524 (uint32_t)ip.s_addr); 525 } else if (rule->flags == IP6_TUNNEL) { 526 struct in6_addr ip; 527 528 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip, 529 NULL) == 0, status, 530 "unrecognized input \"%s\", " 531 "expect valid ipv6 addr", 532 tokens[ti]); 533 if (status->status < 0) 534 return; 535 memcpy(rule->dst.ip.ip6.ip6_b, ip.s6_addr, 16); 536 } else if (rule->flags == TRANSPORT) { 537 APP_CHECK(0, status, "unrecognized " 538 "input \"%s\"", tokens[ti]); 539 return; 540 } 541 542 dst_p = 1; 543 continue; 544 } 545 546 if (strcmp(tokens[ti], "type") == 0) { 547 APP_CHECK_PRESENCE(type_p, tokens[ti], status); 548 if (status->status < 0) 549 return; 550 551 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 552 if (status->status < 0) 553 return; 554 555 if (strcmp(tokens[ti], "inline-crypto-offload") == 0) 556 rule->type = 557 RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO; 558 else if (strcmp(tokens[ti], 559 "inline-protocol-offload") == 0) 560 rule->type = 561 RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL; 562 else if (strcmp(tokens[ti], 563 "lookaside-protocol-offload") == 0) 564 rule->type = 565 RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL; 566 else if (strcmp(tokens[ti], "no-offload") == 0) 567 rule->type = RTE_SECURITY_ACTION_TYPE_NONE; 568 else { 569 APP_CHECK(0, status, "Invalid input \"%s\"", 570 tokens[ti]); 571 return; 572 } 573 574 type_p = 1; 575 continue; 576 } 577 578 if (strcmp(tokens[ti], "port_id") == 0) { 579 APP_CHECK_PRESENCE(portid_p, tokens[ti], status); 580 if (status->status < 0) 581 return; 582 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 583 if (status->status < 0) 584 return; 585 rule->portid = atoi(tokens[ti]); 586 if (status->status < 0) 587 return; 588 portid_p = 1; 589 continue; 590 } 591 592 /* unrecognizeable input */ 593 APP_CHECK(0, status, "unrecognized input \"%s\"", 594 tokens[ti]); 595 return; 596 } 597 598 if (aead_algo_p) { 599 APP_CHECK(cipher_algo_p == 0, status, 600 "AEAD used, no need for cipher options"); 601 if (status->status < 0) 602 return; 603 604 APP_CHECK(auth_algo_p == 0, status, 605 "AEAD used, no need for auth options"); 606 if (status->status < 0) 607 return; 608 } else { 609 APP_CHECK(cipher_algo_p == 1, status, "missing cipher or AEAD options"); 610 if (status->status < 0) 611 return; 612 613 APP_CHECK(auth_algo_p == 1, status, "missing auth or AEAD options"); 614 if (status->status < 0) 615 return; 616 } 617 618 APP_CHECK(mode_p == 1, status, "missing mode option"); 619 if (status->status < 0) 620 return; 621 622 if ((rule->type != RTE_SECURITY_ACTION_TYPE_NONE) && (portid_p == 0)) 623 printf("Missing portid option, falling back to non-offload\n"); 624 625 if (!type_p || !portid_p) { 626 rule->type = RTE_SECURITY_ACTION_TYPE_NONE; 627 rule->portid = -1; 628 } 629 630 *ri = *ri + 1; 631 } 632 633 static void 634 print_one_sa_rule(const struct ipsec_sa *sa, int inbound) 635 { 636 uint32_t i; 637 uint8_t a, b, c, d; 638 639 printf("\tspi_%s(%3u):", inbound?"in":"out", sa->spi); 640 641 for (i = 0; i < RTE_DIM(cipher_algos); i++) { 642 if (cipher_algos[i].algo == sa->cipher_algo && 643 cipher_algos[i].key_len == sa->cipher_key_len) { 644 printf("%s ", cipher_algos[i].keyword); 645 break; 646 } 647 } 648 649 for (i = 0; i < RTE_DIM(auth_algos); i++) { 650 if (auth_algos[i].algo == sa->auth_algo) { 651 printf("%s ", auth_algos[i].keyword); 652 break; 653 } 654 } 655 656 for (i = 0; i < RTE_DIM(aead_algos); i++) { 657 if (aead_algos[i].algo == sa->aead_algo) { 658 printf("%s ", aead_algos[i].keyword); 659 break; 660 } 661 } 662 663 printf("mode:"); 664 665 switch (sa->flags) { 666 case IP4_TUNNEL: 667 printf("IP4Tunnel "); 668 uint32_t_to_char(sa->src.ip.ip4, &a, &b, &c, &d); 669 printf("%hhu.%hhu.%hhu.%hhu ", d, c, b, a); 670 uint32_t_to_char(sa->dst.ip.ip4, &a, &b, &c, &d); 671 printf("%hhu.%hhu.%hhu.%hhu", d, c, b, a); 672 break; 673 case IP6_TUNNEL: 674 printf("IP6Tunnel "); 675 for (i = 0; i < 16; i++) { 676 if (i % 2 && i != 15) 677 printf("%.2x:", sa->src.ip.ip6.ip6_b[i]); 678 else 679 printf("%.2x", sa->src.ip.ip6.ip6_b[i]); 680 } 681 printf(" "); 682 for (i = 0; i < 16; i++) { 683 if (i % 2 && i != 15) 684 printf("%.2x:", sa->dst.ip.ip6.ip6_b[i]); 685 else 686 printf("%.2x", sa->dst.ip.ip6.ip6_b[i]); 687 } 688 break; 689 case TRANSPORT: 690 printf("Transport "); 691 break; 692 } 693 printf(" type:"); 694 switch (sa->type) { 695 case RTE_SECURITY_ACTION_TYPE_NONE: 696 printf("no-offload "); 697 break; 698 case RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO: 699 printf("inline-crypto-offload "); 700 break; 701 case RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL: 702 printf("inline-protocol-offload "); 703 break; 704 case RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL: 705 printf("lookaside-protocol-offload "); 706 break; 707 } 708 printf("\n"); 709 } 710 711 struct sa_ctx { 712 struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES]; 713 union { 714 struct { 715 struct rte_crypto_sym_xform a; 716 struct rte_crypto_sym_xform b; 717 }; 718 } xf[IPSEC_SA_MAX_ENTRIES]; 719 }; 720 721 static struct sa_ctx * 722 sa_create(const char *name, int32_t socket_id) 723 { 724 char s[PATH_MAX]; 725 struct sa_ctx *sa_ctx; 726 uint32_t mz_size; 727 const struct rte_memzone *mz; 728 729 snprintf(s, sizeof(s), "%s_%u", name, socket_id); 730 731 /* Create SA array table */ 732 printf("Creating SA context with %u maximum entries on socket %d\n", 733 IPSEC_SA_MAX_ENTRIES, socket_id); 734 735 mz_size = sizeof(struct sa_ctx); 736 mz = rte_memzone_reserve(s, mz_size, socket_id, 737 RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY); 738 if (mz == NULL) { 739 printf("Failed to allocate SA DB memory\n"); 740 rte_errno = -ENOMEM; 741 return NULL; 742 } 743 744 sa_ctx = (struct sa_ctx *)mz->addr; 745 746 return sa_ctx; 747 } 748 749 static int 750 check_eth_dev_caps(uint16_t portid, uint32_t inbound) 751 { 752 struct rte_eth_dev_info dev_info; 753 754 rte_eth_dev_info_get(portid, &dev_info); 755 756 if (inbound) { 757 if ((dev_info.rx_offload_capa & 758 DEV_RX_OFFLOAD_SECURITY) == 0) { 759 RTE_LOG(WARNING, PORT, 760 "hardware RX IPSec offload is not supported\n"); 761 return -EINVAL; 762 } 763 764 } else { /* outbound */ 765 if ((dev_info.tx_offload_capa & 766 DEV_TX_OFFLOAD_SECURITY) == 0) { 767 RTE_LOG(WARNING, PORT, 768 "hardware TX IPSec offload is not supported\n"); 769 return -EINVAL; 770 } 771 } 772 return 0; 773 } 774 775 776 static int 777 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], 778 uint32_t nb_entries, uint32_t inbound) 779 { 780 struct ipsec_sa *sa; 781 uint32_t i, idx; 782 uint16_t iv_length; 783 784 for (i = 0; i < nb_entries; i++) { 785 idx = SPI2IDX(entries[i].spi); 786 sa = &sa_ctx->sa[idx]; 787 if (sa->spi != 0) { 788 printf("Index %u already in use by SPI %u\n", 789 idx, sa->spi); 790 return -EINVAL; 791 } 792 *sa = entries[i]; 793 sa->seq = 0; 794 795 if (sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_PROTOCOL || 796 sa->type == RTE_SECURITY_ACTION_TYPE_INLINE_CRYPTO) { 797 if (check_eth_dev_caps(sa->portid, inbound)) 798 return -EINVAL; 799 } 800 801 sa->direction = (inbound == 1) ? 802 RTE_SECURITY_IPSEC_SA_DIR_INGRESS : 803 RTE_SECURITY_IPSEC_SA_DIR_EGRESS; 804 805 switch (sa->flags) { 806 case IP4_TUNNEL: 807 sa->src.ip.ip4 = rte_cpu_to_be_32(sa->src.ip.ip4); 808 sa->dst.ip.ip4 = rte_cpu_to_be_32(sa->dst.ip.ip4); 809 } 810 811 if (sa->aead_algo == RTE_CRYPTO_AEAD_AES_GCM) { 812 iv_length = 16; 813 814 sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AEAD; 815 sa_ctx->xf[idx].a.aead.algo = sa->aead_algo; 816 sa_ctx->xf[idx].a.aead.key.data = sa->cipher_key; 817 sa_ctx->xf[idx].a.aead.key.length = 818 sa->cipher_key_len; 819 sa_ctx->xf[idx].a.aead.op = (inbound == 1) ? 820 RTE_CRYPTO_AEAD_OP_DECRYPT : 821 RTE_CRYPTO_AEAD_OP_ENCRYPT; 822 sa_ctx->xf[idx].a.next = NULL; 823 sa_ctx->xf[idx].a.aead.iv.offset = IV_OFFSET; 824 sa_ctx->xf[idx].a.aead.iv.length = iv_length; 825 sa_ctx->xf[idx].a.aead.aad_length = 826 sa->aad_len; 827 sa_ctx->xf[idx].a.aead.digest_length = 828 sa->digest_len; 829 830 sa->xforms = &sa_ctx->xf[idx].a; 831 832 print_one_sa_rule(sa, inbound); 833 } else { 834 switch (sa->cipher_algo) { 835 case RTE_CRYPTO_CIPHER_NULL: 836 case RTE_CRYPTO_CIPHER_3DES_CBC: 837 case RTE_CRYPTO_CIPHER_AES_CBC: 838 iv_length = sa->iv_len; 839 break; 840 case RTE_CRYPTO_CIPHER_AES_CTR: 841 iv_length = 16; 842 break; 843 default: 844 RTE_LOG(ERR, IPSEC_ESP, 845 "unsupported cipher algorithm %u\n", 846 sa->cipher_algo); 847 return -EINVAL; 848 } 849 850 if (inbound) { 851 sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_CIPHER; 852 sa_ctx->xf[idx].b.cipher.algo = sa->cipher_algo; 853 sa_ctx->xf[idx].b.cipher.key.data = sa->cipher_key; 854 sa_ctx->xf[idx].b.cipher.key.length = 855 sa->cipher_key_len; 856 sa_ctx->xf[idx].b.cipher.op = 857 RTE_CRYPTO_CIPHER_OP_DECRYPT; 858 sa_ctx->xf[idx].b.next = NULL; 859 sa_ctx->xf[idx].b.cipher.iv.offset = IV_OFFSET; 860 sa_ctx->xf[idx].b.cipher.iv.length = iv_length; 861 862 sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AUTH; 863 sa_ctx->xf[idx].a.auth.algo = sa->auth_algo; 864 sa_ctx->xf[idx].a.auth.key.data = sa->auth_key; 865 sa_ctx->xf[idx].a.auth.key.length = 866 sa->auth_key_len; 867 sa_ctx->xf[idx].a.auth.digest_length = 868 sa->digest_len; 869 sa_ctx->xf[idx].a.auth.op = 870 RTE_CRYPTO_AUTH_OP_VERIFY; 871 } else { /* outbound */ 872 sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_CIPHER; 873 sa_ctx->xf[idx].a.cipher.algo = sa->cipher_algo; 874 sa_ctx->xf[idx].a.cipher.key.data = sa->cipher_key; 875 sa_ctx->xf[idx].a.cipher.key.length = 876 sa->cipher_key_len; 877 sa_ctx->xf[idx].a.cipher.op = 878 RTE_CRYPTO_CIPHER_OP_ENCRYPT; 879 sa_ctx->xf[idx].a.next = NULL; 880 sa_ctx->xf[idx].a.cipher.iv.offset = IV_OFFSET; 881 sa_ctx->xf[idx].a.cipher.iv.length = iv_length; 882 883 sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_AUTH; 884 sa_ctx->xf[idx].b.auth.algo = sa->auth_algo; 885 sa_ctx->xf[idx].b.auth.key.data = sa->auth_key; 886 sa_ctx->xf[idx].b.auth.key.length = 887 sa->auth_key_len; 888 sa_ctx->xf[idx].b.auth.digest_length = 889 sa->digest_len; 890 sa_ctx->xf[idx].b.auth.op = 891 RTE_CRYPTO_AUTH_OP_GENERATE; 892 } 893 894 sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b; 895 sa_ctx->xf[idx].b.next = NULL; 896 sa->xforms = &sa_ctx->xf[idx].a; 897 898 print_one_sa_rule(sa, inbound); 899 } 900 } 901 902 return 0; 903 } 904 905 static inline int 906 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], 907 uint32_t nb_entries) 908 { 909 return sa_add_rules(sa_ctx, entries, nb_entries, 0); 910 } 911 912 static inline int 913 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[], 914 uint32_t nb_entries) 915 { 916 return sa_add_rules(sa_ctx, entries, nb_entries, 1); 917 } 918 919 /* 920 * Walk through all SA rules to find an SA with given SPI 921 */ 922 int 923 sa_spi_present(uint32_t spi, int inbound) 924 { 925 uint32_t i, num; 926 const struct ipsec_sa *sar; 927 928 if (inbound != 0) { 929 sar = sa_in; 930 num = nb_sa_in; 931 } else { 932 sar = sa_out; 933 num = nb_sa_out; 934 } 935 936 for (i = 0; i != num; i++) { 937 if (sar[i].spi == spi) 938 return i; 939 } 940 941 return -ENOENT; 942 } 943 944 void 945 sa_init(struct socket_ctx *ctx, int32_t socket_id) 946 { 947 const char *name; 948 949 if (ctx == NULL) 950 rte_exit(EXIT_FAILURE, "NULL context.\n"); 951 952 if (ctx->sa_in != NULL) 953 rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already " 954 "initialized\n", socket_id); 955 956 if (ctx->sa_out != NULL) 957 rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already " 958 "initialized\n", socket_id); 959 960 if (nb_sa_in > 0) { 961 name = "sa_in"; 962 ctx->sa_in = sa_create(name, socket_id); 963 if (ctx->sa_in == NULL) 964 rte_exit(EXIT_FAILURE, "Error [%d] creating SA " 965 "context %s in socket %d\n", rte_errno, 966 name, socket_id); 967 968 sa_in_add_rules(ctx->sa_in, sa_in, nb_sa_in); 969 } else 970 RTE_LOG(WARNING, IPSEC, "No SA Inbound rule specified\n"); 971 972 if (nb_sa_out > 0) { 973 name = "sa_out"; 974 ctx->sa_out = sa_create(name, socket_id); 975 if (ctx->sa_out == NULL) 976 rte_exit(EXIT_FAILURE, "Error [%d] creating SA " 977 "context %s in socket %d\n", rte_errno, 978 name, socket_id); 979 980 sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out); 981 } else 982 RTE_LOG(WARNING, IPSEC, "No SA Outbound rule " 983 "specified\n"); 984 } 985 986 int 987 inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx) 988 { 989 struct ipsec_mbuf_metadata *priv; 990 struct ipsec_sa *sa; 991 992 priv = get_priv(m); 993 sa = priv->sa; 994 if (sa != NULL) 995 return (sa_ctx->sa[sa_idx].spi == sa->spi); 996 997 RTE_LOG(ERR, IPSEC, "SA not saved in private data\n"); 998 return 0; 999 } 1000 1001 static inline void 1002 single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt, 1003 struct ipsec_sa **sa_ret) 1004 { 1005 struct esp_hdr *esp; 1006 struct ip *ip; 1007 uint32_t *src4_addr; 1008 uint8_t *src6_addr; 1009 struct ipsec_sa *sa; 1010 1011 *sa_ret = NULL; 1012 1013 ip = rte_pktmbuf_mtod(pkt, struct ip *); 1014 if (ip->ip_v == IPVERSION) 1015 esp = (struct esp_hdr *)(ip + 1); 1016 else 1017 esp = (struct esp_hdr *)(((struct ip6_hdr *)ip) + 1); 1018 1019 if (esp->spi == INVALID_SPI) 1020 return; 1021 1022 sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))]; 1023 if (rte_be_to_cpu_32(esp->spi) != sa->spi) 1024 return; 1025 1026 switch (sa->flags) { 1027 case IP4_TUNNEL: 1028 src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src)); 1029 if ((ip->ip_v == IPVERSION) && 1030 (sa->src.ip.ip4 == *src4_addr) && 1031 (sa->dst.ip.ip4 == *(src4_addr + 1))) 1032 *sa_ret = sa; 1033 break; 1034 case IP6_TUNNEL: 1035 src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src)); 1036 if ((ip->ip_v == IP6_VERSION) && 1037 !memcmp(&sa->src.ip.ip6.ip6, src6_addr, 16) && 1038 !memcmp(&sa->dst.ip.ip6.ip6, src6_addr + 16, 16)) 1039 *sa_ret = sa; 1040 break; 1041 case TRANSPORT: 1042 *sa_ret = sa; 1043 } 1044 } 1045 1046 void 1047 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[], 1048 struct ipsec_sa *sa[], uint16_t nb_pkts) 1049 { 1050 uint32_t i; 1051 1052 for (i = 0; i < nb_pkts; i++) 1053 single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]); 1054 } 1055 1056 void 1057 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[], 1058 struct ipsec_sa *sa[], uint16_t nb_pkts) 1059 { 1060 uint32_t i; 1061 1062 for (i = 0; i < nb_pkts; i++) 1063 sa[i] = &sa_ctx->sa[sa_idx[i]]; 1064 } 1065