blob: a372ac77a500ed5b98a9ef441986b7be6a244f95 [file] [log] [blame]
Piotr Bronowskie1dce372022-05-10 14:06:29 +00001/*
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
Piotr Bronowskie1dce372022-05-10 14:06:29 +000023static_always_inline int
Piotr Bronowski06abf232022-09-20 14:44:36 +000024single_rule_out_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
Piotr Bronowskie1dce372022-05-10 14:06:29 +000025{
26 if (PREDICT_FALSE (policy->is_ipv6 != match->is_ipv6))
27 return (0);
28
29 if (PREDICT_FALSE (policy->protocol != IPSEC_POLICY_PROTOCOL_ANY &&
30 (policy->protocol != match->protocol)))
31 return (0);
32
33 if (!policy->is_ipv6)
34 {
35 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 return (0);
39
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)))
42 return (0);
43
44 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 return (0);
48
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)))
51 return (0);
52 }
53 else
54 {
55
56 if (ip6_address_compare (&match->ip6_laddr, &policy->laddr.start.ip6) <
57 0)
58 return (0);
59
60 if (ip6_address_compare (&policy->laddr.stop.ip6, &match->ip6_laddr) < 0)
61
62 return (0);
63
64 if (ip6_address_compare (&match->ip6_raddr, &policy->raddr.start.ip6) <
65 0)
66
67 return (0);
68
69 if (ip6_address_compare (&policy->raddr.stop.ip6, &match->ip6_raddr) < 0)
70
71 return (0);
72 }
73
74 if (PREDICT_FALSE ((match->protocol != IP_PROTOCOL_TCP) &&
75 (match->protocol != IP_PROTOCOL_UDP) &&
76 (match->protocol != IP_PROTOCOL_SCTP)))
77 {
78 return (1);
79 }
80
81 if (match->lport < policy->lport.start)
82 return (0);
83
84 if (match->lport > policy->lport.stop)
85 return (0);
86
87 if (match->rport < policy->rport.start)
88 return (0);
89
90 if (match->rport > policy->rport.stop)
91 return (0);
92
93 return (1);
94}
95
Piotr Bronowski993b6be2022-08-31 13:48:14 +000096static_always_inline int
97single_rule_in_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
98{
99
100 u32 sa = clib_net_to_host_u32 (match->laddr.as_u32);
101 u32 da = clib_net_to_host_u32 (match->raddr.as_u32);
102
103 if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
104 {
105 ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
106
107 if (match->spi != s->spi)
108 return (0);
109
110 if (ipsec_sa_is_set_IS_TUNNEL (s))
111 {
112 if (da != clib_net_to_host_u32 (s->tunnel.t_dst.ip.ip4.as_u32))
113 return (0);
114
115 if (sa != clib_net_to_host_u32 (s->tunnel.t_src.ip.ip4.as_u32))
116 return (0);
117 }
118 }
119 else
120 {
121 if (da < clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32))
122 return (0);
123
124 if (da > clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32))
125 return (0);
126
127 if (sa < clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32))
128 return (0);
129
130 if (sa > clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32))
131 return (0);
132 }
133 return (1);
134}
135
136static_always_inline u32
137ipsec_fp_in_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
138 ipsec_policy_t **policies, u32 n)
139{
Piotr Bronowski06abf232022-09-20 14:44:36 +0000140 u32 last_priority[n];
141 u32 i = 0;
142 u32 counter = 0;
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;
147 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 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);
159
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));
163 n_left = n;
164 while (n_left)
165 {
166 vec_foreach (mti, mask_type_ids)
167 {
168 mte = im->fp_mask_types + mti->mask_type_idx;
169 if (mte->mask.action == 0)
170 continue;
171
172 pmatch = (u64 *) match->kv_40_8.key;
173 pmask = (u64 *) mte->mask.kv_40_8.key;
174 pkey = (u64 *) kv.key;
175
176 *pkey++ = *pmatch++ & *pmask++;
177 *pkey++ = *pmatch++ & *pmask++;
178 *pkey++ = *pmatch++ & *pmask++;
179 *pkey++ = *pmatch++ & *pmask++;
180 *pkey = *pmatch & *pmask;
181
182 int res =
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. */
185
186 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 if (vec_len (result_val->fp_policies_ids) > 1)
193 {
194 u32 *policy_id;
195 vec_foreach (policy_id, result_val->fp_policies_ids)
196 {
197 policy = im->policies + *policy_id;
198
199 if ((last_priority[i] < policy->priority) &&
200 (single_rule_in_match_5tuple (policy, match)))
201 {
202 last_priority[i] = policy->priority;
203 if (policies[i] == 0)
204 counter++;
205 policies[i] = policy;
206 }
207 }
208 }
209 else
210 {
211 u32 *policy_id;
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)))
217 {
218 last_priority[i] = policy->priority;
219 if (policies[i] == 0)
220 counter++;
221 policies[i] = policy;
222 }
223 }
224 }
225 }
226
227 i++;
228 n_left--;
229 match++;
230 }
231 return counter;
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000232}
233
234static_always_inline u32
235ipsec_fp_in_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
236 ipsec_policy_t **policies, u32 n)
237
238{
239 u32 last_priority[n];
240 u32 i = 0;
241 u32 counter = 0;
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;
246 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 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);
258
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));
262 n_left = n;
263 while (n_left)
264 {
265 vec_foreach (mti, mask_type_ids)
266 {
267 mte = im->fp_mask_types + mti->mask_type_idx;
268 if (mte->mask.action == 0)
269 continue;
270 pmatch = (u64 *) match->kv_16_8.key;
271 pmask = (u64 *) mte->mask.kv_16_8.key;
272 pkey = (u64 *) kv.key;
273
274 *pkey++ = *pmatch++ & *pmask++;
275 *pkey = *pmatch & *pmask;
276
277 int res =
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. */
280
281 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 if (vec_len (result_val->fp_policies_ids) > 1)
288 {
289 u32 *policy_id;
290 vec_foreach (policy_id, result_val->fp_policies_ids)
291 {
292 policy = im->policies + *policy_id;
293
294 if ((last_priority[i] < policy->priority) &&
295 (single_rule_in_match_5tuple (policy, match)))
296 {
297 last_priority[i] = policy->priority;
298 if (policies[i] == 0)
299 counter++;
300 policies[i] = policy;
301 }
302 }
303 }
304 else
305 {
306 u32 *policy_id;
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)))
312 {
313 last_priority[i] = policy->priority;
314 if (policies[i] == 0)
315 counter++;
316 policies[i] = policy;
317 }
318 }
319 }
320 }
321
322 i++;
323 n_left--;
324 match++;
325 }
326 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
334static_always_inline u32
335ipsec_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 if (is_ipv6)
340 return ipsec_fp_in_ip6_policy_match_n (spd_fp, tuples, policies, n);
341 else
342 return ipsec_fp_in_ip4_policy_match_n (spd_fp, tuples, policies, n);
343}
344
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000345static_always_inline u32
Piotr Bronowski06abf232022-09-20 14:44:36 +0000346ipsec_fp_out_ip6_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000347 ipsec_policy_t **policies, u32 *ids, u32 n)
348
349{
350 u32 last_priority[n];
351 u32 i = 0;
352 u32 counter = 0;
353 ipsec_fp_mask_type_entry_t *mte;
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000354 ipsec_fp_mask_id_t *mti;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000355 ipsec_fp_5tuple_t *match = tuples;
356 ipsec_policy_t *policy;
357
358 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 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;
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000367 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);
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000371
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));
375 n_left = n;
376 while (n_left)
377 {
378 vec_foreach (mti, mask_type_ids)
379 {
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000380 mte = im->fp_mask_types + mti->mask_type_idx;
Piotr Bronowski06abf232022-09-20 14:44:36 +0000381 if (mte->mask.action != 0)
382 continue;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000383
Piotr Bronowski81880602022-07-18 16:45:22 +0000384 pmatch = (u64 *) match->kv_40_8.key;
385 pmask = (u64 *) mte->mask.kv_40_8.key;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000386 pkey = (u64 *) kv.key;
387
388 *pkey++ = *pmatch++ & *pmask++;
389 *pkey++ = *pmatch++ & *pmask++;
390 *pkey++ = *pmatch++ & *pmask++;
391 *pkey++ = *pmatch++ & *pmask++;
Piotr Bronowski86f82082022-07-08 12:45:05 +0000392 *pkey = *pmatch & *pmask;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000393
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000394 int res =
395 clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000396 /* lookup the hash by each packet in the burst for this mask. */
397
398 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 if (vec_len (result_val->fp_policies_ids) > 1)
405 {
406 u32 *policy_id;
407 vec_foreach (policy_id, result_val->fp_policies_ids)
408 {
409 policy = im->policies + *policy_id;
410
Piotr Bronowski06abf232022-09-20 14:44:36 +0000411 if (single_rule_out_match_5tuple (policy, match))
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000412 {
413 if (last_priority[i] < policy->priority)
414 {
415 last_priority[i] = policy->priority;
416 if (policies[i] == 0)
417 counter++;
418 policies[i] = policy;
419 ids[i] = *policy_id;
420 }
421 }
422 }
423 }
424 else
425 {
426 u32 *policy_id;
427 ASSERT (vec_len (result_val->fp_policies_ids) == 1);
428 policy_id = result_val->fp_policies_ids;
429 policy = im->policies + *policy_id;
Piotr Bronowski06abf232022-09-20 14:44:36 +0000430 if (single_rule_out_match_5tuple (policy, match))
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000431 {
432 if (last_priority[i] < policy->priority)
433 {
434 last_priority[i] = policy->priority;
435 if (policies[i] == 0)
436 counter++;
437 policies[i] = policy;
438 ids[i] = *policy_id;
439 }
440 }
441 }
442 }
443 }
444 n_left--;
445 match++;
446 i++;
447 }
448 return counter;
449}
450
451static_always_inline u32
Piotr Bronowski06abf232022-09-20 14:44:36 +0000452ipsec_fp_out_ip4_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000453 ipsec_policy_t **policies, u32 *ids, u32 n)
454
455{
456 u32 last_priority[n];
457 u32 i = 0;
458 u32 counter = 0;
459 ipsec_fp_mask_type_entry_t *mte;
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000460 ipsec_fp_mask_id_t *mti;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000461 ipsec_fp_5tuple_t *match = tuples;
462 ipsec_policy_t *policy;
463
464 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 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;
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000473 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);
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000477
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));
481 n_left = n;
482 while (n_left)
483 {
484 vec_foreach (mti, mask_type_ids)
485 {
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000486 mte = im->fp_mask_types + mti->mask_type_idx;
487 if (mte->mask.action != 0)
488 continue;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000489
Piotr Bronowski81880602022-07-18 16:45:22 +0000490 pmatch = (u64 *) match->kv_16_8.key;
491 pmask = (u64 *) mte->mask.kv_16_8.key;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000492 pkey = (u64 *) kv.key;
493
494 *pkey++ = *pmatch++ & *pmask++;
Piotr Bronowski81880602022-07-18 16:45:22 +0000495 *pkey = *pmatch & *pmask;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000496
Piotr Bronowski993b6be2022-08-31 13:48:14 +0000497 int res =
498 clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000499 /* lookup the hash by each packet in the burst for this mask. */
500
501 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 if (vec_len (result_val->fp_policies_ids) > 1)
508 {
509 u32 *policy_id;
510 vec_foreach (policy_id, result_val->fp_policies_ids)
511 {
512 policy = im->policies + *policy_id;
513
514 if ((last_priority[i] < policy->priority) &&
Piotr Bronowski06abf232022-09-20 14:44:36 +0000515 (single_rule_out_match_5tuple (policy, match)))
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000516 {
517 last_priority[i] = policy->priority;
518 if (policies[i] == 0)
519 counter++;
520 policies[i] = policy;
521 ids[i] = *policy_id;
522 }
523 }
524 }
525 else
526 {
527 u32 *policy_id;
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) &&
Piotr Bronowski06abf232022-09-20 14:44:36 +0000532 (single_rule_out_match_5tuple (policy, match)))
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000533 {
534 last_priority[i] = policy->priority;
535 if (policies[i] == 0)
536 counter++;
537 policies[i] = policy;
538 ids[i] = *policy_id;
539 }
540 }
541 }
542 }
543
544 i++;
545 n_left--;
546 match++;
547 }
548 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
557static_always_inline u32
558ipsec_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 if (is_ipv6)
Piotr Bronowski06abf232022-09-20 14:44:36 +0000564 return ipsec_fp_out_ip6_policy_match_n (spd_fp, tuples, policies, ids, n);
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000565 else
Piotr Bronowski06abf232022-09-20 14:44:36 +0000566 return ipsec_fp_out_ip4_policy_match_n (spd_fp, tuples, policies, ids, n);
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000567}
568
569#endif /* !IPSEC_SPD_FP_LOOKUP_H */