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