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/ip6.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 enum { 50 IP6_PROTO, 51 IP6_SRC0, 52 IP6_SRC1, 53 IP6_SRC2, 54 IP6_SRC3, 55 IP6_DST0, 56 IP6_DST1, 57 IP6_DST2, 58 IP6_DST3, 59 IP6_SRCP, 60 IP6_DSTP, 61 IP6_NUM 62 }; 63 64 #define IP6_ADDR_SIZE 16 65 66 struct rte_acl_field_def ip6_defs[IP6_NUM] = { 67 { 68 .type = RTE_ACL_FIELD_TYPE_BITMASK, 69 .size = sizeof(uint8_t), 70 .field_index = IP6_PROTO, 71 .input_index = IP6_PROTO, 72 .offset = 0, 73 }, 74 { 75 .type = RTE_ACL_FIELD_TYPE_MASK, 76 .size = 4, 77 .field_index = IP6_SRC0, 78 .input_index = IP6_SRC0, 79 .offset = 2 80 }, 81 { 82 .type = RTE_ACL_FIELD_TYPE_MASK, 83 .size = 4, 84 .field_index = IP6_SRC1, 85 .input_index = IP6_SRC1, 86 .offset = 6 87 }, 88 { 89 .type = RTE_ACL_FIELD_TYPE_MASK, 90 .size = 4, 91 .field_index = IP6_SRC2, 92 .input_index = IP6_SRC2, 93 .offset = 10 94 }, 95 { 96 .type = RTE_ACL_FIELD_TYPE_MASK, 97 .size = 4, 98 .field_index = IP6_SRC3, 99 .input_index = IP6_SRC3, 100 .offset = 14 101 }, 102 { 103 .type = RTE_ACL_FIELD_TYPE_MASK, 104 .size = 4, 105 .field_index = IP6_DST0, 106 .input_index = IP6_DST0, 107 .offset = 18 108 }, 109 { 110 .type = RTE_ACL_FIELD_TYPE_MASK, 111 .size = 4, 112 .field_index = IP6_DST1, 113 .input_index = IP6_DST1, 114 .offset = 22 115 }, 116 { 117 .type = RTE_ACL_FIELD_TYPE_MASK, 118 .size = 4, 119 .field_index = IP6_DST2, 120 .input_index = IP6_DST2, 121 .offset = 26 122 }, 123 { 124 .type = RTE_ACL_FIELD_TYPE_MASK, 125 .size = 4, 126 .field_index = IP6_DST3, 127 .input_index = IP6_DST3, 128 .offset = 30 129 }, 130 { 131 .type = RTE_ACL_FIELD_TYPE_RANGE, 132 .size = sizeof(uint16_t), 133 .field_index = IP6_SRCP, 134 .input_index = IP6_SRCP, 135 .offset = 34 136 }, 137 { 138 .type = RTE_ACL_FIELD_TYPE_RANGE, 139 .size = sizeof(uint16_t), 140 .field_index = IP6_DSTP, 141 .input_index = IP6_SRCP, 142 .offset = 36 143 } 144 }; 145 146 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs)); 147 148 struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM]; 149 uint32_t nb_acl6_rules_out; 150 151 struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM]; 152 uint32_t nb_acl6_rules_in; 153 154 void 155 parse_sp6_tokens(char **tokens, uint32_t n_tokens, 156 struct parse_status *status) 157 { 158 struct acl6_rules *rule_ipv6 = NULL; 159 160 uint32_t *ri = NULL; /* rule index */ 161 uint32_t ti = 0; /* token index */ 162 163 uint32_t esp_p = 0; 164 uint32_t protect_p = 0; 165 uint32_t bypass_p = 0; 166 uint32_t discard_p = 0; 167 uint32_t pri_p = 0; 168 uint32_t src_p = 0; 169 uint32_t dst_p = 0; 170 uint32_t proto_p = 0; 171 uint32_t sport_p = 0; 172 uint32_t dport_p = 0; 173 174 if (strcmp(tokens[1], "in") == 0) { 175 ri = &nb_acl6_rules_in; 176 177 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too " 178 "many sp rules, abort insertion\n"); 179 if (status->status < 0) 180 return; 181 182 rule_ipv6 = &acl6_rules_in[*ri]; 183 184 } else if (strcmp(tokens[1], "out") == 0) { 185 ri = &nb_acl6_rules_out; 186 187 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too " 188 "many sp rules, abort insertion\n"); 189 if (status->status < 0) 190 return; 191 192 rule_ipv6 = &acl6_rules_out[*ri]; 193 194 } else { 195 APP_CHECK(0, status, "unrecognized input \"%s\", expect" 196 " \"in\" or \"out\"\n", tokens[ti]); 197 return; 198 } 199 200 rule_ipv6->data.category_mask = 1; 201 202 203 for (ti = 2; ti < n_tokens; ti++) { 204 if (strcmp(tokens[ti], "esp") == 0) { 205 /* currently do nothing */ 206 APP_CHECK_PRESENCE(esp_p, tokens[ti], status); 207 if (status->status < 0) 208 return; 209 esp_p = 1; 210 continue; 211 } 212 213 if (strcmp(tokens[ti], "protect") == 0) { 214 APP_CHECK_PRESENCE(protect_p, tokens[ti], status); 215 if (status->status < 0) 216 return; 217 APP_CHECK(bypass_p == 0, status, "conflict item " 218 "between \"%s\" and \"%s\"", tokens[ti], 219 "bypass"); 220 if (status->status < 0) 221 return; 222 APP_CHECK(discard_p == 0, status, "conflict item " 223 "between \"%s\" and \"%s\"", tokens[ti], 224 "discard"); 225 if (status->status < 0) 226 return; 227 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 228 if (status->status < 0) 229 return; 230 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 231 if (status->status < 0) 232 return; 233 234 rule_ipv6->data.userdata = 235 PROTECT(atoi(tokens[ti])); 236 237 protect_p = 1; 238 continue; 239 } 240 241 if (strcmp(tokens[ti], "bypass") == 0) { 242 APP_CHECK_PRESENCE(bypass_p, tokens[ti], status); 243 if (status->status < 0) 244 return; 245 APP_CHECK(protect_p == 0, status, "conflict item " 246 "between \"%s\" and \"%s\"", tokens[ti], 247 "protect"); 248 if (status->status < 0) 249 return; 250 APP_CHECK(discard_p == 0, status, "conflict item " 251 "between \"%s\" and \"%s\"", tokens[ti], 252 "discard"); 253 if (status->status < 0) 254 return; 255 256 rule_ipv6->data.userdata = BYPASS; 257 258 bypass_p = 1; 259 continue; 260 } 261 262 if (strcmp(tokens[ti], "discard") == 0) { 263 APP_CHECK_PRESENCE(discard_p, tokens[ti], status); 264 if (status->status < 0) 265 return; 266 APP_CHECK(protect_p == 0, status, "conflict item " 267 "between \"%s\" and \"%s\"", tokens[ti], 268 "protect"); 269 if (status->status < 0) 270 return; 271 APP_CHECK(bypass_p == 0, status, "conflict item " 272 "between \"%s\" and \"%s\"", tokens[ti], 273 "discard"); 274 if (status->status < 0) 275 return; 276 277 rule_ipv6->data.userdata = DISCARD; 278 279 discard_p = 1; 280 continue; 281 } 282 283 if (strcmp(tokens[ti], "pri") == 0) { 284 APP_CHECK_PRESENCE(pri_p, tokens[ti], status); 285 if (status->status < 0) 286 return; 287 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 288 if (status->status < 0) 289 return; 290 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status); 291 if (status->status < 0) 292 return; 293 294 rule_ipv6->data.priority = atoi(tokens[ti]); 295 296 pri_p = 1; 297 continue; 298 } 299 300 if (strcmp(tokens[ti], "src") == 0) { 301 struct in6_addr ip; 302 uint32_t depth; 303 304 APP_CHECK_PRESENCE(src_p, tokens[ti], status); 305 if (status->status < 0) 306 return; 307 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 308 if (status->status < 0) 309 return; 310 311 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip, 312 &depth) == 0, status, "unrecognized " 313 "input \"%s\", expect valid ipv6 " 314 "addr", tokens[ti]); 315 if (status->status < 0) 316 return; 317 318 rule_ipv6->field[1].value.u32 = 319 (uint32_t)ip.s6_addr[0] << 24 | 320 (uint32_t)ip.s6_addr[1] << 16 | 321 (uint32_t)ip.s6_addr[2] << 8 | 322 (uint32_t)ip.s6_addr[3]; 323 rule_ipv6->field[1].mask_range.u32 = 324 (depth > 32) ? 32 : depth; 325 depth = (depth > 32) ? (depth - 32) : 0; 326 rule_ipv6->field[2].value.u32 = 327 (uint32_t)ip.s6_addr[4] << 24 | 328 (uint32_t)ip.s6_addr[5] << 16 | 329 (uint32_t)ip.s6_addr[6] << 8 | 330 (uint32_t)ip.s6_addr[7]; 331 rule_ipv6->field[2].mask_range.u32 = 332 (depth > 32) ? 32 : depth; 333 depth = (depth > 32) ? (depth - 32) : 0; 334 rule_ipv6->field[3].value.u32 = 335 (uint32_t)ip.s6_addr[8] << 24 | 336 (uint32_t)ip.s6_addr[9] << 16 | 337 (uint32_t)ip.s6_addr[10] << 8 | 338 (uint32_t)ip.s6_addr[11]; 339 rule_ipv6->field[3].mask_range.u32 = 340 (depth > 32) ? 32 : depth; 341 depth = (depth > 32) ? (depth - 32) : 0; 342 rule_ipv6->field[4].value.u32 = 343 (uint32_t)ip.s6_addr[12] << 24 | 344 (uint32_t)ip.s6_addr[13] << 16 | 345 (uint32_t)ip.s6_addr[14] << 8 | 346 (uint32_t)ip.s6_addr[15]; 347 rule_ipv6->field[4].mask_range.u32 = 348 (depth > 32) ? 32 : depth; 349 350 src_p = 1; 351 continue; 352 } 353 354 if (strcmp(tokens[ti], "dst") == 0) { 355 struct in6_addr ip; 356 uint32_t depth; 357 358 APP_CHECK_PRESENCE(dst_p, tokens[ti], status); 359 if (status->status < 0) 360 return; 361 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 362 if (status->status < 0) 363 return; 364 365 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip, 366 &depth) == 0, status, "unrecognized " 367 "input \"%s\", expect valid ipv6 " 368 "addr", tokens[ti]); 369 if (status->status < 0) 370 return; 371 372 rule_ipv6->field[5].value.u32 = 373 (uint32_t)ip.s6_addr[0] << 24 | 374 (uint32_t)ip.s6_addr[1] << 16 | 375 (uint32_t)ip.s6_addr[2] << 8 | 376 (uint32_t)ip.s6_addr[3]; 377 rule_ipv6->field[5].mask_range.u32 = 378 (depth > 32) ? 32 : depth; 379 depth = (depth > 32) ? (depth - 32) : 0; 380 rule_ipv6->field[6].value.u32 = 381 (uint32_t)ip.s6_addr[4] << 24 | 382 (uint32_t)ip.s6_addr[5] << 16 | 383 (uint32_t)ip.s6_addr[6] << 8 | 384 (uint32_t)ip.s6_addr[7]; 385 rule_ipv6->field[6].mask_range.u32 = 386 (depth > 32) ? 32 : depth; 387 depth = (depth > 32) ? (depth - 32) : 0; 388 rule_ipv6->field[7].value.u32 = 389 (uint32_t)ip.s6_addr[8] << 24 | 390 (uint32_t)ip.s6_addr[9] << 16 | 391 (uint32_t)ip.s6_addr[10] << 8 | 392 (uint32_t)ip.s6_addr[11]; 393 rule_ipv6->field[7].mask_range.u32 = 394 (depth > 32) ? 32 : depth; 395 depth = (depth > 32) ? (depth - 32) : 0; 396 rule_ipv6->field[8].value.u32 = 397 (uint32_t)ip.s6_addr[12] << 24 | 398 (uint32_t)ip.s6_addr[13] << 16 | 399 (uint32_t)ip.s6_addr[14] << 8 | 400 (uint32_t)ip.s6_addr[15]; 401 rule_ipv6->field[8].mask_range.u32 = 402 (depth > 32) ? 32 : depth; 403 404 dst_p = 1; 405 continue; 406 } 407 408 if (strcmp(tokens[ti], "proto") == 0) { 409 uint16_t low, high; 410 411 APP_CHECK_PRESENCE(proto_p, tokens[ti], status); 412 if (status->status < 0) 413 return; 414 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 415 if (status->status < 0) 416 return; 417 418 APP_CHECK(parse_range(tokens[ti], &low, &high) 419 == 0, status, "unrecognized input \"%s\"" 420 ", expect \"from:to\"", tokens[ti]); 421 if (status->status < 0) 422 return; 423 APP_CHECK(low <= 0xff, status, "proto low " 424 "over-limit"); 425 if (status->status < 0) 426 return; 427 APP_CHECK(high <= 0xff, status, "proto high " 428 "over-limit"); 429 if (status->status < 0) 430 return; 431 432 rule_ipv6->field[0].value.u8 = (uint8_t)low; 433 rule_ipv6->field[0].mask_range.u8 = (uint8_t)high; 434 435 proto_p = 1; 436 continue; 437 } 438 439 if (strcmp(tokens[ti], "sport") == 0) { 440 uint16_t port_low, port_high; 441 442 APP_CHECK_PRESENCE(sport_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], &port_low, 450 &port_high) == 0, status, "unrecognized " 451 "input \"%s\", expect \"port_from:" 452 "port_to\"", tokens[ti]); 453 if (status->status < 0) 454 return; 455 456 rule_ipv6->field[9].value.u16 = port_low; 457 rule_ipv6->field[9].mask_range.u16 = port_high; 458 459 sport_p = 1; 460 continue; 461 } 462 463 if (strcmp(tokens[ti], "dport") == 0) { 464 uint16_t port_low, port_high; 465 466 APP_CHECK_PRESENCE(dport_p, tokens[ti], status); 467 if (status->status < 0) 468 return; 469 INCREMENT_TOKEN_INDEX(ti, n_tokens, status); 470 if (status->status < 0) 471 return; 472 473 APP_CHECK(parse_range(tokens[ti], &port_low, 474 &port_high) == 0, status, "unrecognized " 475 "input \"%s\", expect \"port_from:" 476 "port_to\"", tokens[ti]); 477 if (status->status < 0) 478 return; 479 480 rule_ipv6->field[10].value.u16 = port_low; 481 rule_ipv6->field[10].mask_range.u16 = port_high; 482 483 dport_p = 1; 484 continue; 485 } 486 487 /* unrecognizeable input */ 488 APP_CHECK(0, status, "unrecognized input \"%s\"", 489 tokens[ti]); 490 return; 491 } 492 493 /* check if argument(s) are missing */ 494 APP_CHECK(esp_p == 1, status, "missing argument \"esp\""); 495 if (status->status < 0) 496 return; 497 498 APP_CHECK(protect_p | bypass_p | discard_p, status, "missing " 499 "argument \"protect\", \"bypass\", or \"discard\""); 500 if (status->status < 0) 501 return; 502 503 *ri = *ri + 1; 504 } 505 506 static inline void 507 print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra) 508 { 509 uint8_t a, b, c, d; 510 511 uint32_t_to_char(rule->field[IP6_SRC0].value.u32, 512 &a, &b, &c, &d); 513 printf("%.2x%.2x:%.2x%.2x", a, b, c, d); 514 uint32_t_to_char(rule->field[IP6_SRC1].value.u32, 515 &a, &b, &c, &d); 516 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 517 uint32_t_to_char(rule->field[IP6_SRC2].value.u32, 518 &a, &b, &c, &d); 519 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 520 uint32_t_to_char(rule->field[IP6_SRC3].value.u32, 521 &a, &b, &c, &d); 522 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d, 523 rule->field[IP6_SRC0].mask_range.u32 524 + rule->field[IP6_SRC1].mask_range.u32 525 + rule->field[IP6_SRC2].mask_range.u32 526 + rule->field[IP6_SRC3].mask_range.u32); 527 528 uint32_t_to_char(rule->field[IP6_DST0].value.u32, 529 &a, &b, &c, &d); 530 printf("%.2x%.2x:%.2x%.2x", a, b, c, d); 531 uint32_t_to_char(rule->field[IP6_DST1].value.u32, 532 &a, &b, &c, &d); 533 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 534 uint32_t_to_char(rule->field[IP6_DST2].value.u32, 535 &a, &b, &c, &d); 536 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d); 537 uint32_t_to_char(rule->field[IP6_DST3].value.u32, 538 &a, &b, &c, &d); 539 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d, 540 rule->field[IP6_DST0].mask_range.u32 541 + rule->field[IP6_DST1].mask_range.u32 542 + rule->field[IP6_DST2].mask_range.u32 543 + rule->field[IP6_DST3].mask_range.u32); 544 545 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ", 546 rule->field[IP6_SRCP].value.u16, 547 rule->field[IP6_SRCP].mask_range.u16, 548 rule->field[IP6_DSTP].value.u16, 549 rule->field[IP6_DSTP].mask_range.u16, 550 rule->field[IP6_PROTO].value.u8, 551 rule->field[IP6_PROTO].mask_range.u8); 552 if (extra) 553 printf("0x%x-0x%x-0x%x ", 554 rule->data.category_mask, 555 rule->data.priority, 556 rule->data.userdata); 557 } 558 559 static inline void 560 dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra) 561 { 562 int32_t i; 563 564 for (i = 0; i < num; i++, rule++) { 565 printf("\t%d:", i + 1); 566 print_one_ip6_rule(rule, extra); 567 printf("\n"); 568 } 569 } 570 571 static struct rte_acl_ctx * 572 acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules, 573 uint32_t rules_nb) 574 { 575 char s[PATH_MAX]; 576 struct rte_acl_param acl_param; 577 struct rte_acl_config acl_build_param; 578 struct rte_acl_ctx *ctx; 579 580 printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM); 581 582 memset(&acl_param, 0, sizeof(acl_param)); 583 584 /* Create ACL contexts */ 585 snprintf(s, sizeof(s), "%s_%d", name, socketid); 586 587 printf("IPv4 %s entries [%u]:\n", s, rules_nb); 588 dump_ip6_rules(rules, rules_nb, 1); 589 590 acl_param.name = s; 591 acl_param.socket_id = socketid; 592 acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs)); 593 acl_param.max_rule_num = MAX_ACL_RULE_NUM; 594 595 ctx = rte_acl_create(&acl_param); 596 if (ctx == NULL) 597 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n"); 598 599 if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules, 600 rules_nb) < 0) 601 rte_exit(EXIT_FAILURE, "add rules failed\n"); 602 603 /* Perform builds */ 604 memset(&acl_build_param, 0, sizeof(acl_build_param)); 605 606 acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES; 607 acl_build_param.num_fields = RTE_DIM(ip6_defs); 608 memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs)); 609 610 if (rte_acl_build(ctx, &acl_build_param) != 0) 611 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n"); 612 613 rte_acl_dump(ctx); 614 615 return ctx; 616 } 617 618 void 619 sp6_init(struct socket_ctx *ctx, int32_t socket_id) 620 { 621 const char *name; 622 623 if (ctx == NULL) 624 rte_exit(EXIT_FAILURE, "NULL context.\n"); 625 626 if (ctx->sp_ip6_in != NULL) 627 rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u " 628 "already initialized\n", socket_id); 629 630 if (ctx->sp_ip6_out != NULL) 631 rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u " 632 "already initialized\n", socket_id); 633 634 if (nb_acl6_rules_in > 0) { 635 name = "sp_ip6_in"; 636 ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name, 637 socket_id, acl6_rules_in, nb_acl6_rules_in); 638 } else 639 RTE_LOG(WARNING, IPSEC, "No IPv6 SP Inbound rule " 640 "specified\n"); 641 642 if (nb_acl6_rules_out > 0) { 643 name = "sp_ip6_out"; 644 ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name, 645 socket_id, acl6_rules_out, nb_acl6_rules_out); 646 } else 647 RTE_LOG(WARNING, IPSEC, "No IPv6 SP Outbound rule " 648 "specified\n"); 649 } 650