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