LCOV - code coverage report
Current view: top level - vnet/ipsec - ipsec_spd_policy.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 411 446 92.2 %
Date: 2023-07-05 22:20:52 Functions: 21 21 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 <vnet/ipsec/ipsec.h>
      17             : 
      18             : /**
      19             :  * @brief
      20             :  * Policy packet & bytes counters
      21             :  */
      22             : vlib_combined_counter_main_t ipsec_spd_policy_counters = {
      23             :   .name = "policy",
      24             :   .stat_segment_name = "/net/ipsec/policy",
      25             : };
      26             : 
      27             : int
      28       31098 : ipsec_policy_mk_type (bool is_outbound,
      29             :                       bool is_ipv6,
      30             :                       ipsec_policy_action_t action,
      31             :                       ipsec_spd_policy_type_t * type)
      32             : {
      33       31098 :   if (is_outbound)
      34             :     {
      35       15588 :       *type = (is_ipv6 ?
      36       15588 :                IPSEC_SPD_POLICY_IP6_OUTBOUND : IPSEC_SPD_POLICY_IP4_OUTBOUND);
      37       15588 :       return (0);
      38             :     }
      39             :   else
      40             :     {
      41       15510 :       switch (action)
      42             :         {
      43        9254 :         case IPSEC_POLICY_ACTION_PROTECT:
      44        9254 :           *type = (is_ipv6 ?
      45        9254 :                    IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT :
      46             :                    IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT);
      47        9254 :           return (0);
      48        6228 :         case IPSEC_POLICY_ACTION_BYPASS:
      49        6228 :           *type = (is_ipv6 ?
      50        6228 :                    IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS :
      51             :                    IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS);
      52        6228 :           return (0);
      53          28 :         case IPSEC_POLICY_ACTION_DISCARD:
      54          28 :           *type = (is_ipv6 ?
      55          28 :                    IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD :
      56             :                    IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD);
      57          28 :           return (0);
      58           0 :         case IPSEC_POLICY_ACTION_RESOLVE:
      59           0 :           break;
      60             :         }
      61           0 :     }
      62             : 
      63             :   /* Unsupported type */
      64           0 :   return (-1);
      65             : }
      66             : 
      67             : static_always_inline int
      68         134 : ipsec_is_policy_inbound (ipsec_policy_t *policy)
      69             : {
      70         134 :   if (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
      71         128 :       policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
      72         106 :       policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD ||
      73          90 :       policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT ||
      74          84 :       policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS ||
      75          80 :       policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD)
      76          54 :     return 1;
      77             : 
      78          80 :   return 0;
      79             : }
      80             : 
      81             : static_always_inline int
      82       31098 : ipsec_is_fp_enabled (ipsec_main_t *im, ipsec_spd_t *spd,
      83             :                      ipsec_policy_t *policy)
      84             : {
      85       31098 :   if ((im->fp_spd_ipv4_out_is_enabled &&
      86          44 :        PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip4_out_lookup_hash_idx) &&
      87          44 :        policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND) ||
      88       31056 :       (im->fp_spd_ipv4_in_is_enabled &&
      89          88 :        PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip4_in_lookup_hash_idx) &&
      90          88 :        (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
      91          82 :         policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
      92          60 :         policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD)) ||
      93       31012 :       (im->fp_spd_ipv6_in_is_enabled &&
      94          40 :        PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip6_in_lookup_hash_idx) &&
      95          40 :        (policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT ||
      96          34 :         policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS ||
      97          30 :         policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD)) ||
      98       31002 :       (im->fp_spd_ipv6_out_is_enabled &&
      99          40 :        PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip6_out_lookup_hash_idx) &&
     100          40 :        policy->type == IPSEC_SPD_POLICY_IP6_OUTBOUND))
     101         134 :     return 1;
     102       30964 :   return 0;
     103             : }
     104             : 
     105             : int
     106       31098 : ipsec_add_del_policy (vlib_main_t * vm,
     107             :                       ipsec_policy_t * policy, int is_add, u32 * stat_index)
     108             : {
     109       31098 :   ipsec_main_t *im = &ipsec_main;
     110       31098 :   ipsec_spd_t *spd = 0;
     111             :   ipsec_policy_t *vp;
     112             :   u32 spd_index;
     113             :   uword *p;
     114             : 
     115       31098 :   p = hash_get (im->spd_index_by_spd_id, policy->id);
     116             : 
     117       31098 :   if (!p)
     118           0 :     return VNET_API_ERROR_SYSCALL_ERROR_1;
     119             : 
     120       31098 :   spd_index = p[0];
     121       31098 :   spd = pool_elt_at_index (im->spds, spd_index);
     122       31098 :   if (!spd)
     123           0 :     return VNET_API_ERROR_SYSCALL_ERROR_1;
     124             : 
     125       31098 :   if (im->output_flow_cache_flag && !policy->is_ipv6 &&
     126          46 :       policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND)
     127             :     {
     128             :       /*
     129             :        * Flow cache entry is valid only when epoch_count value in control
     130             :        * plane and data plane match. Otherwise, flow cache entry is considered
     131             :        * stale. To avoid the race condition of using old epoch_count value
     132             :        * in data plane after the roll over of epoch_count in control plane,
     133             :        * entire flow cache is reset.
     134             :        */
     135          38 :       if (im->epoch_count == 0xFFFFFFFF)
     136             :         {
     137             :           /* Reset all the entries in flow cache */
     138           0 :           clib_memset_u8 (im->ipsec4_out_spd_hash_tbl, 0,
     139           0 :                           im->ipsec4_out_spd_hash_num_buckets *
     140             :                             (sizeof (*(im->ipsec4_out_spd_hash_tbl))));
     141             :         }
     142             :       /* Increment epoch counter by 1 */
     143          38 :       clib_atomic_fetch_add_relax (&im->epoch_count, 1);
     144             :       /* Reset spd flow cache counter since all old entries are stale */
     145          38 :       clib_atomic_store_relax_n (&im->ipsec4_out_spd_flow_cache_entries, 0);
     146             :     }
     147             : 
     148       31098 :   if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
     149       26458 :        policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
     150       23308 :        policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD) &&
     151        7818 :       im->input_flow_cache_flag && !policy->is_ipv6)
     152             :     {
     153             :       /*
     154             :        * Flow cache entry is valid only when input_epoch_count value in control
     155             :        * plane and data plane match. Otherwise, flow cache entry is considered
     156             :        * stale. To avoid the race condition of using old input_epoch_count
     157             :        * value in data plane after the roll over of input_epoch_count in
     158             :        * control plane, entire flow cache is reset.
     159             :        */
     160          34 :       if (im->input_epoch_count == 0xFFFFFFFF)
     161             :         {
     162             :           /* Reset all the entries in flow cache */
     163           0 :           clib_memset_u8 (im->ipsec4_in_spd_hash_tbl, 0,
     164           0 :                           im->ipsec4_in_spd_hash_num_buckets *
     165             :                             (sizeof (*(im->ipsec4_in_spd_hash_tbl))));
     166             :         }
     167             :       /* Increment epoch counter by 1 */
     168          34 :       clib_atomic_fetch_add_relax (&im->input_epoch_count, 1);
     169             :       /* Reset spd flow cache counter since all old entries are stale */
     170          34 :       im->ipsec4_in_spd_flow_cache_entries = 0;
     171             :     }
     172             : 
     173       31098 :   if (is_add)
     174             :     {
     175             :       u32 policy_index;
     176             :       u32 i;
     177             : 
     178       15550 :       if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
     179             :         {
     180        9260 :           index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
     181             : 
     182        9260 :           if (INDEX_INVALID == sa_index)
     183          67 :             return VNET_API_ERROR_SYSCALL_ERROR_1;
     184        9260 :           policy->sa_index = sa_index;
     185             :         }
     186             :       else
     187        6290 :         policy->sa_index = INDEX_INVALID;
     188             : 
     189             :       /**
     190             :        * Try adding the policy into fast path SPD first. Only adding to
     191             :        * traditional SPD when failed.
     192             :        **/
     193       15550 :       if (ipsec_is_fp_enabled (im, spd, policy))
     194          67 :         return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 1,
     195             :                                         stat_index);
     196             : 
     197       15483 :       pool_get (im->policies, vp);
     198       15483 :       clib_memcpy (vp, policy, sizeof (*vp));
     199       15483 :       policy_index = vp - im->policies;
     200             : 
     201       15483 :       vlib_validate_combined_counter (&ipsec_spd_policy_counters,
     202             :                                       policy_index);
     203       15483 :       vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
     204             : 
     205       20136 :       vec_foreach_index (i, spd->policies[policy->type])
     206             :         {
     207        7755 :           ipsec_policy_t *p =
     208        7755 :             pool_elt_at_index (im->policies, spd->policies[policy->type][i]);
     209             : 
     210        7755 :           if (p->priority <= vp->priority)
     211             :             {
     212        3102 :               break;
     213             :             }
     214             :         }
     215             : 
     216       15483 :       vec_insert_elts (spd->policies[policy->type], &policy_index, 1, i);
     217             : 
     218       15483 :       *stat_index = policy_index;
     219             :     }
     220             :   else
     221             :     {
     222             :       u32 ii;
     223             : 
     224             :       /**
     225             :        * Try to delete the policy from the fast path SPD first. Delete from
     226             :        * traditional SPD when fp delete fails.
     227             :        **/
     228             : 
     229       15548 :       if (ipsec_is_fp_enabled (im, spd, policy))
     230             : 
     231             :         {
     232          67 :           if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
     233             :             {
     234           6 :               index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
     235             : 
     236           6 :               if (INDEX_INVALID == sa_index)
     237           0 :                 return VNET_API_ERROR_SYSCALL_ERROR_1;
     238           6 :               policy->sa_index = sa_index;
     239           6 :               ipsec_sa_unlock_id (policy->sa_id);
     240             :             }
     241             :           else
     242          61 :             policy->sa_index = INDEX_INVALID;
     243             : 
     244          67 :           return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 0,
     245             :                                           stat_index);
     246             :         }
     247             : 
     248       20147 :       vec_foreach_index (ii, (spd->policies[policy->type]))
     249             :       {
     250       20147 :         vp = pool_elt_at_index (im->policies,
     251             :                                 spd->policies[policy->type][ii]);
     252       20147 :         if (ipsec_policy_is_equal (vp, policy))
     253             :           {
     254       15481 :             vec_delete (spd->policies[policy->type], 1, ii);
     255       15481 :             ipsec_sa_unlock (vp->sa_index);
     256       15481 :             pool_put (im->policies, vp);
     257       15481 :             break;
     258             :           }
     259             :       }
     260             :     }
     261             : 
     262       30964 :   return 0;
     263             : }
     264             : 
     265             : static_always_inline void
     266          67 : ipsec_fp_release_mask_type (ipsec_main_t *im, u32 mask_type_index)
     267             : {
     268          67 :   ipsec_fp_mask_type_entry_t *mte =
     269          67 :     pool_elt_at_index (im->fp_mask_types, mask_type_index);
     270          67 :   mte->refcount--;
     271          67 :   if (mte->refcount == 0)
     272             :     {
     273             :       /* this entry is not in use anymore */
     274          26 :       ASSERT (clib_memset (mte, 0xae, sizeof (*mte)) == EOK);
     275          26 :       pool_put (im->fp_mask_types, mte);
     276             :     }
     277          67 : }
     278             : 
     279             : static_always_inline u32
     280          67 : find_mask_type_index (ipsec_main_t *im, ipsec_fp_5tuple_t *mask)
     281             : {
     282             :   ipsec_fp_mask_type_entry_t *mte;
     283             : 
     284          73 :   pool_foreach (mte, im->fp_mask_types)
     285             :     {
     286          47 :       if (memcmp (&mte->mask, mask, sizeof (*mask)) == 0)
     287          41 :         return (mte - im->fp_mask_types);
     288             :     }
     289             : 
     290          26 :   return ~0;
     291             : }
     292             : 
     293             : static_always_inline void
     294          48 : fill_ip6_hash_policy_kv (ipsec_fp_5tuple_t *match, ipsec_fp_5tuple_t *mask,
     295             :                          clib_bihash_kv_40_8_t *kv)
     296             : {
     297          48 :   ipsec_fp_lookup_value_t *kv_val = (ipsec_fp_lookup_value_t *) &kv->value;
     298          48 :   u64 *pmatch = (u64 *) match->kv_40_8.key;
     299          48 :   u64 *pmask = (u64 *) mask->kv_40_8.key;
     300          48 :   u64 *pkey = (u64 *) kv->key;
     301             : 
     302          48 :   *pkey++ = *pmatch++ & *pmask++;
     303          48 :   *pkey++ = *pmatch++ & *pmask++;
     304          48 :   *pkey++ = *pmatch++ & *pmask++;
     305          48 :   *pkey++ = *pmatch++ & *pmask++;
     306          48 :   *pkey = *pmatch & *pmask;
     307             : 
     308          48 :   kv_val->as_u64 = 0;
     309          48 : }
     310             : 
     311             : static_always_inline void
     312          86 : fill_ip4_hash_policy_kv (ipsec_fp_5tuple_t *match, ipsec_fp_5tuple_t *mask,
     313             :                          clib_bihash_kv_16_8_t *kv)
     314             : {
     315          86 :   ipsec_fp_lookup_value_t *kv_val = (ipsec_fp_lookup_value_t *) &kv->value;
     316          86 :   u64 *pmatch = (u64 *) match->kv_16_8.key;
     317          86 :   u64 *pmask = (u64 *) mask->kv_16_8.key;
     318          86 :   u64 *pkey = (u64 *) kv->key;
     319             : 
     320          86 :   *pkey++ = *pmatch++ & *pmask++;
     321          86 :   *pkey = *pmatch & *pmask;
     322             : 
     323          86 :   kv_val->as_u64 = 0;
     324          86 : }
     325             : 
     326             : static_always_inline u16
     327         160 : mask_out_highest_set_bit_u16 (u16 x)
     328             : {
     329         160 :   x |= x >> 8;
     330         160 :   x |= x >> 4;
     331         160 :   x |= x >> 2;
     332         160 :   x |= x >> 1;
     333         160 :   return ~x;
     334             : }
     335             : 
     336             : static_always_inline u32
     337         164 : mask_out_highest_set_bit_u32 (u32 x)
     338             : {
     339         164 :   x |= x >> 16;
     340         164 :   x |= x >> 8;
     341         164 :   x |= x >> 4;
     342         164 :   x |= x >> 2;
     343         164 :   x |= x >> 1;
     344         164 :   return ~x;
     345             : }
     346             : 
     347             : static_always_inline u64
     348         148 : mask_out_highest_set_bit_u64 (u64 x)
     349             : {
     350         148 :   x |= x >> 32;
     351         148 :   x |= x >> 16;
     352         148 :   x |= x >> 8;
     353         148 :   x |= x >> 4;
     354         148 :   x |= x >> 2;
     355         148 :   x |= x >> 1;
     356         148 :   return ~x;
     357             : }
     358             : 
     359             : static_always_inline void
     360          80 : ipsec_fp_get_policy_ports_mask (ipsec_policy_t *policy,
     361             :                                 ipsec_fp_5tuple_t *mask)
     362             : {
     363          80 :   if (PREDICT_TRUE ((policy->protocol == IP_PROTOCOL_TCP) ||
     364             :                     (policy->protocol == IP_PROTOCOL_UDP) ||
     365             :                     (policy->protocol == IP_PROTOCOL_SCTP)))
     366             :     {
     367          80 :       mask->lport = policy->lport.start ^ policy->lport.stop;
     368          80 :       mask->rport = policy->rport.start ^ policy->rport.stop;
     369             : 
     370          80 :       mask->lport = mask_out_highest_set_bit_u16 (mask->lport);
     371             : 
     372          80 :       mask->rport = mask_out_highest_set_bit_u16 (mask->rport);
     373             :     }
     374             :   else
     375             :     {
     376           0 :       mask->lport = 0;
     377           0 :       mask->rport = 0;
     378             :     }
     379             : 
     380          80 :   mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0;
     381          80 : }
     382             : 
     383             : static_always_inline void
     384          86 : ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask,
     385             :                               bool inbound)
     386             : {
     387          86 :   u32 *pladdr_start = (u32 *) &policy->laddr.start.ip4;
     388          86 :   u32 *pladdr_stop = (u32 *) &policy->laddr.stop.ip4;
     389          86 :   u32 *plmask = (u32 *) &mask->laddr;
     390          86 :   u32 *praddr_start = (u32 *) &policy->raddr.start.ip4;
     391          86 :   u32 *praddr_stop = (u32 *) &policy->raddr.stop.ip4;
     392          86 :   u32 *prmask = (u32 *) &mask->raddr;
     393             : 
     394          86 :   clib_memset_u8 (mask, 0xff, sizeof (ipsec_fp_5tuple_t));
     395          86 :   clib_memset_u8 (&mask->l3_zero_pad, 0, sizeof (mask->l3_zero_pad));
     396             : 
     397          86 :   if (inbound && (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT &&
     398           6 :                   policy->sa_index != INDEX_INVALID))
     399             :     {
     400           6 :       ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
     401             : 
     402           6 :       if (ipsec_sa_is_set_IS_TUNNEL (s))
     403           4 :         goto set_spi_mask;
     404             :     }
     405             : 
     406             :   /* find bits where start != stop */
     407          82 :   *plmask = *pladdr_start ^ *pladdr_stop;
     408          82 :   *prmask = *praddr_start ^ *praddr_stop;
     409             :   /* Find most significant bit set (that is the first position
     410             :    * start differs from stop). Mask out everything after that bit and
     411             :    * the bit itself. Remember that policy stores start and stop in the net
     412             :    * order.
     413             :    */
     414          82 :   *plmask = clib_host_to_net_u32 (
     415             :     mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*plmask)));
     416             : 
     417          82 :   *prmask = clib_host_to_net_u32 (
     418             :     mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask)));
     419             : 
     420          86 : set_spi_mask:
     421          86 :   if (inbound)
     422             :     {
     423          44 :       if (policy->type != IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT)
     424          38 :         mask->spi = 0;
     425             : 
     426          44 :       mask->protocol = 0;
     427             :     }
     428             :   else
     429             :     {
     430          42 :       mask->action = 0;
     431          42 :       ipsec_fp_get_policy_ports_mask (policy, mask);
     432             :     }
     433          86 : }
     434             : 
     435             : static_always_inline void
     436          48 : ipsec_fp_ip6_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask,
     437             :                               bool inbound)
     438             : {
     439          48 :   u64 *pladdr_start = (u64 *) &policy->laddr.start;
     440          48 :   u64 *pladdr_stop = (u64 *) &policy->laddr.stop;
     441          48 :   u64 *plmask = (u64 *) &mask->ip6_laddr;
     442          48 :   u64 *praddr_start = (u64 *) &policy->raddr.start;
     443          48 :   u64 *praddr_stop = (u64 *) &policy->raddr.stop;
     444          48 :   u64 *prmask = (u64 *) &mask->ip6_raddr;
     445             : 
     446          48 :   clib_memset_u8 (mask, 0xff, sizeof (ipsec_fp_5tuple_t));
     447             : 
     448          48 :   if (inbound && (policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT &&
     449           6 :                   policy->sa_index != INDEX_INVALID))
     450             :     {
     451           6 :       ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
     452             : 
     453           6 :       if (ipsec_sa_is_set_IS_TUNNEL (s))
     454           4 :         goto set_spi_mask;
     455             :     }
     456             : 
     457          44 :   *plmask = (*pladdr_start++ ^ *pladdr_stop++);
     458             : 
     459          44 :   *prmask = (*praddr_start++ ^ *praddr_stop++);
     460             : 
     461             :   /* Find most significant bit set (that is the first position
     462             :    * start differs from stop). Mask out everything after that bit and
     463             :    * the bit itself. Remember that policy stores start and stop in the net
     464             :    * order.
     465             :    */
     466          44 :   *plmask = clib_host_to_net_u64 (
     467             :     mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*plmask)));
     468             : 
     469          44 :   if (*plmask++ & clib_host_to_net_u64 (0x1))
     470             :     {
     471          28 :       *plmask = (*pladdr_start ^ *pladdr_stop);
     472          28 :       *plmask = clib_host_to_net_u64 (
     473             :         mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*plmask)));
     474             :     }
     475             :   else
     476          16 :     *plmask = 0;
     477             : 
     478          44 :   *prmask = clib_host_to_net_u64 (
     479             :     mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*prmask)));
     480             : 
     481          44 :   if (*prmask++ & clib_host_to_net_u64 (0x1))
     482             :     {
     483          32 :       *prmask = (*pladdr_start ^ *pladdr_stop);
     484          32 :       *prmask = clib_host_to_net_u64 (
     485             :         mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*prmask)));
     486             :     }
     487             :   else
     488          12 :     *prmask = 0;
     489          48 : set_spi_mask:
     490          48 :   if (inbound)
     491             :     {
     492          10 :       if (policy->type != IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT)
     493           4 :         mask->spi = 0;
     494             : 
     495          10 :       mask->protocol = 0;
     496             :     }
     497             :   else
     498             :     {
     499          38 :       mask->action = 0;
     500          38 :       ipsec_fp_get_policy_ports_mask (policy, mask);
     501             :     }
     502          48 : }
     503             : 
     504             : static_always_inline void
     505         134 : ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple,
     506             :                             bool inbound)
     507             : {
     508         134 :   memset (tuple, 0, sizeof (*tuple));
     509         134 :   tuple->is_ipv6 = policy->is_ipv6;
     510         134 :   if (tuple->is_ipv6)
     511             :     {
     512          48 :       tuple->ip6_laddr = policy->laddr.start.ip6;
     513          48 :       tuple->ip6_raddr = policy->raddr.start.ip6;
     514             :     }
     515             :   else
     516             :     {
     517          86 :       tuple->laddr = policy->laddr.start.ip4;
     518          86 :       tuple->raddr = policy->raddr.start.ip4;
     519             :     }
     520             : 
     521         134 :   if (inbound)
     522             :     {
     523             : 
     524          54 :       if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
     525          48 :            policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT) &&
     526          12 :           policy->sa_index != INDEX_INVALID)
     527          12 :         {
     528          12 :           ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
     529             : 
     530          12 :           tuple->spi = s->spi;
     531          12 :           if (ipsec_sa_is_set_IS_TUNNEL (s))
     532             :             {
     533           8 :               if (tuple->is_ipv6)
     534             :                 {
     535           4 :                   tuple->ip6_laddr = s->tunnel.t_dst.ip.ip6;
     536           4 :                   tuple->ip6_raddr = s->tunnel.t_src.ip.ip6;
     537             :                 }
     538             :               else
     539             :                 {
     540           4 :                   tuple->laddr = s->tunnel.t_dst.ip.ip4;
     541           4 :                   tuple->raddr = s->tunnel.t_src.ip.ip4;
     542             :                 }
     543             :             }
     544             :         }
     545             :       else
     546          42 :         tuple->spi = INDEX_INVALID;
     547          54 :       tuple->action = policy->type;
     548          54 :       return;
     549             :     }
     550             : 
     551          80 :   tuple->protocol = policy->protocol;
     552          80 :   tuple->lport = policy->lport.start;
     553          80 :   tuple->rport = policy->rport.start;
     554             : }
     555             : 
     556             : static_always_inline int
     557          31 : ipsec_fp_mask_type_idx_cmp (ipsec_fp_mask_id_t *mask_id, u32 *idx)
     558             : {
     559          31 :   return mask_id->mask_type_idx == *idx;
     560             : }
     561             : 
     562             : int
     563          43 : ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
     564             :                          ipsec_policy_t *policy, u32 *stat_index)
     565             : {
     566             :   u32 mask_index, searched_idx;
     567             :   ipsec_policy_t *vp;
     568             :   ipsec_fp_mask_type_entry_t *mte;
     569             :   u32 policy_index;
     570             :   clib_bihash_kv_16_8_t kv;
     571             :   clib_bihash_kv_16_8_t result;
     572          43 :   ipsec_fp_lookup_value_t *result_val =
     573             :     (ipsec_fp_lookup_value_t *) &result.value;
     574          43 :   ipsec_fp_lookup_value_t *key_val = (ipsec_fp_lookup_value_t *) &kv.value;
     575             : 
     576             :   ipsec_fp_5tuple_t mask, policy_5tuple;
     577             :   int res;
     578          43 :   bool inbound = ipsec_is_policy_inbound (policy);
     579          43 :   clib_bihash_16_8_t *bihash_table =
     580          22 :     inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
     581          65 :                                  fp_spd->ip4_in_lookup_hash_idx) :
     582          21 :                     pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
     583             :                                  fp_spd->ip4_out_lookup_hash_idx);
     584             : 
     585          43 :   ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound);
     586          43 :   pool_get (im->policies, vp);
     587          43 :   policy_index = vp - im->policies;
     588          43 :   vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
     589          43 :   vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
     590          43 :   *stat_index = policy_index;
     591          43 :   mask_index = find_mask_type_index (im, &mask);
     592             : 
     593          43 :   if (mask_index == ~0)
     594             :     {
     595             :       /* mask type not found, we need to create a new entry */
     596          17 :       pool_get (im->fp_mask_types, mte);
     597          17 :       mask_index = mte - im->fp_mask_types;
     598          17 :       mte->refcount = 0;
     599             :     }
     600             :   else
     601          26 :     mte = im->fp_mask_types + mask_index;
     602             : 
     603          43 :   policy->fp_mask_type_id = mask_index;
     604          43 :   ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
     605             : 
     606          43 :   fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv);
     607             : 
     608          43 :   res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
     609          43 :   if (res != 0)
     610             :     {
     611             :       /* key was not found crate a new entry */
     612          31 :       vec_add1 (key_val->fp_policies_ids, policy_index);
     613          31 :       res = clib_bihash_add_del_16_8 (bihash_table, &kv, 1);
     614             : 
     615          31 :       if (res != 0)
     616           0 :         goto error;
     617             :     }
     618             :   else
     619             :     {
     620             : 
     621          24 :       if (vec_max_len (result_val->fp_policies_ids) !=
     622          12 :           vec_len (result_val->fp_policies_ids))
     623             :         {
     624             :           /* no need to resize */
     625          12 :           vec_add1 (result_val->fp_policies_ids, policy_index);
     626             :         }
     627             :       else
     628             :         {
     629           0 :           vec_add1 (result_val->fp_policies_ids, policy_index);
     630             : 
     631           0 :           res = clib_bihash_add_del_16_8 (bihash_table, &result, 1);
     632             : 
     633           0 :           if (res != 0)
     634           0 :             goto error;
     635             :         }
     636             :     }
     637             : 
     638          43 :   if (mte->refcount == 0)
     639             :     {
     640          17 :       clib_memcpy (&mte->mask, &mask, sizeof (mask));
     641          17 :       mte->refcount = 0;
     642             :     }
     643             : 
     644          43 :   searched_idx =
     645          43 :     vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index,
     646             :                               ipsec_fp_mask_type_idx_cmp);
     647          43 :   if (~0 == searched_idx)
     648             :     {
     649          25 :       ipsec_fp_mask_id_t mask_id = { mask_index, 1 };
     650          25 :       vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id);
     651             :     }
     652             :   else
     653          18 :     (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++;
     654             : 
     655          43 :   mte->refcount++;
     656          43 :   clib_memcpy (vp, policy, sizeof (*vp));
     657             : 
     658          43 :   return 0;
     659             : 
     660           0 : error:
     661           0 :   pool_put (im->policies, vp);
     662           0 :   ipsec_fp_release_mask_type (im, mask_index);
     663           0 :   return -1;
     664             : }
     665             : 
     666             : int
     667          24 : ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
     668             :                          ipsec_policy_t *policy, u32 *stat_index)
     669             : {
     670             : 
     671             :   u32 mask_index, searched_idx;
     672             :   ipsec_policy_t *vp;
     673             :   ipsec_fp_mask_type_entry_t *mte;
     674             :   u32 policy_index;
     675             :   clib_bihash_kv_40_8_t kv;
     676             :   clib_bihash_kv_40_8_t result;
     677          24 :   ipsec_fp_lookup_value_t *result_val =
     678             :     (ipsec_fp_lookup_value_t *) &result.value;
     679          24 :   ipsec_fp_lookup_value_t *key_val = (ipsec_fp_lookup_value_t *) &kv.value;
     680             : 
     681             :   ipsec_fp_5tuple_t mask, policy_5tuple;
     682             :   int res;
     683          24 :   bool inbound = ipsec_is_policy_inbound (policy);
     684             : 
     685          24 :   ipsec_fp_ip6_get_policy_mask (policy, &mask, inbound);
     686          24 :   pool_get (im->policies, vp);
     687          24 :   policy_index = vp - im->policies;
     688          24 :   vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
     689          24 :   vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
     690          24 :   *stat_index = policy_index;
     691          24 :   mask_index = find_mask_type_index (im, &mask);
     692          24 :   clib_bihash_40_8_t *bihash_table =
     693           5 :     inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
     694          29 :                                  fp_spd->ip6_in_lookup_hash_idx) :
     695          19 :                     pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
     696             :                                  fp_spd->ip6_out_lookup_hash_idx);
     697             : 
     698          24 :   if (mask_index == ~0)
     699             :     {
     700             :       /* mask type not found, we need to create a new entry */
     701           9 :       pool_get (im->fp_mask_types, mte);
     702           9 :       mask_index = mte - im->fp_mask_types;
     703           9 :       mte->refcount = 0;
     704             :     }
     705             :   else
     706          15 :     mte = im->fp_mask_types + mask_index;
     707             : 
     708          24 :   policy->fp_mask_type_id = mask_index;
     709          24 :   ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
     710             : 
     711          24 :   fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv);
     712             : 
     713          24 :   res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
     714          24 :   if (res != 0)
     715             :     {
     716             :       /* key was not found crate a new entry */
     717          13 :       vec_add1 (key_val->fp_policies_ids, policy_index);
     718          13 :       res = clib_bihash_add_del_40_8 (bihash_table, &kv, 1);
     719          13 :       if (res != 0)
     720           0 :         goto error;
     721             :     }
     722             :   else
     723             :     {
     724             : 
     725          22 :       if (vec_max_len (result_val->fp_policies_ids) !=
     726          11 :           vec_len (result_val->fp_policies_ids))
     727             :         {
     728             :           /* no need to resize */
     729          11 :           vec_add1 (result_val->fp_policies_ids, policy_index);
     730             :         }
     731             :       else
     732             :         {
     733           0 :           vec_add1 (result_val->fp_policies_ids, policy_index);
     734             : 
     735           0 :           res = clib_bihash_add_del_40_8 (bihash_table, &result, 1);
     736             : 
     737           0 :           if (res != 0)
     738           0 :             goto error;
     739             :         }
     740             :     }
     741             : 
     742          24 :   if (mte->refcount == 0)
     743             :     {
     744           9 :       clib_memcpy (&mte->mask, &mask, sizeof (mask));
     745           9 :       mte->refcount = 0;
     746             :     }
     747             : 
     748          24 :   searched_idx =
     749          24 :     vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index,
     750             :                               ipsec_fp_mask_type_idx_cmp);
     751          24 :   if (~0 == searched_idx)
     752             :     {
     753          11 :       ipsec_fp_mask_id_t mask_id = { mask_index, 1 };
     754          11 :       vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id);
     755             :     }
     756             :   else
     757          13 :     (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++;
     758             : 
     759          24 :   mte->refcount++;
     760          24 :   clib_memcpy (vp, policy, sizeof (*vp));
     761             : 
     762          24 :   return 0;
     763             : 
     764           0 : error:
     765           0 :   pool_put (im->policies, vp);
     766           0 :   ipsec_fp_release_mask_type (im, mask_index);
     767           0 :   return -1;
     768             : }
     769             : 
     770             : int
     771          24 : ipsec_fp_ip6_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
     772             :                          ipsec_policy_t *policy)
     773             : {
     774             :   int res;
     775          24 :   ipsec_fp_5tuple_t mask = { 0 }, policy_5tuple;
     776             :   clib_bihash_kv_40_8_t kv;
     777             :   clib_bihash_kv_40_8_t result;
     778          24 :   ipsec_fp_lookup_value_t *result_val =
     779             :     (ipsec_fp_lookup_value_t *) &result.value;
     780          24 :   bool inbound = ipsec_is_policy_inbound (policy);
     781          24 :   clib_bihash_40_8_t *bihash_table =
     782           5 :     inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
     783          29 :                                  fp_spd->ip6_in_lookup_hash_idx) :
     784          19 :                     pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
     785             :                                  fp_spd->ip6_out_lookup_hash_idx);
     786             : 
     787             :   ipsec_policy_t *vp;
     788             :   u32 ii, imt;
     789             : 
     790          24 :   ipsec_fp_ip6_get_policy_mask (policy, &mask, inbound);
     791          24 :   ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
     792          24 :   fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv);
     793          24 :   res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
     794          24 :   if (res != 0)
     795           0 :     return -1;
     796             : 
     797          25 :   vec_foreach_index (ii, result_val->fp_policies_ids)
     798             :     {
     799          25 :       vp =
     800          25 :         pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
     801          25 :       if (ipsec_policy_is_equal (vp, policy))
     802             :         {
     803          24 :           if (vec_len (result_val->fp_policies_ids) == 1)
     804             :             {
     805          13 :               vec_free (result_val->fp_policies_ids);
     806          13 :               clib_bihash_add_del_40_8 (bihash_table, &result, 0);
     807             :             }
     808             :           else
     809          11 :             vec_del1 (result_val->fp_policies_ids, ii);
     810             : 
     811          24 :           vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
     812             :             {
     813          24 :               if ((fp_spd->fp_mask_ids[policy->type] + imt)->mask_type_idx ==
     814          24 :                   vp->fp_mask_type_id)
     815             :                 {
     816             : 
     817          24 :                   if ((fp_spd->fp_mask_ids[policy->type] + imt)->refcount-- ==
     818             :                       1)
     819          11 :                     vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
     820             : 
     821          24 :                   break;
     822             :                 }
     823             :             }
     824             : 
     825          24 :           ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
     826          24 :           ipsec_sa_unlock (vp->sa_index);
     827          24 :           pool_put (im->policies, vp);
     828          24 :           return 0;
     829             :         }
     830             :     }
     831           0 :   return -1;
     832             : }
     833             : 
     834             : int
     835          43 : ipsec_fp_ip4_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
     836             :                          ipsec_policy_t *policy)
     837             : {
     838             :   int res;
     839          43 :   ipsec_fp_5tuple_t mask = { 0 }, policy_5tuple;
     840             :   clib_bihash_kv_16_8_t kv;
     841             :   clib_bihash_kv_16_8_t result;
     842          43 :   ipsec_fp_lookup_value_t *result_val =
     843             :     (ipsec_fp_lookup_value_t *) &result.value;
     844          43 :   bool inbound = ipsec_is_policy_inbound (policy);
     845             :   ipsec_policy_t *vp;
     846             :   u32 ii, imt;
     847          43 :   clib_bihash_16_8_t *bihash_table =
     848          22 :     inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
     849          65 :                                  fp_spd->ip4_in_lookup_hash_idx) :
     850          21 :                     pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
     851             :                                  fp_spd->ip4_out_lookup_hash_idx);
     852             : 
     853          43 :   ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound);
     854          43 :   ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
     855          43 :   fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv);
     856          43 :   res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
     857             : 
     858          43 :   if (res != 0)
     859           0 :     return -1;
     860             : 
     861          44 :   vec_foreach_index (ii, result_val->fp_policies_ids)
     862             :     {
     863          44 :       vp =
     864          44 :         pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
     865          44 :       if (ipsec_policy_is_equal (vp, policy))
     866             :         {
     867          43 :           if (vec_len (result_val->fp_policies_ids) == 1)
     868             :             {
     869          31 :               vec_free (result_val->fp_policies_ids);
     870          31 :               clib_bihash_add_del_16_8 (bihash_table, &result, 0);
     871             :             }
     872             :           else
     873          12 :             vec_del1 (result_val->fp_policies_ids, ii);
     874             : 
     875          43 :           vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
     876             :             {
     877          43 :               if ((fp_spd->fp_mask_ids[policy->type] + imt)->mask_type_idx ==
     878          43 :                   vp->fp_mask_type_id)
     879             :                 {
     880             : 
     881          43 :                   if ((fp_spd->fp_mask_ids[policy->type] + imt)->refcount-- ==
     882             :                       1)
     883          25 :                     vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
     884             : 
     885          43 :                   break;
     886             :                 }
     887             :             }
     888          43 :           ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
     889          43 :           ipsec_sa_unlock (vp->sa_index);
     890          43 :           pool_put (im->policies, vp);
     891          43 :           return 0;
     892             :         }
     893             :     }
     894           0 :   return -1;
     895             : }
     896             : 
     897             : int
     898         134 : ipsec_fp_add_del_policy (void *fp_spd, ipsec_policy_t *policy, int is_add,
     899             :                          u32 *stat_index)
     900             : {
     901         134 :   ipsec_main_t *im = &ipsec_main;
     902             : 
     903         134 :   if (is_add)
     904          67 :     if (policy->is_ipv6)
     905          24 :       return ipsec_fp_ip6_add_policy (im, (ipsec_spd_fp_t *) fp_spd, policy,
     906             :                                       stat_index);
     907             :     else
     908          43 :       return ipsec_fp_ip4_add_policy (im, (ipsec_spd_fp_t *) fp_spd, policy,
     909             :                                       stat_index);
     910             : 
     911          67 :   else if (policy->is_ipv6)
     912             : 
     913          24 :     return ipsec_fp_ip6_del_policy (im, (ipsec_spd_fp_t *) fp_spd, policy);
     914             :   else
     915          43 :     return ipsec_fp_ip4_del_policy (im, (ipsec_spd_fp_t *) fp_spd, policy);
     916             : }
     917             : 
     918             : /*
     919             :  * fd.io coding-style-patch-verification: ON
     920             :  *
     921             :  * Local Variables:
     922             :  * eval: (c-set-style "gnu")
     923             :  * End:
     924             :  */

Generated by: LCOV version 1.14