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 103 uint32_t esp_p = 0; 104 uint32_t protect_p = 0; 105 uint32_t bypass_p = 0; 106 uint32_t discard_p = 0; 107 uint32_t pri_p = 0; 108 uint32_t src_p = 0; 109 uint32_t dst_p = 0; 110 uint32_t proto_p = 0; 111 uint32_t sport_p = 0; 112 uint32_t dport_p = 0; 113 114 if (strcmp(tokens[1], "in") == 0) { 115 ri = &nb_acl4_rules_in; 116 117 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, 118 "too many sp rules, abort insertion\n"); 119 if (status->status < 0) 120 return; 121 122 rule_ipv4 = &acl4_rules_in[*ri]; 123 124 } else if (strcmp(tokens[1], "out") == 0) { 125 ri = &nb_acl4_rules_out; 126 127 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, 128 "too many sp rules, abort insertion\n"); 129 if (status->status < 0) 130 return; 131 132 rule_ipv4 = &acl4_rules_out[*ri]; 133 } else { 134 APP_CHECK(0, status, "unrecognized input \"%s\", expect" 135 " \"in\" or \"out\"\n", tokens[ti]); 136 return; 137 } 138 139 rule_ipv4->data.category_mask = 1; 140 141 for (ti = 2; ti < n_tokens; ti++) { 142 if (strcmp(tokens[ti], "esp") == 0) { 143 /* currently do nothing */ 144 APP_CHECK_PRESENCE(esp_p, tokens[ti], status); 145 if (status->status < 0) 146 return; 147 esp_p = 1; 148 continue; 149 } 150 151 if (strcmp(tokens[ti], "protect") == 0) { 152 APP_CHECK_PRESENCE(protect_p, tokens[ti], status); 153 if (status->status < 0) 154 return; 155 APP_CHECK(bypass_p == 0, status, "conflict item " 156 "between \"%s\" and \"%s\"", tokens[ti], 157 "bypass"); 158 if (status->status < 0) 159 return; 160 APP_CHECK(discard_p == 0, status, "conflict item " 161 "between \"%s\" and \"%s\"", tokens[ti], 162 "discard"); 163 if (status->status < 0) 164 return; 165 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 166 if (status->status < 0) 167 return; 168 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 169 if (status->status < 0) 170 return; 171 172 rule_ipv4->data.userdata = 173 PROTECT(atoi(tokens[ti])); 174 175 protect_p = 1; 176 continue; 177 } 178 179 if (strcmp(tokens[ti], "bypass") == 0) { 180 APP_CHECK_PRESENCE(bypass_p, tokens[ti], status); 181 if (status->status < 0) 182 return; 183 APP_CHECK(protect_p == 0, status, "conflict item " 184 "between \"%s\" and \"%s\"", tokens[ti], 185 "protect"); 186 if (status->status < 0) 187 return; 188 APP_CHECK(discard_p == 0, status, "conflict item " 189 "between \"%s\" and \"%s\"", tokens[ti], 190 "discard"); 191 if (status->status < 0) 192 return; 193 194 rule_ipv4->data.userdata = BYPASS; 195 196 bypass_p = 1; 197 continue; 198 } 199 200 if (strcmp(tokens[ti], "discard") == 0) { 201 APP_CHECK_PRESENCE(discard_p, tokens[ti], status); 202 if (status->status < 0) 203 return; 204 APP_CHECK(protect_p == 0, status, "conflict item " 205 "between \"%s\" and \"%s\"", tokens[ti], 206 "protect"); 207 if (status->status < 0) 208 return; 209 APP_CHECK(bypass_p == 0, status, "conflict item " 210 "between \"%s\" and \"%s\"", tokens[ti], 211 "discard"); 212 if (status->status < 0) 213 return; 214 215 rule_ipv4->data.userdata = DISCARD; 216 217 discard_p = 1; 218 continue; 219 } 220 221 if (strcmp(tokens[ti], "pri") == 0) { 222 APP_CHECK_PRESENCE(pri_p, tokens[ti], status); 223 if (status->status < 0) 224 return; 225 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 226 if (status->status < 0) 227 return; 228 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 229 if (status->status < 0) 230 return; 231 232 rule_ipv4->data.priority = atoi(tokens[ti]); 233 234 pri_p = 1; 235 continue; 236 } 237 238 if (strcmp(tokens[ti], "src") == 0) { 239 struct in_addr ip; 240 uint32_t depth; 241 242 APP_CHECK_PRESENCE(src_p, tokens[ti], status); 243 if (status->status < 0) 244 return; 245 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 246 if (status->status < 0) 247 return; 248 249 APP_CHECK(parse_ipv4_addr(tokens[ti], &ip, 250 &depth) == 0, status, "unrecognized " 251 "input \"%s\", expect valid ipv4 addr", 252 tokens[ti]); 253 if (status->status < 0) 254 return; 255 256 rule_ipv4->field[1].value.u32 = 257 rte_bswap32(ip.s_addr); 258 rule_ipv4->field[1].mask_range.u32 = 259 depth; 260 261 src_p = 1; 262 continue; 263 } 264 265 if (strcmp(tokens[ti], "dst") == 0) { 266 struct in_addr ip; 267 uint32_t depth; 268 269 APP_CHECK_PRESENCE(dst_p, tokens[ti], status); 270 if (status->status < 0) 271 return; 272 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 273 if (status->status < 0) 274 return; 275 APP_CHECK(parse_ipv4_addr(tokens[ti], &ip, 276 &depth) == 0, status, "unrecognized " 277 "input \"%s\", expect valid ipv4 addr", 278 tokens[ti]); 279 if (status->status < 0) 280 return; 281 282 rule_ipv4->field[2].value.u32 = 283 rte_bswap32(ip.s_addr); 284 rule_ipv4->field[2].mask_range.u32 = 285 depth; 286 287 dst_p = 1; 288 continue; 289 } 290 291 if (strcmp(tokens[ti], "proto") == 0) { 292 uint16_t low, high; 293 294 APP_CHECK_PRESENCE(proto_p, tokens[ti], status); 295 if (status->status < 0) 296 return; 297 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 298 if (status->status < 0) 299 return; 300 301 APP_CHECK(parse_range(tokens[ti], &low, &high) 302 == 0, status, "unrecognized input \"%s\"" 303 ", expect \"from:to\"", tokens[ti]); 304 if (status->status < 0) 305 return; 306 APP_CHECK(low <= 0xff, status, "proto low " 307 "over-limit"); 308 if (status->status < 0) 309 return; 310 APP_CHECK(high <= 0xff, status, "proto high " 311 "over-limit"); 312 if (status->status < 0) 313 return; 314 315 rule_ipv4->field[0].value.u8 = (uint8_t)low; 316 rule_ipv4->field[0].mask_range.u8 = (uint8_t)high; 317 318 proto_p = 1; 319 continue; 320 } 321 322 if (strcmp(tokens[ti], "sport") == 0) { 323 uint16_t port_low, port_high; 324 325 APP_CHECK_PRESENCE(sport_p, tokens[ti], status); 326 if (status->status < 0) 327 return; 328 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 329 if (status->status < 0) 330 return; 331 332 APP_CHECK(parse_range(tokens[ti], &port_low, 333 &port_high) == 0, status, "unrecognized " 334 "input \"%s\", expect \"port_from:" 335 "port_to\"", tokens[ti]); 336 if (status->status < 0) 337 return; 338 339 rule_ipv4->field[3].value.u16 = port_low; 340 rule_ipv4->field[3].mask_range.u16 = port_high; 341 342 sport_p = 1; 343 continue; 344 } 345 346 if (strcmp(tokens[ti], "dport") == 0) { 347 uint16_t port_low, port_high; 348 349 APP_CHECK_PRESENCE(dport_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_range(tokens[ti], &port_low, 357 &port_high) == 0, status, "unrecognized " 358 "input \"%s\", expect \"port_from:" 359 "port_to\"", tokens[ti]); 360 if (status->status < 0) 361 return; 362 363 rule_ipv4->field[4].value.u16 = port_low; 364 rule_ipv4->field[4].mask_range.u16 = port_high; 365 366 dport_p = 1; 367 continue; 368 } 369 370 /* unrecognizeable input */ 371 APP_CHECK(0, status, "unrecognized input \"%s\"", 372 tokens[ti]); 373 return; 374 } 375 376 /* check if argument(s) are missing */ 377 APP_CHECK(esp_p == 1, status, "missing argument \"esp\""); 378 if (status->status < 0) 379 return; 380 381 APP_CHECK(protect_p | bypass_p | discard_p, status, "missing " 382 "argument \"protect\", \"bypass\", or \"discard\""); 383 if (status->status < 0) 384 return; 385 386 *ri = *ri + 1; 387 } 388 389 static void 390 print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra) 391 { 392 uint8_t a, b, c, d; 393 394 uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32, 395 &a, &b, &c, &d); 396 printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d, 397 rule->field[SRC_FIELD_IPV4].mask_range.u32); 398 uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32, 399 &a, &b, &c, &d); 400 printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d, 401 rule->field[DST_FIELD_IPV4].mask_range.u32); 402 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ", 403 rule->field[SRCP_FIELD_IPV4].value.u16, 404 rule->field[SRCP_FIELD_IPV4].mask_range.u16, 405 rule->field[DSTP_FIELD_IPV4].value.u16, 406 rule->field[DSTP_FIELD_IPV4].mask_range.u16, 407 rule->field[PROTO_FIELD_IPV4].value.u8, 408 rule->field[PROTO_FIELD_IPV4].mask_range.u8); 409 if (extra) 410 printf("0x%x-0x%x-0x%x ", 411 rule->data.category_mask, 412 rule->data.priority, 413 rule->data.userdata); 414 } 415 416 static inline void 417 dump_ip4_rules(const struct acl4_rules *rule, int32_t num, int32_t extra) 418 { 419 int32_t i; 420 421 for (i = 0; i < num; i++, rule++) { 422 printf("\t%d:", i + 1); 423 print_one_ip4_rule(rule, extra); 424 printf("\n"); 425 } 426 } 427 428 static struct rte_acl_ctx * 429 acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules, 430 uint32_t rules_nb) 431 { 432 char s[PATH_MAX]; 433 struct rte_acl_param acl_param; 434 struct rte_acl_config acl_build_param; 435 struct rte_acl_ctx *ctx; 436 437 printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM); 438 439 memset(&acl_param, 0, sizeof(acl_param)); 440 441 /* Create ACL contexts */ 442 snprintf(s, sizeof(s), "%s_%d", name, socketid); 443 444 printf("IPv4 %s entries [%u]:\n", s, rules_nb); 445 dump_ip4_rules(rules, rules_nb, 1); 446 447 acl_param.name = s; 448 acl_param.socket_id = socketid; 449 acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip4_defs)); 450 acl_param.max_rule_num = MAX_ACL_RULE_NUM; 451 452 ctx = rte_acl_create(&acl_param); 453 if (ctx == NULL) 454 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n"); 455 456 if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules, 457 rules_nb) < 0) 458 rte_exit(EXIT_FAILURE, "add rules failed\n"); 459 460 /* Perform builds */ 461 memset(&acl_build_param, 0, sizeof(acl_build_param)); 462 463 acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES; 464 acl_build_param.num_fields = RTE_DIM(ip4_defs); 465 memcpy(&acl_build_param.defs, ip4_defs, sizeof(ip4_defs)); 466 467 if (rte_acl_build(ctx, &acl_build_param) != 0) 468 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n"); 469 470 rte_acl_dump(ctx); 471 472 return ctx; 473 } 474 475 void 476 sp4_init(struct socket_ctx *ctx, int32_t socket_id) 477 { 478 const char *name; 479 480 if (ctx == NULL) 481 rte_exit(EXIT_FAILURE, "NULL context.\n"); 482 483 if (ctx->sp_ip4_in != NULL) 484 rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already " 485 "initialized\n", socket_id); 486 487 if (ctx->sp_ip4_out != NULL) 488 rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already " 489 "initialized\n", socket_id); 490 491 if (nb_acl4_rules_in > 0) { 492 name = "sp_ip4_in"; 493 ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, 494 socket_id, acl4_rules_in, nb_acl4_rules_in); 495 } else 496 RTE_LOG(WARNING, IPSEC, "No IPv4 SP Inbound rule " 497 "specified\n"); 498 499 if (nb_acl4_rules_out > 0) { 500 name = "sp_ip4_out"; 501 ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, 502 socket_id, acl4_rules_out, nb_acl4_rules_out); 503 } else 504 RTE_LOG(WARNING, IPSEC, "No IPv4 SP Outbound rule " 505 "specified\n"); 506 } 507