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