2 *------------------------------------------------------------------
3 * Copyright (c) 2022 Intel and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
18 #ifndef IPSEC_SPD_FP_LOOKUP_H
19 #define IPSEC_SPD_FP_LOOKUP_H
21 #include <vnet/ipsec/ipsec.h>
23 static_always_inline int
24 single_rule_out_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
26 if (PREDICT_FALSE (policy->is_ipv6 != match->is_ipv6))
29 if (PREDICT_FALSE (policy->protocol != IPSEC_POLICY_PROTOCOL_ANY &&
30 (policy->protocol != match->protocol)))
36 clib_net_to_host_u32 (match->laddr.as_u32) <
37 clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32)))
40 if (PREDICT_FALSE (clib_net_to_host_u32 (match->laddr.as_u32) >
41 clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32)))
45 clib_net_to_host_u32 (match->raddr.as_u32) <
46 clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32)))
49 if (PREDICT_FALSE (clib_net_to_host_u32 (match->raddr.as_u32) >
50 clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32)))
56 if (ip6_address_compare (&match->ip6_laddr, &policy->laddr.start.ip6) <
60 if (ip6_address_compare (&policy->laddr.stop.ip6, &match->ip6_laddr) < 0)
64 if (ip6_address_compare (&match->ip6_raddr, &policy->raddr.start.ip6) <
69 if (ip6_address_compare (&policy->raddr.stop.ip6, &match->ip6_raddr) < 0)
74 if (PREDICT_FALSE ((match->protocol != IP_PROTOCOL_TCP) &&
75 (match->protocol != IP_PROTOCOL_UDP) &&
76 (match->protocol != IP_PROTOCOL_SCTP)))
81 if (match->lport < policy->lport.start)
84 if (match->lport > policy->lport.stop)
87 if (match->rport < policy->rport.start)
90 if (match->rport > policy->rport.stop)
96 static_always_inline int
97 single_rule_in_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
100 u32 sa = clib_net_to_host_u32 (match->laddr.as_u32);
101 u32 da = clib_net_to_host_u32 (match->raddr.as_u32);
103 if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
105 ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
107 if (match->spi != s->spi)
110 if (ipsec_sa_is_set_IS_TUNNEL (s))
112 if (da != clib_net_to_host_u32 (s->tunnel.t_dst.ip.ip4.as_u32))
115 if (sa != clib_net_to_host_u32 (s->tunnel.t_src.ip.ip4.as_u32))
121 if (da < clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32))
124 if (da > clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32))
127 if (sa < clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32))
130 if (sa > clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32))
136 static_always_inline u32
137 ipsec_fp_in_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
138 ipsec_policy_t **policies, u32 n)
140 u32 last_priority[n];
143 ipsec_fp_mask_type_entry_t *mte;
144 ipsec_fp_mask_id_t *mti;
145 ipsec_fp_5tuple_t *match = tuples;
146 ipsec_policy_t *policy;
148 clib_bihash_kv_40_8_t kv;
149 /* result of the lookup */
150 clib_bihash_kv_40_8_t result;
151 ipsec_fp_lookup_value_t *result_val =
152 (ipsec_fp_lookup_value_t *) &result.value;
153 u64 *pkey, *pmatch, *pmask;
154 ipsec_main_t *im = &ipsec_main;
155 ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
156 ipsec_fp_mask_id_t *mask_type_ids = pspd_fp->fp_mask_ids[match->action];
157 clib_bihash_40_8_t *bihash_table = pool_elt_at_index (
158 im->fp_ip6_lookup_hashes_pool, pspd_fp->ip6_in_lookup_hash_idx);
160 /* clear the list of matched policies pointers */
161 clib_memset (policies, 0, n * sizeof (*policies));
162 clib_memset (last_priority, 0, n * sizeof (u32));
166 vec_foreach (mti, mask_type_ids)
168 mte = im->fp_mask_types + mti->mask_type_idx;
169 if (mte->mask.action == 0)
172 pmatch = (u64 *) match->kv_40_8.key;
173 pmask = (u64 *) mte->mask.kv_40_8.key;
174 pkey = (u64 *) kv.key;
176 *pkey++ = *pmatch++ & *pmask++;
177 *pkey++ = *pmatch++ & *pmask++;
178 *pkey++ = *pmatch++ & *pmask++;
179 *pkey++ = *pmatch++ & *pmask++;
180 *pkey = *pmatch & *pmask;
183 clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
184 /* lookup the hash by each packet in the burst for this mask. */
188 /* There is a hit in the hash table. */
189 /* Find the policy with highest priority. */
190 /* Store the lookup results in a dedicated array. */
192 if (vec_len (result_val->fp_policies_ids) > 1)
195 vec_foreach (policy_id, result_val->fp_policies_ids)
197 policy = im->policies + *policy_id;
199 if ((last_priority[i] < policy->priority) &&
200 (single_rule_in_match_5tuple (policy, match)))
202 last_priority[i] = policy->priority;
203 if (policies[i] == 0)
205 policies[i] = policy;
212 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
213 policy_id = result_val->fp_policies_ids;
214 policy = im->policies + *policy_id;
215 if ((last_priority[i] < policy->priority) &&
216 (single_rule_in_match_5tuple (policy, match)))
218 last_priority[i] = policy->priority;
219 if (policies[i] == 0)
221 policies[i] = policy;
234 static_always_inline u32
235 ipsec_fp_in_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
236 ipsec_policy_t **policies, u32 n)
239 u32 last_priority[n];
242 ipsec_fp_mask_type_entry_t *mte;
243 ipsec_fp_mask_id_t *mti;
244 ipsec_fp_5tuple_t *match = tuples;
245 ipsec_policy_t *policy;
247 clib_bihash_kv_16_8_t kv;
248 /* result of the lookup */
249 clib_bihash_kv_16_8_t result;
250 ipsec_fp_lookup_value_t *result_val =
251 (ipsec_fp_lookup_value_t *) &result.value;
252 u64 *pkey, *pmatch, *pmask;
253 ipsec_main_t *im = &ipsec_main;
254 ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
255 ipsec_fp_mask_id_t *mask_type_ids = pspd_fp->fp_mask_ids[match->action];
256 clib_bihash_16_8_t *bihash_table = pool_elt_at_index (
257 im->fp_ip4_lookup_hashes_pool, pspd_fp->ip4_in_lookup_hash_idx);
259 /* clear the list of matched policies pointers */
260 clib_memset (policies, 0, n * sizeof (*policies));
261 clib_memset (last_priority, 0, n * sizeof (u32));
265 vec_foreach (mti, mask_type_ids)
267 mte = im->fp_mask_types + mti->mask_type_idx;
268 if (mte->mask.action == 0)
270 pmatch = (u64 *) match->kv_16_8.key;
271 pmask = (u64 *) mte->mask.kv_16_8.key;
272 pkey = (u64 *) kv.key;
274 *pkey++ = *pmatch++ & *pmask++;
275 *pkey = *pmatch & *pmask;
278 clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
279 /* lookup the hash by each packet in the burst for this mask. */
283 /* There is a hit in the hash table. */
284 /* Find the policy with highest priority. */
285 /* Store the lookup results in a dedicated array. */
287 if (vec_len (result_val->fp_policies_ids) > 1)
290 vec_foreach (policy_id, result_val->fp_policies_ids)
292 policy = im->policies + *policy_id;
294 if ((last_priority[i] < policy->priority) &&
295 (single_rule_in_match_5tuple (policy, match)))
297 last_priority[i] = policy->priority;
298 if (policies[i] == 0)
300 policies[i] = policy;
307 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
308 policy_id = result_val->fp_policies_ids;
309 policy = im->policies + *policy_id;
310 if ((last_priority[i] < policy->priority) &&
311 (single_rule_in_match_5tuple (policy, match)))
313 last_priority[i] = policy->priority;
314 if (policies[i] == 0)
316 policies[i] = policy;
330 * @brief function handler to perform lookup in fastpath SPD
331 * for inbound traffic burst of n packets
334 static_always_inline u32
335 ipsec_fp_in_policy_match_n (void *spd_fp, u8 is_ipv6,
336 ipsec_fp_5tuple_t *tuples,
337 ipsec_policy_t **policies, u32 n)
340 return ipsec_fp_in_ip6_policy_match_n (spd_fp, tuples, policies, n);
342 return ipsec_fp_in_ip4_policy_match_n (spd_fp, tuples, policies, n);
345 static_always_inline u32
346 ipsec_fp_out_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
347 ipsec_policy_t **policies, u32 *ids, u32 n)
350 u32 last_priority[n];
353 ipsec_fp_mask_type_entry_t *mte;
354 ipsec_fp_mask_id_t *mti;
355 ipsec_fp_5tuple_t *match = tuples;
356 ipsec_policy_t *policy;
359 clib_bihash_kv_40_8_t kv;
360 /* result of the lookup */
361 clib_bihash_kv_40_8_t result;
362 ipsec_fp_lookup_value_t *result_val =
363 (ipsec_fp_lookup_value_t *) &result.value;
364 u64 *pkey, *pmatch, *pmask;
365 ipsec_main_t *im = &ipsec_main;
366 ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
367 ipsec_fp_mask_id_t *mask_type_ids =
368 pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP6_OUTBOUND];
369 clib_bihash_40_8_t *bihash_table = pool_elt_at_index (
370 im->fp_ip6_lookup_hashes_pool, pspd_fp->ip6_out_lookup_hash_idx);
372 /*clear the list of matched policies pointers */
373 clib_memset (policies, 0, n * sizeof (*policies));
374 clib_memset (last_priority, 0, n * sizeof (u32));
378 vec_foreach (mti, mask_type_ids)
380 mte = im->fp_mask_types + mti->mask_type_idx;
381 if (mte->mask.action != 0)
384 pmatch = (u64 *) match->kv_40_8.key;
385 pmask = (u64 *) mte->mask.kv_40_8.key;
386 pkey = (u64 *) kv.key;
388 *pkey++ = *pmatch++ & *pmask++;
389 *pkey++ = *pmatch++ & *pmask++;
390 *pkey++ = *pmatch++ & *pmask++;
391 *pkey++ = *pmatch++ & *pmask++;
392 *pkey = *pmatch & *pmask;
395 clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
396 /* lookup the hash by each packet in the burst for this mask. */
400 /* There is a hit in the hash table. */
401 /* Find the policy with highest priority. */
402 /* Store the lookup results in a dedicated array. */
404 if (vec_len (result_val->fp_policies_ids) > 1)
407 vec_foreach (policy_id, result_val->fp_policies_ids)
409 policy = im->policies + *policy_id;
411 if (single_rule_out_match_5tuple (policy, match))
413 if (last_priority[i] < policy->priority)
415 last_priority[i] = policy->priority;
416 if (policies[i] == 0)
418 policies[i] = policy;
427 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
428 policy_id = result_val->fp_policies_ids;
429 policy = im->policies + *policy_id;
430 if (single_rule_out_match_5tuple (policy, match))
432 if (last_priority[i] < policy->priority)
434 last_priority[i] = policy->priority;
435 if (policies[i] == 0)
437 policies[i] = policy;
451 static_always_inline u32
452 ipsec_fp_out_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
453 ipsec_policy_t **policies, u32 *ids, u32 n)
456 u32 last_priority[n];
459 ipsec_fp_mask_type_entry_t *mte;
460 ipsec_fp_mask_id_t *mti;
461 ipsec_fp_5tuple_t *match = tuples;
462 ipsec_policy_t *policy;
465 clib_bihash_kv_16_8_t kv;
466 /* result of the lookup */
467 clib_bihash_kv_16_8_t result;
468 ipsec_fp_lookup_value_t *result_val =
469 (ipsec_fp_lookup_value_t *) &result.value;
470 u64 *pkey, *pmatch, *pmask;
471 ipsec_main_t *im = &ipsec_main;
472 ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
473 ipsec_fp_mask_id_t *mask_type_ids =
474 pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP4_OUTBOUND];
475 clib_bihash_16_8_t *bihash_table = pool_elt_at_index (
476 im->fp_ip4_lookup_hashes_pool, pspd_fp->ip4_out_lookup_hash_idx);
478 /* clear the list of matched policies pointers */
479 clib_memset (policies, 0, n * sizeof (*policies));
480 clib_memset (last_priority, 0, n * sizeof (u32));
484 vec_foreach (mti, mask_type_ids)
486 mte = im->fp_mask_types + mti->mask_type_idx;
487 if (mte->mask.action != 0)
490 pmatch = (u64 *) match->kv_16_8.key;
491 pmask = (u64 *) mte->mask.kv_16_8.key;
492 pkey = (u64 *) kv.key;
494 *pkey++ = *pmatch++ & *pmask++;
495 *pkey = *pmatch & *pmask;
498 clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
499 /* lookup the hash by each packet in the burst for this mask. */
503 /* There is a hit in the hash table. */
504 /* Find the policy with highest priority. */
505 /* Store the lookup results in a dedicated array. */
507 if (vec_len (result_val->fp_policies_ids) > 1)
510 vec_foreach (policy_id, result_val->fp_policies_ids)
512 policy = im->policies + *policy_id;
514 if ((last_priority[i] < policy->priority) &&
515 (single_rule_out_match_5tuple (policy, match)))
517 last_priority[i] = policy->priority;
518 if (policies[i] == 0)
520 policies[i] = policy;
528 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
529 policy_id = result_val->fp_policies_ids;
530 policy = im->policies + *policy_id;
531 if ((last_priority[i] < policy->priority) &&
532 (single_rule_out_match_5tuple (policy, match)))
534 last_priority[i] = policy->priority;
535 if (policies[i] == 0)
537 policies[i] = policy;
552 * @brief function handler to perform lookup in fastpath SPD
553 * for outbound traffic burst of n packets
554 * returns number of successfully matched policies
557 static_always_inline u32
558 ipsec_fp_out_policy_match_n (void *spd_fp, u8 is_ipv6,
559 ipsec_fp_5tuple_t *tuples,
560 ipsec_policy_t **policies, u32 *ids, u32 n)
564 return ipsec_fp_out_ip6_policy_match_n (spd_fp, tuples, policies, ids, n);
566 return ipsec_fp_out_ip4_policy_match_n (spd_fp, tuples, policies, ids, n);
569 #endif /* !IPSEC_SPD_FP_LOOKUP_H */