Imported Upstream version 16.07-rc1
[deb_dpdk.git] / examples / ipsec-secgw / sp4.c
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/ip.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 /*
49  * Rule and trace formats definitions.
50  */
51 enum {
52         PROTO_FIELD_IPV4,
53         SRC_FIELD_IPV4,
54         DST_FIELD_IPV4,
55         SRCP_FIELD_IPV4,
56         DSTP_FIELD_IPV4,
57         NUM_FIELDS_IPV4
58 };
59
60 /*
61  * That effectively defines order of IPV4 classifications:
62  *  - PROTO
63  *  - SRC IP ADDRESS
64  *  - DST IP ADDRESS
65  *  - PORTS (SRC and DST)
66  */
67 enum {
68         RTE_ACL_IPV4_PROTO,
69         RTE_ACL_IPV4_SRC,
70         RTE_ACL_IPV4_DST,
71         RTE_ACL_IPV4_PORTS,
72         RTE_ACL_IPV4_NUM
73 };
74
75 struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {
76         {
77         .type = RTE_ACL_FIELD_TYPE_BITMASK,
78         .size = sizeof(uint8_t),
79         .field_index = PROTO_FIELD_IPV4,
80         .input_index = RTE_ACL_IPV4_PROTO,
81         .offset = 0,
82         },
83         {
84         .type = RTE_ACL_FIELD_TYPE_MASK,
85         .size = sizeof(uint32_t),
86         .field_index = SRC_FIELD_IPV4,
87         .input_index = RTE_ACL_IPV4_SRC,
88         .offset = offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p)
89         },
90         {
91         .type = RTE_ACL_FIELD_TYPE_MASK,
92         .size = sizeof(uint32_t),
93         .field_index = DST_FIELD_IPV4,
94         .input_index = RTE_ACL_IPV4_DST,
95         .offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p)
96         },
97         {
98         .type = RTE_ACL_FIELD_TYPE_RANGE,
99         .size = sizeof(uint16_t),
100         .field_index = SRCP_FIELD_IPV4,
101         .input_index = RTE_ACL_IPV4_PORTS,
102         .offset = sizeof(struct ip) - offsetof(struct ip, ip_p)
103         },
104         {
105         .type = RTE_ACL_FIELD_TYPE_RANGE,
106         .size = sizeof(uint16_t),
107         .field_index = DSTP_FIELD_IPV4,
108         .input_index = RTE_ACL_IPV4_PORTS,
109         .offset = sizeof(struct ip) - offsetof(struct ip, ip_p) +
110                 sizeof(uint16_t)
111         },
112 };
113
114 RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));
115
116 const struct acl4_rules acl4_rules_out[] = {
117         {
118         .data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
119         /* destination IPv4 */
120         .field[2] = {.value.u32 = IPv4(192, 168, 105, 0),
121                                 .mask_range.u32 = 24,},
122         /* source port */
123         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
124         /* destination port */
125         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
126         },
127         {
128         .data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
129         /* destination IPv4 */
130         .field[2] = {.value.u32 = IPv4(192, 168, 106, 0),
131                                 .mask_range.u32 = 24,},
132         /* source port */
133         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
134         /* destination port */
135         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
136         },
137         {
138         .data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},
139         /* destination IPv4 */
140         .field[2] = {.value.u32 = IPv4(192, 168, 175, 0),
141                                 .mask_range.u32 = 24,},
142         /* source port */
143         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
144         /* destination port */
145         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
146         },
147         {
148         .data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},
149         /* destination IPv4 */
150         .field[2] = {.value.u32 = IPv4(192, 168, 176, 0),
151                                 .mask_range.u32 = 24,},
152         /* source port */
153         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
154         /* destination port */
155         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
156         },
157         {
158         .data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
159         /* destination IPv4 */
160         .field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
161                                 .mask_range.u32 = 24,},
162         /* source port */
163         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
164         /* destination port */
165         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
166         },
167         {
168         .data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
169         /* destination IPv4 */
170         .field[2] = {.value.u32 = IPv4(192, 168, 201, 0),
171                                 .mask_range.u32 = 24,},
172         /* source port */
173         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
174         /* destination port */
175         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
176         },
177         {
178         .data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
179         /* destination IPv4 */
180         .field[2] = {.value.u32 = IPv4(192, 168, 55, 0),
181                                 .mask_range.u32 = 24,},
182         /* source port */
183         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
184         /* destination port */
185         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
186         },
187         {
188         .data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
189         /* destination IPv4 */
190         .field[2] = {.value.u32 = IPv4(192, 168, 56, 0),
191                                 .mask_range.u32 = 24,},
192         /* source port */
193         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
194         /* destination port */
195         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
196         },
197         {
198         .data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
199         /* destination IPv4 */
200         .field[2] = {.value.u32 = IPv4(192, 168, 240, 0),
201                                 .mask_range.u32 = 24,},
202         /* source port */
203         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
204         /* destination port */
205         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
206         },
207         {
208         .data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
209         /* destination IPv4 */
210         .field[2] = {.value.u32 = IPv4(192, 168, 241, 0),
211                                 .mask_range.u32 = 24,},
212         /* source port */
213         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
214         /* destination port */
215         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
216         }
217 };
218
219 const struct acl4_rules acl4_rules_in[] = {
220         {
221         .data = {.userdata = PROTECT(105), .category_mask = 1, .priority = 1},
222         /* destination IPv4 */
223         .field[2] = {.value.u32 = IPv4(192, 168, 115, 0),
224                                 .mask_range.u32 = 24,},
225         /* source port */
226         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
227         /* destination port */
228         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
229         },
230         {
231         .data = {.userdata = PROTECT(106), .category_mask = 1, .priority = 1},
232         /* destination IPv4 */
233         .field[2] = {.value.u32 = IPv4(192, 168, 116, 0),
234                                 .mask_range.u32 = 24,},
235         /* source port */
236         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
237         /* destination port */
238         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
239         },
240         {
241         .data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},
242         /* destination IPv4 */
243         .field[2] = {.value.u32 = IPv4(192, 168, 185, 0),
244                                 .mask_range.u32 = 24,},
245         /* source port */
246         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
247         /* destination port */
248         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
249         },
250         {
251         .data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},
252         /* destination IPv4 */
253         .field[2] = {.value.u32 = IPv4(192, 168, 186, 0),
254                                 .mask_range.u32 = 24,},
255         /* source port */
256         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
257         /* destination port */
258         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
259         },
260         {
261         .data = {.userdata = PROTECT(115), .category_mask = 1, .priority = 1},
262         /* destination IPv4 */
263         .field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
264                                 .mask_range.u32 = 24,},
265         /* source port */
266         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
267         /* destination port */
268         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
269         },
270         {
271         .data = {.userdata = PROTECT(116), .category_mask = 1, .priority = 1},
272         /* destination IPv4 */
273         .field[2] = {.value.u32 = IPv4(192, 168, 211, 0),
274                                 .mask_range.u32 = 24,},
275         /* source port */
276         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
277         /* destination port */
278         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
279         },
280         {
281         .data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
282         /* destination IPv4 */
283         .field[2] = {.value.u32 = IPv4(192, 168, 65, 0),
284                                 .mask_range.u32 = 24,},
285         /* source port */
286         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
287         /* destination port */
288         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
289         },
290         {
291         .data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
292         /* destination IPv4 */
293         .field[2] = {.value.u32 = IPv4(192, 168, 66, 0),
294                                 .mask_range.u32 = 24,},
295         /* source port */
296         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
297         /* destination port */
298         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
299         },
300         {
301         .data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
302         /* destination IPv4 */
303         .field[2] = {.value.u32 = IPv4(192, 168, 245, 0),
304                                 .mask_range.u32 = 24,},
305         /* source port */
306         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
307         /* destination port */
308         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
309         },
310         {
311         .data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
312         /* destination IPv4 */
313         .field[2] = {.value.u32 = IPv4(192, 168, 246, 0),
314                                 .mask_range.u32 = 24,},
315         /* source port */
316         .field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
317         /* destination port */
318         .field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
319         }
320 };
321
322 static void
323 print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra)
324 {
325         uint8_t a, b, c, d;
326
327         uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32,
328                         &a, &b, &c, &d);
329         printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
330                         rule->field[SRC_FIELD_IPV4].mask_range.u32);
331         uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32,
332                         &a, &b, &c, &d);
333         printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
334                         rule->field[DST_FIELD_IPV4].mask_range.u32);
335         printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
336                 rule->field[SRCP_FIELD_IPV4].value.u16,
337                 rule->field[SRCP_FIELD_IPV4].mask_range.u16,
338                 rule->field[DSTP_FIELD_IPV4].value.u16,
339                 rule->field[DSTP_FIELD_IPV4].mask_range.u16,
340                 rule->field[PROTO_FIELD_IPV4].value.u8,
341                 rule->field[PROTO_FIELD_IPV4].mask_range.u8);
342         if (extra)
343                 printf("0x%x-0x%x-0x%x ",
344                         rule->data.category_mask,
345                         rule->data.priority,
346                         rule->data.userdata);
347 }
348
349 static inline void
350 dump_ip4_rules(const struct acl4_rules *rule, int32_t num, int32_t extra)
351 {
352         int32_t i;
353
354         for (i = 0; i < num; i++, rule++) {
355                 printf("\t%d:", i + 1);
356                 print_one_ip4_rule(rule, extra);
357                 printf("\n");
358         }
359 }
360
361 static struct rte_acl_ctx *
362 acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
363                 uint32_t rules_nb)
364 {
365         char s[PATH_MAX];
366         struct rte_acl_param acl_param;
367         struct rte_acl_config acl_build_param;
368         struct rte_acl_ctx *ctx;
369
370         printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
371
372         memset(&acl_param, 0, sizeof(acl_param));
373
374         /* Create ACL contexts */
375         snprintf(s, sizeof(s), "%s_%d", name, socketid);
376
377         printf("IPv4 %s entries [%u]:\n", s, rules_nb);
378         dump_ip4_rules(rules, rules_nb, 1);
379
380         acl_param.name = s;
381         acl_param.socket_id = socketid;
382         acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ip4_defs));
383         acl_param.max_rule_num = MAX_ACL_RULE_NUM;
384
385         ctx = rte_acl_create(&acl_param);
386         if (ctx == NULL)
387                 rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
388
389         if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
390                                 rules_nb) < 0)
391                 rte_exit(EXIT_FAILURE, "add rules failed\n");
392
393         /* Perform builds */
394         memset(&acl_build_param, 0, sizeof(acl_build_param));
395
396         acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
397         acl_build_param.num_fields = RTE_DIM(ip4_defs);
398         memcpy(&acl_build_param.defs, ip4_defs, sizeof(ip4_defs));
399
400         if (rte_acl_build(ctx, &acl_build_param) != 0)
401                 rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
402
403         rte_acl_dump(ctx);
404
405         return ctx;
406 }
407
408 void
409 sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
410 {
411         const char *name;
412         const struct acl4_rules *rules_out, *rules_in;
413         uint32_t nb_out_rules, nb_in_rules;
414
415         if (ctx == NULL)
416                 rte_exit(EXIT_FAILURE, "NULL context.\n");
417
418         if (ctx->sp_ip4_in != NULL)
419                 rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already "
420                                 "initialized\n", socket_id);
421
422         if (ctx->sp_ip4_out != NULL)
423                 rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
424                                 "initialized\n", socket_id);
425
426         if (ep == 0) {
427                 rules_out = acl4_rules_out;
428                 nb_out_rules = RTE_DIM(acl4_rules_out);
429                 rules_in = acl4_rules_in;
430                 nb_in_rules = RTE_DIM(acl4_rules_in);
431         } else if (ep == 1) {
432                 rules_out = acl4_rules_in;
433                 nb_out_rules = RTE_DIM(acl4_rules_in);
434                 rules_in = acl4_rules_out;
435                 nb_in_rules = RTE_DIM(acl4_rules_out);
436         } else
437                 rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
438                                 "Only 0 or 1 supported.\n", ep);
439
440         name = "sp_ip4_in";
441         ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, socket_id,
442                         rules_in, nb_in_rules);
443
444         name = "sp_ip4_out";
445         ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, socket_id,
446                         rules_out, nb_out_rules);
447 }