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