1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2016 Intel Corporation
9 #include <netinet/in.h>
10 #include <netinet/ip6.h>
18 #define MAX_ACL_RULE_NUM 1024
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)
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));\
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));\
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)
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)
65 #define IP6_ADDR_SIZE 16
67 static struct rte_acl_field_def ip6_defs[IP6_NUM] = {
69 .type = RTE_ACL_FIELD_TYPE_BITMASK,
70 .size = sizeof(uint8_t),
71 .field_index = IP6_PROTO,
72 .input_index = IP6_PROTO,
76 .type = RTE_ACL_FIELD_TYPE_MASK,
78 .field_index = IP6_SRC0,
79 .input_index = IP6_SRC0,
83 .type = RTE_ACL_FIELD_TYPE_MASK,
85 .field_index = IP6_SRC1,
86 .input_index = IP6_SRC1,
90 .type = RTE_ACL_FIELD_TYPE_MASK,
92 .field_index = IP6_SRC2,
93 .input_index = IP6_SRC2,
97 .type = RTE_ACL_FIELD_TYPE_MASK,
99 .field_index = IP6_SRC3,
100 .input_index = IP6_SRC3,
104 .type = RTE_ACL_FIELD_TYPE_MASK,
106 .field_index = IP6_DST0,
107 .input_index = IP6_DST0,
111 .type = RTE_ACL_FIELD_TYPE_MASK,
113 .field_index = IP6_DST1,
114 .input_index = IP6_DST1,
118 .type = RTE_ACL_FIELD_TYPE_MASK,
120 .field_index = IP6_DST2,
121 .input_index = IP6_DST2,
125 .type = RTE_ACL_FIELD_TYPE_MASK,
127 .field_index = IP6_DST3,
128 .input_index = IP6_DST3,
132 .type = RTE_ACL_FIELD_TYPE_RANGE,
133 .size = sizeof(uint16_t),
134 .field_index = IP6_SRCP,
135 .input_index = IP6_SRCP,
139 .type = RTE_ACL_FIELD_TYPE_RANGE,
140 .size = sizeof(uint16_t),
141 .field_index = IP6_DSTP,
142 .input_index = IP6_SRCP,
147 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
149 static struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM];
150 static uint32_t nb_acl6_rules_out;
152 static struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM];
153 static uint32_t nb_acl6_rules_in;
156 parse_sp6_tokens(char **tokens, uint32_t n_tokens,
157 struct parse_status *status)
159 struct acl6_rules *rule_ipv6 = NULL;
161 uint32_t *ri = NULL; /* rule index */
162 uint32_t ti = 0; /* token index */
166 uint32_t protect_p = 0;
167 uint32_t bypass_p = 0;
168 uint32_t discard_p = 0;
172 uint32_t proto_p = 0;
173 uint32_t sport_p = 0;
174 uint32_t dport_p = 0;
176 if (strcmp(tokens[1], "in") == 0) {
177 ri = &nb_acl6_rules_in;
179 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
180 "many sp rules, abort insertion\n");
181 if (status->status < 0)
184 rule_ipv6 = &acl6_rules_in[*ri];
186 } else if (strcmp(tokens[1], "out") == 0) {
187 ri = &nb_acl6_rules_out;
189 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
190 "many sp rules, abort insertion\n");
191 if (status->status < 0)
194 rule_ipv6 = &acl6_rules_out[*ri];
197 APP_CHECK(0, status, "unrecognized input \"%s\", expect"
198 " \"in\" or \"out\"\n", tokens[ti]);
202 rule_ipv6->data.category_mask = 1;
205 for (ti = 2; ti < n_tokens; ti++) {
206 if (strcmp(tokens[ti], "esp") == 0) {
207 /* currently do nothing */
208 APP_CHECK_PRESENCE(esp_p, tokens[ti], status);
209 if (status->status < 0)
215 if (strcmp(tokens[ti], "protect") == 0) {
216 APP_CHECK_PRESENCE(protect_p, tokens[ti], status);
217 if (status->status < 0)
219 APP_CHECK(bypass_p == 0, status, "conflict item "
220 "between \"%s\" and \"%s\"", tokens[ti],
222 if (status->status < 0)
224 APP_CHECK(discard_p == 0, status, "conflict item "
225 "between \"%s\" and \"%s\"", tokens[ti],
227 if (status->status < 0)
229 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
230 if (status->status < 0)
232 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
233 if (status->status < 0)
236 tv = atoi(tokens[ti]);
237 APP_CHECK(tv != DISCARD && tv != BYPASS, status,
238 "invalid SPI: %s", tokens[ti]);
239 if (status->status < 0)
241 rule_ipv6->data.userdata = tv;
247 if (strcmp(tokens[ti], "bypass") == 0) {
248 APP_CHECK_PRESENCE(bypass_p, tokens[ti], status);
249 if (status->status < 0)
251 APP_CHECK(protect_p == 0, status, "conflict item "
252 "between \"%s\" and \"%s\"", tokens[ti],
254 if (status->status < 0)
256 APP_CHECK(discard_p == 0, status, "conflict item "
257 "between \"%s\" and \"%s\"", tokens[ti],
259 if (status->status < 0)
262 rule_ipv6->data.userdata = BYPASS;
268 if (strcmp(tokens[ti], "discard") == 0) {
269 APP_CHECK_PRESENCE(discard_p, tokens[ti], status);
270 if (status->status < 0)
272 APP_CHECK(protect_p == 0, status, "conflict item "
273 "between \"%s\" and \"%s\"", tokens[ti],
275 if (status->status < 0)
277 APP_CHECK(bypass_p == 0, status, "conflict item "
278 "between \"%s\" and \"%s\"", tokens[ti],
280 if (status->status < 0)
283 rule_ipv6->data.userdata = DISCARD;
289 if (strcmp(tokens[ti], "pri") == 0) {
290 APP_CHECK_PRESENCE(pri_p, tokens[ti], status);
291 if (status->status < 0)
293 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
294 if (status->status < 0)
296 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
297 if (status->status < 0)
300 rule_ipv6->data.priority = atoi(tokens[ti]);
306 if (strcmp(tokens[ti], "src") == 0) {
310 APP_CHECK_PRESENCE(src_p, tokens[ti], status);
311 if (status->status < 0)
313 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
314 if (status->status < 0)
317 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
318 &depth) == 0, status, "unrecognized "
319 "input \"%s\", expect valid ipv6 "
321 if (status->status < 0)
324 rule_ipv6->field[1].value.u32 =
325 (uint32_t)ip.s6_addr[0] << 24 |
326 (uint32_t)ip.s6_addr[1] << 16 |
327 (uint32_t)ip.s6_addr[2] << 8 |
328 (uint32_t)ip.s6_addr[3];
329 rule_ipv6->field[1].mask_range.u32 =
330 (depth > 32) ? 32 : depth;
331 depth = (depth > 32) ? (depth - 32) : 0;
332 rule_ipv6->field[2].value.u32 =
333 (uint32_t)ip.s6_addr[4] << 24 |
334 (uint32_t)ip.s6_addr[5] << 16 |
335 (uint32_t)ip.s6_addr[6] << 8 |
336 (uint32_t)ip.s6_addr[7];
337 rule_ipv6->field[2].mask_range.u32 =
338 (depth > 32) ? 32 : depth;
339 depth = (depth > 32) ? (depth - 32) : 0;
340 rule_ipv6->field[3].value.u32 =
341 (uint32_t)ip.s6_addr[8] << 24 |
342 (uint32_t)ip.s6_addr[9] << 16 |
343 (uint32_t)ip.s6_addr[10] << 8 |
344 (uint32_t)ip.s6_addr[11];
345 rule_ipv6->field[3].mask_range.u32 =
346 (depth > 32) ? 32 : depth;
347 depth = (depth > 32) ? (depth - 32) : 0;
348 rule_ipv6->field[4].value.u32 =
349 (uint32_t)ip.s6_addr[12] << 24 |
350 (uint32_t)ip.s6_addr[13] << 16 |
351 (uint32_t)ip.s6_addr[14] << 8 |
352 (uint32_t)ip.s6_addr[15];
353 rule_ipv6->field[4].mask_range.u32 =
354 (depth > 32) ? 32 : depth;
360 if (strcmp(tokens[ti], "dst") == 0) {
364 APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
365 if (status->status < 0)
367 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
368 if (status->status < 0)
371 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
372 &depth) == 0, status, "unrecognized "
373 "input \"%s\", expect valid ipv6 "
375 if (status->status < 0)
378 rule_ipv6->field[5].value.u32 =
379 (uint32_t)ip.s6_addr[0] << 24 |
380 (uint32_t)ip.s6_addr[1] << 16 |
381 (uint32_t)ip.s6_addr[2] << 8 |
382 (uint32_t)ip.s6_addr[3];
383 rule_ipv6->field[5].mask_range.u32 =
384 (depth > 32) ? 32 : depth;
385 depth = (depth > 32) ? (depth - 32) : 0;
386 rule_ipv6->field[6].value.u32 =
387 (uint32_t)ip.s6_addr[4] << 24 |
388 (uint32_t)ip.s6_addr[5] << 16 |
389 (uint32_t)ip.s6_addr[6] << 8 |
390 (uint32_t)ip.s6_addr[7];
391 rule_ipv6->field[6].mask_range.u32 =
392 (depth > 32) ? 32 : depth;
393 depth = (depth > 32) ? (depth - 32) : 0;
394 rule_ipv6->field[7].value.u32 =
395 (uint32_t)ip.s6_addr[8] << 24 |
396 (uint32_t)ip.s6_addr[9] << 16 |
397 (uint32_t)ip.s6_addr[10] << 8 |
398 (uint32_t)ip.s6_addr[11];
399 rule_ipv6->field[7].mask_range.u32 =
400 (depth > 32) ? 32 : depth;
401 depth = (depth > 32) ? (depth - 32) : 0;
402 rule_ipv6->field[8].value.u32 =
403 (uint32_t)ip.s6_addr[12] << 24 |
404 (uint32_t)ip.s6_addr[13] << 16 |
405 (uint32_t)ip.s6_addr[14] << 8 |
406 (uint32_t)ip.s6_addr[15];
407 rule_ipv6->field[8].mask_range.u32 =
408 (depth > 32) ? 32 : depth;
414 if (strcmp(tokens[ti], "proto") == 0) {
417 APP_CHECK_PRESENCE(proto_p, tokens[ti], status);
418 if (status->status < 0)
420 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
421 if (status->status < 0)
424 APP_CHECK(parse_range(tokens[ti], &low, &high)
425 == 0, status, "unrecognized input \"%s\""
426 ", expect \"from:to\"", tokens[ti]);
427 if (status->status < 0)
429 APP_CHECK(low <= 0xff, status, "proto low "
431 if (status->status < 0)
433 APP_CHECK(high <= 0xff, status, "proto high "
435 if (status->status < 0)
438 rule_ipv6->field[0].value.u8 = (uint8_t)low;
439 rule_ipv6->field[0].mask_range.u8 = (uint8_t)high;
445 if (strcmp(tokens[ti], "sport") == 0) {
446 uint16_t port_low, port_high;
448 APP_CHECK_PRESENCE(sport_p, tokens[ti], status);
449 if (status->status < 0)
451 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
452 if (status->status < 0)
455 APP_CHECK(parse_range(tokens[ti], &port_low,
456 &port_high) == 0, status, "unrecognized "
457 "input \"%s\", expect \"port_from:"
458 "port_to\"", tokens[ti]);
459 if (status->status < 0)
462 rule_ipv6->field[9].value.u16 = port_low;
463 rule_ipv6->field[9].mask_range.u16 = port_high;
469 if (strcmp(tokens[ti], "dport") == 0) {
470 uint16_t port_low, port_high;
472 APP_CHECK_PRESENCE(dport_p, tokens[ti], status);
473 if (status->status < 0)
475 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
476 if (status->status < 0)
479 APP_CHECK(parse_range(tokens[ti], &port_low,
480 &port_high) == 0, status, "unrecognized "
481 "input \"%s\", expect \"port_from:"
482 "port_to\"", tokens[ti]);
483 if (status->status < 0)
486 rule_ipv6->field[10].value.u16 = port_low;
487 rule_ipv6->field[10].mask_range.u16 = port_high;
493 /* unrecognizeable input */
494 APP_CHECK(0, status, "unrecognized input \"%s\"",
499 /* check if argument(s) are missing */
500 APP_CHECK(esp_p == 1, status, "missing argument \"esp\"");
501 if (status->status < 0)
504 APP_CHECK(protect_p | bypass_p | discard_p, status, "missing "
505 "argument \"protect\", \"bypass\", or \"discard\"");
506 if (status->status < 0)
513 print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
517 uint32_t_to_char(rule->field[IP6_SRC0].value.u32,
519 printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
520 uint32_t_to_char(rule->field[IP6_SRC1].value.u32,
522 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
523 uint32_t_to_char(rule->field[IP6_SRC2].value.u32,
525 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
526 uint32_t_to_char(rule->field[IP6_SRC3].value.u32,
528 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
529 rule->field[IP6_SRC0].mask_range.u32
530 + rule->field[IP6_SRC1].mask_range.u32
531 + rule->field[IP6_SRC2].mask_range.u32
532 + rule->field[IP6_SRC3].mask_range.u32);
534 uint32_t_to_char(rule->field[IP6_DST0].value.u32,
536 printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
537 uint32_t_to_char(rule->field[IP6_DST1].value.u32,
539 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
540 uint32_t_to_char(rule->field[IP6_DST2].value.u32,
542 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
543 uint32_t_to_char(rule->field[IP6_DST3].value.u32,
545 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
546 rule->field[IP6_DST0].mask_range.u32
547 + rule->field[IP6_DST1].mask_range.u32
548 + rule->field[IP6_DST2].mask_range.u32
549 + rule->field[IP6_DST3].mask_range.u32);
551 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
552 rule->field[IP6_SRCP].value.u16,
553 rule->field[IP6_SRCP].mask_range.u16,
554 rule->field[IP6_DSTP].value.u16,
555 rule->field[IP6_DSTP].mask_range.u16,
556 rule->field[IP6_PROTO].value.u8,
557 rule->field[IP6_PROTO].mask_range.u8);
559 printf("0x%x-0x%x-0x%x ",
560 rule->data.category_mask,
562 rule->data.userdata);
566 dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
570 for (i = 0; i < num; i++, rule++) {
571 printf("\t%d:", i + 1);
572 print_one_ip6_rule(rule, extra);
577 static struct rte_acl_ctx *
578 acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
582 struct rte_acl_param acl_param;
583 struct rte_acl_config acl_build_param;
584 struct rte_acl_ctx *ctx;
586 printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
588 memset(&acl_param, 0, sizeof(acl_param));
590 /* Create ACL contexts */
591 snprintf(s, sizeof(s), "%s_%d", name, socketid);
593 printf("IPv4 %s entries [%u]:\n", s, rules_nb);
594 dump_ip6_rules(rules, rules_nb, 1);
597 acl_param.socket_id = socketid;
598 acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs));
599 acl_param.max_rule_num = MAX_ACL_RULE_NUM;
601 ctx = rte_acl_create(&acl_param);
603 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
605 if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
607 rte_exit(EXIT_FAILURE, "add rules failed\n");
610 memset(&acl_build_param, 0, sizeof(acl_build_param));
612 acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
613 acl_build_param.num_fields = RTE_DIM(ip6_defs);
614 memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs));
616 if (rte_acl_build(ctx, &acl_build_param) != 0)
617 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
625 * check that for each rule it's SPI has a correspondent entry in SAD
628 check_spi_value(int inbound)
630 uint32_t i, num, spi;
631 const struct acl6_rules *acr;
635 num = nb_acl6_rules_in;
637 acr = acl6_rules_out;
638 num = nb_acl6_rules_out;
641 for (i = 0; i != num; i++) {
642 spi = acr[i].data.userdata;
643 if (spi != DISCARD && spi != BYPASS &&
644 sa_spi_present(spi, inbound) < 0) {
645 RTE_LOG(ERR, IPSEC, "SPI %u is not present in SAD\n",
655 sp6_init(struct socket_ctx *ctx, int32_t socket_id)
660 rte_exit(EXIT_FAILURE, "NULL context.\n");
662 if (ctx->sp_ip6_in != NULL)
663 rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u "
664 "already initialized\n", socket_id);
666 if (ctx->sp_ip6_out != NULL)
667 rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
668 "already initialized\n", socket_id);
670 if (check_spi_value(1) < 0)
671 rte_exit(EXIT_FAILURE,
672 "Inbound IPv6 SP DB has unmatched in SAD SPIs\n");
674 if (check_spi_value(0) < 0)
675 rte_exit(EXIT_FAILURE,
676 "Outbound IPv6 SP DB has unmatched in SAD SPIs\n");
678 if (nb_acl6_rules_in > 0) {
680 ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name,
681 socket_id, acl6_rules_in, nb_acl6_rules_in);
683 RTE_LOG(WARNING, IPSEC, "No IPv6 SP Inbound rule "
686 if (nb_acl6_rules_out > 0) {
688 ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name,
689 socket_id, acl6_rules_out, nb_acl6_rules_out);
691 RTE_LOG(WARNING, IPSEC, "No IPv6 SP Outbound rule "
696 * Search though SP rules for given SPI.
699 sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
703 const struct acl6_rules *acr;
707 num = nb_acl6_rules_in;
709 acr = acl6_rules_out;
710 num = nb_acl6_rules_out;
713 for (i = 0; i != num; i++) {
714 if (acr[i].data.userdata == spi) {
715 if (NULL != ip_addr && NULL != mask) {
716 IPV6_SRC_FROM_SP(ip_addr[0], acr[i]);
717 IPV6_DST_FROM_SP(ip_addr[1], acr[i]);
718 IPV6_SRC_MASK_FROM_SP(mask[0], acr[i]);
719 IPV6_DST_MASK_FROM_SP(mask[1], acr[i]);