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, ¶ms->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