Imported Upstream version 16.07-rc1
[deb_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 #include <netinet/ip6.h>
41
42 #include <rte_memzone.h>
43 #include <rte_crypto.h>
44 #include <rte_cryptodev.h>
45 #include <rte_byteorder.h>
46 #include <rte_errno.h>
47 #include <rte_ip.h>
48
49 #include "ipsec.h"
50 #include "esp.h"
51
52 /* SAs Outbound */
53 const struct ipsec_sa sa_out[] = {
54         {
55         .spi = 5,
56         .src.ip4 = IPv4(172, 16, 1, 5),
57         .dst.ip4 = IPv4(172, 16, 2, 5),
58         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
59         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
60         .digest_len = 12,
61         .iv_len = 16,
62         .block_size = 16,
63         .flags = IP4_TUNNEL
64         },
65         {
66         .spi = 6,
67         .src.ip4 = IPv4(172, 16, 1, 6),
68         .dst.ip4 = IPv4(172, 16, 2, 6),
69         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
70         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
71         .digest_len = 12,
72         .iv_len = 16,
73         .block_size = 16,
74         .flags = IP4_TUNNEL
75         },
76         {
77         .spi = 10,
78         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
79         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
80         .digest_len = 12,
81         .iv_len = 16,
82         .block_size = 16,
83         .flags = TRANSPORT
84         },
85         {
86         .spi = 11,
87         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
88         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
89         .digest_len = 12,
90         .iv_len = 16,
91         .block_size = 16,
92         .flags = TRANSPORT
93         },
94         {
95         .spi = 15,
96         .src.ip4 = IPv4(172, 16, 1, 5),
97         .dst.ip4 = IPv4(172, 16, 2, 5),
98         .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
99         .auth_algo = RTE_CRYPTO_AUTH_NULL,
100         .digest_len = 0,
101         .iv_len = 0,
102         .block_size = 4,
103         .flags = IP4_TUNNEL
104         },
105         {
106         .spi = 16,
107         .src.ip4 = IPv4(172, 16, 1, 6),
108         .dst.ip4 = IPv4(172, 16, 2, 6),
109         .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
110         .auth_algo = RTE_CRYPTO_AUTH_NULL,
111         .digest_len = 0,
112         .iv_len = 0,
113         .block_size = 4,
114         .flags = IP4_TUNNEL
115         },
116         {
117         .spi = 25,
118         .src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
119                 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
120         .dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
121                 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
122         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
123         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
124         .digest_len = 12,
125         .iv_len = 16,
126         .block_size = 16,
127         .flags = IP6_TUNNEL
128         },
129         {
130         .spi = 26,
131         .src.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
132                 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
133         .dst.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
134                 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
135         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
136         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
137         .digest_len = 12,
138         .iv_len = 16,
139         .block_size = 16,
140         .flags = IP6_TUNNEL
141         },
142 };
143
144 /* SAs Inbound */
145 const struct ipsec_sa sa_in[] = {
146         {
147         .spi = 105,
148         .src.ip4 = IPv4(172, 16, 2, 5),
149         .dst.ip4 = IPv4(172, 16, 1, 5),
150         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
151         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
152         .digest_len = 12,
153         .iv_len = 16,
154         .block_size = 16,
155         .flags = IP4_TUNNEL
156         },
157         {
158         .spi = 106,
159         .src.ip4 = IPv4(172, 16, 2, 6),
160         .dst.ip4 = IPv4(172, 16, 1, 6),
161         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
162         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
163         .digest_len = 12,
164         .iv_len = 16,
165         .block_size = 16,
166         .flags = IP4_TUNNEL
167         },
168         {
169         .spi = 110,
170         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
171         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
172         .digest_len = 12,
173         .iv_len = 16,
174         .block_size = 16,
175         .flags = TRANSPORT
176         },
177         {
178         .spi = 111,
179         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
180         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
181         .digest_len = 12,
182         .iv_len = 16,
183         .block_size = 16,
184         .flags = TRANSPORT
185         },
186         {
187         .spi = 115,
188         .src.ip4 = IPv4(172, 16, 2, 5),
189         .dst.ip4 = IPv4(172, 16, 1, 5),
190         .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
191         .auth_algo = RTE_CRYPTO_AUTH_NULL,
192         .digest_len = 0,
193         .iv_len = 0,
194         .block_size = 4,
195         .flags = IP4_TUNNEL
196         },
197         {
198         .spi = 116,
199         .src.ip4 = IPv4(172, 16, 2, 6),
200         .dst.ip4 = IPv4(172, 16, 1, 6),
201         .cipher_algo = RTE_CRYPTO_CIPHER_NULL,
202         .auth_algo = RTE_CRYPTO_AUTH_NULL,
203         .digest_len = 0,
204         .iv_len = 0,
205         .block_size = 4,
206         .flags = IP4_TUNNEL
207         },
208         {
209         .spi = 125,
210         .src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
211                 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
212         .dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
213                 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
214         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
215         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
216         .digest_len = 12,
217         .iv_len = 16,
218         .block_size = 16,
219         .flags = IP6_TUNNEL
220         },
221         {
222         .spi = 126,
223         .src.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
224                 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
225         .dst.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
226                 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
227         .cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
228         .auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
229         .digest_len = 12,
230         .iv_len = 16,
231         .block_size = 16,
232         .flags = IP6_TUNNEL
233         },
234 };
235
236 static uint8_t cipher_key[256] = "sixteenbytes key";
237
238 /* AES CBC xform */
239 const struct rte_crypto_sym_xform aescbc_enc_xf = {
240         NULL,
241         RTE_CRYPTO_SYM_XFORM_CIPHER,
242         {.cipher = { RTE_CRYPTO_CIPHER_OP_ENCRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
243                 .key = { cipher_key, 16 } }
244         }
245 };
246
247 const struct rte_crypto_sym_xform aescbc_dec_xf = {
248         NULL,
249         RTE_CRYPTO_SYM_XFORM_CIPHER,
250         {.cipher = { RTE_CRYPTO_CIPHER_OP_DECRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
251                 .key = { cipher_key, 16 } }
252         }
253 };
254
255 static uint8_t auth_key[256] = "twentybytes hash key";
256
257 /* SHA1 HMAC xform */
258 const struct rte_crypto_sym_xform sha1hmac_gen_xf = {
259         NULL,
260         RTE_CRYPTO_SYM_XFORM_AUTH,
261         {.auth = { RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_SHA1_HMAC,
262                 .key = { auth_key, 20 }, 12, 0 }
263         }
264 };
265
266 const struct rte_crypto_sym_xform sha1hmac_verify_xf = {
267         NULL,
268         RTE_CRYPTO_SYM_XFORM_AUTH,
269         {.auth = { RTE_CRYPTO_AUTH_OP_VERIFY, RTE_CRYPTO_AUTH_SHA1_HMAC,
270                 .key = { auth_key, 20 }, 12, 0 }
271         }
272 };
273
274 /* AES CBC xform */
275 const struct rte_crypto_sym_xform null_cipher_xf = {
276         NULL,
277         RTE_CRYPTO_SYM_XFORM_CIPHER,
278         {.cipher = { .algo = RTE_CRYPTO_CIPHER_NULL }
279         }
280 };
281
282 const struct rte_crypto_sym_xform null_auth_xf = {
283         NULL,
284         RTE_CRYPTO_SYM_XFORM_AUTH,
285         {.auth = { .algo = RTE_CRYPTO_AUTH_NULL }
286         }
287 };
288
289 struct sa_ctx {
290         struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
291         struct {
292                 struct rte_crypto_sym_xform a;
293                 struct rte_crypto_sym_xform b;
294         } xf[IPSEC_SA_MAX_ENTRIES];
295 };
296
297 static struct sa_ctx *
298 sa_create(const char *name, int32_t socket_id)
299 {
300         char s[PATH_MAX];
301         struct sa_ctx *sa_ctx;
302         uint32_t mz_size;
303         const struct rte_memzone *mz;
304
305         snprintf(s, sizeof(s), "%s_%u", name, socket_id);
306
307         /* Create SA array table */
308         printf("Creating SA context with %u maximum entries\n",
309                         IPSEC_SA_MAX_ENTRIES);
310
311         mz_size = sizeof(struct sa_ctx);
312         mz = rte_memzone_reserve(s, mz_size, socket_id,
313                         RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
314         if (mz == NULL) {
315                 printf("Failed to allocate SA DB memory\n");
316                 rte_errno = -ENOMEM;
317                 return NULL;
318         }
319
320         sa_ctx = (struct sa_ctx *)mz->addr;
321
322         return sa_ctx;
323 }
324
325 static int
326 sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
327                 uint32_t nb_entries, uint32_t inbound)
328 {
329         struct ipsec_sa *sa;
330         uint32_t i, idx;
331
332         for (i = 0; i < nb_entries; i++) {
333                 idx = SPI2IDX(entries[i].spi);
334                 sa = &sa_ctx->sa[idx];
335                 if (sa->spi != 0) {
336                         printf("Index %u already in use by SPI %u\n",
337                                         idx, sa->spi);
338                         return -EINVAL;
339                 }
340                 *sa = entries[i];
341                 sa->seq = 0;
342
343                 switch (sa->flags) {
344                 case IP4_TUNNEL:
345                         sa->src.ip4 = rte_cpu_to_be_32(sa->src.ip4);
346                         sa->dst.ip4 = rte_cpu_to_be_32(sa->dst.ip4);
347                 }
348
349                 if (inbound) {
350                         if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
351                                 sa_ctx->xf[idx].a = null_auth_xf;
352                                 sa_ctx->xf[idx].b = null_cipher_xf;
353                         } else {
354                                 sa_ctx->xf[idx].a = sha1hmac_verify_xf;
355                                 sa_ctx->xf[idx].b = aescbc_dec_xf;
356                         }
357                 } else { /* outbound */
358                         if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
359                                 sa_ctx->xf[idx].a = null_cipher_xf;
360                                 sa_ctx->xf[idx].b = null_auth_xf;
361                         } else {
362                                 sa_ctx->xf[idx].a = aescbc_enc_xf;
363                                 sa_ctx->xf[idx].b = sha1hmac_gen_xf;
364                         }
365                 }
366                 sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
367                 sa_ctx->xf[idx].b.next = NULL;
368                 sa->xforms = &sa_ctx->xf[idx].a;
369         }
370
371         return 0;
372 }
373
374 static inline int
375 sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
376                 uint32_t nb_entries)
377 {
378         return sa_add_rules(sa_ctx, entries, nb_entries, 0);
379 }
380
381 static inline int
382 sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
383                 uint32_t nb_entries)
384 {
385         return sa_add_rules(sa_ctx, entries, nb_entries, 1);
386 }
387
388 void
389 sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
390 {
391         const struct ipsec_sa *sa_out_entries, *sa_in_entries;
392         uint32_t nb_out_entries, nb_in_entries;
393         const char *name;
394
395         if (ctx == NULL)
396                 rte_exit(EXIT_FAILURE, "NULL context.\n");
397
398         if (ctx->sa_in != NULL)
399                 rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
400                                 "initialized\n", socket_id);
401
402         if (ctx->sa_out != NULL)
403                 rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
404                                 "initialized\n", socket_id);
405
406         if (ep == 0) {
407                 sa_out_entries = sa_out;
408                 nb_out_entries = RTE_DIM(sa_out);
409                 sa_in_entries = sa_in;
410                 nb_in_entries = RTE_DIM(sa_in);
411         } else if (ep == 1) {
412                 sa_out_entries = sa_in;
413                 nb_out_entries = RTE_DIM(sa_in);
414                 sa_in_entries = sa_out;
415                 nb_in_entries = RTE_DIM(sa_out);
416         } else
417                 rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
418                                 "Only 0 or 1 supported.\n", ep);
419
420         name = "sa_in";
421         ctx->sa_in = sa_create(name, socket_id);
422         if (ctx->sa_in == NULL)
423                 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
424                                 "in socket %d\n", rte_errno, name, socket_id);
425
426         name = "sa_out";
427         ctx->sa_out = sa_create(name, socket_id);
428         if (ctx->sa_out == NULL)
429                 rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
430                                 "in socket %d\n", rte_errno, name, socket_id);
431
432         sa_in_add_rules(ctx->sa_in, sa_in_entries, nb_in_entries);
433
434         sa_out_add_rules(ctx->sa_out, sa_out_entries, nb_out_entries);
435 }
436
437 int
438 inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
439 {
440         struct ipsec_mbuf_metadata *priv;
441
442         priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
443
444         return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
445 }
446
447 static inline void
448 single_inbound_lookup(struct ipsec_sa *sadb, struct rte_mbuf *pkt,
449                 struct ipsec_sa **sa_ret)
450 {
451         struct esp_hdr *esp;
452         struct ip *ip;
453         uint32_t *src4_addr;
454         uint8_t *src6_addr;
455         struct ipsec_sa *sa;
456
457         *sa_ret = NULL;
458
459         ip = rte_pktmbuf_mtod(pkt, struct ip *);
460         if (ip->ip_v == IPVERSION)
461                 esp = (struct esp_hdr *)(ip + 1);
462         else
463                 esp = (struct esp_hdr *)(((struct ip6_hdr *)ip) + 1);
464
465         if (esp->spi == INVALID_SPI)
466                 return;
467
468         sa = &sadb[SPI2IDX(rte_be_to_cpu_32(esp->spi))];
469         if (rte_be_to_cpu_32(esp->spi) != sa->spi)
470                 return;
471
472         switch (sa->flags) {
473         case IP4_TUNNEL:
474                 src4_addr = RTE_PTR_ADD(ip, offsetof(struct ip, ip_src));
475                 if ((ip->ip_v == IPVERSION) &&
476                                 (sa->src.ip4 == *src4_addr) &&
477                                 (sa->dst.ip4 == *(src4_addr + 1)))
478                         *sa_ret = sa;
479                 break;
480         case IP6_TUNNEL:
481                 src6_addr = RTE_PTR_ADD(ip, offsetof(struct ip6_hdr, ip6_src));
482                 if ((ip->ip_v == IP6_VERSION) &&
483                                 !memcmp(&sa->src.ip6, src6_addr, 16) &&
484                                 !memcmp(&sa->dst.ip6, src6_addr + 16, 16))
485                         *sa_ret = sa;
486                 break;
487         case TRANSPORT:
488                 *sa_ret = sa;
489         }
490 }
491
492 void
493 inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
494                 struct ipsec_sa *sa[], uint16_t nb_pkts)
495 {
496         uint32_t i;
497
498         for (i = 0; i < nb_pkts; i++)
499                 single_inbound_lookup(sa_ctx->sa, pkts[i], &sa[i]);
500 }
501
502 void
503 outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
504                 struct ipsec_sa *sa[], uint16_t nb_pkts)
505 {
506         uint32_t i;
507
508         for (i = 0; i < nb_pkts; i++)
509                 sa[i] = &sa_ctx->sa[sa_idx[i]];
510 }