xref: /dpdk/examples/ipsec-secgw/sp6.c (revision 906257e9)
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 
46 #define MAX_ACL_RULE_NUM	1000
47 
48 enum {
49 	IP6_PROTO,
50 	IP6_SRC0,
51 	IP6_SRC1,
52 	IP6_SRC2,
53 	IP6_SRC3,
54 	IP6_DST0,
55 	IP6_DST1,
56 	IP6_DST2,
57 	IP6_DST3,
58 	IP6_SRCP,
59 	IP6_DSTP,
60 	IP6_NUM
61 };
62 
63 #define IP6_ADDR_SIZE 16
64 
65 struct rte_acl_field_def ip6_defs[IP6_NUM] = {
66 	{
67 	.type = RTE_ACL_FIELD_TYPE_BITMASK,
68 	.size = sizeof(uint8_t),
69 	.field_index = IP6_PROTO,
70 	.input_index = IP6_PROTO,
71 	.offset = 0,
72 	},
73 	{
74 	.type = RTE_ACL_FIELD_TYPE_MASK,
75 	.size = 4,
76 	.field_index = IP6_SRC0,
77 	.input_index = IP6_SRC0,
78 	.offset = 2
79 	},
80 	{
81 	.type = RTE_ACL_FIELD_TYPE_MASK,
82 	.size = 4,
83 	.field_index = IP6_SRC1,
84 	.input_index = IP6_SRC1,
85 	.offset = 6
86 	},
87 	{
88 	.type = RTE_ACL_FIELD_TYPE_MASK,
89 	.size = 4,
90 	.field_index = IP6_SRC2,
91 	.input_index = IP6_SRC2,
92 	.offset = 10
93 	},
94 	{
95 	.type = RTE_ACL_FIELD_TYPE_MASK,
96 	.size = 4,
97 	.field_index = IP6_SRC3,
98 	.input_index = IP6_SRC3,
99 	.offset = 14
100 	},
101 	{
102 	.type = RTE_ACL_FIELD_TYPE_MASK,
103 	.size = 4,
104 	.field_index = IP6_DST0,
105 	.input_index = IP6_DST0,
106 	.offset = 18
107 	},
108 	{
109 	.type = RTE_ACL_FIELD_TYPE_MASK,
110 	.size = 4,
111 	.field_index = IP6_DST1,
112 	.input_index = IP6_DST1,
113 	.offset = 22
114 	},
115 	{
116 	.type = RTE_ACL_FIELD_TYPE_MASK,
117 	.size = 4,
118 	.field_index = IP6_DST2,
119 	.input_index = IP6_DST2,
120 	.offset = 26
121 	},
122 	{
123 	.type = RTE_ACL_FIELD_TYPE_MASK,
124 	.size = 4,
125 	.field_index = IP6_DST3,
126 	.input_index = IP6_DST3,
127 	.offset = 30
128 	},
129 	{
130 	.type = RTE_ACL_FIELD_TYPE_RANGE,
131 	.size = sizeof(uint16_t),
132 	.field_index = IP6_SRCP,
133 	.input_index = IP6_SRCP,
134 	.offset = 34
135 	},
136 	{
137 	.type = RTE_ACL_FIELD_TYPE_RANGE,
138 	.size = sizeof(uint16_t),
139 	.field_index = IP6_DSTP,
140 	.input_index = IP6_SRCP,
141 	.offset = 36
142 	}
143 };
144 
145 RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
146 
147 const struct acl6_rules acl6_rules_out[] = {
148 	{
149 	.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
150 	/* destination IPv6 */
151 	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
152 	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
153 	.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
154 	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
155 	/* source port */
156 	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
157 	/* destination port */
158 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
159 	},
160 	{
161 	.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
162 	/* destination IPv6 */
163 	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
164 	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
165 	.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
166 	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
167 	/* source port */
168 	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
169 	/* destination port */
170 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
171 	},
172 	{
173 	.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
174 	/* destination IPv6 */
175 	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
176 	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
177 	.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
178 	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
179 	/* source port */
180 	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
181 	/* destination port */
182 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
183 	},
184 	{
185 	.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
186 	/* destination IPv6 */
187 	.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
188 	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
189 	.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
190 	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
191 	/* source port */
192 	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
193 	/* destination port */
194 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
195 	}
196 };
197 
198 const struct acl6_rules acl6_rules_in[] = {
199 	{
200 	.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
201 	/* destination IPv6 */
202 	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
203 	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
204 	.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
205 	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
206 	/* source port */
207 	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
208 	/* destination port */
209 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
210 	},
211 	{
212 	.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
213 	/* destination IPv6 */
214 	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
215 	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
216 	.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
217 	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
218 	/* source port */
219 	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
220 	/* destination port */
221 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
222 	},
223 	{
224 	.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
225 	/* destination IPv6 */
226 	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
227 	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
228 	.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
229 	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
230 	/* source port */
231 	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
232 	/* destination port */
233 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
234 	},
235 	{
236 	.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
237 	/* destination IPv6 */
238 	.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
239 	.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
240 	.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
241 	.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
242 	/* source port */
243 	.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
244 	/* destination port */
245 	.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
246 	}
247 };
248 
249 static inline void
250 print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
251 {
252 	uint8_t a, b, c, d;
253 
254 	uint32_t_to_char(rule->field[IP6_SRC0].value.u32,
255 		&a, &b, &c, &d);
256 	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
257 	uint32_t_to_char(rule->field[IP6_SRC1].value.u32,
258 		&a, &b, &c, &d);
259 	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
260 	uint32_t_to_char(rule->field[IP6_SRC2].value.u32,
261 		&a, &b, &c, &d);
262 	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
263 	uint32_t_to_char(rule->field[IP6_SRC3].value.u32,
264 		&a, &b, &c, &d);
265 	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
266 			rule->field[IP6_SRC0].mask_range.u32
267 			+ rule->field[IP6_SRC1].mask_range.u32
268 			+ rule->field[IP6_SRC2].mask_range.u32
269 			+ rule->field[IP6_SRC3].mask_range.u32);
270 
271 	uint32_t_to_char(rule->field[IP6_DST0].value.u32,
272 		&a, &b, &c, &d);
273 	printf("%.2x%.2x:%.2x%.2x", a, b, c, d);
274 	uint32_t_to_char(rule->field[IP6_DST1].value.u32,
275 		&a, &b, &c, &d);
276 	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
277 	uint32_t_to_char(rule->field[IP6_DST2].value.u32,
278 		&a, &b, &c, &d);
279 	printf(":%.2x%.2x:%.2x%.2x", a, b, c, d);
280 	uint32_t_to_char(rule->field[IP6_DST3].value.u32,
281 		&a, &b, &c, &d);
282 	printf(":%.2x%.2x:%.2x%.2x/%u ", a, b, c, d,
283 			rule->field[IP6_DST0].mask_range.u32
284 			+ rule->field[IP6_DST1].mask_range.u32
285 			+ rule->field[IP6_DST2].mask_range.u32
286 			+ rule->field[IP6_DST3].mask_range.u32);
287 
288 	printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
289 		rule->field[IP6_SRCP].value.u16,
290 		rule->field[IP6_SRCP].mask_range.u16,
291 		rule->field[IP6_DSTP].value.u16,
292 		rule->field[IP6_DSTP].mask_range.u16,
293 		rule->field[IP6_PROTO].value.u8,
294 		rule->field[IP6_PROTO].mask_range.u8);
295 	if (extra)
296 		printf("0x%x-0x%x-0x%x ",
297 			rule->data.category_mask,
298 			rule->data.priority,
299 			rule->data.userdata);
300 }
301 
302 static inline void
303 dump_ip6_rules(const struct acl6_rules *rule, int32_t num, int32_t extra)
304 {
305 	int32_t i;
306 
307 	for (i = 0; i < num; i++, rule++) {
308 		printf("\t%d:", i + 1);
309 		print_one_ip6_rule(rule, extra);
310 		printf("\n");
311 	}
312 }
313 
314 static struct rte_acl_ctx *
315 acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
316 		uint32_t rules_nb)
317 {
318 	char s[PATH_MAX];
319 	struct rte_acl_param acl_param;
320 	struct rte_acl_config acl_build_param;
321 	struct rte_acl_ctx *ctx;
322 
323 	printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
324 
325 	memset(&acl_param, 0, sizeof(acl_param));
326 
327 	/* Create ACL contexts */
328 	snprintf(s, sizeof(s), "%s_%d", name, socketid);
329 
330 	printf("IPv4 %s entries [%u]:\n", s, rules_nb);
331 	dump_ip6_rules(rules, rules_nb, 1);
332 
333 	acl_param.name = s;
334 	acl_param.socket_id = socketid;
335 	acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip6_defs));
336 	acl_param.max_rule_num = MAX_ACL_RULE_NUM;
337 
338 	ctx = rte_acl_create(&acl_param);
339 	if (ctx == NULL)
340 		rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
341 
342 	if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
343 				rules_nb) < 0)
344 		rte_exit(EXIT_FAILURE, "add rules failed\n");
345 
346 	/* Perform builds */
347 	memset(&acl_build_param, 0, sizeof(acl_build_param));
348 
349 	acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
350 	acl_build_param.num_fields = RTE_DIM(ip6_defs);
351 	memcpy(&acl_build_param.defs, ip6_defs, sizeof(ip6_defs));
352 
353 	if (rte_acl_build(ctx, &acl_build_param) != 0)
354 		rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
355 
356 	rte_acl_dump(ctx);
357 
358 	return ctx;
359 }
360 
361 void
362 sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
363 {
364 	const char *name;
365 	const struct acl6_rules *rules_out, *rules_in;
366 	uint32_t nb_out_rules, nb_in_rules;
367 
368 	if (ctx == NULL)
369 		rte_exit(EXIT_FAILURE, "NULL context.\n");
370 
371 	if (ctx->sp_ip6_in != NULL)
372 		rte_exit(EXIT_FAILURE, "Inbound IPv6 SP DB for socket %u "
373 				"already initialized\n", socket_id);
374 
375 	if (ctx->sp_ip6_out != NULL)
376 		rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
377 				"already initialized\n", socket_id);
378 
379 	if (ep == 0) {
380 		rules_out = acl6_rules_out;
381 		nb_out_rules = RTE_DIM(acl6_rules_out);
382 		rules_in = acl6_rules_in;
383 		nb_in_rules = RTE_DIM(acl6_rules_in);
384 	} else if (ep == 1) {
385 		rules_out = acl6_rules_in;
386 		nb_out_rules = RTE_DIM(acl6_rules_in);
387 		rules_in = acl6_rules_out;
388 		nb_in_rules = RTE_DIM(acl6_rules_out);
389 	} else
390 		rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
391 				"Only 0 or 1 supported.\n", ep);
392 
393 	name = "sp_ip6_in";
394 	ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name, socket_id,
395 			rules_in, nb_in_rules);
396 
397 	name = "sp_ip6_out";
398 	ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name, socket_id,
399 			rules_out, nb_out_rules);
400 }
401