1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2016 Intel Corporation 3 */ 4 5 /* 6 * Security Policies 7 */ 8 #include <sys/types.h> 9 #include <netinet/in.h> 10 #include <netinet/ip.h> 11 12 #include <rte_acl.h> 13 #include <rte_ip.h> 14 15 #include "ipsec.h" 16 #include "parser.h" 17 18 #define INIT_ACL_RULE_NUM 128 19 20 #define IPV4_DST_FROM_SP(acr) \ 21 (rte_cpu_to_be_32((acr).field[DST_FIELD_IPV4].value.u32)) 22 23 #define IPV4_SRC_FROM_SP(acr) \ 24 (rte_cpu_to_be_32((acr).field[SRC_FIELD_IPV4].value.u32)) 25 26 #define IPV4_DST_MASK_FROM_SP(acr) \ 27 ((acr).field[DST_FIELD_IPV4].mask_range.u32) 28 29 #define IPV4_SRC_MASK_FROM_SP(acr) \ 30 ((acr).field[SRC_FIELD_IPV4].mask_range.u32) 31 32 /* 33 * Rule and trace formats definitions. 34 */ 35 enum { 36 PROTO_FIELD_IPV4, 37 SRC_FIELD_IPV4, 38 DST_FIELD_IPV4, 39 SRCP_FIELD_IPV4, 40 DSTP_FIELD_IPV4, 41 NUM_FIELDS_IPV4 42 }; 43 44 /* 45 * That effectively defines order of IPV4 classifications: 46 * - PROTO 47 * - SRC IP ADDRESS 48 * - DST IP ADDRESS 49 * - PORTS (SRC and DST) 50 */ 51 enum { 52 RTE_ACL_IPV4_PROTO, 53 RTE_ACL_IPV4_SRC, 54 RTE_ACL_IPV4_DST, 55 RTE_ACL_IPV4_PORTS, 56 RTE_ACL_IPV4_NUM 57 }; 58 59 static struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = { 60 { 61 .type = RTE_ACL_FIELD_TYPE_BITMASK, 62 .size = sizeof(uint8_t), 63 .field_index = PROTO_FIELD_IPV4, 64 .input_index = RTE_ACL_IPV4_PROTO, 65 .offset = 0, 66 }, 67 { 68 .type = RTE_ACL_FIELD_TYPE_MASK, 69 .size = sizeof(uint32_t), 70 .field_index = SRC_FIELD_IPV4, 71 .input_index = RTE_ACL_IPV4_SRC, 72 .offset = offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p) 73 }, 74 { 75 .type = RTE_ACL_FIELD_TYPE_MASK, 76 .size = sizeof(uint32_t), 77 .field_index = DST_FIELD_IPV4, 78 .input_index = RTE_ACL_IPV4_DST, 79 .offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p) 80 }, 81 { 82 .type = RTE_ACL_FIELD_TYPE_RANGE, 83 .size = sizeof(uint16_t), 84 .field_index = SRCP_FIELD_IPV4, 85 .input_index = RTE_ACL_IPV4_PORTS, 86 .offset = sizeof(struct ip) - offsetof(struct ip, ip_p) 87 }, 88 { 89 .type = RTE_ACL_FIELD_TYPE_RANGE, 90 .size = sizeof(uint16_t), 91 .field_index = DSTP_FIELD_IPV4, 92 .input_index = RTE_ACL_IPV4_PORTS, 93 .offset = sizeof(struct ip) - offsetof(struct ip, ip_p) + 94 sizeof(uint16_t) 95 }, 96 }; 97 98 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs)); 99 100 static struct acl4_rules *acl4_rules_out; 101 static uint32_t nb_acl4_rules_out; 102 static uint32_t sp_out_sz; 103 104 static struct acl4_rules *acl4_rules_in; 105 static uint32_t nb_acl4_rules_in; 106 static uint32_t sp_in_sz; 107 108 static int 109 extend_sp_arr(struct acl4_rules **sp_tbl, uint32_t cur_cnt, uint32_t *cur_sz) 110 { 111 if (*sp_tbl == NULL) { 112 *sp_tbl = calloc(INIT_ACL_RULE_NUM, sizeof(struct acl4_rules)); 113 if (*sp_tbl == NULL) 114 return -1; 115 *cur_sz = INIT_ACL_RULE_NUM; 116 return 0; 117 } 118 119 if (cur_cnt >= *cur_sz) { 120 *sp_tbl = realloc(*sp_tbl, 121 *cur_sz * sizeof(struct acl4_rules) * 2); 122 if (*sp_tbl == NULL) 123 return -1; 124 /* clean reallocated extra space */ 125 memset(&(*sp_tbl)[*cur_sz], 0, 126 *cur_sz * sizeof(struct acl4_rules)); 127 *cur_sz *= 2; 128 } 129 130 return 0; 131 } 132 133 134 void 135 parse_sp4_tokens(char **tokens, uint32_t n_tokens, 136 struct parse_status *status) 137 { 138 struct acl4_rules *rule_ipv4 = NULL; 139 140 uint32_t *ri = NULL; /* rule index */ 141 uint32_t ti = 0; /* token index */ 142 uint32_t tv; 143 144 uint32_t esp_p = 0; 145 uint32_t protect_p = 0; 146 uint32_t bypass_p = 0; 147 uint32_t discard_p = 0; 148 uint32_t pri_p = 0; 149 uint32_t src_p = 0; 150 uint32_t dst_p = 0; 151 uint32_t proto_p = 0; 152 uint32_t sport_p = 0; 153 uint32_t dport_p = 0; 154 155 if (strcmp(tokens[1], "in") == 0) { 156 ri = &nb_acl4_rules_in; 157 158 if (extend_sp_arr(&acl4_rules_in, nb_acl4_rules_in, 159 &sp_in_sz) < 0) 160 return; 161 162 rule_ipv4 = &acl4_rules_in[*ri]; 163 164 } else if (strcmp(tokens[1], "out") == 0) { 165 ri = &nb_acl4_rules_out; 166 167 if (extend_sp_arr(&acl4_rules_out, nb_acl4_rules_out, 168 &sp_out_sz) < 0) 169 return; 170 171 rule_ipv4 = &acl4_rules_out[*ri]; 172 } else { 173 APP_CHECK(0, status, "unrecognized input \"%s\", expect" 174 " \"in\" or \"out\"\n", tokens[ti]); 175 return; 176 } 177 178 rule_ipv4->data.category_mask = 1; 179 180 for (ti = 2; ti < n_tokens; ti++) { 181 if (strcmp(tokens[ti], "esp") == 0) { 182 /* currently do nothing */ 183 APP_CHECK_PRESENCE(esp_p, tokens[ti], status); 184 if (status->status < 0) 185 return; 186 esp_p = 1; 187 continue; 188 } 189 190 if (strcmp(tokens[ti], "protect") == 0) { 191 APP_CHECK_PRESENCE(protect_p, tokens[ti], status); 192 if (status->status < 0) 193 return; 194 APP_CHECK(bypass_p == 0, status, "conflict item " 195 "between \"%s\" and \"%s\"", tokens[ti], 196 "bypass"); 197 if (status->status < 0) 198 return; 199 APP_CHECK(discard_p == 0, status, "conflict item " 200 "between \"%s\" and \"%s\"", tokens[ti], 201 "discard"); 202 if (status->status < 0) 203 return; 204 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 205 if (status->status < 0) 206 return; 207 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 208 if (status->status < 0) 209 return; 210 211 tv = atoi(tokens[ti]); 212 APP_CHECK(tv != DISCARD && tv != BYPASS, status, 213 "invalid SPI: %s", tokens[ti]); 214 if (status->status < 0) 215 return; 216 rule_ipv4->data.userdata = tv; 217 218 protect_p = 1; 219 continue; 220 } 221 222 if (strcmp(tokens[ti], "bypass") == 0) { 223 APP_CHECK_PRESENCE(bypass_p, tokens[ti], status); 224 if (status->status < 0) 225 return; 226 APP_CHECK(protect_p == 0, status, "conflict item " 227 "between \"%s\" and \"%s\"", tokens[ti], 228 "protect"); 229 if (status->status < 0) 230 return; 231 APP_CHECK(discard_p == 0, status, "conflict item " 232 "between \"%s\" and \"%s\"", tokens[ti], 233 "discard"); 234 if (status->status < 0) 235 return; 236 237 rule_ipv4->data.userdata = BYPASS; 238 239 bypass_p = 1; 240 continue; 241 } 242 243 if (strcmp(tokens[ti], "discard") == 0) { 244 APP_CHECK_PRESENCE(discard_p, tokens[ti], status); 245 if (status->status < 0) 246 return; 247 APP_CHECK(protect_p == 0, status, "conflict item " 248 "between \"%s\" and \"%s\"", tokens[ti], 249 "protect"); 250 if (status->status < 0) 251 return; 252 APP_CHECK(bypass_p == 0, status, "conflict item " 253 "between \"%s\" and \"%s\"", tokens[ti], 254 "discard"); 255 if (status->status < 0) 256 return; 257 258 rule_ipv4->data.userdata = DISCARD; 259 260 discard_p = 1; 261 continue; 262 } 263 264 if (strcmp(tokens[ti], "pri") == 0) { 265 APP_CHECK_PRESENCE(pri_p, tokens[ti], status); 266 if (status->status < 0) 267 return; 268 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 269 if (status->status < 0) 270 return; 271 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 272 if (status->status < 0) 273 return; 274 275 rule_ipv4->data.priority = atoi(tokens[ti]); 276 277 pri_p = 1; 278 continue; 279 } 280 281 if (strcmp(tokens[ti], "src") == 0) { 282 struct in_addr ip; 283 uint32_t depth; 284 285 APP_CHECK_PRESENCE(src_p, tokens[ti], status); 286 if (status->status < 0) 287 return; 288 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 289 if (status->status < 0) 290 return; 291 292 APP_CHECK(parse_ipv4_addr(tokens[ti], &ip, 293 &depth) == 0, status, "unrecognized " 294 "input \"%s\", expect valid ipv4 addr", 295 tokens[ti]); 296 if (status->status < 0) 297 return; 298 299 rule_ipv4->field[1].value.u32 = 300 rte_bswap32(ip.s_addr); 301 rule_ipv4->field[1].mask_range.u32 = 302 depth; 303 304 src_p = 1; 305 continue; 306 } 307 308 if (strcmp(tokens[ti], "dst") == 0) { 309 struct in_addr ip; 310 uint32_t depth; 311 312 APP_CHECK_PRESENCE(dst_p, tokens[ti], status); 313 if (status->status < 0) 314 return; 315 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 316 if (status->status < 0) 317 return; 318 APP_CHECK(parse_ipv4_addr(tokens[ti], &ip, 319 &depth) == 0, status, "unrecognized " 320 "input \"%s\", expect valid ipv4 addr", 321 tokens[ti]); 322 if (status->status < 0) 323 return; 324 325 rule_ipv4->field[2].value.u32 = 326 rte_bswap32(ip.s_addr); 327 rule_ipv4->field[2].mask_range.u32 = 328 depth; 329 330 dst_p = 1; 331 continue; 332 } 333 334 if (strcmp(tokens[ti], "proto") == 0) { 335 uint16_t low, high; 336 337 APP_CHECK_PRESENCE(proto_p, tokens[ti], status); 338 if (status->status < 0) 339 return; 340 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 341 if (status->status < 0) 342 return; 343 344 APP_CHECK(parse_range(tokens[ti], &low, &high) 345 == 0, status, "unrecognized input \"%s\"" 346 ", expect \"from:to\"", tokens[ti]); 347 if (status->status < 0) 348 return; 349 APP_CHECK(low <= 0xff, status, "proto low " 350 "over-limit"); 351 if (status->status < 0) 352 return; 353 APP_CHECK(high <= 0xff, status, "proto high " 354 "over-limit"); 355 if (status->status < 0) 356 return; 357 358 rule_ipv4->field[0].value.u8 = (uint8_t)low; 359 rule_ipv4->field[0].mask_range.u8 = (uint8_t)high; 360 361 proto_p = 1; 362 continue; 363 } 364 365 if (strcmp(tokens[ti], "sport") == 0) { 366 uint16_t port_low, port_high; 367 368 APP_CHECK_PRESENCE(sport_p, tokens[ti], status); 369 if (status->status < 0) 370 return; 371 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 372 if (status->status < 0) 373 return; 374 375 APP_CHECK(parse_range(tokens[ti], &port_low, 376 &port_high) == 0, status, "unrecognized " 377 "input \"%s\", expect \"port_from:" 378 "port_to\"", tokens[ti]); 379 if (status->status < 0) 380 return; 381 382 rule_ipv4->field[3].value.u16 = port_low; 383 rule_ipv4->field[3].mask_range.u16 = port_high; 384 385 sport_p = 1; 386 continue; 387 } 388 389 if (strcmp(tokens[ti], "dport") == 0) { 390 uint16_t port_low, port_high; 391 392 APP_CHECK_PRESENCE(dport_p, tokens[ti], status); 393 if (status->status < 0) 394 return; 395 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 396 if (status->status < 0) 397 return; 398 399 APP_CHECK(parse_range(tokens[ti], &port_low, 400 &port_high) == 0, status, "unrecognized " 401 "input \"%s\", expect \"port_from:" 402 "port_to\"", tokens[ti]); 403 if (status->status < 0) 404 return; 405 406 rule_ipv4->field[4].value.u16 = port_low; 407 rule_ipv4->field[4].mask_range.u16 = port_high; 408 409 dport_p = 1; 410 continue; 411 } 412 413 /* unrecognizeable input */ 414 APP_CHECK(0, status, "unrecognized input \"%s\"", 415 tokens[ti]); 416 return; 417 } 418 419 /* check if argument(s) are missing */ 420 APP_CHECK(esp_p == 1, status, "missing argument \"esp\""); 421 if (status->status < 0) 422 return; 423 424 APP_CHECK(protect_p | bypass_p | discard_p, status, "missing " 425 "argument \"protect\", \"bypass\", or \"discard\""); 426 if (status->status < 0) 427 return; 428 429 *ri = *ri + 1; 430 } 431 432 static void 433 print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra) 434 { 435 uint8_t a, b, c, d; 436 437 uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32, 438 &a, &b, &c, &d); 439 printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d, 440 rule->field[SRC_FIELD_IPV4].mask_range.u32); 441 uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32, 442 &a, &b, &c, &d); 443 printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d, 444 rule->field[DST_FIELD_IPV4].mask_range.u32); 445 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ", 446 rule->field[SRCP_FIELD_IPV4].value.u16, 447 rule->field[SRCP_FIELD_IPV4].mask_range.u16, 448 rule->field[DSTP_FIELD_IPV4].value.u16, 449 rule->field[DSTP_FIELD_IPV4].mask_range.u16, 450 rule->field[PROTO_FIELD_IPV4].value.u8, 451 rule->field[PROTO_FIELD_IPV4].mask_range.u8); 452 if (extra) 453 printf("0x%x-0x%x-0x%x ", 454 rule->data.category_mask, 455 rule->data.priority, 456 rule->data.userdata); 457 } 458 459 static inline void 460 dump_ip4_rules(const struct acl4_rules *rule, int32_t num, int32_t extra) 461 { 462 int32_t i; 463 464 for (i = 0; i < num; i++, rule++) { 465 printf("\t%d:", i + 1); 466 print_one_ip4_rule(rule, extra); 467 printf("\n"); 468 } 469 } 470 471 static struct rte_acl_ctx * 472 acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules, 473 uint32_t rules_nb) 474 { 475 char s[PATH_MAX]; 476 struct rte_acl_param acl_param; 477 struct rte_acl_config acl_build_param; 478 struct rte_acl_ctx *ctx; 479 480 printf("Creating SP context with %u rules\n", rules_nb); 481 482 memset(&acl_param, 0, sizeof(acl_param)); 483 484 /* Create ACL contexts */ 485 snprintf(s, sizeof(s), "%s_%d", name, socketid); 486 487 printf("IPv4 %s entries [%u]:\n", s, rules_nb); 488 dump_ip4_rules(rules, rules_nb, 1); 489 490 acl_param.name = s; 491 acl_param.socket_id = socketid; 492 acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip4_defs)); 493 acl_param.max_rule_num = rules_nb; 494 495 ctx = rte_acl_create(&acl_param); 496 if (ctx == NULL) 497 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n"); 498 499 if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules, 500 rules_nb) < 0) 501 rte_exit(EXIT_FAILURE, "add rules failed\n"); 502 503 /* Perform builds */ 504 memset(&acl_build_param, 0, sizeof(acl_build_param)); 505 506 acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES; 507 acl_build_param.num_fields = RTE_DIM(ip4_defs); 508 memcpy(&acl_build_param.defs, ip4_defs, sizeof(ip4_defs)); 509 510 if (rte_acl_build(ctx, &acl_build_param) != 0) 511 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n"); 512 513 rte_acl_dump(ctx); 514 515 return ctx; 516 } 517 518 /* 519 * check that for each rule it's SPI has a correspondent entry in SAD 520 */ 521 static int 522 check_spi_value(struct sa_ctx *sa_ctx, int inbound) 523 { 524 uint32_t i, num, spi; 525 int32_t spi_idx; 526 struct acl4_rules *acr; 527 528 if (inbound != 0) { 529 acr = acl4_rules_in; 530 num = nb_acl4_rules_in; 531 } else { 532 acr = acl4_rules_out; 533 num = nb_acl4_rules_out; 534 } 535 536 for (i = 0; i != num; i++) { 537 spi = acr[i].data.userdata; 538 if (spi != DISCARD && spi != BYPASS) { 539 spi_idx = sa_spi_present(sa_ctx, spi, inbound); 540 if (spi_idx < 0) { 541 RTE_LOG(ERR, IPSEC, 542 "SPI %u is not present in SAD\n", 543 spi); 544 return -ENOENT; 545 } 546 /* Update userdata with spi index */ 547 acr[i].data.userdata = spi_idx + 1; 548 } 549 } 550 551 return 0; 552 } 553 554 void 555 sp4_init(struct socket_ctx *ctx, int32_t socket_id) 556 { 557 const char *name; 558 559 if (ctx == NULL) 560 rte_exit(EXIT_FAILURE, "NULL context.\n"); 561 562 if (ctx->sp_ip4_in != NULL) 563 rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already " 564 "initialized\n", socket_id); 565 566 if (ctx->sp_ip4_out != NULL) 567 rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already " 568 "initialized\n", socket_id); 569 570 if (check_spi_value(ctx->sa_in, 1) < 0) 571 rte_exit(EXIT_FAILURE, 572 "Inbound IPv4 SP DB has unmatched in SAD SPIs\n"); 573 574 if (check_spi_value(ctx->sa_out, 0) < 0) 575 rte_exit(EXIT_FAILURE, 576 "Outbound IPv4 SP DB has unmatched in SAD SPIs\n"); 577 578 if (nb_acl4_rules_in > 0) { 579 name = "sp_ip4_in"; 580 ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, 581 socket_id, acl4_rules_in, nb_acl4_rules_in); 582 } else 583 RTE_LOG(WARNING, IPSEC, "No IPv4 SP Inbound rule " 584 "specified\n"); 585 586 if (nb_acl4_rules_out > 0) { 587 name = "sp_ip4_out"; 588 ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, 589 socket_id, acl4_rules_out, nb_acl4_rules_out); 590 } else 591 RTE_LOG(WARNING, IPSEC, "No IPv4 SP Outbound rule " 592 "specified\n"); 593 } 594 595 static int 596 sp_cmp(const void *p, const void *q) 597 { 598 uint32_t spi1 = ((const struct acl4_rules *)p)->data.userdata; 599 uint32_t spi2 = ((const struct acl4_rules *)q)->data.userdata; 600 601 return (int)(spi1 - spi2); 602 } 603 604 605 /* 606 * Search though SP rules for given SPI. 607 */ 608 int 609 sp4_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2], 610 uint32_t mask[2]) 611 { 612 uint32_t num; 613 struct acl4_rules *rule; 614 const struct acl4_rules *acr; 615 struct acl4_rules tmpl; 616 617 if (inbound != 0) { 618 acr = acl4_rules_in; 619 num = nb_acl4_rules_in; 620 } else { 621 acr = acl4_rules_out; 622 num = nb_acl4_rules_out; 623 } 624 625 tmpl.data.userdata = spi; 626 627 rule = bsearch(&tmpl, acr, num, sizeof(struct acl4_rules), sp_cmp); 628 if (rule != NULL) { 629 if (NULL != ip_addr && NULL != mask) { 630 ip_addr[0].ip.ip4 = IPV4_SRC_FROM_SP(*rule); 631 ip_addr[1].ip.ip4 = IPV4_DST_FROM_SP(*rule); 632 mask[0] = IPV4_SRC_MASK_FROM_SP(*rule); 633 mask[1] = IPV4_DST_MASK_FROM_SP(*rule); 634 } 635 return RTE_PTR_DIFF(rule, acr) / sizeof(struct acl4_rules); 636 } 637 638 return -ENOENT; 639 } 640 641 void 642 sp4_sort_arr(void) 643 { 644 qsort(acl4_rules_in, nb_acl4_rules_in, sizeof(struct acl4_rules), 645 sp_cmp); 646 qsort(acl4_rules_out, nb_acl4_rules_out, sizeof(struct acl4_rules), 647 sp_cmp); 648 } 649