ipsec: introduce fast path ipv6 inbound matching
[vpp.git] / src / vnet / ipsec / ipsec_spd_fp_lookup.h
index e4ef194..a372ac7 100644 (file)
@@ -20,9 +20,8 @@
 
 #include <vnet/ipsec/ipsec.h>
 
-
 static_always_inline int
-single_rule_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
+single_rule_out_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
 {
   if (PREDICT_FALSE (policy->is_ipv6 != match->is_ipv6))
     return (0);
@@ -138,7 +137,98 @@ static_always_inline u32
 ipsec_fp_in_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
                                ipsec_policy_t **policies, u32 n)
 {
-  return 0;
+  u32 last_priority[n];
+  u32 i = 0;
+  u32 counter = 0;
+  ipsec_fp_mask_type_entry_t *mte;
+  ipsec_fp_mask_id_t *mti;
+  ipsec_fp_5tuple_t *match = tuples;
+  ipsec_policy_t *policy;
+  u32 n_left = n;
+  clib_bihash_kv_40_8_t kv;
+  /* result of the lookup */
+  clib_bihash_kv_40_8_t result;
+  ipsec_fp_lookup_value_t *result_val =
+    (ipsec_fp_lookup_value_t *) &result.value;
+  u64 *pkey, *pmatch, *pmask;
+  ipsec_main_t *im = &ipsec_main;
+  ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
+  ipsec_fp_mask_id_t *mask_type_ids = pspd_fp->fp_mask_ids[match->action];
+  clib_bihash_40_8_t *bihash_table = pool_elt_at_index (
+    im->fp_ip6_lookup_hashes_pool, pspd_fp->ip6_in_lookup_hash_idx);
+
+  /* clear the list of matched policies pointers */
+  clib_memset (policies, 0, n * sizeof (*policies));
+  clib_memset (last_priority, 0, n * sizeof (u32));
+  n_left = n;
+  while (n_left)
+    {
+      vec_foreach (mti, mask_type_ids)
+       {
+         mte = im->fp_mask_types + mti->mask_type_idx;
+         if (mte->mask.action == 0)
+           continue;
+
+         pmatch = (u64 *) match->kv_40_8.key;
+         pmask = (u64 *) mte->mask.kv_40_8.key;
+         pkey = (u64 *) kv.key;
+
+         *pkey++ = *pmatch++ & *pmask++;
+         *pkey++ = *pmatch++ & *pmask++;
+         *pkey++ = *pmatch++ & *pmask++;
+         *pkey++ = *pmatch++ & *pmask++;
+         *pkey = *pmatch & *pmask;
+
+         int res =
+           clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
+         /* lookup the hash by each packet in the burst for this mask. */
+
+         if (res == 0)
+           {
+             /* There is a hit in the hash table. */
+             /* Find the policy with highest priority. */
+             /* Store the lookup results in a dedicated array. */
+
+             if (vec_len (result_val->fp_policies_ids) > 1)
+               {
+                 u32 *policy_id;
+                 vec_foreach (policy_id, result_val->fp_policies_ids)
+                   {
+                     policy = im->policies + *policy_id;
+
+                     if ((last_priority[i] < policy->priority) &&
+                         (single_rule_in_match_5tuple (policy, match)))
+                       {
+                         last_priority[i] = policy->priority;
+                         if (policies[i] == 0)
+                           counter++;
+                         policies[i] = policy;
+                       }
+                   }
+               }
+             else
+               {
+                 u32 *policy_id;
+                 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
+                 policy_id = result_val->fp_policies_ids;
+                 policy = im->policies + *policy_id;
+                 if ((last_priority[i] < policy->priority) &&
+                     (single_rule_in_match_5tuple (policy, match)))
+                   {
+                     last_priority[i] = policy->priority;
+                     if (policies[i] == 0)
+                       counter++;
+                     policies[i] = policy;
+                   }
+               }
+           }
+       }
+
+      i++;
+      n_left--;
+      match++;
+    }
+  return counter;
 }
 
 static_always_inline u32
@@ -253,7 +343,7 @@ ipsec_fp_in_policy_match_n (void *spd_fp, u8 is_ipv6,
 }
 
 static_always_inline u32
-ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
+ipsec_fp_out_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
                                 ipsec_policy_t **policies, u32 *ids, u32 n)
 
 {
@@ -288,6 +378,8 @@ ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
       vec_foreach (mti, mask_type_ids)
        {
          mte = im->fp_mask_types + mti->mask_type_idx;
+         if (mte->mask.action != 0)
+           continue;
 
          pmatch = (u64 *) match->kv_40_8.key;
          pmask = (u64 *) mte->mask.kv_40_8.key;
@@ -316,7 +408,7 @@ ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
                    {
                      policy = im->policies + *policy_id;
 
-                     if (single_rule_match_5tuple (policy, match))
+                     if (single_rule_out_match_5tuple (policy, match))
                        {
                          if (last_priority[i] < policy->priority)
                            {
@@ -335,7 +427,7 @@ ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
                  ASSERT (vec_len (result_val->fp_policies_ids) == 1);
                  policy_id = result_val->fp_policies_ids;
                  policy = im->policies + *policy_id;
-                 if (single_rule_match_5tuple (policy, match))
+                 if (single_rule_out_match_5tuple (policy, match))
                    {
                      if (last_priority[i] < policy->priority)
                        {
@@ -357,7 +449,7 @@ ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
 }
 
 static_always_inline u32
-ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
+ipsec_fp_out_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
                                 ipsec_policy_t **policies, u32 *ids, u32 n)
 
 {
@@ -420,7 +512,7 @@ ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
                      policy = im->policies + *policy_id;
 
                      if ((last_priority[i] < policy->priority) &&
-                         (single_rule_match_5tuple (policy, match)))
+                         (single_rule_out_match_5tuple (policy, match)))
                        {
                          last_priority[i] = policy->priority;
                          if (policies[i] == 0)
@@ -437,7 +529,7 @@ ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
                  policy_id = result_val->fp_policies_ids;
                  policy = im->policies + *policy_id;
                  if ((last_priority[i] < policy->priority) &&
-                     (single_rule_match_5tuple (policy, match)))
+                     (single_rule_out_match_5tuple (policy, match)))
                    {
                      last_priority[i] = policy->priority;
                      if (policies[i] == 0)
@@ -469,9 +561,9 @@ ipsec_fp_out_policy_match_n (void *spd_fp, u8 is_ipv6,
 
 {
   if (is_ipv6)
-    return ipsec_fp_ip6_out_policy_match_n (spd_fp, tuples, policies, ids, n);
+    return ipsec_fp_out_ip6_policy_match_n (spd_fp, tuples, policies, ids, n);
   else
-    return ipsec_fp_ip4_out_policy_match_n (spd_fp, tuples, policies, ids, n);
+    return ipsec_fp_out_ip4_policy_match_n (spd_fp, tuples, policies, ids, n);
 }
 
 #endif /* !IPSEC_SPD_FP_LOOKUP_H */