Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2022 Intel Corporation
3 : : */
4 : :
5 : : #include <stdalign.h>
6 : : #include <stdlib.h>
7 : : #include <stdio.h>
8 : : #include <errno.h>
9 : : #include <arpa/inet.h>
10 : :
11 : : #include <rte_common.h>
12 : : #include <rte_random.h>
13 : : #include <rte_ip.h>
14 : : #include <rte_tailq.h>
15 : : #include <rte_eal_memconfig.h>
16 : : #include <rte_ring.h>
17 : : #include <rte_mbuf.h>
18 : : #include <rte_cryptodev.h>
19 : : #include <rte_ipsec.h>
20 : :
21 : : #include "rte_swx_ipsec.h"
22 : :
23 : : #ifndef RTE_SWX_IPSEC_HUGE_PAGES_DISABLE
24 : :
25 : : #include <rte_malloc.h>
26 : :
27 : : static void *
28 : : env_calloc(size_t size, size_t alignment, int numa_node)
29 : : {
30 : 0 : return rte_zmalloc_socket(NULL, size, alignment, numa_node);
31 : : }
32 : :
33 : : static void
34 : : env_free(void *start, size_t size __rte_unused)
35 : : {
36 : 0 : rte_free(start);
37 : 0 : }
38 : :
39 : : #else
40 : :
41 : : #include <numa.h>
42 : :
43 : : static void *
44 : : env_calloc(size_t size, size_t alignment __rte_unused, int numa_node)
45 : : {
46 : : void *start;
47 : :
48 : : if (numa_available() == -1)
49 : : return NULL;
50 : :
51 : : start = numa_alloc_onnode(size, numa_node);
52 : : if (!start)
53 : : return NULL;
54 : :
55 : : memset(start, 0, size);
56 : : return start;
57 : : }
58 : :
59 : : static void
60 : : env_free(void *start, size_t size)
61 : : {
62 : : if ((numa_available() == -1) || !start)
63 : : return;
64 : :
65 : : numa_free(start, size);
66 : : }
67 : :
68 : : #endif
69 : :
70 : : #ifndef RTE_SWX_IPSEC_POOL_CACHE_SIZE
71 : : #define RTE_SWX_IPSEC_POOL_CACHE_SIZE 256
72 : : #endif
73 : :
74 : : /* The two crypto device mempools have their size set to the number of SAs. The mempool API requires
75 : : * the mempool size to be at least 1.5 times the size of the mempool cache.
76 : : */
77 : : #define N_SA_MIN (RTE_SWX_IPSEC_POOL_CACHE_SIZE * 1.5)
78 : :
79 : : struct ipsec_sa {
80 : : struct rte_ipsec_session s;
81 : : int valid;
82 : : };
83 : :
84 : : struct ipsec_pkts_in {
85 : : struct rte_mbuf *pkts[RTE_SWX_IPSEC_BURST_SIZE_MAX];
86 : : struct ipsec_sa *sa[RTE_SWX_IPSEC_BURST_SIZE_MAX];
87 : : struct rte_ipsec_group groups[RTE_SWX_IPSEC_BURST_SIZE_MAX];
88 : : struct rte_crypto_op *group_cops[RTE_SWX_IPSEC_BURST_SIZE_MAX];
89 : : struct rte_crypto_op *cops[RTE_SWX_IPSEC_BURST_SIZE_MAX];
90 : : uint32_t n_cops;
91 : : };
92 : :
93 : : struct ipsec_pkts_out {
94 : : struct rte_crypto_op *cops[RTE_SWX_IPSEC_BURST_SIZE_MAX];
95 : : struct rte_mbuf *group_pkts[RTE_SWX_IPSEC_BURST_SIZE_MAX];
96 : : struct rte_ipsec_group groups[RTE_SWX_IPSEC_BURST_SIZE_MAX];
97 : : struct rte_mbuf *pkts[RTE_SWX_IPSEC_BURST_SIZE_MAX];
98 : : uint32_t n_pkts;
99 : : };
100 : :
101 : : struct rte_swx_ipsec {
102 : : /*
103 : : * Parameters.
104 : : */
105 : :
106 : : /* IPsec instance name. */
107 : : char name[RTE_SWX_IPSEC_NAME_SIZE];
108 : :
109 : : /* Input packet queue. */
110 : : struct rte_ring *ring_in;
111 : :
112 : : /* Output packet queue. */
113 : : struct rte_ring *ring_out;
114 : :
115 : : /* Crypto device ID. */
116 : : uint8_t dev_id;
117 : :
118 : : /* Crypto device queue pair ID. */
119 : : uint16_t qp_id;
120 : :
121 : : /* Burst sizes. */
122 : : struct rte_swx_ipsec_burst_size bsz;
123 : :
124 : : /* SA table size. */
125 : : size_t n_sa_max;
126 : :
127 : : /*
128 : : * Internals.
129 : : */
130 : : /* Crypto device buffer pool for sessions. */
131 : : struct rte_mempool *mp_session;
132 : :
133 : : /* Pre-crypto packets. */
134 : : struct ipsec_pkts_in in;
135 : :
136 : : /* Post-crypto packets. */
137 : : struct ipsec_pkts_out out;
138 : :
139 : : /* Crypto device enqueue threshold. */
140 : : uint32_t crypto_wr_threshold;
141 : :
142 : : /* Packets currently under crypto device processing. */
143 : : uint32_t n_pkts_crypto;
144 : :
145 : : /* List of free SADB positions. */
146 : : uint32_t *sa_free_id;
147 : :
148 : : /* Number of elements in the SADB list of free positions. */
149 : : size_t n_sa_free_id;
150 : :
151 : : /* Allocated memory total size in bytes. */
152 : : size_t total_size;
153 : :
154 : : /* Flag for registration to the global list of instances. */
155 : : int registered;
156 : :
157 : : /*
158 : : * Table memory.
159 : : */
160 : : alignas(RTE_CACHE_LINE_SIZE) uint8_t memory[];
161 : : };
162 : :
163 : : static inline struct ipsec_sa *
164 : : ipsec_sa_get(struct rte_swx_ipsec *ipsec, uint32_t sa_id)
165 : : {
166 : 0 : struct ipsec_sa *sadb = (struct ipsec_sa *)ipsec->memory;
167 : :
168 : 0 : return &sadb[sa_id & (ipsec->n_sa_max - 1)];
169 : : }
170 : :
171 : : /* Global list of instances. */
172 : : TAILQ_HEAD(rte_swx_ipsec_list, rte_tailq_entry);
173 : :
174 : : static struct rte_tailq_elem rte_swx_ipsec_tailq = {
175 : : .name = "RTE_SWX_IPSEC",
176 : : };
177 : :
178 [ - + ]: 252 : EAL_REGISTER_TAILQ(rte_swx_ipsec_tailq)
179 : :
180 : : struct rte_swx_ipsec *
181 : 0 : rte_swx_ipsec_find(const char *name)
182 : : {
183 : : struct rte_swx_ipsec_list *ipsec_list;
184 : : struct rte_tailq_entry *te = NULL;
185 : :
186 [ # # ]: 0 : if (!name ||
187 [ # # ]: 0 : !name[0] ||
188 [ # # ]: 0 : (strnlen(name, RTE_SWX_IPSEC_NAME_SIZE) == RTE_SWX_IPSEC_NAME_SIZE))
189 : : return NULL;
190 : :
191 : 0 : ipsec_list = RTE_TAILQ_CAST(rte_swx_ipsec_tailq.head, rte_swx_ipsec_list);
192 : :
193 : 0 : rte_mcfg_tailq_read_lock();
194 : :
195 [ # # ]: 0 : TAILQ_FOREACH(te, ipsec_list, next) {
196 : 0 : struct rte_swx_ipsec *ipsec = (struct rte_swx_ipsec *)te->data;
197 : :
198 [ # # ]: 0 : if (!strncmp(name, ipsec->name, sizeof(ipsec->name))) {
199 : 0 : rte_mcfg_tailq_read_unlock();
200 : 0 : return ipsec;
201 : : }
202 : : }
203 : :
204 : 0 : rte_mcfg_tailq_read_unlock();
205 : 0 : return NULL;
206 : : }
207 : :
208 : : static int
209 : 0 : ipsec_register(struct rte_swx_ipsec *ipsec)
210 : : {
211 : : struct rte_swx_ipsec_list *ipsec_list;
212 : : struct rte_tailq_entry *te = NULL;
213 : :
214 : 0 : ipsec_list = RTE_TAILQ_CAST(rte_swx_ipsec_tailq.head, rte_swx_ipsec_list);
215 : :
216 : 0 : rte_mcfg_tailq_write_lock();
217 : :
218 [ # # ]: 0 : TAILQ_FOREACH(te, ipsec_list, next) {
219 : 0 : struct rte_swx_ipsec *elem = (struct rte_swx_ipsec *)te->data;
220 : :
221 [ # # ]: 0 : if (!strncmp(ipsec->name, elem->name, sizeof(ipsec->name))) {
222 : 0 : rte_mcfg_tailq_write_unlock();
223 : 0 : return -EEXIST;
224 : : }
225 : : }
226 : :
227 : 0 : te = calloc(1, sizeof(struct rte_tailq_entry));
228 [ # # ]: 0 : if (!te) {
229 : 0 : rte_mcfg_tailq_write_unlock();
230 : 0 : return -ENOMEM;
231 : : }
232 : :
233 : 0 : te->data = (void *)ipsec;
234 : 0 : TAILQ_INSERT_TAIL(ipsec_list, te, next);
235 : 0 : rte_mcfg_tailq_write_unlock();
236 : 0 : return 0;
237 : : }
238 : :
239 : : static void
240 : 0 : ipsec_unregister(struct rte_swx_ipsec *ipsec)
241 : : {
242 : : struct rte_swx_ipsec_list *ipsec_list;
243 : : struct rte_tailq_entry *te = NULL;
244 : :
245 : 0 : ipsec_list = RTE_TAILQ_CAST(rte_swx_ipsec_tailq.head, rte_swx_ipsec_list);
246 : :
247 : 0 : rte_mcfg_tailq_write_lock();
248 : :
249 [ # # ]: 0 : TAILQ_FOREACH(te, ipsec_list, next) {
250 [ # # ]: 0 : if (te->data == (void *)ipsec) {
251 [ # # ]: 0 : TAILQ_REMOVE(ipsec_list, te, next);
252 : 0 : rte_mcfg_tailq_write_unlock();
253 : 0 : free(te);
254 : 0 : return;
255 : : }
256 : : }
257 : :
258 : 0 : rte_mcfg_tailq_write_unlock();
259 : : }
260 : :
261 : : static void
262 : : ipsec_session_free(struct rte_swx_ipsec *ipsec, struct rte_ipsec_session *s);
263 : :
264 : : void
265 : 0 : rte_swx_ipsec_free(struct rte_swx_ipsec *ipsec)
266 : : {
267 : : size_t i;
268 : :
269 [ # # ]: 0 : if (!ipsec)
270 : : return;
271 : :
272 : : /* Remove the current instance from the global list. */
273 [ # # ]: 0 : if (ipsec->registered)
274 : 0 : ipsec_unregister(ipsec);
275 : :
276 : : /* SADB. */
277 [ # # ]: 0 : for (i = 0; i < ipsec->n_sa_max; i++) {
278 : : struct ipsec_sa *sa = ipsec_sa_get(ipsec, i);
279 : :
280 [ # # ]: 0 : if (!sa->valid)
281 : 0 : continue;
282 : :
283 : : /* SA session. */
284 : 0 : ipsec_session_free(ipsec, &sa->s);
285 : : }
286 : :
287 : : /* Crypto device buffer pools. */
288 : 0 : rte_mempool_free(ipsec->mp_session);
289 : :
290 : : /* IPsec object memory. */
291 : : env_free(ipsec, ipsec->total_size);
292 : : }
293 : :
294 : : int
295 : 0 : rte_swx_ipsec_create(struct rte_swx_ipsec **ipsec_out,
296 : : const char *name,
297 : : struct rte_swx_ipsec_params *params,
298 : : int numa_node)
299 : : {
300 : : char resource_name[RTE_SWX_IPSEC_NAME_SIZE];
301 : : struct rte_swx_ipsec *ipsec = NULL;
302 : : struct rte_ring *ring_in, *ring_out;
303 : : struct rte_cryptodev_info dev_info;
304 : : size_t n_sa_max, sadb_offset, sadb_size, sa_free_id_offset, sa_free_id_size, total_size, i;
305 : : uint32_t dev_session_size;
306 : : int dev_id, status = 0;
307 : :
308 : : /* Check input parameters. */
309 : 0 : if (!ipsec_out ||
310 [ # # ]: 0 : !name ||
311 [ # # ]: 0 : !name[0] ||
312 [ # # # # ]: 0 : (strnlen((name), RTE_SWX_IPSEC_NAME_SIZE) == RTE_SWX_IPSEC_NAME_SIZE) ||
313 : 0 : !params ||
314 [ # # ]: 0 : (params->bsz.ring_rd > RTE_SWX_IPSEC_BURST_SIZE_MAX) ||
315 [ # # ]: 0 : (params->bsz.ring_wr > RTE_SWX_IPSEC_BURST_SIZE_MAX) ||
316 [ # # ]: 0 : (params->bsz.crypto_wr > RTE_SWX_IPSEC_BURST_SIZE_MAX) ||
317 [ # # ]: 0 : (params->bsz.crypto_rd > RTE_SWX_IPSEC_BURST_SIZE_MAX) ||
318 [ # # ]: 0 : !params->n_sa_max) {
319 : : status = -EINVAL;
320 : 0 : goto error;
321 : : }
322 : :
323 : 0 : ring_in = rte_ring_lookup(params->ring_in_name);
324 [ # # ]: 0 : if (!ring_in) {
325 : : status = -EINVAL;
326 : 0 : goto error;
327 : : }
328 : :
329 : 0 : ring_out = rte_ring_lookup(params->ring_out_name);
330 [ # # ]: 0 : if (!ring_out) {
331 : : status = -EINVAL;
332 : 0 : goto error;
333 : : }
334 : :
335 : 0 : dev_id = rte_cryptodev_get_dev_id(params->crypto_dev_name);
336 [ # # ]: 0 : if (dev_id == -1) {
337 : : status = -EINVAL;
338 : 0 : goto error;
339 : : }
340 : :
341 : 0 : rte_cryptodev_info_get(dev_id, &dev_info);
342 [ # # ]: 0 : if (params->crypto_dev_queue_pair_id >= dev_info.max_nb_queue_pairs) {
343 : : status = -EINVAL;
344 : 0 : goto error;
345 : : }
346 : :
347 : : /* Memory allocation. */
348 [ # # ]: 0 : n_sa_max = rte_align64pow2(RTE_MAX(params->n_sa_max, N_SA_MIN));
349 : :
350 : : sadb_offset = sizeof(struct rte_swx_ipsec);
351 : 0 : sadb_size = RTE_CACHE_LINE_ROUNDUP(n_sa_max * sizeof(struct ipsec_sa));
352 : :
353 : 0 : sa_free_id_offset = sadb_offset + sadb_size;
354 : 0 : sa_free_id_size = RTE_CACHE_LINE_ROUNDUP(n_sa_max * sizeof(uint32_t));
355 : :
356 : 0 : total_size = sa_free_id_offset + sa_free_id_size;
357 : : ipsec = env_calloc(total_size, RTE_CACHE_LINE_SIZE, numa_node);
358 [ # # ]: 0 : if (!ipsec) {
359 : : status = -ENOMEM;
360 : 0 : goto error;
361 : : }
362 : :
363 : : /* Initialization. */
364 : 0 : strcpy(ipsec->name, name);
365 : 0 : ipsec->ring_in = ring_in;
366 : 0 : ipsec->ring_out = ring_out;
367 : 0 : ipsec->dev_id = (uint8_t)dev_id;
368 : 0 : ipsec->qp_id = params->crypto_dev_queue_pair_id;
369 : 0 : memcpy(&ipsec->bsz, ¶ms->bsz, sizeof(struct rte_swx_ipsec_burst_size));
370 : 0 : ipsec->n_sa_max = n_sa_max;
371 : :
372 : 0 : ipsec->crypto_wr_threshold = params->bsz.crypto_wr * 3 / 4;
373 : :
374 : 0 : ipsec->sa_free_id = (uint32_t *)&ipsec->memory[sa_free_id_offset];
375 [ # # ]: 0 : for (i = 0; i < n_sa_max; i++)
376 : 0 : ipsec->sa_free_id[i] = n_sa_max - 1 - i;
377 : 0 : ipsec->n_sa_free_id = n_sa_max;
378 : :
379 : 0 : ipsec->total_size = total_size;
380 : :
381 : : /* Crypto device memory pools. */
382 : 0 : dev_session_size = rte_cryptodev_sym_get_private_session_size((uint8_t)dev_id);
383 : :
384 : : snprintf(resource_name, sizeof(resource_name), "%s_mp", name);
385 : 0 : ipsec->mp_session = rte_cryptodev_sym_session_pool_create(resource_name,
386 : : n_sa_max, /* number of pool elements */
387 : : dev_session_size, /* pool element size */
388 : : RTE_SWX_IPSEC_POOL_CACHE_SIZE, /* pool cache size */
389 : : 0, /* pool element private data size */
390 : : numa_node);
391 [ # # ]: 0 : if (!ipsec->mp_session) {
392 : : status = -ENOMEM;
393 : 0 : goto error;
394 : : }
395 : :
396 : : /* Add the current instance to the global list. */
397 : 0 : status = ipsec_register(ipsec);
398 [ # # ]: 0 : if (status)
399 : 0 : goto error;
400 : :
401 : 0 : ipsec->registered = 1;
402 : :
403 : 0 : *ipsec_out = ipsec;
404 : 0 : return 0;
405 : :
406 : 0 : error:
407 : 0 : rte_swx_ipsec_free(ipsec);
408 : 0 : return status;
409 : : }
410 : :
411 : : static inline int
412 : : ipsec_sa_group(struct rte_swx_ipsec *ipsec, int n_pkts)
413 : : {
414 : : struct ipsec_sa *sa;
415 : : struct rte_ipsec_group *g;
416 : : int n_groups, n_pkts_in_group, i;
417 : :
418 : 0 : sa = ipsec->in.sa[0];
419 : :
420 : 0 : g = &ipsec->in.groups[0];
421 : 0 : g->id.ptr = sa;
422 : 0 : g->m = &ipsec->in.pkts[0];
423 : : n_pkts_in_group = 1;
424 : : n_groups = 1;
425 : :
426 [ # # ]: 0 : for (i = 1; i < n_pkts; i++) {
427 : 0 : struct ipsec_sa *sa_new = ipsec->in.sa[i];
428 : :
429 : : /* Same SA => Add the current pkt to the same group. */
430 [ # # ]: 0 : if (sa_new == sa) {
431 : 0 : n_pkts_in_group++;
432 : 0 : continue;
433 : : }
434 : :
435 : : /* Different SA => Close the current group & add the current pkt to a new group. */
436 : 0 : g->cnt = n_pkts_in_group;
437 : : sa = sa_new;
438 : :
439 : 0 : g++;
440 : 0 : g->id.ptr = sa;
441 : 0 : g->m = &ipsec->in.pkts[i];
442 : : n_pkts_in_group = 1;
443 : 0 : n_groups++;
444 : : }
445 : :
446 : : /* Close the last group. */
447 : 0 : g->cnt = n_pkts_in_group;
448 : :
449 : : return n_groups;
450 : : }
451 : :
452 : : static inline void
453 : 0 : ipsec_crypto_enqueue(struct rte_swx_ipsec *ipsec, uint16_t n_cops)
454 : : {
455 : 0 : struct rte_crypto_op **dst0 = ipsec->in.cops, **dst;
456 : 0 : struct rte_crypto_op **src = ipsec->in.group_cops;
457 : :
458 : 0 : uint32_t n_pkts_crypto = ipsec->n_pkts_crypto;
459 : 0 : uint32_t n_dst = ipsec->in.n_cops;
460 : 0 : uint32_t n_dst_max = ipsec->bsz.crypto_wr;
461 : 0 : uint32_t n_dst_avail = n_dst_max - n_dst;
462 : 0 : uint32_t n_src = n_cops;
463 : : uint32_t i;
464 : :
465 : 0 : dst = &dst0[n_dst];
466 : :
467 : : /* Shortcut: If no elements in DST and enough elements in SRC, then simply use SRC directly
468 : : * instead of moving the SRC to DST first and then using DST.
469 : : */
470 [ # # # # ]: 0 : if (!n_dst && n_src >= ipsec->crypto_wr_threshold) {
471 : : uint16_t n_ok;
472 : :
473 : 0 : n_ok = rte_cryptodev_enqueue_burst(ipsec->dev_id, ipsec->qp_id, src, n_src);
474 : 0 : ipsec->n_pkts_crypto = n_pkts_crypto + n_ok;
475 : :
476 [ # # ]: 0 : for (i = n_ok; i < n_src; i++) {
477 : 0 : struct rte_crypto_op *cop = src[i];
478 : 0 : struct rte_mbuf *m = cop->sym->m_src;
479 : :
480 : 0 : rte_pktmbuf_free(m);
481 : : }
482 : :
483 : : return;
484 : : }
485 : :
486 : : /* Move from SRC to DST. Every time DST gets full, send burst from DST. */
487 [ # # ]: 0 : for ( ; n_src >= n_dst_avail; ) {
488 : : uint32_t n_ok;
489 : :
490 : : /* Move from SRC to DST. */
491 [ # # ]: 0 : for (i = 0; i < n_dst_avail; i++)
492 : 0 : *dst++ = *src++;
493 : :
494 : 0 : n_src -= n_dst_avail;
495 : :
496 : : /* DST full: send burst from DST. */
497 : 0 : n_ok = rte_cryptodev_enqueue_burst(ipsec->dev_id, ipsec->qp_id, dst0, n_dst_max);
498 : 0 : n_pkts_crypto += n_ok;
499 : :
500 [ # # ]: 0 : for (i = n_ok ; i < n_dst_max; i++) {
501 : 0 : struct rte_crypto_op *cop = dst0[i];
502 : 0 : struct rte_mbuf *m = cop->sym->m_src;
503 : :
504 : 0 : rte_pktmbuf_free(m);
505 : : }
506 : :
507 : : /* Next iteration. */
508 : : dst = dst0;
509 : : n_dst = 0;
510 : : n_dst_avail = n_dst_max;
511 : : }
512 : :
513 : 0 : ipsec->n_pkts_crypto = n_pkts_crypto;
514 : :
515 : : /* Move from SRC to DST. Not enough elements in SRC to get DST full. */
516 [ # # ]: 0 : for (i = 0; i < n_src; i++)
517 : 0 : *dst++ = *src++;
518 : :
519 : 0 : n_dst += n_src;
520 : :
521 : 0 : ipsec->in.n_cops = n_dst;
522 : : }
523 : :
524 : : /**
525 : : * Packet buffer anatomy:
526 : : *
527 : : * +----------+---------+--------------------------------------------------------------------------+
528 : : * | Offset | Size | Description |
529 : : * | (Byte #) | (Bytes) | |
530 : : * +==========+=========+==========================================================================+
531 : : * | 0 | 128 | Meta-data: struct rte_mbuf. |
532 : : * | | | The buf_addr field points to the start of the packet section. |
533 : : * +----------+---------+--------------------------------------------------------------------------+
534 : : * | 128 | 128 | Meta-data: struct ipsec_mbuf (see below). |
535 : : * +----------+---------+--------------------------------------------------------------------------+
536 : : * | 256 | | Packet section. |
537 : : * | | | The first packet byte is placed at the offset indicated by the struct |
538 : : * | | | rte_mbuf::data_off field relative to the start of the packet section. |
539 : : * +----------+---------+--------------------------------------------------------------------------+
540 : : */
541 : : struct ipsec_mbuf {
542 : : struct ipsec_sa *sa;
543 : : struct rte_crypto_op cop;
544 : : struct rte_crypto_sym_op sym_cop;
545 : : uint8_t buffer[32]; /* The crypto IV is placed here. */
546 : : };
547 : :
548 : : /* Offset from the start of the struct ipsec_mbuf::cop where the crypto IV will be placed. */
549 : : #define IV_OFFSET (sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op))
550 : :
551 : : #define META_LENGTH sizeof(struct rte_swx_ipsec_input_packet_metadata)
552 : :
553 : : static inline void
554 : 0 : rte_swx_ipsec_pre_crypto(struct rte_swx_ipsec *ipsec)
555 : : {
556 : : int n_pkts, n_groups, i;
557 : :
558 : : /* Read packets from the input ring. */
559 : 0 : n_pkts = rte_ring_sc_dequeue_burst(ipsec->ring_in,
560 : 0 : (void **)ipsec->in.pkts,
561 : : ipsec->bsz.ring_rd,
562 : : NULL);
563 [ # # ]: 0 : if (!n_pkts)
564 : : return;
565 : :
566 : : /* Get the SA for each packet. */
567 [ # # ]: 0 : for (i = 0; i < n_pkts; i++) {
568 : 0 : struct rte_mbuf *m = ipsec->in.pkts[i];
569 : : struct rte_swx_ipsec_input_packet_metadata *meta;
570 : : struct rte_ipv4_hdr *ipv4_hdr;
571 : : uint32_t sa_id;
572 : :
573 : 0 : meta = rte_pktmbuf_mtod(m, struct rte_swx_ipsec_input_packet_metadata *);
574 : 0 : ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, META_LENGTH);
575 : :
576 : : /* Read the SA ID from the IPsec meta-data placed at the front of the IP packet. */
577 [ # # ]: 0 : sa_id = ntohl(meta->sa_id);
578 : :
579 : : /* Consume the IPsec meta-data. */
580 : 0 : m->data_off += META_LENGTH;
581 : 0 : m->data_len -= META_LENGTH;
582 : 0 : m->pkt_len -= META_LENGTH;
583 : :
584 : : /* Set the fields required by the IPsec library. */
585 : 0 : m->l2_len = 0;
586 : 0 : m->l3_len = (ipv4_hdr->version_ihl >> 4 == 4) ?
587 [ # # ]: 0 : sizeof(struct rte_ipv4_hdr) :
588 : : sizeof(struct rte_ipv6_hdr);
589 : :
590 : : /* Get the SA. */
591 : 0 : ipsec->in.sa[i] = ipsec_sa_get(ipsec, sa_id);
592 : : }
593 : :
594 : : /* Group packets that share the same SA. */
595 : : n_groups = ipsec_sa_group(ipsec, n_pkts);
596 : :
597 : : /* Write each group of packets sharing the same SA to the crypto device. */
598 [ # # ]: 0 : for (i = 0; i < n_groups; i++) {
599 : : struct rte_ipsec_group *g = &ipsec->in.groups[i];
600 : 0 : struct ipsec_sa *sa = g->id.ptr;
601 : 0 : struct rte_ipsec_session *s = &sa->s;
602 : : uint32_t j;
603 : : uint16_t n_pkts_ok;
604 : :
605 : : /* Prepare the crypto ops for the current group. */
606 [ # # ]: 0 : for (j = 0; j < g->cnt; j++) {
607 : 0 : struct rte_mbuf *m = g->m[j];
608 : : struct ipsec_mbuf *priv = rte_mbuf_to_priv(m);
609 : :
610 : 0 : priv->sa = sa;
611 : 0 : ipsec->in.group_cops[j] = &priv->cop;
612 : : }
613 : :
614 : 0 : n_pkts_ok = rte_ipsec_pkt_crypto_prepare(s, g->m, ipsec->in.group_cops, g->cnt);
615 : :
616 [ # # ]: 0 : for (j = n_pkts_ok; j < g->cnt; j++) {
617 : 0 : struct rte_mbuf *m = g->m[j];
618 : :
619 : 0 : rte_pktmbuf_free(m);
620 : : }
621 : :
622 : : /* Write the crypto ops of the current group to the crypto device. */
623 : 0 : ipsec_crypto_enqueue(ipsec, n_pkts_ok);
624 : : }
625 : : }
626 : :
627 : : static inline void
628 : 0 : ipsec_ring_enqueue(struct rte_swx_ipsec *ipsec, struct rte_ipsec_group *g, uint32_t n_pkts)
629 : : {
630 : 0 : struct rte_mbuf **dst0 = ipsec->out.pkts, **dst;
631 : 0 : struct rte_mbuf **src = g->m;
632 : :
633 : 0 : uint32_t n_dst = ipsec->out.n_pkts;
634 : 0 : uint32_t n_dst_max = ipsec->bsz.ring_wr;
635 : 0 : uint32_t n_dst_avail = n_dst_max - n_dst;
636 : : uint32_t n_src = n_pkts;
637 : : uint32_t i;
638 : :
639 : 0 : dst = &dst0[n_dst];
640 : :
641 : : /* Move from SRC to DST. Every time DST gets full, send burst from DST. */
642 [ # # ]: 0 : for ( ; n_src >= n_dst_avail; ) {
643 : : uint32_t n_ok;
644 : :
645 : : /* Move from SRC to DST. */
646 [ # # ]: 0 : for (i = 0; i < n_dst_avail; i++)
647 : 0 : *dst++ = *src++;
648 : :
649 : 0 : n_src -= n_dst_avail;
650 : :
651 : : /* DST full: send burst from DST. */
652 : 0 : n_ok = rte_ring_sp_enqueue_burst(ipsec->ring_out, (void **)dst0, n_dst_max, NULL);
653 : :
654 [ # # ]: 0 : for (i = n_ok ; i < n_dst_max; i++) {
655 : 0 : struct rte_mbuf *m = dst[i];
656 : :
657 : 0 : rte_pktmbuf_free(m);
658 : : }
659 : :
660 : : /* Next iteration. */
661 : : dst = dst0;
662 : : n_dst = 0;
663 : : n_dst_avail = n_dst_max;
664 : : }
665 : :
666 : : /* Move from SRC to DST. Not enough elements in SRC to get DST full. */
667 [ # # ]: 0 : for (i = 0; i < n_src; i++)
668 : 0 : *dst++ = *src++;
669 : :
670 : 0 : n_dst += n_src;
671 : :
672 : 0 : ipsec->out.n_pkts = n_dst;
673 : 0 : }
674 : :
675 : : static inline void
676 : 0 : rte_swx_ipsec_post_crypto(struct rte_swx_ipsec *ipsec)
677 : : {
678 : 0 : uint32_t n_pkts_crypto = ipsec->n_pkts_crypto, n_pkts, ng, i;
679 : :
680 : : /* Read the crypto ops from the crypto device. */
681 [ # # ]: 0 : if (!n_pkts_crypto)
682 : : return;
683 : :
684 : 0 : n_pkts = rte_cryptodev_dequeue_burst(ipsec->dev_id,
685 : 0 : ipsec->qp_id,
686 : 0 : ipsec->out.cops,
687 : 0 : ipsec->bsz.crypto_rd);
688 [ # # ]: 0 : if (!n_pkts)
689 : : return;
690 : :
691 : 0 : ipsec->n_pkts_crypto = n_pkts_crypto - n_pkts;
692 : :
693 : : /* Group packets that share the same SA. */
694 : 0 : ng = rte_ipsec_pkt_crypto_group((const struct rte_crypto_op **)(uintptr_t)ipsec->out.cops,
695 : 0 : ipsec->out.group_pkts,
696 : 0 : ipsec->out.groups,
697 : : n_pkts);
698 : :
699 : : /* Perform post-crypto IPsec processing for each group of packets that share the same SA.
700 : : * Write each group of packets to the output ring.
701 : : */
702 [ # # ]: 0 : for (i = 0, n_pkts = 0; i < ng; i++) {
703 : 0 : struct rte_ipsec_group *g = &ipsec->out.groups[i];
704 : 0 : struct rte_ipsec_session *s = g->id.ptr;
705 : : uint32_t n_pkts_ok, j;
706 : :
707 : : /* Perform post-crypto IPsec processing for the current group. */
708 : 0 : n_pkts_ok = rte_ipsec_pkt_process(s, g->m, g->cnt);
709 : :
710 [ # # ]: 0 : for (j = n_pkts_ok; j < g->cnt; j++) {
711 : 0 : struct rte_mbuf *m = g->m[j];
712 : :
713 : 0 : rte_pktmbuf_free(m);
714 : : }
715 : :
716 : : /* Write the packets of the current group to the output ring. */
717 : 0 : ipsec_ring_enqueue(ipsec, g, n_pkts_ok);
718 : : }
719 : : }
720 : :
721 : : void
722 : 0 : rte_swx_ipsec_run(struct rte_swx_ipsec *ipsec)
723 : : {
724 : 0 : rte_swx_ipsec_pre_crypto(ipsec);
725 : 0 : rte_swx_ipsec_post_crypto(ipsec);
726 : 0 : }
727 : :
728 : : /**
729 : : * IPsec Control Plane API
730 : : */
731 : : struct cipher_alg {
732 : : const char *name;
733 : : enum rte_crypto_cipher_algorithm alg;
734 : : uint32_t iv_size;
735 : : uint32_t block_size;
736 : : uint32_t key_size;
737 : : };
738 : :
739 : : struct auth_alg {
740 : : const char *name;
741 : : enum rte_crypto_auth_algorithm alg;
742 : : uint32_t iv_size;
743 : : uint32_t digest_size;
744 : : uint32_t key_size;
745 : : };
746 : :
747 : : struct aead_alg {
748 : : const char *name;
749 : : enum rte_crypto_aead_algorithm alg;
750 : : uint32_t iv_size;
751 : : uint32_t block_size;
752 : : uint32_t digest_size;
753 : : uint32_t key_size;
754 : : uint32_t aad_size;
755 : : };
756 : :
757 : : static struct cipher_alg cipher_algs[] = {
758 : : [0] = {
759 : : .name = "null",
760 : : .alg = RTE_CRYPTO_CIPHER_NULL,
761 : : .iv_size = 0,
762 : : .block_size = 4,
763 : : .key_size = 0,
764 : : },
765 : :
766 : : [1] = {
767 : : .name = "aes-cbc-128",
768 : : .alg = RTE_CRYPTO_CIPHER_AES_CBC,
769 : : .iv_size = 16,
770 : : .block_size = 16,
771 : : .key_size = 16,
772 : : },
773 : :
774 : : [2] = {
775 : : .name = "aes-cbc-192",
776 : : .alg = RTE_CRYPTO_CIPHER_AES_CBC,
777 : : .iv_size = 16,
778 : : .block_size = 16,
779 : : .key_size = 24,
780 : : },
781 : :
782 : : [3] = {
783 : : .name = "aes-cbc-256",
784 : : .alg = RTE_CRYPTO_CIPHER_AES_CBC,
785 : : .iv_size = 16,
786 : : .block_size = 16,
787 : : .key_size = 32,
788 : : },
789 : :
790 : : [4] = {
791 : : .name = "aes-ctr-128",
792 : : .alg = RTE_CRYPTO_CIPHER_AES_CTR,
793 : : .iv_size = 8,
794 : : .block_size = 4,
795 : : .key_size = 20,
796 : : },
797 : :
798 : : [5] = {
799 : : .name = "aes-ctr-192",
800 : : .alg = RTE_CRYPTO_CIPHER_AES_CTR,
801 : : .iv_size = 16,
802 : : .block_size = 16,
803 : : .key_size = 28,
804 : : },
805 : :
806 : : [6] = {
807 : : .name = "aes-ctr-256",
808 : : .alg = RTE_CRYPTO_CIPHER_AES_CTR,
809 : : .iv_size = 16,
810 : : .block_size = 16,
811 : : .key_size = 36,
812 : : },
813 : :
814 : : [7] = {
815 : : .name = "3des-cbc",
816 : : .alg = RTE_CRYPTO_CIPHER_3DES_CBC,
817 : : .iv_size = 8,
818 : : .block_size = 8,
819 : : .key_size = 24,
820 : : },
821 : :
822 : : [8] = {
823 : : .name = "des-cbc",
824 : : .alg = RTE_CRYPTO_CIPHER_DES_CBC,
825 : : .iv_size = 8,
826 : : .block_size = 8,
827 : : .key_size = 8,
828 : : },
829 : : };
830 : :
831 : : static struct auth_alg auth_algs[] = {
832 : : [0] = {
833 : : .name = "null",
834 : : .alg = RTE_CRYPTO_AUTH_NULL,
835 : : .iv_size = 0,
836 : : .digest_size = 0,
837 : : .key_size = 0,
838 : : },
839 : :
840 : : [1] = {
841 : : .name = "sha1-hmac",
842 : : .alg = RTE_CRYPTO_AUTH_SHA1_HMAC,
843 : : .iv_size = 0,
844 : : .digest_size = 12,
845 : : .key_size = 20,
846 : : },
847 : :
848 : : [2] = {
849 : : .name = "sha256-hmac",
850 : : .alg = RTE_CRYPTO_AUTH_SHA256_HMAC,
851 : : .iv_size = 0,
852 : : .digest_size = 16,
853 : : .key_size = 32,
854 : : },
855 : :
856 : : [3] = {
857 : : .name = "sha384-hmac",
858 : : .alg = RTE_CRYPTO_AUTH_SHA384_HMAC,
859 : : .iv_size = 0,
860 : : .digest_size = 24,
861 : : .key_size = 48,
862 : : },
863 : :
864 : : [4] = {
865 : : .name = "sha512-hmac",
866 : : .alg = RTE_CRYPTO_AUTH_SHA512_HMAC,
867 : : .iv_size = 0,
868 : : .digest_size = 32,
869 : : .key_size = 64,
870 : : },
871 : :
872 : : [5] = {
873 : : .name = "aes-gmac",
874 : : .alg = RTE_CRYPTO_AUTH_AES_GMAC,
875 : : .iv_size = 8,
876 : : .digest_size = 16,
877 : : .key_size = 20,
878 : : },
879 : :
880 : : [6] = {
881 : : .name = "aes-xcbc-mac-96",
882 : : .alg = RTE_CRYPTO_AUTH_AES_XCBC_MAC,
883 : : .iv_size = 0,
884 : : .digest_size = 12,
885 : : .key_size = 16,
886 : : },
887 : : };
888 : :
889 : : static struct aead_alg aead_algs[] = {
890 : : [0] = {
891 : : .name = "aes-gcm-128",
892 : : .alg = RTE_CRYPTO_AEAD_AES_GCM,
893 : : .iv_size = 8,
894 : : .block_size = 4,
895 : : .key_size = 20,
896 : : .digest_size = 16,
897 : : .aad_size = 8,
898 : : },
899 : :
900 : : [1] = {
901 : : .name = "aes-gcm-192",
902 : : .alg = RTE_CRYPTO_AEAD_AES_GCM,
903 : : .iv_size = 8,
904 : : .block_size = 4,
905 : : .key_size = 28,
906 : : .digest_size = 16,
907 : : .aad_size = 8,
908 : : },
909 : :
910 : : [2] = {
911 : : .name = "aes-gcm-256",
912 : : .alg = RTE_CRYPTO_AEAD_AES_GCM,
913 : : .iv_size = 8,
914 : : .block_size = 4,
915 : : .key_size = 36,
916 : : .digest_size = 16,
917 : : .aad_size = 8,
918 : : },
919 : :
920 : : [3] = {
921 : : .name = "aes-ccm-128",
922 : : .alg = RTE_CRYPTO_AEAD_AES_CCM,
923 : : .iv_size = 8,
924 : : .block_size = 4,
925 : : .key_size = 20,
926 : : .digest_size = 16,
927 : : .aad_size = 8,
928 : : },
929 : :
930 : : [4] = {
931 : : .name = "aes-ccm-192",
932 : : .alg = RTE_CRYPTO_AEAD_AES_CCM,
933 : : .iv_size = 8,
934 : : .block_size = 4,
935 : : .key_size = 28,
936 : : .digest_size = 16,
937 : : .aad_size = 8,
938 : : },
939 : :
940 : : [5] = {
941 : : .name = "aes-ccm-256",
942 : : .alg = RTE_CRYPTO_AEAD_AES_CCM,
943 : : .iv_size = 8,
944 : : .block_size = 4,
945 : : .key_size = 36,
946 : : .digest_size = 16,
947 : : .aad_size = 8,
948 : : },
949 : :
950 : : [6] = {
951 : : .name = "chacha20-poly1305",
952 : : .alg = RTE_CRYPTO_AEAD_CHACHA20_POLY1305,
953 : : .iv_size = 12,
954 : : .block_size = 64,
955 : : .key_size = 36,
956 : : .digest_size = 16,
957 : : .aad_size = 8,
958 : : },
959 : : };
960 : :
961 : : static struct cipher_alg *
962 : 0 : cipher_alg_find(const char *name)
963 : : {
964 : : size_t i;
965 : :
966 [ # # ]: 0 : for (i = 0; i < RTE_DIM(cipher_algs); i++) {
967 : 0 : struct cipher_alg *alg = &cipher_algs[i];
968 : :
969 [ # # ]: 0 : if (!strcmp(name, alg->name))
970 : 0 : return alg;
971 : : }
972 : :
973 : : return NULL;
974 : : }
975 : :
976 : : static struct cipher_alg *
977 : : cipher_alg_find_by_id(enum rte_crypto_cipher_algorithm alg_id, uint32_t key_size)
978 : : {
979 : : size_t i;
980 : :
981 [ # # ]: 0 : for (i = 0; i < RTE_DIM(cipher_algs); i++) {
982 : 0 : struct cipher_alg *alg = &cipher_algs[i];
983 : :
984 [ # # # # ]: 0 : if (alg->alg == alg_id && alg->key_size == key_size)
985 : : return alg;
986 : : }
987 : :
988 : : return NULL;
989 : : }
990 : :
991 : : static struct auth_alg *
992 : 0 : auth_alg_find(const char *name)
993 : : {
994 : : size_t i;
995 : :
996 [ # # ]: 0 : for (i = 0; i < RTE_DIM(auth_algs); i++) {
997 : 0 : struct auth_alg *alg = &auth_algs[i];
998 : :
999 [ # # ]: 0 : if (!strcmp(name, alg->name))
1000 : 0 : return alg;
1001 : : }
1002 : :
1003 : : return NULL;
1004 : : }
1005 : :
1006 : : static struct auth_alg *
1007 : : auth_alg_find_by_id(enum rte_crypto_auth_algorithm alg_id, uint32_t key_size)
1008 : : {
1009 : : size_t i;
1010 : :
1011 [ # # ]: 0 : for (i = 0; i < RTE_DIM(auth_algs); i++) {
1012 : 0 : struct auth_alg *alg = &auth_algs[i];
1013 : :
1014 [ # # # # ]: 0 : if (alg->alg == alg_id && alg->key_size == key_size)
1015 : : return alg;
1016 : : }
1017 : :
1018 : : return NULL;
1019 : : }
1020 : :
1021 : : static struct aead_alg *
1022 : 0 : aead_alg_find(const char *name)
1023 : : {
1024 : : size_t i;
1025 : :
1026 [ # # ]: 0 : for (i = 0; i < RTE_DIM(aead_algs); i++) {
1027 : 0 : struct aead_alg *alg = &aead_algs[i];
1028 : :
1029 [ # # ]: 0 : if (!strcmp(name, alg->name))
1030 : 0 : return alg;
1031 : : }
1032 : :
1033 : : return NULL;
1034 : : }
1035 : :
1036 : : static struct aead_alg *
1037 : : aead_alg_find_by_id(enum rte_crypto_aead_algorithm alg_id, uint32_t key_size)
1038 : : {
1039 : : size_t i;
1040 : :
1041 [ # # ]: 0 : for (i = 0; i < RTE_DIM(aead_algs); i++) {
1042 : 0 : struct aead_alg *alg = &aead_algs[i];
1043 : :
1044 [ # # # # ]: 0 : if (alg->alg == alg_id && alg->key_size == key_size)
1045 : : return alg;
1046 : : }
1047 : :
1048 : : return NULL;
1049 : : }
1050 : :
1051 : : static int
1052 : : char_to_hex(char c, uint8_t *val)
1053 : : {
1054 : 0 : if (c >= '0' && c <= '9') {
1055 : : *val = c - '0';
1056 : : return 0;
1057 : : }
1058 : :
1059 [ # # # # ]: 0 : if (c >= 'A' && c <= 'F') {
1060 : 0 : *val = c - 'A' + 10;
1061 : : return 0;
1062 : : }
1063 : :
1064 [ # # # # ]: 0 : if (c >= 'a' && c <= 'f') {
1065 : 0 : *val = c - 'a' + 10;
1066 : : return 0;
1067 : : }
1068 : :
1069 : : return -EINVAL;
1070 : : }
1071 : :
1072 : : static int
1073 : 0 : hex_string_parse(char *src, uint8_t *dst, uint32_t n_dst_bytes)
1074 : : {
1075 : : uint32_t i;
1076 : :
1077 : : /* Check input arguments. */
1078 [ # # # # : 0 : if (!src || !src[0] || !dst || !n_dst_bytes)
# # ]
1079 : : return -EINVAL;
1080 : :
1081 : : /* Skip any leading "0x" or "0X" in the src string. */
1082 [ # # # # ]: 0 : if ((src[0] == '0') && (src[1] == 'x' || src[1] == 'X'))
1083 : 0 : src += 2;
1084 : :
1085 : : /* Convert each group of two hex characters in the src string to one byte in dst array. */
1086 [ # # ]: 0 : for (i = 0; i < n_dst_bytes; i++) {
1087 : : uint8_t a, b;
1088 : : int status;
1089 : :
1090 [ # # ]: 0 : status = char_to_hex(*src, &a);
1091 : : if (status)
1092 : : return status;
1093 : : src++;
1094 : :
1095 [ # # ]: 0 : status = char_to_hex(*src, &b);
1096 : : if (status)
1097 : : return status;
1098 : 0 : src++;
1099 : :
1100 : 0 : dst[i] = a * 16 + b;
1101 : : }
1102 : :
1103 : : /* Check for the end of the src string. */
1104 [ # # ]: 0 : if (*src)
1105 : 0 : return -EINVAL;
1106 : :
1107 : : return 0;
1108 : : }
1109 : :
1110 : : static int
1111 : : token_is_comment(const char *token)
1112 : : {
1113 [ # # ]: 0 : if ((token[0] == '#') ||
1114 [ # # ]: 0 : (token[0] == ';') ||
1115 [ # # ]: 0 : ((token[0] == '/') && (token[1] == '/')))
1116 : : return 1; /* TRUE. */
1117 : :
1118 : : return 0; /* FALSE. */
1119 : : }
1120 : :
1121 : : #define MAX_TOKENS 64
1122 : :
1123 : : #define CHECK(condition, msg) \
1124 : : do { \
1125 : : if (!(condition)) { \
1126 : : if (errmsg) \
1127 : : *errmsg = msg; \
1128 : : goto error; \
1129 : : } \
1130 : : } while (0)
1131 : :
1132 : : struct rte_swx_ipsec_sa_params *
1133 : 0 : rte_swx_ipsec_sa_read(struct rte_swx_ipsec *ipsec __rte_unused,
1134 : : const char *string,
1135 : : int *is_blank_or_comment,
1136 : : const char **errmsg)
1137 : : {
1138 : : char *token_array[MAX_TOKENS], **t;
1139 : : struct rte_swx_ipsec_sa_params *p = NULL;
1140 : : char *s0 = NULL, *s;
1141 : : uint32_t n_tokens = 0;
1142 : : int blank_or_comment = 0;
1143 : :
1144 : : /* Check input arguments. */
1145 [ # # # # : 0 : CHECK(string && string[0], "NULL input");
# # ]
1146 : :
1147 : : /* Memory allocation. */
1148 : 0 : s0 = strdup(string);
1149 : 0 : p = calloc(1, sizeof(struct rte_swx_ipsec_sa_params));
1150 [ # # # # ]: 0 : CHECK(s0 && p, "Not enough memory");
1151 : :
1152 : : /* Parse the string into tokens. */
1153 : 0 : for (s = s0; ; ) {
1154 : : char *token;
1155 : :
1156 : 0 : token = strtok_r(s, " \f\n\r\t\v", &s);
1157 [ # # ]: 0 : if (!token || token_is_comment(token))
1158 : : break;
1159 : :
1160 [ # # # # ]: 0 : CHECK(n_tokens < RTE_DIM(token_array), "Too many tokens");
1161 : :
1162 : 0 : token_array[n_tokens] = token;
1163 : 0 : n_tokens++;
1164 : : }
1165 : :
1166 : : t = token_array;
1167 [ # # ]: 0 : if (!n_tokens) {
1168 : : blank_or_comment = 1;
1169 : 0 : goto error;
1170 : : }
1171 : :
1172 : : /*
1173 : : * Crypto operation.
1174 : : */
1175 [ # # ]: 0 : if (!strcmp(t[0], "encrypt"))
1176 : 0 : p->encrypt = 1;
1177 [ # # ]: 0 : else if (!strcmp(t[0], "decrypt"))
1178 : 0 : p->encrypt = 0;
1179 : : else
1180 [ # # ]: 0 : CHECK(0, "Missing \"encrypt\"/\"decrypt\" keyword");
1181 : :
1182 : : t++;
1183 : 0 : n_tokens--;
1184 : :
1185 : : /*
1186 : : * Crypto parameters.
1187 : : */
1188 [ # # # # ]: 0 : CHECK(n_tokens >= 2, "Not enough tokens");
1189 : :
1190 [ # # ]: 0 : if (!strcmp(t[0], "cipher")) {
1191 : : struct cipher_alg *cipher_alg;
1192 : : struct auth_alg *auth_alg;
1193 : : uint32_t key_size;
1194 : :
1195 : 0 : p->crypto.is_aead = 0;
1196 : :
1197 : : /* cipher. */
1198 : 0 : cipher_alg = cipher_alg_find(t[1]);
1199 [ # # # # ]: 0 : CHECK(cipher_alg, "Unsupported cipher algorithm");
1200 : :
1201 : 0 : key_size = cipher_alg->key_size;
1202 : 0 : p->crypto.cipher_auth.cipher.alg = cipher_alg->alg;
1203 : 0 : p->crypto.cipher_auth.cipher.key_size = key_size;
1204 : :
1205 : : t += 2;
1206 : 0 : n_tokens -= 2;
1207 : :
1208 [ # # ]: 0 : if (key_size) {
1209 : : int status;
1210 : :
1211 [ # # # # ]: 0 : CHECK(n_tokens >= 2, "Not enough tokens");
1212 [ # # # # ]: 0 : CHECK(!strcmp(t[0], "key"), "Missing cipher \"key\" keyword");
1213 [ # # # # ]: 0 : CHECK(key_size <= RTE_DIM(p->crypto.cipher_auth.cipher.key),
1214 : : "Cipher algorithm key too big");
1215 : :
1216 : 0 : status = hex_string_parse(t[1], p->crypto.cipher_auth.cipher.key, key_size);
1217 [ # # # # ]: 0 : CHECK(!status, "Cipher key invalid format");
1218 : :
1219 : : t += 2;
1220 : 0 : n_tokens -= 2;
1221 : : }
1222 : :
1223 : : /* authentication. */
1224 [ # # # # ]: 0 : CHECK(n_tokens >= 2, "Not enough tokens");
1225 [ # # # # ]: 0 : CHECK(!strcmp(t[0], "auth"), "Missing \"auth\" keyword");
1226 : :
1227 : 0 : auth_alg = auth_alg_find(t[1]);
1228 [ # # # # ]: 0 : CHECK(auth_alg, "Unsupported authentication algorithm");
1229 : :
1230 : 0 : key_size = auth_alg->key_size;
1231 : 0 : p->crypto.cipher_auth.auth.alg = auth_alg->alg;
1232 : 0 : p->crypto.cipher_auth.auth.key_size = key_size;
1233 : :
1234 : 0 : t += 2;
1235 : 0 : n_tokens -= 2;
1236 : :
1237 [ # # ]: 0 : if (key_size) {
1238 : : int status;
1239 : :
1240 [ # # # # ]: 0 : CHECK(n_tokens >= 2, "Not enough tokens");
1241 [ # # # # ]: 0 : CHECK(!strcmp(t[0], "key"), "Missing authentication \"key\" keyword");
1242 [ # # # # ]: 0 : CHECK(key_size <= RTE_DIM(p->crypto.cipher_auth.auth.key),
1243 : : "Authentication algorithm key too big");
1244 : :
1245 : 0 : status = hex_string_parse(t[1], p->crypto.cipher_auth.auth.key, key_size);
1246 [ # # # # ]: 0 : CHECK(!status, "Authentication key invalid format");
1247 : :
1248 : 0 : t += 2;
1249 : 0 : n_tokens -= 2;
1250 : : }
1251 [ # # ]: 0 : } else if (!strcmp(t[0], "aead")) {
1252 : : struct aead_alg *alg;
1253 : : uint32_t key_size;
1254 : : int status;
1255 : :
1256 : 0 : p->crypto.is_aead = 1;
1257 : :
1258 [ # # # # ]: 0 : CHECK(n_tokens >= 4, "Not enough tokens");
1259 : 0 : alg = aead_alg_find(t[1]);
1260 [ # # # # ]: 0 : CHECK(alg, "Unsupported AEAD algorithm");
1261 : :
1262 : 0 : key_size = alg->key_size;
1263 : 0 : p->crypto.aead.alg = alg->alg;
1264 : 0 : p->crypto.aead.key_size = key_size;
1265 : :
1266 [ # # # # ]: 0 : CHECK(!strcmp(t[2], "key"), "Missing AEAD \"key\" keyword");
1267 [ # # # # ]: 0 : CHECK(key_size <= RTE_DIM(p->crypto.aead.key),
1268 : : "AEAD algorithm key too big");
1269 : :
1270 : 0 : status = hex_string_parse(t[3], p->crypto.aead.key, key_size);
1271 [ # # # # ]: 0 : CHECK(!status, "AEAD key invalid format");
1272 : :
1273 : : t += 4;
1274 : 0 : n_tokens -= 4;
1275 : : } else
1276 [ # # ]: 0 : CHECK(0, "Missing \"cipher\"/\"aead\" keyword");
1277 : :
1278 : : /*
1279 : : * Packet ecapsulation parameters.
1280 : : */
1281 [ # # # # ]: 0 : CHECK(n_tokens >= 4, "Not enough tokens");
1282 [ # # # # ]: 0 : CHECK(!strcmp(t[0], "esp"), "Missing \"esp\" keyword");
1283 [ # # # # ]: 0 : CHECK(!strcmp(t[1], "spi"), "Missing \"spi\" keyword");
1284 : :
1285 : 0 : p->encap.esp.spi = strtoul(t[2], &t[2], 0);
1286 [ # # # # ]: 0 : CHECK(!t[2][0], "ESP SPI field invalid format");
1287 : :
1288 : : t += 3;
1289 : 0 : n_tokens -= 3;
1290 : :
1291 [ # # ]: 0 : if (!strcmp(t[0], "tunnel")) {
1292 : 0 : p->encap.tunnel_mode = 1;
1293 : :
1294 [ # # # # ]: 0 : CHECK(n_tokens >= 6, "Not enough tokens");
1295 : :
1296 [ # # ]: 0 : if (!strcmp(t[1], "ipv4")) {
1297 : : uint32_t addr;
1298 : :
1299 : 0 : p->encap.tunnel_ipv4 = 1;
1300 : :
1301 [ # # # # ]: 0 : CHECK(!strcmp(t[2], "srcaddr"), "Missing \"srcaddr\" keyword");
1302 : :
1303 : 0 : addr = strtoul(t[3], &t[3], 0);
1304 [ # # # # ]: 0 : CHECK(!t[3][0], "Tunnel IPv4 source address invalid format");
1305 : 0 : p->encap.tunnel.ipv4.src_addr.s_addr = htonl(addr);
1306 : :
1307 [ # # # # ]: 0 : CHECK(!strcmp(t[4], "dstaddr"), "Missing \"dstaddr\" keyword");
1308 : :
1309 : 0 : addr = strtoul(t[5], &t[5], 0);
1310 [ # # # # ]: 0 : CHECK(!t[5][0], "Tunnel IPv4 destination address invalid format");
1311 : 0 : p->encap.tunnel.ipv4.dst_addr.s_addr = htonl(addr);
1312 : :
1313 : : t += 6;
1314 : 0 : n_tokens -= 6;
1315 [ # # ]: 0 : } else if (!strcmp(t[1], "ipv6")) {
1316 : : int status;
1317 : :
1318 : 0 : p->encap.tunnel_ipv4 = 0;
1319 : :
1320 [ # # # # ]: 0 : CHECK(!strcmp(t[2], "srcaddr"), "Missing \"srcaddr\" keyword");
1321 : :
1322 : 0 : status = hex_string_parse(t[3],
1323 : 0 : p->encap.tunnel.ipv6.src_addr.a,
1324 : : 16);
1325 [ # # # # ]: 0 : CHECK(!status, "Tunnel IPv6 source address invalid format");
1326 : :
1327 [ # # # # ]: 0 : CHECK(!strcmp(t[4], "dstaddr"), "Missing \"dstaddr\" keyword");
1328 : :
1329 : 0 : status = hex_string_parse(t[5],
1330 : 0 : p->encap.tunnel.ipv6.dst_addr.a,
1331 : : 16);
1332 [ # # # # ]: 0 : CHECK(!status, "Tunnel IPv6 destination address invalid format");
1333 : :
1334 : : t += 6;
1335 : 0 : n_tokens -= 6;
1336 : : } else
1337 [ # # ]: 0 : CHECK(0, "Missing \"ipv4\"/\"ipv6\" keyword");
1338 [ # # ]: 0 : } else if (!strcmp(t[0], "transport")) {
1339 : 0 : p->encap.tunnel_mode = 0;
1340 : :
1341 : : t++;
1342 : 0 : n_tokens--;
1343 : : } else
1344 [ # # ]: 0 : CHECK(0, "Missing \"tunnel\"/\"transport\" keyword");
1345 : :
1346 : : /*
1347 : : * Any other parameters.
1348 : : */
1349 [ # # # # ]: 0 : CHECK(!n_tokens, "Unexpected trailing tokens");
1350 : :
1351 : 0 : free(s0);
1352 : 0 : return p;
1353 : :
1354 : 0 : error:
1355 : 0 : free(p);
1356 : 0 : free(s0);
1357 [ # # ]: 0 : if (is_blank_or_comment)
1358 : 0 : *is_blank_or_comment = blank_or_comment;
1359 : : return NULL;
1360 : : }
1361 : :
1362 : : static void
1363 : 0 : tunnel_ipv4_header_set(struct rte_ipv4_hdr *h, struct rte_swx_ipsec_sa_params *p)
1364 : : {
1365 : 0 : struct rte_ipv4_hdr ipv4_hdr = {
1366 : : .version_ihl = 0x45,
1367 : : .type_of_service = 0,
1368 : : .total_length = 0, /* Cannot be pre-computed. */
1369 : : .packet_id = 0,
1370 : : .fragment_offset = 0,
1371 : : .time_to_live = 64,
1372 : : .next_proto_id = IPPROTO_ESP,
1373 : : .hdr_checksum = 0, /* Cannot be pre-computed. */
1374 : 0 : .src_addr = p->encap.tunnel.ipv4.src_addr.s_addr,
1375 : 0 : .dst_addr = p->encap.tunnel.ipv4.dst_addr.s_addr,
1376 : : };
1377 : :
1378 : : memcpy(h, &ipv4_hdr, sizeof(ipv4_hdr));
1379 : 0 : }
1380 : :
1381 : : static void
1382 : 0 : tunnel_ipv6_header_set(struct rte_ipv6_hdr *h, struct rte_swx_ipsec_sa_params *p)
1383 : : {
1384 : 0 : struct rte_ipv6_hdr ipv6_hdr = {
1385 : : .vtc_flow = 0x60000000,
1386 : : .payload_len = 0, /* Cannot be pre-computed. */
1387 : : .proto = IPPROTO_ESP,
1388 : : .hop_limits = 64,
1389 : : .src_addr = p->encap.tunnel.ipv6.src_addr,
1390 : : .dst_addr = p->encap.tunnel.ipv6.dst_addr,
1391 : : };
1392 : :
1393 : : memcpy(h, &ipv6_hdr, sizeof(ipv6_hdr));
1394 : 0 : }
1395 : :
1396 : : /* IPsec library SA parameters. */
1397 : : static struct rte_crypto_sym_xform *
1398 : 0 : crypto_xform_get(struct rte_swx_ipsec_sa_params *p,
1399 : : struct rte_crypto_sym_xform *xform,
1400 : : uint32_t *salt_out)
1401 : : {
1402 [ # # ]: 0 : if (p->crypto.is_aead) {
1403 : : struct aead_alg *alg;
1404 : : uint32_t key_size, salt, iv_length;
1405 : :
1406 : 0 : alg = aead_alg_find_by_id(p->crypto.aead.alg, p->crypto.aead.key_size);
1407 [ # # ]: 0 : if (!alg)
1408 : : return NULL;
1409 : :
1410 : : /* salt and salt-related key size adjustment. */
1411 : 0 : key_size = p->crypto.aead.key_size - 4;
1412 : 0 : memcpy(&salt, &p->crypto.aead.key[key_size], 4);
1413 : :
1414 : : /* IV length. */
1415 : : iv_length = 12;
1416 [ # # ]: 0 : if (p->crypto.aead.alg == RTE_CRYPTO_AEAD_AES_CCM)
1417 : : iv_length = 11;
1418 : :
1419 : : /* xform. */
1420 : 0 : xform[0].type = RTE_CRYPTO_SYM_XFORM_AEAD;
1421 : 0 : xform[0].aead.op = p->encrypt ?
1422 : 0 : RTE_CRYPTO_AEAD_OP_ENCRYPT :
1423 : : RTE_CRYPTO_AEAD_OP_DECRYPT;
1424 : 0 : xform[0].aead.algo = p->crypto.aead.alg;
1425 : 0 : xform[0].aead.key.data = p->crypto.aead.key;
1426 : 0 : xform[0].aead.key.length = key_size;
1427 : 0 : xform[0].aead.iv.offset = IV_OFFSET;
1428 : 0 : xform[0].aead.iv.length = iv_length;
1429 : 0 : xform[0].aead.digest_length = alg->digest_size;
1430 : 0 : xform[0].aead.aad_length = alg->aad_size;
1431 : 0 : xform[0].next = NULL;
1432 : :
1433 : 0 : *salt_out = salt;
1434 : 0 : return &xform[0];
1435 : : } else {
1436 : : struct cipher_alg *cipher_alg;
1437 : : struct auth_alg *auth_alg;
1438 : : uint32_t cipher_key_size, auth_key_size, salt, auth_iv_length;
1439 : :
1440 : 0 : cipher_alg = cipher_alg_find_by_id(p->crypto.cipher_auth.cipher.alg,
1441 : : p->crypto.cipher_auth.cipher.key_size);
1442 [ # # ]: 0 : if (!cipher_alg)
1443 : : return NULL;
1444 : :
1445 : 0 : auth_alg = auth_alg_find_by_id(p->crypto.cipher_auth.auth.alg,
1446 : : p->crypto.cipher_auth.auth.key_size);
1447 [ # # ]: 0 : if (!auth_alg)
1448 : : return NULL;
1449 : :
1450 : : /* salt and salt-related key size adjustment. */
1451 : : cipher_key_size = p->crypto.cipher_auth.cipher.key_size;
1452 : : auth_key_size = p->crypto.cipher_auth.auth.key_size;
1453 : :
1454 [ # # # ]: 0 : switch (p->crypto.cipher_auth.cipher.alg) {
1455 : 0 : case RTE_CRYPTO_CIPHER_AES_CBC:
1456 : : case RTE_CRYPTO_CIPHER_3DES_CBC:
1457 : 0 : salt = rte_rand();
1458 : 0 : break;
1459 : :
1460 : 0 : case RTE_CRYPTO_CIPHER_AES_CTR:
1461 : 0 : cipher_key_size -= 4;
1462 : 0 : memcpy(&salt, &p->crypto.cipher_auth.cipher.key[cipher_key_size], 4);
1463 : : break;
1464 : :
1465 : 0 : default:
1466 : 0 : salt = 0;
1467 : : }
1468 : :
1469 [ # # ]: 0 : if (p->crypto.cipher_auth.auth.alg == RTE_CRYPTO_AUTH_AES_GMAC) {
1470 : 0 : auth_key_size -= 4;
1471 : 0 : memcpy(&salt, &p->crypto.cipher_auth.auth.key[auth_key_size], 4);
1472 : : }
1473 : :
1474 : : /* IV length. */
1475 : 0 : auth_iv_length = cipher_alg->iv_size;
1476 [ # # ]: 0 : if (p->crypto.cipher_auth.auth.alg == RTE_CRYPTO_AUTH_AES_GMAC)
1477 : : auth_iv_length = 12;
1478 : :
1479 : : /* xform. */
1480 [ # # ]: 0 : if (p->encrypt) {
1481 : 0 : xform[0].type = RTE_CRYPTO_SYM_XFORM_CIPHER;
1482 : 0 : xform[0].cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
1483 : 0 : xform[0].cipher.algo = p->crypto.cipher_auth.cipher.alg;
1484 : 0 : xform[0].cipher.key.data = p->crypto.cipher_auth.cipher.key;
1485 : 0 : xform[0].cipher.key.length = cipher_key_size;
1486 : 0 : xform[0].cipher.iv.offset = IV_OFFSET;
1487 : 0 : xform[0].cipher.iv.length = cipher_alg->iv_size;
1488 : 0 : xform[0].cipher.dataunit_len = 0;
1489 : 0 : xform[0].next = &xform[1];
1490 : :
1491 : 0 : xform[1].type = RTE_CRYPTO_SYM_XFORM_AUTH;
1492 : 0 : xform[1].auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
1493 : 0 : xform[1].auth.algo = p->crypto.cipher_auth.auth.alg;
1494 : 0 : xform[1].auth.key.data = p->crypto.cipher_auth.auth.key;
1495 : 0 : xform[1].auth.key.length = auth_key_size;
1496 : 0 : xform[1].auth.iv.offset = IV_OFFSET;
1497 : 0 : xform[1].auth.iv.length = auth_iv_length;
1498 : 0 : xform[1].auth.digest_length = auth_alg->digest_size;
1499 : 0 : xform[1].next = NULL;
1500 : : } else {
1501 : 0 : xform[0].type = RTE_CRYPTO_SYM_XFORM_AUTH;
1502 : 0 : xform[0].auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
1503 : 0 : xform[0].auth.algo = p->crypto.cipher_auth.auth.alg;
1504 : 0 : xform[0].auth.key.data = p->crypto.cipher_auth.auth.key;
1505 : 0 : xform[0].auth.key.length = auth_key_size;
1506 : 0 : xform[0].auth.iv.offset = IV_OFFSET;
1507 : 0 : xform[0].auth.iv.length = auth_iv_length;
1508 : 0 : xform[0].auth.digest_length = auth_alg->digest_size;
1509 : 0 : xform[0].next = &xform[1];
1510 : :
1511 : 0 : xform[1].type = RTE_CRYPTO_SYM_XFORM_CIPHER;
1512 : 0 : xform[1].cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
1513 : 0 : xform[1].cipher.algo = p->crypto.cipher_auth.cipher.alg;
1514 : 0 : xform[1].cipher.key.data = p->crypto.cipher_auth.cipher.key;
1515 : 0 : xform[1].cipher.key.length = cipher_key_size;
1516 : 0 : xform[1].cipher.iv.offset = IV_OFFSET;
1517 : 0 : xform[1].cipher.iv.length = cipher_alg->iv_size;
1518 : 0 : xform[1].cipher.dataunit_len = 0;
1519 : 0 : xform[1].next = NULL;
1520 : : }
1521 : :
1522 : 0 : *salt_out = salt;
1523 : :
1524 [ # # ]: 0 : if (p->crypto.cipher_auth.auth.alg == RTE_CRYPTO_AUTH_AES_GMAC) {
1525 [ # # ]: 0 : if (p->encrypt)
1526 : 0 : return &xform[1];
1527 : :
1528 : 0 : xform[0].next = NULL;
1529 : 0 : return &xform[0];
1530 : : }
1531 : :
1532 : : return &xform[0];
1533 : : }
1534 : : }
1535 : :
1536 : : static void
1537 : 0 : ipsec_xform_get(struct rte_swx_ipsec_sa_params *p,
1538 : : struct rte_security_ipsec_xform *ipsec_xform,
1539 : : uint32_t salt)
1540 : : {
1541 : 0 : ipsec_xform->spi = p->encap.esp.spi;
1542 : :
1543 : 0 : ipsec_xform->salt = salt;
1544 : :
1545 : 0 : ipsec_xform->options.esn = 0;
1546 : 0 : ipsec_xform->options.udp_encap = 0;
1547 : 0 : ipsec_xform->options.copy_dscp = 1;
1548 : 0 : ipsec_xform->options.copy_flabel = 0;
1549 : 0 : ipsec_xform->options.copy_df = 0;
1550 : 0 : ipsec_xform->options.dec_ttl = 0;
1551 : 0 : ipsec_xform->options.ecn = 1;
1552 : 0 : ipsec_xform->options.stats = 0;
1553 : 0 : ipsec_xform->options.iv_gen_disable = 0;
1554 : 0 : ipsec_xform->options.tunnel_hdr_verify = 0;
1555 : 0 : ipsec_xform->options.udp_ports_verify = 0;
1556 : 0 : ipsec_xform->options.ip_csum_enable = 0;
1557 : 0 : ipsec_xform->options.l4_csum_enable = 0;
1558 : 0 : ipsec_xform->options.ip_reassembly_en = 0;
1559 : :
1560 : 0 : ipsec_xform->direction = p->encrypt ?
1561 : 0 : RTE_SECURITY_IPSEC_SA_DIR_EGRESS :
1562 : : RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
1563 : :
1564 : 0 : ipsec_xform->proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
1565 : :
1566 : 0 : ipsec_xform->mode = p->encap.tunnel_mode ?
1567 [ # # ]: 0 : RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
1568 : : RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT;
1569 : :
1570 : 0 : ipsec_xform->tunnel.type = p->encap.tunnel_ipv4 ?
1571 [ # # ]: 0 : RTE_SECURITY_IPSEC_TUNNEL_IPV4 :
1572 : : RTE_SECURITY_IPSEC_TUNNEL_IPV6;
1573 : :
1574 [ # # ]: 0 : if (p->encap.tunnel_mode) {
1575 [ # # ]: 0 : if (p->encap.tunnel_ipv4) {
1576 : 0 : ipsec_xform->tunnel.ipv4.src_ip = p->encap.tunnel.ipv4.src_addr;
1577 : 0 : ipsec_xform->tunnel.ipv4.dst_ip = p->encap.tunnel.ipv4.dst_addr;
1578 : 0 : ipsec_xform->tunnel.ipv4.dscp = 0;
1579 : 0 : ipsec_xform->tunnel.ipv4.df = 0;
1580 : 0 : ipsec_xform->tunnel.ipv4.ttl = 64;
1581 : : } else {
1582 : 0 : ipsec_xform->tunnel.ipv6.src_addr = p->encap.tunnel.ipv6.src_addr;
1583 : 0 : ipsec_xform->tunnel.ipv6.dst_addr = p->encap.tunnel.ipv6.dst_addr;
1584 : 0 : ipsec_xform->tunnel.ipv6.dscp = 0;
1585 : 0 : ipsec_xform->tunnel.ipv6.flabel = 0;
1586 : 0 : ipsec_xform->tunnel.ipv6.hlimit = 64;
1587 : : }
1588 : : }
1589 : :
1590 : 0 : ipsec_xform->life.packets_soft_limit = 0;
1591 : 0 : ipsec_xform->life.bytes_soft_limit = 0;
1592 : 0 : ipsec_xform->life.packets_hard_limit = 0;
1593 : 0 : ipsec_xform->life.bytes_hard_limit = 0;
1594 : :
1595 : 0 : ipsec_xform->replay_win_sz = 0;
1596 : :
1597 : 0 : ipsec_xform->esn.value = 0;
1598 : :
1599 : 0 : ipsec_xform->udp.dport = 0;
1600 : 0 : ipsec_xform->udp.sport = 0;
1601 : 0 : }
1602 : :
1603 : : static int
1604 : 0 : ipsec_sa_prm_get(struct rte_swx_ipsec_sa_params *p,
1605 : : struct rte_ipsec_sa_prm *sa_prm,
1606 : : struct rte_ipv4_hdr *ipv4_hdr,
1607 : : struct rte_ipv6_hdr *ipv6_hdr,
1608 : : struct rte_crypto_sym_xform *crypto_xform)
1609 : : {
1610 : : uint32_t salt;
1611 : :
1612 : : memset(sa_prm, 0, sizeof(*sa_prm)); /* Better to be safe than sorry. */
1613 : :
1614 : : sa_prm->userdata = 0; /* Not used. */
1615 : :
1616 : : sa_prm->flags = 0; /* Flag RTE_IPSEC_SAFLAG_SQN_ATOM not enabled. */
1617 : :
1618 : : /*
1619 : : * crypto_xform.
1620 : : */
1621 : 0 : sa_prm->crypto_xform = crypto_xform_get(p, crypto_xform, &salt);
1622 [ # # ]: 0 : if (!sa_prm->crypto_xform)
1623 : : return -EINVAL;
1624 : :
1625 : : /*
1626 : : * ipsec_xform.
1627 : : */
1628 : 0 : ipsec_xform_get(p, &sa_prm->ipsec_xform, salt);
1629 : :
1630 : : /*
1631 : : * tunnel / transport.
1632 : : *
1633 : : * Currently, the input IP packet type is assumed to be IPv4. To support both IPv4 and IPv6,
1634 : : * the input packet type should be added to the SA configuration parameters.
1635 : : */
1636 [ # # ]: 0 : if (p->encap.tunnel_mode) {
1637 [ # # ]: 0 : if (p->encap.tunnel_ipv4) {
1638 : 0 : sa_prm->tun.hdr_len = sizeof(struct rte_ipv4_hdr);
1639 : 0 : sa_prm->tun.hdr_l3_off = 0;
1640 : 0 : sa_prm->tun.next_proto = IPPROTO_IPIP; /* IPv4. */
1641 : 0 : sa_prm->tun.hdr = ipv4_hdr;
1642 : : } else {
1643 : 0 : sa_prm->tun.hdr_len = sizeof(struct rte_ipv6_hdr);
1644 : 0 : sa_prm->tun.hdr_l3_off = 0;
1645 : 0 : sa_prm->tun.next_proto = IPPROTO_IPIP; /* IPv4. */
1646 : 0 : sa_prm->tun.hdr = ipv6_hdr;
1647 : : }
1648 : : } else {
1649 : 0 : sa_prm->trs.proto = IPPROTO_IPIP; /* IPv4. */
1650 : : }
1651 : :
1652 : : return 0;
1653 : : }
1654 : :
1655 : : static int
1656 : 0 : ipsec_session_create(struct rte_swx_ipsec *ipsec,
1657 : : struct rte_swx_ipsec_sa_params *p,
1658 : : struct rte_ipsec_session *s)
1659 : : {
1660 : : struct rte_ipv4_hdr ipv4_hdr;
1661 : : struct rte_ipv6_hdr ipv6_hdr;
1662 : : struct rte_crypto_sym_xform crypto_xform[2];
1663 : : struct rte_ipsec_sa_prm sa_prm;
1664 : : struct rte_ipsec_sa *sa = NULL;
1665 : : struct rte_cryptodev_sym_session *crypto_session = NULL;
1666 : : int sa_size;
1667 : : int sa_valid = 0, status = 0;
1668 : :
1669 : 0 : tunnel_ipv4_header_set(&ipv4_hdr, p);
1670 : 0 : tunnel_ipv6_header_set(&ipv6_hdr, p);
1671 : :
1672 : : /* IPsec library SA setup. */
1673 : 0 : status = ipsec_sa_prm_get(p, &sa_prm, &ipv4_hdr, &ipv6_hdr, crypto_xform);
1674 [ # # ]: 0 : if (status)
1675 : 0 : goto error;
1676 : :
1677 : 0 : sa_size = rte_ipsec_sa_size(&sa_prm);
1678 [ # # ]: 0 : if (sa_size < 0) {
1679 : : status = sa_size;
1680 : 0 : goto error;
1681 : : }
1682 [ # # ]: 0 : if (!sa_size) {
1683 : : status = -EINVAL;
1684 : 0 : goto error;
1685 : : }
1686 : :
1687 : 0 : sa = calloc(1, sa_size);
1688 [ # # ]: 0 : if (!sa) {
1689 : : status = -ENOMEM;
1690 : 0 : goto error;
1691 : : }
1692 : :
1693 : 0 : sa_size = rte_ipsec_sa_init(sa, &sa_prm, sa_size);
1694 [ # # ]: 0 : if (sa_size < 0) {
1695 : : status = sa_size;
1696 : 0 : goto error;
1697 : : }
1698 [ # # ]: 0 : if (!sa_size) {
1699 : : status = -EINVAL;
1700 : 0 : goto error;
1701 : : }
1702 : :
1703 : : sa_valid = 1;
1704 : :
1705 : : /* Cryptodev library session setup. */
1706 : 0 : crypto_session = rte_cryptodev_sym_session_create(ipsec->dev_id,
1707 : : sa_prm.crypto_xform,
1708 : : ipsec->mp_session);
1709 [ # # ]: 0 : if (!crypto_session) {
1710 : : status = -ENOMEM;
1711 : 0 : goto error;
1712 : : }
1713 : :
1714 : : /* IPsec library session setup. */
1715 : 0 : s->sa = sa;
1716 : 0 : s->type = RTE_SECURITY_ACTION_TYPE_NONE;
1717 : 0 : s->crypto.ses = crypto_session;
1718 : 0 : s->crypto.dev_id = ipsec->dev_id;
1719 : 0 : s->pkt_func.prepare.async = NULL;
1720 : 0 : s->pkt_func.process = NULL;
1721 : :
1722 : 0 : status = rte_ipsec_session_prepare(s);
1723 [ # # ]: 0 : if (status)
1724 : 0 : goto error;
1725 : :
1726 : : return 0;
1727 : :
1728 : 0 : error:
1729 : : /* sa. */
1730 [ # # ]: 0 : if (sa_valid)
1731 : 0 : rte_ipsec_sa_fini(sa);
1732 : :
1733 : 0 : free(sa);
1734 : :
1735 : : /* crypto_session. */
1736 [ # # ]: 0 : if (crypto_session)
1737 : 0 : rte_cryptodev_sym_session_free(ipsec->dev_id, crypto_session);
1738 : :
1739 : : /* s. */
1740 : : memset(s, 0, sizeof(*s));
1741 : :
1742 : 0 : return status;
1743 : : }
1744 : :
1745 : : static void
1746 : 0 : ipsec_session_free(struct rte_swx_ipsec *ipsec,
1747 : : struct rte_ipsec_session *s)
1748 : : {
1749 [ # # ]: 0 : if (!s)
1750 : : return;
1751 : :
1752 : : /* IPsec library SA. */
1753 [ # # ]: 0 : if (s->sa)
1754 : 0 : rte_ipsec_sa_fini(s->sa);
1755 : 0 : free(s->sa);
1756 : :
1757 : : /* Cryptodev library session. */
1758 [ # # ]: 0 : if (s->crypto.ses)
1759 : 0 : rte_cryptodev_sym_session_free(ipsec->dev_id, s->crypto.ses);
1760 : :
1761 : : /* IPsec library session. */
1762 : : memset(s, 0, sizeof(*s));
1763 : : }
1764 : :
1765 : : int
1766 : 0 : rte_swx_ipsec_sa_add(struct rte_swx_ipsec *ipsec,
1767 : : struct rte_swx_ipsec_sa_params *sa_params,
1768 : : uint32_t *id)
1769 : : {
1770 : : struct ipsec_sa *sa;
1771 : : uint32_t sa_id;
1772 : : int status;
1773 : :
1774 : : /* Check the input parameters. */
1775 [ # # # # ]: 0 : if (!ipsec || !sa_params || !id)
1776 : : return -EINVAL;
1777 : :
1778 : : /* Allocate a free SADB entry. */
1779 [ # # ]: 0 : if (!ipsec->n_sa_free_id)
1780 : : return -ENOSPC;
1781 : :
1782 : 0 : sa_id = ipsec->sa_free_id[ipsec->n_sa_free_id - 1];
1783 : 0 : ipsec->n_sa_free_id--;
1784 : :
1785 : : /* Acquire the SA resources. */
1786 : : sa = ipsec_sa_get(ipsec, sa_id);
1787 : :
1788 : 0 : status = ipsec_session_create(ipsec, sa_params, &sa->s);
1789 [ # # ]: 0 : if (status) {
1790 : : /* Free the allocated SADB entry. */
1791 : 0 : ipsec->sa_free_id[ipsec->n_sa_free_id] = sa_id;
1792 : 0 : ipsec->n_sa_free_id++;
1793 : :
1794 : 0 : return status;
1795 : : }
1796 : :
1797 : : /* Validate the new SA. */
1798 : 0 : sa->valid = 1;
1799 : 0 : *id = sa_id;
1800 : :
1801 : 0 : return 0;
1802 : : }
1803 : :
1804 : : void
1805 : 0 : rte_swx_ipsec_sa_delete(struct rte_swx_ipsec *ipsec,
1806 : : uint32_t sa_id)
1807 : : {
1808 : : struct ipsec_sa *sa;
1809 : :
1810 : : /* Check the input parameters. */
1811 [ # # # # ]: 0 : if (!ipsec || (sa_id >= ipsec->n_sa_max))
1812 : : return;
1813 : :
1814 : : /* Release the SA resources. */
1815 : : sa = ipsec_sa_get(ipsec, sa_id);
1816 : :
1817 : 0 : ipsec_session_free(ipsec, &sa->s);
1818 : :
1819 : : /* Free the SADB entry. */
1820 : 0 : ipsec->sa_free_id[ipsec->n_sa_free_id] = sa_id;
1821 : 0 : ipsec->n_sa_free_id++;
1822 : :
1823 : : /* Invalidate the SA. */
1824 : 0 : sa->valid = 0;
1825 : : }
|