Line data Source code
1 : /*
2 : * Copyright (c) 2015 Cisco and/or its affiliates.
3 : * Licensed under the Apache License, Version 2.0 (the "License");
4 : * you may not use this file except in compliance with the License.
5 : * You may obtain a copy of the License at:
6 : *
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : *
9 : * Unless required by applicable law or agreed to in writing, software
10 : * distributed under the License is distributed on an "AS IS" BASIS,
11 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : * See the License for the specific language governing permissions and
13 : * limitations under the License.
14 : */
15 :
16 : #include <vnet/ipsec/ipsec.h>
17 :
18 : /**
19 : * @brief
20 : * Policy packet & bytes counters
21 : */
22 : vlib_combined_counter_main_t ipsec_spd_policy_counters = {
23 : .name = "policy",
24 : .stat_segment_name = "/net/ipsec/policy",
25 : };
26 :
27 : int
28 33260 : ipsec_policy_mk_type (bool is_outbound,
29 : bool is_ipv6,
30 : ipsec_policy_action_t action,
31 : ipsec_spd_policy_type_t * type)
32 : {
33 33260 : if (is_outbound)
34 : {
35 16668 : *type = (is_ipv6 ?
36 16668 : IPSEC_SPD_POLICY_IP6_OUTBOUND : IPSEC_SPD_POLICY_IP4_OUTBOUND);
37 16668 : return (0);
38 : }
39 : else
40 : {
41 16592 : switch (action)
42 : {
43 9904 : case IPSEC_POLICY_ACTION_PROTECT:
44 9904 : *type = (is_ipv6 ?
45 9904 : IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT :
46 : IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT);
47 9904 : return (0);
48 6660 : case IPSEC_POLICY_ACTION_BYPASS:
49 6660 : *type = (is_ipv6 ?
50 6660 : IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS :
51 : IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS);
52 6660 : return (0);
53 28 : case IPSEC_POLICY_ACTION_DISCARD:
54 28 : *type = (is_ipv6 ?
55 28 : IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD :
56 : IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD);
57 28 : return (0);
58 0 : case IPSEC_POLICY_ACTION_RESOLVE:
59 0 : break;
60 : }
61 0 : }
62 :
63 : /* Unsupported type */
64 0 : return (-1);
65 : }
66 :
67 : static_always_inline int
68 134 : ipsec_is_policy_inbound (ipsec_policy_t *policy)
69 : {
70 134 : if (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
71 128 : policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
72 106 : policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD ||
73 90 : policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT ||
74 84 : policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS ||
75 80 : policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD)
76 54 : return 1;
77 :
78 80 : return 0;
79 : }
80 :
81 : static_always_inline int
82 33260 : ipsec_is_fp_enabled (ipsec_main_t *im, ipsec_spd_t *spd,
83 : ipsec_policy_t *policy)
84 : {
85 33260 : if ((im->fp_spd_ipv4_out_is_enabled &&
86 44 : PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip4_out_lookup_hash_idx) &&
87 44 : policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND) ||
88 33218 : (im->fp_spd_ipv4_in_is_enabled &&
89 88 : PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip4_in_lookup_hash_idx) &&
90 88 : (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
91 82 : policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
92 60 : policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD)) ||
93 33174 : (im->fp_spd_ipv6_in_is_enabled &&
94 40 : PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip6_in_lookup_hash_idx) &&
95 40 : (policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT ||
96 34 : policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS ||
97 30 : policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD)) ||
98 33164 : (im->fp_spd_ipv6_out_is_enabled &&
99 40 : PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip6_out_lookup_hash_idx) &&
100 40 : policy->type == IPSEC_SPD_POLICY_IP6_OUTBOUND))
101 134 : return 1;
102 33126 : return 0;
103 : }
104 :
105 : int
106 33260 : ipsec_add_del_policy (vlib_main_t * vm,
107 : ipsec_policy_t * policy, int is_add, u32 * stat_index)
108 : {
109 33260 : ipsec_main_t *im = &ipsec_main;
110 33260 : ipsec_spd_t *spd = 0;
111 : ipsec_policy_t *vp;
112 : u32 spd_index;
113 : uword *p;
114 :
115 33260 : p = hash_get (im->spd_index_by_spd_id, policy->id);
116 :
117 33260 : if (!p)
118 0 : return VNET_API_ERROR_SYSCALL_ERROR_1;
119 :
120 33260 : spd_index = p[0];
121 33260 : spd = pool_elt_at_index (im->spds, spd_index);
122 33260 : if (!spd)
123 0 : return VNET_API_ERROR_SYSCALL_ERROR_1;
124 :
125 33260 : if (im->output_flow_cache_flag && !policy->is_ipv6 &&
126 46 : policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND)
127 : {
128 : /*
129 : * Flow cache entry is valid only when epoch_count value in control
130 : * plane and data plane match. Otherwise, flow cache entry is considered
131 : * stale. To avoid the race condition of using old epoch_count value
132 : * in data plane after the roll over of epoch_count in control plane,
133 : * entire flow cache is reset.
134 : */
135 38 : if (im->epoch_count == 0xFFFFFFFF)
136 : {
137 : /* Reset all the entries in flow cache */
138 0 : clib_memset_u8 (im->ipsec4_out_spd_hash_tbl, 0,
139 0 : im->ipsec4_out_spd_hash_num_buckets *
140 : (sizeof (*(im->ipsec4_out_spd_hash_tbl))));
141 : }
142 : /* Increment epoch counter by 1 */
143 38 : clib_atomic_fetch_add_relax (&im->epoch_count, 1);
144 : /* Reset spd flow cache counter since all old entries are stale */
145 38 : clib_atomic_store_relax_n (&im->ipsec4_out_spd_flow_cache_entries, 0);
146 : }
147 :
148 33260 : if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
149 28294 : policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
150 24928 : policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD) &&
151 8360 : im->input_flow_cache_flag && !policy->is_ipv6)
152 : {
153 : /*
154 : * Flow cache entry is valid only when input_epoch_count value in control
155 : * plane and data plane match. Otherwise, flow cache entry is considered
156 : * stale. To avoid the race condition of using old input_epoch_count
157 : * value in data plane after the roll over of input_epoch_count in
158 : * control plane, entire flow cache is reset.
159 : */
160 34 : if (im->input_epoch_count == 0xFFFFFFFF)
161 : {
162 : /* Reset all the entries in flow cache */
163 0 : clib_memset_u8 (im->ipsec4_in_spd_hash_tbl, 0,
164 0 : im->ipsec4_in_spd_hash_num_buckets *
165 : (sizeof (*(im->ipsec4_in_spd_hash_tbl))));
166 : }
167 : /* Increment epoch counter by 1 */
168 34 : clib_atomic_fetch_add_relax (&im->input_epoch_count, 1);
169 : /* Reset spd flow cache counter since all old entries are stale */
170 34 : im->ipsec4_in_spd_flow_cache_entries = 0;
171 : }
172 :
173 33260 : if (is_add)
174 : {
175 : u32 policy_index;
176 : u32 i;
177 :
178 16631 : if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
179 : {
180 9909 : index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
181 :
182 9909 : if (INDEX_INVALID == sa_index)
183 67 : return VNET_API_ERROR_SYSCALL_ERROR_1;
184 9909 : policy->sa_index = sa_index;
185 : }
186 : else
187 6722 : policy->sa_index = INDEX_INVALID;
188 :
189 : /**
190 : * Try adding the policy into fast path SPD first. Only adding to
191 : * traditional SPD when failed.
192 : **/
193 16631 : if (ipsec_is_fp_enabled (im, spd, policy))
194 67 : return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 1,
195 : stat_index);
196 :
197 16564 : pool_get (im->policies, vp);
198 16564 : clib_memcpy (vp, policy, sizeof (*vp));
199 16564 : policy_index = vp - im->policies;
200 :
201 16564 : vlib_validate_combined_counter (&ipsec_spd_policy_counters,
202 : policy_index);
203 16564 : vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
204 :
205 21541 : vec_foreach_index (i, spd->policies[policy->type])
206 : {
207 8295 : ipsec_policy_t *p =
208 8295 : pool_elt_at_index (im->policies, spd->policies[policy->type][i]);
209 :
210 8295 : if (p->priority <= vp->priority)
211 : {
212 3318 : break;
213 : }
214 : }
215 :
216 16564 : vec_insert_elts (spd->policies[policy->type], &policy_index, 1, i);
217 :
218 16564 : *stat_index = policy_index;
219 : }
220 : else
221 : {
222 : u32 ii;
223 :
224 : /**
225 : * Try to delete the policy from the fast path SPD first. Delete from
226 : * traditional SPD when fp delete fails.
227 : **/
228 :
229 16629 : if (ipsec_is_fp_enabled (im, spd, policy))
230 :
231 : {
232 67 : if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
233 : {
234 6 : index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
235 :
236 6 : if (INDEX_INVALID == sa_index)
237 0 : return VNET_API_ERROR_SYSCALL_ERROR_1;
238 6 : policy->sa_index = sa_index;
239 6 : ipsec_sa_unlock_id (policy->sa_id);
240 : }
241 : else
242 61 : policy->sa_index = INDEX_INVALID;
243 :
244 67 : return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 0,
245 : stat_index);
246 : }
247 :
248 21552 : vec_foreach_index (ii, (spd->policies[policy->type]))
249 : {
250 21552 : vp = pool_elt_at_index (im->policies,
251 : spd->policies[policy->type][ii]);
252 21552 : if (ipsec_policy_is_equal (vp, policy))
253 : {
254 16562 : vec_delete (spd->policies[policy->type], 1, ii);
255 16562 : ipsec_sa_unlock (vp->sa_index);
256 16562 : pool_put (im->policies, vp);
257 16562 : break;
258 : }
259 : }
260 : }
261 :
262 33126 : return 0;
263 : }
264 :
265 : static_always_inline void
266 67 : ipsec_fp_release_mask_type (ipsec_main_t *im, u32 mask_type_index)
267 : {
268 67 : ipsec_fp_mask_type_entry_t *mte =
269 67 : pool_elt_at_index (im->fp_mask_types, mask_type_index);
270 67 : mte->refcount--;
271 67 : if (mte->refcount == 0)
272 : {
273 : /* this entry is not in use anymore */
274 26 : ASSERT (clib_memset (mte, 0xae, sizeof (*mte)) == EOK);
275 26 : pool_put (im->fp_mask_types, mte);
276 : }
277 67 : }
278 :
279 : static_always_inline u32
280 67 : find_mask_type_index (ipsec_main_t *im, ipsec_fp_5tuple_t *mask)
281 : {
282 : ipsec_fp_mask_type_entry_t *mte;
283 :
284 73 : pool_foreach (mte, im->fp_mask_types)
285 : {
286 47 : if (memcmp (&mte->mask, mask, sizeof (*mask)) == 0)
287 41 : return (mte - im->fp_mask_types);
288 : }
289 :
290 26 : return ~0;
291 : }
292 :
293 : static_always_inline void
294 48 : fill_ip6_hash_policy_kv (ipsec_fp_5tuple_t *match, ipsec_fp_5tuple_t *mask,
295 : clib_bihash_kv_40_8_t *kv)
296 : {
297 48 : ipsec_fp_lookup_value_t *kv_val = (ipsec_fp_lookup_value_t *) &kv->value;
298 48 : u64 *pmatch = (u64 *) match->kv_40_8.key;
299 48 : u64 *pmask = (u64 *) mask->kv_40_8.key;
300 48 : u64 *pkey = (u64 *) kv->key;
301 :
302 48 : *pkey++ = *pmatch++ & *pmask++;
303 48 : *pkey++ = *pmatch++ & *pmask++;
304 48 : *pkey++ = *pmatch++ & *pmask++;
305 48 : *pkey++ = *pmatch++ & *pmask++;
306 48 : *pkey = *pmatch & *pmask;
307 :
308 48 : kv_val->as_u64 = 0;
309 48 : }
310 :
311 : static_always_inline void
312 86 : fill_ip4_hash_policy_kv (ipsec_fp_5tuple_t *match, ipsec_fp_5tuple_t *mask,
313 : clib_bihash_kv_16_8_t *kv)
314 : {
315 86 : ipsec_fp_lookup_value_t *kv_val = (ipsec_fp_lookup_value_t *) &kv->value;
316 86 : u64 *pmatch = (u64 *) match->kv_16_8.key;
317 86 : u64 *pmask = (u64 *) mask->kv_16_8.key;
318 86 : u64 *pkey = (u64 *) kv->key;
319 :
320 86 : *pkey++ = *pmatch++ & *pmask++;
321 86 : *pkey = *pmatch & *pmask;
322 :
323 86 : kv_val->as_u64 = 0;
324 86 : }
325 :
326 : static_always_inline u16
327 160 : mask_out_highest_set_bit_u16 (u16 x)
328 : {
329 160 : x |= x >> 8;
330 160 : x |= x >> 4;
331 160 : x |= x >> 2;
332 160 : x |= x >> 1;
333 160 : return ~x;
334 : }
335 :
336 : static_always_inline u32
337 164 : mask_out_highest_set_bit_u32 (u32 x)
338 : {
339 164 : x |= x >> 16;
340 164 : x |= x >> 8;
341 164 : x |= x >> 4;
342 164 : x |= x >> 2;
343 164 : x |= x >> 1;
344 164 : return ~x;
345 : }
346 :
347 : static_always_inline u64
348 148 : mask_out_highest_set_bit_u64 (u64 x)
349 : {
350 148 : x |= x >> 32;
351 148 : x |= x >> 16;
352 148 : x |= x >> 8;
353 148 : x |= x >> 4;
354 148 : x |= x >> 2;
355 148 : x |= x >> 1;
356 148 : return ~x;
357 : }
358 :
359 : static_always_inline void
360 80 : ipsec_fp_get_policy_ports_mask (ipsec_policy_t *policy,
361 : ipsec_fp_5tuple_t *mask)
362 : {
363 80 : if (PREDICT_TRUE ((policy->protocol == IP_PROTOCOL_TCP) ||
364 : (policy->protocol == IP_PROTOCOL_UDP) ||
365 : (policy->protocol == IP_PROTOCOL_SCTP)))
366 : {
367 80 : mask->lport = policy->lport.start ^ policy->lport.stop;
368 80 : mask->rport = policy->rport.start ^ policy->rport.stop;
369 :
370 80 : mask->lport = mask_out_highest_set_bit_u16 (mask->lport);
371 :
372 80 : mask->rport = mask_out_highest_set_bit_u16 (mask->rport);
373 : }
374 : else
375 : {
376 0 : mask->lport = 0;
377 0 : mask->rport = 0;
378 : }
379 :
380 80 : mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0;
381 80 : }
382 :
383 : static_always_inline void
384 86 : ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask,
385 : bool inbound)
386 : {
387 86 : u32 *pladdr_start = (u32 *) &policy->laddr.start.ip4;
388 86 : u32 *pladdr_stop = (u32 *) &policy->laddr.stop.ip4;
389 86 : u32 *plmask = (u32 *) &mask->laddr;
390 86 : u32 *praddr_start = (u32 *) &policy->raddr.start.ip4;
391 86 : u32 *praddr_stop = (u32 *) &policy->raddr.stop.ip4;
392 86 : u32 *prmask = (u32 *) &mask->raddr;
393 :
394 86 : clib_memset_u8 (mask, 0xff, sizeof (ipsec_fp_5tuple_t));
395 86 : clib_memset_u8 (&mask->l3_zero_pad, 0, sizeof (mask->l3_zero_pad));
396 :
397 86 : if (inbound && (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT &&
398 6 : policy->sa_index != INDEX_INVALID))
399 : {
400 6 : ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
401 :
402 6 : if (ipsec_sa_is_set_IS_TUNNEL (s))
403 4 : goto set_spi_mask;
404 : }
405 :
406 : /* find bits where start != stop */
407 82 : *plmask = *pladdr_start ^ *pladdr_stop;
408 82 : *prmask = *praddr_start ^ *praddr_stop;
409 : /* Find most significant bit set (that is the first position
410 : * start differs from stop). Mask out everything after that bit and
411 : * the bit itself. Remember that policy stores start and stop in the net
412 : * order.
413 : */
414 82 : *plmask = clib_host_to_net_u32 (
415 : mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*plmask)));
416 :
417 82 : *prmask = clib_host_to_net_u32 (
418 : mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask)));
419 :
420 86 : set_spi_mask:
421 86 : if (inbound)
422 : {
423 44 : if (policy->type != IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT)
424 38 : mask->spi = 0;
425 :
426 44 : mask->protocol = 0;
427 : }
428 : else
429 : {
430 42 : mask->action = 0;
431 42 : ipsec_fp_get_policy_ports_mask (policy, mask);
432 : }
433 86 : }
434 :
435 : static_always_inline void
436 48 : ipsec_fp_ip6_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask,
437 : bool inbound)
438 : {
439 48 : u64 *pladdr_start = (u64 *) &policy->laddr.start;
440 48 : u64 *pladdr_stop = (u64 *) &policy->laddr.stop;
441 48 : u64 *plmask = (u64 *) &mask->ip6_laddr;
442 48 : u64 *praddr_start = (u64 *) &policy->raddr.start;
443 48 : u64 *praddr_stop = (u64 *) &policy->raddr.stop;
444 48 : u64 *prmask = (u64 *) &mask->ip6_raddr;
445 :
446 48 : clib_memset_u8 (mask, 0xff, sizeof (ipsec_fp_5tuple_t));
447 :
448 48 : if (inbound && (policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT &&
449 6 : policy->sa_index != INDEX_INVALID))
450 : {
451 6 : ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
452 :
453 6 : if (ipsec_sa_is_set_IS_TUNNEL (s))
454 4 : goto set_spi_mask;
455 : }
456 :
457 44 : *plmask = (*pladdr_start++ ^ *pladdr_stop++);
458 :
459 44 : *prmask = (*praddr_start++ ^ *praddr_stop++);
460 :
461 : /* Find most significant bit set (that is the first position
462 : * start differs from stop). Mask out everything after that bit and
463 : * the bit itself. Remember that policy stores start and stop in the net
464 : * order.
465 : */
466 44 : *plmask = clib_host_to_net_u64 (
467 : mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*plmask)));
468 :
469 44 : if (*plmask++ & clib_host_to_net_u64 (0x1))
470 : {
471 28 : *plmask = (*pladdr_start ^ *pladdr_stop);
472 28 : *plmask = clib_host_to_net_u64 (
473 : mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*plmask)));
474 : }
475 : else
476 16 : *plmask = 0;
477 :
478 44 : *prmask = clib_host_to_net_u64 (
479 : mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*prmask)));
480 :
481 44 : if (*prmask++ & clib_host_to_net_u64 (0x1))
482 : {
483 32 : *prmask = (*pladdr_start ^ *pladdr_stop);
484 32 : *prmask = clib_host_to_net_u64 (
485 : mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*prmask)));
486 : }
487 : else
488 12 : *prmask = 0;
489 48 : set_spi_mask:
490 48 : if (inbound)
491 : {
492 10 : if (policy->type != IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT)
493 4 : mask->spi = 0;
494 :
495 10 : mask->protocol = 0;
496 : }
497 : else
498 : {
499 38 : mask->action = 0;
500 38 : ipsec_fp_get_policy_ports_mask (policy, mask);
501 : }
502 48 : }
503 :
504 : static_always_inline void
505 134 : ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple,
506 : bool inbound)
507 : {
508 134 : memset (tuple, 0, sizeof (*tuple));
509 134 : tuple->is_ipv6 = policy->is_ipv6;
510 134 : if (tuple->is_ipv6)
511 : {
512 48 : tuple->ip6_laddr = policy->laddr.start.ip6;
513 48 : tuple->ip6_raddr = policy->raddr.start.ip6;
514 : }
515 : else
516 : {
517 86 : tuple->laddr = policy->laddr.start.ip4;
518 86 : tuple->raddr = policy->raddr.start.ip4;
519 : }
520 :
521 134 : if (inbound)
522 : {
523 :
524 54 : if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
525 48 : policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT) &&
526 12 : policy->sa_index != INDEX_INVALID)
527 12 : {
528 12 : ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
529 :
530 12 : tuple->spi = s->spi;
531 12 : if (ipsec_sa_is_set_IS_TUNNEL (s))
532 : {
533 8 : if (tuple->is_ipv6)
534 : {
535 4 : tuple->ip6_laddr = s->tunnel.t_dst.ip.ip6;
536 4 : tuple->ip6_raddr = s->tunnel.t_src.ip.ip6;
537 : }
538 : else
539 : {
540 4 : tuple->laddr = s->tunnel.t_dst.ip.ip4;
541 4 : tuple->raddr = s->tunnel.t_src.ip.ip4;
542 : }
543 : }
544 : }
545 : else
546 42 : tuple->spi = INDEX_INVALID;
547 54 : tuple->action = policy->type;
548 54 : return;
549 : }
550 :
551 80 : tuple->protocol = policy->protocol;
552 80 : tuple->lport = policy->lport.start;
553 80 : tuple->rport = policy->rport.start;
554 : }
555 :
556 : static_always_inline int
557 31 : ipsec_fp_mask_type_idx_cmp (ipsec_fp_mask_id_t *mask_id, u32 *idx)
558 : {
559 31 : return mask_id->mask_type_idx == *idx;
560 : }
561 :
562 : int
563 43 : ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
564 : ipsec_policy_t *policy, u32 *stat_index)
565 : {
566 : u32 mask_index, searched_idx;
567 : ipsec_policy_t *vp;
568 : ipsec_fp_mask_type_entry_t *mte;
569 : u32 policy_index;
570 : clib_bihash_kv_16_8_t kv;
571 : clib_bihash_kv_16_8_t result;
572 43 : ipsec_fp_lookup_value_t *result_val =
573 : (ipsec_fp_lookup_value_t *) &result.value;
574 43 : ipsec_fp_lookup_value_t *key_val = (ipsec_fp_lookup_value_t *) &kv.value;
575 :
576 : ipsec_fp_5tuple_t mask, policy_5tuple;
577 : int res;
578 43 : bool inbound = ipsec_is_policy_inbound (policy);
579 43 : clib_bihash_16_8_t *bihash_table =
580 22 : inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
581 65 : fp_spd->ip4_in_lookup_hash_idx) :
582 21 : pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
583 : fp_spd->ip4_out_lookup_hash_idx);
584 :
585 43 : ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound);
586 43 : pool_get (im->policies, vp);
587 43 : policy_index = vp - im->policies;
588 43 : vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
589 43 : vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
590 43 : *stat_index = policy_index;
591 43 : mask_index = find_mask_type_index (im, &mask);
592 :
593 43 : if (mask_index == ~0)
594 : {
595 : /* mask type not found, we need to create a new entry */
596 17 : pool_get (im->fp_mask_types, mte);
597 17 : mask_index = mte - im->fp_mask_types;
598 17 : mte->refcount = 0;
599 : }
600 : else
601 26 : mte = im->fp_mask_types + mask_index;
602 :
603 43 : policy->fp_mask_type_id = mask_index;
604 43 : ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
605 :
606 43 : fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv);
607 :
608 43 : res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
609 43 : if (res != 0)
610 : {
611 : /* key was not found crate a new entry */
612 31 : vec_add1 (key_val->fp_policies_ids, policy_index);
613 31 : res = clib_bihash_add_del_16_8 (bihash_table, &kv, 1);
614 :
615 31 : if (res != 0)
616 0 : goto error;
617 : }
618 : else
619 : {
620 : u32 i;
621 12 : u32 *old_fp_policies_ids = result_val->fp_policies_ids;
622 :
623 20 : vec_foreach_index (i, result_val->fp_policies_ids)
624 : {
625 12 : ipsec_policy_t *p =
626 12 : pool_elt_at_index (im->policies, result_val->fp_policies_ids[i]);
627 :
628 12 : if (p->priority <= policy->priority)
629 : {
630 4 : break;
631 : }
632 : }
633 :
634 12 : vec_insert_elts (result_val->fp_policies_ids, &policy_index, 1, i);
635 :
636 12 : if (result_val->fp_policies_ids != old_fp_policies_ids)
637 : {
638 0 : res = clib_bihash_add_del_16_8 (bihash_table, &result, 1);
639 :
640 0 : if (res != 0)
641 0 : goto error;
642 : }
643 : }
644 :
645 43 : if (mte->refcount == 0)
646 : {
647 17 : clib_memcpy (&mte->mask, &mask, sizeof (mask));
648 17 : mte->refcount = 0;
649 : }
650 :
651 43 : searched_idx =
652 43 : vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index,
653 : ipsec_fp_mask_type_idx_cmp);
654 43 : if (~0 == searched_idx)
655 : {
656 25 : ipsec_fp_mask_id_t mask_id = { mask_index, 1 };
657 25 : vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id);
658 : }
659 : else
660 18 : (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++;
661 :
662 43 : mte->refcount++;
663 43 : clib_memcpy (vp, policy, sizeof (*vp));
664 :
665 43 : return 0;
666 :
667 0 : error:
668 0 : pool_put (im->policies, vp);
669 0 : ipsec_fp_release_mask_type (im, mask_index);
670 0 : return -1;
671 : }
672 :
673 : int
674 24 : ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
675 : ipsec_policy_t *policy, u32 *stat_index)
676 : {
677 :
678 : u32 mask_index, searched_idx;
679 : ipsec_policy_t *vp;
680 : ipsec_fp_mask_type_entry_t *mte;
681 : u32 policy_index;
682 : clib_bihash_kv_40_8_t kv;
683 : clib_bihash_kv_40_8_t result;
684 24 : ipsec_fp_lookup_value_t *result_val =
685 : (ipsec_fp_lookup_value_t *) &result.value;
686 24 : ipsec_fp_lookup_value_t *key_val = (ipsec_fp_lookup_value_t *) &kv.value;
687 :
688 : ipsec_fp_5tuple_t mask, policy_5tuple;
689 : int res;
690 24 : bool inbound = ipsec_is_policy_inbound (policy);
691 :
692 24 : ipsec_fp_ip6_get_policy_mask (policy, &mask, inbound);
693 24 : pool_get (im->policies, vp);
694 24 : policy_index = vp - im->policies;
695 24 : vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
696 24 : vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
697 24 : *stat_index = policy_index;
698 24 : mask_index = find_mask_type_index (im, &mask);
699 24 : clib_bihash_40_8_t *bihash_table =
700 5 : inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
701 29 : fp_spd->ip6_in_lookup_hash_idx) :
702 19 : pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
703 : fp_spd->ip6_out_lookup_hash_idx);
704 :
705 24 : if (mask_index == ~0)
706 : {
707 : /* mask type not found, we need to create a new entry */
708 9 : pool_get (im->fp_mask_types, mte);
709 9 : mask_index = mte - im->fp_mask_types;
710 9 : mte->refcount = 0;
711 : }
712 : else
713 15 : mte = im->fp_mask_types + mask_index;
714 :
715 24 : policy->fp_mask_type_id = mask_index;
716 24 : ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
717 :
718 24 : fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv);
719 :
720 24 : res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
721 24 : if (res != 0)
722 : {
723 : /* key was not found crate a new entry */
724 13 : vec_add1 (key_val->fp_policies_ids, policy_index);
725 13 : res = clib_bihash_add_del_40_8 (bihash_table, &kv, 1);
726 13 : if (res != 0)
727 0 : goto error;
728 : }
729 : else
730 : {
731 : u32 i;
732 11 : u32 *old_fp_policies_ids = result_val->fp_policies_ids;
733 :
734 18 : vec_foreach_index (i, result_val->fp_policies_ids)
735 : {
736 11 : ipsec_policy_t *p =
737 11 : pool_elt_at_index (im->policies, result_val->fp_policies_ids[i]);
738 :
739 11 : if (p->priority <= policy->priority)
740 : {
741 4 : break;
742 : }
743 : }
744 :
745 11 : vec_insert_elts (result_val->fp_policies_ids, &policy_index, 1, i);
746 :
747 11 : if (result_val->fp_policies_ids != old_fp_policies_ids)
748 : {
749 0 : res = clib_bihash_add_del_40_8 (bihash_table, &result, 1);
750 :
751 0 : if (res != 0)
752 0 : goto error;
753 : }
754 : }
755 :
756 24 : if (mte->refcount == 0)
757 : {
758 9 : clib_memcpy (&mte->mask, &mask, sizeof (mask));
759 9 : mte->refcount = 0;
760 : }
761 :
762 24 : searched_idx =
763 24 : vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index,
764 : ipsec_fp_mask_type_idx_cmp);
765 24 : if (~0 == searched_idx)
766 : {
767 11 : ipsec_fp_mask_id_t mask_id = { mask_index, 1 };
768 11 : vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id);
769 : }
770 : else
771 13 : (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++;
772 :
773 24 : mte->refcount++;
774 24 : clib_memcpy (vp, policy, sizeof (*vp));
775 :
776 24 : return 0;
777 :
778 0 : error:
779 0 : pool_put (im->policies, vp);
780 0 : ipsec_fp_release_mask_type (im, mask_index);
781 0 : return -1;
782 : }
783 :
784 : int
785 24 : ipsec_fp_ip6_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
786 : ipsec_policy_t *policy)
787 : {
788 : int res;
789 24 : ipsec_fp_5tuple_t mask = { 0 }, policy_5tuple;
790 : clib_bihash_kv_40_8_t kv;
791 : clib_bihash_kv_40_8_t result;
792 24 : ipsec_fp_lookup_value_t *result_val =
793 : (ipsec_fp_lookup_value_t *) &result.value;
794 24 : bool inbound = ipsec_is_policy_inbound (policy);
795 24 : clib_bihash_40_8_t *bihash_table =
796 5 : inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
797 29 : fp_spd->ip6_in_lookup_hash_idx) :
798 19 : pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
799 : fp_spd->ip6_out_lookup_hash_idx);
800 :
801 : ipsec_policy_t *vp;
802 : u32 ii, imt;
803 :
804 24 : ipsec_fp_ip6_get_policy_mask (policy, &mask, inbound);
805 24 : ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
806 24 : fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv);
807 24 : res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
808 24 : if (res != 0)
809 0 : return -1;
810 :
811 27 : vec_foreach_index (ii, result_val->fp_policies_ids)
812 : {
813 27 : vp =
814 27 : pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
815 27 : if (ipsec_policy_is_equal (vp, policy))
816 : {
817 24 : if (vec_len (result_val->fp_policies_ids) == 1)
818 : {
819 13 : vec_free (result_val->fp_policies_ids);
820 13 : clib_bihash_add_del_40_8 (bihash_table, &result, 0);
821 : }
822 : else
823 11 : vec_delete (result_val->fp_policies_ids, 1, ii);
824 :
825 24 : vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
826 : {
827 24 : if ((fp_spd->fp_mask_ids[policy->type] + imt)->mask_type_idx ==
828 24 : vp->fp_mask_type_id)
829 : {
830 :
831 24 : if ((fp_spd->fp_mask_ids[policy->type] + imt)->refcount-- ==
832 : 1)
833 11 : vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
834 :
835 24 : break;
836 : }
837 : }
838 :
839 24 : ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
840 24 : ipsec_sa_unlock (vp->sa_index);
841 24 : pool_put (im->policies, vp);
842 24 : return 0;
843 : }
844 : }
845 0 : return -1;
846 : }
847 :
848 : int
849 43 : ipsec_fp_ip4_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
850 : ipsec_policy_t *policy)
851 : {
852 : int res;
853 43 : ipsec_fp_5tuple_t mask = { 0 }, policy_5tuple;
854 : clib_bihash_kv_16_8_t kv;
855 : clib_bihash_kv_16_8_t result;
856 43 : ipsec_fp_lookup_value_t *result_val =
857 : (ipsec_fp_lookup_value_t *) &result.value;
858 43 : bool inbound = ipsec_is_policy_inbound (policy);
859 : ipsec_policy_t *vp;
860 : u32 ii, imt;
861 43 : clib_bihash_16_8_t *bihash_table =
862 22 : inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
863 65 : fp_spd->ip4_in_lookup_hash_idx) :
864 21 : pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
865 : fp_spd->ip4_out_lookup_hash_idx);
866 :
867 43 : ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound);
868 43 : ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
869 43 : fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv);
870 43 : res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
871 :
872 43 : if (res != 0)
873 0 : return -1;
874 :
875 46 : vec_foreach_index (ii, result_val->fp_policies_ids)
876 : {
877 46 : vp =
878 46 : pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
879 46 : if (ipsec_policy_is_equal (vp, policy))
880 : {
881 43 : if (vec_len (result_val->fp_policies_ids) == 1)
882 : {
883 31 : vec_free (result_val->fp_policies_ids);
884 31 : clib_bihash_add_del_16_8 (bihash_table, &result, 0);
885 : }
886 : else
887 12 : vec_delete (result_val->fp_policies_ids, 1, ii);
888 :
889 43 : vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
890 : {
891 43 : if ((fp_spd->fp_mask_ids[policy->type] + imt)->mask_type_idx ==
892 43 : vp->fp_mask_type_id)
893 : {
894 :
895 43 : if ((fp_spd->fp_mask_ids[policy->type] + imt)->refcount-- ==
896 : 1)
897 25 : vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
898 :
899 43 : break;
900 : }
901 : }
902 43 : ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
903 43 : ipsec_sa_unlock (vp->sa_index);
904 43 : pool_put (im->policies, vp);
905 43 : return 0;
906 : }
907 : }
908 0 : return -1;
909 : }
910 :
911 : int
912 134 : ipsec_fp_add_del_policy (void *fp_spd, ipsec_policy_t *policy, int is_add,
913 : u32 *stat_index)
914 : {
915 134 : ipsec_main_t *im = &ipsec_main;
916 :
917 134 : if (is_add)
918 67 : if (policy->is_ipv6)
919 24 : return ipsec_fp_ip6_add_policy (im, (ipsec_spd_fp_t *) fp_spd, policy,
920 : stat_index);
921 : else
922 43 : return ipsec_fp_ip4_add_policy (im, (ipsec_spd_fp_t *) fp_spd, policy,
923 : stat_index);
924 :
925 67 : else if (policy->is_ipv6)
926 :
927 24 : return ipsec_fp_ip6_del_policy (im, (ipsec_spd_fp_t *) fp_spd, policy);
928 : else
929 43 : return ipsec_fp_ip4_del_policy (im, (ipsec_spd_fp_t *) fp_spd, policy);
930 : }
931 :
932 : /*
933 : * fd.io coding-style-patch-verification: ON
934 : *
935 : * Local Variables:
936 : * eval: (c-set-style "gnu")
937 : * End:
938 : */
|