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>
24 static_always_inline int
25 single_rule_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
27 if (PREDICT_FALSE (policy->is_ipv6 != match->is_ipv6))
30 if (PREDICT_FALSE (policy->protocol != IPSEC_POLICY_PROTOCOL_ANY &&
31 (policy->protocol != match->protocol)))
37 clib_net_to_host_u32 (match->laddr.as_u32) <
38 clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32)))
41 if (PREDICT_FALSE (clib_net_to_host_u32 (match->laddr.as_u32) >
42 clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32)))
46 clib_net_to_host_u32 (match->raddr.as_u32) <
47 clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32)))
50 if (PREDICT_FALSE (clib_net_to_host_u32 (match->raddr.as_u32) >
51 clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32)))
57 if (ip6_address_compare (&match->ip6_laddr, &policy->laddr.start.ip6) <
61 if (ip6_address_compare (&policy->laddr.stop.ip6, &match->ip6_laddr) < 0)
65 if (ip6_address_compare (&match->ip6_raddr, &policy->raddr.start.ip6) <
70 if (ip6_address_compare (&policy->raddr.stop.ip6, &match->ip6_raddr) < 0)
75 if (PREDICT_FALSE ((match->protocol != IP_PROTOCOL_TCP) &&
76 (match->protocol != IP_PROTOCOL_UDP) &&
77 (match->protocol != IP_PROTOCOL_SCTP)))
82 if (match->lport < policy->lport.start)
85 if (match->lport > policy->lport.stop)
88 if (match->rport < policy->rport.start)
91 if (match->rport > policy->rport.stop)
97 static_always_inline int
98 single_rule_in_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
101 u32 sa = clib_net_to_host_u32 (match->laddr.as_u32);
102 u32 da = clib_net_to_host_u32 (match->raddr.as_u32);
104 if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
106 ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
108 if (match->spi != s->spi)
111 if (ipsec_sa_is_set_IS_TUNNEL (s))
113 if (da != clib_net_to_host_u32 (s->tunnel.t_dst.ip.ip4.as_u32))
116 if (sa != clib_net_to_host_u32 (s->tunnel.t_src.ip.ip4.as_u32))
122 if (da < clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32))
125 if (da > clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32))
128 if (sa < clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32))
131 if (sa > clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32))
137 static_always_inline u32
138 ipsec_fp_in_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
139 ipsec_policy_t **policies, u32 n)
144 static_always_inline u32
145 ipsec_fp_in_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
146 ipsec_policy_t **policies, u32 n)
149 u32 last_priority[n];
152 ipsec_fp_mask_type_entry_t *mte;
153 ipsec_fp_mask_id_t *mti;
154 ipsec_fp_5tuple_t *match = tuples;
155 ipsec_policy_t *policy;
157 clib_bihash_kv_16_8_t kv;
158 /* result of the lookup */
159 clib_bihash_kv_16_8_t result;
160 ipsec_fp_lookup_value_t *result_val =
161 (ipsec_fp_lookup_value_t *) &result.value;
162 u64 *pkey, *pmatch, *pmask;
163 ipsec_main_t *im = &ipsec_main;
164 ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
165 ipsec_fp_mask_id_t *mask_type_ids = pspd_fp->fp_mask_ids[match->action];
166 clib_bihash_16_8_t *bihash_table = pool_elt_at_index (
167 im->fp_ip4_lookup_hashes_pool, pspd_fp->ip4_in_lookup_hash_idx);
169 /* clear the list of matched policies pointers */
170 clib_memset (policies, 0, n * sizeof (*policies));
171 clib_memset (last_priority, 0, n * sizeof (u32));
175 vec_foreach (mti, mask_type_ids)
177 mte = im->fp_mask_types + mti->mask_type_idx;
178 if (mte->mask.action == 0)
180 pmatch = (u64 *) match->kv_16_8.key;
181 pmask = (u64 *) mte->mask.kv_16_8.key;
182 pkey = (u64 *) kv.key;
184 *pkey++ = *pmatch++ & *pmask++;
185 *pkey = *pmatch & *pmask;
188 clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
189 /* lookup the hash by each packet in the burst for this mask. */
193 /* There is a hit in the hash table. */
194 /* Find the policy with highest priority. */
195 /* Store the lookup results in a dedicated array. */
197 if (vec_len (result_val->fp_policies_ids) > 1)
200 vec_foreach (policy_id, result_val->fp_policies_ids)
202 policy = im->policies + *policy_id;
204 if ((last_priority[i] < policy->priority) &&
205 (single_rule_in_match_5tuple (policy, match)))
207 last_priority[i] = policy->priority;
208 if (policies[i] == 0)
210 policies[i] = policy;
217 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
218 policy_id = result_val->fp_policies_ids;
219 policy = im->policies + *policy_id;
220 if ((last_priority[i] < policy->priority) &&
221 (single_rule_in_match_5tuple (policy, match)))
223 last_priority[i] = policy->priority;
224 if (policies[i] == 0)
226 policies[i] = policy;
240 * @brief function handler to perform lookup in fastpath SPD
241 * for inbound traffic burst of n packets
244 static_always_inline u32
245 ipsec_fp_in_policy_match_n (void *spd_fp, u8 is_ipv6,
246 ipsec_fp_5tuple_t *tuples,
247 ipsec_policy_t **policies, u32 n)
250 return ipsec_fp_in_ip6_policy_match_n (spd_fp, tuples, policies, n);
252 return ipsec_fp_in_ip4_policy_match_n (spd_fp, tuples, policies, n);
255 static_always_inline u32
256 ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
257 ipsec_policy_t **policies, u32 *ids, u32 n)
260 u32 last_priority[n];
263 ipsec_fp_mask_type_entry_t *mte;
264 ipsec_fp_mask_id_t *mti;
265 ipsec_fp_5tuple_t *match = tuples;
266 ipsec_policy_t *policy;
269 clib_bihash_kv_40_8_t kv;
270 /* result of the lookup */
271 clib_bihash_kv_40_8_t result;
272 ipsec_fp_lookup_value_t *result_val =
273 (ipsec_fp_lookup_value_t *) &result.value;
274 u64 *pkey, *pmatch, *pmask;
275 ipsec_main_t *im = &ipsec_main;
276 ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
277 ipsec_fp_mask_id_t *mask_type_ids =
278 pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP6_OUTBOUND];
279 clib_bihash_40_8_t *bihash_table = pool_elt_at_index (
280 im->fp_ip6_lookup_hashes_pool, pspd_fp->ip6_out_lookup_hash_idx);
282 /*clear the list of matched policies pointers */
283 clib_memset (policies, 0, n * sizeof (*policies));
284 clib_memset (last_priority, 0, n * sizeof (u32));
288 vec_foreach (mti, mask_type_ids)
290 mte = im->fp_mask_types + mti->mask_type_idx;
292 pmatch = (u64 *) match->kv_40_8.key;
293 pmask = (u64 *) mte->mask.kv_40_8.key;
294 pkey = (u64 *) kv.key;
296 *pkey++ = *pmatch++ & *pmask++;
297 *pkey++ = *pmatch++ & *pmask++;
298 *pkey++ = *pmatch++ & *pmask++;
299 *pkey++ = *pmatch++ & *pmask++;
300 *pkey = *pmatch & *pmask;
303 clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
304 /* lookup the hash by each packet in the burst for this mask. */
308 /* There is a hit in the hash table. */
309 /* Find the policy with highest priority. */
310 /* Store the lookup results in a dedicated array. */
312 if (vec_len (result_val->fp_policies_ids) > 1)
315 vec_foreach (policy_id, result_val->fp_policies_ids)
317 policy = im->policies + *policy_id;
319 if (single_rule_match_5tuple (policy, match))
321 if (last_priority[i] < policy->priority)
323 last_priority[i] = policy->priority;
324 if (policies[i] == 0)
326 policies[i] = policy;
335 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
336 policy_id = result_val->fp_policies_ids;
337 policy = im->policies + *policy_id;
338 if (single_rule_match_5tuple (policy, match))
340 if (last_priority[i] < policy->priority)
342 last_priority[i] = policy->priority;
343 if (policies[i] == 0)
345 policies[i] = policy;
359 static_always_inline u32
360 ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
361 ipsec_policy_t **policies, u32 *ids, u32 n)
364 u32 last_priority[n];
367 ipsec_fp_mask_type_entry_t *mte;
368 ipsec_fp_mask_id_t *mti;
369 ipsec_fp_5tuple_t *match = tuples;
370 ipsec_policy_t *policy;
373 clib_bihash_kv_16_8_t kv;
374 /* result of the lookup */
375 clib_bihash_kv_16_8_t result;
376 ipsec_fp_lookup_value_t *result_val =
377 (ipsec_fp_lookup_value_t *) &result.value;
378 u64 *pkey, *pmatch, *pmask;
379 ipsec_main_t *im = &ipsec_main;
380 ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
381 ipsec_fp_mask_id_t *mask_type_ids =
382 pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP4_OUTBOUND];
383 clib_bihash_16_8_t *bihash_table = pool_elt_at_index (
384 im->fp_ip4_lookup_hashes_pool, pspd_fp->ip4_out_lookup_hash_idx);
386 /* clear the list of matched policies pointers */
387 clib_memset (policies, 0, n * sizeof (*policies));
388 clib_memset (last_priority, 0, n * sizeof (u32));
392 vec_foreach (mti, mask_type_ids)
394 mte = im->fp_mask_types + mti->mask_type_idx;
395 if (mte->mask.action != 0)
398 pmatch = (u64 *) match->kv_16_8.key;
399 pmask = (u64 *) mte->mask.kv_16_8.key;
400 pkey = (u64 *) kv.key;
402 *pkey++ = *pmatch++ & *pmask++;
403 *pkey = *pmatch & *pmask;
406 clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
407 /* lookup the hash by each packet in the burst for this mask. */
411 /* There is a hit in the hash table. */
412 /* Find the policy with highest priority. */
413 /* Store the lookup results in a dedicated array. */
415 if (vec_len (result_val->fp_policies_ids) > 1)
418 vec_foreach (policy_id, result_val->fp_policies_ids)
420 policy = im->policies + *policy_id;
422 if ((last_priority[i] < policy->priority) &&
423 (single_rule_match_5tuple (policy, match)))
425 last_priority[i] = policy->priority;
426 if (policies[i] == 0)
428 policies[i] = policy;
436 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
437 policy_id = result_val->fp_policies_ids;
438 policy = im->policies + *policy_id;
439 if ((last_priority[i] < policy->priority) &&
440 (single_rule_match_5tuple (policy, match)))
442 last_priority[i] = policy->priority;
443 if (policies[i] == 0)
445 policies[i] = policy;
460 * @brief function handler to perform lookup in fastpath SPD
461 * for outbound traffic burst of n packets
462 * returns number of successfully matched policies
465 static_always_inline u32
466 ipsec_fp_out_policy_match_n (void *spd_fp, u8 is_ipv6,
467 ipsec_fp_5tuple_t *tuples,
468 ipsec_policy_t **policies, u32 *ids, u32 n)
472 return ipsec_fp_ip6_out_policy_match_n (spd_fp, tuples, policies, ids, n);
474 return ipsec_fp_ip4_out_policy_match_n (spd_fp, tuples, policies, ids, n);
477 #endif /* !IPSEC_SPD_FP_LOOKUP_H */