1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2016 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Security Policies 36 */ 37 #include <sys/types.h> 38 #include <netinet/in.h> 39 #include <netinet/ip.h> 40 41 #include <rte_acl.h> 42 #include <rte_ip.h> 43 44 #include "ipsec.h" 45 #include "parser.h" 46 47 #define MAX_ACL_RULE_NUM 1024 48 49 /* 50 * Rule and trace formats definitions. 51 */ 52 enum { 53 PROTO_FIELD_IPV4, 54 SRC_FIELD_IPV4, 55 DST_FIELD_IPV4, 56 SRCP_FIELD_IPV4, 57 DSTP_FIELD_IPV4, 58 NUM_FIELDS_IPV4 59 }; 60 61 /* 62 * That effectively defines order of IPV4 classifications: 63 * - PROTO 64 * - SRC IP ADDRESS 65 * - DST IP ADDRESS 66 * - PORTS (SRC and DST) 67 */ 68 enum { 69 RTE_ACL_IPV4_PROTO, 70 RTE_ACL_IPV4_SRC, 71 RTE_ACL_IPV4_DST, 72 RTE_ACL_IPV4_PORTS, 73 RTE_ACL_IPV4_NUM 74 }; 75 76 struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = { 77 { 78 .type = RTE_ACL_FIELD_TYPE_BITMASK, 79 .size = sizeof(uint8_t), 80 .field_index = PROTO_FIELD_IPV4, 81 .input_index = RTE_ACL_IPV4_PROTO, 82 .offset = 0, 83 }, 84 { 85 .type = RTE_ACL_FIELD_TYPE_MASK, 86 .size = sizeof(uint32_t), 87 .field_index = SRC_FIELD_IPV4, 88 .input_index = RTE_ACL_IPV4_SRC, 89 .offset = offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p) 90 }, 91 { 92 .type = RTE_ACL_FIELD_TYPE_MASK, 93 .size = sizeof(uint32_t), 94 .field_index = DST_FIELD_IPV4, 95 .input_index = RTE_ACL_IPV4_DST, 96 .offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p) 97 }, 98 { 99 .type = RTE_ACL_FIELD_TYPE_RANGE, 100 .size = sizeof(uint16_t), 101 .field_index = SRCP_FIELD_IPV4, 102 .input_index = RTE_ACL_IPV4_PORTS, 103 .offset = sizeof(struct ip) - offsetof(struct ip, ip_p) 104 }, 105 { 106 .type = RTE_ACL_FIELD_TYPE_RANGE, 107 .size = sizeof(uint16_t), 108 .field_index = DSTP_FIELD_IPV4, 109 .input_index = RTE_ACL_IPV4_PORTS, 110 .offset = sizeof(struct ip) - offsetof(struct ip, ip_p) + 111 sizeof(uint16_t) 112 }, 113 }; 114 115 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs)); 116 117 struct acl4_rules acl4_rules_out[MAX_ACL_RULE_NUM]; 118 uint32_t nb_acl4_rules_out; 119 120 struct acl4_rules acl4_rules_in[MAX_ACL_RULE_NUM]; 121 uint32_t nb_acl4_rules_in; 122 123 void 124 parse_sp4_tokens(char **tokens, uint32_t n_tokens, 125 struct parse_status *status) 126 { 127 struct acl4_rules *rule_ipv4 = NULL; 128 129 uint32_t *ri = NULL; /* rule index */ 130 uint32_t ti = 0; /* token index */ 131 132 uint32_t esp_p = 0; 133 uint32_t protect_p = 0; 134 uint32_t bypass_p = 0; 135 uint32_t discard_p = 0; 136 uint32_t pri_p = 0; 137 uint32_t src_p = 0; 138 uint32_t dst_p = 0; 139 uint32_t proto_p = 0; 140 uint32_t sport_p = 0; 141 uint32_t dport_p = 0; 142 143 if (strcmp(tokens[1], "in") == 0) { 144 ri = &nb_acl4_rules_in; 145 146 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, 147 "too many sp rules, abort insertion\n"); 148 if (status->status < 0) 149 return; 150 151 rule_ipv4 = &acl4_rules_in[*ri]; 152 153 } else if (strcmp(tokens[1], "out") == 0) { 154 ri = &nb_acl4_rules_out; 155 156 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, 157 "too many sp rules, abort insertion\n"); 158 if (status->status < 0) 159 return; 160 161 rule_ipv4 = &acl4_rules_out[*ri]; 162 } else { 163 APP_CHECK(0, status, "unrecognized input \"%s\", expect" 164 " \"in\" or \"out\"\n", tokens[ti]); 165 return; 166 } 167 168 rule_ipv4->data.category_mask = 1; 169 170 for (ti = 2; ti < n_tokens; ti++) { 171 if (strcmp(tokens[ti], "esp") == 0) { 172 /* currently do nothing */ 173 APP_CHECK_PRESENCE(esp_p, tokens[ti], status); 174 if (status->status < 0) 175 return; 176 esp_p = 1; 177 continue; 178 } 179 180 if (strcmp(tokens[ti], "protect") == 0) { 181 APP_CHECK_PRESENCE(protect_p, tokens[ti], status); 182 if (status->status < 0) 183 return; 184 APP_CHECK(bypass_p == 0, status, "conflict item " 185 "between \"%s\" and \"%s\"", tokens[ti], 186 "bypass"); 187 if (status->status < 0) 188 return; 189 APP_CHECK(discard_p == 0, status, "conflict item " 190 "between \"%s\" and \"%s\"", tokens[ti], 191 "discard"); 192 if (status->status < 0) 193 return; 194 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 195 if (status->status < 0) 196 return; 197 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 198 if (status->status < 0) 199 return; 200 201 rule_ipv4->data.userdata = 202 PROTECT(atoi(tokens[ti])); 203 204 protect_p = 1; 205 continue; 206 } 207 208 if (strcmp(tokens[ti], "bypass") == 0) { 209 APP_CHECK_PRESENCE(bypass_p, tokens[ti], status); 210 if (status->status < 0) 211 return; 212 APP_CHECK(protect_p == 0, status, "conflict item " 213 "between \"%s\" and \"%s\"", tokens[ti], 214 "protect"); 215 if (status->status < 0) 216 return; 217 APP_CHECK(discard_p == 0, status, "conflict item " 218 "between \"%s\" and \"%s\"", tokens[ti], 219 "discard"); 220 if (status->status < 0) 221 return; 222 223 rule_ipv4->data.userdata = BYPASS; 224 225 bypass_p = 1; 226 continue; 227 } 228 229 if (strcmp(tokens[ti], "discard") == 0) { 230 APP_CHECK_PRESENCE(discard_p, tokens[ti], status); 231 if (status->status < 0) 232 return; 233 APP_CHECK(protect_p == 0, status, "conflict item " 234 "between \"%s\" and \"%s\"", tokens[ti], 235 "protect"); 236 if (status->status < 0) 237 return; 238 APP_CHECK(bypass_p == 0, status, "conflict item " 239 "between \"%s\" and \"%s\"", tokens[ti], 240 "discard"); 241 if (status->status < 0) 242 return; 243 244 rule_ipv4->data.userdata = DISCARD; 245 246 discard_p = 1; 247 continue; 248 } 249 250 if (strcmp(tokens[ti], "pri") == 0) { 251 APP_CHECK_PRESENCE(pri_p, tokens[ti], status); 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 rule_ipv4->data.priority = atoi(tokens[ti]); 262 263 pri_p = 1; 264 continue; 265 } 266 267 if (strcmp(tokens[ti], "src") == 0) { 268 struct in_addr ip; 269 uint32_t depth; 270 271 APP_CHECK_PRESENCE(src_p, tokens[ti], status); 272 if (status->status < 0) 273 return; 274 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 275 if (status->status < 0) 276 return; 277 278 APP_CHECK(parse_ipv4_addr(tokens[ti], &ip, 279 &depth) == 0, status, "unrecognized " 280 "input \"%s\", expect valid ipv4 addr", 281 tokens[ti]); 282 if (status->status < 0) 283 return; 284 285 rule_ipv4->field[1].value.u32 = 286 rte_bswap32(ip.s_addr); 287 rule_ipv4->field[1].mask_range.u32 = 288 depth; 289 290 src_p = 1; 291 continue; 292 } 293 294 if (strcmp(tokens[ti], "dst") == 0) { 295 struct in_addr ip; 296 uint32_t depth; 297 298 APP_CHECK_PRESENCE(dst_p, tokens[ti], status); 299 if (status->status < 0) 300 return; 301 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 302 if (status->status < 0) 303 return; 304 APP_CHECK(parse_ipv4_addr(tokens[ti], &ip, 305 &depth) == 0, status, "unrecognized " 306 "input \"%s\", expect valid ipv4 addr", 307 tokens[ti]); 308 if (status->status < 0) 309 return; 310 311 rule_ipv4->field[2].value.u32 = 312 rte_bswap32(ip.s_addr); 313 rule_ipv4->field[2].mask_range.u32 = 314 depth; 315 316 dst_p = 1; 317 continue; 318 } 319 320 if (strcmp(tokens[ti], "proto") == 0) { 321 uint16_t low, high; 322 323 APP_CHECK_PRESENCE(proto_p, tokens[ti], status); 324 if (status->status < 0) 325 return; 326 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 327 if (status->status < 0) 328 return; 329 330 APP_CHECK(parse_range(tokens[ti], &low, &high) 331 == 0, status, "unrecognized input \"%s\"" 332 ", expect \"from:to\"", tokens[ti]); 333 if (status->status < 0) 334 return; 335 APP_CHECK(low <= 0xff, status, "proto low " 336 "over-limit"); 337 if (status->status < 0) 338 return; 339 APP_CHECK(high <= 0xff, status, "proto high " 340 "over-limit"); 341 if (status->status < 0) 342 return; 343 344 rule_ipv4->field[0].value.u8 = (uint8_t)low; 345 rule_ipv4->field[0].mask_range.u8 = (uint8_t)high; 346 347 proto_p = 1; 348 continue; 349 } 350 351 if (strcmp(tokens[ti], "sport") == 0) { 352 uint16_t port_low, port_high; 353 354 APP_CHECK_PRESENCE(sport_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[3].value.u16 = port_low; 369 rule_ipv4->field[3].mask_range.u16 = port_high; 370 371 sport_p = 1; 372 continue; 373 } 374 375 if (strcmp(tokens[ti], "dport") == 0) { 376 uint16_t port_low, port_high; 377 378 APP_CHECK_PRESENCE(dport_p, tokens[ti], status); 379 if (status->status < 0) 380 return; 381 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 382 if (status->status < 0) 383 return; 384 385 APP_CHECK(parse_range(tokens[ti], &port_low, 386 &port_high) == 0, status, "unrecognized " 387 "input \"%s\", expect \"port_from:" 388 "port_to\"", tokens[ti]); 389 if (status->status < 0) 390 return; 391 392 rule_ipv4->field[4].value.u16 = port_low; 393 rule_ipv4->field[4].mask_range.u16 = port_high; 394 395 dport_p = 1; 396 continue; 397 } 398 399 /* unrecognizeable input */ 400 APP_CHECK(0, status, "unrecognized input \"%s\"", 401 tokens[ti]); 402 return; 403 } 404 405 /* check if argument(s) are missing */ 406 APP_CHECK(esp_p == 1, status, "missing argument \"esp\""); 407 if (status->status < 0) 408 return; 409 410 APP_CHECK(protect_p | bypass_p | discard_p, status, "missing " 411 "argument \"protect\", \"bypass\", or \"discard\""); 412 if (status->status < 0) 413 return; 414 415 *ri = *ri + 1; 416 } 417 418 static void 419 print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra) 420 { 421 uint8_t a, b, c, d; 422 423 uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32, 424 &a, &b, &c, &d); 425 printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d, 426 rule->field[SRC_FIELD_IPV4].mask_range.u32); 427 uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32, 428 &a, &b, &c, &d); 429 printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d, 430 rule->field[DST_FIELD_IPV4].mask_range.u32); 431 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ", 432 rule->field[SRCP_FIELD_IPV4].value.u16, 433 rule->field[SRCP_FIELD_IPV4].mask_range.u16, 434 rule->field[DSTP_FIELD_IPV4].value.u16, 435 rule->field[DSTP_FIELD_IPV4].mask_range.u16, 436 rule->field[PROTO_FIELD_IPV4].value.u8, 437 rule->field[PROTO_FIELD_IPV4].mask_range.u8); 438 if (extra) 439 printf("0x%x-0x%x-0x%x ", 440 rule->data.category_mask, 441 rule->data.priority, 442 rule->data.userdata); 443 } 444 445 static inline void 446 dump_ip4_rules(const struct acl4_rules *rule, int32_t num, int32_t extra) 447 { 448 int32_t i; 449 450 for (i = 0; i < num; i++, rule++) { 451 printf("\t%d:", i + 1); 452 print_one_ip4_rule(rule, extra); 453 printf("\n"); 454 } 455 } 456 457 static struct rte_acl_ctx * 458 acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules, 459 uint32_t rules_nb) 460 { 461 char s[PATH_MAX]; 462 struct rte_acl_param acl_param; 463 struct rte_acl_config acl_build_param; 464 struct rte_acl_ctx *ctx; 465 466 printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM); 467 468 memset(&acl_param, 0, sizeof(acl_param)); 469 470 /* Create ACL contexts */ 471 snprintf(s, sizeof(s), "%s_%d", name, socketid); 472 473 printf("IPv4 %s entries [%u]:\n", s, rules_nb); 474 dump_ip4_rules(rules, rules_nb, 1); 475 476 acl_param.name = s; 477 acl_param.socket_id = socketid; 478 acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip4_defs)); 479 acl_param.max_rule_num = MAX_ACL_RULE_NUM; 480 481 ctx = rte_acl_create(&acl_param); 482 if (ctx == NULL) 483 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n"); 484 485 if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules, 486 rules_nb) < 0) 487 rte_exit(EXIT_FAILURE, "add rules failed\n"); 488 489 /* Perform builds */ 490 memset(&acl_build_param, 0, sizeof(acl_build_param)); 491 492 acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES; 493 acl_build_param.num_fields = RTE_DIM(ip4_defs); 494 memcpy(&acl_build_param.defs, ip4_defs, sizeof(ip4_defs)); 495 496 if (rte_acl_build(ctx, &acl_build_param) != 0) 497 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n"); 498 499 rte_acl_dump(ctx); 500 501 return ctx; 502 } 503 504 void 505 sp4_init(struct socket_ctx *ctx, int32_t socket_id) 506 { 507 const char *name; 508 509 if (ctx == NULL) 510 rte_exit(EXIT_FAILURE, "NULL context.\n"); 511 512 if (ctx->sp_ip4_in != NULL) 513 rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already " 514 "initialized\n", socket_id); 515 516 if (ctx->sp_ip4_out != NULL) 517 rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already " 518 "initialized\n", socket_id); 519 520 if (nb_acl4_rules_in > 0) { 521 name = "sp_ip4_in"; 522 ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, 523 socket_id, acl4_rules_in, nb_acl4_rules_in); 524 } else 525 RTE_LOG(WARNING, IPSEC, "No IPv4 SP Inbound rule " 526 "specified\n"); 527 528 if (nb_acl4_rules_out > 0) { 529 name = "sp_ip4_out"; 530 ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, 531 socket_id, acl4_rules_out, nb_acl4_rules_out); 532 } else 533 RTE_LOG(WARNING, IPSEC, "No IPv4 SP Outbound rule " 534 "specified\n"); 535 } 536