ipsec: perf improvement of ipsec4_input_node using flow cache
[vpp.git] / src / vnet / ipsec / ipsec_spd_policy.c
index d4a32e3..72da408 100644 (file)
@@ -123,6 +123,10 @@ ipsec_policy_mk_type (bool is_outbound,
                   IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS);
          return (0);
        case IPSEC_POLICY_ACTION_DISCARD:
+         *type = (is_ipv6 ?
+                  IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD :
+                  IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD);
+         return (0);
        case IPSEC_POLICY_ACTION_RESOLVE:
          break;
        }
@@ -142,17 +146,6 @@ ipsec_add_del_policy (vlib_main_t * vm,
   u32 spd_index;
   uword *p;
 
-  clib_warning ("policy-id %u priority %d type %U", policy->id,
-               policy->priority, format_ipsec_policy_type, policy->type);
-
-  if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
-    {
-      p = hash_get (im->sa_index_by_sa_id, policy->sa_id);
-      if (!p)
-       return VNET_API_ERROR_SYSCALL_ERROR_1;
-      policy->sa_index = p[0];
-    }
-
   p = hash_get (im->spd_index_by_spd_id, policy->id);
 
   if (!p)
@@ -163,10 +156,69 @@ ipsec_add_del_policy (vlib_main_t * vm,
   if (!spd)
     return VNET_API_ERROR_SYSCALL_ERROR_1;
 
+  if (im->output_flow_cache_flag && !policy->is_ipv6 &&
+      policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND)
+    {
+      /*
+       * Flow cache entry is valid only when epoch_count value in control
+       * plane and data plane match. Otherwise, flow cache entry is considered
+       * stale. To avoid the race condition of using old epoch_count value
+       * in data plane after the roll over of epoch_count in control plane,
+       * entire flow cache is reset.
+       */
+      if (im->epoch_count == 0xFFFFFFFF)
+       {
+         /* Reset all the entries in flow cache */
+         clib_memset_u8 (im->ipsec4_out_spd_hash_tbl, 0,
+                         im->ipsec4_out_spd_hash_num_buckets *
+                           (sizeof (*(im->ipsec4_out_spd_hash_tbl))));
+       }
+      /* Increment epoch counter by 1 */
+      clib_atomic_fetch_add_relax (&im->epoch_count, 1);
+      /* Reset spd flow cache counter since all old entries are stale */
+      clib_atomic_store_relax_n (&im->ipsec4_out_spd_flow_cache_entries, 0);
+    }
+
+  if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
+       policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
+       policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD) &&
+      im->input_flow_cache_flag && !policy->is_ipv6)
+    {
+      /*
+       * Flow cache entry is valid only when input_epoch_count value in control
+       * plane and data plane match. Otherwise, flow cache entry is considered
+       * stale. To avoid the race condition of using old input_epoch_count
+       * value in data plane after the roll over of input_epoch_count in
+       * control plane, entire flow cache is reset.
+       */
+      if (im->input_epoch_count == 0xFFFFFFFF)
+       {
+         /* Reset all the entries in flow cache */
+         clib_memset_u8 (im->ipsec4_in_spd_hash_tbl, 0,
+                         im->ipsec4_in_spd_hash_num_buckets *
+                           (sizeof (*(im->ipsec4_in_spd_hash_tbl))));
+       }
+      /* Increment epoch counter by 1 */
+      clib_atomic_fetch_add_relax (&im->input_epoch_count, 1);
+      /* Reset spd flow cache counter since all old entries are stale */
+      im->ipsec4_in_spd_flow_cache_entries = 0;
+    }
+
   if (is_add)
     {
       u32 policy_index;
 
+      if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
+       {
+         index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
+
+         if (INDEX_INVALID == sa_index)
+           return VNET_API_ERROR_SYSCALL_ERROR_1;
+         policy->sa_index = sa_index;
+       }
+      else
+       policy->sa_index = INDEX_INVALID;
+
       pool_get (im->policies, vp);
       clib_memcpy (vp, policy, sizeof (*vp));
       policy_index = vp - im->policies;
@@ -182,23 +234,20 @@ ipsec_add_del_policy (vlib_main_t * vm,
     }
   else
     {
-      ipsec_spd_policy_type_t ptype;
       u32 ii;
 
-      FOR_EACH_IPSEC_SPD_POLICY_TYPE (ptype)
+      vec_foreach_index (ii, (spd->policies[policy->type]))
       {
-       vec_foreach_index (ii, (spd->policies[ptype]))
-       {
-         vp = pool_elt_at_index (im->policies, spd->policies[ptype][ii]);
-         if (ipsec_policy_is_equal (vp, policy))
-           {
-             vec_del1 (spd->policies[ptype], ii);
-             pool_put (im->policies, vp);
-             goto done;
-           }
-       }
+       vp = pool_elt_at_index (im->policies,
+                               spd->policies[policy->type][ii]);
+       if (ipsec_policy_is_equal (vp, policy))
+         {
+           vec_delete (spd->policies[policy->type], 1, ii);
+           ipsec_sa_unlock (vp->sa_index);
+           pool_put (im->policies, vp);
+           break;
+         }
       }
-    done:;
     }
 
   return 0;