Line data Source code
1 : /*
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:
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
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 : *------------------------------------------------------------------
16 : */
17 :
18 : #ifndef IPSEC_SPD_FP_LOOKUP_H
19 : #define IPSEC_SPD_FP_LOOKUP_H
20 :
21 : #include <vnet/ipsec/ipsec.h>
22 :
23 : static_always_inline int
24 130 : single_rule_out_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
25 : {
26 130 : if (PREDICT_FALSE (policy->is_ipv6 != match->is_ipv6))
27 0 : return (0);
28 :
29 130 : if (PREDICT_FALSE (policy->protocol != IPSEC_POLICY_PROTOCOL_ANY &&
30 : (policy->protocol != match->protocol)))
31 0 : return (0);
32 :
33 130 : if (!policy->is_ipv6)
34 : {
35 70 : if (PREDICT_FALSE (
36 : clib_net_to_host_u32 (match->laddr.as_u32) <
37 : clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32)))
38 0 : return (0);
39 :
40 70 : if (PREDICT_FALSE (clib_net_to_host_u32 (match->laddr.as_u32) >
41 : clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32)))
42 0 : return (0);
43 :
44 70 : if (PREDICT_FALSE (
45 : clib_net_to_host_u32 (match->raddr.as_u32) <
46 : clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32)))
47 0 : return (0);
48 :
49 70 : if (PREDICT_FALSE (clib_net_to_host_u32 (match->raddr.as_u32) >
50 : clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32)))
51 0 : return (0);
52 : }
53 : else
54 : {
55 :
56 60 : if (ip6_address_compare (&match->ip6_laddr, &policy->laddr.start.ip6) <
57 : 0)
58 0 : return (0);
59 :
60 60 : if (ip6_address_compare (&policy->laddr.stop.ip6, &match->ip6_laddr) < 0)
61 :
62 0 : return (0);
63 :
64 60 : if (ip6_address_compare (&match->ip6_raddr, &policy->raddr.start.ip6) <
65 : 0)
66 :
67 0 : return (0);
68 :
69 60 : if (ip6_address_compare (&policy->raddr.stop.ip6, &match->ip6_raddr) < 0)
70 :
71 0 : return (0);
72 : }
73 :
74 130 : if (PREDICT_FALSE ((match->protocol != IP_PROTOCOL_TCP) &&
75 : (match->protocol != IP_PROTOCOL_UDP) &&
76 : (match->protocol != IP_PROTOCOL_SCTP)))
77 : {
78 0 : return (1);
79 : }
80 :
81 130 : if (match->lport < policy->lport.start)
82 0 : return (0);
83 :
84 130 : if (match->lport > policy->lport.stop)
85 0 : return (0);
86 :
87 130 : if (match->rport < policy->rport.start)
88 0 : return (0);
89 :
90 130 : if (match->rport > policy->rport.stop)
91 0 : return (0);
92 :
93 130 : return (1);
94 : }
95 :
96 : static_always_inline int
97 75 : single_rule_in_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
98 : {
99 :
100 75 : u32 da = clib_net_to_host_u32 (match->laddr.as_u32);
101 75 : u32 sa = clib_net_to_host_u32 (match->raddr.as_u32);
102 :
103 75 : if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
104 : {
105 10 : ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
106 :
107 10 : if (match->spi != s->spi)
108 0 : return (0);
109 :
110 10 : if (ipsec_sa_is_set_IS_TUNNEL (s))
111 : {
112 0 : if (da != clib_net_to_host_u32 (s->tunnel.t_dst.ip.ip4.as_u32))
113 0 : return (0);
114 :
115 0 : if (sa != clib_net_to_host_u32 (s->tunnel.t_src.ip.ip4.as_u32))
116 0 : return (0);
117 : }
118 : }
119 : else
120 : {
121 65 : if (sa < clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32))
122 0 : return (0);
123 :
124 65 : if (sa > clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32))
125 0 : return (0);
126 :
127 65 : if (da < clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32))
128 0 : return (0);
129 :
130 65 : if (da > clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32))
131 0 : return (0);
132 : }
133 75 : return (1);
134 : }
135 :
136 : static_always_inline u32
137 5 : ipsec_fp_in_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
138 : ipsec_policy_t **policies, u32 n)
139 5 : {
140 5 : u32 last_priority[n];
141 5 : u32 i = 0;
142 5 : u32 counter = 0;
143 : ipsec_fp_mask_type_entry_t *mte;
144 : ipsec_fp_mask_id_t *mti;
145 5 : ipsec_fp_5tuple_t *match = tuples;
146 : ipsec_policy_t *policy;
147 5 : u32 n_left = n;
148 : clib_bihash_kv_40_8_t kv;
149 : /* result of the lookup */
150 : clib_bihash_kv_40_8_t result;
151 5 : ipsec_fp_lookup_value_t *result_val =
152 : (ipsec_fp_lookup_value_t *) &result.value;
153 : u64 *pkey, *pmatch, *pmask;
154 5 : ipsec_main_t *im = &ipsec_main;
155 5 : ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
156 5 : ipsec_fp_mask_id_t *mask_type_ids = pspd_fp->fp_mask_ids[match->action];
157 5 : 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);
159 :
160 : /* clear the list of matched policies pointers */
161 5 : clib_memset (policies, 0, n * sizeof (*policies));
162 5 : clib_memset (last_priority, 0, n * sizeof (u32));
163 5 : n_left = n;
164 10 : while (n_left)
165 : {
166 10 : vec_foreach (mti, mask_type_ids)
167 : {
168 5 : mte = im->fp_mask_types + mti->mask_type_idx;
169 5 : if (mte->mask.action == 0)
170 0 : continue;
171 :
172 5 : pmatch = (u64 *) match->kv_40_8.key;
173 5 : pmask = (u64 *) mte->mask.kv_40_8.key;
174 5 : pkey = (u64 *) kv.key;
175 :
176 5 : *pkey++ = *pmatch++ & *pmask++;
177 5 : *pkey++ = *pmatch++ & *pmask++;
178 5 : *pkey++ = *pmatch++ & *pmask++;
179 5 : *pkey++ = *pmatch++ & *pmask++;
180 5 : *pkey = *pmatch & *pmask;
181 :
182 : int res =
183 5 : clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
184 : /* lookup the hash by each packet in the burst for this mask. */
185 :
186 5 : if (res == 0)
187 : {
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. */
191 :
192 5 : if (vec_len (result_val->fp_policies_ids) > 1)
193 0 : {
194 : u32 *policy_id;
195 0 : vec_foreach (policy_id, result_val->fp_policies_ids)
196 : {
197 0 : policy = im->policies + *policy_id;
198 :
199 0 : if (single_rule_in_match_5tuple (policy, match))
200 : {
201 0 : if (last_priority[i] < policy->priority)
202 : {
203 0 : last_priority[i] = policy->priority;
204 0 : if (policies[i] == 0)
205 0 : counter++;
206 0 : policies[i] = policy;
207 : }
208 0 : break;
209 : }
210 : }
211 : }
212 : else
213 : {
214 : u32 *policy_id;
215 5 : ASSERT (vec_len (result_val->fp_policies_ids) == 1);
216 5 : policy_id = result_val->fp_policies_ids;
217 5 : policy = im->policies + *policy_id;
218 10 : if ((last_priority[i] < policy->priority) &&
219 5 : (single_rule_in_match_5tuple (policy, match)))
220 : {
221 5 : last_priority[i] = policy->priority;
222 5 : if (policies[i] == 0)
223 5 : counter++;
224 5 : policies[i] = policy;
225 : }
226 : }
227 : }
228 : }
229 :
230 5 : i++;
231 5 : n_left--;
232 5 : match++;
233 : }
234 5 : return counter;
235 : }
236 :
237 : static_always_inline u32
238 155 : ipsec_fp_in_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
239 : ipsec_policy_t **policies, u32 n)
240 :
241 155 : {
242 155 : u32 last_priority[n];
243 155 : u32 i = 0;
244 155 : u32 counter = 0;
245 : ipsec_fp_mask_type_entry_t *mte;
246 : ipsec_fp_mask_id_t *mti;
247 155 : ipsec_fp_5tuple_t *match = tuples;
248 : ipsec_policy_t *policy;
249 155 : u32 n_left = n;
250 : clib_bihash_kv_16_8_t kv;
251 : /* result of the lookup */
252 : clib_bihash_kv_16_8_t result;
253 155 : ipsec_fp_lookup_value_t *result_val =
254 : (ipsec_fp_lookup_value_t *) &result.value;
255 : u64 *pkey, *pmatch, *pmask;
256 155 : ipsec_main_t *im = &ipsec_main;
257 155 : ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
258 155 : ipsec_fp_mask_id_t *mask_type_ids = pspd_fp->fp_mask_ids[match->action];
259 155 : clib_bihash_16_8_t *bihash_table = pool_elt_at_index (
260 : im->fp_ip4_lookup_hashes_pool, pspd_fp->ip4_in_lookup_hash_idx);
261 :
262 : /* clear the list of matched policies pointers */
263 155 : clib_memset (policies, 0, n * sizeof (*policies));
264 155 : clib_memset (last_priority, 0, n * sizeof (u32));
265 155 : n_left = n;
266 310 : while (n_left)
267 : {
268 225 : vec_foreach (mti, mask_type_ids)
269 : {
270 70 : mte = im->fp_mask_types + mti->mask_type_idx;
271 70 : if (mte->mask.action == 0)
272 0 : continue;
273 70 : pmatch = (u64 *) match->kv_16_8.key;
274 70 : pmask = (u64 *) mte->mask.kv_16_8.key;
275 70 : pkey = (u64 *) kv.key;
276 :
277 70 : *pkey++ = *pmatch++ & *pmask++;
278 70 : *pkey = *pmatch & *pmask;
279 :
280 : int res =
281 70 : clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
282 : /* lookup the hash by each packet in the burst for this mask. */
283 :
284 70 : if (res == 0)
285 : {
286 : /* There is a hit in the hash table. */
287 : /* Find the policy with highest priority. */
288 : /* Store the lookup results in a dedicated array. */
289 :
290 70 : if (vec_len (result_val->fp_policies_ids) > 1)
291 0 : {
292 : u32 *policy_id;
293 0 : vec_foreach (policy_id, result_val->fp_policies_ids)
294 : {
295 0 : policy = im->policies + *policy_id;
296 :
297 0 : if (single_rule_in_match_5tuple (policy, match))
298 : {
299 0 : if (last_priority[i] < policy->priority)
300 : {
301 0 : last_priority[i] = policy->priority;
302 0 : if (policies[i] == 0)
303 0 : counter++;
304 0 : policies[i] = policy;
305 : }
306 0 : break;
307 : }
308 : }
309 : }
310 : else
311 : {
312 : u32 *policy_id;
313 70 : ASSERT (vec_len (result_val->fp_policies_ids) == 1);
314 70 : policy_id = result_val->fp_policies_ids;
315 70 : policy = im->policies + *policy_id;
316 140 : if ((last_priority[i] < policy->priority) &&
317 70 : (single_rule_in_match_5tuple (policy, match)))
318 : {
319 70 : last_priority[i] = policy->priority;
320 70 : if (policies[i] == 0)
321 70 : counter++;
322 70 : policies[i] = policy;
323 : }
324 : }
325 : }
326 : }
327 :
328 155 : i++;
329 155 : n_left--;
330 155 : match++;
331 : }
332 155 : return counter;
333 : }
334 :
335 : /**
336 : * @brief function handler to perform lookup in fastpath SPD
337 : * for inbound traffic burst of n packets
338 : **/
339 :
340 : static_always_inline u32
341 160 : ipsec_fp_in_policy_match_n (void *spd_fp, u8 is_ipv6,
342 : ipsec_fp_5tuple_t *tuples,
343 : ipsec_policy_t **policies, u32 n)
344 : {
345 160 : if (is_ipv6)
346 5 : return ipsec_fp_in_ip6_policy_match_n (spd_fp, tuples, policies, n);
347 : else
348 155 : return ipsec_fp_in_ip4_policy_match_n (spd_fp, tuples, policies, n);
349 : }
350 :
351 : static_always_inline u32
352 69 : ipsec_fp_out_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
353 : ipsec_policy_t **policies, u32 *ids, u32 n)
354 :
355 69 : {
356 69 : u32 last_priority[n];
357 69 : u32 i = 0;
358 69 : u32 counter = 0;
359 : ipsec_fp_mask_type_entry_t *mte;
360 : ipsec_fp_mask_id_t *mti;
361 69 : ipsec_fp_5tuple_t *match = tuples;
362 : ipsec_policy_t *policy;
363 :
364 69 : u32 n_left = n;
365 : clib_bihash_kv_40_8_t kv;
366 : /* result of the lookup */
367 : clib_bihash_kv_40_8_t result;
368 69 : ipsec_fp_lookup_value_t *result_val =
369 : (ipsec_fp_lookup_value_t *) &result.value;
370 : u64 *pkey, *pmatch, *pmask;
371 69 : ipsec_main_t *im = &ipsec_main;
372 69 : ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
373 69 : ipsec_fp_mask_id_t *mask_type_ids =
374 : pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP6_OUTBOUND];
375 69 : clib_bihash_40_8_t *bihash_table = pool_elt_at_index (
376 : im->fp_ip6_lookup_hashes_pool, pspd_fp->ip6_out_lookup_hash_idx);
377 :
378 : /*clear the list of matched policies pointers */
379 69 : clib_memset (policies, 0, n * sizeof (*policies));
380 69 : clib_memset (last_priority, 0, n * sizeof (u32));
381 69 : n_left = n;
382 138 : while (n_left)
383 : {
384 138 : vec_foreach (mti, mask_type_ids)
385 : {
386 69 : mte = im->fp_mask_types + mti->mask_type_idx;
387 69 : if (mte->mask.action != 0)
388 0 : continue;
389 :
390 69 : pmatch = (u64 *) match->kv_40_8.key;
391 69 : pmask = (u64 *) mte->mask.kv_40_8.key;
392 69 : pkey = (u64 *) kv.key;
393 :
394 69 : *pkey++ = *pmatch++ & *pmask++;
395 69 : *pkey++ = *pmatch++ & *pmask++;
396 69 : *pkey++ = *pmatch++ & *pmask++;
397 69 : *pkey++ = *pmatch++ & *pmask++;
398 69 : *pkey = *pmatch & *pmask;
399 :
400 : int res =
401 69 : clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
402 : /* lookup the hash by each packet in the burst for this mask. */
403 :
404 69 : if (res == 0)
405 : {
406 : /* There is a hit in the hash table. */
407 : /* Find the policy with highest priority. */
408 : /* Store the lookup results in a dedicated array. */
409 :
410 60 : if (vec_len (result_val->fp_policies_ids) > 1)
411 50 : {
412 : u32 *policy_id;
413 50 : vec_foreach (policy_id, result_val->fp_policies_ids)
414 : {
415 50 : policy = im->policies + *policy_id;
416 :
417 50 : if (single_rule_out_match_5tuple (policy, match))
418 : {
419 50 : if (last_priority[i] < policy->priority)
420 : {
421 50 : last_priority[i] = policy->priority;
422 50 : if (policies[i] == 0)
423 50 : counter++;
424 50 : policies[i] = policy;
425 50 : ids[i] = *policy_id;
426 : }
427 50 : break;
428 : }
429 : }
430 : }
431 : else
432 : {
433 : u32 *policy_id;
434 10 : ASSERT (vec_len (result_val->fp_policies_ids) == 1);
435 10 : policy_id = result_val->fp_policies_ids;
436 10 : policy = im->policies + *policy_id;
437 10 : if (single_rule_out_match_5tuple (policy, match))
438 : {
439 10 : if (last_priority[i] < policy->priority)
440 : {
441 10 : last_priority[i] = policy->priority;
442 10 : if (policies[i] == 0)
443 10 : counter++;
444 10 : policies[i] = policy;
445 10 : ids[i] = *policy_id;
446 : }
447 : }
448 : }
449 : }
450 : }
451 69 : n_left--;
452 69 : match++;
453 69 : i++;
454 : }
455 69 : return counter;
456 : }
457 :
458 : static_always_inline u32
459 70 : ipsec_fp_out_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
460 : ipsec_policy_t **policies, u32 *ids, u32 n)
461 :
462 70 : {
463 70 : u32 last_priority[n];
464 70 : u32 i = 0;
465 70 : u32 counter = 0;
466 : ipsec_fp_mask_type_entry_t *mte;
467 : ipsec_fp_mask_id_t *mti;
468 70 : ipsec_fp_5tuple_t *match = tuples;
469 : ipsec_policy_t *policy;
470 :
471 70 : u32 n_left = n;
472 : clib_bihash_kv_16_8_t kv;
473 : /* result of the lookup */
474 : clib_bihash_kv_16_8_t result;
475 70 : ipsec_fp_lookup_value_t *result_val =
476 : (ipsec_fp_lookup_value_t *) &result.value;
477 : u64 *pkey, *pmatch, *pmask;
478 70 : ipsec_main_t *im = &ipsec_main;
479 70 : ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
480 70 : ipsec_fp_mask_id_t *mask_type_ids =
481 : pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP4_OUTBOUND];
482 70 : clib_bihash_16_8_t *bihash_table = pool_elt_at_index (
483 : im->fp_ip4_lookup_hashes_pool, pspd_fp->ip4_out_lookup_hash_idx);
484 :
485 : /* clear the list of matched policies pointers */
486 70 : clib_memset (policies, 0, n * sizeof (*policies));
487 70 : clib_memset (last_priority, 0, n * sizeof (u32));
488 70 : n_left = n;
489 140 : while (n_left)
490 : {
491 140 : vec_foreach (mti, mask_type_ids)
492 : {
493 70 : mte = im->fp_mask_types + mti->mask_type_idx;
494 70 : if (mte->mask.action != 0)
495 0 : continue;
496 :
497 70 : pmatch = (u64 *) match->kv_16_8.key;
498 70 : pmask = (u64 *) mte->mask.kv_16_8.key;
499 70 : pkey = (u64 *) kv.key;
500 :
501 70 : *pkey++ = *pmatch++ & *pmask++;
502 70 : *pkey = *pmatch & *pmask;
503 :
504 : int res =
505 70 : clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
506 : /* lookup the hash by each packet in the burst for this mask. */
507 :
508 70 : if (res == 0)
509 : {
510 : /* There is a hit in the hash table. */
511 : /* Find the policy with highest priority. */
512 : /* Store the lookup results in a dedicated array. */
513 :
514 70 : if (vec_len (result_val->fp_policies_ids) > 1)
515 55 : {
516 : u32 *policy_id;
517 55 : vec_foreach (policy_id, result_val->fp_policies_ids)
518 : {
519 55 : policy = im->policies + *policy_id;
520 :
521 55 : if (single_rule_out_match_5tuple (policy, match))
522 : {
523 55 : if (last_priority[i] < policy->priority)
524 : {
525 55 : last_priority[i] = policy->priority;
526 55 : if (policies[i] == 0)
527 55 : counter++;
528 55 : policies[i] = policy;
529 55 : ids[i] = *policy_id;
530 : }
531 55 : break;
532 : }
533 : }
534 : }
535 : else
536 : {
537 : u32 *policy_id;
538 15 : ASSERT (vec_len (result_val->fp_policies_ids) == 1);
539 15 : policy_id = result_val->fp_policies_ids;
540 15 : policy = im->policies + *policy_id;
541 30 : if ((last_priority[i] < policy->priority) &&
542 15 : (single_rule_out_match_5tuple (policy, match)))
543 : {
544 15 : last_priority[i] = policy->priority;
545 15 : if (policies[i] == 0)
546 15 : counter++;
547 15 : policies[i] = policy;
548 15 : ids[i] = *policy_id;
549 : }
550 : }
551 : }
552 : }
553 :
554 70 : i++;
555 70 : n_left--;
556 70 : match++;
557 : }
558 70 : return counter;
559 : }
560 :
561 : /**
562 : * @brief function handler to perform lookup in fastpath SPD
563 : * for outbound traffic burst of n packets
564 : * returns number of successfully matched policies
565 : **/
566 :
567 : static_always_inline u32
568 139 : ipsec_fp_out_policy_match_n (void *spd_fp, u8 is_ipv6,
569 : ipsec_fp_5tuple_t *tuples,
570 : ipsec_policy_t **policies, u32 *ids, u32 n)
571 :
572 : {
573 139 : if (is_ipv6)
574 69 : return ipsec_fp_out_ip6_policy_match_n (spd_fp, tuples, policies, ids, n);
575 : else
576 70 : return ipsec_fp_out_ip4_policy_match_n (spd_fp, tuples, policies, ids, n);
577 : }
578 :
579 : #endif /* !IPSEC_SPD_FP_LOOKUP_H */
|