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

Generated by: LCOV version 1.14