LCOV - code coverage report
Current view: top level - lib/pipeline - rte_swx_ipsec.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 1 595 0.2 %
Date: 2025-05-01 17:49:45 Functions: 1 25 4.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 1 429 0.2 %

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

Generated by: LCOV version 1.14