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
35 #define IP6_ADDR_SIZE 16
37 struct rte_acl_field_def ip6_defs[IP6_NUM] = {
39 .type = RTE_ACL_FIELD_TYPE_BITMASK,
40 .size = sizeof(uint8_t),
41 .field_index = IP6_PROTO,
42 .input_index = IP6_PROTO,
46 .type = RTE_ACL_FIELD_TYPE_MASK,
48 .field_index = IP6_SRC0,
49 .input_index = IP6_SRC0,
53 .type = RTE_ACL_FIELD_TYPE_MASK,
55 .field_index = IP6_SRC1,
56 .input_index = IP6_SRC1,
60 .type = RTE_ACL_FIELD_TYPE_MASK,
62 .field_index = IP6_SRC2,
63 .input_index = IP6_SRC2,
67 .type = RTE_ACL_FIELD_TYPE_MASK,
69 .field_index = IP6_SRC3,
70 .input_index = IP6_SRC3,
74 .type = RTE_ACL_FIELD_TYPE_MASK,
76 .field_index = IP6_DST0,
77 .input_index = IP6_DST0,
81 .type = RTE_ACL_FIELD_TYPE_MASK,
83 .field_index = IP6_DST1,
84 .input_index = IP6_DST1,
88 .type = RTE_ACL_FIELD_TYPE_MASK,
90 .field_index = IP6_DST2,
91 .input_index = IP6_DST2,
95 .type = RTE_ACL_FIELD_TYPE_MASK,
97 .field_index = IP6_DST3,
98 .input_index = IP6_DST3,
102 .type = RTE_ACL_FIELD_TYPE_RANGE,
103 .size = sizeof(uint16_t),
104 .field_index = IP6_SRCP,
105 .input_index = IP6_SRCP,
109 .type = RTE_ACL_FIELD_TYPE_RANGE,
110 .size = sizeof(uint16_t),
111 .field_index = IP6_DSTP,
112 .input_index = IP6_SRCP,
117 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
119 struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM];
120 uint32_t nb_acl6_rules_out;
122 struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM];
123 uint32_t nb_acl6_rules_in;
126 parse_sp6_tokens(char **tokens, uint32_t n_tokens,
127 struct parse_status *status)
129 struct acl6_rules *rule_ipv6 = NULL;
131 uint32_t *ri = NULL; /* rule index */
132 uint32_t ti = 0; /* token index */
135 uint32_t protect_p = 0;
136 uint32_t bypass_p = 0;
137 uint32_t discard_p = 0;
141 uint32_t proto_p = 0;
142 uint32_t sport_p = 0;
143 uint32_t dport_p = 0;
145 if (strcmp(tokens[1], "in") == 0) {
146 ri = &nb_acl6_rules_in;
148 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
149 "many sp rules, abort insertion\n");
150 if (status->status < 0)
153 rule_ipv6 = &acl6_rules_in[*ri];
155 } else if (strcmp(tokens[1], "out") == 0) {
156 ri = &nb_acl6_rules_out;
158 APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
159 "many sp rules, abort insertion\n");
160 if (status->status < 0)
163 rule_ipv6 = &acl6_rules_out[*ri];
166 APP_CHECK(0, status, "unrecognized input \"%s\", expect"
167 " \"in\" or \"out\"\n", tokens[ti]);
171 rule_ipv6->data.category_mask = 1;
174 for (ti = 2; ti < n_tokens; ti++) {
175 if (strcmp(tokens[ti], "esp") == 0) {
176 /* currently do nothing */
177 APP_CHECK_PRESENCE(esp_p, tokens[ti], status);
178 if (status->status < 0)
184 if (strcmp(tokens[ti], "protect") == 0) {
185 APP_CHECK_PRESENCE(protect_p, tokens[ti], status);
186 if (status->status < 0)
188 APP_CHECK(bypass_p == 0, status, "conflict item "
189 "between \"%s\" and \"%s\"", tokens[ti],
191 if (status->status < 0)
193 APP_CHECK(discard_p == 0, status, "conflict item "
194 "between \"%s\" and \"%s\"", tokens[ti],
196 if (status->status < 0)
198 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
199 if (status->status < 0)
201 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
202 if (status->status < 0)
205 rule_ipv6->data.userdata =
206 PROTECT(atoi(tokens[ti]));
212 if (strcmp(tokens[ti], "bypass") == 0) {
213 APP_CHECK_PRESENCE(bypass_p, tokens[ti], status);
214 if (status->status < 0)
216 APP_CHECK(protect_p == 0, status, "conflict item "
217 "between \"%s\" and \"%s\"", tokens[ti],
219 if (status->status < 0)
221 APP_CHECK(discard_p == 0, status, "conflict item "
222 "between \"%s\" and \"%s\"", tokens[ti],
224 if (status->status < 0)
227 rule_ipv6->data.userdata = BYPASS;
233 if (strcmp(tokens[ti], "discard") == 0) {
234 APP_CHECK_PRESENCE(discard_p, tokens[ti], status);
235 if (status->status < 0)
237 APP_CHECK(protect_p == 0, status, "conflict item "
238 "between \"%s\" and \"%s\"", tokens[ti],
240 if (status->status < 0)
242 APP_CHECK(bypass_p == 0, status, "conflict item "
243 "between \"%s\" and \"%s\"", tokens[ti],
245 if (status->status < 0)
248 rule_ipv6->data.userdata = DISCARD;
254 if (strcmp(tokens[ti], "pri") == 0) {
255 APP_CHECK_PRESENCE(pri_p, tokens[ti], status);
256 if (status->status < 0)
258 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
259 if (status->status < 0)
261 APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
262 if (status->status < 0)
265 rule_ipv6->data.priority = atoi(tokens[ti]);
271 if (strcmp(tokens[ti], "src") == 0) {
275 APP_CHECK_PRESENCE(src_p, tokens[ti], status);
276 if (status->status < 0)
278 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
279 if (status->status < 0)
282 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
283 &depth) == 0, status, "unrecognized "
284 "input \"%s\", expect valid ipv6 "
286 if (status->status < 0)
289 rule_ipv6->field[1].value.u32 =
290 (uint32_t)ip.s6_addr[0] << 24 |
291 (uint32_t)ip.s6_addr[1] << 16 |
292 (uint32_t)ip.s6_addr[2] << 8 |
293 (uint32_t)ip.s6_addr[3];
294 rule_ipv6->field[1].mask_range.u32 =
295 (depth > 32) ? 32 : depth;
296 depth = (depth > 32) ? (depth - 32) : 0;
297 rule_ipv6->field[2].value.u32 =
298 (uint32_t)ip.s6_addr[4] << 24 |
299 (uint32_t)ip.s6_addr[5] << 16 |
300 (uint32_t)ip.s6_addr[6] << 8 |
301 (uint32_t)ip.s6_addr[7];
302 rule_ipv6->field[2].mask_range.u32 =
303 (depth > 32) ? 32 : depth;
304 depth = (depth > 32) ? (depth - 32) : 0;
305 rule_ipv6->field[3].value.u32 =
306 (uint32_t)ip.s6_addr[8] << 24 |
307 (uint32_t)ip.s6_addr[9] << 16 |
308 (uint32_t)ip.s6_addr[10] << 8 |
309 (uint32_t)ip.s6_addr[11];
310 rule_ipv6->field[3].mask_range.u32 =
311 (depth > 32) ? 32 : depth;
312 depth = (depth > 32) ? (depth - 32) : 0;
313 rule_ipv6->field[4].value.u32 =
314 (uint32_t)ip.s6_addr[12] << 24 |
315 (uint32_t)ip.s6_addr[13] << 16 |
316 (uint32_t)ip.s6_addr[14] << 8 |
317 (uint32_t)ip.s6_addr[15];
318 rule_ipv6->field[4].mask_range.u32 =
319 (depth > 32) ? 32 : depth;
325 if (strcmp(tokens[ti], "dst") == 0) {
329 APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
330 if (status->status < 0)
332 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
333 if (status->status < 0)
336 APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
337 &depth) == 0, status, "unrecognized "
338 "input \"%s\", expect valid ipv6 "
340 if (status->status < 0)
343 rule_ipv6->field[5].value.u32 =
344 (uint32_t)ip.s6_addr[0] << 24 |
345 (uint32_t)ip.s6_addr[1] << 16 |
346 (uint32_t)ip.s6_addr[2] << 8 |
347 (uint32_t)ip.s6_addr[3];
348 rule_ipv6->field[5].mask_range.u32 =
349 (depth > 32) ? 32 : depth;
350 depth = (depth > 32) ? (depth - 32) : 0;
351 rule_ipv6->field[6].value.u32 =
352 (uint32_t)ip.s6_addr[4] << 24 |
353 (uint32_t)ip.s6_addr[5] << 16 |
354 (uint32_t)ip.s6_addr[6] << 8 |
355 (uint32_t)ip.s6_addr[7];
356 rule_ipv6->field[6].mask_range.u32 =
357 (depth > 32) ? 32 : depth;
358 depth = (depth > 32) ? (depth - 32) : 0;
359 rule_ipv6->field[7].value.u32 =
360 (uint32_t)ip.s6_addr[8] << 24 |
361 (uint32_t)ip.s6_addr[9] << 16 |
362 (uint32_t)ip.s6_addr[10] << 8 |
363 (uint32_t)ip.s6_addr[11];
364 rule_ipv6->field[7].mask_range.u32 =
365 (depth > 32) ? 32 : depth;
366 depth = (depth > 32) ? (depth - 32) : 0;
367 rule_ipv6->field[8].value.u32 =
368 (uint32_t)ip.s6_addr[12] << 24 |
369 (uint32_t)ip.s6_addr[13] << 16 |
370 (uint32_t)ip.s6_addr[14] << 8 |
371 (uint32_t)ip.s6_addr[15];
372 rule_ipv6->field[8].mask_range.u32 =
373 (depth > 32) ? 32 : depth;
379 if (strcmp(tokens[ti], "proto") == 0) {
382 APP_CHECK_PRESENCE(proto_p, tokens[ti], status);
383 if (status->status < 0)
385 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
386 if (status->status < 0)
389 APP_CHECK(parse_range(tokens[ti], &low, &high)
390 == 0, status, "unrecognized input \"%s\""
391 ", expect \"from:to\"", tokens[ti]);
392 if (status->status < 0)
394 APP_CHECK(low <= 0xff, status, "proto low "
396 if (status->status < 0)
398 APP_CHECK(high <= 0xff, status, "proto high "
400 if (status->status < 0)
403 rule_ipv6->field[0].value.u8 = (uint8_t)low;
404 rule_ipv6->field[0].mask_range.u8 = (uint8_t)high;
410 if (strcmp(tokens[ti], "sport") == 0) {
411 uint16_t port_low, port_high;
413 APP_CHECK_PRESENCE(sport_p, tokens[ti], status);
414 if (status->status < 0)
416 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
417 if (status->status < 0)
420 APP_CHECK(parse_range(tokens[ti], &port_low,
421 &port_high) == 0, status, "unrecognized "
422 "input \"%s\", expect \"port_from:"
423 "port_to\"", tokens[ti]);
424 if (status->status < 0)
427 rule_ipv6->field[9].value.u16 = port_low;
428 rule_ipv6->field[9].mask_range.u16 = port_high;
434 if (strcmp(tokens[ti], "dport") == 0) {
435 uint16_t port_low, port_high;
437 APP_CHECK_PRESENCE(dport_p, tokens[ti], status);
438 if (status->status < 0)
440 INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
441 if (status->status < 0)
444 APP_CHECK(parse_range(tokens[ti], &port_low,
445 &port_high) == 0, status, "unrecognized "
446 "input \"%s\", expect \"port_from:"
447 "port_to\"", tokens[ti]);
448 if (status->status < 0)
451 rule_ipv6->field[10].value.u16 = port_low;
452 rule_ipv6->field[10].mask_range.u16 = port_high;
458 /* unrecognizeable input */
459 APP_CHECK(0, status, "unrecognized input \"%s\"",
464 /* check if argument(s) are missing */
465 APP_CHECK(esp_p == 1, status, "missing argument \"esp\"");
466 if (status->status < 0)
469 APP_CHECK(protect_p | bypass_p | discard_p, status, "missing "
470 "argument \"protect\", \"bypass\", or \"discard\"");
471 if (status->status < 0)
478 print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
482 uint32_t_to_char(rule->field[IP6_SRC0].value.u32,
484 printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
485 uint32_t_to_char(rule->field[IP6_SRC1].value.u32,
487 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
488 uint32_t_to_char(rule->field[IP6_SRC2].value.u32,
490 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
491 uint32_t_to_char(rule->field[IP6_SRC3].value.u32,
493 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
494 rule->field[IP6_SRC0].mask_range.u32
495 + rule->field[IP6_SRC1].mask_range.u32
496 + rule->field[IP6_SRC2].mask_range.u32
497 + rule->field[IP6_SRC3].mask_range.u32);
499 uint32_t_to_char(rule->field[IP6_DST0].value.u32,
501 printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
502 uint32_t_to_char(rule->field[IP6_DST1].value.u32,
504 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
505 uint32_t_to_char(rule->field[IP6_DST2].value.u32,
507 printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
508 uint32_t_to_char(rule->field[IP6_DST3].value.u32,
510 printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
511 rule->field[IP6_DST0].mask_range.u32
512 + rule->field[IP6_DST1].mask_range.u32
513 + rule->field[IP6_DST2].mask_range.u32
514 + rule->field[IP6_DST3].mask_range.u32);
516 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
517 rule->field[IP6_SRCP].value.u16,
518 rule->field[IP6_SRCP].mask_range.u16,
519 rule->field[IP6_DSTP].value.u16,
520 rule->field[IP6_DSTP].mask_range.u16,
521 rule->field[IP6_PROTO].value.u8,
522 rule->field[IP6_PROTO].mask_range.u8);
524 printf("0x%x-0x%x-0x%x ",
525 rule->data.category_mask,
527 rule->data.userdata);
531 dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
535 for (i = 0; i < num; i++, rule++) {
536 printf("\t%d:", i + 1);
537 print_one_ip6_rule(rule, extra);
542 static struct rte_acl_ctx *
543 acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
547 struct rte_acl_param acl_param;
548 struct rte_acl_config acl_build_param;
549 struct rte_acl_ctx *ctx;
551 printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
553 memset(&acl_param, 0, sizeof(acl_param));
555 /* Create ACL contexts */
556 snprintf(s, sizeof(s), "%s_%d", name, socketid);
558 printf("IPv4 %s entries [%u]:\n", s, rules_nb);
559 dump_ip6_rules(rules, rules_nb, 1);
562 acl_param.socket_id = socketid;
563 acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs));
564 acl_param.max_rule_num = MAX_ACL_RULE_NUM;
566 ctx = rte_acl_create(&acl_param);
568 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
570 if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
572 rte_exit(EXIT_FAILURE, "add rules failed\n");
575 memset(&acl_build_param, 0, sizeof(acl_build_param));
577 acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
578 acl_build_param.num_fields = RTE_DIM(ip6_defs);
579 memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs));
581 if (rte_acl_build(ctx, &acl_build_param) != 0)
582 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
590 sp6_init(struct socket_ctx *ctx, int32_t socket_id)
595 rte_exit(EXIT_FAILURE, "NULL context.\n");
597 if (ctx->sp_ip6_in != NULL)
598 rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u "
599 "already initialized\n", socket_id);
601 if (ctx->sp_ip6_out != NULL)
602 rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
603 "already initialized\n", socket_id);
605 if (nb_acl6_rules_in > 0) {
607 ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name,
608 socket_id, acl6_rules_in, nb_acl6_rules_in);
610 RTE_LOG(WARNING, IPSEC, "No IPv6 SP Inbound rule "
613 if (nb_acl6_rules_out > 0) {
615 ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name,
616 socket_id, acl6_rules_out, nb_acl6_rules_out);
618 RTE_LOG(WARNING, IPSEC, "No IPv6 SP Outbound rule "