571a4b82fd2a477fa484dfbc543cbe76c5a1238b
[vpp.git] / src / vnet / ipsec / ipsec_spd_fp_lookup.h
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 /**
24  * @brief function handler to perform lookup in fastpath SPD
25  * for inbound traffic burst of n packets
26  **/
27
28 inline u32
29 ipsec_fp_in_policy_match_n (void *spd_fp, u8 is_ipv6,
30                             ipsec_fp_5tuple_t *tuples,
31                             ipsec_policy_t **policies, u32 *policy_ids, u32 n)
32 {
33   return 0;
34 }
35
36 static_always_inline int
37 single_rule_match_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *match)
38 {
39   if (PREDICT_FALSE (policy->is_ipv6 != match->is_ipv6))
40     return (0);
41
42   if (PREDICT_FALSE (policy->protocol != IPSEC_POLICY_PROTOCOL_ANY &&
43                      (policy->protocol != match->protocol)))
44     return (0);
45
46   if (!policy->is_ipv6)
47     {
48       if (PREDICT_FALSE (
49             clib_net_to_host_u32 (match->laddr.as_u32) <
50             clib_net_to_host_u32 (policy->laddr.start.ip4.as_u32)))
51         return (0);
52
53       if (PREDICT_FALSE (clib_net_to_host_u32 (match->laddr.as_u32) >
54                          clib_net_to_host_u32 (policy->laddr.stop.ip4.as_u32)))
55         return (0);
56
57       if (PREDICT_FALSE (
58             clib_net_to_host_u32 (match->raddr.as_u32) <
59             clib_net_to_host_u32 (policy->raddr.start.ip4.as_u32)))
60         return (0);
61
62       if (PREDICT_FALSE (clib_net_to_host_u32 (match->raddr.as_u32) >
63                          clib_net_to_host_u32 (policy->raddr.stop.ip4.as_u32)))
64         return (0);
65     }
66   else
67     {
68
69       if (ip6_address_compare (&match->ip6_laddr, &policy->laddr.start.ip6) <
70           0)
71         return (0);
72
73       if (ip6_address_compare (&policy->laddr.stop.ip6, &match->ip6_laddr) < 0)
74
75         return (0);
76
77       if (ip6_address_compare (&match->ip6_raddr, &policy->raddr.start.ip6) <
78           0)
79
80         return (0);
81
82       if (ip6_address_compare (&policy->raddr.stop.ip6, &match->ip6_raddr) < 0)
83
84         return (0);
85     }
86
87   if (PREDICT_FALSE ((match->protocol != IP_PROTOCOL_TCP) &&
88                      (match->protocol != IP_PROTOCOL_UDP) &&
89                      (match->protocol != IP_PROTOCOL_SCTP)))
90     {
91       return (1);
92     }
93
94   if (match->lport < policy->lport.start)
95     return (0);
96
97   if (match->lport > policy->lport.stop)
98     return (0);
99
100   if (match->rport < policy->rport.start)
101     return (0);
102
103   if (match->rport > policy->rport.stop)
104     return (0);
105
106   return (1);
107 }
108
109 static_always_inline u32
110 ipsec_fp_ip6_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
111                                  ipsec_policy_t **policies, u32 *ids, u32 n)
112
113 {
114   u32 last_priority[n];
115   u32 i = 0;
116   u32 counter = 0;
117   ipsec_fp_mask_type_entry_t *mte;
118   u32 *mti;
119   ipsec_fp_5tuple_t *match = tuples;
120   ipsec_policy_t *policy;
121
122   u32 n_left = n;
123   clib_bihash_kv_40_8_t kv;
124   /* result of the lookup */
125   clib_bihash_kv_40_8_t result;
126   ipsec_fp_lookup_value_t *result_val =
127     (ipsec_fp_lookup_value_t *) &result.value;
128   u64 *pkey, *pmatch, *pmask;
129   ipsec_main_t *im = &ipsec_main;
130   ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
131   u32 *mask_type_ids = pspd_fp->fp_mask_types[IPSEC_SPD_POLICY_IP4_OUTBOUND];
132
133   /*clear the list of matched policies pointers */
134   clib_memset (policies, 0, n * sizeof (*policies));
135   clib_memset (last_priority, 0, n * sizeof (u32));
136   n_left = n;
137   while (n_left)
138     {
139       vec_foreach (mti, mask_type_ids)
140         {
141           mte = im->fp_mask_types + *mti;
142
143           pmatch = (u64 *) match;
144           pmask = (u64 *) &mte->mask;
145           pkey = (u64 *) kv.key;
146
147           *pkey++ = *pmatch++ & *pmask++;
148           *pkey++ = *pmatch++ & *pmask++;
149           *pkey++ = *pmatch++ & *pmask++;
150           *pkey++ = *pmatch++ & *pmask++;
151           *pkey++ = *pmatch++ & *pmask++;
152           *pkey++ = *pmatch++ & *pmask++;
153
154           int res = clib_bihash_search_inline_2_40_8 (
155             &pspd_fp->fp_ip6_lookup_hash, &kv, &result);
156           /* lookup the hash by each packet in the burst for this mask. */
157
158           if (res == 0)
159             {
160               /* There is a hit in the hash table. */
161               /* Find the policy with highest priority. */
162               /* Store the lookup results in a dedicated array. */
163
164               if (vec_len (result_val->fp_policies_ids) > 1)
165                 {
166                   u32 *policy_id;
167                   vec_foreach (policy_id, result_val->fp_policies_ids)
168                     {
169                       policy = im->policies + *policy_id;
170
171                       if (single_rule_match_5tuple (policy, match))
172                         {
173                           if (last_priority[i] < policy->priority)
174                             {
175                               last_priority[i] = policy->priority;
176                               if (policies[i] == 0)
177                                 counter++;
178                               policies[i] = policy;
179                               ids[i] = *policy_id;
180                             }
181                         }
182                     }
183                 }
184               else
185                 {
186                   u32 *policy_id;
187                   ASSERT (vec_len (result_val->fp_policies_ids) == 1);
188                   policy_id = result_val->fp_policies_ids;
189                   policy = im->policies + *policy_id;
190                   if (single_rule_match_5tuple (policy, match))
191                     {
192                       if (last_priority[i] < policy->priority)
193                         {
194                           last_priority[i] = policy->priority;
195                           if (policies[i] == 0)
196                             counter++;
197                           policies[i] = policy;
198                           ids[i] = *policy_id;
199                         }
200                     }
201                 }
202             }
203         }
204       n_left--;
205       match++;
206       i++;
207     }
208   return counter;
209 }
210
211 static_always_inline u32
212 ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
213                                  ipsec_policy_t **policies, u32 *ids, u32 n)
214
215 {
216   u32 last_priority[n];
217   u32 i = 0;
218   u32 counter = 0;
219   ipsec_fp_mask_type_entry_t *mte;
220   u32 *mti;
221   ipsec_fp_5tuple_t *match = tuples;
222   ipsec_policy_t *policy;
223
224   u32 n_left = n;
225   clib_bihash_kv_16_8_t kv;
226   /* result of the lookup */
227   clib_bihash_kv_16_8_t result;
228   ipsec_fp_lookup_value_t *result_val =
229     (ipsec_fp_lookup_value_t *) &result.value;
230   u64 *pkey, *pmatch, *pmask;
231   ipsec_main_t *im = &ipsec_main;
232   ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
233   u32 *mask_type_ids = pspd_fp->fp_mask_types[IPSEC_SPD_POLICY_IP4_OUTBOUND];
234
235   /* clear the list of matched policies pointers */
236   clib_memset (policies, 0, n * sizeof (*policies));
237   clib_memset (last_priority, 0, n * sizeof (u32));
238   n_left = n;
239   while (n_left)
240     {
241       vec_foreach (mti, mask_type_ids)
242         {
243           mte = im->fp_mask_types + *mti;
244
245           pmatch = (u64 *) &match->laddr;
246           pmask = (u64 *) &mte->mask.laddr;
247           pkey = (u64 *) kv.key;
248
249           *pkey++ = *pmatch++ & *pmask++;
250           *pkey++ = *pmatch++ & *pmask++;
251
252           int res = clib_bihash_search_inline_2_16_8 (
253             &pspd_fp->fp_ip4_lookup_hash, &kv, &result);
254           /* lookup the hash by each packet in the burst for this mask. */
255
256           if (res == 0)
257             {
258               /* There is a hit in the hash table. */
259               /* Find the policy with highest priority. */
260               /* Store the lookup results in a dedicated array. */
261
262               if (vec_len (result_val->fp_policies_ids) > 1)
263                 {
264                   u32 *policy_id;
265                   vec_foreach (policy_id, result_val->fp_policies_ids)
266                     {
267                       policy = im->policies + *policy_id;
268
269                       if ((last_priority[i] < policy->priority) &&
270                           (single_rule_match_5tuple (policy, match)))
271                         {
272                           last_priority[i] = policy->priority;
273                           if (policies[i] == 0)
274                             counter++;
275                           policies[i] = policy;
276                           ids[i] = *policy_id;
277                         }
278                     }
279                 }
280               else
281                 {
282                   u32 *policy_id;
283                   ASSERT (vec_len (result_val->fp_policies_ids) == 1);
284                   policy_id = result_val->fp_policies_ids;
285                   policy = im->policies + *policy_id;
286                   if ((last_priority[i] < policy->priority) &&
287                       (single_rule_match_5tuple (policy, match)))
288                     {
289                       last_priority[i] = policy->priority;
290                       if (policies[i] == 0)
291                         counter++;
292                       policies[i] = policy;
293                       ids[i] = *policy_id;
294                     }
295                 }
296             }
297         }
298
299       i++;
300       n_left--;
301       match++;
302     }
303   return counter;
304 }
305
306 /**
307  * @brief function handler to perform lookup in fastpath SPD
308  * for outbound traffic burst of n packets
309  * returns number of successfully matched policies
310  **/
311
312 static_always_inline u32
313 ipsec_fp_out_policy_match_n (void *spd_fp, u8 is_ipv6,
314                              ipsec_fp_5tuple_t *tuples,
315                              ipsec_policy_t **policies, u32 *ids, u32 n)
316
317 {
318   if (is_ipv6)
319     return ipsec_fp_ip6_out_policy_match_n (spd_fp, tuples, policies, ids, n);
320   else
321     return ipsec_fp_ip4_out_policy_match_n (spd_fp, tuples, policies, ids, n);
322 }
323
324 #endif /* !IPSEC_SPD_FP_LOOKUP_H */