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 static 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 static struct acl6_rules acl6_rules_out
[MAX_ACL_RULE_NUM
];
120 static uint32_t nb_acl6_rules_out
;
122 static struct acl6_rules acl6_rules_in
[MAX_ACL_RULE_NUM
];
123 static 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 */
136 uint32_t protect_p
= 0;
137 uint32_t bypass_p
= 0;
138 uint32_t discard_p
= 0;
142 uint32_t proto_p
= 0;
143 uint32_t sport_p
= 0;
144 uint32_t dport_p
= 0;
146 if (strcmp(tokens
[1], "in") == 0) {
147 ri
= &nb_acl6_rules_in
;
149 APP_CHECK(*ri
<= MAX_ACL_RULE_NUM
- 1, status
, "too "
150 "many sp rules, abort insertion\n");
151 if (status
->status
< 0)
154 rule_ipv6
= &acl6_rules_in
[*ri
];
156 } else if (strcmp(tokens
[1], "out") == 0) {
157 ri
= &nb_acl6_rules_out
;
159 APP_CHECK(*ri
<= MAX_ACL_RULE_NUM
- 1, status
, "too "
160 "many sp rules, abort insertion\n");
161 if (status
->status
< 0)
164 rule_ipv6
= &acl6_rules_out
[*ri
];
167 APP_CHECK(0, status
, "unrecognized input \"%s\", expect"
168 " \"in\" or \"out\"\n", tokens
[ti
]);
172 rule_ipv6
->data
.category_mask
= 1;
175 for (ti
= 2; ti
< n_tokens
; ti
++) {
176 if (strcmp(tokens
[ti
], "esp") == 0) {
177 /* currently do nothing */
178 APP_CHECK_PRESENCE(esp_p
, tokens
[ti
], status
);
179 if (status
->status
< 0)
185 if (strcmp(tokens
[ti
], "protect") == 0) {
186 APP_CHECK_PRESENCE(protect_p
, tokens
[ti
], status
);
187 if (status
->status
< 0)
189 APP_CHECK(bypass_p
== 0, status
, "conflict item "
190 "between \"%s\" and \"%s\"", tokens
[ti
],
192 if (status
->status
< 0)
194 APP_CHECK(discard_p
== 0, status
, "conflict item "
195 "between \"%s\" and \"%s\"", tokens
[ti
],
197 if (status
->status
< 0)
199 INCREMENT_TOKEN_INDEX(ti
, n_tokens
, status
);
200 if (status
->status
< 0)
202 APP_CHECK_TOKEN_IS_NUM(tokens
, ti
, status
);
203 if (status
->status
< 0)
206 tv
= atoi(tokens
[ti
]);
207 APP_CHECK(tv
!= DISCARD
&& tv
!= BYPASS
, status
,
208 "invalid SPI: %s", tokens
[ti
]);
209 if (status
->status
< 0)
211 rule_ipv6
->data
.userdata
= tv
;
217 if (strcmp(tokens
[ti
], "bypass") == 0) {
218 APP_CHECK_PRESENCE(bypass_p
, tokens
[ti
], status
);
219 if (status
->status
< 0)
221 APP_CHECK(protect_p
== 0, status
, "conflict item "
222 "between \"%s\" and \"%s\"", tokens
[ti
],
224 if (status
->status
< 0)
226 APP_CHECK(discard_p
== 0, status
, "conflict item "
227 "between \"%s\" and \"%s\"", tokens
[ti
],
229 if (status
->status
< 0)
232 rule_ipv6
->data
.userdata
= BYPASS
;
238 if (strcmp(tokens
[ti
], "discard") == 0) {
239 APP_CHECK_PRESENCE(discard_p
, tokens
[ti
], status
);
240 if (status
->status
< 0)
242 APP_CHECK(protect_p
== 0, status
, "conflict item "
243 "between \"%s\" and \"%s\"", tokens
[ti
],
245 if (status
->status
< 0)
247 APP_CHECK(bypass_p
== 0, status
, "conflict item "
248 "between \"%s\" and \"%s\"", tokens
[ti
],
250 if (status
->status
< 0)
253 rule_ipv6
->data
.userdata
= DISCARD
;
259 if (strcmp(tokens
[ti
], "pri") == 0) {
260 APP_CHECK_PRESENCE(pri_p
, tokens
[ti
], status
);
261 if (status
->status
< 0)
263 INCREMENT_TOKEN_INDEX(ti
, n_tokens
, status
);
264 if (status
->status
< 0)
266 APP_CHECK_TOKEN_IS_NUM(tokens
, ti
, status
);
267 if (status
->status
< 0)
270 rule_ipv6
->data
.priority
= atoi(tokens
[ti
]);
276 if (strcmp(tokens
[ti
], "src") == 0) {
280 APP_CHECK_PRESENCE(src_p
, tokens
[ti
], status
);
281 if (status
->status
< 0)
283 INCREMENT_TOKEN_INDEX(ti
, n_tokens
, status
);
284 if (status
->status
< 0)
287 APP_CHECK(parse_ipv6_addr(tokens
[ti
], &ip
,
288 &depth
) == 0, status
, "unrecognized "
289 "input \"%s\", expect valid ipv6 "
291 if (status
->status
< 0)
294 rule_ipv6
->field
[1].value
.u32
=
295 (uint32_t)ip
.s6_addr
[0] << 24 |
296 (uint32_t)ip
.s6_addr
[1] << 16 |
297 (uint32_t)ip
.s6_addr
[2] << 8 |
298 (uint32_t)ip
.s6_addr
[3];
299 rule_ipv6
->field
[1].mask_range
.u32
=
300 (depth
> 32) ? 32 : depth
;
301 depth
= (depth
> 32) ? (depth
- 32) : 0;
302 rule_ipv6
->field
[2].value
.u32
=
303 (uint32_t)ip
.s6_addr
[4] << 24 |
304 (uint32_t)ip
.s6_addr
[5] << 16 |
305 (uint32_t)ip
.s6_addr
[6] << 8 |
306 (uint32_t)ip
.s6_addr
[7];
307 rule_ipv6
->field
[2].mask_range
.u32
=
308 (depth
> 32) ? 32 : depth
;
309 depth
= (depth
> 32) ? (depth
- 32) : 0;
310 rule_ipv6
->field
[3].value
.u32
=
311 (uint32_t)ip
.s6_addr
[8] << 24 |
312 (uint32_t)ip
.s6_addr
[9] << 16 |
313 (uint32_t)ip
.s6_addr
[10] << 8 |
314 (uint32_t)ip
.s6_addr
[11];
315 rule_ipv6
->field
[3].mask_range
.u32
=
316 (depth
> 32) ? 32 : depth
;
317 depth
= (depth
> 32) ? (depth
- 32) : 0;
318 rule_ipv6
->field
[4].value
.u32
=
319 (uint32_t)ip
.s6_addr
[12] << 24 |
320 (uint32_t)ip
.s6_addr
[13] << 16 |
321 (uint32_t)ip
.s6_addr
[14] << 8 |
322 (uint32_t)ip
.s6_addr
[15];
323 rule_ipv6
->field
[4].mask_range
.u32
=
324 (depth
> 32) ? 32 : depth
;
330 if (strcmp(tokens
[ti
], "dst") == 0) {
334 APP_CHECK_PRESENCE(dst_p
, tokens
[ti
], status
);
335 if (status
->status
< 0)
337 INCREMENT_TOKEN_INDEX(ti
, n_tokens
, status
);
338 if (status
->status
< 0)
341 APP_CHECK(parse_ipv6_addr(tokens
[ti
], &ip
,
342 &depth
) == 0, status
, "unrecognized "
343 "input \"%s\", expect valid ipv6 "
345 if (status
->status
< 0)
348 rule_ipv6
->field
[5].value
.u32
=
349 (uint32_t)ip
.s6_addr
[0] << 24 |
350 (uint32_t)ip
.s6_addr
[1] << 16 |
351 (uint32_t)ip
.s6_addr
[2] << 8 |
352 (uint32_t)ip
.s6_addr
[3];
353 rule_ipv6
->field
[5].mask_range
.u32
=
354 (depth
> 32) ? 32 : depth
;
355 depth
= (depth
> 32) ? (depth
- 32) : 0;
356 rule_ipv6
->field
[6].value
.u32
=
357 (uint32_t)ip
.s6_addr
[4] << 24 |
358 (uint32_t)ip
.s6_addr
[5] << 16 |
359 (uint32_t)ip
.s6_addr
[6] << 8 |
360 (uint32_t)ip
.s6_addr
[7];
361 rule_ipv6
->field
[6].mask_range
.u32
=
362 (depth
> 32) ? 32 : depth
;
363 depth
= (depth
> 32) ? (depth
- 32) : 0;
364 rule_ipv6
->field
[7].value
.u32
=
365 (uint32_t)ip
.s6_addr
[8] << 24 |
366 (uint32_t)ip
.s6_addr
[9] << 16 |
367 (uint32_t)ip
.s6_addr
[10] << 8 |
368 (uint32_t)ip
.s6_addr
[11];
369 rule_ipv6
->field
[7].mask_range
.u32
=
370 (depth
> 32) ? 32 : depth
;
371 depth
= (depth
> 32) ? (depth
- 32) : 0;
372 rule_ipv6
->field
[8].value
.u32
=
373 (uint32_t)ip
.s6_addr
[12] << 24 |
374 (uint32_t)ip
.s6_addr
[13] << 16 |
375 (uint32_t)ip
.s6_addr
[14] << 8 |
376 (uint32_t)ip
.s6_addr
[15];
377 rule_ipv6
->field
[8].mask_range
.u32
=
378 (depth
> 32) ? 32 : depth
;
384 if (strcmp(tokens
[ti
], "proto") == 0) {
387 APP_CHECK_PRESENCE(proto_p
, tokens
[ti
], status
);
388 if (status
->status
< 0)
390 INCREMENT_TOKEN_INDEX(ti
, n_tokens
, status
);
391 if (status
->status
< 0)
394 APP_CHECK(parse_range(tokens
[ti
], &low
, &high
)
395 == 0, status
, "unrecognized input \"%s\""
396 ", expect \"from:to\"", tokens
[ti
]);
397 if (status
->status
< 0)
399 APP_CHECK(low
<= 0xff, status
, "proto low "
401 if (status
->status
< 0)
403 APP_CHECK(high
<= 0xff, status
, "proto high "
405 if (status
->status
< 0)
408 rule_ipv6
->field
[0].value
.u8
= (uint8_t)low
;
409 rule_ipv6
->field
[0].mask_range
.u8
= (uint8_t)high
;
415 if (strcmp(tokens
[ti
], "sport") == 0) {
416 uint16_t port_low
, port_high
;
418 APP_CHECK_PRESENCE(sport_p
, tokens
[ti
], status
);
419 if (status
->status
< 0)
421 INCREMENT_TOKEN_INDEX(ti
, n_tokens
, status
);
422 if (status
->status
< 0)
425 APP_CHECK(parse_range(tokens
[ti
], &port_low
,
426 &port_high
) == 0, status
, "unrecognized "
427 "input \"%s\", expect \"port_from:"
428 "port_to\"", tokens
[ti
]);
429 if (status
->status
< 0)
432 rule_ipv6
->field
[9].value
.u16
= port_low
;
433 rule_ipv6
->field
[9].mask_range
.u16
= port_high
;
439 if (strcmp(tokens
[ti
], "dport") == 0) {
440 uint16_t port_low
, port_high
;
442 APP_CHECK_PRESENCE(dport_p
, tokens
[ti
], status
);
443 if (status
->status
< 0)
445 INCREMENT_TOKEN_INDEX(ti
, n_tokens
, status
);
446 if (status
->status
< 0)
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)
456 rule_ipv6
->field
[10].value
.u16
= port_low
;
457 rule_ipv6
->field
[10].mask_range
.u16
= port_high
;
463 /* unrecognizeable input */
464 APP_CHECK(0, status
, "unrecognized input \"%s\"",
469 /* check if argument(s) are missing */
470 APP_CHECK(esp_p
== 1, status
, "missing argument \"esp\"");
471 if (status
->status
< 0)
474 APP_CHECK(protect_p
| bypass_p
| discard_p
, status
, "missing "
475 "argument \"protect\", \"bypass\", or \"discard\"");
476 if (status
->status
< 0)
483 print_one_ip6_rule(const struct acl6_rules
*rule
, int32_t extra
)
487 uint32_t_to_char(rule
->field
[IP6_SRC0
].value
.u32
,
489 printf("%.2x%.2x:%.2x%.2x", a
, b
, c
, d
);
490 uint32_t_to_char(rule
->field
[IP6_SRC1
].value
.u32
,
492 printf(":%.2x%.2x:%.2x%.2x", a
, b
, c
, d
);
493 uint32_t_to_char(rule
->field
[IP6_SRC2
].value
.u32
,
495 printf(":%.2x%.2x:%.2x%.2x", a
, b
, c
, d
);
496 uint32_t_to_char(rule
->field
[IP6_SRC3
].value
.u32
,
498 printf(":%.2x%.2x:%.2x%.2x/%u ", a
, b
, c
, d
,
499 rule
->field
[IP6_SRC0
].mask_range
.u32
500 + rule
->field
[IP6_SRC1
].mask_range
.u32
501 + rule
->field
[IP6_SRC2
].mask_range
.u32
502 + rule
->field
[IP6_SRC3
].mask_range
.u32
);
504 uint32_t_to_char(rule
->field
[IP6_DST0
].value
.u32
,
506 printf("%.2x%.2x:%.2x%.2x", a
, b
, c
, d
);
507 uint32_t_to_char(rule
->field
[IP6_DST1
].value
.u32
,
509 printf(":%.2x%.2x:%.2x%.2x", a
, b
, c
, d
);
510 uint32_t_to_char(rule
->field
[IP6_DST2
].value
.u32
,
512 printf(":%.2x%.2x:%.2x%.2x", a
, b
, c
, d
);
513 uint32_t_to_char(rule
->field
[IP6_DST3
].value
.u32
,
515 printf(":%.2x%.2x:%.2x%.2x/%u ", a
, b
, c
, d
,
516 rule
->field
[IP6_DST0
].mask_range
.u32
517 + rule
->field
[IP6_DST1
].mask_range
.u32
518 + rule
->field
[IP6_DST2
].mask_range
.u32
519 + rule
->field
[IP6_DST3
].mask_range
.u32
);
521 printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
522 rule
->field
[IP6_SRCP
].value
.u16
,
523 rule
->field
[IP6_SRCP
].mask_range
.u16
,
524 rule
->field
[IP6_DSTP
].value
.u16
,
525 rule
->field
[IP6_DSTP
].mask_range
.u16
,
526 rule
->field
[IP6_PROTO
].value
.u8
,
527 rule
->field
[IP6_PROTO
].mask_range
.u8
);
529 printf("0x%x-0x%x-0x%x ",
530 rule
->data
.category_mask
,
532 rule
->data
.userdata
);
536 dump_ip6_rules(const struct acl6_rules
*rule
, int32_t num
, int32_t extra
)
540 for (i
= 0; i
< num
; i
++, rule
++) {
541 printf("\t%d:", i
+ 1);
542 print_one_ip6_rule(rule
, extra
);
547 static struct rte_acl_ctx
*
548 acl6_init(const char *name
, int32_t socketid
, const struct acl6_rules
*rules
,
552 struct rte_acl_param acl_param
;
553 struct rte_acl_config acl_build_param
;
554 struct rte_acl_ctx
*ctx
;
556 printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM
);
558 memset(&acl_param
, 0, sizeof(acl_param
));
560 /* Create ACL contexts */
561 snprintf(s
, sizeof(s
), "%s_%d", name
, socketid
);
563 printf("IPv4 %s entries [%u]:\n", s
, rules_nb
);
564 dump_ip6_rules(rules
, rules_nb
, 1);
567 acl_param
.socket_id
= socketid
;
568 acl_param
.rule_size
= RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs
));
569 acl_param
.max_rule_num
= MAX_ACL_RULE_NUM
;
571 ctx
= rte_acl_create(&acl_param
);
573 rte_exit(EXIT_FAILURE
, "Failed to create ACL context\n");
575 if (rte_acl_add_rules(ctx
, (const struct rte_acl_rule
*)rules
,
577 rte_exit(EXIT_FAILURE
, "add rules failed\n");
580 memset(&acl_build_param
, 0, sizeof(acl_build_param
));
582 acl_build_param
.num_categories
= DEFAULT_MAX_CATEGORIES
;
583 acl_build_param
.num_fields
= RTE_DIM(ip6_defs
);
584 memcpy(&acl_build_param
.defs
, ip6_defs
, sizeof(ip6_defs
));
586 if (rte_acl_build(ctx
, &acl_build_param
) != 0)
587 rte_exit(EXIT_FAILURE
, "Failed to build ACL trie\n");
595 * check that for each rule it's SPI has a correspondent entry in SAD
598 check_spi_value(int inbound
)
600 uint32_t i
, num
, spi
;
601 const struct acl6_rules
*acr
;
605 num
= nb_acl6_rules_in
;
607 acr
= acl6_rules_out
;
608 num
= nb_acl6_rules_out
;
611 for (i
= 0; i
!= num
; i
++) {
612 spi
= acr
[i
].data
.userdata
;
613 if (spi
!= DISCARD
&& spi
!= BYPASS
&&
614 sa_spi_present(spi
, inbound
) < 0) {
615 RTE_LOG(ERR
, IPSEC
, "SPI %u is not present in SAD\n",
625 sp6_init(struct socket_ctx
*ctx
, int32_t socket_id
)
630 rte_exit(EXIT_FAILURE
, "NULL context.\n");
632 if (ctx
->sp_ip6_in
!= NULL
)
633 rte_exit(EXIT_FAILURE
, "Inbound IPv6 SP DB for socket %u "
634 "already initialized\n", socket_id
);
636 if (ctx
->sp_ip6_out
!= NULL
)
637 rte_exit(EXIT_FAILURE
, "Outbound IPv6 SP DB for socket %u "
638 "already initialized\n", socket_id
);
640 if (check_spi_value(1) < 0)
641 rte_exit(EXIT_FAILURE
,
642 "Inbound IPv6 SP DB has unmatched in SAD SPIs\n");
644 if (check_spi_value(0) < 0)
645 rte_exit(EXIT_FAILURE
,
646 "Outbound IPv6 SP DB has unmatched in SAD SPIs\n");
648 if (nb_acl6_rules_in
> 0) {
650 ctx
->sp_ip6_in
= (struct sp_ctx
*)acl6_init(name
,
651 socket_id
, acl6_rules_in
, nb_acl6_rules_in
);
653 RTE_LOG(WARNING
, IPSEC
, "No IPv6 SP Inbound rule "
656 if (nb_acl6_rules_out
> 0) {
658 ctx
->sp_ip6_out
= (struct sp_ctx
*)acl6_init(name
,
659 socket_id
, acl6_rules_out
, nb_acl6_rules_out
);
661 RTE_LOG(WARNING
, IPSEC
, "No IPv6 SP Outbound rule "
666 * Search though SP rules for given SPI.
669 sp6_spi_present(uint32_t spi
, int inbound
)
672 const struct acl6_rules
*acr
;
676 num
= nb_acl6_rules_in
;
678 acr
= acl6_rules_out
;
679 num
= nb_acl6_rules_out
;
682 for (i
= 0; i
!= num
; i
++) {
683 if (acr
[i
].data
.userdata
== spi
)