xref: /dpdk/examples/ipsec-secgw/sp6.c (revision 9ac91e2f7339e66658ef55b756a06b328e336fde)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016 Intel Corporation
3  */
4 
5 /*
6  * Security Policies
7  */
8 #include <sys/types.h>
9 #include <netinet/in.h>
10 #include <netinet/ip6.h>
11 
12 #include <rte_acl.h>
13 #include <rte_ip.h>
14 
15 #include "ipsec.h"
16 #include "parser.h"
17 
18 #define INIT_ACL_RULE_NUM	128
19 
20 enum {
21 	IP6_PROTO,
22 	IP6_SRC0,
23 	IP6_SRC1,
24 	IP6_SRC2,
25 	IP6_SRC3,
26 	IP6_DST0,
27 	IP6_DST1,
28 	IP6_DST2,
29 	IP6_DST3,
30 	IP6_SRCP,
31 	IP6_DSTP,
32 	IP6_NUM
33 };
34 
35 static struct rte_acl_field_def ip6_defs[IP6_NUM] = {
36 	{
37 	.type = RTE_ACL_FIELD_TYPE_BITMASK,
38 	.size = sizeof(uint8_t),
39 	.field_index = IP6_PROTO,
40 	.input_index = IP6_PROTO,
41 	.offset = 0,
42 	},
43 	{
44 	.type = RTE_ACL_FIELD_TYPE_MASK,
45 	.size = 4,
46 	.field_index = IP6_SRC0,
47 	.input_index = IP6_SRC0,
48 	.offset = 2
49 	},
50 	{
51 	.type = RTE_ACL_FIELD_TYPE_MASK,
52 	.size = 4,
53 	.field_index = IP6_SRC1,
54 	.input_index = IP6_SRC1,
55 	.offset = 6
56 	},
57 	{
58 	.type = RTE_ACL_FIELD_TYPE_MASK,
59 	.size = 4,
60 	.field_index = IP6_SRC2,
61 	.input_index = IP6_SRC2,
62 	.offset = 10
63 	},
64 	{
65 	.type = RTE_ACL_FIELD_TYPE_MASK,
66 	.size = 4,
67 	.field_index = IP6_SRC3,
68 	.input_index = IP6_SRC3,
69 	.offset = 14
70 	},
71 	{
72 	.type = RTE_ACL_FIELD_TYPE_MASK,
73 	.size = 4,
74 	.field_index = IP6_DST0,
75 	.input_index = IP6_DST0,
76 	.offset = 18
77 	},
78 	{
79 	.type = RTE_ACL_FIELD_TYPE_MASK,
80 	.size = 4,
81 	.field_index = IP6_DST1,
82 	.input_index = IP6_DST1,
83 	.offset = 22
84 	},
85 	{
86 	.type = RTE_ACL_FIELD_TYPE_MASK,
87 	.size = 4,
88 	.field_index = IP6_DST2,
89 	.input_index = IP6_DST2,
90 	.offset = 26
91 	},
92 	{
93 	.type = RTE_ACL_FIELD_TYPE_MASK,
94 	.size = 4,
95 	.field_index = IP6_DST3,
96 	.input_index = IP6_DST3,
97 	.offset = 30
98 	},
99 	{
100 	.type = RTE_ACL_FIELD_TYPE_RANGE,
101 	.size = sizeof(uint16_t),
102 	.field_index = IP6_SRCP,
103 	.input_index = IP6_SRCP,
104 	.offset = 34
105 	},
106 	{
107 	.type = RTE_ACL_FIELD_TYPE_RANGE,
108 	.size = sizeof(uint16_t),
109 	.field_index = IP6_DSTP,
110 	.input_index = IP6_SRCP,
111 	.offset = 36
112 	}
113 };
114 
115 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
116 
117 static struct acl6_rules *acl6_rules_out;
118 static uint32_t nb_acl6_rules_out;
119 static uint32_t sp_out_sz;
120 
121 static struct acl6_rules *acl6_rules_in;
122 static uint32_t nb_acl6_rules_in;
123 static uint32_t sp_in_sz;
124 
125 static struct rte_ipv6_addr
126 ipv6_src_from_sp(const struct acl6_rules *rule)
127 {
128 	struct rte_ipv6_addr alignas(alignof(rte_be64_t)) addr = RTE_IPV6_ADDR_UNSPEC;
129 	rte_be64_t *values = (rte_be64_t *)&addr;
130 
131 	values[0] = rte_cpu_to_be_64((uint64_t)rule->field[IP6_SRC0].value.u32 << 32 |
132 		rule->field[IP6_SRC1].value.u32);
133 	values[1] = rte_cpu_to_be_64((uint64_t)rule->field[IP6_SRC2].value.u32 << 32 |
134 		rule->field[IP6_SRC3].value.u32);
135 
136 	return addr;
137 }
138 
139 static struct rte_ipv6_addr
140 ipv6_dst_from_sp(const struct acl6_rules *rule)
141 {
142 	struct rte_ipv6_addr alignas(alignof(rte_be64_t)) addr = RTE_IPV6_ADDR_UNSPEC;
143 	rte_be64_t *values = (rte_be64_t *)&addr;
144 
145 	values[0] = rte_cpu_to_be_64((uint64_t)rule->field[IP6_DST0].value.u32 << 32 |
146 		rule->field[IP6_DST1].value.u32);
147 	values[1] = rte_cpu_to_be_64((uint64_t)rule->field[IP6_DST2].value.u32 << 32 |
148 		rule->field[IP6_DST3].value.u32);
149 
150 	return addr;
151 }
152 
153 static uint32_t
154 ipv6_src_mask_from_sp(const struct acl6_rules *rule)
155 {
156 	return rule->field[IP6_SRC0].mask_range.u32 +
157 		rule->field[IP6_SRC1].mask_range.u32 +
158 		rule->field[IP6_SRC2].mask_range.u32 +
159 		rule->field[IP6_SRC3].mask_range.u32;
160 }
161 
162 static uint32_t
163 ipv6_dst_mask_from_sp(const struct acl6_rules *rule)
164 {
165 	return rule->field[IP6_DST0].mask_range.u32 +
166 		rule->field[IP6_DST1].mask_range.u32 +
167 		rule->field[IP6_DST2].mask_range.u32 +
168 		rule->field[IP6_DST3].mask_range.u32;
169 }
170 
171 static int
172 extend_sp_arr(struct acl6_rules **sp_tbl, uint32_t cur_cnt, uint32_t *cur_sz)
173 {
174 	if (*sp_tbl == NULL) {
175 		*sp_tbl = calloc(INIT_ACL_RULE_NUM, sizeof(struct acl6_rules));
176 		if (*sp_tbl == NULL)
177 			return -1;
178 		*cur_sz = INIT_ACL_RULE_NUM;
179 		return 0;
180 	}
181 
182 	if (cur_cnt >= *cur_sz) {
183 		*sp_tbl = realloc(*sp_tbl,
184 			*cur_sz * sizeof(struct acl6_rules) * 2);
185 		if (*sp_tbl == NULL)
186 			return -1;
187 		/* clean reallocated extra space */
188 		memset(&(*sp_tbl)[*cur_sz], 0,
189 			*cur_sz * sizeof(struct acl6_rules));
190 		*cur_sz *= 2;
191 	}
192 
193 	return 0;
194 }
195 
196 void
197 parse_sp6_tokens(char **tokens, uint32_t n_tokens,
198 	struct parse_status *status)
199 {
200 	struct acl6_rules *rule_ipv6 = NULL;
201 
202 	uint32_t *ri = NULL; /* rule index */
203 	uint32_t ti = 0; /* token index */
204 	uint32_t tv;
205 
206 	uint32_t esp_p = 0;
207 	uint32_t protect_p = 0;
208 	uint32_t bypass_p = 0;
209 	uint32_t discard_p = 0;
210 	uint32_t pri_p = 0;
211 	uint32_t src_p = 0;
212 	uint32_t dst_p = 0;
213 	uint32_t proto_p = 0;
214 	uint32_t sport_p = 0;
215 	uint32_t dport_p = 0;
216 
217 	if (strcmp(tokens[1], "in") == 0) {
218 		ri = &nb_acl6_rules_in;
219 
220 		if (extend_sp_arr(&acl6_rules_in, nb_acl6_rules_in,
221 				&sp_in_sz) < 0)
222 			return;
223 
224 		rule_ipv6 = &acl6_rules_in[*ri];
225 
226 	} else if (strcmp(tokens[1], "out") == 0) {
227 		ri = &nb_acl6_rules_out;
228 
229 		if (extend_sp_arr(&acl6_rules_out, nb_acl6_rules_out,
230 				&sp_out_sz) < 0)
231 			return;
232 
233 		rule_ipv6 = &acl6_rules_out[*ri];
234 
235 	} else {
236 		APP_CHECK(0, status, "unrecognized input \"%s\", expect"
237 			" \"in\" or \"out\"\n", tokens[ti]);
238 		return;
239 	}
240 
241 	rule_ipv6->data.category_mask = 1;
242 
243 
244 	for (ti = 2; ti < n_tokens; ti++) {
245 		if (strcmp(tokens[ti], "esp") == 0) {
246 			/* currently do nothing */
247 			APP_CHECK_PRESENCE(esp_p, tokens[ti], status);
248 			if (status->status < 0)
249 				return;
250 			esp_p = 1;
251 			continue;
252 		}
253 
254 		if (strcmp(tokens[ti], "protect") == 0) {
255 			APP_CHECK_PRESENCE(protect_p, tokens[ti], status);
256 			if (status->status < 0)
257 				return;
258 			APP_CHECK(bypass_p == 0, status, "conflict item "
259 				"between \"%s\" and \"%s\"", tokens[ti],
260 				"bypass");
261 			if (status->status < 0)
262 				return;
263 			APP_CHECK(discard_p == 0, status, "conflict item "
264 				"between \"%s\" and \"%s\"", tokens[ti],
265 				"discard");
266 			if (status->status < 0)
267 				return;
268 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
269 			if (status->status < 0)
270 				return;
271 			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
272 			if (status->status < 0)
273 				return;
274 
275 			tv = atoi(tokens[ti]);
276 			APP_CHECK(tv != DISCARD && tv != BYPASS, status,
277 				"invalid SPI: %s", tokens[ti]);
278 			if (status->status < 0)
279 				return;
280 			rule_ipv6->data.userdata = tv;
281 
282 			protect_p = 1;
283 			continue;
284 		}
285 
286 		if (strcmp(tokens[ti], "bypass") == 0) {
287 			APP_CHECK_PRESENCE(bypass_p, tokens[ti], status);
288 			if (status->status < 0)
289 				return;
290 			APP_CHECK(protect_p == 0, status, "conflict item "
291 				"between \"%s\" and \"%s\"", tokens[ti],
292 				"protect");
293 			if (status->status < 0)
294 				return;
295 			APP_CHECK(discard_p == 0, status, "conflict item "
296 				"between \"%s\" and \"%s\"", tokens[ti],
297 				"discard");
298 			if (status->status < 0)
299 				return;
300 
301 			rule_ipv6->data.userdata = BYPASS;
302 
303 			bypass_p = 1;
304 			continue;
305 		}
306 
307 		if (strcmp(tokens[ti], "discard") == 0) {
308 			APP_CHECK_PRESENCE(discard_p, tokens[ti], status);
309 			if (status->status < 0)
310 				return;
311 			APP_CHECK(protect_p == 0, status, "conflict item "
312 				"between \"%s\" and \"%s\"", tokens[ti],
313 				"protect");
314 			if (status->status < 0)
315 				return;
316 			APP_CHECK(bypass_p == 0, status, "conflict item "
317 				"between \"%s\" and \"%s\"", tokens[ti],
318 				"discard");
319 			if (status->status < 0)
320 				return;
321 
322 			rule_ipv6->data.userdata = DISCARD;
323 
324 			discard_p = 1;
325 			continue;
326 		}
327 
328 		if (strcmp(tokens[ti], "pri") == 0) {
329 			APP_CHECK_PRESENCE(pri_p, tokens[ti], status);
330 			if (status->status < 0)
331 				return;
332 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
333 			if (status->status < 0)
334 				return;
335 			APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
336 			if (status->status < 0)
337 				return;
338 
339 			rule_ipv6->data.priority = atoi(tokens[ti]);
340 
341 			pri_p = 1;
342 			continue;
343 		}
344 
345 		if (strcmp(tokens[ti], "src") == 0) {
346 			struct rte_ipv6_addr ip;
347 			uint32_t depth;
348 
349 			APP_CHECK_PRESENCE(src_p, tokens[ti], status);
350 			if (status->status < 0)
351 				return;
352 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
353 			if (status->status < 0)
354 				return;
355 
356 			APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
357 				&depth) == 0, status, "unrecognized "
358 				"input \"%s\", expect valid ipv6 "
359 				"addr", tokens[ti]);
360 			if (status->status < 0)
361 				return;
362 
363 			rule_ipv6->field[1].value.u32 =
364 				(uint32_t)ip.a[0] << 24 |
365 				(uint32_t)ip.a[1] << 16 |
366 				(uint32_t)ip.a[2] << 8 |
367 				(uint32_t)ip.a[3];
368 			rule_ipv6->field[1].mask_range.u32 =
369 				(depth > 32) ? 32 : depth;
370 			depth = (depth > 32) ? (depth - 32) : 0;
371 			rule_ipv6->field[2].value.u32 =
372 				(uint32_t)ip.a[4] << 24 |
373 				(uint32_t)ip.a[5] << 16 |
374 				(uint32_t)ip.a[6] << 8 |
375 				(uint32_t)ip.a[7];
376 			rule_ipv6->field[2].mask_range.u32 =
377 				(depth > 32) ? 32 : depth;
378 			depth = (depth > 32) ? (depth - 32) : 0;
379 			rule_ipv6->field[3].value.u32 =
380 				(uint32_t)ip.a[8] << 24 |
381 				(uint32_t)ip.a[9] << 16 |
382 				(uint32_t)ip.a[10] << 8 |
383 				(uint32_t)ip.a[11];
384 			rule_ipv6->field[3].mask_range.u32 =
385 				(depth > 32) ? 32 : depth;
386 			depth = (depth > 32) ? (depth - 32) : 0;
387 			rule_ipv6->field[4].value.u32 =
388 				(uint32_t)ip.a[12] << 24 |
389 				(uint32_t)ip.a[13] << 16 |
390 				(uint32_t)ip.a[14] << 8 |
391 				(uint32_t)ip.a[15];
392 			rule_ipv6->field[4].mask_range.u32 =
393 				(depth > 32) ? 32 : depth;
394 
395 			src_p = 1;
396 			continue;
397 		}
398 
399 		if (strcmp(tokens[ti], "dst") == 0) {
400 			struct rte_ipv6_addr ip;
401 			uint32_t depth;
402 
403 			APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
404 			if (status->status < 0)
405 				return;
406 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
407 			if (status->status < 0)
408 				return;
409 
410 			APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
411 				&depth) == 0, status, "unrecognized "
412 				"input \"%s\", expect valid ipv6 "
413 				"addr", tokens[ti]);
414 			if (status->status < 0)
415 				return;
416 
417 			rule_ipv6->field[5].value.u32 =
418 				(uint32_t)ip.a[0] << 24 |
419 				(uint32_t)ip.a[1] << 16 |
420 				(uint32_t)ip.a[2] << 8 |
421 				(uint32_t)ip.a[3];
422 			rule_ipv6->field[5].mask_range.u32 =
423 				(depth > 32) ? 32 : depth;
424 			depth = (depth > 32) ? (depth - 32) : 0;
425 			rule_ipv6->field[6].value.u32 =
426 				(uint32_t)ip.a[4] << 24 |
427 				(uint32_t)ip.a[5] << 16 |
428 				(uint32_t)ip.a[6] << 8 |
429 				(uint32_t)ip.a[7];
430 			rule_ipv6->field[6].mask_range.u32 =
431 				(depth > 32) ? 32 : depth;
432 			depth = (depth > 32) ? (depth - 32) : 0;
433 			rule_ipv6->field[7].value.u32 =
434 				(uint32_t)ip.a[8] << 24 |
435 				(uint32_t)ip.a[9] << 16 |
436 				(uint32_t)ip.a[10] << 8 |
437 				(uint32_t)ip.a[11];
438 			rule_ipv6->field[7].mask_range.u32 =
439 				(depth > 32) ? 32 : depth;
440 			depth = (depth > 32) ? (depth - 32) : 0;
441 			rule_ipv6->field[8].value.u32 =
442 				(uint32_t)ip.a[12] << 24 |
443 				(uint32_t)ip.a[13] << 16 |
444 				(uint32_t)ip.a[14] << 8 |
445 				(uint32_t)ip.a[15];
446 			rule_ipv6->field[8].mask_range.u32 =
447 				(depth > 32) ? 32 : depth;
448 
449 			dst_p = 1;
450 			continue;
451 		}
452 
453 		if (strcmp(tokens[ti], "proto") == 0) {
454 			uint16_t low, high;
455 
456 			APP_CHECK_PRESENCE(proto_p, tokens[ti], status);
457 			if (status->status < 0)
458 				return;
459 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
460 			if (status->status < 0)
461 				return;
462 
463 			APP_CHECK(parse_range(tokens[ti], &low, &high)
464 				== 0, status, "unrecognized input \"%s\""
465 				", expect \"from:to\"", tokens[ti]);
466 			if (status->status < 0)
467 				return;
468 			APP_CHECK(low <= 0xff, status, "proto low "
469 				"over-limit");
470 			if (status->status < 0)
471 				return;
472 			APP_CHECK(high <= 0xff, status, "proto high "
473 				"over-limit");
474 			if (status->status < 0)
475 				return;
476 
477 			rule_ipv6->field[0].value.u8 = (uint8_t)low;
478 			rule_ipv6->field[0].mask_range.u8 = (uint8_t)high;
479 
480 			proto_p = 1;
481 			continue;
482 		}
483 
484 		if (strcmp(tokens[ti], "sport") == 0) {
485 			uint16_t port_low, port_high;
486 
487 			APP_CHECK_PRESENCE(sport_p, tokens[ti], status);
488 			if (status->status < 0)
489 				return;
490 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
491 			if (status->status < 0)
492 				return;
493 
494 			APP_CHECK(parse_range(tokens[ti], &port_low,
495 				&port_high) == 0, status, "unrecognized "
496 				"input \"%s\", expect \"port_from:"
497 				"port_to\"", tokens[ti]);
498 			if (status->status < 0)
499 				return;
500 
501 			rule_ipv6->field[9].value.u16 = port_low;
502 			rule_ipv6->field[9].mask_range.u16 = port_high;
503 
504 			sport_p = 1;
505 			continue;
506 		}
507 
508 		if (strcmp(tokens[ti], "dport") == 0) {
509 			uint16_t port_low, port_high;
510 
511 			APP_CHECK_PRESENCE(dport_p, tokens[ti], status);
512 			if (status->status < 0)
513 				return;
514 			INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
515 			if (status->status < 0)
516 				return;
517 
518 			APP_CHECK(parse_range(tokens[ti], &port_low,
519 				&port_high) == 0, status, "unrecognized "
520 				"input \"%s\", expect \"port_from:"
521 				"port_to\"", tokens[ti]);
522 			if (status->status < 0)
523 				return;
524 
525 			rule_ipv6->field[10].value.u16 = port_low;
526 			rule_ipv6->field[10].mask_range.u16 = port_high;
527 
528 			dport_p = 1;
529 			continue;
530 		}
531 
532 		/* unrecognizable input */
533 		APP_CHECK(0, status, "unrecognized input \"%s\"",
534 			tokens[ti]);
535 		return;
536 	}
537 
538 	/* check if argument(s) are missing */
539 	APP_CHECK(esp_p == 1, status, "missing argument \"esp\"");
540 	if (status->status < 0)
541 		return;
542 
543 	APP_CHECK(protect_p | bypass_p | discard_p, status, "missing "
544 		"argument \"protect\", \"bypass\", or \"discard\"");
545 	if (status->status < 0)
546 		return;
547 
548 	*ri = *ri + 1;
549 }
550 
551 static inline void
552 print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
553 {
554 	uint8_t a, b, c, d;
555 
556 	uint32_t_to_char(rule->field[IP6_SRC0].value.u32,
557 		&a, &b, &c, &d);
558 	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
559 	uint32_t_to_char(rule->field[IP6_SRC1].value.u32,
560 		&a, &b, &c, &d);
561 	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
562 	uint32_t_to_char(rule->field[IP6_SRC2].value.u32,
563 		&a, &b, &c, &d);
564 	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
565 	uint32_t_to_char(rule->field[IP6_SRC3].value.u32,
566 		&a, &b, &c, &d);
567 	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
568 			rule->field[IP6_SRC0].mask_range.u32
569 			+ rule->field[IP6_SRC1].mask_range.u32
570 			+ rule->field[IP6_SRC2].mask_range.u32
571 			+ rule->field[IP6_SRC3].mask_range.u32);
572 
573 	uint32_t_to_char(rule->field[IP6_DST0].value.u32,
574 		&a, &b, &c, &d);
575 	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
576 	uint32_t_to_char(rule->field[IP6_DST1].value.u32,
577 		&a, &b, &c, &d);
578 	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
579 	uint32_t_to_char(rule->field[IP6_DST2].value.u32,
580 		&a, &b, &c, &d);
581 	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
582 	uint32_t_to_char(rule->field[IP6_DST3].value.u32,
583 		&a, &b, &c, &d);
584 	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
585 			rule->field[IP6_DST0].mask_range.u32
586 			+ rule->field[IP6_DST1].mask_range.u32
587 			+ rule->field[IP6_DST2].mask_range.u32
588 			+ rule->field[IP6_DST3].mask_range.u32);
589 
590 	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
591 		rule->field[IP6_SRCP].value.u16,
592 		rule->field[IP6_SRCP].mask_range.u16,
593 		rule->field[IP6_DSTP].value.u16,
594 		rule->field[IP6_DSTP].mask_range.u16,
595 		rule->field[IP6_PROTO].value.u8,
596 		rule->field[IP6_PROTO].mask_range.u8);
597 	if (extra)
598 		printf("0x%x-0x%x-0x%x ",
599 			rule->data.category_mask,
600 			rule->data.priority,
601 			rule->data.userdata);
602 }
603 
604 static inline void
605 dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
606 {
607 	int32_t i;
608 
609 	for (i = 0; i < num; i++, rule++) {
610 		printf("\t%d:", i + 1);
611 		print_one_ip6_rule(rule, extra);
612 		printf("\n");
613 	}
614 }
615 
616 static struct rte_acl_ctx *
617 acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
618 		uint32_t rules_nb)
619 {
620 	char s[PATH_MAX];
621 	struct rte_acl_param acl_param;
622 	struct rte_acl_config acl_build_param;
623 	struct rte_acl_ctx *ctx;
624 
625 	printf("Creating SP context with %u rules\n", rules_nb);
626 
627 	memset(&acl_param, 0, sizeof(acl_param));
628 
629 	/* Create ACL contexts */
630 	snprintf(s, sizeof(s), "%s_%d", name, socketid);
631 
632 	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
633 	dump_ip6_rules(rules, rules_nb, 1);
634 
635 	acl_param.name = s;
636 	acl_param.socket_id = socketid;
637 	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs));
638 	acl_param.max_rule_num = rules_nb;
639 
640 	ctx = rte_acl_create(&acl_param);
641 	if (ctx == NULL)
642 		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
643 
644 	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
645 				rules_nb) < 0)
646 		rte_exit(EXIT_FAILURE, "add rules failed\n");
647 
648 	/* Perform builds */
649 	memset(&acl_build_param, 0, sizeof(acl_build_param));
650 
651 	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
652 	acl_build_param.num_fields = RTE_DIM(ip6_defs);
653 	memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs));
654 
655 	if (rte_acl_build(ctx, &acl_build_param) != 0)
656 		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
657 
658 	rte_acl_dump(ctx);
659 
660 	return ctx;
661 }
662 
663 /*
664  * check that for each rule it's SPI has a correspondent entry in SAD
665  */
666 static int
667 check_spi_value(struct sa_ctx *sa_ctx, int inbound)
668 {
669 	uint32_t i, num, spi;
670 	int32_t spi_idx;
671 	struct acl6_rules *acr;
672 
673 	if (inbound != 0) {
674 		acr = acl6_rules_in;
675 		num = nb_acl6_rules_in;
676 	} else {
677 		acr = acl6_rules_out;
678 		num = nb_acl6_rules_out;
679 	}
680 
681 	for (i = 0; i != num; i++) {
682 		spi = acr[i].data.userdata;
683 		if (spi != DISCARD && spi != BYPASS) {
684 			spi_idx = sa_spi_present(sa_ctx, spi, inbound);
685 			if (spi_idx < 0) {
686 				RTE_LOG(ERR, IPSEC,
687 					"SPI %u is not present in SAD\n",
688 					spi);
689 				return -ENOENT;
690 			}
691 			/* Update userdata with spi index */
692 			acr[i].data.userdata = spi_idx + 1;
693 		}
694 	}
695 
696 	return 0;
697 }
698 
699 void
700 sp6_init(struct socket_ctx *ctx, int32_t socket_id)
701 {
702 	const char *name;
703 
704 	if (ctx == NULL)
705 		rte_exit(EXIT_FAILURE, "NULL context.\n");
706 
707 	if (ctx->sp_ip6_in != NULL)
708 		rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u "
709 				"already initialized\n", socket_id);
710 
711 	if (ctx->sp_ip6_out != NULL)
712 		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
713 				"already initialized\n", socket_id);
714 
715 	if (check_spi_value(ctx->sa_in, 1) < 0)
716 		rte_exit(EXIT_FAILURE,
717 			"Inbound IPv6 SP DB has unmatched in SAD SPIs\n");
718 
719 	if (check_spi_value(ctx->sa_out, 0) < 0)
720 		rte_exit(EXIT_FAILURE,
721 			"Outbound IPv6 SP DB has unmatched in SAD SPIs\n");
722 
723 	if (nb_acl6_rules_in > 0) {
724 		name = "sp_ip6_in";
725 		ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name,
726 			socket_id, acl6_rules_in, nb_acl6_rules_in);
727 	} else
728 		RTE_LOG(WARNING, IPSEC, "No IPv6 SP Inbound rule "
729 			"specified\n");
730 
731 	if (nb_acl6_rules_out > 0) {
732 		name = "sp_ip6_out";
733 		ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name,
734 			socket_id, acl6_rules_out, nb_acl6_rules_out);
735 	} else
736 		RTE_LOG(WARNING, IPSEC, "No IPv6 SP Outbound rule "
737 			"specified\n");
738 }
739 
740 static int
741 sp_cmp(const void *p, const void *q)
742 {
743 	uint32_t spi1 = ((const struct acl6_rules *)p)->data.userdata;
744 	uint32_t spi2 = ((const struct acl6_rules *)q)->data.userdata;
745 
746 	return (int)(spi1 - spi2);
747 }
748 
749 /*
750  * Search though SP rules for given SPI.
751  */
752 int
753 sp6_spi_present(uint32_t spi, int inbound, struct ip_addr ip_addr[2],
754 			uint32_t mask[2])
755 {
756 	uint32_t num;
757 	struct acl6_rules *rule;
758 	const struct acl6_rules *acr;
759 	struct acl6_rules tmpl;
760 
761 	if (inbound != 0) {
762 		acr = acl6_rules_in;
763 		num = nb_acl6_rules_in;
764 	} else {
765 		acr = acl6_rules_out;
766 		num = nb_acl6_rules_out;
767 	}
768 
769 	tmpl.data.userdata = spi;
770 
771 	rule = bsearch(&tmpl, acr, num, sizeof(struct acl6_rules), sp_cmp);
772 	if (rule != NULL) {
773 		if (NULL != ip_addr && NULL != mask) {
774 			ip_addr[0].ip.ip6 = ipv6_src_from_sp(rule);
775 			ip_addr[1].ip.ip6 = ipv6_dst_from_sp(rule);
776 			mask[0] = ipv6_src_mask_from_sp(rule);
777 			mask[1] = ipv6_dst_mask_from_sp(rule);
778 		}
779 		return RTE_PTR_DIFF(rule, acr) / sizeof(struct acl6_rules);
780 	}
781 
782 	return -ENOENT;
783 }
784 
785 void
786 sp6_sort_arr(void)
787 {
788 	qsort(acl6_rules_in, nb_acl6_rules_in, sizeof(struct acl6_rules),
789 		sp_cmp);
790 	qsort(acl6_rules_out, nb_acl6_rules_out, sizeof(struct acl6_rules),
791 		sp_cmp);
792 }
793