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 195 : single_rule_out_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
25 : {
26 195 : if (PREDICT_FALSE (policy->is_ipv6 != match->is_ipv6))
27 0 : return (0);
28 :
29 195 : if (PREDICT_FALSE (policy->protocol != IPSEC_POLICY_PROTOCOL_ANY &&
30 : (policy->protocol != match->protocol)))
31 0 : return (0);
32 :
33 195 : if (!policy->is_ipv6)
34 : {
35 85 : 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 85 : 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 85 : 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 85 : 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 110 : if (ip6_address_compare (&match->ip6_laddr, &policy->laddr.start.ip6) <
57 : 0)
58 0 : return (0);
59 :
60 110 : if (ip6_address_compare (&policy->laddr.stop.ip6, &match->ip6_laddr) < 0)
61 :
62 0 : return (0);
63 :
64 110 : if (ip6_address_compare (&match->ip6_raddr, &policy->raddr.start.ip6) <
65 : 0)
66 :
67 0 : return (0);
68 :
69 110 : if (ip6_address_compare (&policy->raddr.stop.ip6, &match->ip6_raddr) < 0)
70 :
71 0 : return (0);
72 : }
73 :
74 195 : 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 195 : if (match->lport < policy->lport.start)
82 0 : return (0);
83 :
84 195 : if (match->lport > policy->lport.stop)
85 0 : return (0);
86 :
87 195 : if (match->rport < policy->rport.start)
88 0 : return (0);
89 :
90 195 : if (match->rport > policy->rport.stop)
91 0 : return (0);
92 :
93 195 : 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 ((last_priority[i] < policy->priority) &&
200 0 : (single_rule_in_match_5tuple (policy, match)))
201 : {
202 0 : last_priority[i] = policy->priority;
203 0 : if (policies[i] == 0)
204 0 : counter++;
205 0 : policies[i] = policy;
206 : }
207 : }
208 : }
209 : else
210 : {
211 : u32 *policy_id;
212 5 : ASSERT (vec_len (result_val->fp_policies_ids) == 1);
213 5 : policy_id = result_val->fp_policies_ids;
214 5 : policy = im->policies + *policy_id;
215 10 : if ((last_priority[i] < policy->priority) &&
216 5 : (single_rule_in_match_5tuple (policy, match)))
217 : {
218 5 : last_priority[i] = policy->priority;
219 5 : if (policies[i] == 0)
220 5 : counter++;
221 5 : policies[i] = policy;
222 : }
223 : }
224 : }
225 : }
226 :
227 5 : i++;
228 5 : n_left--;
229 5 : match++;
230 : }
231 5 : return counter;
232 : }
233 :
234 : static_always_inline u32
235 155 : ipsec_fp_in_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
236 : ipsec_policy_t **policies, u32 n)
237 :
238 155 : {
239 155 : u32 last_priority[n];
240 155 : u32 i = 0;
241 155 : u32 counter = 0;
242 : ipsec_fp_mask_type_entry_t *mte;
243 : ipsec_fp_mask_id_t *mti;
244 155 : ipsec_fp_5tuple_t *match = tuples;
245 : ipsec_policy_t *policy;
246 155 : u32 n_left = n;
247 : clib_bihash_kv_16_8_t kv;
248 : /* result of the lookup */
249 : clib_bihash_kv_16_8_t result;
250 155 : ipsec_fp_lookup_value_t *result_val =
251 : (ipsec_fp_lookup_value_t *) &result.value;
252 : u64 *pkey, *pmatch, *pmask;
253 155 : ipsec_main_t *im = &ipsec_main;
254 155 : ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
255 155 : ipsec_fp_mask_id_t *mask_type_ids = pspd_fp->fp_mask_ids[match->action];
256 155 : 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);
258 :
259 : /* clear the list of matched policies pointers */
260 155 : clib_memset (policies, 0, n * sizeof (*policies));
261 155 : clib_memset (last_priority, 0, n * sizeof (u32));
262 155 : n_left = n;
263 310 : while (n_left)
264 : {
265 225 : vec_foreach (mti, mask_type_ids)
266 : {
267 70 : mte = im->fp_mask_types + mti->mask_type_idx;
268 70 : if (mte->mask.action == 0)
269 0 : continue;
270 70 : pmatch = (u64 *) match->kv_16_8.key;
271 70 : pmask = (u64 *) mte->mask.kv_16_8.key;
272 70 : pkey = (u64 *) kv.key;
273 :
274 70 : *pkey++ = *pmatch++ & *pmask++;
275 70 : *pkey = *pmatch & *pmask;
276 :
277 : int res =
278 70 : clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
279 : /* lookup the hash by each packet in the burst for this mask. */
280 :
281 70 : if (res == 0)
282 : {
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. */
286 :
287 70 : if (vec_len (result_val->fp_policies_ids) > 1)
288 0 : {
289 : u32 *policy_id;
290 0 : vec_foreach (policy_id, result_val->fp_policies_ids)
291 : {
292 0 : policy = im->policies + *policy_id;
293 :
294 0 : if ((last_priority[i] < policy->priority) &&
295 0 : (single_rule_in_match_5tuple (policy, match)))
296 : {
297 0 : last_priority[i] = policy->priority;
298 0 : if (policies[i] == 0)
299 0 : counter++;
300 0 : policies[i] = policy;
301 : }
302 : }
303 : }
304 : else
305 : {
306 : u32 *policy_id;
307 70 : ASSERT (vec_len (result_val->fp_policies_ids) == 1);
308 70 : policy_id = result_val->fp_policies_ids;
309 70 : policy = im->policies + *policy_id;
310 140 : if ((last_priority[i] < policy->priority) &&
311 70 : (single_rule_in_match_5tuple (policy, match)))
312 : {
313 70 : last_priority[i] = policy->priority;
314 70 : if (policies[i] == 0)
315 70 : counter++;
316 70 : policies[i] = policy;
317 : }
318 : }
319 : }
320 : }
321 :
322 155 : i++;
323 155 : n_left--;
324 155 : match++;
325 : }
326 155 : return counter;
327 : }
328 :
329 : /**
330 : * @brief function handler to perform lookup in fastpath SPD
331 : * for inbound traffic burst of n packets
332 : **/
333 :
334 : static_always_inline u32
335 160 : 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)
338 : {
339 160 : if (is_ipv6)
340 5 : return ipsec_fp_in_ip6_policy_match_n (spd_fp, tuples, policies, n);
341 : else
342 155 : return ipsec_fp_in_ip4_policy_match_n (spd_fp, tuples, policies, n);
343 : }
344 :
345 : static_always_inline u32
346 69 : ipsec_fp_out_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
347 : ipsec_policy_t **policies, u32 *ids, u32 n)
348 :
349 69 : {
350 69 : u32 last_priority[n];
351 69 : u32 i = 0;
352 69 : u32 counter = 0;
353 : ipsec_fp_mask_type_entry_t *mte;
354 : ipsec_fp_mask_id_t *mti;
355 69 : ipsec_fp_5tuple_t *match = tuples;
356 : ipsec_policy_t *policy;
357 :
358 69 : u32 n_left = n;
359 : clib_bihash_kv_40_8_t kv;
360 : /* result of the lookup */
361 : clib_bihash_kv_40_8_t result;
362 69 : ipsec_fp_lookup_value_t *result_val =
363 : (ipsec_fp_lookup_value_t *) &result.value;
364 : u64 *pkey, *pmatch, *pmask;
365 69 : ipsec_main_t *im = &ipsec_main;
366 69 : ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
367 69 : ipsec_fp_mask_id_t *mask_type_ids =
368 : pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP6_OUTBOUND];
369 69 : 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);
371 :
372 : /*clear the list of matched policies pointers */
373 69 : clib_memset (policies, 0, n * sizeof (*policies));
374 69 : clib_memset (last_priority, 0, n * sizeof (u32));
375 69 : n_left = n;
376 138 : while (n_left)
377 : {
378 138 : vec_foreach (mti, mask_type_ids)
379 : {
380 69 : mte = im->fp_mask_types + mti->mask_type_idx;
381 69 : if (mte->mask.action != 0)
382 0 : continue;
383 :
384 69 : pmatch = (u64 *) match->kv_40_8.key;
385 69 : pmask = (u64 *) mte->mask.kv_40_8.key;
386 69 : pkey = (u64 *) kv.key;
387 :
388 69 : *pkey++ = *pmatch++ & *pmask++;
389 69 : *pkey++ = *pmatch++ & *pmask++;
390 69 : *pkey++ = *pmatch++ & *pmask++;
391 69 : *pkey++ = *pmatch++ & *pmask++;
392 69 : *pkey = *pmatch & *pmask;
393 :
394 : int res =
395 69 : clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
396 : /* lookup the hash by each packet in the burst for this mask. */
397 :
398 69 : if (res == 0)
399 : {
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. */
403 :
404 60 : if (vec_len (result_val->fp_policies_ids) > 1)
405 50 : {
406 : u32 *policy_id;
407 150 : vec_foreach (policy_id, result_val->fp_policies_ids)
408 : {
409 100 : policy = im->policies + *policy_id;
410 :
411 100 : if (single_rule_out_match_5tuple (policy, match))
412 : {
413 100 : if (last_priority[i] < policy->priority)
414 : {
415 65 : last_priority[i] = policy->priority;
416 65 : if (policies[i] == 0)
417 50 : counter++;
418 65 : policies[i] = policy;
419 65 : ids[i] = *policy_id;
420 : }
421 : }
422 : }
423 : }
424 : else
425 : {
426 : u32 *policy_id;
427 10 : ASSERT (vec_len (result_val->fp_policies_ids) == 1);
428 10 : policy_id = result_val->fp_policies_ids;
429 10 : policy = im->policies + *policy_id;
430 10 : if (single_rule_out_match_5tuple (policy, match))
431 : {
432 10 : if (last_priority[i] < policy->priority)
433 : {
434 10 : last_priority[i] = policy->priority;
435 10 : if (policies[i] == 0)
436 10 : counter++;
437 10 : policies[i] = policy;
438 10 : ids[i] = *policy_id;
439 : }
440 : }
441 : }
442 : }
443 : }
444 69 : n_left--;
445 69 : match++;
446 69 : i++;
447 : }
448 69 : return counter;
449 : }
450 :
451 : static_always_inline u32
452 70 : ipsec_fp_out_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
453 : ipsec_policy_t **policies, u32 *ids, u32 n)
454 :
455 70 : {
456 70 : u32 last_priority[n];
457 70 : u32 i = 0;
458 70 : u32 counter = 0;
459 : ipsec_fp_mask_type_entry_t *mte;
460 : ipsec_fp_mask_id_t *mti;
461 70 : ipsec_fp_5tuple_t *match = tuples;
462 : ipsec_policy_t *policy;
463 :
464 70 : u32 n_left = n;
465 : clib_bihash_kv_16_8_t kv;
466 : /* result of the lookup */
467 : clib_bihash_kv_16_8_t result;
468 70 : ipsec_fp_lookup_value_t *result_val =
469 : (ipsec_fp_lookup_value_t *) &result.value;
470 : u64 *pkey, *pmatch, *pmask;
471 70 : ipsec_main_t *im = &ipsec_main;
472 70 : ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
473 70 : ipsec_fp_mask_id_t *mask_type_ids =
474 : pspd_fp->fp_mask_ids[IPSEC_SPD_POLICY_IP4_OUTBOUND];
475 70 : 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);
477 :
478 : /* clear the list of matched policies pointers */
479 70 : clib_memset (policies, 0, n * sizeof (*policies));
480 70 : clib_memset (last_priority, 0, n * sizeof (u32));
481 70 : n_left = n;
482 140 : while (n_left)
483 : {
484 140 : vec_foreach (mti, mask_type_ids)
485 : {
486 70 : mte = im->fp_mask_types + mti->mask_type_idx;
487 70 : if (mte->mask.action != 0)
488 0 : continue;
489 :
490 70 : pmatch = (u64 *) match->kv_16_8.key;
491 70 : pmask = (u64 *) mte->mask.kv_16_8.key;
492 70 : pkey = (u64 *) kv.key;
493 :
494 70 : *pkey++ = *pmatch++ & *pmask++;
495 70 : *pkey = *pmatch & *pmask;
496 :
497 : int res =
498 70 : clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
499 : /* lookup the hash by each packet in the burst for this mask. */
500 :
501 70 : if (res == 0)
502 : {
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. */
506 :
507 70 : if (vec_len (result_val->fp_policies_ids) > 1)
508 55 : {
509 : u32 *policy_id;
510 165 : vec_foreach (policy_id, result_val->fp_policies_ids)
511 : {
512 110 : policy = im->policies + *policy_id;
513 :
514 180 : if ((last_priority[i] < policy->priority) &&
515 70 : (single_rule_out_match_5tuple (policy, match)))
516 : {
517 70 : last_priority[i] = policy->priority;
518 70 : if (policies[i] == 0)
519 55 : counter++;
520 70 : policies[i] = policy;
521 70 : ids[i] = *policy_id;
522 : }
523 : }
524 : }
525 : else
526 : {
527 : u32 *policy_id;
528 15 : ASSERT (vec_len (result_val->fp_policies_ids) == 1);
529 15 : policy_id = result_val->fp_policies_ids;
530 15 : policy = im->policies + *policy_id;
531 30 : if ((last_priority[i] < policy->priority) &&
532 15 : (single_rule_out_match_5tuple (policy, match)))
533 : {
534 15 : last_priority[i] = policy->priority;
535 15 : if (policies[i] == 0)
536 15 : counter++;
537 15 : policies[i] = policy;
538 15 : ids[i] = *policy_id;
539 : }
540 : }
541 : }
542 : }
543 :
544 70 : i++;
545 70 : n_left--;
546 70 : match++;
547 : }
548 70 : return counter;
549 : }
550 :
551 : /**
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
555 : **/
556 :
557 : static_always_inline u32
558 139 : 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)
561 :
562 : {
563 139 : if (is_ipv6)
564 69 : return ipsec_fp_out_ip6_policy_match_n (spd_fp, tuples, policies, ids, n);
565 : else
566 70 : return ipsec_fp_out_ip4_policy_match_n (spd_fp, tuples, policies, ids, n);
567 : }
568 :
569 : #endif /* !IPSEC_SPD_FP_LOOKUP_H */
|