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 INIT_ACL_RULE_NUM 128 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 static struct rte_acl_field_def ip6_defs[IP6_NUM] = { 36 { 37 .type = RTE_ACL_FIELD_TYPE_BITMASK, 38 .size = sizeof(uint8_t), 39 .field_index = IP6_PROTO, 40 .input_index = IP6_PROTO, 41 .offset = 0, 42 }, 43 { 44 .type = RTE_ACL_FIELD_TYPE_MASK, 45 .size = 4, 46 .field_index = IP6_SRC0, 47 .input_index = IP6_SRC0, 48 .offset = 2 49 }, 50 { 51 .type = RTE_ACL_FIELD_TYPE_MASK, 52 .size = 4, 53 .field_index = IP6_SRC1, 54 .input_index = IP6_SRC1, 55 .offset = 6 56 }, 57 { 58 .type = RTE_ACL_FIELD_TYPE_MASK, 59 .size = 4, 60 .field_index = IP6_SRC2, 61 .input_index = IP6_SRC2, 62 .offset = 10 63 }, 64 { 65 .type = RTE_ACL_FIELD_TYPE_MASK, 66 .size = 4, 67 .field_index = IP6_SRC3, 68 .input_index = IP6_SRC3, 69 .offset = 14 70 }, 71 { 72 .type = RTE_ACL_FIELD_TYPE_MASK, 73 .size = 4, 74 .field_index = IP6_DST0, 75 .input_index = IP6_DST0, 76 .offset = 18 77 }, 78 { 79 .type = RTE_ACL_FIELD_TYPE_MASK, 80 .size = 4, 81 .field_index = IP6_DST1, 82 .input_index = IP6_DST1, 83 .offset = 22 84 }, 85 { 86 .type = RTE_ACL_FIELD_TYPE_MASK, 87 .size = 4, 88 .field_index = IP6_DST2, 89 .input_index = IP6_DST2, 90 .offset = 26 91 }, 92 { 93 .type = RTE_ACL_FIELD_TYPE_MASK, 94 .size = 4, 95 .field_index = IP6_DST3, 96 .input_index = IP6_DST3, 97 .offset = 30 98 }, 99 { 100 .type = RTE_ACL_FIELD_TYPE_RANGE, 101 .size = sizeof(uint16_t), 102 .field_index = IP6_SRCP, 103 .input_index = IP6_SRCP, 104 .offset = 34 105 }, 106 { 107 .type = RTE_ACL_FIELD_TYPE_RANGE, 108 .size = sizeof(uint16_t), 109 .field_index = IP6_DSTP, 110 .input_index = IP6_SRCP, 111 .offset = 36 112 } 113 }; 114 115 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs)); 116 117 static struct acl6_rules *acl6_rules_out; 118 static uint32_t nb_acl6_rules_out; 119 static uint32_t sp_out_sz; 120 121 static struct acl6_rules *acl6_rules_in; 122 static uint32_t nb_acl6_rules_in; 123 static uint32_t sp_in_sz; 124 125 static struct rte_ipv6_addr 126 ipv6_src_from_sp(const struct acl6_rules *rule) 127 { 128 struct rte_ipv6_addr alignas(alignof(rte_be64_t)) addr = RTE_IPV6_ADDR_UNSPEC; 129 rte_be64_t *values = (rte_be64_t *)&addr; 130 131 values[0] = rte_cpu_to_be_64((uint64_t)rule->field[IP6_SRC0].value.u32 << 32 | 132 rule->field[IP6_SRC1].value.u32); 133 values[1] = rte_cpu_to_be_64((uint64_t)rule->field[IP6_SRC2].value.u32 << 32 | 134 rule->field[IP6_SRC3].value.u32); 135 136 return addr; 137 } 138 139 static struct rte_ipv6_addr 140 ipv6_dst_from_sp(const struct acl6_rules *rule) 141 { 142 struct rte_ipv6_addr alignas(alignof(rte_be64_t)) addr = RTE_IPV6_ADDR_UNSPEC; 143 rte_be64_t *values = (rte_be64_t *)&addr; 144 145 values[0] = rte_cpu_to_be_64((uint64_t)rule->field[IP6_DST0].value.u32 << 32 | 146 rule->field[IP6_DST1].value.u32); 147 values[1] = rte_cpu_to_be_64((uint64_t)rule->field[IP6_DST2].value.u32 << 32 | 148 rule->field[IP6_DST3].value.u32); 149 150 return addr; 151 } 152 153 static uint32_t 154 ipv6_src_mask_from_sp(const struct acl6_rules *rule) 155 { 156 return rule->field[IP6_SRC0].mask_range.u32 + 157 rule->field[IP6_SRC1].mask_range.u32 + 158 rule->field[IP6_SRC2].mask_range.u32 + 159 rule->field[IP6_SRC3].mask_range.u32; 160 } 161 162 static uint32_t 163 ipv6_dst_mask_from_sp(const struct acl6_rules *rule) 164 { 165 return rule->field[IP6_DST0].mask_range.u32 + 166 rule->field[IP6_DST1].mask_range.u32 + 167 rule->field[IP6_DST2].mask_range.u32 + 168 rule->field[IP6_DST3].mask_range.u32; 169 } 170 171 static int 172 extend_sp_arr(struct acl6_rules **sp_tbl, uint32_t cur_cnt, uint32_t *cur_sz) 173 { 174 if (*sp_tbl == NULL) { 175 *sp_tbl = calloc(INIT_ACL_RULE_NUM, sizeof(struct acl6_rules)); 176 if (*sp_tbl == NULL) 177 return -1; 178 *cur_sz = INIT_ACL_RULE_NUM; 179 return 0; 180 } 181 182 if (cur_cnt >= *cur_sz) { 183 *sp_tbl = realloc(*sp_tbl, 184 *cur_sz * sizeof(struct acl6_rules) * 2); 185 if (*sp_tbl == NULL) 186 return -1; 187 /* clean reallocated extra space */ 188 memset(&(*sp_tbl)[*cur_sz], 0, 189 *cur_sz * sizeof(struct acl6_rules)); 190 *cur_sz *= 2; 191 } 192 193 return 0; 194 } 195 196 void 197 parse_sp6_tokens(char **tokens, uint32_t n_tokens, 198 struct parse_status *status) 199 { 200 struct acl6_rules *rule_ipv6 = NULL; 201 202 uint32_t *ri = NULL; /* rule index */ 203 uint32_t ti = 0; /* token index */ 204 uint32_t tv; 205 206 uint32_t esp_p = 0; 207 uint32_t protect_p = 0; 208 uint32_t bypass_p = 0; 209 uint32_t discard_p = 0; 210 uint32_t pri_p = 0; 211 uint32_t src_p = 0; 212 uint32_t dst_p = 0; 213 uint32_t proto_p = 0; 214 uint32_t sport_p = 0; 215 uint32_t dport_p = 0; 216 217 if (strcmp(tokens[1], "in") == 0) { 218 ri = &nb_acl6_rules_in; 219 220 if (extend_sp_arr(&acl6_rules_in, nb_acl6_rules_in, 221 &sp_in_sz) < 0) 222 return; 223 224 rule_ipv6 = &acl6_rules_in[*ri]; 225 226 } else if (strcmp(tokens[1], "out") == 0) { 227 ri = &nb_acl6_rules_out; 228 229 if (extend_sp_arr(&acl6_rules_out, nb_acl6_rules_out, 230 &sp_out_sz) < 0) 231 return; 232 233 rule_ipv6 = &acl6_rules_out[*ri]; 234 235 } else { 236 APP_CHECK(0, status, "unrecognized input \"%s\", expect" 237 " \"in\" or \"out\"\n", tokens[ti]); 238 return; 239 } 240 241 rule_ipv6->data.category_mask = 1; 242 243 244 for (ti = 2; ti < n_tokens; ti++) { 245 if (strcmp(tokens[ti], "esp") == 0) { 246 /* currently do nothing */ 247 APP_CHECK_PRESENCE(esp_p, tokens[ti], status); 248 if (status->status < 0) 249 return; 250 esp_p = 1; 251 continue; 252 } 253 254 if (strcmp(tokens[ti], "protect") == 0) { 255 APP_CHECK_PRESENCE(protect_p, tokens[ti], status); 256 if (status->status < 0) 257 return; 258 APP_CHECK(bypass_p == 0, status, "conflict item " 259 "between \"%s\" and \"%s\"", tokens[ti], 260 "bypass"); 261 if (status->status < 0) 262 return; 263 APP_CHECK(discard_p == 0, status, "conflict item " 264 "between \"%s\" and \"%s\"", tokens[ti], 265 "discard"); 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 tv = atoi(tokens[ti]); 276 APP_CHECK(tv != DISCARD && tv != BYPASS, status, 277 "invalid SPI: %s", tokens[ti]); 278 if (status->status < 0) 279 return; 280 rule_ipv6->data.userdata = tv; 281 282 protect_p = 1; 283 continue; 284 } 285 286 if (strcmp(tokens[ti], "bypass") == 0) { 287 APP_CHECK_PRESENCE(bypass_p, tokens[ti], status); 288 if (status->status < 0) 289 return; 290 APP_CHECK(protect_p == 0, status, "conflict item " 291 "between \"%s\" and \"%s\"", tokens[ti], 292 "protect"); 293 if (status->status < 0) 294 return; 295 APP_CHECK(discard_p == 0, status, "conflict item " 296 "between \"%s\" and \"%s\"", tokens[ti], 297 "discard"); 298 if (status->status < 0) 299 return; 300 301 rule_ipv6->data.userdata = BYPASS; 302 303 bypass_p = 1; 304 continue; 305 } 306 307 if (strcmp(tokens[ti], "discard") == 0) { 308 APP_CHECK_PRESENCE(discard_p, tokens[ti], status); 309 if (status->status < 0) 310 return; 311 APP_CHECK(protect_p == 0, status, "conflict item " 312 "between \"%s\" and \"%s\"", tokens[ti], 313 "protect"); 314 if (status->status < 0) 315 return; 316 APP_CHECK(bypass_p == 0, status, "conflict item " 317 "between \"%s\" and \"%s\"", tokens[ti], 318 "discard"); 319 if (status->status < 0) 320 return; 321 322 rule_ipv6->data.userdata = DISCARD; 323 324 discard_p = 1; 325 continue; 326 } 327 328 if (strcmp(tokens[ti], "pri") == 0) { 329 APP_CHECK_PRESENCE(pri_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 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 336 if (status->status < 0) 337 return; 338 339 rule_ipv6->data.priority = atoi(tokens[ti]); 340 341 pri_p = 1; 342 continue; 343 } 344 345 if (strcmp(tokens[ti], "src") == 0) { 346 struct rte_ipv6_addr ip; 347 uint32_t depth; 348 349 APP_CHECK_PRESENCE(src_p, tokens[ti], status); 350 if (status->status < 0) 351 return; 352 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 353 if (status->status < 0) 354 return; 355 356 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip, 357 &depth) == 0, status, "unrecognized " 358 "input \"%s\", expect valid ipv6 " 359 "addr", tokens[ti]); 360 if (status->status < 0) 361 return; 362 363 rule_ipv6->field[1].value.u32 = 364 (uint32_t)ip.a[0] << 24 | 365 (uint32_t)ip.a[1] << 16 | 366 (uint32_t)ip.a[2] << 8 | 367 (uint32_t)ip.a[3]; 368 rule_ipv6->field[1].mask_range.u32 = 369 (depth > 32) ? 32 : depth; 370 depth = (depth > 32) ? (depth - 32) : 0; 371 rule_ipv6->field[2].value.u32 = 372 (uint32_t)ip.a[4] << 24 | 373 (uint32_t)ip.a[5] << 16 | 374 (uint32_t)ip.a[6] << 8 | 375 (uint32_t)ip.a[7]; 376 rule_ipv6->field[2].mask_range.u32 = 377 (depth > 32) ? 32 : depth; 378 depth = (depth > 32) ? (depth - 32) : 0; 379 rule_ipv6->field[3].value.u32 = 380 (uint32_t)ip.a[8] << 24 | 381 (uint32_t)ip.a[9] << 16 | 382 (uint32_t)ip.a[10] << 8 | 383 (uint32_t)ip.a[11]; 384 rule_ipv6->field[3].mask_range.u32 = 385 (depth > 32) ? 32 : depth; 386 depth = (depth > 32) ? (depth - 32) : 0; 387 rule_ipv6->field[4].value.u32 = 388 (uint32_t)ip.a[12] << 24 | 389 (uint32_t)ip.a[13] << 16 | 390 (uint32_t)ip.a[14] << 8 | 391 (uint32_t)ip.a[15]; 392 rule_ipv6->field[4].mask_range.u32 = 393 (depth > 32) ? 32 : depth; 394 395 src_p = 1; 396 continue; 397 } 398 399 if (strcmp(tokens[ti], "dst") == 0) { 400 struct rte_ipv6_addr ip; 401 uint32_t depth; 402 403 APP_CHECK_PRESENCE(dst_p, tokens[ti], status); 404 if (status->status < 0) 405 return; 406 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 407 if (status->status < 0) 408 return; 409 410 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip, 411 &depth) == 0, status, "unrecognized " 412 "input \"%s\", expect valid ipv6 " 413 "addr", tokens[ti]); 414 if (status->status < 0) 415 return; 416 417 rule_ipv6->field[5].value.u32 = 418 (uint32_t)ip.a[0] << 24 | 419 (uint32_t)ip.a[1] << 16 | 420 (uint32_t)ip.a[2] << 8 | 421 (uint32_t)ip.a[3]; 422 rule_ipv6->field[5].mask_range.u32 = 423 (depth > 32) ? 32 : depth; 424 depth = (depth > 32) ? (depth - 32) : 0; 425 rule_ipv6->field[6].value.u32 = 426 (uint32_t)ip.a[4] << 24 | 427 (uint32_t)ip.a[5] << 16 | 428 (uint32_t)ip.a[6] << 8 | 429 (uint32_t)ip.a[7]; 430 rule_ipv6->field[6].mask_range.u32 = 431 (depth > 32) ? 32 : depth; 432 depth = (depth > 32) ? (depth - 32) : 0; 433 rule_ipv6->field[7].value.u32 = 434 (uint32_t)ip.a[8] << 24 | 435 (uint32_t)ip.a[9] << 16 | 436 (uint32_t)ip.a[10] << 8 | 437 (uint32_t)ip.a[11]; 438 rule_ipv6->field[7].mask_range.u32 = 439 (depth > 32) ? 32 : depth; 440 depth = (depth > 32) ? (depth - 32) : 0; 441 rule_ipv6->field[8].value.u32 = 442 (uint32_t)ip.a[12] << 24 | 443 (uint32_t)ip.a[13] << 16 | 444 (uint32_t)ip.a[14] << 8 | 445 (uint32_t)ip.a[15]; 446 rule_ipv6->field[8].mask_range.u32 = 447 (depth > 32) ? 32 : depth; 448 449 dst_p = 1; 450 continue; 451 } 452 453 if (strcmp(tokens[ti], "proto") == 0) { 454 uint16_t low, high; 455 456 APP_CHECK_PRESENCE(proto_p, tokens[ti], status); 457 if (status->status < 0) 458 return; 459 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 460 if (status->status < 0) 461 return; 462 463 APP_CHECK(parse_range(tokens[ti], &low, &high) 464 == 0, status, "unrecognized input \"%s\"" 465 ", expect \"from:to\"", tokens[ti]); 466 if (status->status < 0) 467 return; 468 APP_CHECK(low <= 0xff, status, "proto low " 469 "over-limit"); 470 if (status->status < 0) 471 return; 472 APP_CHECK(high <= 0xff, status, "proto high " 473 "over-limit"); 474 if (status->status < 0) 475 return; 476 477 rule_ipv6->field[0].value.u8 = (uint8_t)low; 478 rule_ipv6->field[0].mask_range.u8 = (uint8_t)high; 479 480 proto_p = 1; 481 continue; 482 } 483 484 if (strcmp(tokens[ti], "sport") == 0) { 485 uint16_t port_low, port_high; 486 487 APP_CHECK_PRESENCE(sport_p, tokens[ti], status); 488 if (status->status < 0) 489 return; 490 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 491 if (status->status < 0) 492 return; 493 494 APP_CHECK(parse_range(tokens[ti], &port_low, 495 &port_high) == 0, status, "unrecognized " 496 "input \"%s\", expect \"port_from:" 497 "port_to\"", tokens[ti]); 498 if (status->status < 0) 499 return; 500 501 rule_ipv6->field[9].value.u16 = port_low; 502 rule_ipv6->field[9].mask_range.u16 = port_high; 503 504 sport_p = 1; 505 continue; 506 } 507 508 if (strcmp(tokens[ti], "dport") == 0) { 509 uint16_t port_low, port_high; 510 511 APP_CHECK_PRESENCE(dport_p, tokens[ti], status); 512 if (status->status < 0) 513 return; 514 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 515 if (status->status < 0) 516 return; 517 518 APP_CHECK(parse_range(tokens[ti], &port_low, 519 &port_high) == 0, status, "unrecognized " 520 "input \"%s\", expect \"port_from:" 521 "port_to\"", tokens[ti]); 522 if (status->status < 0) 523 return; 524 525 rule_ipv6->field[10].value.u16 = port_low; 526 rule_ipv6->field[10].mask_range.u16 = port_high; 527 528 dport_p = 1; 529 continue; 530 } 531 532 /* unrecognizable input */ 533 APP_CHECK(0, status, "unrecognized input \"%s\"", 534 tokens[ti]); 535 return; 536 } 537 538 /* check if argument(s) are missing */ 539 APP_CHECK(esp_p == 1, status, "missing argument \"esp\""); 540 if (status->status < 0) 541 return; 542 543 APP_CHECK(protect_p | bypass_p | discard_p, status, "missing " 544 "argument \"protect\", \"bypass\", or \"discard\""); 545 if (status->status < 0) 546 return; 547 548 *ri = *ri + 1; 549 } 550 551 static inline void 552 print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra) 553 { 554 uint8_t a, b, c, d; 555 556 uint32_t_to_char(rule->field[IP6_SRC0].value.u32, 557 &a, &b, &c, &d); 558 printf("%.2x%.2x:%.2x%.2x", a, b, c, d); 559 uint32_t_to_char(rule->field[IP6_SRC1].value.u32, 560 &a, &b, &c, &d); 561 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 562 uint32_t_to_char(rule->field[IP6_SRC2].value.u32, 563 &a, &b, &c, &d); 564 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 565 uint32_t_to_char(rule->field[IP6_SRC3].value.u32, 566 &a, &b, &c, &d); 567 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d, 568 rule->field[IP6_SRC0].mask_range.u32 569 + rule->field[IP6_SRC1].mask_range.u32 570 + rule->field[IP6_SRC2].mask_range.u32 571 + rule->field[IP6_SRC3].mask_range.u32); 572 573 uint32_t_to_char(rule->field[IP6_DST0].value.u32, 574 &a, &b, &c, &d); 575 printf("%.2x%.2x:%.2x%.2x", a, b, c, d); 576 uint32_t_to_char(rule->field[IP6_DST1].value.u32, 577 &a, &b, &c, &d); 578 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 579 uint32_t_to_char(rule->field[IP6_DST2].value.u32, 580 &a, &b, &c, &d); 581 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 582 uint32_t_to_char(rule->field[IP6_DST3].value.u32, 583 &a, &b, &c, &d); 584 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d, 585 rule->field[IP6_DST0].mask_range.u32 586 + rule->field[IP6_DST1].mask_range.u32 587 + rule->field[IP6_DST2].mask_range.u32 588 + rule->field[IP6_DST3].mask_range.u32); 589 590 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ", 591 rule->field[IP6_SRCP].value.u16, 592 rule->field[IP6_SRCP].mask_range.u16, 593 rule->field[IP6_DSTP].value.u16, 594 rule->field[IP6_DSTP].mask_range.u16, 595 rule->field[IP6_PROTO].value.u8, 596 rule->field[IP6_PROTO].mask_range.u8); 597 if (extra) 598 printf("0x%x-0x%x-0x%x ", 599 rule->data.category_mask, 600 rule->data.priority, 601 rule->data.userdata); 602 } 603 604 static inline void 605 dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra) 606 { 607 int32_t i; 608 609 for (i = 0; i < num; i++, rule++) { 610 printf("\t%d:", i + 1); 611 print_one_ip6_rule(rule, extra); 612 printf("\n"); 613 } 614 } 615 616 static struct rte_acl_ctx * 617 acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules, 618 uint32_t rules_nb) 619 { 620 char s[PATH_MAX]; 621 struct rte_acl_param acl_param; 622 struct rte_acl_config acl_build_param; 623 struct rte_acl_ctx *ctx; 624 625 printf("Creating SP context with %u rules\n", rules_nb); 626 627 memset(&acl_param, 0, sizeof(acl_param)); 628 629 /* Create ACL contexts */ 630 snprintf(s, sizeof(s), "%s_%d", name, socketid); 631 632 printf("IPv4 %s entries [%u]:\n", s, rules_nb); 633 dump_ip6_rules(rules, rules_nb, 1); 634 635 acl_param.name = s; 636 acl_param.socket_id = socketid; 637 acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs)); 638 acl_param.max_rule_num = rules_nb; 639 640 ctx = rte_acl_create(&acl_param); 641 if (ctx == NULL) 642 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n"); 643 644 if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules, 645 rules_nb) < 0) 646 rte_exit(EXIT_FAILURE, "add rules failed\n"); 647 648 /* Perform builds */ 649 memset(&acl_build_param, 0, sizeof(acl_build_param)); 650 651 acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES; 652 acl_build_param.num_fields = RTE_DIM(ip6_defs); 653 memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs)); 654 655 if (rte_acl_build(ctx, &acl_build_param) != 0) 656 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n"); 657 658 rte_acl_dump(ctx); 659 660 return ctx; 661 } 662 663 /* 664 * check that for each rule it's SPI has a correspondent entry in SAD 665 */ 666 static int 667 check_spi_value(struct sa_ctx *sa_ctx, int inbound) 668 { 669 uint32_t i, num, spi; 670 int32_t spi_idx; 671 struct acl6_rules *acr; 672 673 if (inbound != 0) { 674 acr = acl6_rules_in; 675 num = nb_acl6_rules_in; 676 } else { 677 acr = acl6_rules_out; 678 num = nb_acl6_rules_out; 679 } 680 681 for (i = 0; i != num; i++) { 682 spi = acr[i].data.userdata; 683 if (spi != DISCARD && spi != BYPASS) { 684 spi_idx = sa_spi_present(sa_ctx, spi, inbound); 685 if (spi_idx < 0) { 686 RTE_LOG(ERR, IPSEC, 687 "SPI %u is not present in SAD\n", 688 spi); 689 return -ENOENT; 690 } 691 /* Update userdata with spi index */ 692 acr[i].data.userdata = spi_idx + 1; 693 } 694 } 695 696 return 0; 697 } 698 699 void 700 sp6_init(struct socket_ctx *ctx, int32_t socket_id) 701 { 702 const char *name; 703 704 if (ctx == NULL) 705 rte_exit(EXIT_FAILURE, "NULL context.\n"); 706 707 if (ctx->sp_ip6_in != NULL) 708 rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u " 709 "already initialized\n", socket_id); 710 711 if (ctx->sp_ip6_out != NULL) 712 rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u " 713 "already initialized\n", socket_id); 714 715 if (check_spi_value(ctx->sa_in, 1) < 0) 716 rte_exit(EXIT_FAILURE, 717 "Inbound IPv6 SP DB has unmatched in SAD SPIs\n"); 718 719 if (check_spi_value(ctx->sa_out, 0) < 0) 720 rte_exit(EXIT_FAILURE, 721 "Outbound IPv6 SP DB has unmatched in SAD SPIs\n"); 722 723 if (nb_acl6_rules_in > 0) { 724 name = "sp_ip6_in"; 725 ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name, 726 socket_id, acl6_rules_in, nb_acl6_rules_in); 727 } else 728 RTE_LOG(WARNING, IPSEC, "No IPv6 SP Inbound rule " 729 "specified\n"); 730 731 if (nb_acl6_rules_out > 0) { 732 name = "sp_ip6_out"; 733 ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name, 734 socket_id, acl6_rules_out, nb_acl6_rules_out); 735 } else 736 RTE_LOG(WARNING, IPSEC, "No IPv6 SP Outbound rule " 737 "specified\n"); 738 } 739 740 static int 741 sp_cmp(const void *p, const void *q) 742 { 743 uint32_t spi1 = ((const struct acl6_rules *)p)->data.userdata; 744 uint32_t spi2 = ((const struct acl6_rules *)q)->data.userdata; 745 746 return (int)(spi1 - spi2); 747 } 748 749 /* 750 * Search though SP rules for given SPI. 751 */ 752 int 753 sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2], 754 uint32_t mask[2]) 755 { 756 uint32_t num; 757 struct acl6_rules *rule; 758 const struct acl6_rules *acr; 759 struct acl6_rules tmpl; 760 761 if (inbound != 0) { 762 acr = acl6_rules_in; 763 num = nb_acl6_rules_in; 764 } else { 765 acr = acl6_rules_out; 766 num = nb_acl6_rules_out; 767 } 768 769 tmpl.data.userdata = spi; 770 771 rule = bsearch(&tmpl, acr, num, sizeof(struct acl6_rules), sp_cmp); 772 if (rule != NULL) { 773 if (NULL != ip_addr && NULL != mask) { 774 ip_addr[0].ip.ip6 = ipv6_src_from_sp(rule); 775 ip_addr[1].ip.ip6 = ipv6_dst_from_sp(rule); 776 mask[0] = ipv6_src_mask_from_sp(rule); 777 mask[1] = ipv6_dst_mask_from_sp(rule); 778 } 779 return RTE_PTR_DIFF(rule, acr) / sizeof(struct acl6_rules); 780 } 781 782 return -ENOENT; 783 } 784 785 void 786 sp6_sort_arr(void) 787 { 788 qsort(acl6_rules_in, nb_acl6_rules_in, sizeof(struct acl6_rules), 789 sp_cmp); 790 qsort(acl6_rules_out, nb_acl6_rules_out, sizeof(struct acl6_rules), 791 sp_cmp); 792 } 793