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