blob: 3aea86f70a0c38f11fe862482bc828dc0faf7d22 [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
23/**
24 * @brief function handler to perform lookup in fastpath SPD
25 * for inbound traffic burst of n packets
26 **/
27
28inline u32
29ipsec_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
36static_always_inline int
37single_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
109static_always_inline u32
110ipsec_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;
Piotr Bronowski86f82082022-07-08 12:45:05 +0000131 u32 *mask_type_ids = pspd_fp->fp_mask_types[IPSEC_SPD_POLICY_IP6_OUTBOUND];
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000132
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
Piotr Bronowski81880602022-07-18 16:45:22 +0000143 pmatch = (u64 *) match->kv_40_8.key;
144 pmask = (u64 *) mte->mask.kv_40_8.key;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000145 pkey = (u64 *) kv.key;
146
147 *pkey++ = *pmatch++ & *pmask++;
148 *pkey++ = *pmatch++ & *pmask++;
149 *pkey++ = *pmatch++ & *pmask++;
150 *pkey++ = *pmatch++ & *pmask++;
Piotr Bronowski86f82082022-07-08 12:45:05 +0000151 *pkey = *pmatch & *pmask;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000152
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
210static_always_inline u32
211ipsec_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
Piotr Bronowski81880602022-07-18 16:45:22 +0000244 pmatch = (u64 *) match->kv_16_8.key;
245 pmask = (u64 *) mte->mask.kv_16_8.key;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000246 pkey = (u64 *) kv.key;
247
248 *pkey++ = *pmatch++ & *pmask++;
Piotr Bronowski81880602022-07-18 16:45:22 +0000249 *pkey = *pmatch & *pmask;
Piotr Bronowskie1dce372022-05-10 14:06:29 +0000250
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
311static_always_inline u32
312ipsec_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 */