examples/ipsec-secgw: fix build on FreeBSD
[dpdk.git] / examples / ipsec-secgw / sa.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 Associations
36  */
37 #include <sys/types.h>
38 #include <netinet/in.h>
39 #include <netinet/ip.h>
40
41 #include <rte_memzone.h>
42 #include <rte_crypto.h>
43 #include <rte_cryptodev.h>
44 #include <rte_byteorder.h>
45 #include <rte_errno.h>
46
47 #include "ipsec.h"
48 #include "esp.h"
49
50 /* SAs EP0 Outbound */
51 const struct ipsec_sa sa_ep0_out[] = {
52         { 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
53                 NULL, NULL,
54                 esp4_tunnel_outbound_pre_crypto,
55                 esp4_tunnel_outbound_post_crypto,
56                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
57                 12, 16, 16,
58                 0, 0 },
59         { 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
60                 NULL, NULL,
61                 esp4_tunnel_outbound_pre_crypto,
62                 esp4_tunnel_outbound_post_crypto,
63                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
64                 12, 16, 16,
65                 0, 0 },
66         { 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
67                 NULL, NULL,
68                 esp4_tunnel_outbound_pre_crypto,
69                 esp4_tunnel_outbound_post_crypto,
70                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
71                 12, 16, 16,
72                 0, 0 },
73         { 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
74                 NULL, NULL,
75                 esp4_tunnel_outbound_pre_crypto,
76                 esp4_tunnel_outbound_post_crypto,
77                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
78                 12, 16, 16,
79                 0, 0 },
80         { 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
81                 NULL, NULL,
82                 esp4_tunnel_outbound_pre_crypto,
83                 esp4_tunnel_outbound_post_crypto,
84                 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
85                 0, 0, 4,
86                 0, 0 },
87 };
88
89 /* SAs EP0 Inbound */
90 const struct ipsec_sa sa_ep0_in[] = {
91         { 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
92                 NULL, NULL,
93                 esp4_tunnel_inbound_pre_crypto,
94                 esp4_tunnel_inbound_post_crypto,
95                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
96                 12, 16, 16,
97                 0, 0 },
98         { 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
99                 NULL, NULL,
100                 esp4_tunnel_inbound_pre_crypto,
101                 esp4_tunnel_inbound_post_crypto,
102                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
103                 12, 16, 16,
104                 0, 0 },
105         { 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
106                 NULL, NULL,
107                 esp4_tunnel_inbound_pre_crypto,
108                 esp4_tunnel_inbound_post_crypto,
109                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
110                 12, 16, 16,
111                 0, 0 },
112         { 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
113                 NULL, NULL,
114                 esp4_tunnel_inbound_pre_crypto,
115                 esp4_tunnel_inbound_post_crypto,
116                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
117                 12, 16, 16,
118                 0, 0 },
119         { 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
120                 NULL, NULL,
121                 esp4_tunnel_inbound_pre_crypto,
122                 esp4_tunnel_inbound_post_crypto,
123                 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
124                 0, 0, 4,
125                 0, 0 },
126 };
127
128 /* SAs EP1 Outbound */
129 const struct ipsec_sa sa_ep1_out[] = {
130         { 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
131                 NULL, NULL,
132                 esp4_tunnel_outbound_pre_crypto,
133                 esp4_tunnel_outbound_post_crypto,
134                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
135                 12, 16, 16,
136                 0, 0 },
137         { 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
138                 NULL, NULL,
139                 esp4_tunnel_outbound_pre_crypto,
140                 esp4_tunnel_outbound_post_crypto,
141                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
142                 12, 16, 16,
143                 0, 0 },
144         { 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
145                 NULL, NULL,
146                 esp4_tunnel_outbound_pre_crypto,
147                 esp4_tunnel_outbound_post_crypto,
148                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
149                 12, 16, 16,
150                 0, 0 },
151         { 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
152                 NULL, NULL,
153                 esp4_tunnel_outbound_pre_crypto,
154                 esp4_tunnel_outbound_post_crypto,
155                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
156                 12, 16, 16,
157                 0, 0 },
158         { 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
159                 NULL, NULL,
160                 esp4_tunnel_outbound_pre_crypto,
161                 esp4_tunnel_outbound_post_crypto,
162                 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
163                 0, 0, 4,
164                 0, 0 },
165 };
166
167 /* SAs EP1 Inbound */
168 const struct ipsec_sa sa_ep1_in[] = {
169         { 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
170                 NULL, NULL,
171                 esp4_tunnel_inbound_pre_crypto,
172                 esp4_tunnel_inbound_post_crypto,
173                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
174                 12, 16, 16,
175                 0, 0 },
176         { 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
177                 NULL, NULL,
178                 esp4_tunnel_inbound_pre_crypto,
179                 esp4_tunnel_inbound_post_crypto,
180                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
181                 12, 16, 16,
182                 0, 0 },
183         { 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
184                 NULL, NULL,
185                 esp4_tunnel_inbound_pre_crypto,
186                 esp4_tunnel_inbound_post_crypto,
187                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
188                 12, 16, 16,
189                 0, 0 },
190         { 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
191                 NULL, NULL,
192                 esp4_tunnel_inbound_pre_crypto,
193                 esp4_tunnel_inbound_post_crypto,
194                 RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
195                 12, 16, 16,
196                 0, 0 },
197         { 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
198                 NULL, NULL,
199                 esp4_tunnel_inbound_pre_crypto,
200                 esp4_tunnel_inbound_post_crypto,
201                 RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
202                 0, 0, 4,
203                 0, 0 },
204 };
205
206 static uint8_t cipher_key[256] = "sixteenbytes key";
207
208 /* AES CBC xform */
209 const struct rte_crypto_sym_xform aescbc_enc_xf = {
210         NULL,
211         RTE_CRYPTO_SYM_XFORM_CIPHER,
212         .cipher = { RTE_CRYPTO_CIPHER_OP_ENCRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
213                 .key = { cipher_key, 16 } }
214 };
215
216 const struct rte_crypto_sym_xform aescbc_dec_xf = {
217         NULL,
218         RTE_CRYPTO_SYM_XFORM_CIPHER,
219         .cipher = { RTE_CRYPTO_CIPHER_OP_DECRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
220                 .key = { cipher_key, 16 } }
221 };
222
223 static uint8_t auth_key[256] = "twentybytes hash key";
224
225 /* SHA1 HMAC xform */
226 const struct rte_crypto_sym_xform sha1hmac_gen_xf = {
227         NULL,
228         RTE_CRYPTO_SYM_XFORM_AUTH,
229         .auth = { RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_SHA1_HMAC,
230                 .key = { auth_key, 20 }, 12, 0 }
231 };
232
233 const struct rte_crypto_sym_xform sha1hmac_verify_xf = {
234         NULL,
235         RTE_CRYPTO_SYM_XFORM_AUTH,
236         .auth = { RTE_CRYPTO_AUTH_OP_VERIFY, RTE_CRYPTO_AUTH_SHA1_HMAC,
237                 .key = { auth_key, 20 }, 12, 0 }
238 };
239
240 /* AES CBC xform */
241 const struct rte_crypto_sym_xform null_cipher_xf = {
242         NULL,
243         RTE_CRYPTO_SYM_XFORM_CIPHER,
244         .cipher = { .algo = RTE_CRYPTO_CIPHER_NULL }
245 };
246
247 const struct rte_crypto_sym_xform null_auth_xf = {
248         NULL,
249         RTE_CRYPTO_SYM_XFORM_AUTH,
250         .auth = { .algo = RTE_CRYPTO_AUTH_NULL }
251 };
252
253 struct sa_ctx {
254         struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
255         struct {
256                 struct rte_crypto_sym_xform a;
257                 struct rte_crypto_sym_xform b;
258         } xf[IPSEC_SA_MAX_ENTRIES];
259 };
260
261 static struct sa_ctx *
262 sa_ipv4_create(const char *name, int socket_id)
263 {
264         char s[PATH_MAX];
265         struct sa_ctx *sa_ctx;
266         unsigned mz_size;
267         const struct rte_memzone *mz;
268
269         snprintf(s, sizeof(s), "%s_%u", name, socket_id);
270
271         /* Create SA array table */
272         printf("Creating SA context with %u maximum entries\n",
273                         IPSEC_SA_MAX_ENTRIES);
274
275         mz_size = sizeof(struct sa_ctx);
276         mz = rte_memzone_reserve(s, mz_size, socket_id,
277                         RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
278         if (mz == NULL) {
279                 printf("Failed to allocate SA DB memory\n");
280                 rte_errno = -ENOMEM;
281                 return NULL;
282         }
283
284         sa_ctx = (struct sa_ctx *)mz->addr;
285
286         return sa_ctx;
287 }
288
289 static int
290 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
291                 unsigned nb_entries, unsigned inbound)
292 {
293         struct ipsec_sa *sa;
294         unsigned i, idx;
295
296         for (i = 0; i < nb_entries; i++) {
297                 idx = SPI2IDX(entries[i].spi);
298                 sa = &sa_ctx->sa[idx];
299                 if (sa->spi != 0) {
300                         printf("Index %u already in use by SPI %u\n",
301                                         idx, sa->spi);
302                         return -EINVAL;
303                 }
304                 *sa = entries[i];
305                 sa->src = rte_cpu_to_be_32(sa->src);
306                 sa->dst = rte_cpu_to_be_32(sa->dst);
307                 if (inbound) {
308                         if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
309                                 sa_ctx->xf[idx].a = null_auth_xf;
310                                 sa_ctx->xf[idx].b = null_cipher_xf;
311                         } else {
312                                 sa_ctx->xf[idx].a = sha1hmac_verify_xf;
313                                 sa_ctx->xf[idx].b = aescbc_dec_xf;
314                         }
315                 } else { /* outbound */
316                         if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
317                                 sa_ctx->xf[idx].a = null_cipher_xf;
318                                 sa_ctx->xf[idx].b = null_auth_xf;
319                         } else {
320                                 sa_ctx->xf[idx].a = aescbc_enc_xf;
321                                 sa_ctx->xf[idx].b = sha1hmac_gen_xf;
322                         }
323                 }
324                 sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
325                 sa_ctx->xf[idx].b.next = NULL;
326                 sa->xforms = &sa_ctx->xf[idx].a;
327         }
328
329         return 0;
330 }
331
332 static inline int
333 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
334                 unsigned nb_entries)
335 {
336         return sa_add_rules(sa_ctx, entries, nb_entries, 0);
337 }
338
339 static inline int
340 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
341                 unsigned nb_entries)
342 {
343         return sa_add_rules(sa_ctx, entries, nb_entries, 1);
344 }
345
346 void
347 sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
348 {
349         const struct ipsec_sa *sa_out_entries, *sa_in_entries;
350         unsigned nb_out_entries, nb_in_entries;
351         const char *name;
352
353         if (ctx == NULL)
354                 rte_exit(EXIT_FAILURE, "NULL context.\n");
355
356         if (ctx->sa_ipv4_in != NULL)
357                 rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
358                                 "initialized\n", socket_id);
359
360         if (ctx->sa_ipv4_out != NULL)
361                 rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
362                                 "initialized\n", socket_id);
363
364         if (ep == 0) {
365                 sa_out_entries = sa_ep0_out;
366                 nb_out_entries = RTE_DIM(sa_ep0_out);
367                 sa_in_entries = sa_ep0_in;
368                 nb_in_entries = RTE_DIM(sa_ep0_in);
369         } else if (ep == 1) {
370                 sa_out_entries = sa_ep1_out;
371                 nb_out_entries = RTE_DIM(sa_ep1_out);
372                 sa_in_entries = sa_ep1_in;
373                 nb_in_entries = RTE_DIM(sa_ep1_in);
374         } else
375                 rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
376                                 "Only 0 or 1 supported.\n", ep);
377
378         name = "sa_ipv4_in";
379         ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id);
380         if (ctx->sa_ipv4_in == NULL)
381                 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
382                                 "in socket %d\n", rte_errno, name, socket_id);
383
384         name = "sa_ipv4_out";
385         ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id);
386         if (ctx->sa_ipv4_out == NULL)
387                 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
388                                 "in socket %d\n", rte_errno, name, socket_id);
389
390         sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries);
391
392         sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries);
393 }
394
395 int
396 inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
397 {
398         struct ipsec_mbuf_metadata *priv;
399
400         priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
401
402         return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
403 }
404
405 void
406 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
407                 struct ipsec_sa *sa[], uint16_t nb_pkts)
408 {
409         unsigned i;
410         uint32_t *src, spi;
411
412         for (i = 0; i < nb_pkts; i++) {
413                 spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *,
414                                 sizeof(struct ip))->spi;
415
416                 if (spi == INVALID_SPI)
417                         continue;
418
419                 sa[i] = &sa_ctx->sa[SPI2IDX(spi)];
420                 if (spi != sa[i]->spi) {
421                         sa[i] = NULL;
422                         continue;
423                 }
424
425                 src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *,
426                                 offsetof(struct ip, ip_src));
427                 if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1)))
428                         sa[i] = NULL;
429         }
430 }
431
432 void
433 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
434                 struct ipsec_sa *sa[], uint16_t nb_pkts)
435 {
436         unsigned i;
437
438         for (i = 0; i < nb_pkts; i++)
439                 sa[i] = &sa_ctx->sa[sa_idx[i]];
440 }