912e18a3f8ad0d5a33a60a97452c8d91dbe7bc88
[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_IP6_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->ip6_laddr;
144           pmask = (u64 *) &mte->mask.ip6_laddr;
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
153           int res = clib_bihash_search_inline_2_40_8 (
154             &pspd_fp->fp_ip6_lookup_hash, &kv, &result);
155           /* lookup the hash by each packet in the burst for this mask. */
156
157           if (res == 0)
158             {
159               /* There is a hit in the hash table. */
160               /* Find the policy with highest priority. */
161               /* Store the lookup results in a dedicated array. */
162
163               if (vec_len (result_val->fp_policies_ids) > 1)
164                 {
165                   u32 *policy_id;
166                   vec_foreach (policy_id, result_val->fp_policies_ids)
167                     {
168                       policy = im->policies + *policy_id;
169
170                       if (single_rule_match_5tuple (policy, match))
171                         {
172                           if (last_priority[i] < policy->priority)
173                             {
174                               last_priority[i] = policy->priority;
175                               if (policies[i] == 0)
176                                 counter++;
177                               policies[i] = policy;
178                               ids[i] = *policy_id;
179                             }
180                         }
181                     }
182                 }
183               else
184                 {
185                   u32 *policy_id;
186                   ASSERT (vec_len (result_val->fp_policies_ids) == 1);
187                   policy_id = result_val->fp_policies_ids;
188                   policy = im->policies + *policy_id;
189                   if (single_rule_match_5tuple (policy, match))
190                     {
191                       if (last_priority[i] < policy->priority)
192                         {
193                           last_priority[i] = policy->priority;
194                           if (policies[i] == 0)
195                             counter++;
196                           policies[i] = policy;
197                           ids[i] = *policy_id;
198                         }
199                     }
200                 }
201             }
202         }
203       n_left--;
204       match++;
205       i++;
206     }
207   return counter;
208 }
209
210 static_always_inline u32
211 ipsec_fp_ip4_out_policy_match_n (void *spd_fp, ipsec_fp_5tuple_t *tuples,
212                                  ipsec_policy_t **policies, u32 *ids, u32 n)
213
214 {
215   u32 last_priority[n];
216   u32 i = 0;
217   u32 counter = 0;
218   ipsec_fp_mask_type_entry_t *mte;
219   u32 *mti;
220   ipsec_fp_5tuple_t *match = tuples;
221   ipsec_policy_t *policy;
222
223   u32 n_left = n;
224   clib_bihash_kv_16_8_t kv;
225   /* result of the lookup */
226   clib_bihash_kv_16_8_t result;
227   ipsec_fp_lookup_value_t *result_val =
228     (ipsec_fp_lookup_value_t *) &result.value;
229   u64 *pkey, *pmatch, *pmask;
230   ipsec_main_t *im = &ipsec_main;
231   ipsec_spd_fp_t *pspd_fp = (ipsec_spd_fp_t *) spd_fp;
232   u32 *mask_type_ids = pspd_fp->fp_mask_types[IPSEC_SPD_POLICY_IP4_OUTBOUND];
233
234   /* clear the list of matched policies pointers */
235   clib_memset (policies, 0, n * sizeof (*policies));
236   clib_memset (last_priority, 0, n * sizeof (u32));
237   n_left = n;
238   while (n_left)
239     {
240       vec_foreach (mti, mask_type_ids)
241         {
242           mte = im->fp_mask_types + *mti;
243
244           pmatch = (u64 *) &match->laddr;
245           pmask = (u64 *) &mte->mask.laddr;
246           pkey = (u64 *) kv.key;
247
248           *pkey++ = *pmatch++ & *pmask++;
249           *pkey++ = *pmatch++ & *pmask++;
250
251           int res = clib_bihash_search_inline_2_16_8 (
252             &pspd_fp->fp_ip4_lookup_hash, &kv, &result);
253           /* lookup the hash by each packet in the burst for this mask. */
254
255           if (res == 0)
256             {
257               /* There is a hit in the hash table. */
258               /* Find the policy with highest priority. */
259               /* Store the lookup results in a dedicated array. */
260
261               if (vec_len (result_val->fp_policies_ids) > 1)
262                 {
263                   u32 *policy_id;
264                   vec_foreach (policy_id, result_val->fp_policies_ids)
265                     {
266                       policy = im->policies + *policy_id;
267
268                       if ((last_priority[i] < policy->priority) &&
269                           (single_rule_match_5tuple (policy, match)))
270                         {
271                           last_priority[i] = policy->priority;
272                           if (policies[i] == 0)
273                             counter++;
274                           policies[i] = policy;
275                           ids[i] = *policy_id;
276                         }
277                     }
278                 }
279               else
280                 {
281                   u32 *policy_id;
282                   ASSERT (vec_len (result_val->fp_policies_ids) == 1);
283                   policy_id = result_val->fp_policies_ids;
284                   policy = im->policies + *policy_id;
285                   if ((last_priority[i] < policy->priority) &&
286                       (single_rule_match_5tuple (policy, match)))
287                     {
288                       last_priority[i] = policy->priority;
289                       if (policies[i] == 0)
290                         counter++;
291                       policies[i] = policy;
292                       ids[i] = *policy_id;
293                     }
294                 }
295             }
296         }
297
298       i++;
299       n_left--;
300       match++;
301     }
302   return counter;
303 }
304
305 /**
306  * @brief function handler to perform lookup in fastpath SPD
307  * for outbound traffic burst of n packets
308  * returns number of successfully matched policies
309  **/
310
311 static_always_inline u32
312 ipsec_fp_out_policy_match_n (void *spd_fp, u8 is_ipv6,
313                              ipsec_fp_5tuple_t *tuples,
314                              ipsec_policy_t **policies, u32 *ids, u32 n)
315
316 {
317   if (is_ipv6)
318     return ipsec_fp_ip6_out_policy_match_n (spd_fp, tuples, policies, ids, n);
319   else
320     return ipsec_fp_ip4_out_policy_match_n (spd_fp, tuples, policies, ids, n);
321 }
322
323 #endif /* !IPSEC_SPD_FP_LOOKUP_H */