xref: /dpdk/lib/pipeline/rte_swx_ipsec.c (revision 2ede1422fa57225b0864702083a8c7bea2c5117e)
120777eb5SCristian Dumitrescu /* SPDX-License-Identifier: BSD-3-Clause
220777eb5SCristian Dumitrescu  * Copyright(c) 2022 Intel Corporation
320777eb5SCristian Dumitrescu  */
4e9fd1ebfSTyler Retzlaff 
5e9fd1ebfSTyler Retzlaff #include <stdalign.h>
620777eb5SCristian Dumitrescu #include <stdlib.h>
720777eb5SCristian Dumitrescu #include <stdio.h>
820777eb5SCristian Dumitrescu #include <errno.h>
920777eb5SCristian Dumitrescu #include <arpa/inet.h>
1020777eb5SCristian Dumitrescu 
1120777eb5SCristian Dumitrescu #include <rte_common.h>
12015f535fSStephen Hemminger #include <rte_random.h>
1320777eb5SCristian Dumitrescu #include <rte_ip.h>
1420777eb5SCristian Dumitrescu #include <rte_tailq.h>
1520777eb5SCristian Dumitrescu #include <rte_eal_memconfig.h>
1620777eb5SCristian Dumitrescu #include <rte_ring.h>
1720777eb5SCristian Dumitrescu #include <rte_mbuf.h>
1820777eb5SCristian Dumitrescu #include <rte_cryptodev.h>
1920777eb5SCristian Dumitrescu #include <rte_ipsec.h>
2020777eb5SCristian Dumitrescu 
2120777eb5SCristian Dumitrescu #include "rte_swx_ipsec.h"
2220777eb5SCristian Dumitrescu 
2320777eb5SCristian Dumitrescu #ifndef RTE_SWX_IPSEC_HUGE_PAGES_DISABLE
2420777eb5SCristian Dumitrescu 
2520777eb5SCristian Dumitrescu #include <rte_malloc.h>
2620777eb5SCristian Dumitrescu 
2720777eb5SCristian Dumitrescu static void *
2820777eb5SCristian Dumitrescu env_calloc(size_t size, size_t alignment, int numa_node)
2920777eb5SCristian Dumitrescu {
3020777eb5SCristian Dumitrescu 	return rte_zmalloc_socket(NULL, size, alignment, numa_node);
3120777eb5SCristian Dumitrescu }
3220777eb5SCristian Dumitrescu 
3320777eb5SCristian Dumitrescu static void
3420777eb5SCristian Dumitrescu env_free(void *start, size_t size __rte_unused)
3520777eb5SCristian Dumitrescu {
3620777eb5SCristian Dumitrescu 	rte_free(start);
3720777eb5SCristian Dumitrescu }
3820777eb5SCristian Dumitrescu 
3920777eb5SCristian Dumitrescu #else
4020777eb5SCristian Dumitrescu 
4120777eb5SCristian Dumitrescu #include <numa.h>
4220777eb5SCristian Dumitrescu 
4320777eb5SCristian Dumitrescu static void *
4420777eb5SCristian Dumitrescu env_calloc(size_t size, size_t alignment __rte_unused, int numa_node)
4520777eb5SCristian Dumitrescu {
4620777eb5SCristian Dumitrescu 	void *start;
4720777eb5SCristian Dumitrescu 
4820777eb5SCristian Dumitrescu 	if (numa_available() == -1)
4920777eb5SCristian Dumitrescu 		return NULL;
5020777eb5SCristian Dumitrescu 
5120777eb5SCristian Dumitrescu 	start = numa_alloc_onnode(size, numa_node);
5220777eb5SCristian Dumitrescu 	if (!start)
5320777eb5SCristian Dumitrescu 		return NULL;
5420777eb5SCristian Dumitrescu 
5520777eb5SCristian Dumitrescu 	memset(start, 0, size);
5620777eb5SCristian Dumitrescu 	return start;
5720777eb5SCristian Dumitrescu }
5820777eb5SCristian Dumitrescu 
5920777eb5SCristian Dumitrescu static void
6020777eb5SCristian Dumitrescu env_free(void *start, size_t size)
6120777eb5SCristian Dumitrescu {
6220777eb5SCristian Dumitrescu 	if ((numa_available() == -1) || !start)
6320777eb5SCristian Dumitrescu 		return;
6420777eb5SCristian Dumitrescu 
6520777eb5SCristian Dumitrescu 	numa_free(start, size);
6620777eb5SCristian Dumitrescu }
6720777eb5SCristian Dumitrescu 
6820777eb5SCristian Dumitrescu #endif
6920777eb5SCristian Dumitrescu 
7020777eb5SCristian Dumitrescu #ifndef RTE_SWX_IPSEC_POOL_CACHE_SIZE
7120777eb5SCristian Dumitrescu #define RTE_SWX_IPSEC_POOL_CACHE_SIZE 256
7220777eb5SCristian Dumitrescu #endif
7320777eb5SCristian Dumitrescu 
7420777eb5SCristian Dumitrescu /* The two crypto device mempools have their size set to the number of SAs. The mempool API requires
7520777eb5SCristian Dumitrescu  * the mempool size to be at least 1.5 times the size of the mempool cache.
7620777eb5SCristian Dumitrescu  */
7720777eb5SCristian Dumitrescu #define N_SA_MIN (RTE_SWX_IPSEC_POOL_CACHE_SIZE * 1.5)
7820777eb5SCristian Dumitrescu 
7920777eb5SCristian Dumitrescu struct ipsec_sa {
8020777eb5SCristian Dumitrescu 	struct rte_ipsec_session s;
8120777eb5SCristian Dumitrescu 	int valid;
8220777eb5SCristian Dumitrescu };
8320777eb5SCristian Dumitrescu 
8420777eb5SCristian Dumitrescu struct ipsec_pkts_in {
8520777eb5SCristian Dumitrescu 	struct rte_mbuf *pkts[RTE_SWX_IPSEC_BURST_SIZE_MAX];
8620777eb5SCristian Dumitrescu 	struct ipsec_sa *sa[RTE_SWX_IPSEC_BURST_SIZE_MAX];
8720777eb5SCristian Dumitrescu 	struct rte_ipsec_group groups[RTE_SWX_IPSEC_BURST_SIZE_MAX];
8820777eb5SCristian Dumitrescu 	struct rte_crypto_op *group_cops[RTE_SWX_IPSEC_BURST_SIZE_MAX];
8920777eb5SCristian Dumitrescu 	struct rte_crypto_op *cops[RTE_SWX_IPSEC_BURST_SIZE_MAX];
9020777eb5SCristian Dumitrescu 	uint32_t n_cops;
9120777eb5SCristian Dumitrescu };
9220777eb5SCristian Dumitrescu 
9320777eb5SCristian Dumitrescu struct ipsec_pkts_out {
9420777eb5SCristian Dumitrescu 	struct rte_crypto_op *cops[RTE_SWX_IPSEC_BURST_SIZE_MAX];
9520777eb5SCristian Dumitrescu 	struct rte_mbuf *group_pkts[RTE_SWX_IPSEC_BURST_SIZE_MAX];
9620777eb5SCristian Dumitrescu 	struct rte_ipsec_group groups[RTE_SWX_IPSEC_BURST_SIZE_MAX];
9720777eb5SCristian Dumitrescu 	struct rte_mbuf *pkts[RTE_SWX_IPSEC_BURST_SIZE_MAX];
9820777eb5SCristian Dumitrescu 	uint32_t n_pkts;
9920777eb5SCristian Dumitrescu };
10020777eb5SCristian Dumitrescu 
10120777eb5SCristian Dumitrescu struct rte_swx_ipsec {
10220777eb5SCristian Dumitrescu 	/*
10320777eb5SCristian Dumitrescu 	 * Parameters.
10420777eb5SCristian Dumitrescu 	 */
10520777eb5SCristian Dumitrescu 
10620777eb5SCristian Dumitrescu 	/* IPsec instance name. */
10720777eb5SCristian Dumitrescu 	char name[RTE_SWX_IPSEC_NAME_SIZE];
10820777eb5SCristian Dumitrescu 
10920777eb5SCristian Dumitrescu 	/* Input packet queue. */
11020777eb5SCristian Dumitrescu 	struct rte_ring *ring_in;
11120777eb5SCristian Dumitrescu 
11220777eb5SCristian Dumitrescu 	/* Output packet queue. */
11320777eb5SCristian Dumitrescu 	struct rte_ring *ring_out;
11420777eb5SCristian Dumitrescu 
11520777eb5SCristian Dumitrescu 	/* Crypto device ID. */
11620777eb5SCristian Dumitrescu 	uint8_t dev_id;
11720777eb5SCristian Dumitrescu 
11820777eb5SCristian Dumitrescu 	/* Crypto device queue pair ID. */
11920777eb5SCristian Dumitrescu 	uint16_t qp_id;
12020777eb5SCristian Dumitrescu 
12120777eb5SCristian Dumitrescu 	/* Burst sizes. */
12220777eb5SCristian Dumitrescu 	struct rte_swx_ipsec_burst_size bsz;
12320777eb5SCristian Dumitrescu 
12420777eb5SCristian Dumitrescu 	/* SA table size. */
12520777eb5SCristian Dumitrescu 	size_t n_sa_max;
12620777eb5SCristian Dumitrescu 
12720777eb5SCristian Dumitrescu 	/*
12820777eb5SCristian Dumitrescu 	 * Internals.
12920777eb5SCristian Dumitrescu 	 */
13020777eb5SCristian Dumitrescu 	/* Crypto device buffer pool for sessions. */
13120777eb5SCristian Dumitrescu 	struct rte_mempool *mp_session;
13220777eb5SCristian Dumitrescu 
13320777eb5SCristian Dumitrescu 	/* Pre-crypto packets. */
13420777eb5SCristian Dumitrescu 	struct ipsec_pkts_in in;
13520777eb5SCristian Dumitrescu 
13620777eb5SCristian Dumitrescu 	/* Post-crypto packets. */
13720777eb5SCristian Dumitrescu 	struct ipsec_pkts_out out;
13820777eb5SCristian Dumitrescu 
13920777eb5SCristian Dumitrescu 	/* Crypto device enqueue threshold. */
14020777eb5SCristian Dumitrescu 	uint32_t crypto_wr_threshold;
14120777eb5SCristian Dumitrescu 
14220777eb5SCristian Dumitrescu 	/* Packets currently under crypto device processing. */
14320777eb5SCristian Dumitrescu 	uint32_t n_pkts_crypto;
14420777eb5SCristian Dumitrescu 
14520777eb5SCristian Dumitrescu 	/* List of free SADB positions. */
14620777eb5SCristian Dumitrescu 	uint32_t *sa_free_id;
14720777eb5SCristian Dumitrescu 
14820777eb5SCristian Dumitrescu 	/* Number of elements in the SADB list of free positions. */
14920777eb5SCristian Dumitrescu 	size_t n_sa_free_id;
15020777eb5SCristian Dumitrescu 
15120777eb5SCristian Dumitrescu 	/* Allocated memory total size in bytes. */
15220777eb5SCristian Dumitrescu 	size_t total_size;
15320777eb5SCristian Dumitrescu 
15420777eb5SCristian Dumitrescu 	/* Flag for registration to the global list of instances. */
15520777eb5SCristian Dumitrescu 	int registered;
15620777eb5SCristian Dumitrescu 
15720777eb5SCristian Dumitrescu 	/*
15820777eb5SCristian Dumitrescu 	 * Table memory.
15920777eb5SCristian Dumitrescu 	 */
160e9fd1ebfSTyler Retzlaff 	alignas(RTE_CACHE_LINE_SIZE) uint8_t memory[];
16120777eb5SCristian Dumitrescu };
16220777eb5SCristian Dumitrescu 
16320777eb5SCristian Dumitrescu static inline struct ipsec_sa *
16420777eb5SCristian Dumitrescu ipsec_sa_get(struct rte_swx_ipsec *ipsec, uint32_t sa_id)
16520777eb5SCristian Dumitrescu {
16620777eb5SCristian Dumitrescu 	struct ipsec_sa *sadb = (struct ipsec_sa *)ipsec->memory;
16720777eb5SCristian Dumitrescu 
16820777eb5SCristian Dumitrescu 	return &sadb[sa_id & (ipsec->n_sa_max - 1)];
16920777eb5SCristian Dumitrescu }
17020777eb5SCristian Dumitrescu 
17120777eb5SCristian Dumitrescu /* Global list of instances. */
17220777eb5SCristian Dumitrescu TAILQ_HEAD(rte_swx_ipsec_list, rte_tailq_entry);
17320777eb5SCristian Dumitrescu 
17420777eb5SCristian Dumitrescu static struct rte_tailq_elem rte_swx_ipsec_tailq = {
17520777eb5SCristian Dumitrescu 	.name = "RTE_SWX_IPSEC",
17620777eb5SCristian Dumitrescu };
17720777eb5SCristian Dumitrescu 
17820777eb5SCristian Dumitrescu EAL_REGISTER_TAILQ(rte_swx_ipsec_tailq)
17920777eb5SCristian Dumitrescu 
18020777eb5SCristian Dumitrescu struct rte_swx_ipsec *
18120777eb5SCristian Dumitrescu rte_swx_ipsec_find(const char *name)
18220777eb5SCristian Dumitrescu {
18320777eb5SCristian Dumitrescu 	struct rte_swx_ipsec_list *ipsec_list;
18420777eb5SCristian Dumitrescu 	struct rte_tailq_entry *te = NULL;
18520777eb5SCristian Dumitrescu 
18620777eb5SCristian Dumitrescu 	if (!name ||
18720777eb5SCristian Dumitrescu 	    !name[0] ||
18820777eb5SCristian Dumitrescu 	    (strnlen(name, RTE_SWX_IPSEC_NAME_SIZE) == RTE_SWX_IPSEC_NAME_SIZE))
18920777eb5SCristian Dumitrescu 		return NULL;
19020777eb5SCristian Dumitrescu 
19120777eb5SCristian Dumitrescu 	ipsec_list = RTE_TAILQ_CAST(rte_swx_ipsec_tailq.head, rte_swx_ipsec_list);
19220777eb5SCristian Dumitrescu 
19320777eb5SCristian Dumitrescu 	rte_mcfg_tailq_read_lock();
19420777eb5SCristian Dumitrescu 
19520777eb5SCristian Dumitrescu 	TAILQ_FOREACH(te, ipsec_list, next) {
19620777eb5SCristian Dumitrescu 		struct rte_swx_ipsec *ipsec = (struct rte_swx_ipsec *)te->data;
19720777eb5SCristian Dumitrescu 
19820777eb5SCristian Dumitrescu 		if (!strncmp(name, ipsec->name, sizeof(ipsec->name))) {
19920777eb5SCristian Dumitrescu 			rte_mcfg_tailq_read_unlock();
20020777eb5SCristian Dumitrescu 			return ipsec;
20120777eb5SCristian Dumitrescu 		}
20220777eb5SCristian Dumitrescu 	}
20320777eb5SCristian Dumitrescu 
20420777eb5SCristian Dumitrescu 	rte_mcfg_tailq_read_unlock();
20520777eb5SCristian Dumitrescu 	return NULL;
20620777eb5SCristian Dumitrescu }
20720777eb5SCristian Dumitrescu 
20820777eb5SCristian Dumitrescu static int
20920777eb5SCristian Dumitrescu ipsec_register(struct rte_swx_ipsec *ipsec)
21020777eb5SCristian Dumitrescu {
21120777eb5SCristian Dumitrescu 	struct rte_swx_ipsec_list *ipsec_list;
21220777eb5SCristian Dumitrescu 	struct rte_tailq_entry *te = NULL;
21320777eb5SCristian Dumitrescu 
21420777eb5SCristian Dumitrescu 	ipsec_list = RTE_TAILQ_CAST(rte_swx_ipsec_tailq.head, rte_swx_ipsec_list);
21520777eb5SCristian Dumitrescu 
21620777eb5SCristian Dumitrescu 	rte_mcfg_tailq_write_lock();
21720777eb5SCristian Dumitrescu 
21820777eb5SCristian Dumitrescu 	TAILQ_FOREACH(te, ipsec_list, next) {
21920777eb5SCristian Dumitrescu 		struct rte_swx_ipsec *elem = (struct rte_swx_ipsec *)te->data;
22020777eb5SCristian Dumitrescu 
22120777eb5SCristian Dumitrescu 		if (!strncmp(ipsec->name, elem->name, sizeof(ipsec->name))) {
22220777eb5SCristian Dumitrescu 			rte_mcfg_tailq_write_unlock();
22320777eb5SCristian Dumitrescu 			return -EEXIST;
22420777eb5SCristian Dumitrescu 		}
22520777eb5SCristian Dumitrescu 	}
22620777eb5SCristian Dumitrescu 
22720777eb5SCristian Dumitrescu 	te = calloc(1, sizeof(struct rte_tailq_entry));
22820777eb5SCristian Dumitrescu 	if (!te) {
22920777eb5SCristian Dumitrescu 		rte_mcfg_tailq_write_unlock();
23020777eb5SCristian Dumitrescu 		return -ENOMEM;
23120777eb5SCristian Dumitrescu 	}
23220777eb5SCristian Dumitrescu 
23320777eb5SCristian Dumitrescu 	te->data = (void *)ipsec;
23420777eb5SCristian Dumitrescu 	TAILQ_INSERT_TAIL(ipsec_list, te, next);
23520777eb5SCristian Dumitrescu 	rte_mcfg_tailq_write_unlock();
23620777eb5SCristian Dumitrescu 	return 0;
23720777eb5SCristian Dumitrescu }
23820777eb5SCristian Dumitrescu 
23920777eb5SCristian Dumitrescu static void
24020777eb5SCristian Dumitrescu ipsec_unregister(struct rte_swx_ipsec *ipsec)
24120777eb5SCristian Dumitrescu {
24220777eb5SCristian Dumitrescu 	struct rte_swx_ipsec_list *ipsec_list;
24320777eb5SCristian Dumitrescu 	struct rte_tailq_entry *te = NULL;
24420777eb5SCristian Dumitrescu 
24520777eb5SCristian Dumitrescu 	ipsec_list = RTE_TAILQ_CAST(rte_swx_ipsec_tailq.head, rte_swx_ipsec_list);
24620777eb5SCristian Dumitrescu 
24720777eb5SCristian Dumitrescu 	rte_mcfg_tailq_write_lock();
24820777eb5SCristian Dumitrescu 
24920777eb5SCristian Dumitrescu 	TAILQ_FOREACH(te, ipsec_list, next) {
25020777eb5SCristian Dumitrescu 		if (te->data == (void *)ipsec) {
25120777eb5SCristian Dumitrescu 			TAILQ_REMOVE(ipsec_list, te, next);
25220777eb5SCristian Dumitrescu 			rte_mcfg_tailq_write_unlock();
25320777eb5SCristian Dumitrescu 			free(te);
25420777eb5SCristian Dumitrescu 			return;
25520777eb5SCristian Dumitrescu 		}
25620777eb5SCristian Dumitrescu 	}
25720777eb5SCristian Dumitrescu 
25820777eb5SCristian Dumitrescu 	rte_mcfg_tailq_write_unlock();
25920777eb5SCristian Dumitrescu }
26020777eb5SCristian Dumitrescu 
26120777eb5SCristian Dumitrescu static void
26220777eb5SCristian Dumitrescu ipsec_session_free(struct rte_swx_ipsec *ipsec, struct rte_ipsec_session *s);
26320777eb5SCristian Dumitrescu 
26420777eb5SCristian Dumitrescu void
26520777eb5SCristian Dumitrescu rte_swx_ipsec_free(struct rte_swx_ipsec *ipsec)
26620777eb5SCristian Dumitrescu {
26720777eb5SCristian Dumitrescu 	size_t i;
26820777eb5SCristian Dumitrescu 
26920777eb5SCristian Dumitrescu 	if (!ipsec)
27020777eb5SCristian Dumitrescu 		return;
27120777eb5SCristian Dumitrescu 
27220777eb5SCristian Dumitrescu 	/* Remove the current instance from the global list. */
27320777eb5SCristian Dumitrescu 	if (ipsec->registered)
27420777eb5SCristian Dumitrescu 		ipsec_unregister(ipsec);
27520777eb5SCristian Dumitrescu 
27620777eb5SCristian Dumitrescu 	/* SADB. */
27720777eb5SCristian Dumitrescu 	for (i = 0; i < ipsec->n_sa_max; i++) {
27820777eb5SCristian Dumitrescu 		struct ipsec_sa *sa = ipsec_sa_get(ipsec, i);
27920777eb5SCristian Dumitrescu 
28020777eb5SCristian Dumitrescu 		if (!sa->valid)
28120777eb5SCristian Dumitrescu 			continue;
28220777eb5SCristian Dumitrescu 
28320777eb5SCristian Dumitrescu 		/* SA session. */
28420777eb5SCristian Dumitrescu 		ipsec_session_free(ipsec, &sa->s);
28520777eb5SCristian Dumitrescu 	}
28620777eb5SCristian Dumitrescu 
28720777eb5SCristian Dumitrescu 	/* Crypto device buffer pools. */
28820777eb5SCristian Dumitrescu 	rte_mempool_free(ipsec->mp_session);
28920777eb5SCristian Dumitrescu 
29020777eb5SCristian Dumitrescu 	/* IPsec object memory. */
29120777eb5SCristian Dumitrescu 	env_free(ipsec, ipsec->total_size);
29220777eb5SCristian Dumitrescu }
29320777eb5SCristian Dumitrescu 
29420777eb5SCristian Dumitrescu int
29520777eb5SCristian Dumitrescu rte_swx_ipsec_create(struct rte_swx_ipsec **ipsec_out,
29620777eb5SCristian Dumitrescu 		     const char *name,
29720777eb5SCristian Dumitrescu 		     struct rte_swx_ipsec_params *params,
29820777eb5SCristian Dumitrescu 		     int numa_node)
29920777eb5SCristian Dumitrescu {
30020777eb5SCristian Dumitrescu 	char resource_name[RTE_SWX_IPSEC_NAME_SIZE];
30120777eb5SCristian Dumitrescu 	struct rte_swx_ipsec *ipsec = NULL;
30220777eb5SCristian Dumitrescu 	struct rte_ring *ring_in, *ring_out;
30320777eb5SCristian Dumitrescu 	struct rte_cryptodev_info dev_info;
30420777eb5SCristian Dumitrescu 	size_t n_sa_max, sadb_offset, sadb_size, sa_free_id_offset, sa_free_id_size, total_size, i;
30520777eb5SCristian Dumitrescu 	uint32_t dev_session_size;
30620777eb5SCristian Dumitrescu 	int dev_id, status = 0;
30720777eb5SCristian Dumitrescu 
30820777eb5SCristian Dumitrescu 	/* Check input parameters. */
30920777eb5SCristian Dumitrescu 	if (!ipsec_out ||
31020777eb5SCristian Dumitrescu 	    !name ||
31120777eb5SCristian Dumitrescu 	    !name[0] ||
31220777eb5SCristian Dumitrescu 	    (strnlen((name), RTE_SWX_IPSEC_NAME_SIZE) == RTE_SWX_IPSEC_NAME_SIZE) ||
31320777eb5SCristian Dumitrescu 	    !params ||
31420777eb5SCristian Dumitrescu 	    (params->bsz.ring_rd > RTE_SWX_IPSEC_BURST_SIZE_MAX) ||
31520777eb5SCristian Dumitrescu 	    (params->bsz.ring_wr > RTE_SWX_IPSEC_BURST_SIZE_MAX) ||
31620777eb5SCristian Dumitrescu 	    (params->bsz.crypto_wr > RTE_SWX_IPSEC_BURST_SIZE_MAX) ||
31720777eb5SCristian Dumitrescu 	    (params->bsz.crypto_rd > RTE_SWX_IPSEC_BURST_SIZE_MAX) ||
31820777eb5SCristian Dumitrescu 	    !params->n_sa_max) {
31920777eb5SCristian Dumitrescu 		status = -EINVAL;
32020777eb5SCristian Dumitrescu 		goto error;
32120777eb5SCristian Dumitrescu 	}
32220777eb5SCristian Dumitrescu 
32320777eb5SCristian Dumitrescu 	ring_in = rte_ring_lookup(params->ring_in_name);
32420777eb5SCristian Dumitrescu 	if (!ring_in) {
32520777eb5SCristian Dumitrescu 		status = -EINVAL;
32620777eb5SCristian Dumitrescu 		goto error;
32720777eb5SCristian Dumitrescu 	}
32820777eb5SCristian Dumitrescu 
32920777eb5SCristian Dumitrescu 	ring_out = rte_ring_lookup(params->ring_out_name);
33020777eb5SCristian Dumitrescu 	if (!ring_out) {
33120777eb5SCristian Dumitrescu 		status = -EINVAL;
33220777eb5SCristian Dumitrescu 		goto error;
33320777eb5SCristian Dumitrescu 	}
33420777eb5SCristian Dumitrescu 
33520777eb5SCristian Dumitrescu 	dev_id = rte_cryptodev_get_dev_id(params->crypto_dev_name);
33620777eb5SCristian Dumitrescu 	if (dev_id == -1) {
33720777eb5SCristian Dumitrescu 		status = -EINVAL;
33820777eb5SCristian Dumitrescu 		goto error;
33920777eb5SCristian Dumitrescu 	}
34020777eb5SCristian Dumitrescu 
34120777eb5SCristian Dumitrescu 	rte_cryptodev_info_get(dev_id, &dev_info);
34220777eb5SCristian Dumitrescu 	if (params->crypto_dev_queue_pair_id >= dev_info.max_nb_queue_pairs) {
34320777eb5SCristian Dumitrescu 		status = -EINVAL;
34420777eb5SCristian Dumitrescu 		goto error;
34520777eb5SCristian Dumitrescu 	}
34620777eb5SCristian Dumitrescu 
34720777eb5SCristian Dumitrescu 	/* Memory allocation. */
34820777eb5SCristian Dumitrescu 	n_sa_max = rte_align64pow2(RTE_MAX(params->n_sa_max, N_SA_MIN));
34920777eb5SCristian Dumitrescu 
35020777eb5SCristian Dumitrescu 	sadb_offset = sizeof(struct rte_swx_ipsec);
35120777eb5SCristian Dumitrescu 	sadb_size = RTE_CACHE_LINE_ROUNDUP(n_sa_max * sizeof(struct ipsec_sa));
35220777eb5SCristian Dumitrescu 
35320777eb5SCristian Dumitrescu 	sa_free_id_offset = sadb_offset + sadb_size;
35420777eb5SCristian Dumitrescu 	sa_free_id_size = RTE_CACHE_LINE_ROUNDUP(n_sa_max * sizeof(uint32_t));
35520777eb5SCristian Dumitrescu 
35620777eb5SCristian Dumitrescu 	total_size = sa_free_id_offset + sa_free_id_size;
35720777eb5SCristian Dumitrescu 	ipsec = env_calloc(total_size, RTE_CACHE_LINE_SIZE, numa_node);
35820777eb5SCristian Dumitrescu 	if (!ipsec) {
35920777eb5SCristian Dumitrescu 		status = -ENOMEM;
36020777eb5SCristian Dumitrescu 		goto error;
36120777eb5SCristian Dumitrescu 	}
36220777eb5SCristian Dumitrescu 
36320777eb5SCristian Dumitrescu 	/* Initialization. */
36420777eb5SCristian Dumitrescu 	strcpy(ipsec->name, name);
36520777eb5SCristian Dumitrescu 	ipsec->ring_in = ring_in;
36620777eb5SCristian Dumitrescu 	ipsec->ring_out = ring_out;
36720777eb5SCristian Dumitrescu 	ipsec->dev_id = (uint8_t)dev_id;
36820777eb5SCristian Dumitrescu 	ipsec->qp_id = params->crypto_dev_queue_pair_id;
36920777eb5SCristian Dumitrescu 	memcpy(&ipsec->bsz, &params->bsz, sizeof(struct rte_swx_ipsec_burst_size));
37020777eb5SCristian Dumitrescu 	ipsec->n_sa_max = n_sa_max;
37120777eb5SCristian Dumitrescu 
37220777eb5SCristian Dumitrescu 	ipsec->crypto_wr_threshold = params->bsz.crypto_wr * 3 / 4;
37320777eb5SCristian Dumitrescu 
37420777eb5SCristian Dumitrescu 	ipsec->sa_free_id = (uint32_t *)&ipsec->memory[sa_free_id_offset];
37520777eb5SCristian Dumitrescu 	for (i = 0; i < n_sa_max; i++)
37620777eb5SCristian Dumitrescu 		ipsec->sa_free_id[i] = n_sa_max - 1 - i;
37720777eb5SCristian Dumitrescu 	ipsec->n_sa_free_id = n_sa_max;
37820777eb5SCristian Dumitrescu 
37920777eb5SCristian Dumitrescu 	ipsec->total_size = total_size;
38020777eb5SCristian Dumitrescu 
38120777eb5SCristian Dumitrescu 	/* Crypto device memory pools. */
38220777eb5SCristian Dumitrescu 	dev_session_size = rte_cryptodev_sym_get_private_session_size((uint8_t)dev_id);
38320777eb5SCristian Dumitrescu 
38420777eb5SCristian Dumitrescu 	snprintf(resource_name, sizeof(resource_name), "%s_mp", name);
38520777eb5SCristian Dumitrescu 	ipsec->mp_session = rte_cryptodev_sym_session_pool_create(resource_name,
38620777eb5SCristian Dumitrescu 		n_sa_max, /* number of pool elements */
38720777eb5SCristian Dumitrescu 		dev_session_size, /* pool element size */
38820777eb5SCristian Dumitrescu 		RTE_SWX_IPSEC_POOL_CACHE_SIZE, /* pool cache size */
38920777eb5SCristian Dumitrescu 		0, /* pool element private data size */
39020777eb5SCristian Dumitrescu 		numa_node);
39120777eb5SCristian Dumitrescu 	if (!ipsec->mp_session) {
39220777eb5SCristian Dumitrescu 		status = -ENOMEM;
39320777eb5SCristian Dumitrescu 		goto error;
39420777eb5SCristian Dumitrescu 	}
39520777eb5SCristian Dumitrescu 
39620777eb5SCristian Dumitrescu 	/* Add the current instance to the global list. */
39720777eb5SCristian Dumitrescu 	status = ipsec_register(ipsec);
39820777eb5SCristian Dumitrescu 	if (status)
39920777eb5SCristian Dumitrescu 		goto error;
40020777eb5SCristian Dumitrescu 
40120777eb5SCristian Dumitrescu 	ipsec->registered = 1;
40220777eb5SCristian Dumitrescu 
40320777eb5SCristian Dumitrescu 	*ipsec_out = ipsec;
40420777eb5SCristian Dumitrescu 	return 0;
40520777eb5SCristian Dumitrescu 
40620777eb5SCristian Dumitrescu error:
40720777eb5SCristian Dumitrescu 	rte_swx_ipsec_free(ipsec);
40820777eb5SCristian Dumitrescu 	return status;
40920777eb5SCristian Dumitrescu }
41020777eb5SCristian Dumitrescu 
41120777eb5SCristian Dumitrescu static inline int
41220777eb5SCristian Dumitrescu ipsec_sa_group(struct rte_swx_ipsec *ipsec, int n_pkts)
41320777eb5SCristian Dumitrescu {
41420777eb5SCristian Dumitrescu 	struct ipsec_sa *sa;
41520777eb5SCristian Dumitrescu 	struct rte_ipsec_group *g;
41620777eb5SCristian Dumitrescu 	int n_groups, n_pkts_in_group, i;
41720777eb5SCristian Dumitrescu 
41820777eb5SCristian Dumitrescu 	sa = ipsec->in.sa[0];
41920777eb5SCristian Dumitrescu 
42020777eb5SCristian Dumitrescu 	g = &ipsec->in.groups[0];
42120777eb5SCristian Dumitrescu 	g->id.ptr = sa;
42220777eb5SCristian Dumitrescu 	g->m = &ipsec->in.pkts[0];
42320777eb5SCristian Dumitrescu 	n_pkts_in_group = 1;
42420777eb5SCristian Dumitrescu 	n_groups = 1;
42520777eb5SCristian Dumitrescu 
42620777eb5SCristian Dumitrescu 	for (i = 1; i < n_pkts; i++) {
42720777eb5SCristian Dumitrescu 		struct ipsec_sa *sa_new = ipsec->in.sa[i];
42820777eb5SCristian Dumitrescu 
42920777eb5SCristian Dumitrescu 		/* Same SA => Add the current pkt to the same group. */
43020777eb5SCristian Dumitrescu 		if (sa_new == sa) {
43120777eb5SCristian Dumitrescu 			n_pkts_in_group++;
43220777eb5SCristian Dumitrescu 			continue;
43320777eb5SCristian Dumitrescu 		}
43420777eb5SCristian Dumitrescu 
43520777eb5SCristian Dumitrescu 		/* Different SA => Close the current group & add the current pkt to a new group. */
43620777eb5SCristian Dumitrescu 		g->cnt = n_pkts_in_group;
43720777eb5SCristian Dumitrescu 		sa = sa_new;
43820777eb5SCristian Dumitrescu 
43920777eb5SCristian Dumitrescu 		g++;
44020777eb5SCristian Dumitrescu 		g->id.ptr = sa;
44120777eb5SCristian Dumitrescu 		g->m = &ipsec->in.pkts[i];
44220777eb5SCristian Dumitrescu 		n_pkts_in_group = 1;
44320777eb5SCristian Dumitrescu 		n_groups++;
44420777eb5SCristian Dumitrescu 	}
44520777eb5SCristian Dumitrescu 
44620777eb5SCristian Dumitrescu 	/* Close the last group. */
44720777eb5SCristian Dumitrescu 	g->cnt = n_pkts_in_group;
44820777eb5SCristian Dumitrescu 
44920777eb5SCristian Dumitrescu 	return n_groups;
45020777eb5SCristian Dumitrescu }
45120777eb5SCristian Dumitrescu 
45220777eb5SCristian Dumitrescu static inline void
45320777eb5SCristian Dumitrescu ipsec_crypto_enqueue(struct rte_swx_ipsec *ipsec, uint16_t n_cops)
45420777eb5SCristian Dumitrescu {
45520777eb5SCristian Dumitrescu 	struct rte_crypto_op **dst0 = ipsec->in.cops, **dst;
45620777eb5SCristian Dumitrescu 	struct rte_crypto_op **src = ipsec->in.group_cops;
45720777eb5SCristian Dumitrescu 
45820777eb5SCristian Dumitrescu 	uint32_t n_pkts_crypto = ipsec->n_pkts_crypto;
45920777eb5SCristian Dumitrescu 	uint32_t n_dst = ipsec->in.n_cops;
46020777eb5SCristian Dumitrescu 	uint32_t n_dst_max = ipsec->bsz.crypto_wr;
46120777eb5SCristian Dumitrescu 	uint32_t n_dst_avail = n_dst_max - n_dst;
46220777eb5SCristian Dumitrescu 	uint32_t n_src = n_cops;
46320777eb5SCristian Dumitrescu 	uint32_t i;
46420777eb5SCristian Dumitrescu 
46520777eb5SCristian Dumitrescu 	dst = &dst0[n_dst];
46620777eb5SCristian Dumitrescu 
46720777eb5SCristian Dumitrescu 	/* Shortcut: If no elements in DST and enough elements in SRC, then simply use SRC directly
46820777eb5SCristian Dumitrescu 	 * instead of moving the SRC to DST first and then using DST.
46920777eb5SCristian Dumitrescu 	 */
47020777eb5SCristian Dumitrescu 	if (!n_dst && n_src >= ipsec->crypto_wr_threshold) {
47120777eb5SCristian Dumitrescu 		uint16_t n_ok;
47220777eb5SCristian Dumitrescu 
47320777eb5SCristian Dumitrescu 		n_ok = rte_cryptodev_enqueue_burst(ipsec->dev_id, ipsec->qp_id, src, n_src);
47420777eb5SCristian Dumitrescu 		ipsec->n_pkts_crypto = n_pkts_crypto + n_ok;
47520777eb5SCristian Dumitrescu 
47620777eb5SCristian Dumitrescu 		for (i = n_ok; i < n_src; i++) {
47720777eb5SCristian Dumitrescu 			struct rte_crypto_op *cop = src[i];
47820777eb5SCristian Dumitrescu 			struct rte_mbuf *m = cop->sym->m_src;
47920777eb5SCristian Dumitrescu 
48020777eb5SCristian Dumitrescu 			rte_pktmbuf_free(m);
48120777eb5SCristian Dumitrescu 		}
48220777eb5SCristian Dumitrescu 
48320777eb5SCristian Dumitrescu 		return;
48420777eb5SCristian Dumitrescu 	}
48520777eb5SCristian Dumitrescu 
48620777eb5SCristian Dumitrescu 	/* Move from SRC to DST. Every time DST gets full, send burst from DST. */
48720777eb5SCristian Dumitrescu 	for ( ; n_src >= n_dst_avail; ) {
48820777eb5SCristian Dumitrescu 		uint32_t n_ok;
48920777eb5SCristian Dumitrescu 
49020777eb5SCristian Dumitrescu 		/* Move from SRC to DST. */
49120777eb5SCristian Dumitrescu 		for (i = 0; i < n_dst_avail; i++)
49220777eb5SCristian Dumitrescu 			*dst++ = *src++;
49320777eb5SCristian Dumitrescu 
49420777eb5SCristian Dumitrescu 		n_src -= n_dst_avail;
49520777eb5SCristian Dumitrescu 
49620777eb5SCristian Dumitrescu 		/* DST full: send burst from DST. */
49720777eb5SCristian Dumitrescu 		n_ok = rte_cryptodev_enqueue_burst(ipsec->dev_id, ipsec->qp_id, dst0, n_dst_max);
49820777eb5SCristian Dumitrescu 		n_pkts_crypto += n_ok;
49920777eb5SCristian Dumitrescu 
50020777eb5SCristian Dumitrescu 		for (i = n_ok ; i < n_dst_max; i++) {
50120777eb5SCristian Dumitrescu 			struct rte_crypto_op *cop = dst0[i];
50220777eb5SCristian Dumitrescu 			struct rte_mbuf *m = cop->sym->m_src;
50320777eb5SCristian Dumitrescu 
50420777eb5SCristian Dumitrescu 			rte_pktmbuf_free(m);
50520777eb5SCristian Dumitrescu 		}
50620777eb5SCristian Dumitrescu 
50720777eb5SCristian Dumitrescu 		/* Next iteration. */
50820777eb5SCristian Dumitrescu 		dst = dst0;
50920777eb5SCristian Dumitrescu 		n_dst = 0;
51020777eb5SCristian Dumitrescu 		n_dst_avail = n_dst_max;
51120777eb5SCristian Dumitrescu 	}
51220777eb5SCristian Dumitrescu 
51320777eb5SCristian Dumitrescu 	ipsec->n_pkts_crypto = n_pkts_crypto;
51420777eb5SCristian Dumitrescu 
51520777eb5SCristian Dumitrescu 	/* Move from SRC to DST. Not enough elements in SRC to get DST full. */
51620777eb5SCristian Dumitrescu 	for (i = 0; i < n_src; i++)
51720777eb5SCristian Dumitrescu 		*dst++ = *src++;
51820777eb5SCristian Dumitrescu 
51920777eb5SCristian Dumitrescu 	n_dst += n_src;
52020777eb5SCristian Dumitrescu 
52120777eb5SCristian Dumitrescu 	ipsec->in.n_cops = n_dst;
52220777eb5SCristian Dumitrescu }
52320777eb5SCristian Dumitrescu 
52420777eb5SCristian Dumitrescu /**
52520777eb5SCristian Dumitrescu  * Packet buffer anatomy:
52620777eb5SCristian Dumitrescu  *
52720777eb5SCristian Dumitrescu  * +----------+---------+--------------------------------------------------------------------------+
52820777eb5SCristian Dumitrescu  * | Offset   | Size    | Description                                                              |
52920777eb5SCristian Dumitrescu  * | (Byte #) | (Bytes) |                                                                          |
53020777eb5SCristian Dumitrescu  * +==========+=========+==========================================================================+
53120777eb5SCristian Dumitrescu  * | 0        | 128     | Meta-data: struct rte_mbuf.                                              |
53220777eb5SCristian Dumitrescu  * |          |         | The buf_addr field points to the start of the packet section.            |
53320777eb5SCristian Dumitrescu  * +----------+---------+--------------------------------------------------------------------------+
53420777eb5SCristian Dumitrescu  * | 128      | 128     | Meta-data: struct ipsec_mbuf (see below).                                |
53520777eb5SCristian Dumitrescu  * +----------+---------+--------------------------------------------------------------------------+
53620777eb5SCristian Dumitrescu  * | 256      |         | Packet section.                                                          |
53720777eb5SCristian Dumitrescu  * |          |         | The first packet byte is placed at the offset indicated by the struct    |
53820777eb5SCristian Dumitrescu  * |          |         | rte_mbuf::data_off field relative to the start of the packet section.    |
53920777eb5SCristian Dumitrescu  * +----------+---------+--------------------------------------------------------------------------+
54020777eb5SCristian Dumitrescu  */
54120777eb5SCristian Dumitrescu struct ipsec_mbuf {
54220777eb5SCristian Dumitrescu 	struct ipsec_sa *sa;
54320777eb5SCristian Dumitrescu 	struct rte_crypto_op cop;
54420777eb5SCristian Dumitrescu 	struct rte_crypto_sym_op sym_cop;
54520777eb5SCristian Dumitrescu 	uint8_t buffer[32]; /* The crypto IV is placed here. */
54620777eb5SCristian Dumitrescu };
54720777eb5SCristian Dumitrescu 
54820777eb5SCristian Dumitrescu /* Offset from the start of the struct ipsec_mbuf::cop where the crypto IV will be placed. */
54920777eb5SCristian Dumitrescu #define IV_OFFSET (sizeof(struct rte_crypto_op) + sizeof(struct rte_crypto_sym_op))
55020777eb5SCristian Dumitrescu 
55120777eb5SCristian Dumitrescu #define META_LENGTH sizeof(struct rte_swx_ipsec_input_packet_metadata)
55220777eb5SCristian Dumitrescu 
55320777eb5SCristian Dumitrescu static inline void
55420777eb5SCristian Dumitrescu rte_swx_ipsec_pre_crypto(struct rte_swx_ipsec *ipsec)
55520777eb5SCristian Dumitrescu {
55620777eb5SCristian Dumitrescu 	int n_pkts, n_groups, i;
55720777eb5SCristian Dumitrescu 
55820777eb5SCristian Dumitrescu 	/* Read packets from the input ring. */
55920777eb5SCristian Dumitrescu 	n_pkts = rte_ring_sc_dequeue_burst(ipsec->ring_in,
56020777eb5SCristian Dumitrescu 					   (void **)ipsec->in.pkts,
56120777eb5SCristian Dumitrescu 					   ipsec->bsz.ring_rd,
56220777eb5SCristian Dumitrescu 					   NULL);
56320777eb5SCristian Dumitrescu 	if (!n_pkts)
56420777eb5SCristian Dumitrescu 		return;
56520777eb5SCristian Dumitrescu 
56620777eb5SCristian Dumitrescu 	/* Get the SA for each packet. */
56720777eb5SCristian Dumitrescu 	for (i = 0; i < n_pkts; i++) {
56820777eb5SCristian Dumitrescu 		struct rte_mbuf *m = ipsec->in.pkts[i];
56920777eb5SCristian Dumitrescu 		struct rte_swx_ipsec_input_packet_metadata *meta;
57020777eb5SCristian Dumitrescu 		struct rte_ipv4_hdr *ipv4_hdr;
57120777eb5SCristian Dumitrescu 		uint32_t sa_id;
57220777eb5SCristian Dumitrescu 
57320777eb5SCristian Dumitrescu 		meta = rte_pktmbuf_mtod(m, struct rte_swx_ipsec_input_packet_metadata *);
57420777eb5SCristian Dumitrescu 		ipv4_hdr = rte_pktmbuf_mtod_offset(m, struct rte_ipv4_hdr *, META_LENGTH);
57520777eb5SCristian Dumitrescu 
57620777eb5SCristian Dumitrescu 		/* Read the SA ID from the IPsec meta-data placed at the front of the IP packet. */
57720777eb5SCristian Dumitrescu 		sa_id = ntohl(meta->sa_id);
57820777eb5SCristian Dumitrescu 
57920777eb5SCristian Dumitrescu 		/* Consume the IPsec meta-data. */
58020777eb5SCristian Dumitrescu 		m->data_off += META_LENGTH;
58120777eb5SCristian Dumitrescu 		m->data_len -= META_LENGTH;
58220777eb5SCristian Dumitrescu 		m->pkt_len -= META_LENGTH;
58320777eb5SCristian Dumitrescu 
58420777eb5SCristian Dumitrescu 		/* Set the fields required by the IPsec library. */
58520777eb5SCristian Dumitrescu 		m->l2_len = 0;
58620777eb5SCristian Dumitrescu 		m->l3_len = (ipv4_hdr->version_ihl >> 4 == 4) ?
58720777eb5SCristian Dumitrescu 			sizeof(struct rte_ipv4_hdr) :
58820777eb5SCristian Dumitrescu 			sizeof(struct rte_ipv6_hdr);
58920777eb5SCristian Dumitrescu 
59020777eb5SCristian Dumitrescu 		/* Get the SA. */
59120777eb5SCristian Dumitrescu 		ipsec->in.sa[i] = ipsec_sa_get(ipsec, sa_id);
59220777eb5SCristian Dumitrescu 	}
59320777eb5SCristian Dumitrescu 
59420777eb5SCristian Dumitrescu 	/* Group packets that share the same SA. */
59520777eb5SCristian Dumitrescu 	n_groups = ipsec_sa_group(ipsec, n_pkts);
59620777eb5SCristian Dumitrescu 
59720777eb5SCristian Dumitrescu 	/* Write each group of packets sharing the same SA to the crypto device. */
59820777eb5SCristian Dumitrescu 	for (i = 0; i < n_groups; i++) {
59920777eb5SCristian Dumitrescu 		struct rte_ipsec_group *g = &ipsec->in.groups[i];
60020777eb5SCristian Dumitrescu 		struct ipsec_sa *sa = g->id.ptr;
60120777eb5SCristian Dumitrescu 		struct rte_ipsec_session *s = &sa->s;
60220777eb5SCristian Dumitrescu 		uint32_t j;
60320777eb5SCristian Dumitrescu 		uint16_t n_pkts_ok;
60420777eb5SCristian Dumitrescu 
60520777eb5SCristian Dumitrescu 		/* Prepare the crypto ops for the current group. */
60620777eb5SCristian Dumitrescu 		for (j = 0; j < g->cnt; j++) {
60720777eb5SCristian Dumitrescu 			struct rte_mbuf *m = g->m[j];
60820777eb5SCristian Dumitrescu 			struct ipsec_mbuf *priv = rte_mbuf_to_priv(m);
60920777eb5SCristian Dumitrescu 
61020777eb5SCristian Dumitrescu 			priv->sa = sa;
61120777eb5SCristian Dumitrescu 			ipsec->in.group_cops[j] = &priv->cop;
61220777eb5SCristian Dumitrescu 		}
61320777eb5SCristian Dumitrescu 
61420777eb5SCristian Dumitrescu 		n_pkts_ok = rte_ipsec_pkt_crypto_prepare(s, g->m, ipsec->in.group_cops, g->cnt);
61520777eb5SCristian Dumitrescu 
61620777eb5SCristian Dumitrescu 		for (j = n_pkts_ok; j < g->cnt; j++) {
61720777eb5SCristian Dumitrescu 			struct rte_mbuf *m = g->m[j];
61820777eb5SCristian Dumitrescu 
61920777eb5SCristian Dumitrescu 			rte_pktmbuf_free(m);
62020777eb5SCristian Dumitrescu 		}
62120777eb5SCristian Dumitrescu 
62220777eb5SCristian Dumitrescu 		/* Write the crypto ops of the current group to the crypto device. */
62320777eb5SCristian Dumitrescu 		ipsec_crypto_enqueue(ipsec, n_pkts_ok);
62420777eb5SCristian Dumitrescu 	}
62520777eb5SCristian Dumitrescu }
62620777eb5SCristian Dumitrescu 
62720777eb5SCristian Dumitrescu static inline void
62820777eb5SCristian Dumitrescu ipsec_ring_enqueue(struct rte_swx_ipsec *ipsec, struct rte_ipsec_group *g, uint32_t n_pkts)
62920777eb5SCristian Dumitrescu {
63020777eb5SCristian Dumitrescu 	struct rte_mbuf **dst0 = ipsec->out.pkts, **dst;
63120777eb5SCristian Dumitrescu 	struct rte_mbuf **src = g->m;
63220777eb5SCristian Dumitrescu 
63320777eb5SCristian Dumitrescu 	uint32_t n_dst = ipsec->out.n_pkts;
63420777eb5SCristian Dumitrescu 	uint32_t n_dst_max = ipsec->bsz.ring_wr;
63520777eb5SCristian Dumitrescu 	uint32_t n_dst_avail = n_dst_max - n_dst;
63620777eb5SCristian Dumitrescu 	uint32_t n_src = n_pkts;
63720777eb5SCristian Dumitrescu 	uint32_t i;
63820777eb5SCristian Dumitrescu 
63920777eb5SCristian Dumitrescu 	dst = &dst0[n_dst];
64020777eb5SCristian Dumitrescu 
64120777eb5SCristian Dumitrescu 	/* Move from SRC to DST. Every time DST gets full, send burst from DST. */
64220777eb5SCristian Dumitrescu 	for ( ; n_src >= n_dst_avail; ) {
64320777eb5SCristian Dumitrescu 		uint32_t n_ok;
64420777eb5SCristian Dumitrescu 
64520777eb5SCristian Dumitrescu 		/* Move from SRC to DST. */
64620777eb5SCristian Dumitrescu 		for (i = 0; i < n_dst_avail; i++)
64720777eb5SCristian Dumitrescu 			*dst++ = *src++;
64820777eb5SCristian Dumitrescu 
64920777eb5SCristian Dumitrescu 		n_src -= n_dst_avail;
65020777eb5SCristian Dumitrescu 
65120777eb5SCristian Dumitrescu 		/* DST full: send burst from DST. */
65220777eb5SCristian Dumitrescu 		n_ok = rte_ring_sp_enqueue_burst(ipsec->ring_out, (void **)dst0, n_dst_max, NULL);
65320777eb5SCristian Dumitrescu 
65420777eb5SCristian Dumitrescu 		for (i = n_ok ; i < n_dst_max; i++) {
65520777eb5SCristian Dumitrescu 			struct rte_mbuf *m = dst[i];
65620777eb5SCristian Dumitrescu 
65720777eb5SCristian Dumitrescu 			rte_pktmbuf_free(m);
65820777eb5SCristian Dumitrescu 		}
65920777eb5SCristian Dumitrescu 
66020777eb5SCristian Dumitrescu 		/* Next iteration. */
66120777eb5SCristian Dumitrescu 		dst = dst0;
66220777eb5SCristian Dumitrescu 		n_dst = 0;
66320777eb5SCristian Dumitrescu 		n_dst_avail = n_dst_max;
66420777eb5SCristian Dumitrescu 	}
66520777eb5SCristian Dumitrescu 
66620777eb5SCristian Dumitrescu 	/* Move from SRC to DST. Not enough elements in SRC to get DST full. */
66720777eb5SCristian Dumitrescu 	for (i = 0; i < n_src; i++)
66820777eb5SCristian Dumitrescu 		*dst++ = *src++;
66920777eb5SCristian Dumitrescu 
67020777eb5SCristian Dumitrescu 	n_dst += n_src;
67120777eb5SCristian Dumitrescu 
67220777eb5SCristian Dumitrescu 	ipsec->out.n_pkts = n_dst;
67320777eb5SCristian Dumitrescu }
67420777eb5SCristian Dumitrescu 
67520777eb5SCristian Dumitrescu static inline void
67620777eb5SCristian Dumitrescu rte_swx_ipsec_post_crypto(struct rte_swx_ipsec *ipsec)
67720777eb5SCristian Dumitrescu {
67820777eb5SCristian Dumitrescu 	uint32_t n_pkts_crypto = ipsec->n_pkts_crypto, n_pkts, ng, i;
67920777eb5SCristian Dumitrescu 
68020777eb5SCristian Dumitrescu 	/* Read the crypto ops from the crypto device. */
68120777eb5SCristian Dumitrescu 	if (!n_pkts_crypto)
68220777eb5SCristian Dumitrescu 		return;
68320777eb5SCristian Dumitrescu 
68420777eb5SCristian Dumitrescu 	n_pkts = rte_cryptodev_dequeue_burst(ipsec->dev_id,
68520777eb5SCristian Dumitrescu 					     ipsec->qp_id,
68620777eb5SCristian Dumitrescu 					     ipsec->out.cops,
68720777eb5SCristian Dumitrescu 					     ipsec->bsz.crypto_rd);
68820777eb5SCristian Dumitrescu 	if (!n_pkts)
68920777eb5SCristian Dumitrescu 		return;
69020777eb5SCristian Dumitrescu 
69120777eb5SCristian Dumitrescu 	ipsec->n_pkts_crypto = n_pkts_crypto - n_pkts;
69220777eb5SCristian Dumitrescu 
69320777eb5SCristian Dumitrescu 	/* Group packets that share the same SA. */
69420777eb5SCristian Dumitrescu 	ng = rte_ipsec_pkt_crypto_group((const struct rte_crypto_op **)(uintptr_t)ipsec->out.cops,
69520777eb5SCristian Dumitrescu 					      ipsec->out.group_pkts,
69620777eb5SCristian Dumitrescu 					      ipsec->out.groups,
69720777eb5SCristian Dumitrescu 					      n_pkts);
69820777eb5SCristian Dumitrescu 
69920777eb5SCristian Dumitrescu 	/* Perform post-crypto IPsec processing for each group of packets that share the same SA.
70020777eb5SCristian Dumitrescu 	 * Write each group of packets to the output ring.
70120777eb5SCristian Dumitrescu 	 */
70220777eb5SCristian Dumitrescu 	for (i = 0, n_pkts = 0; i < ng; i++) {
70320777eb5SCristian Dumitrescu 		struct rte_ipsec_group *g = &ipsec->out.groups[i];
70420777eb5SCristian Dumitrescu 		struct rte_ipsec_session *s = g->id.ptr;
70520777eb5SCristian Dumitrescu 		uint32_t n_pkts_ok, j;
70620777eb5SCristian Dumitrescu 
70720777eb5SCristian Dumitrescu 		/* Perform post-crypto IPsec processing for the current group. */
70820777eb5SCristian Dumitrescu 		n_pkts_ok = rte_ipsec_pkt_process(s, g->m, g->cnt);
70920777eb5SCristian Dumitrescu 
71020777eb5SCristian Dumitrescu 		for (j = n_pkts_ok; j < g->cnt; j++) {
71120777eb5SCristian Dumitrescu 			struct rte_mbuf *m = g->m[j];
71220777eb5SCristian Dumitrescu 
71320777eb5SCristian Dumitrescu 			rte_pktmbuf_free(m);
71420777eb5SCristian Dumitrescu 		}
71520777eb5SCristian Dumitrescu 
71620777eb5SCristian Dumitrescu 		/* Write the packets of the current group to the output ring. */
71720777eb5SCristian Dumitrescu 		ipsec_ring_enqueue(ipsec, g, n_pkts_ok);
71820777eb5SCristian Dumitrescu 	}
71920777eb5SCristian Dumitrescu }
72020777eb5SCristian Dumitrescu 
72120777eb5SCristian Dumitrescu void
72220777eb5SCristian Dumitrescu rte_swx_ipsec_run(struct rte_swx_ipsec *ipsec)
72320777eb5SCristian Dumitrescu {
72420777eb5SCristian Dumitrescu 	rte_swx_ipsec_pre_crypto(ipsec);
72520777eb5SCristian Dumitrescu 	rte_swx_ipsec_post_crypto(ipsec);
72620777eb5SCristian Dumitrescu }
72720777eb5SCristian Dumitrescu 
72820777eb5SCristian Dumitrescu /**
72920777eb5SCristian Dumitrescu  * IPsec Control Plane API
73020777eb5SCristian Dumitrescu  */
73120777eb5SCristian Dumitrescu struct cipher_alg {
73220777eb5SCristian Dumitrescu 	const char *name;
73320777eb5SCristian Dumitrescu 	enum rte_crypto_cipher_algorithm alg;
73420777eb5SCristian Dumitrescu 	uint32_t iv_size;
73520777eb5SCristian Dumitrescu 	uint32_t block_size;
73620777eb5SCristian Dumitrescu 	uint32_t key_size;
73720777eb5SCristian Dumitrescu };
73820777eb5SCristian Dumitrescu 
73920777eb5SCristian Dumitrescu struct auth_alg {
74020777eb5SCristian Dumitrescu 	const char *name;
74120777eb5SCristian Dumitrescu 	enum rte_crypto_auth_algorithm alg;
74220777eb5SCristian Dumitrescu 	uint32_t iv_size;
74320777eb5SCristian Dumitrescu 	uint32_t digest_size;
74420777eb5SCristian Dumitrescu 	uint32_t key_size;
74520777eb5SCristian Dumitrescu };
74620777eb5SCristian Dumitrescu 
74720777eb5SCristian Dumitrescu struct aead_alg {
74820777eb5SCristian Dumitrescu 	const char *name;
74920777eb5SCristian Dumitrescu 	enum rte_crypto_aead_algorithm alg;
75020777eb5SCristian Dumitrescu 	uint32_t iv_size;
75120777eb5SCristian Dumitrescu 	uint32_t block_size;
75220777eb5SCristian Dumitrescu 	uint32_t digest_size;
75320777eb5SCristian Dumitrescu 	uint32_t key_size;
75420777eb5SCristian Dumitrescu 	uint32_t aad_size;
75520777eb5SCristian Dumitrescu };
75620777eb5SCristian Dumitrescu 
75720777eb5SCristian Dumitrescu static struct cipher_alg cipher_algs[] = {
75820777eb5SCristian Dumitrescu 	[0] = {
75920777eb5SCristian Dumitrescu 		.name = "null",
76020777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_NULL,
76120777eb5SCristian Dumitrescu 		.iv_size = 0,
76220777eb5SCristian Dumitrescu 		.block_size = 4,
76320777eb5SCristian Dumitrescu 		.key_size = 0,
76420777eb5SCristian Dumitrescu 	},
76520777eb5SCristian Dumitrescu 
76620777eb5SCristian Dumitrescu 	[1] = {
76720777eb5SCristian Dumitrescu 		.name = "aes-cbc-128",
76820777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_AES_CBC,
76920777eb5SCristian Dumitrescu 		.iv_size = 16,
77020777eb5SCristian Dumitrescu 		.block_size = 16,
77120777eb5SCristian Dumitrescu 		.key_size = 16,
77220777eb5SCristian Dumitrescu 	},
77320777eb5SCristian Dumitrescu 
77420777eb5SCristian Dumitrescu 	[2] = {
77520777eb5SCristian Dumitrescu 		.name = "aes-cbc-192",
77620777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_AES_CBC,
77720777eb5SCristian Dumitrescu 		.iv_size = 16,
77820777eb5SCristian Dumitrescu 		.block_size = 16,
77920777eb5SCristian Dumitrescu 		.key_size = 24,
78020777eb5SCristian Dumitrescu 	},
78120777eb5SCristian Dumitrescu 
78220777eb5SCristian Dumitrescu 	[3] = {
78320777eb5SCristian Dumitrescu 		.name = "aes-cbc-256",
78420777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_AES_CBC,
78520777eb5SCristian Dumitrescu 		.iv_size = 16,
78620777eb5SCristian Dumitrescu 		.block_size = 16,
78720777eb5SCristian Dumitrescu 		.key_size = 32,
78820777eb5SCristian Dumitrescu 	},
78920777eb5SCristian Dumitrescu 
79020777eb5SCristian Dumitrescu 	[4] = {
79120777eb5SCristian Dumitrescu 		.name = "aes-ctr-128",
79220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_AES_CTR,
79320777eb5SCristian Dumitrescu 		.iv_size = 8,
79420777eb5SCristian Dumitrescu 		.block_size = 4,
79520777eb5SCristian Dumitrescu 		.key_size = 20,
79620777eb5SCristian Dumitrescu 	},
79720777eb5SCristian Dumitrescu 
79820777eb5SCristian Dumitrescu 	[5] = {
79920777eb5SCristian Dumitrescu 		.name = "aes-ctr-192",
80020777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_AES_CTR,
80120777eb5SCristian Dumitrescu 		.iv_size = 16,
80220777eb5SCristian Dumitrescu 		.block_size = 16,
80320777eb5SCristian Dumitrescu 		.key_size = 28,
80420777eb5SCristian Dumitrescu 	},
80520777eb5SCristian Dumitrescu 
80620777eb5SCristian Dumitrescu 	[6] = {
80720777eb5SCristian Dumitrescu 		.name = "aes-ctr-256",
80820777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_AES_CTR,
80920777eb5SCristian Dumitrescu 		.iv_size = 16,
81020777eb5SCristian Dumitrescu 		.block_size = 16,
81120777eb5SCristian Dumitrescu 		.key_size = 36,
81220777eb5SCristian Dumitrescu 	},
81320777eb5SCristian Dumitrescu 
81420777eb5SCristian Dumitrescu 	[7] = {
81520777eb5SCristian Dumitrescu 		.name = "3des-cbc",
81620777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_3DES_CBC,
81720777eb5SCristian Dumitrescu 		.iv_size = 8,
81820777eb5SCristian Dumitrescu 		.block_size = 8,
81920777eb5SCristian Dumitrescu 		.key_size = 24,
82020777eb5SCristian Dumitrescu 	},
82120777eb5SCristian Dumitrescu 
82220777eb5SCristian Dumitrescu 	[8] = {
82320777eb5SCristian Dumitrescu 		.name = "des-cbc",
82420777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_CIPHER_DES_CBC,
82520777eb5SCristian Dumitrescu 		.iv_size = 8,
82620777eb5SCristian Dumitrescu 		.block_size = 8,
82720777eb5SCristian Dumitrescu 		.key_size = 8,
82820777eb5SCristian Dumitrescu 	},
82920777eb5SCristian Dumitrescu };
83020777eb5SCristian Dumitrescu 
83120777eb5SCristian Dumitrescu static struct auth_alg auth_algs[] = {
83220777eb5SCristian Dumitrescu 	[0] = {
83320777eb5SCristian Dumitrescu 		.name = "null",
83420777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AUTH_NULL,
83520777eb5SCristian Dumitrescu 		.iv_size = 0,
83620777eb5SCristian Dumitrescu 		.digest_size = 0,
83720777eb5SCristian Dumitrescu 		.key_size = 0,
83820777eb5SCristian Dumitrescu 	},
83920777eb5SCristian Dumitrescu 
84020777eb5SCristian Dumitrescu 	[1] = {
84120777eb5SCristian Dumitrescu 		.name = "sha1-hmac",
84220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AUTH_SHA1_HMAC,
84320777eb5SCristian Dumitrescu 		.iv_size = 0,
84420777eb5SCristian Dumitrescu 		.digest_size = 12,
84520777eb5SCristian Dumitrescu 		.key_size = 20,
84620777eb5SCristian Dumitrescu 	},
84720777eb5SCristian Dumitrescu 
84820777eb5SCristian Dumitrescu 	[2] = {
84920777eb5SCristian Dumitrescu 		.name = "sha256-hmac",
85020777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AUTH_SHA256_HMAC,
85120777eb5SCristian Dumitrescu 		.iv_size = 0,
85220777eb5SCristian Dumitrescu 		.digest_size = 16,
85320777eb5SCristian Dumitrescu 		.key_size = 32,
85420777eb5SCristian Dumitrescu 	},
85520777eb5SCristian Dumitrescu 
85620777eb5SCristian Dumitrescu 	[3] = {
85720777eb5SCristian Dumitrescu 		.name = "sha384-hmac",
85820777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AUTH_SHA384_HMAC,
85920777eb5SCristian Dumitrescu 		.iv_size = 0,
86020777eb5SCristian Dumitrescu 		.digest_size = 24,
86120777eb5SCristian Dumitrescu 		.key_size = 48,
86220777eb5SCristian Dumitrescu 	},
86320777eb5SCristian Dumitrescu 
86420777eb5SCristian Dumitrescu 	[4] = {
86520777eb5SCristian Dumitrescu 		.name = "sha512-hmac",
86620777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AUTH_SHA512_HMAC,
86720777eb5SCristian Dumitrescu 		.iv_size = 0,
86820777eb5SCristian Dumitrescu 		.digest_size = 32,
86920777eb5SCristian Dumitrescu 		.key_size = 64,
87020777eb5SCristian Dumitrescu 	},
87120777eb5SCristian Dumitrescu 
87220777eb5SCristian Dumitrescu 	[5] = {
87320777eb5SCristian Dumitrescu 		.name = "aes-gmac",
87420777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AUTH_AES_GMAC,
87520777eb5SCristian Dumitrescu 		.iv_size = 8,
87620777eb5SCristian Dumitrescu 		.digest_size = 16,
87720777eb5SCristian Dumitrescu 		.key_size = 20,
87820777eb5SCristian Dumitrescu 	},
87920777eb5SCristian Dumitrescu 
88020777eb5SCristian Dumitrescu 	[6] = {
88120777eb5SCristian Dumitrescu 		.name = "aes-xcbc-mac-96",
88220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AUTH_AES_XCBC_MAC,
88320777eb5SCristian Dumitrescu 		.iv_size = 0,
88420777eb5SCristian Dumitrescu 		.digest_size = 12,
88520777eb5SCristian Dumitrescu 		.key_size = 16,
88620777eb5SCristian Dumitrescu 	},
88720777eb5SCristian Dumitrescu };
88820777eb5SCristian Dumitrescu 
88920777eb5SCristian Dumitrescu static struct aead_alg aead_algs[] = {
89020777eb5SCristian Dumitrescu 	[0] = {
89120777eb5SCristian Dumitrescu 		.name = "aes-gcm-128",
89220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AEAD_AES_GCM,
89320777eb5SCristian Dumitrescu 		.iv_size = 8,
89420777eb5SCristian Dumitrescu 		.block_size = 4,
89520777eb5SCristian Dumitrescu 		.key_size = 20,
89620777eb5SCristian Dumitrescu 		.digest_size = 16,
89720777eb5SCristian Dumitrescu 		.aad_size = 8,
89820777eb5SCristian Dumitrescu 	},
89920777eb5SCristian Dumitrescu 
90020777eb5SCristian Dumitrescu 	[1] = {
90120777eb5SCristian Dumitrescu 		.name = "aes-gcm-192",
90220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AEAD_AES_GCM,
90320777eb5SCristian Dumitrescu 		.iv_size = 8,
90420777eb5SCristian Dumitrescu 		.block_size = 4,
90520777eb5SCristian Dumitrescu 		.key_size = 28,
90620777eb5SCristian Dumitrescu 		.digest_size = 16,
90720777eb5SCristian Dumitrescu 		.aad_size = 8,
90820777eb5SCristian Dumitrescu 	},
90920777eb5SCristian Dumitrescu 
91020777eb5SCristian Dumitrescu 	[2] = {
91120777eb5SCristian Dumitrescu 		.name = "aes-gcm-256",
91220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AEAD_AES_GCM,
91320777eb5SCristian Dumitrescu 		.iv_size = 8,
91420777eb5SCristian Dumitrescu 		.block_size = 4,
91520777eb5SCristian Dumitrescu 		.key_size = 36,
91620777eb5SCristian Dumitrescu 		.digest_size = 16,
91720777eb5SCristian Dumitrescu 		.aad_size = 8,
91820777eb5SCristian Dumitrescu 	},
91920777eb5SCristian Dumitrescu 
92020777eb5SCristian Dumitrescu 	[3] = {
92120777eb5SCristian Dumitrescu 		.name = "aes-ccm-128",
92220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AEAD_AES_CCM,
92320777eb5SCristian Dumitrescu 		.iv_size = 8,
92420777eb5SCristian Dumitrescu 		.block_size = 4,
92520777eb5SCristian Dumitrescu 		.key_size = 20,
92620777eb5SCristian Dumitrescu 		.digest_size = 16,
92720777eb5SCristian Dumitrescu 		.aad_size = 8,
92820777eb5SCristian Dumitrescu 	},
92920777eb5SCristian Dumitrescu 
93020777eb5SCristian Dumitrescu 	[4] = {
93120777eb5SCristian Dumitrescu 		.name = "aes-ccm-192",
93220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AEAD_AES_CCM,
93320777eb5SCristian Dumitrescu 		.iv_size = 8,
93420777eb5SCristian Dumitrescu 		.block_size = 4,
93520777eb5SCristian Dumitrescu 		.key_size = 28,
93620777eb5SCristian Dumitrescu 		.digest_size = 16,
93720777eb5SCristian Dumitrescu 		.aad_size = 8,
93820777eb5SCristian Dumitrescu 	},
93920777eb5SCristian Dumitrescu 
94020777eb5SCristian Dumitrescu 	[5] = {
94120777eb5SCristian Dumitrescu 		.name = "aes-ccm-256",
94220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AEAD_AES_CCM,
94320777eb5SCristian Dumitrescu 		.iv_size = 8,
94420777eb5SCristian Dumitrescu 		.block_size = 4,
94520777eb5SCristian Dumitrescu 		.key_size = 36,
94620777eb5SCristian Dumitrescu 		.digest_size = 16,
94720777eb5SCristian Dumitrescu 		.aad_size = 8,
94820777eb5SCristian Dumitrescu 	},
94920777eb5SCristian Dumitrescu 
95020777eb5SCristian Dumitrescu 	[6] = {
95120777eb5SCristian Dumitrescu 		.name = "chacha20-poly1305",
95220777eb5SCristian Dumitrescu 		.alg = RTE_CRYPTO_AEAD_CHACHA20_POLY1305,
95320777eb5SCristian Dumitrescu 		.iv_size = 12,
95420777eb5SCristian Dumitrescu 		.block_size = 64,
95520777eb5SCristian Dumitrescu 		.key_size = 36,
95620777eb5SCristian Dumitrescu 		.digest_size = 16,
95720777eb5SCristian Dumitrescu 		.aad_size = 8,
95820777eb5SCristian Dumitrescu 	},
95920777eb5SCristian Dumitrescu };
96020777eb5SCristian Dumitrescu 
96120777eb5SCristian Dumitrescu static struct cipher_alg *
96220777eb5SCristian Dumitrescu cipher_alg_find(const char *name)
96320777eb5SCristian Dumitrescu {
96420777eb5SCristian Dumitrescu 	size_t i;
96520777eb5SCristian Dumitrescu 
96620777eb5SCristian Dumitrescu 	for (i = 0; i < RTE_DIM(cipher_algs); i++) {
96720777eb5SCristian Dumitrescu 		struct cipher_alg *alg = &cipher_algs[i];
96820777eb5SCristian Dumitrescu 
96920777eb5SCristian Dumitrescu 		if (!strcmp(name, alg->name))
97020777eb5SCristian Dumitrescu 			return alg;
97120777eb5SCristian Dumitrescu 	}
97220777eb5SCristian Dumitrescu 
97320777eb5SCristian Dumitrescu 	return NULL;
97420777eb5SCristian Dumitrescu }
97520777eb5SCristian Dumitrescu 
97620777eb5SCristian Dumitrescu static struct cipher_alg *
97720777eb5SCristian Dumitrescu cipher_alg_find_by_id(enum rte_crypto_cipher_algorithm alg_id, uint32_t key_size)
97820777eb5SCristian Dumitrescu {
97920777eb5SCristian Dumitrescu 	size_t i;
98020777eb5SCristian Dumitrescu 
98120777eb5SCristian Dumitrescu 	for (i = 0; i < RTE_DIM(cipher_algs); i++) {
98220777eb5SCristian Dumitrescu 		struct cipher_alg *alg = &cipher_algs[i];
98320777eb5SCristian Dumitrescu 
98420777eb5SCristian Dumitrescu 		if (alg->alg == alg_id && alg->key_size == key_size)
98520777eb5SCristian Dumitrescu 			return alg;
98620777eb5SCristian Dumitrescu 	}
98720777eb5SCristian Dumitrescu 
98820777eb5SCristian Dumitrescu 	return NULL;
98920777eb5SCristian Dumitrescu }
99020777eb5SCristian Dumitrescu 
99120777eb5SCristian Dumitrescu static struct auth_alg *
99220777eb5SCristian Dumitrescu auth_alg_find(const char *name)
99320777eb5SCristian Dumitrescu {
99420777eb5SCristian Dumitrescu 	size_t i;
99520777eb5SCristian Dumitrescu 
99620777eb5SCristian Dumitrescu 	for (i = 0; i < RTE_DIM(auth_algs); i++) {
99720777eb5SCristian Dumitrescu 		struct auth_alg *alg = &auth_algs[i];
99820777eb5SCristian Dumitrescu 
99920777eb5SCristian Dumitrescu 		if (!strcmp(name, alg->name))
100020777eb5SCristian Dumitrescu 			return alg;
100120777eb5SCristian Dumitrescu 	}
100220777eb5SCristian Dumitrescu 
100320777eb5SCristian Dumitrescu 	return NULL;
100420777eb5SCristian Dumitrescu }
100520777eb5SCristian Dumitrescu 
100620777eb5SCristian Dumitrescu static struct auth_alg *
100720777eb5SCristian Dumitrescu auth_alg_find_by_id(enum rte_crypto_auth_algorithm alg_id, uint32_t key_size)
100820777eb5SCristian Dumitrescu {
100920777eb5SCristian Dumitrescu 	size_t i;
101020777eb5SCristian Dumitrescu 
101120777eb5SCristian Dumitrescu 	for (i = 0; i < RTE_DIM(auth_algs); i++) {
101220777eb5SCristian Dumitrescu 		struct auth_alg *alg = &auth_algs[i];
101320777eb5SCristian Dumitrescu 
101420777eb5SCristian Dumitrescu 		if (alg->alg == alg_id && alg->key_size == key_size)
101520777eb5SCristian Dumitrescu 			return alg;
101620777eb5SCristian Dumitrescu 	}
101720777eb5SCristian Dumitrescu 
101820777eb5SCristian Dumitrescu 	return NULL;
101920777eb5SCristian Dumitrescu }
102020777eb5SCristian Dumitrescu 
102120777eb5SCristian Dumitrescu static struct aead_alg *
102220777eb5SCristian Dumitrescu aead_alg_find(const char *name)
102320777eb5SCristian Dumitrescu {
102420777eb5SCristian Dumitrescu 	size_t i;
102520777eb5SCristian Dumitrescu 
102620777eb5SCristian Dumitrescu 	for (i = 0; i < RTE_DIM(aead_algs); i++) {
102720777eb5SCristian Dumitrescu 		struct aead_alg *alg = &aead_algs[i];
102820777eb5SCristian Dumitrescu 
102920777eb5SCristian Dumitrescu 		if (!strcmp(name, alg->name))
103020777eb5SCristian Dumitrescu 			return alg;
103120777eb5SCristian Dumitrescu 	}
103220777eb5SCristian Dumitrescu 
103320777eb5SCristian Dumitrescu 	return NULL;
103420777eb5SCristian Dumitrescu }
103520777eb5SCristian Dumitrescu 
103620777eb5SCristian Dumitrescu static struct aead_alg *
103720777eb5SCristian Dumitrescu aead_alg_find_by_id(enum rte_crypto_aead_algorithm alg_id, uint32_t key_size)
103820777eb5SCristian Dumitrescu {
103920777eb5SCristian Dumitrescu 	size_t i;
104020777eb5SCristian Dumitrescu 
104120777eb5SCristian Dumitrescu 	for (i = 0; i < RTE_DIM(aead_algs); i++) {
104220777eb5SCristian Dumitrescu 		struct aead_alg *alg = &aead_algs[i];
104320777eb5SCristian Dumitrescu 
104420777eb5SCristian Dumitrescu 		if (alg->alg == alg_id && alg->key_size == key_size)
104520777eb5SCristian Dumitrescu 			return alg;
104620777eb5SCristian Dumitrescu 	}
104720777eb5SCristian Dumitrescu 
104820777eb5SCristian Dumitrescu 	return NULL;
104920777eb5SCristian Dumitrescu }
105020777eb5SCristian Dumitrescu 
105120777eb5SCristian Dumitrescu static int
105220777eb5SCristian Dumitrescu char_to_hex(char c, uint8_t *val)
105320777eb5SCristian Dumitrescu {
105420777eb5SCristian Dumitrescu 	if (c >= '0' && c <= '9') {
105520777eb5SCristian Dumitrescu 		*val = c - '0';
105620777eb5SCristian Dumitrescu 		return 0;
105720777eb5SCristian Dumitrescu 	}
105820777eb5SCristian Dumitrescu 
105920777eb5SCristian Dumitrescu 	if (c >= 'A' && c <= 'F') {
106020777eb5SCristian Dumitrescu 		*val = c - 'A' + 10;
106120777eb5SCristian Dumitrescu 		return 0;
106220777eb5SCristian Dumitrescu 	}
106320777eb5SCristian Dumitrescu 
106420777eb5SCristian Dumitrescu 	if (c >= 'a' && c <= 'f') {
106520777eb5SCristian Dumitrescu 		*val = c - 'a' + 10;
106620777eb5SCristian Dumitrescu 		return 0;
106720777eb5SCristian Dumitrescu 	}
106820777eb5SCristian Dumitrescu 
106920777eb5SCristian Dumitrescu 	return -EINVAL;
107020777eb5SCristian Dumitrescu }
107120777eb5SCristian Dumitrescu 
107220777eb5SCristian Dumitrescu static int
107320777eb5SCristian Dumitrescu hex_string_parse(char *src, uint8_t *dst, uint32_t n_dst_bytes)
107420777eb5SCristian Dumitrescu {
107520777eb5SCristian Dumitrescu 	uint32_t i;
107620777eb5SCristian Dumitrescu 
107720777eb5SCristian Dumitrescu 	/* Check input arguments. */
107820777eb5SCristian Dumitrescu 	if (!src || !src[0] || !dst || !n_dst_bytes)
107920777eb5SCristian Dumitrescu 		return -EINVAL;
108020777eb5SCristian Dumitrescu 
108120777eb5SCristian Dumitrescu 	/* Skip any leading "0x" or "0X" in the src string. */
108220777eb5SCristian Dumitrescu 	if ((src[0] == '0') && (src[1] == 'x' || src[1] == 'X'))
108320777eb5SCristian Dumitrescu 		src += 2;
108420777eb5SCristian Dumitrescu 
108520777eb5SCristian Dumitrescu 	/* Convert each group of two hex characters in the src string to one byte in dst array. */
108620777eb5SCristian Dumitrescu 	for (i = 0; i < n_dst_bytes; i++) {
108720777eb5SCristian Dumitrescu 		uint8_t a, b;
108820777eb5SCristian Dumitrescu 		int status;
108920777eb5SCristian Dumitrescu 
109020777eb5SCristian Dumitrescu 		status = char_to_hex(*src, &a);
109120777eb5SCristian Dumitrescu 		if (status)
109220777eb5SCristian Dumitrescu 			return status;
109320777eb5SCristian Dumitrescu 		src++;
109420777eb5SCristian Dumitrescu 
109520777eb5SCristian Dumitrescu 		status = char_to_hex(*src, &b);
109620777eb5SCristian Dumitrescu 		if (status)
109720777eb5SCristian Dumitrescu 			return status;
109820777eb5SCristian Dumitrescu 		src++;
109920777eb5SCristian Dumitrescu 
110020777eb5SCristian Dumitrescu 		dst[i] = a * 16 + b;
110120777eb5SCristian Dumitrescu 	}
110220777eb5SCristian Dumitrescu 
110320777eb5SCristian Dumitrescu 	/* Check for the end of the src string. */
110420777eb5SCristian Dumitrescu 	if (*src)
110520777eb5SCristian Dumitrescu 		return -EINVAL;
110620777eb5SCristian Dumitrescu 
110720777eb5SCristian Dumitrescu 	return 0;
110820777eb5SCristian Dumitrescu }
110920777eb5SCristian Dumitrescu 
111020777eb5SCristian Dumitrescu static int
111120777eb5SCristian Dumitrescu token_is_comment(const char *token)
111220777eb5SCristian Dumitrescu {
111320777eb5SCristian Dumitrescu 	if ((token[0] == '#') ||
111420777eb5SCristian Dumitrescu 	    (token[0] == ';') ||
111520777eb5SCristian Dumitrescu 	    ((token[0] == '/') && (token[1] == '/')))
111620777eb5SCristian Dumitrescu 		return 1; /* TRUE. */
111720777eb5SCristian Dumitrescu 
111820777eb5SCristian Dumitrescu 	return 0; /* FALSE. */
111920777eb5SCristian Dumitrescu }
112020777eb5SCristian Dumitrescu 
112120777eb5SCristian Dumitrescu #define MAX_TOKENS 64
112220777eb5SCristian Dumitrescu 
112320777eb5SCristian Dumitrescu #define CHECK(condition, msg)          \
112420777eb5SCristian Dumitrescu do {                                   \
112520777eb5SCristian Dumitrescu 	if (!(condition)) {            \
112620777eb5SCristian Dumitrescu 		if (errmsg)            \
112720777eb5SCristian Dumitrescu 			*errmsg = msg; \
112820777eb5SCristian Dumitrescu 		goto error;            \
112920777eb5SCristian Dumitrescu 	}                              \
113020777eb5SCristian Dumitrescu } while (0)
113120777eb5SCristian Dumitrescu 
113220777eb5SCristian Dumitrescu struct rte_swx_ipsec_sa_params *
113320777eb5SCristian Dumitrescu rte_swx_ipsec_sa_read(struct rte_swx_ipsec *ipsec __rte_unused,
113420777eb5SCristian Dumitrescu 		      const char *string,
113520777eb5SCristian Dumitrescu 		      int *is_blank_or_comment,
113620777eb5SCristian Dumitrescu 		      const char **errmsg)
113720777eb5SCristian Dumitrescu {
113820777eb5SCristian Dumitrescu 	char *token_array[MAX_TOKENS], **t;
113920777eb5SCristian Dumitrescu 	struct rte_swx_ipsec_sa_params *p = NULL;
114020777eb5SCristian Dumitrescu 	char *s0 = NULL, *s;
114120777eb5SCristian Dumitrescu 	uint32_t n_tokens = 0;
114220777eb5SCristian Dumitrescu 	int blank_or_comment = 0;
114320777eb5SCristian Dumitrescu 
114420777eb5SCristian Dumitrescu 	/* Check input arguments. */
114520777eb5SCristian Dumitrescu 	CHECK(string && string[0], "NULL input");
114620777eb5SCristian Dumitrescu 
114720777eb5SCristian Dumitrescu 	/* Memory allocation. */
114820777eb5SCristian Dumitrescu 	s0 = strdup(string);
114920777eb5SCristian Dumitrescu 	p = calloc(1, sizeof(struct rte_swx_ipsec_sa_params));
115020777eb5SCristian Dumitrescu 	CHECK(s0 && p, "Not enough memory");
115120777eb5SCristian Dumitrescu 
115220777eb5SCristian Dumitrescu 	/* Parse the string into tokens. */
115320777eb5SCristian Dumitrescu 	for (s = s0; ; ) {
115420777eb5SCristian Dumitrescu 		char *token;
115520777eb5SCristian Dumitrescu 
115620777eb5SCristian Dumitrescu 		token = strtok_r(s, " \f\n\r\t\v", &s);
115720777eb5SCristian Dumitrescu 		if (!token || token_is_comment(token))
115820777eb5SCristian Dumitrescu 			break;
115920777eb5SCristian Dumitrescu 
116020777eb5SCristian Dumitrescu 		CHECK(n_tokens < RTE_DIM(token_array), "Too many tokens");
116120777eb5SCristian Dumitrescu 
116220777eb5SCristian Dumitrescu 		token_array[n_tokens] = token;
116320777eb5SCristian Dumitrescu 		n_tokens++;
116420777eb5SCristian Dumitrescu 	}
116520777eb5SCristian Dumitrescu 
116620777eb5SCristian Dumitrescu 	t = token_array;
116720777eb5SCristian Dumitrescu 	if (!n_tokens) {
116820777eb5SCristian Dumitrescu 		blank_or_comment = 1;
116920777eb5SCristian Dumitrescu 		goto error;
117020777eb5SCristian Dumitrescu 	}
117120777eb5SCristian Dumitrescu 
117220777eb5SCristian Dumitrescu 	/*
117320777eb5SCristian Dumitrescu 	 * Crypto operation.
117420777eb5SCristian Dumitrescu 	 */
117520777eb5SCristian Dumitrescu 	if (!strcmp(t[0], "encrypt"))
117620777eb5SCristian Dumitrescu 		p->encrypt = 1;
117720777eb5SCristian Dumitrescu 	else if (!strcmp(t[0], "decrypt"))
117820777eb5SCristian Dumitrescu 		p->encrypt = 0;
117920777eb5SCristian Dumitrescu 	else
118020777eb5SCristian Dumitrescu 		CHECK(0, "Missing \"encrypt\"/\"decrypt\" keyword");
118120777eb5SCristian Dumitrescu 
118220777eb5SCristian Dumitrescu 	t++;
118320777eb5SCristian Dumitrescu 	n_tokens--;
118420777eb5SCristian Dumitrescu 
118520777eb5SCristian Dumitrescu 	/*
118620777eb5SCristian Dumitrescu 	 * Crypto parameters.
118720777eb5SCristian Dumitrescu 	 */
118820777eb5SCristian Dumitrescu 	CHECK(n_tokens >= 2, "Not enough tokens");
118920777eb5SCristian Dumitrescu 
119020777eb5SCristian Dumitrescu 	if (!strcmp(t[0], "cipher")) {
119120777eb5SCristian Dumitrescu 		struct cipher_alg *cipher_alg;
119220777eb5SCristian Dumitrescu 		struct auth_alg *auth_alg;
119320777eb5SCristian Dumitrescu 		uint32_t key_size;
119420777eb5SCristian Dumitrescu 
119520777eb5SCristian Dumitrescu 		p->crypto.is_aead = 0;
119620777eb5SCristian Dumitrescu 
119720777eb5SCristian Dumitrescu 		/* cipher. */
119820777eb5SCristian Dumitrescu 		cipher_alg = cipher_alg_find(t[1]);
119920777eb5SCristian Dumitrescu 		CHECK(cipher_alg, "Unsupported cipher algorithm");
120020777eb5SCristian Dumitrescu 
120120777eb5SCristian Dumitrescu 		key_size = cipher_alg->key_size;
120220777eb5SCristian Dumitrescu 		p->crypto.cipher_auth.cipher.alg = cipher_alg->alg;
120320777eb5SCristian Dumitrescu 		p->crypto.cipher_auth.cipher.key_size = key_size;
120420777eb5SCristian Dumitrescu 
120520777eb5SCristian Dumitrescu 		t += 2;
120620777eb5SCristian Dumitrescu 		n_tokens -= 2;
120720777eb5SCristian Dumitrescu 
120820777eb5SCristian Dumitrescu 		if (key_size) {
120920777eb5SCristian Dumitrescu 			int status;
121020777eb5SCristian Dumitrescu 
121120777eb5SCristian Dumitrescu 			CHECK(n_tokens >= 2, "Not enough tokens");
121220777eb5SCristian Dumitrescu 			CHECK(!strcmp(t[0], "key"), "Missing cipher \"key\" keyword");
121320777eb5SCristian Dumitrescu 			CHECK(key_size <= RTE_DIM(p->crypto.cipher_auth.cipher.key),
121420777eb5SCristian Dumitrescu 				"Cipher algorithm key too big");
121520777eb5SCristian Dumitrescu 
121620777eb5SCristian Dumitrescu 			status = hex_string_parse(t[1], p->crypto.cipher_auth.cipher.key, key_size);
121720777eb5SCristian Dumitrescu 			CHECK(!status, "Cipher key invalid format");
121820777eb5SCristian Dumitrescu 
121920777eb5SCristian Dumitrescu 			t += 2;
122020777eb5SCristian Dumitrescu 			n_tokens -= 2;
122120777eb5SCristian Dumitrescu 		}
122220777eb5SCristian Dumitrescu 
122320777eb5SCristian Dumitrescu 		/* authentication. */
122420777eb5SCristian Dumitrescu 		CHECK(n_tokens >= 2, "Not enough tokens");
122520777eb5SCristian Dumitrescu 		CHECK(!strcmp(t[0], "auth"), "Missing \"auth\" keyword");
122620777eb5SCristian Dumitrescu 
122720777eb5SCristian Dumitrescu 		auth_alg = auth_alg_find(t[1]);
122820777eb5SCristian Dumitrescu 		CHECK(auth_alg, "Unsupported authentication algorithm");
122920777eb5SCristian Dumitrescu 
123020777eb5SCristian Dumitrescu 		key_size = auth_alg->key_size;
123120777eb5SCristian Dumitrescu 		p->crypto.cipher_auth.auth.alg = auth_alg->alg;
123220777eb5SCristian Dumitrescu 		p->crypto.cipher_auth.auth.key_size = key_size;
123320777eb5SCristian Dumitrescu 
123420777eb5SCristian Dumitrescu 		t += 2;
123520777eb5SCristian Dumitrescu 		n_tokens -= 2;
123620777eb5SCristian Dumitrescu 
123720777eb5SCristian Dumitrescu 		if (key_size) {
123820777eb5SCristian Dumitrescu 			int status;
123920777eb5SCristian Dumitrescu 
124020777eb5SCristian Dumitrescu 			CHECK(n_tokens >= 2, "Not enough tokens");
124120777eb5SCristian Dumitrescu 			CHECK(!strcmp(t[0], "key"), "Missing authentication \"key\" keyword");
124220777eb5SCristian Dumitrescu 			CHECK(key_size <= RTE_DIM(p->crypto.cipher_auth.auth.key),
124320777eb5SCristian Dumitrescu 				"Authentication algorithm key too big");
124420777eb5SCristian Dumitrescu 
124520777eb5SCristian Dumitrescu 			status = hex_string_parse(t[1], p->crypto.cipher_auth.auth.key, key_size);
124620777eb5SCristian Dumitrescu 			CHECK(!status, "Authentication key invalid format");
124720777eb5SCristian Dumitrescu 
124820777eb5SCristian Dumitrescu 			t += 2;
124920777eb5SCristian Dumitrescu 			n_tokens -= 2;
125020777eb5SCristian Dumitrescu 		}
125120777eb5SCristian Dumitrescu 	} else if (!strcmp(t[0], "aead")) {
125220777eb5SCristian Dumitrescu 		struct aead_alg *alg;
125320777eb5SCristian Dumitrescu 		uint32_t key_size;
125420777eb5SCristian Dumitrescu 		int status;
125520777eb5SCristian Dumitrescu 
125620777eb5SCristian Dumitrescu 		p->crypto.is_aead = 1;
125720777eb5SCristian Dumitrescu 
125820777eb5SCristian Dumitrescu 		CHECK(n_tokens >= 4, "Not enough tokens");
125920777eb5SCristian Dumitrescu 		alg = aead_alg_find(t[1]);
126020777eb5SCristian Dumitrescu 		CHECK(alg, "Unsupported AEAD algorithm");
126120777eb5SCristian Dumitrescu 
126220777eb5SCristian Dumitrescu 		key_size = alg->key_size;
126320777eb5SCristian Dumitrescu 		p->crypto.aead.alg = alg->alg;
126420777eb5SCristian Dumitrescu 		p->crypto.aead.key_size = key_size;
126520777eb5SCristian Dumitrescu 
126620777eb5SCristian Dumitrescu 		CHECK(!strcmp(t[2], "key"), "Missing AEAD \"key\" keyword");
126720777eb5SCristian Dumitrescu 		CHECK(key_size <= RTE_DIM(p->crypto.aead.key),
126820777eb5SCristian Dumitrescu 			"AEAD algorithm key too big");
126920777eb5SCristian Dumitrescu 
127020777eb5SCristian Dumitrescu 		status = hex_string_parse(t[3], p->crypto.aead.key, key_size);
127120777eb5SCristian Dumitrescu 		CHECK(!status, "AEAD key invalid format");
127220777eb5SCristian Dumitrescu 
127320777eb5SCristian Dumitrescu 		t += 4;
127420777eb5SCristian Dumitrescu 		n_tokens -= 4;
127520777eb5SCristian Dumitrescu 	} else
127620777eb5SCristian Dumitrescu 		CHECK(0, "Missing \"cipher\"/\"aead\" keyword");
127720777eb5SCristian Dumitrescu 
127820777eb5SCristian Dumitrescu 	/*
127920777eb5SCristian Dumitrescu 	 * Packet ecapsulation parameters.
128020777eb5SCristian Dumitrescu 	 */
128120777eb5SCristian Dumitrescu 	CHECK(n_tokens >= 4, "Not enough tokens");
128220777eb5SCristian Dumitrescu 	CHECK(!strcmp(t[0], "esp"), "Missing \"esp\" keyword");
128320777eb5SCristian Dumitrescu 	CHECK(!strcmp(t[1], "spi"), "Missing \"spi\" keyword");
128420777eb5SCristian Dumitrescu 
128520777eb5SCristian Dumitrescu 	p->encap.esp.spi = strtoul(t[2], &t[2], 0);
128620777eb5SCristian Dumitrescu 	CHECK(!t[2][0], "ESP SPI field invalid format");
128720777eb5SCristian Dumitrescu 
128820777eb5SCristian Dumitrescu 	t += 3;
128920777eb5SCristian Dumitrescu 	n_tokens -= 3;
129020777eb5SCristian Dumitrescu 
129120777eb5SCristian Dumitrescu 	if (!strcmp(t[0], "tunnel")) {
129220777eb5SCristian Dumitrescu 		p->encap.tunnel_mode = 1;
129320777eb5SCristian Dumitrescu 
129420777eb5SCristian Dumitrescu 		CHECK(n_tokens >= 6, "Not enough tokens");
129520777eb5SCristian Dumitrescu 
129620777eb5SCristian Dumitrescu 		if (!strcmp(t[1], "ipv4")) {
129720777eb5SCristian Dumitrescu 			uint32_t addr;
129820777eb5SCristian Dumitrescu 
129920777eb5SCristian Dumitrescu 			p->encap.tunnel_ipv4 = 1;
130020777eb5SCristian Dumitrescu 
130120777eb5SCristian Dumitrescu 			CHECK(!strcmp(t[2], "srcaddr"), "Missing \"srcaddr\" keyword");
130220777eb5SCristian Dumitrescu 
130320777eb5SCristian Dumitrescu 			addr = strtoul(t[3], &t[3], 0);
130420777eb5SCristian Dumitrescu 			CHECK(!t[3][0], "Tunnel IPv4 source address invalid format");
130520777eb5SCristian Dumitrescu 			p->encap.tunnel.ipv4.src_addr.s_addr = htonl(addr);
130620777eb5SCristian Dumitrescu 
130720777eb5SCristian Dumitrescu 			CHECK(!strcmp(t[4], "dstaddr"), "Missing \"dstaddr\" keyword");
130820777eb5SCristian Dumitrescu 
130920777eb5SCristian Dumitrescu 			addr = strtoul(t[5], &t[5], 0);
131020777eb5SCristian Dumitrescu 			CHECK(!t[5][0], "Tunnel IPv4 destination address invalid format");
131120777eb5SCristian Dumitrescu 			p->encap.tunnel.ipv4.dst_addr.s_addr = htonl(addr);
131220777eb5SCristian Dumitrescu 
131320777eb5SCristian Dumitrescu 			t += 6;
131420777eb5SCristian Dumitrescu 			n_tokens -= 6;
131520777eb5SCristian Dumitrescu 		} else if (!strcmp(t[1], "ipv6")) {
131620777eb5SCristian Dumitrescu 			int status;
131720777eb5SCristian Dumitrescu 
131820777eb5SCristian Dumitrescu 			p->encap.tunnel_ipv4 = 0;
131920777eb5SCristian Dumitrescu 
132020777eb5SCristian Dumitrescu 			CHECK(!strcmp(t[2], "srcaddr"), "Missing \"srcaddr\" keyword");
132120777eb5SCristian Dumitrescu 
132220777eb5SCristian Dumitrescu 			status = hex_string_parse(t[3],
13235ac1abddSRobin Jarry 						  p->encap.tunnel.ipv6.src_addr.a,
132420777eb5SCristian Dumitrescu 						  16);
132520777eb5SCristian Dumitrescu 			CHECK(!status, "Tunnel IPv6 source address invalid format");
132620777eb5SCristian Dumitrescu 
132720777eb5SCristian Dumitrescu 			CHECK(!strcmp(t[4], "dstaddr"), "Missing \"dstaddr\" keyword");
132820777eb5SCristian Dumitrescu 
132920777eb5SCristian Dumitrescu 			status = hex_string_parse(t[5],
13305ac1abddSRobin Jarry 						  p->encap.tunnel.ipv6.dst_addr.a,
133120777eb5SCristian Dumitrescu 						  16);
133220777eb5SCristian Dumitrescu 			CHECK(!status, "Tunnel IPv6 destination address invalid format");
133320777eb5SCristian Dumitrescu 
133420777eb5SCristian Dumitrescu 			t += 6;
133520777eb5SCristian Dumitrescu 			n_tokens -= 6;
133620777eb5SCristian Dumitrescu 		} else
133720777eb5SCristian Dumitrescu 			CHECK(0, "Missing \"ipv4\"/\"ipv6\" keyword");
133820777eb5SCristian Dumitrescu 	} else if (!strcmp(t[0], "transport")) {
133920777eb5SCristian Dumitrescu 		p->encap.tunnel_mode = 0;
134020777eb5SCristian Dumitrescu 
134120777eb5SCristian Dumitrescu 		t++;
134220777eb5SCristian Dumitrescu 		n_tokens--;
134320777eb5SCristian Dumitrescu 	} else
134420777eb5SCristian Dumitrescu 		CHECK(0, "Missing \"tunnel\"/\"transport\" keyword");
134520777eb5SCristian Dumitrescu 
134620777eb5SCristian Dumitrescu 	/*
134720777eb5SCristian Dumitrescu 	 * Any other parameters.
134820777eb5SCristian Dumitrescu 	 */
134920777eb5SCristian Dumitrescu 	CHECK(!n_tokens, "Unexpected trailing tokens");
135020777eb5SCristian Dumitrescu 
135120777eb5SCristian Dumitrescu 	free(s0);
135220777eb5SCristian Dumitrescu 	return p;
135320777eb5SCristian Dumitrescu 
135420777eb5SCristian Dumitrescu error:
135520777eb5SCristian Dumitrescu 	free(p);
135620777eb5SCristian Dumitrescu 	free(s0);
135720777eb5SCristian Dumitrescu 	if (is_blank_or_comment)
135820777eb5SCristian Dumitrescu 		*is_blank_or_comment = blank_or_comment;
135920777eb5SCristian Dumitrescu 	return NULL;
136020777eb5SCristian Dumitrescu }
136120777eb5SCristian Dumitrescu 
136220777eb5SCristian Dumitrescu static void
136320777eb5SCristian Dumitrescu tunnel_ipv4_header_set(struct rte_ipv4_hdr *h, struct rte_swx_ipsec_sa_params *p)
136420777eb5SCristian Dumitrescu {
136520777eb5SCristian Dumitrescu 	struct rte_ipv4_hdr ipv4_hdr = {
136620777eb5SCristian Dumitrescu 		.version_ihl = 0x45,
136720777eb5SCristian Dumitrescu 		.type_of_service = 0,
136820777eb5SCristian Dumitrescu 		.total_length = 0, /* Cannot be pre-computed. */
136920777eb5SCristian Dumitrescu 		.packet_id = 0,
137020777eb5SCristian Dumitrescu 		.fragment_offset = 0,
137120777eb5SCristian Dumitrescu 		.time_to_live = 64,
137220777eb5SCristian Dumitrescu 		.next_proto_id = IPPROTO_ESP,
137320777eb5SCristian Dumitrescu 		.hdr_checksum = 0, /* Cannot be pre-computed. */
137420777eb5SCristian Dumitrescu 		.src_addr = p->encap.tunnel.ipv4.src_addr.s_addr,
137520777eb5SCristian Dumitrescu 		.dst_addr = p->encap.tunnel.ipv4.dst_addr.s_addr,
137620777eb5SCristian Dumitrescu 	};
137720777eb5SCristian Dumitrescu 
137820777eb5SCristian Dumitrescu 	memcpy(h, &ipv4_hdr, sizeof(ipv4_hdr));
137920777eb5SCristian Dumitrescu }
138020777eb5SCristian Dumitrescu 
138120777eb5SCristian Dumitrescu static void
138220777eb5SCristian Dumitrescu tunnel_ipv6_header_set(struct rte_ipv6_hdr *h, struct rte_swx_ipsec_sa_params *p)
138320777eb5SCristian Dumitrescu {
138420777eb5SCristian Dumitrescu 	struct rte_ipv6_hdr ipv6_hdr = {
138520777eb5SCristian Dumitrescu 		.vtc_flow = 0x60000000,
138620777eb5SCristian Dumitrescu 		.payload_len = 0, /* Cannot be pre-computed. */
138720777eb5SCristian Dumitrescu 		.proto = IPPROTO_ESP,
138820777eb5SCristian Dumitrescu 		.hop_limits = 64,
13895ac1abddSRobin Jarry 		.src_addr = p->encap.tunnel.ipv6.src_addr,
13905ac1abddSRobin Jarry 		.dst_addr = p->encap.tunnel.ipv6.dst_addr,
139120777eb5SCristian Dumitrescu 	};
139220777eb5SCristian Dumitrescu 
139320777eb5SCristian Dumitrescu 	memcpy(h, &ipv6_hdr, sizeof(ipv6_hdr));
139420777eb5SCristian Dumitrescu }
139520777eb5SCristian Dumitrescu 
139620777eb5SCristian Dumitrescu /* IPsec library SA parameters. */
139720777eb5SCristian Dumitrescu static struct rte_crypto_sym_xform *
139820777eb5SCristian Dumitrescu crypto_xform_get(struct rte_swx_ipsec_sa_params *p,
139920777eb5SCristian Dumitrescu 		struct rte_crypto_sym_xform *xform,
140020777eb5SCristian Dumitrescu 		uint32_t *salt_out)
140120777eb5SCristian Dumitrescu {
140220777eb5SCristian Dumitrescu 	if (p->crypto.is_aead) {
140320777eb5SCristian Dumitrescu 		struct aead_alg *alg;
140420777eb5SCristian Dumitrescu 		uint32_t key_size, salt, iv_length;
140520777eb5SCristian Dumitrescu 
140620777eb5SCristian Dumitrescu 		alg = aead_alg_find_by_id(p->crypto.aead.alg, p->crypto.aead.key_size);
140720777eb5SCristian Dumitrescu 		if (!alg)
140820777eb5SCristian Dumitrescu 			return NULL;
140920777eb5SCristian Dumitrescu 
141020777eb5SCristian Dumitrescu 		/* salt and salt-related key size adjustment. */
141120777eb5SCristian Dumitrescu 		key_size = p->crypto.aead.key_size - 4;
141220777eb5SCristian Dumitrescu 		memcpy(&salt, &p->crypto.aead.key[key_size], 4);
141320777eb5SCristian Dumitrescu 
141420777eb5SCristian Dumitrescu 		/* IV length. */
141520777eb5SCristian Dumitrescu 		iv_length = 12;
141620777eb5SCristian Dumitrescu 		if (p->crypto.aead.alg == RTE_CRYPTO_AEAD_AES_CCM)
141720777eb5SCristian Dumitrescu 			iv_length = 11;
141820777eb5SCristian Dumitrescu 
141920777eb5SCristian Dumitrescu 		/* xform. */
142020777eb5SCristian Dumitrescu 		xform[0].type = RTE_CRYPTO_SYM_XFORM_AEAD;
142120777eb5SCristian Dumitrescu 		xform[0].aead.op = p->encrypt ?
142220777eb5SCristian Dumitrescu 			RTE_CRYPTO_AEAD_OP_ENCRYPT :
142320777eb5SCristian Dumitrescu 			RTE_CRYPTO_AEAD_OP_DECRYPT;
142420777eb5SCristian Dumitrescu 		xform[0].aead.algo = p->crypto.aead.alg;
142520777eb5SCristian Dumitrescu 		xform[0].aead.key.data = p->crypto.aead.key;
142620777eb5SCristian Dumitrescu 		xform[0].aead.key.length = key_size;
142720777eb5SCristian Dumitrescu 		xform[0].aead.iv.offset = IV_OFFSET;
142820777eb5SCristian Dumitrescu 		xform[0].aead.iv.length = iv_length;
142920777eb5SCristian Dumitrescu 		xform[0].aead.digest_length = alg->digest_size;
143020777eb5SCristian Dumitrescu 		xform[0].aead.aad_length = alg->aad_size;
143120777eb5SCristian Dumitrescu 		xform[0].next = NULL;
143220777eb5SCristian Dumitrescu 
143320777eb5SCristian Dumitrescu 		*salt_out = salt;
143420777eb5SCristian Dumitrescu 		return &xform[0];
143520777eb5SCristian Dumitrescu 	} else {
143620777eb5SCristian Dumitrescu 		struct cipher_alg *cipher_alg;
143720777eb5SCristian Dumitrescu 		struct auth_alg *auth_alg;
143820777eb5SCristian Dumitrescu 		uint32_t cipher_key_size, auth_key_size, salt, auth_iv_length;
143920777eb5SCristian Dumitrescu 
144020777eb5SCristian Dumitrescu 		cipher_alg = cipher_alg_find_by_id(p->crypto.cipher_auth.cipher.alg,
144120777eb5SCristian Dumitrescu 						   p->crypto.cipher_auth.cipher.key_size);
144220777eb5SCristian Dumitrescu 		if (!cipher_alg)
144320777eb5SCristian Dumitrescu 			return NULL;
144420777eb5SCristian Dumitrescu 
144520777eb5SCristian Dumitrescu 		auth_alg = auth_alg_find_by_id(p->crypto.cipher_auth.auth.alg,
144620777eb5SCristian Dumitrescu 					       p->crypto.cipher_auth.auth.key_size);
144720777eb5SCristian Dumitrescu 		if (!auth_alg)
144820777eb5SCristian Dumitrescu 			return NULL;
144920777eb5SCristian Dumitrescu 
145020777eb5SCristian Dumitrescu 		/* salt and salt-related key size adjustment. */
145120777eb5SCristian Dumitrescu 		cipher_key_size = p->crypto.cipher_auth.cipher.key_size;
145220777eb5SCristian Dumitrescu 		auth_key_size = p->crypto.cipher_auth.auth.key_size;
145320777eb5SCristian Dumitrescu 
145420777eb5SCristian Dumitrescu 		switch (p->crypto.cipher_auth.cipher.alg) {
145520777eb5SCristian Dumitrescu 		case RTE_CRYPTO_CIPHER_AES_CBC:
145620777eb5SCristian Dumitrescu 		case RTE_CRYPTO_CIPHER_3DES_CBC:
1457015f535fSStephen Hemminger 			salt = rte_rand();
145820777eb5SCristian Dumitrescu 			break;
145920777eb5SCristian Dumitrescu 
146020777eb5SCristian Dumitrescu 		case RTE_CRYPTO_CIPHER_AES_CTR:
146120777eb5SCristian Dumitrescu 			cipher_key_size -= 4;
146220777eb5SCristian Dumitrescu 			memcpy(&salt, &p->crypto.cipher_auth.cipher.key[cipher_key_size], 4);
146320777eb5SCristian Dumitrescu 			break;
146420777eb5SCristian Dumitrescu 
146520777eb5SCristian Dumitrescu 		default:
146620777eb5SCristian Dumitrescu 			salt = 0;
146720777eb5SCristian Dumitrescu 		}
146820777eb5SCristian Dumitrescu 
146920777eb5SCristian Dumitrescu 		if (p->crypto.cipher_auth.auth.alg == RTE_CRYPTO_AUTH_AES_GMAC) {
147020777eb5SCristian Dumitrescu 			auth_key_size -= 4;
147120777eb5SCristian Dumitrescu 			memcpy(&salt, &p->crypto.cipher_auth.auth.key[auth_key_size], 4);
147220777eb5SCristian Dumitrescu 		}
147320777eb5SCristian Dumitrescu 
147420777eb5SCristian Dumitrescu 		/* IV length. */
147520777eb5SCristian Dumitrescu 		auth_iv_length = cipher_alg->iv_size;
147620777eb5SCristian Dumitrescu 		if (p->crypto.cipher_auth.auth.alg == RTE_CRYPTO_AUTH_AES_GMAC)
147720777eb5SCristian Dumitrescu 			auth_iv_length = 12;
147820777eb5SCristian Dumitrescu 
147920777eb5SCristian Dumitrescu 		/* xform. */
148020777eb5SCristian Dumitrescu 		if (p->encrypt) {
148120777eb5SCristian Dumitrescu 			xform[0].type = RTE_CRYPTO_SYM_XFORM_CIPHER;
148220777eb5SCristian Dumitrescu 			xform[0].cipher.op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
148320777eb5SCristian Dumitrescu 			xform[0].cipher.algo = p->crypto.cipher_auth.cipher.alg;
148420777eb5SCristian Dumitrescu 			xform[0].cipher.key.data = p->crypto.cipher_auth.cipher.key;
148520777eb5SCristian Dumitrescu 			xform[0].cipher.key.length = cipher_key_size;
148620777eb5SCristian Dumitrescu 			xform[0].cipher.iv.offset = IV_OFFSET;
148720777eb5SCristian Dumitrescu 			xform[0].cipher.iv.length = cipher_alg->iv_size;
148820777eb5SCristian Dumitrescu 			xform[0].cipher.dataunit_len = 0;
148920777eb5SCristian Dumitrescu 			xform[0].next = &xform[1];
149020777eb5SCristian Dumitrescu 
149120777eb5SCristian Dumitrescu 			xform[1].type = RTE_CRYPTO_SYM_XFORM_AUTH;
149220777eb5SCristian Dumitrescu 			xform[1].auth.op = RTE_CRYPTO_AUTH_OP_GENERATE;
149320777eb5SCristian Dumitrescu 			xform[1].auth.algo = p->crypto.cipher_auth.auth.alg;
149420777eb5SCristian Dumitrescu 			xform[1].auth.key.data = p->crypto.cipher_auth.auth.key;
149520777eb5SCristian Dumitrescu 			xform[1].auth.key.length = auth_key_size;
149620777eb5SCristian Dumitrescu 			xform[1].auth.iv.offset = IV_OFFSET;
149720777eb5SCristian Dumitrescu 			xform[1].auth.iv.length = auth_iv_length;
149820777eb5SCristian Dumitrescu 			xform[1].auth.digest_length = auth_alg->digest_size;
149920777eb5SCristian Dumitrescu 			xform[1].next = NULL;
150020777eb5SCristian Dumitrescu 		} else {
150120777eb5SCristian Dumitrescu 			xform[0].type = RTE_CRYPTO_SYM_XFORM_AUTH;
150220777eb5SCristian Dumitrescu 			xform[0].auth.op = RTE_CRYPTO_AUTH_OP_VERIFY;
150320777eb5SCristian Dumitrescu 			xform[0].auth.algo = p->crypto.cipher_auth.auth.alg;
150420777eb5SCristian Dumitrescu 			xform[0].auth.key.data = p->crypto.cipher_auth.auth.key;
150520777eb5SCristian Dumitrescu 			xform[0].auth.key.length = auth_key_size;
150620777eb5SCristian Dumitrescu 			xform[0].auth.iv.offset = IV_OFFSET;
150720777eb5SCristian Dumitrescu 			xform[0].auth.iv.length = auth_iv_length;
150820777eb5SCristian Dumitrescu 			xform[0].auth.digest_length = auth_alg->digest_size;
150920777eb5SCristian Dumitrescu 			xform[0].next = &xform[1];
151020777eb5SCristian Dumitrescu 
151120777eb5SCristian Dumitrescu 			xform[1].type = RTE_CRYPTO_SYM_XFORM_CIPHER;
151220777eb5SCristian Dumitrescu 			xform[1].cipher.op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
151320777eb5SCristian Dumitrescu 			xform[1].cipher.algo = p->crypto.cipher_auth.cipher.alg;
151420777eb5SCristian Dumitrescu 			xform[1].cipher.key.data = p->crypto.cipher_auth.cipher.key;
151520777eb5SCristian Dumitrescu 			xform[1].cipher.key.length = cipher_key_size;
151620777eb5SCristian Dumitrescu 			xform[1].cipher.iv.offset = IV_OFFSET;
151720777eb5SCristian Dumitrescu 			xform[1].cipher.iv.length = cipher_alg->iv_size;
151820777eb5SCristian Dumitrescu 			xform[1].cipher.dataunit_len = 0;
151920777eb5SCristian Dumitrescu 			xform[1].next = NULL;
152020777eb5SCristian Dumitrescu 		}
152120777eb5SCristian Dumitrescu 
152220777eb5SCristian Dumitrescu 		*salt_out = salt;
152320777eb5SCristian Dumitrescu 
152420777eb5SCristian Dumitrescu 		if (p->crypto.cipher_auth.auth.alg == RTE_CRYPTO_AUTH_AES_GMAC) {
152520777eb5SCristian Dumitrescu 			if (p->encrypt)
152620777eb5SCristian Dumitrescu 				return &xform[1];
152720777eb5SCristian Dumitrescu 
152820777eb5SCristian Dumitrescu 			xform[0].next = NULL;
152920777eb5SCristian Dumitrescu 			return &xform[0];
153020777eb5SCristian Dumitrescu 		}
153120777eb5SCristian Dumitrescu 
153220777eb5SCristian Dumitrescu 		return &xform[0];
153320777eb5SCristian Dumitrescu 	}
153420777eb5SCristian Dumitrescu }
153520777eb5SCristian Dumitrescu 
153620777eb5SCristian Dumitrescu static void
153720777eb5SCristian Dumitrescu ipsec_xform_get(struct rte_swx_ipsec_sa_params *p,
153820777eb5SCristian Dumitrescu 		struct rte_security_ipsec_xform *ipsec_xform,
153920777eb5SCristian Dumitrescu 		uint32_t salt)
154020777eb5SCristian Dumitrescu {
154120777eb5SCristian Dumitrescu 	ipsec_xform->spi = p->encap.esp.spi;
154220777eb5SCristian Dumitrescu 
154320777eb5SCristian Dumitrescu 	ipsec_xform->salt = salt;
154420777eb5SCristian Dumitrescu 
154520777eb5SCristian Dumitrescu 	ipsec_xform->options.esn = 0;
154620777eb5SCristian Dumitrescu 	ipsec_xform->options.udp_encap = 0;
154720777eb5SCristian Dumitrescu 	ipsec_xform->options.copy_dscp = 1;
154820777eb5SCristian Dumitrescu 	ipsec_xform->options.copy_flabel = 0;
154920777eb5SCristian Dumitrescu 	ipsec_xform->options.copy_df = 0;
155020777eb5SCristian Dumitrescu 	ipsec_xform->options.dec_ttl = 0;
155120777eb5SCristian Dumitrescu 	ipsec_xform->options.ecn = 1;
155220777eb5SCristian Dumitrescu 	ipsec_xform->options.stats = 0;
155320777eb5SCristian Dumitrescu 	ipsec_xform->options.iv_gen_disable = 0;
155420777eb5SCristian Dumitrescu 	ipsec_xform->options.tunnel_hdr_verify = 0;
155520777eb5SCristian Dumitrescu 	ipsec_xform->options.udp_ports_verify = 0;
155620777eb5SCristian Dumitrescu 	ipsec_xform->options.ip_csum_enable = 0;
155720777eb5SCristian Dumitrescu 	ipsec_xform->options.l4_csum_enable = 0;
155820777eb5SCristian Dumitrescu 	ipsec_xform->options.ip_reassembly_en = 0;
155920777eb5SCristian Dumitrescu 
156020777eb5SCristian Dumitrescu 	ipsec_xform->direction = p->encrypt ?
156120777eb5SCristian Dumitrescu 		RTE_SECURITY_IPSEC_SA_DIR_EGRESS :
156220777eb5SCristian Dumitrescu 		RTE_SECURITY_IPSEC_SA_DIR_INGRESS;
156320777eb5SCristian Dumitrescu 
156420777eb5SCristian Dumitrescu 	ipsec_xform->proto = RTE_SECURITY_IPSEC_SA_PROTO_ESP;
156520777eb5SCristian Dumitrescu 
156620777eb5SCristian Dumitrescu 	ipsec_xform->mode = p->encap.tunnel_mode ?
156720777eb5SCristian Dumitrescu 		RTE_SECURITY_IPSEC_SA_MODE_TUNNEL :
156820777eb5SCristian Dumitrescu 		RTE_SECURITY_IPSEC_SA_MODE_TRANSPORT;
156920777eb5SCristian Dumitrescu 
157020777eb5SCristian Dumitrescu 	ipsec_xform->tunnel.type = p->encap.tunnel_ipv4 ?
157120777eb5SCristian Dumitrescu 		RTE_SECURITY_IPSEC_TUNNEL_IPV4 :
157220777eb5SCristian Dumitrescu 		RTE_SECURITY_IPSEC_TUNNEL_IPV6;
157320777eb5SCristian Dumitrescu 
157420777eb5SCristian Dumitrescu 	if (p->encap.tunnel_mode) {
157520777eb5SCristian Dumitrescu 		if (p->encap.tunnel_ipv4) {
157620777eb5SCristian Dumitrescu 			ipsec_xform->tunnel.ipv4.src_ip = p->encap.tunnel.ipv4.src_addr;
157720777eb5SCristian Dumitrescu 			ipsec_xform->tunnel.ipv4.dst_ip = p->encap.tunnel.ipv4.dst_addr;
157820777eb5SCristian Dumitrescu 			ipsec_xform->tunnel.ipv4.dscp = 0;
157920777eb5SCristian Dumitrescu 			ipsec_xform->tunnel.ipv4.df = 0;
158020777eb5SCristian Dumitrescu 			ipsec_xform->tunnel.ipv4.ttl = 64;
158120777eb5SCristian Dumitrescu 		} else {
1582*2ede1422SRobin Jarry 			ipsec_xform->tunnel.ipv6.src_addr = p->encap.tunnel.ipv6.src_addr;
1583*2ede1422SRobin Jarry 			ipsec_xform->tunnel.ipv6.dst_addr = p->encap.tunnel.ipv6.dst_addr;
158420777eb5SCristian Dumitrescu 			ipsec_xform->tunnel.ipv6.dscp = 0;
158520777eb5SCristian Dumitrescu 			ipsec_xform->tunnel.ipv6.flabel = 0;
158620777eb5SCristian Dumitrescu 			ipsec_xform->tunnel.ipv6.hlimit = 64;
158720777eb5SCristian Dumitrescu 		}
158820777eb5SCristian Dumitrescu 	}
158920777eb5SCristian Dumitrescu 
159020777eb5SCristian Dumitrescu 	ipsec_xform->life.packets_soft_limit = 0;
159120777eb5SCristian Dumitrescu 	ipsec_xform->life.bytes_soft_limit = 0;
159220777eb5SCristian Dumitrescu 	ipsec_xform->life.packets_hard_limit = 0;
159320777eb5SCristian Dumitrescu 	ipsec_xform->life.bytes_hard_limit = 0;
159420777eb5SCristian Dumitrescu 
159520777eb5SCristian Dumitrescu 	ipsec_xform->replay_win_sz = 0;
159620777eb5SCristian Dumitrescu 
159720777eb5SCristian Dumitrescu 	ipsec_xform->esn.value = 0;
159820777eb5SCristian Dumitrescu 
159920777eb5SCristian Dumitrescu 	ipsec_xform->udp.dport = 0;
160020777eb5SCristian Dumitrescu 	ipsec_xform->udp.sport = 0;
160120777eb5SCristian Dumitrescu }
160220777eb5SCristian Dumitrescu 
160320777eb5SCristian Dumitrescu static int
160420777eb5SCristian Dumitrescu ipsec_sa_prm_get(struct rte_swx_ipsec_sa_params *p,
160520777eb5SCristian Dumitrescu 		 struct rte_ipsec_sa_prm *sa_prm,
160620777eb5SCristian Dumitrescu 		 struct rte_ipv4_hdr *ipv4_hdr,
160720777eb5SCristian Dumitrescu 		 struct rte_ipv6_hdr *ipv6_hdr,
160820777eb5SCristian Dumitrescu 		 struct rte_crypto_sym_xform *crypto_xform)
160920777eb5SCristian Dumitrescu {
161020777eb5SCristian Dumitrescu 	uint32_t salt;
161120777eb5SCristian Dumitrescu 
161220777eb5SCristian Dumitrescu 	memset(sa_prm, 0, sizeof(*sa_prm)); /* Better to be safe than sorry. */
161320777eb5SCristian Dumitrescu 
161420777eb5SCristian Dumitrescu 	sa_prm->userdata = 0; /* Not used. */
161520777eb5SCristian Dumitrescu 
161620777eb5SCristian Dumitrescu 	sa_prm->flags = 0; /* Flag RTE_IPSEC_SAFLAG_SQN_ATOM not enabled. */
161720777eb5SCristian Dumitrescu 
161820777eb5SCristian Dumitrescu 	/*
161920777eb5SCristian Dumitrescu 	 * crypto_xform.
162020777eb5SCristian Dumitrescu 	 */
162120777eb5SCristian Dumitrescu 	sa_prm->crypto_xform = crypto_xform_get(p, crypto_xform, &salt);
162220777eb5SCristian Dumitrescu 	if (!sa_prm->crypto_xform)
162320777eb5SCristian Dumitrescu 		return -EINVAL;
162420777eb5SCristian Dumitrescu 
162520777eb5SCristian Dumitrescu 	/*
162620777eb5SCristian Dumitrescu 	 * ipsec_xform.
162720777eb5SCristian Dumitrescu 	 */
162820777eb5SCristian Dumitrescu 	ipsec_xform_get(p, &sa_prm->ipsec_xform, salt);
162920777eb5SCristian Dumitrescu 
163020777eb5SCristian Dumitrescu 	/*
163120777eb5SCristian Dumitrescu 	 * tunnel / transport.
163220777eb5SCristian Dumitrescu 	 *
163320777eb5SCristian Dumitrescu 	 * Currently, the input IP packet type is assumed to be IPv4. To support both IPv4 and IPv6,
163420777eb5SCristian Dumitrescu 	 * the input packet type should be added to the SA configuration parameters.
163520777eb5SCristian Dumitrescu 	 */
163620777eb5SCristian Dumitrescu 	if (p->encap.tunnel_mode) {
163720777eb5SCristian Dumitrescu 		if (p->encap.tunnel_ipv4) {
163820777eb5SCristian Dumitrescu 			sa_prm->tun.hdr_len = sizeof(struct rte_ipv4_hdr);
163920777eb5SCristian Dumitrescu 			sa_prm->tun.hdr_l3_off = 0;
164020777eb5SCristian Dumitrescu 			sa_prm->tun.next_proto = IPPROTO_IPIP; /* IPv4. */
164120777eb5SCristian Dumitrescu 			sa_prm->tun.hdr = ipv4_hdr;
164220777eb5SCristian Dumitrescu 		} else {
164320777eb5SCristian Dumitrescu 			sa_prm->tun.hdr_len = sizeof(struct rte_ipv6_hdr);
164420777eb5SCristian Dumitrescu 			sa_prm->tun.hdr_l3_off = 0;
164520777eb5SCristian Dumitrescu 			sa_prm->tun.next_proto = IPPROTO_IPIP; /* IPv4. */
164620777eb5SCristian Dumitrescu 			sa_prm->tun.hdr = ipv6_hdr;
164720777eb5SCristian Dumitrescu 		}
164820777eb5SCristian Dumitrescu 	} else {
164920777eb5SCristian Dumitrescu 		sa_prm->trs.proto = IPPROTO_IPIP; /* IPv4. */
165020777eb5SCristian Dumitrescu 	}
165120777eb5SCristian Dumitrescu 
165220777eb5SCristian Dumitrescu 	return 0;
165320777eb5SCristian Dumitrescu }
165420777eb5SCristian Dumitrescu 
165520777eb5SCristian Dumitrescu static int
165620777eb5SCristian Dumitrescu ipsec_session_create(struct rte_swx_ipsec *ipsec,
165720777eb5SCristian Dumitrescu 		     struct rte_swx_ipsec_sa_params *p,
165820777eb5SCristian Dumitrescu 		     struct rte_ipsec_session *s)
165920777eb5SCristian Dumitrescu {
166020777eb5SCristian Dumitrescu 	struct rte_ipv4_hdr ipv4_hdr;
166120777eb5SCristian Dumitrescu 	struct rte_ipv6_hdr ipv6_hdr;
166220777eb5SCristian Dumitrescu 	struct rte_crypto_sym_xform crypto_xform[2];
166320777eb5SCristian Dumitrescu 	struct rte_ipsec_sa_prm sa_prm;
166420777eb5SCristian Dumitrescu 	struct rte_ipsec_sa *sa = NULL;
166520777eb5SCristian Dumitrescu 	struct rte_cryptodev_sym_session *crypto_session = NULL;
166620777eb5SCristian Dumitrescu 	int sa_size;
166720777eb5SCristian Dumitrescu 	int sa_valid = 0, status = 0;
166820777eb5SCristian Dumitrescu 
166920777eb5SCristian Dumitrescu 	tunnel_ipv4_header_set(&ipv4_hdr, p);
167020777eb5SCristian Dumitrescu 	tunnel_ipv6_header_set(&ipv6_hdr, p);
167120777eb5SCristian Dumitrescu 
167220777eb5SCristian Dumitrescu 	/* IPsec library SA setup. */
167320777eb5SCristian Dumitrescu 	status = ipsec_sa_prm_get(p, &sa_prm, &ipv4_hdr, &ipv6_hdr, crypto_xform);
167420777eb5SCristian Dumitrescu 	if (status)
167520777eb5SCristian Dumitrescu 		goto error;
167620777eb5SCristian Dumitrescu 
167720777eb5SCristian Dumitrescu 	sa_size = rte_ipsec_sa_size(&sa_prm);
167820777eb5SCristian Dumitrescu 	if (sa_size < 0) {
167920777eb5SCristian Dumitrescu 		status = sa_size;
168020777eb5SCristian Dumitrescu 		goto error;
168120777eb5SCristian Dumitrescu 	}
168220777eb5SCristian Dumitrescu 	if (!sa_size) {
168320777eb5SCristian Dumitrescu 		status = -EINVAL;
168420777eb5SCristian Dumitrescu 		goto error;
168520777eb5SCristian Dumitrescu 	}
168620777eb5SCristian Dumitrescu 
168720777eb5SCristian Dumitrescu 	sa = calloc(1, sa_size);
168820777eb5SCristian Dumitrescu 	if (!sa) {
168920777eb5SCristian Dumitrescu 		status = -ENOMEM;
169020777eb5SCristian Dumitrescu 		goto error;
169120777eb5SCristian Dumitrescu 	}
169220777eb5SCristian Dumitrescu 
169320777eb5SCristian Dumitrescu 	sa_size = rte_ipsec_sa_init(sa, &sa_prm, sa_size);
169420777eb5SCristian Dumitrescu 	if (sa_size < 0) {
169520777eb5SCristian Dumitrescu 		status = sa_size;
169620777eb5SCristian Dumitrescu 		goto error;
169720777eb5SCristian Dumitrescu 	}
169820777eb5SCristian Dumitrescu 	if (!sa_size) {
169920777eb5SCristian Dumitrescu 		status = -EINVAL;
170020777eb5SCristian Dumitrescu 		goto error;
170120777eb5SCristian Dumitrescu 	}
170220777eb5SCristian Dumitrescu 
170320777eb5SCristian Dumitrescu 	sa_valid = 1;
170420777eb5SCristian Dumitrescu 
170520777eb5SCristian Dumitrescu 	/* Cryptodev library session setup. */
170620777eb5SCristian Dumitrescu 	crypto_session = rte_cryptodev_sym_session_create(ipsec->dev_id,
170720777eb5SCristian Dumitrescu 							  sa_prm.crypto_xform,
170820777eb5SCristian Dumitrescu 							  ipsec->mp_session);
170920777eb5SCristian Dumitrescu 	if (!crypto_session) {
171020777eb5SCristian Dumitrescu 		status = -ENOMEM;
171120777eb5SCristian Dumitrescu 		goto error;
171220777eb5SCristian Dumitrescu 	}
171320777eb5SCristian Dumitrescu 
171420777eb5SCristian Dumitrescu 	/* IPsec library session setup. */
171520777eb5SCristian Dumitrescu 	s->sa = sa;
171620777eb5SCristian Dumitrescu 	s->type = RTE_SECURITY_ACTION_TYPE_NONE;
171720777eb5SCristian Dumitrescu 	s->crypto.ses = crypto_session;
171820777eb5SCristian Dumitrescu 	s->crypto.dev_id = ipsec->dev_id;
171920777eb5SCristian Dumitrescu 	s->pkt_func.prepare.async = NULL;
172020777eb5SCristian Dumitrescu 	s->pkt_func.process = NULL;
172120777eb5SCristian Dumitrescu 
17225a0e82ccSCristian Dumitrescu 	status = rte_ipsec_session_prepare(s);
17235a0e82ccSCristian Dumitrescu 	if (status)
17245a0e82ccSCristian Dumitrescu 		goto error;
17255a0e82ccSCristian Dumitrescu 
17265a0e82ccSCristian Dumitrescu 	return 0;
172720777eb5SCristian Dumitrescu 
172820777eb5SCristian Dumitrescu error:
172920777eb5SCristian Dumitrescu 	/* sa. */
173020777eb5SCristian Dumitrescu 	if (sa_valid)
173120777eb5SCristian Dumitrescu 		rte_ipsec_sa_fini(sa);
173220777eb5SCristian Dumitrescu 
173320777eb5SCristian Dumitrescu 	free(sa);
173420777eb5SCristian Dumitrescu 
173520777eb5SCristian Dumitrescu 	/* crypto_session. */
173620777eb5SCristian Dumitrescu 	if (crypto_session)
173720777eb5SCristian Dumitrescu 		rte_cryptodev_sym_session_free(ipsec->dev_id, crypto_session);
173820777eb5SCristian Dumitrescu 
173920777eb5SCristian Dumitrescu 	/* s. */
174020777eb5SCristian Dumitrescu 	memset(s, 0, sizeof(*s));
174120777eb5SCristian Dumitrescu 
174220777eb5SCristian Dumitrescu 	return status;
174320777eb5SCristian Dumitrescu }
174420777eb5SCristian Dumitrescu 
174520777eb5SCristian Dumitrescu static void
174620777eb5SCristian Dumitrescu ipsec_session_free(struct rte_swx_ipsec *ipsec,
174720777eb5SCristian Dumitrescu 		   struct rte_ipsec_session *s)
174820777eb5SCristian Dumitrescu {
174920777eb5SCristian Dumitrescu 	if (!s)
175020777eb5SCristian Dumitrescu 		return;
175120777eb5SCristian Dumitrescu 
175220777eb5SCristian Dumitrescu 	/* IPsec library SA. */
175320777eb5SCristian Dumitrescu 	if (s->sa)
175420777eb5SCristian Dumitrescu 		rte_ipsec_sa_fini(s->sa);
175520777eb5SCristian Dumitrescu 	free(s->sa);
175620777eb5SCristian Dumitrescu 
175720777eb5SCristian Dumitrescu 	/* Cryptodev library session. */
175820777eb5SCristian Dumitrescu 	if (s->crypto.ses)
175920777eb5SCristian Dumitrescu 		rte_cryptodev_sym_session_free(ipsec->dev_id, s->crypto.ses);
176020777eb5SCristian Dumitrescu 
176120777eb5SCristian Dumitrescu 	/* IPsec library session. */
176220777eb5SCristian Dumitrescu 	memset(s, 0, sizeof(*s));
176320777eb5SCristian Dumitrescu }
176420777eb5SCristian Dumitrescu 
176520777eb5SCristian Dumitrescu int
176620777eb5SCristian Dumitrescu rte_swx_ipsec_sa_add(struct rte_swx_ipsec *ipsec,
176720777eb5SCristian Dumitrescu 		     struct rte_swx_ipsec_sa_params *sa_params,
176820777eb5SCristian Dumitrescu 		     uint32_t *id)
176920777eb5SCristian Dumitrescu {
177020777eb5SCristian Dumitrescu 	struct ipsec_sa *sa;
177120777eb5SCristian Dumitrescu 	uint32_t sa_id;
177220777eb5SCristian Dumitrescu 	int status;
177320777eb5SCristian Dumitrescu 
177420777eb5SCristian Dumitrescu 	/* Check the input parameters. */
177520777eb5SCristian Dumitrescu 	if (!ipsec || !sa_params || !id)
177620777eb5SCristian Dumitrescu 		return -EINVAL;
177720777eb5SCristian Dumitrescu 
177820777eb5SCristian Dumitrescu 	/* Allocate a free SADB entry. */
177920777eb5SCristian Dumitrescu 	if (!ipsec->n_sa_free_id)
178020777eb5SCristian Dumitrescu 		return -ENOSPC;
178120777eb5SCristian Dumitrescu 
178220777eb5SCristian Dumitrescu 	sa_id = ipsec->sa_free_id[ipsec->n_sa_free_id - 1];
178320777eb5SCristian Dumitrescu 	ipsec->n_sa_free_id--;
178420777eb5SCristian Dumitrescu 
178520777eb5SCristian Dumitrescu 	/* Acquire the SA resources. */
178620777eb5SCristian Dumitrescu 	sa = ipsec_sa_get(ipsec, sa_id);
178720777eb5SCristian Dumitrescu 
178820777eb5SCristian Dumitrescu 	status = ipsec_session_create(ipsec, sa_params, &sa->s);
178920777eb5SCristian Dumitrescu 	if (status) {
179020777eb5SCristian Dumitrescu 		/* Free the allocated SADB entry. */
179120777eb5SCristian Dumitrescu 		ipsec->sa_free_id[ipsec->n_sa_free_id] = sa_id;
179220777eb5SCristian Dumitrescu 		ipsec->n_sa_free_id++;
179320777eb5SCristian Dumitrescu 
179420777eb5SCristian Dumitrescu 		return status;
179520777eb5SCristian Dumitrescu 	}
179620777eb5SCristian Dumitrescu 
179720777eb5SCristian Dumitrescu 	/* Validate the new SA. */
179820777eb5SCristian Dumitrescu 	sa->valid = 1;
179920777eb5SCristian Dumitrescu 	*id = sa_id;
180020777eb5SCristian Dumitrescu 
180120777eb5SCristian Dumitrescu 	return 0;
180220777eb5SCristian Dumitrescu }
180320777eb5SCristian Dumitrescu 
180420777eb5SCristian Dumitrescu void
180520777eb5SCristian Dumitrescu rte_swx_ipsec_sa_delete(struct rte_swx_ipsec *ipsec,
180620777eb5SCristian Dumitrescu 			uint32_t sa_id)
180720777eb5SCristian Dumitrescu {
180820777eb5SCristian Dumitrescu 	struct ipsec_sa *sa;
180920777eb5SCristian Dumitrescu 
181020777eb5SCristian Dumitrescu 	/* Check the input parameters. */
181120777eb5SCristian Dumitrescu 	if (!ipsec || (sa_id >= ipsec->n_sa_max))
181220777eb5SCristian Dumitrescu 		return;
181320777eb5SCristian Dumitrescu 
181420777eb5SCristian Dumitrescu 	/* Release the SA resources. */
181520777eb5SCristian Dumitrescu 	sa = ipsec_sa_get(ipsec, sa_id);
181620777eb5SCristian Dumitrescu 
181720777eb5SCristian Dumitrescu 	ipsec_session_free(ipsec, &sa->s);
181820777eb5SCristian Dumitrescu 
181920777eb5SCristian Dumitrescu 	/* Free the SADB entry. */
182020777eb5SCristian Dumitrescu 	ipsec->sa_free_id[ipsec->n_sa_free_id] = sa_id;
182120777eb5SCristian Dumitrescu 	ipsec->n_sa_free_id++;
182220777eb5SCristian Dumitrescu 
182320777eb5SCristian Dumitrescu 	/* Invalidate the SA. */
182420777eb5SCristian Dumitrescu 	sa->valid = 0;
182520777eb5SCristian Dumitrescu }
1826