blob: 571a4b82fd2a477fa484dfbc543cbe76c5a1238b [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;
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
211static_always_inline u32
212ipsec_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
312static_always_inline u32
313ipsec_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 */