LCOV - code coverage report
Current view: top level - vnet/ipsec - ipsec_sa.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 271 311 87.1 %
Date: 2023-07-05 22:20:52 Functions: 24 24 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include <sys/random.h>
      17             : #include <vnet/ipsec/ipsec.h>
      18             : #include <vnet/ipsec/esp.h>
      19             : #include <vnet/udp/udp_local.h>
      20             : #include <vnet/fib/fib_table.h>
      21             : #include <vnet/fib/fib_entry_track.h>
      22             : #include <vnet/ipsec/ipsec_tun.h>
      23             : #include <vnet/ipsec/ipsec.api_enum.h>
      24             : 
      25             : /**
      26             :  * @brief
      27             :  * SA packet & bytes counters
      28             :  */
      29             : vlib_combined_counter_main_t ipsec_sa_counters = {
      30             :   .name = "SA",
      31             :   .stat_segment_name = "/net/ipsec/sa",
      32             : };
      33             : /* Per-SA error counters */
      34             : vlib_simple_counter_main_t ipsec_sa_err_counters[IPSEC_SA_N_ERRORS];
      35             : 
      36             : ipsec_sa_t *ipsec_sa_pool;
      37             : 
      38             : static clib_error_t *
      39       13192 : ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa,
      40             :                               u32 sa_index, int is_add)
      41             : {
      42             :   ipsec_ah_backend_t *ab;
      43             :   ipsec_esp_backend_t *eb;
      44       13192 :   switch (sa->protocol)
      45             :     {
      46         818 :     case IPSEC_PROTOCOL_AH:
      47         818 :       ab = pool_elt_at_index (im->ah_backends, im->ah_current_backend);
      48         818 :       if (ab->add_del_sa_sess_cb)
      49           0 :         return ab->add_del_sa_sess_cb (sa_index, is_add);
      50         818 :       break;
      51       12374 :     case IPSEC_PROTOCOL_ESP:
      52       12374 :       eb = pool_elt_at_index (im->esp_backends, im->esp_current_backend);
      53       12374 :       if (eb->add_del_sa_sess_cb)
      54           0 :         return eb->add_del_sa_sess_cb (sa_index, is_add);
      55       12374 :       break;
      56             :     }
      57       13192 :   return 0;
      58             : }
      59             : 
      60             : void
      61       13192 : ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len)
      62             : {
      63       13192 :   memset (key, 0, sizeof (*key));
      64             : 
      65       13192 :   if (len > sizeof (key->data))
      66           0 :     key->len = sizeof (key->data);
      67             :   else
      68       13192 :     key->len = len;
      69             : 
      70       13192 :   memcpy (key->data, data, key->len);
      71       13192 : }
      72             : 
      73             : /**
      74             :  * 'stack' (resolve the recursion for) the SA tunnel destination
      75             :  */
      76             : static void
      77        3317 : ipsec_sa_stack (ipsec_sa_t * sa)
      78             : {
      79        3317 :   ipsec_main_t *im = &ipsec_main;
      80        3317 :   dpo_id_t tmp = DPO_INVALID;
      81             : 
      82        3317 :   tunnel_contribute_forwarding (&sa->tunnel, &tmp);
      83             : 
      84        3317 :   if (IPSEC_PROTOCOL_AH == sa->protocol)
      85         261 :     dpo_stack_from_node ((ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ?
      86             :                           im->ah6_encrypt_node_index :
      87             :                           im->ah4_encrypt_node_index), &sa->dpo, &tmp);
      88             :   else
      89        3056 :     dpo_stack_from_node ((ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ?
      90             :                           im->esp6_encrypt_node_index :
      91             :                           im->esp4_encrypt_node_index), &sa->dpo, &tmp);
      92        3317 :   dpo_reset (&tmp);
      93        3317 : }
      94             : 
      95             : void
      96        6614 : ipsec_sa_set_async_mode (ipsec_sa_t *sa, int is_enabled)
      97             : {
      98        6614 :   if (is_enabled)
      99             :     {
     100         732 :       sa->crypto_key_index = sa->crypto_async_key_index;
     101         732 :       sa->crypto_enc_op_id = sa->crypto_async_enc_op_id;
     102         732 :       sa->crypto_dec_op_id = sa->crypto_async_dec_op_id;
     103         732 :       sa->integ_key_index = ~0;
     104         732 :       sa->integ_op_id = ~0;
     105             :     }
     106             :   else
     107             :     {
     108        5882 :       sa->crypto_key_index = sa->crypto_sync_key_index;
     109        5882 :       sa->crypto_enc_op_id = sa->crypto_sync_enc_op_id;
     110        5882 :       sa->crypto_dec_op_id = sa->crypto_sync_dec_op_id;
     111        5882 :       sa->integ_key_index = sa->integ_sync_key_index;
     112        5882 :       sa->integ_op_id = sa->integ_sync_op_id;
     113             :     }
     114        6614 : }
     115             : 
     116             : void
     117        6596 : ipsec_sa_set_crypto_alg (ipsec_sa_t * sa, ipsec_crypto_alg_t crypto_alg)
     118             : {
     119        6596 :   ipsec_main_t *im = &ipsec_main;
     120        6596 :   sa->crypto_alg = crypto_alg;
     121        6596 :   sa->crypto_iv_size = im->crypto_algs[crypto_alg].iv_size;
     122        6596 :   sa->esp_block_align = clib_max (4, im->crypto_algs[crypto_alg].block_align);
     123        6596 :   sa->crypto_sync_enc_op_id = im->crypto_algs[crypto_alg].enc_op_id;
     124        6596 :   sa->crypto_sync_dec_op_id = im->crypto_algs[crypto_alg].dec_op_id;
     125        6596 :   sa->crypto_calg = im->crypto_algs[crypto_alg].alg;
     126        6596 :   ASSERT (sa->crypto_iv_size <= ESP_MAX_IV_SIZE);
     127        6596 :   ASSERT (sa->esp_block_align <= ESP_MAX_BLOCK_SIZE);
     128        6596 :   if (IPSEC_CRYPTO_ALG_IS_GCM (crypto_alg) ||
     129             :       IPSEC_CRYPTO_ALG_CTR_AEAD_OTHERS (crypto_alg))
     130             :     {
     131        1750 :       sa->integ_icv_size = im->crypto_algs[crypto_alg].icv_size;
     132        1750 :       ipsec_sa_set_IS_CTR (sa);
     133        1750 :       ipsec_sa_set_IS_AEAD (sa);
     134             :     }
     135        4846 :   else if (IPSEC_CRYPTO_ALG_IS_CTR (crypto_alg))
     136             :     {
     137        1296 :       ipsec_sa_set_IS_CTR (sa);
     138             :     }
     139        6596 : }
     140             : 
     141             : void
     142        4842 : ipsec_sa_set_integ_alg (ipsec_sa_t * sa, ipsec_integ_alg_t integ_alg)
     143             : {
     144        4842 :   ipsec_main_t *im = &ipsec_main;
     145        4842 :   sa->integ_alg = integ_alg;
     146        4842 :   sa->integ_icv_size = im->integ_algs[integ_alg].icv_size;
     147        4842 :   sa->integ_sync_op_id = im->integ_algs[integ_alg].op_id;
     148        4842 :   sa->integ_calg = im->integ_algs[integ_alg].alg;
     149        4842 :   ASSERT (sa->integ_icv_size <= ESP_MAX_ICV_SIZE);
     150        4842 : }
     151             : 
     152             : void
     153        6596 : ipsec_sa_set_async_op_ids (ipsec_sa_t * sa)
     154             : {
     155             :   /* *INDENT-OFF* */
     156        6596 :   if (ipsec_sa_is_set_USE_ESN (sa))
     157             :     {
     158             : #define _(n, s, k)                                                            \
     159             :   if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##n##_ENC)                  \
     160             :     sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD12_ENC;        \
     161             :   if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##n##_DEC)                  \
     162             :     sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD12_DEC;
     163        2838 :       foreach_crypto_aead_alg
     164             : #undef _
     165             :     }
     166             :   else
     167             :     {
     168             : #define _(n, s, k)                                                            \
     169             :   if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##n##_ENC)                  \
     170             :     sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD8_ENC;         \
     171             :   if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##n##_DEC)                  \
     172             :     sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD8_DEC;
     173        3758 :       foreach_crypto_aead_alg
     174             : #undef _
     175             :     }
     176             : 
     177             : #define _(c, h, s, k, d)                                                      \
     178             :   if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##c##_ENC &&                \
     179             :       sa->integ_sync_op_id == VNET_CRYPTO_OP_##h##_HMAC)                      \
     180             :     sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##c##_##h##_TAG##d##_ENC;     \
     181             :   if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##c##_DEC &&                \
     182             :       sa->integ_sync_op_id == VNET_CRYPTO_OP_##h##_HMAC)                      \
     183             :     sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##c##_##h##_TAG##d##_DEC;
     184        6596 :   foreach_crypto_link_async_alg
     185             : #undef _
     186             :   /* *INDENT-ON* */
     187        6596 : }
     188             : 
     189             : int
     190           8 : ipsec_sa_update (u32 id, u16 src_port, u16 dst_port, const tunnel_t *tun,
     191             :                  bool is_tun)
     192             : {
     193           8 :   ipsec_main_t *im = &ipsec_main;
     194             :   ipsec_sa_t *sa;
     195             :   u32 sa_index;
     196             :   uword *p;
     197             :   int rv;
     198             : 
     199           8 :   p = hash_get (im->sa_index_by_sa_id, id);
     200           8 :   if (!p)
     201           0 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     202             : 
     203           8 :   sa = ipsec_sa_get (p[0]);
     204           8 :   sa_index = sa - ipsec_sa_pool;
     205             : 
     206          10 :   if (is_tun && ipsec_sa_is_set_IS_TUNNEL (sa) &&
     207           2 :       (ip_address_cmp (&tun->t_src, &sa->tunnel.t_src) != 0 ||
     208           0 :        ip_address_cmp (&tun->t_dst, &sa->tunnel.t_dst) != 0))
     209             :     {
     210             :       /* if the source IP is updated for an inbound SA under a tunnel protect,
     211             :        we need to update the tun_protect DB with the new src IP */
     212           3 :       if (ipsec_sa_is_set_IS_INBOUND (sa) &&
     213           2 :           ip_address_cmp (&tun->t_src, &sa->tunnel.t_src) != 0 &&
     214           1 :           !ip46_address_is_zero (&tun->t_src.ip))
     215             :         {
     216           1 :           if (ip46_address_is_ip4 (&sa->tunnel.t_src.ip))
     217             :             {
     218             :               ipsec4_tunnel_kv_t old_key, new_key;
     219             :               clib_bihash_kv_8_16_t res,
     220           1 :                 *bkey = (clib_bihash_kv_8_16_t *) &old_key;
     221             : 
     222           1 :               ipsec4_tunnel_mk_key (&old_key, &sa->tunnel.t_src.ip.ip4,
     223             :                                     clib_host_to_net_u32 (sa->spi));
     224           1 :               ipsec4_tunnel_mk_key (&new_key, &tun->t_src.ip.ip4,
     225             :                                     clib_host_to_net_u32 (sa->spi));
     226             : 
     227           1 :               if (!clib_bihash_search_8_16 (&im->tun4_protect_by_key, bkey,
     228             :                                             &res))
     229             :                 {
     230           1 :                   clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, &res, 0);
     231           1 :                   res.key = new_key.key;
     232           1 :                   clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, &res, 1);
     233             :                 }
     234             :             }
     235             :           else
     236             :             {
     237           0 :               ipsec6_tunnel_kv_t old_key = {
     238             :           .key = {
     239             :             .remote_ip =  sa->tunnel.t_src.ip.ip6,
     240           0 :             .spi = clib_host_to_net_u32 (sa->spi),
     241             :           },
     242           0 :         }, new_key = {
     243             :           .key = {
     244             :             .remote_ip = tun->t_src.ip.ip6,
     245           0 :             .spi = clib_host_to_net_u32 (sa->spi),
     246             :           }};
     247             :               clib_bihash_kv_24_16_t res,
     248           0 :                 *bkey = (clib_bihash_kv_24_16_t *) &old_key;
     249             : 
     250           0 :               if (!clib_bihash_search_24_16 (&im->tun6_protect_by_key, bkey,
     251             :                                              &res))
     252             :                 {
     253           0 :                   clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, &res,
     254             :                                              0);
     255           0 :                   clib_memcpy (&res.key, &new_key.key, 3);
     256           0 :                   clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, &res,
     257             :                                              1);
     258             :                 }
     259             :             }
     260             :         }
     261           2 :       tunnel_unresolve (&sa->tunnel);
     262           2 :       tunnel_copy (tun, &sa->tunnel);
     263           2 :       if (!ipsec_sa_is_set_IS_INBOUND (sa))
     264             :         {
     265           1 :           dpo_reset (&sa->dpo);
     266             : 
     267           1 :           sa->tunnel_flags = sa->tunnel.t_encap_decap_flags;
     268             : 
     269           1 :           rv = tunnel_resolve (&sa->tunnel, FIB_NODE_TYPE_IPSEC_SA, sa_index);
     270             : 
     271           1 :           if (rv)
     272             :             {
     273           0 :               hash_unset (im->sa_index_by_sa_id, sa->id);
     274           0 :               pool_put (ipsec_sa_pool, sa);
     275           0 :               return rv;
     276             :             }
     277           1 :           ipsec_sa_stack (sa);
     278             :           /* generate header templates */
     279           1 :           if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa))
     280             :             {
     281           0 :               tunnel_build_v6_hdr (&sa->tunnel,
     282           0 :                                    (ipsec_sa_is_set_UDP_ENCAP (sa) ?
     283             :                                             IP_PROTOCOL_UDP :
     284             :                                             IP_PROTOCOL_IPSEC_ESP),
     285             :                                    &sa->ip6_hdr);
     286             :             }
     287             :           else
     288             :             {
     289           1 :               tunnel_build_v4_hdr (&sa->tunnel,
     290           1 :                                    (ipsec_sa_is_set_UDP_ENCAP (sa) ?
     291             :                                             IP_PROTOCOL_UDP :
     292             :                                             IP_PROTOCOL_IPSEC_ESP),
     293             :                                    &sa->ip4_hdr);
     294             :             }
     295             :         }
     296             :     }
     297             : 
     298           8 :   if (ipsec_sa_is_set_UDP_ENCAP (sa))
     299             :     {
     300          12 :       if (dst_port != IPSEC_UDP_PORT_NONE &&
     301           6 :           dst_port != clib_net_to_host_u16 (sa->udp_hdr.dst_port))
     302             :         {
     303           6 :           if (ipsec_sa_is_set_IS_INBOUND (sa))
     304             :             {
     305           3 :               ipsec_unregister_udp_port (
     306           3 :                 clib_net_to_host_u16 (sa->udp_hdr.dst_port),
     307           3 :                 !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
     308           3 :               ipsec_register_udp_port (dst_port,
     309           3 :                                        !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
     310             :             }
     311           6 :           sa->udp_hdr.dst_port = clib_host_to_net_u16 (dst_port);
     312             :         }
     313          12 :       if (src_port != IPSEC_UDP_PORT_NONE &&
     314           6 :           src_port != clib_net_to_host_u16 (sa->udp_hdr.src_port))
     315           6 :         sa->udp_hdr.src_port = clib_host_to_net_u16 (src_port);
     316             :     }
     317           8 :   return (0);
     318             : }
     319             : 
     320             : int
     321        6596 : ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
     322             :                        ipsec_crypto_alg_t crypto_alg, const ipsec_key_t *ck,
     323             :                        ipsec_integ_alg_t integ_alg, const ipsec_key_t *ik,
     324             :                        ipsec_sa_flags_t flags, u32 salt, u16 src_port,
     325             :                        u16 dst_port, const tunnel_t *tun, u32 *sa_out_index)
     326             : {
     327        6596 :   vlib_main_t *vm = vlib_get_main ();
     328        6596 :   ipsec_main_t *im = &ipsec_main;
     329             :   clib_error_t *err;
     330             :   ipsec_sa_t *sa;
     331             :   u32 sa_index;
     332             :   u64 rand[2];
     333             :   uword *p;
     334             :   int rv;
     335             : 
     336        6596 :   p = hash_get (im->sa_index_by_sa_id, id);
     337        6596 :   if (p)
     338           0 :     return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
     339             : 
     340        6596 :   if (getrandom (rand, sizeof (rand), 0) != sizeof (rand))
     341           0 :     return VNET_API_ERROR_INIT_FAILED;
     342             : 
     343        6596 :   pool_get_aligned_zero (ipsec_sa_pool, sa, CLIB_CACHE_LINE_BYTES);
     344             : 
     345        6596 :   clib_pcg64i_srandom_r (&sa->iv_prng, rand[0], rand[1]);
     346             : 
     347        6596 :   fib_node_init (&sa->node, FIB_NODE_TYPE_IPSEC_SA);
     348        6596 :   fib_node_lock (&sa->node);
     349        6596 :   sa_index = sa - ipsec_sa_pool;
     350             : 
     351        6596 :   vlib_validate_combined_counter (&ipsec_sa_counters, sa_index);
     352        6596 :   vlib_zero_combined_counter (&ipsec_sa_counters, sa_index);
     353      112132 :   for (int i = 0; i < IPSEC_SA_N_ERRORS; i++)
     354             :     {
     355      105536 :       vlib_validate_simple_counter (&ipsec_sa_err_counters[i], sa_index);
     356      105536 :       vlib_zero_simple_counter (&ipsec_sa_err_counters[i], sa_index);
     357             :     }
     358             : 
     359        6596 :   tunnel_copy (tun, &sa->tunnel);
     360        6596 :   sa->id = id;
     361        6596 :   sa->spi = spi;
     362        6596 :   sa->stat_index = sa_index;
     363        6596 :   sa->protocol = proto;
     364        6596 :   sa->flags = flags;
     365        6596 :   sa->salt = salt;
     366        6596 :   sa->thread_index = (vlib_num_workers ()) ? ~0 : 0;
     367        6596 :   if (integ_alg != IPSEC_INTEG_ALG_NONE)
     368             :     {
     369        4842 :       ipsec_sa_set_integ_alg (sa, integ_alg);
     370        4842 :       clib_memcpy (&sa->integ_key, ik, sizeof (sa->integ_key));
     371             :     }
     372        6596 :   ipsec_sa_set_crypto_alg (sa, crypto_alg);
     373        6596 :   ipsec_sa_set_async_op_ids (sa);
     374             : 
     375        6596 :   clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key));
     376             : 
     377       13192 :   sa->crypto_sync_key_index = vnet_crypto_key_add (
     378        6596 :     vm, im->crypto_algs[crypto_alg].alg, (u8 *) ck->data, ck->len);
     379        6596 :   if (~0 == sa->crypto_sync_key_index)
     380             :     {
     381           0 :       pool_put (ipsec_sa_pool, sa);
     382           0 :       return VNET_API_ERROR_KEY_LENGTH;
     383             :     }
     384             : 
     385        6596 :   if (integ_alg != IPSEC_INTEG_ALG_NONE)
     386             :     {
     387        9684 :       sa->integ_sync_key_index = vnet_crypto_key_add (
     388        4842 :         vm, im->integ_algs[integ_alg].alg, (u8 *) ik->data, ik->len);
     389        4842 :       if (~0 == sa->integ_sync_key_index)
     390             :         {
     391           0 :           pool_put (ipsec_sa_pool, sa);
     392           0 :           return VNET_API_ERROR_KEY_LENGTH;
     393             :         }
     394             :     }
     395             : 
     396        6596 :   if (sa->crypto_async_enc_op_id && !ipsec_sa_is_set_IS_AEAD (sa))
     397        4404 :     sa->crypto_async_key_index =
     398        4404 :       vnet_crypto_key_add_linked (vm, sa->crypto_sync_key_index,
     399        4404 :                                   sa->integ_sync_key_index); // AES-CBC & HMAC
     400             :   else
     401        2192 :     sa->crypto_async_key_index = sa->crypto_sync_key_index;
     402             : 
     403        6596 :   if (im->async_mode)
     404             :     {
     405         720 :       ipsec_sa_set_async_mode (sa, 1);
     406             :     }
     407        5876 :   else if (ipsec_sa_is_set_IS_ASYNC (sa))
     408             :     {
     409           2 :       ipsec_sa_set_async_mode (sa, 1 /* is_enabled */);
     410             :     }
     411             :   else
     412             :     {
     413        5874 :       ipsec_sa_set_async_mode (sa, 0 /* is_enabled */);
     414             :     }
     415             : 
     416        6596 :   err = ipsec_check_support_cb (im, sa);
     417        6596 :   if (err)
     418             :     {
     419           0 :       clib_warning ("%s", err->what);
     420           0 :       pool_put (ipsec_sa_pool, sa);
     421           0 :       return VNET_API_ERROR_UNIMPLEMENTED;
     422             :     }
     423             : 
     424        6596 :   err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
     425        6596 :   if (err)
     426             :     {
     427           0 :       pool_put (ipsec_sa_pool, sa);
     428           0 :       return VNET_API_ERROR_SYSCALL_ERROR_1;
     429             :     }
     430             : 
     431        6596 :   if (ipsec_sa_is_set_IS_TUNNEL (sa) &&
     432        3176 :       AF_IP6 == ip_addr_version (&tun->t_src))
     433        1552 :     ipsec_sa_set_IS_TUNNEL_V6 (sa);
     434             : 
     435        6596 :   if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa))
     436             :     {
     437        3169 :       sa->tunnel_flags = sa->tunnel.t_encap_decap_flags;
     438             : 
     439        3169 :       rv = tunnel_resolve (&sa->tunnel, FIB_NODE_TYPE_IPSEC_SA, sa_index);
     440             : 
     441        3169 :       if (rv)
     442             :         {
     443           0 :           pool_put (ipsec_sa_pool, sa);
     444           0 :           return rv;
     445             :         }
     446        3169 :       ipsec_sa_stack (sa);
     447             : 
     448             :       /* generate header templates */
     449        3169 :       if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa))
     450             :         {
     451        1552 :           tunnel_build_v6_hdr (&sa->tunnel,
     452        1552 :                                (ipsec_sa_is_set_UDP_ENCAP (sa) ?
     453             :                                   IP_PROTOCOL_UDP :
     454             :                                   IP_PROTOCOL_IPSEC_ESP),
     455        1552 :                                &sa->ip6_hdr);
     456             :         }
     457             :       else
     458             :         {
     459        1617 :           tunnel_build_v4_hdr (&sa->tunnel,
     460        1617 :                                (ipsec_sa_is_set_UDP_ENCAP (sa) ?
     461             :                                   IP_PROTOCOL_UDP :
     462             :                                   IP_PROTOCOL_IPSEC_ESP),
     463        1617 :                                &sa->ip4_hdr);
     464             :         }
     465             :     }
     466             : 
     467        6596 :   if (ipsec_sa_is_set_UDP_ENCAP (sa))
     468             :     {
     469          70 :       if (dst_port == IPSEC_UDP_PORT_NONE)
     470           6 :         sa->udp_hdr.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
     471             :       else
     472          64 :         sa->udp_hdr.dst_port = clib_host_to_net_u16 (dst_port);
     473             : 
     474          70 :       if (src_port == IPSEC_UDP_PORT_NONE)
     475           8 :         sa->udp_hdr.src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
     476             :       else
     477          62 :         sa->udp_hdr.src_port = clib_host_to_net_u16 (src_port);
     478             : 
     479          70 :       if (ipsec_sa_is_set_IS_INBOUND (sa))
     480          24 :         ipsec_register_udp_port (clib_host_to_net_u16 (sa->udp_hdr.dst_port),
     481          24 :                                  !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
     482             :     }
     483             : 
     484        6596 :   hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
     485             : 
     486        6596 :   if (sa_out_index)
     487        6542 :     *sa_out_index = sa_index;
     488             : 
     489        6596 :   return (0);
     490             : }
     491             : 
     492             : static void
     493        6596 : ipsec_sa_del (ipsec_sa_t * sa)
     494             : {
     495        6596 :   vlib_main_t *vm = vlib_get_main ();
     496        6596 :   ipsec_main_t *im = &ipsec_main;
     497             :   u32 sa_index;
     498             : 
     499        6596 :   sa_index = sa - ipsec_sa_pool;
     500        6596 :   hash_unset (im->sa_index_by_sa_id, sa->id);
     501        6596 :   tunnel_unresolve (&sa->tunnel);
     502             : 
     503             :   /* no recovery possible when deleting an SA */
     504        6596 :   (void) ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
     505             : 
     506        6596 :   if (ipsec_sa_is_set_IS_ASYNC (sa))
     507             :     {
     508           2 :       if (!ipsec_sa_is_set_IS_AEAD (sa))
     509           0 :         vnet_crypto_key_del (vm, sa->crypto_async_key_index);
     510             :     }
     511             : 
     512        6596 :   if (ipsec_sa_is_set_UDP_ENCAP (sa) && ipsec_sa_is_set_IS_INBOUND (sa))
     513          24 :     ipsec_unregister_udp_port (clib_net_to_host_u16 (sa->udp_hdr.dst_port),
     514          24 :                                !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
     515             : 
     516        6596 :   if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa))
     517        3169 :     dpo_reset (&sa->dpo);
     518        6596 :   vnet_crypto_key_del (vm, sa->crypto_sync_key_index);
     519        6596 :   if (sa->integ_alg != IPSEC_INTEG_ALG_NONE)
     520        4842 :     vnet_crypto_key_del (vm, sa->integ_sync_key_index);
     521        6596 :   pool_put (ipsec_sa_pool, sa);
     522        6596 : }
     523             : 
     524             : int
     525           1 : ipsec_sa_bind (u32 id, u32 worker, bool bind)
     526             : {
     527           1 :   ipsec_main_t *im = &ipsec_main;
     528             :   uword *p;
     529             :   ipsec_sa_t *sa;
     530             : 
     531           1 :   p = hash_get (im->sa_index_by_sa_id, id);
     532           1 :   if (!p)
     533           0 :     return VNET_API_ERROR_INVALID_VALUE;
     534             : 
     535           1 :   sa = ipsec_sa_get (p[0]);
     536             : 
     537           1 :   if (!bind)
     538             :     {
     539           0 :       sa->thread_index = ~0;
     540           0 :       return 0;
     541             :     }
     542             : 
     543           1 :   if (worker >= vlib_num_workers ())
     544           0 :     return VNET_API_ERROR_INVALID_WORKER;
     545             : 
     546           1 :   sa->thread_index = vlib_get_worker_thread_index (worker);
     547           1 :   return 0;
     548             : }
     549             : 
     550             : void
     551       23190 : ipsec_sa_unlock (index_t sai)
     552             : {
     553             :   ipsec_sa_t *sa;
     554             : 
     555       23190 :   if (INDEX_INVALID == sai)
     556        6290 :     return;
     557             : 
     558       16900 :   sa = ipsec_sa_get (sai);
     559             : 
     560       16900 :   fib_node_unlock (&sa->node);
     561             : }
     562             : 
     563             : void
     564         440 : ipsec_sa_lock (index_t sai)
     565             : {
     566             :   ipsec_sa_t *sa;
     567             : 
     568         440 :   if (INDEX_INVALID == sai)
     569           0 :     return;
     570             : 
     571         440 :   sa = ipsec_sa_get (sai);
     572             : 
     573         440 :   fib_node_lock (&sa->node);
     574             : }
     575             : 
     576             : index_t
     577        9864 : ipsec_sa_find_and_lock (u32 id)
     578             : {
     579        9864 :   ipsec_main_t *im = &ipsec_main;
     580             :   ipsec_sa_t *sa;
     581             :   uword *p;
     582             : 
     583        9864 :   p = hash_get (im->sa_index_by_sa_id, id);
     584             : 
     585        9864 :   if (!p)
     586           0 :     return INDEX_INVALID;
     587             : 
     588        9864 :   sa = ipsec_sa_get (p[0]);
     589             : 
     590        9864 :   fib_node_lock (&sa->node);
     591             : 
     592        9864 :   return (p[0]);
     593             : }
     594             : 
     595             : int
     596        6617 : ipsec_sa_unlock_id (u32 id)
     597             : {
     598        6617 :   ipsec_main_t *im = &ipsec_main;
     599             :   uword *p;
     600             : 
     601        6617 :   p = hash_get (im->sa_index_by_sa_id, id);
     602             : 
     603        6617 :   if (!p)
     604          13 :     return VNET_API_ERROR_NO_SUCH_ENTRY;
     605             : 
     606        6604 :   ipsec_sa_unlock (p[0]);
     607             : 
     608        6604 :   return (0);
     609             : }
     610             : 
     611             : void
     612       20818 : ipsec_sa_clear (index_t sai)
     613             : {
     614       20818 :   vlib_zero_combined_counter (&ipsec_sa_counters, sai);
     615      353906 :   for (int i = 0; i < IPSEC_SA_N_ERRORS; i++)
     616      333088 :     vlib_zero_simple_counter (&ipsec_sa_err_counters[i], sai);
     617       20818 : }
     618             : 
     619             : void
     620        2531 : ipsec_sa_walk (ipsec_sa_walk_cb_t cb, void *ctx)
     621             : {
     622             :   ipsec_sa_t *sa;
     623             : 
     624             :   /* *INDENT-OFF* */
     625        7449 :   pool_foreach (sa, ipsec_sa_pool)
     626             :     {
     627        4918 :       if (WALK_CONTINUE != cb (sa, ctx))
     628           0 :         break;
     629             :     }
     630             :   /* *INDENT-ON* */
     631        2531 : }
     632             : 
     633             : /**
     634             :  * Function definition to get a FIB node from its index
     635             :  */
     636             : static fib_node_t *
     637         147 : ipsec_sa_fib_node_get (fib_node_index_t index)
     638             : {
     639             :   ipsec_sa_t *sa;
     640             : 
     641         147 :   sa = ipsec_sa_get (index);
     642             : 
     643         147 :   return (&sa->node);
     644             : }
     645             : 
     646             : static ipsec_sa_t *
     647        6743 : ipsec_sa_from_fib_node (fib_node_t *node)
     648             : {
     649        6743 :   ASSERT (FIB_NODE_TYPE_IPSEC_SA == node->fn_type);
     650             :   return (
     651        6743 :     (ipsec_sa_t *) (((char *) node) - STRUCT_OFFSET_OF (ipsec_sa_t, node)));
     652             : }
     653             : 
     654             : /**
     655             :  * Function definition to inform the FIB node that its last lock has gone.
     656             :  */
     657             : static void
     658        6596 : ipsec_sa_last_lock_gone (fib_node_t *node)
     659             : {
     660             :   /*
     661             :    * The ipsec SA is a root of the graph. As such
     662             :    * it never has children and thus is never locked.
     663             :    */
     664        6596 :   ipsec_sa_del (ipsec_sa_from_fib_node (node));
     665        6596 : }
     666             : 
     667             : /**
     668             :  * Function definition to backwalk a FIB node
     669             :  */
     670             : static fib_node_back_walk_rc_t
     671         147 : ipsec_sa_back_walk (fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
     672             : {
     673         147 :   ipsec_sa_stack (ipsec_sa_from_fib_node (node));
     674             : 
     675         147 :   return (FIB_NODE_BACK_WALK_CONTINUE);
     676             : }
     677             : 
     678             : /*
     679             :  * Virtual function table registered by SAs
     680             :  * for participation in the FIB object graph.
     681             :  */
     682             : const static fib_node_vft_t ipsec_sa_vft = {
     683             :   .fnv_get = ipsec_sa_fib_node_get,
     684             :   .fnv_last_lock = ipsec_sa_last_lock_gone,
     685             :   .fnv_back_walk = ipsec_sa_back_walk,
     686             : };
     687             : 
     688             : /* Init per-SA error counters and node type */
     689             : clib_error_t *
     690         559 : ipsec_sa_init (vlib_main_t *vm)
     691             : {
     692         559 :   fib_node_register_type (FIB_NODE_TYPE_IPSEC_SA, &ipsec_sa_vft);
     693             : 
     694             : #define _(index, val, err, desc)                                              \
     695             :   ipsec_sa_err_counters[index].name =                                         \
     696             :     (char *) format (0, "SA-" #err "%c", 0);                                  \
     697             :   ipsec_sa_err_counters[index].stat_segment_name =                            \
     698             :     (char *) format (0, "/net/ipsec/sa/err/" #err "%c", 0);                   \
     699             :   ipsec_sa_err_counters[index].counters = 0;
     700         559 :   foreach_ipsec_sa_err
     701             : #undef _
     702         559 :     return 0;
     703             : }
     704             : 
     705       52639 : VLIB_INIT_FUNCTION (ipsec_sa_init);
     706             : 
     707             : /*
     708             :  * fd.io coding-style-patch-verification: ON
     709             :  *
     710             :  * Local Variables:
     711             :  * eval: (c-set-style "gnu")
     712             :  * End:
     713             :  */

Generated by: LCOV version 1.14