blob: 8cdbe3257d7f6f3825cfa2053546ee5a86e5ed6c [file] [log] [blame]
Neale Ranns999c8ee2019-02-01 03:31:24 -08001/*
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
Neale Rannsa09c1ff2019-02-04 01:10:30 -080018/**
19 * @brief
20 * Policy packet & bytes counters
21 */
22vlib_combined_counter_main_t ipsec_spd_policy_counters = {
23 .name = "policy",
24 .stat_segment_name = "/net/ipsec/policy",
25};
26
27static int
Neale Ranns999c8ee2019-02-01 03:31:24 -080028ipsec_spd_entry_sort (void *a1, void *a2)
29{
Neale Rannsa09c1ff2019-02-04 01:10:30 -080030 ipsec_main_t *im = &ipsec_main;
Neale Ranns999c8ee2019-02-01 03:31:24 -080031 u32 *id1 = a1;
32 u32 *id2 = a2;
Neale Ranns999c8ee2019-02-01 03:31:24 -080033 ipsec_policy_t *p1, *p2;
34
Neale Rannsa09c1ff2019-02-04 01:10:30 -080035 p1 = pool_elt_at_index (im->policies, *id1);
36 p2 = pool_elt_at_index (im->policies, *id2);
Neale Ranns999c8ee2019-02-01 03:31:24 -080037 if (p1 && p2)
38 return p2->priority - p1->priority;
39
40 return 0;
41}
42
43int
Neale Ranns9f231d42019-03-19 10:06:00 +000044ipsec_policy_mk_type (bool is_outbound,
45 bool is_ipv6,
46 ipsec_policy_action_t action,
47 ipsec_spd_policy_type_t * type)
48{
49 if (is_outbound)
50 {
51 *type = (is_ipv6 ?
52 IPSEC_SPD_POLICY_IP6_OUTBOUND : IPSEC_SPD_POLICY_IP4_OUTBOUND);
53 return (0);
54 }
55 else
56 {
57 switch (action)
58 {
59 case IPSEC_POLICY_ACTION_PROTECT:
60 *type = (is_ipv6 ?
61 IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT :
62 IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT);
63 return (0);
64 case IPSEC_POLICY_ACTION_BYPASS:
65 *type = (is_ipv6 ?
66 IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS :
67 IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS);
68 return (0);
69 case IPSEC_POLICY_ACTION_DISCARD:
ShivaShankarK05464832020-04-14 14:01:03 +053070 *type = (is_ipv6 ?
71 IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD :
72 IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD);
73 return (0);
Neale Ranns9f231d42019-03-19 10:06:00 +000074 case IPSEC_POLICY_ACTION_RESOLVE:
75 break;
76 }
77 }
78
79 /* Unsupported type */
80 return (-1);
81}
82
83int
Neale Rannsa09c1ff2019-02-04 01:10:30 -080084ipsec_add_del_policy (vlib_main_t * vm,
85 ipsec_policy_t * policy, int is_add, u32 * stat_index)
Neale Ranns999c8ee2019-02-01 03:31:24 -080086{
87 ipsec_main_t *im = &ipsec_main;
88 ipsec_spd_t *spd = 0;
89 ipsec_policy_t *vp;
Neale Ranns999c8ee2019-02-01 03:31:24 -080090 u32 spd_index;
Neale Rannsa09c1ff2019-02-04 01:10:30 -080091 uword *p;
Neale Ranns999c8ee2019-02-01 03:31:24 -080092
Neale Ranns999c8ee2019-02-01 03:31:24 -080093 p = hash_get (im->spd_index_by_spd_id, policy->id);
94
95 if (!p)
96 return VNET_API_ERROR_SYSCALL_ERROR_1;
97
98 spd_index = p[0];
99 spd = pool_elt_at_index (im->spds, spd_index);
100 if (!spd)
101 return VNET_API_ERROR_SYSCALL_ERROR_1;
102
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500103 if (im->output_flow_cache_flag && !policy->is_ipv6 &&
Govindarajan Mohandoss6d7dfcb2021-03-19 19:20:49 +0000104 policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND)
105 {
106 /*
107 * Flow cache entry is valid only when epoch_count value in control
108 * plane and data plane match. Otherwise, flow cache entry is considered
109 * stale. To avoid the race condition of using old epoch_count value
110 * in data plane after the roll over of epoch_count in control plane,
111 * entire flow cache is reset.
112 */
113 if (im->epoch_count == 0xFFFFFFFF)
114 {
115 /* Reset all the entries in flow cache */
116 clib_memset_u8 (im->ipsec4_out_spd_hash_tbl, 0,
117 im->ipsec4_out_spd_hash_num_buckets *
118 (sizeof (*(im->ipsec4_out_spd_hash_tbl))));
119 }
120 /* Increment epoch counter by 1 */
121 clib_atomic_fetch_add_relax (&im->epoch_count, 1);
122 /* Reset spd flow cache counter since all old entries are stale */
123 clib_atomic_store_relax_n (&im->ipsec4_out_spd_flow_cache_entries, 0);
124 }
125
Zachary Leaf7cd35f52021-06-25 08:11:15 -0500126 if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
127 policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
128 policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD) &&
129 im->input_flow_cache_flag && !policy->is_ipv6)
130 {
131 /*
132 * Flow cache entry is valid only when input_epoch_count value in control
133 * plane and data plane match. Otherwise, flow cache entry is considered
134 * stale. To avoid the race condition of using old input_epoch_count
135 * value in data plane after the roll over of input_epoch_count in
136 * control plane, entire flow cache is reset.
137 */
138 if (im->input_epoch_count == 0xFFFFFFFF)
139 {
140 /* Reset all the entries in flow cache */
141 clib_memset_u8 (im->ipsec4_in_spd_hash_tbl, 0,
142 im->ipsec4_in_spd_hash_num_buckets *
143 (sizeof (*(im->ipsec4_in_spd_hash_tbl))));
144 }
145 /* Increment epoch counter by 1 */
146 clib_atomic_fetch_add_relax (&im->input_epoch_count, 1);
147 /* Reset spd flow cache counter since all old entries are stale */
148 im->ipsec4_in_spd_flow_cache_entries = 0;
149 }
150
Neale Ranns999c8ee2019-02-01 03:31:24 -0800151 if (is_add)
152 {
153 u32 policy_index;
154
Neale Ranns495d7ff2019-07-12 09:15:26 +0000155 if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
156 {
157 index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
158
159 if (INDEX_INVALID == sa_index)
160 return VNET_API_ERROR_SYSCALL_ERROR_1;
161 policy->sa_index = sa_index;
162 }
163 else
164 policy->sa_index = INDEX_INVALID;
165
Piotr Bronowski04643102022-05-10 13:18:22 +0000166 /**
167 * Try adding the policy into fast path SPD first. Only adding to
168 * traditional SPD when failed.
169 **/
170 if (im->fp_spd_is_enabled &&
171 (policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND))
172 return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 1,
173 stat_index);
174
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800175 pool_get (im->policies, vp);
Neale Ranns999c8ee2019-02-01 03:31:24 -0800176 clib_memcpy (vp, policy, sizeof (*vp));
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800177 policy_index = vp - im->policies;
Neale Ranns999c8ee2019-02-01 03:31:24 -0800178
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800179 vlib_validate_combined_counter (&ipsec_spd_policy_counters,
180 policy_index);
181 vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
Neale Ranns9f231d42019-03-19 10:06:00 +0000182 vec_add1 (spd->policies[policy->type], policy_index);
183 vec_sort_with_function (spd->policies[policy->type],
184 ipsec_spd_entry_sort);
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800185 *stat_index = policy_index;
Neale Ranns999c8ee2019-02-01 03:31:24 -0800186 }
187 else
188 {
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800189 u32 ii;
190
Piotr Bronowski04643102022-05-10 13:18:22 +0000191 /**
192 * Try to delete the policy from the fast path SPD first. Delete from
193 * traditional SPD when fp delete fails.
194 **/
195 /**
196 * TODO: add ipv6 fast path support for outbound and
197 * ipv4/v6 inbound support for fast path
198 */
199 if (im->fp_spd_is_enabled &&
200 (policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND))
201 return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 0,
202 stat_index);
203
Neale Ranns50d50692019-03-26 08:26:39 +0000204 vec_foreach_index (ii, (spd->policies[policy->type]))
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800205 {
Neale Ranns50d50692019-03-26 08:26:39 +0000206 vp = pool_elt_at_index (im->policies,
207 spd->policies[policy->type][ii]);
208 if (ipsec_policy_is_equal (vp, policy))
209 {
Gabriel Oginskiaacd3ed2022-02-18 08:05:00 +0000210 vec_delete (spd->policies[policy->type], 1, ii);
Neale Ranns495d7ff2019-07-12 09:15:26 +0000211 ipsec_sa_unlock (vp->sa_index);
Neale Ranns50d50692019-03-26 08:26:39 +0000212 pool_put (im->policies, vp);
213 break;
214 }
Neale Rannsa09c1ff2019-02-04 01:10:30 -0800215 }
Neale Ranns999c8ee2019-02-01 03:31:24 -0800216 }
217
218 return 0;
219}
220
Piotr Bronowski04643102022-05-10 13:18:22 +0000221static_always_inline void
222release_mask_type_index (ipsec_main_t *im, u32 mask_type_index)
223{
224 ipsec_fp_mask_type_entry_t *mte =
225 pool_elt_at_index (im->fp_mask_types, mask_type_index);
226 mte->refcount--;
227 if (mte->refcount == 0)
228 {
229 /* this entry is not in use anymore */
230 ASSERT (clib_memset (mte, 0xae, sizeof (*mte)) == EOK);
231 pool_put (im->fp_mask_types, mte);
232 }
233}
234
235static_always_inline u32
236find_mask_type_index (ipsec_main_t *im, ipsec_fp_5tuple_t *mask)
237{
238 ipsec_fp_mask_type_entry_t *mte;
239
240 pool_foreach (mte, im->fp_mask_types)
241 {
242 if (memcmp (&mte->mask, mask, sizeof (*mask)) == 0)
243 return (mte - im->fp_mask_types);
244 }
245
246 return ~0;
247}
248
249static_always_inline void
250fill_ip6_hash_policy_kv (ipsec_main_t *im, ipsec_fp_5tuple_t *match,
251 ipsec_fp_5tuple_t *mask, clib_bihash_kv_40_8_t *kv)
252{
253 ipsec_fp_lookup_value_t *kv_val = (ipsec_fp_lookup_value_t *) &kv->value;
254 u64 *pmatch = (u64 *) &match;
255 u64 *pmask = (u64 *) &mask;
256 u64 *pkey = (u64 *) &kv->key;
257
258 *pkey++ = *pmatch++ & *pmask++;
259 *pkey++ = *pmatch++ & *pmask++;
260 *pkey++ = *pmatch++ & *pmask++;
261 *pkey++ = *pmatch++ & *pmask++;
262 *pkey++ = *pmatch++ & *pmask++;
263 *pkey++ = *pmatch++ & *pmask++;
264
265 kv_val->as_u64 = 0;
266}
267
268static_always_inline void
269fill_ip4_hash_policy_kv (ipsec_main_t *im, ipsec_fp_5tuple_t *match,
270 ipsec_fp_5tuple_t *mask, clib_bihash_kv_16_8_t *kv)
271{
272 ipsec_fp_lookup_value_t *kv_val = (ipsec_fp_lookup_value_t *) &kv->value;
273 u64 *pmatch = (u64 *) &match->laddr;
274 u64 *pmask = (u64 *) &mask->laddr;
275 u64 *pkey = (u64 *) kv->key;
276
277 *pkey++ = *pmatch++ & *pmask++;
278 *pkey++ = *pmatch++ & *pmask++;
279
280 kv_val->as_u64 = 0;
281}
282
283static_always_inline u16
284get_highest_set_bit_u16 (u16 x)
285{
286 x |= x >> 8;
287 x |= x >> 4;
288 x |= x >> 2;
289 x |= x >> 1;
290 return x ^= x >> 1;
291}
292
293static_always_inline u32
294get_highest_set_bit_u32 (u32 x)
295{
296 x |= x >> 16;
297 x |= x >> 8;
298 x |= x >> 4;
299 x |= x >> 2;
300 x |= x >> 1;
301 return x ^= x >> 1;
302}
303
304static_always_inline void
305ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask)
306{
307 u32 *pladdr_start = (u32 *) &policy->laddr.start.ip4;
308 u32 *pladdr_stop = (u32 *) &policy->laddr.stop.ip4;
309 u32 *plmask = (u32 *) &mask->laddr;
310 u32 *praddr_start = (u32 *) &policy->raddr.start.ip4;
311 u32 *praddr_stop = (u32 *) &policy->raddr.stop.ip4;
312 u32 *prmask = (u32 *) &mask->raddr;
313
314 memset (mask, 0, sizeof (mask->l3_zero_pad));
315 memset (plmask, 1, sizeof (*mask) - sizeof (mask->l3_zero_pad));
316 /* find bits where start != stop */
317 *plmask = *pladdr_start ^ *pladdr_stop;
318 *prmask = *praddr_start ^ *praddr_stop;
319 /* Find most significant bit set (that is the first position
320 * start differs from stop). Mask out everything after that bit and
321 * the bit itself. Remember that policy stores start and stop in the net
322 * order.
323 */
324 *plmask = get_highest_set_bit_u32 (clib_net_to_host_u32 (*plmask));
325 *plmask = clib_host_to_net_u32 (~(*plmask - 1) & (~*plmask));
326
327 *prmask = get_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask));
328 *prmask = clib_host_to_net_u32 (~(*prmask - 1) & (~*prmask));
329
330 if (PREDICT_TRUE ((policy->protocol == IP_PROTOCOL_TCP) ||
331 (policy->protocol == IP_PROTOCOL_UDP) ||
332 (policy->protocol == IP_PROTOCOL_SCTP)))
333 {
334 mask->lport = policy->lport.start ^ policy->lport.stop;
335 mask->rport = policy->rport.start ^ policy->rport.stop;
336
337 mask->lport = get_highest_set_bit_u16 (mask->lport);
338 mask->lport = ~(mask->lport - 1) & (~mask->lport);
339
340 mask->rport = get_highest_set_bit_u16 (mask->rport);
341 mask->rport = ~(mask->rport - 1) & (~mask->rport);
342 }
343 else
344 {
345 mask->lport = 0;
346 mask->rport = 0;
347 }
348
349 mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0;
350}
351
352static_always_inline int
353ipsec_fp_ip6_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask)
354{
355 u64 *pladdr_start = (u64 *) &policy->laddr.start;
356 u64 *pladdr_stop = (u64 *) &policy->laddr.stop;
357 u64 *plmask = (u64 *) &mask->laddr;
358 u64 *praddr_start = (u64 *) &policy->raddr.start;
359 u64 *praddr_stop = (u64 *) &policy->raddr.stop;
360 u64 *prmask = (u64 *) &mask->ip6_raddr;
361 u16 *plport_start = (u16 *) &policy->lport.start;
362 u16 *plport_stop = (u16 *) &policy->lport.stop;
363 u16 *prport_start = (u16 *) &policy->rport.start;
364 u16 *prport_stop = (u16 *) &policy->rport.stop;
365
366 /* test if x is not power of 2. The test form is !((x & (x - 1)) == 0) */
367 if (((*pladdr_stop - *pladdr_start + 1) & (*pladdr_stop - *pladdr_start)) &&
368 (((*(pladdr_stop + 1) - *(pladdr_start + 1)) + 1) &
369 (*(pladdr_stop + 1) - *(pladdr_start + 1))))
370 return -1;
371
372 if (((*praddr_stop - *praddr_start + 1) & (*praddr_stop - *praddr_start)) &&
373 (((*(praddr_stop + 1) - *(praddr_start + 1)) + 1) &
374 (*(praddr_stop + 1) - *(praddr_start + 1))))
375 return -1;
376
377 if (((*plport_stop - *plport_start + 1) & (*plport_stop - *plport_start)))
378 return -1;
379
380 if (((*prport_stop - *prport_start + 1) & (*prport_stop - *prport_start)))
381 return -1;
382
383 memset (mask, 1, sizeof (ipsec_fp_5tuple_t));
384
385 *plmask++ = ~(*pladdr_start++ ^ *pladdr_stop++);
386 *plmask++ = ~(*pladdr_start++ ^ *pladdr_stop++);
387
388 *prmask++ = ~(*praddr_start++ ^ *praddr_stop++);
389 *prmask++ = ~(*praddr_start++ ^ *praddr_stop++);
390
391 mask->lport = ~(policy->lport.start ^ policy->lport.stop);
392 mask->rport = ~(policy->rport.start ^ policy->rport.stop);
393 mask->protocol = 0;
394 return 0;
395}
396
397static_always_inline void
398ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple)
399{
400 memset (tuple, 0, sizeof (*tuple));
401 tuple->is_ipv6 = policy->is_ipv6;
402 if (tuple->is_ipv6)
403 {
404 tuple->ip6_laddr = policy->laddr.start.ip6;
405 tuple->ip6_raddr = policy->raddr.start.ip6;
406 }
407 else
408 {
409 tuple->laddr = policy->laddr.start.ip4;
410 tuple->raddr = policy->raddr.start.ip4;
411 }
412
413 tuple->protocol = policy->protocol;
414
415 tuple->lport = policy->lport.start;
416 tuple->rport = policy->rport.start;
417}
418
419int
420ipsec_fp_ip4_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
421 ipsec_policy_t *policy, u32 *stat_index)
422{
423 u32 mask_index;
424 ipsec_policy_t *vp;
425 ipsec_fp_mask_type_entry_t *mte;
426 u32 policy_index;
427 clib_bihash_kv_16_8_t kv;
428 clib_bihash_kv_16_8_t result;
429 ipsec_fp_lookup_value_t *result_val =
430 (ipsec_fp_lookup_value_t *) &result.value;
431 ipsec_fp_lookup_value_t *key_val = (ipsec_fp_lookup_value_t *) &kv.value;
432
433 ipsec_fp_5tuple_t mask, policy_5tuple;
434 int res;
435
436 ipsec_fp_ip4_get_policy_mask (policy, &mask);
437 pool_get (im->policies, vp);
438 policy_index = vp - im->policies;
439 vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
440 vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
441 *stat_index = policy_index;
442 mask_index = find_mask_type_index (im, &mask);
443
444 if (mask_index == ~0)
445 {
446 /* mask type not found, we need to create a new entry */
447 pool_get (im->fp_mask_types, mte);
448 mask_index = mte - im->fp_mask_types;
449 mte->refcount = 0;
450 }
451 else
452 mte = im->fp_mask_types + mask_index;
453
454 policy->fp_mask_type_id = mask_index;
455 ipsec_fp_get_policy_5tuple (policy, &policy_5tuple);
456
457 fill_ip4_hash_policy_kv (im, &policy_5tuple, &mask, &kv);
458
459 res = clib_bihash_search_inline_2_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv,
460 &result);
461 if (res != 0)
462 {
463 /* key was not found crate a new entry */
464 vec_add1 (key_val->fp_policies_ids, policy_index);
465 res = clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv, 1);
466 if (res != 0)
467 goto error;
468 }
469 else
470 {
471
472 if (vec_max_len (result_val->fp_policies_ids) !=
473 vec_len (result_val->fp_policies_ids))
474 {
475 /* no need to resize */
476 vec_add1 (result_val->fp_policies_ids, policy_index);
477 }
478 else
479 {
480 vec_add1 (result_val->fp_policies_ids, policy_index);
481
482 res =
483 clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash, &result, 1);
484
485 if (res != 0)
486 goto error;
487 }
488 }
489
490 if (mte->refcount == 0)
491 {
492 clib_memcpy (&mte->mask, &mask, sizeof (mask));
493 mte->refcount = 0;
494 vec_add1 (fp_spd->fp_mask_types[policy->type], mask_index);
495 }
496
497 mte->refcount++;
498 vec_add1 (fp_spd->fp_policies[policy->type], policy_index);
499 clib_memcpy (vp, policy, sizeof (*vp));
500
501 return 0;
502
503error:
504 pool_put (im->policies, vp);
505 release_mask_type_index (im, mask_index);
506 return -1;
507}
508
509int
510ipsec_fp_ip6_add_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
511 ipsec_policy_t *policy, u32 *stat_index)
512{
513
514 u32 mask_index;
515 ipsec_policy_t *vp;
516 ipsec_fp_mask_type_entry_t *mte;
517 u32 policy_index;
518 clib_bihash_kv_40_8_t kv;
519 clib_bihash_kv_40_8_t result;
520 ipsec_fp_lookup_value_t *result_val =
521 (ipsec_fp_lookup_value_t *) &result.value;
522 ipsec_fp_lookup_value_t *key_val = (ipsec_fp_lookup_value_t *) &kv.value;
523
524 ipsec_fp_5tuple_t mask, policy_5tuple;
525 int res;
526 /* u64 hash; */
527
528 if (PREDICT_FALSE (!fp_spd->fp_ip6_lookup_hash_initialized))
529 {
530 clib_bihash_init_40_8 (
531 &fp_spd->fp_ip6_lookup_hash, "SPD_FP ip6 rules lookup bihash",
532 im->fp_lookup_hash_buckets,
533 im->fp_lookup_hash_buckets * IPSEC_FP_IP6_HASH_MEM_PER_BUCKET);
534 fp_spd->fp_ip6_lookup_hash_initialized = 1;
535 }
536
537 if (ipsec_fp_ip6_get_policy_mask (policy, &mask) != 0)
538 return -1;
539
540 pool_get (im->policies, vp);
541 policy_index = vp - im->policies;
542 vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
543 vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
544 *stat_index = policy_index;
545 mask_index = find_mask_type_index (im, &mask);
546
547 if (mask_index == ~0)
548 {
549 /* mask type not found, we need to create a new entry */
550 pool_get (im->fp_mask_types, mte);
551 mask_index = mte - im->fp_mask_types;
552 mte->refcount = 0;
553 }
554 else
555 mte = im->fp_mask_types + mask_index;
556
557 policy->fp_mask_type_id = mask_index;
558 ipsec_fp_ip6_get_policy_mask (policy, &mask);
559 ipsec_fp_get_policy_5tuple (policy, &policy_5tuple);
560
561 fill_ip6_hash_policy_kv (im, &policy_5tuple, &mask, &kv);
562
563 res = clib_bihash_search_inline_2_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv,
564 &result);
565 if (res != 0)
566 {
567 /* key was not found crate a new entry */
568 vec_add1 (key_val->fp_policies_ids, policy_index);
569 res = clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv, 1);
570 if (res != 0)
571 goto error;
572 }
573 else
574 {
575
576 if (vec_max_len (result_val->fp_policies_ids) !=
577 vec_len (result_val->fp_policies_ids))
578 {
579 /* no need to resize */
580 vec_add1 (result_val->fp_policies_ids, policy_index);
581 }
582 else
583 {
584 vec_add1 (result_val->fp_policies_ids, policy_index);
585
586 res =
587 clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash, &result, 1);
588
589 if (res != 0)
590 goto error;
591 }
592 }
593
594 if (mte->refcount == 0)
595 {
596 clib_memcpy (&mte->mask, &mask, sizeof (mask));
597 mte->refcount = 0;
598 vec_add1 (fp_spd->fp_mask_types[policy->type], mask_index);
599 }
600
601 mte->refcount++;
602 vec_add1 (fp_spd->fp_policies[policy->type], policy_index);
603 clib_memcpy (vp, policy, sizeof (*vp));
604
605 return 0;
606
607error:
608 pool_put (im->policies, vp);
609 release_mask_type_index (im, mask_index);
610 return -1;
611}
612
613int
614ipsec_fp_ip6_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
615 ipsec_policy_t *policy)
616{
617 int res;
618 ipsec_fp_5tuple_t mask = { 0 }, policy_5tuple;
619 clib_bihash_kv_40_8_t kv;
620 clib_bihash_kv_40_8_t result;
621 ipsec_fp_lookup_value_t *result_val =
622 (ipsec_fp_lookup_value_t *) &result.value;
623
624 ipsec_policy_t *vp;
625 u32 ii, iii, imt;
626
627 ipsec_fp_ip6_get_policy_mask (policy, &mask);
628 ipsec_fp_get_policy_5tuple (policy, &policy_5tuple);
629 fill_ip6_hash_policy_kv (im, &policy_5tuple, &mask, &kv);
630 res = clib_bihash_search_inline_2_40_8 (&fp_spd->fp_ip6_lookup_hash, &kv,
631 &result);
632 if (res != 0)
633 return -1;
634
635 res = -1;
636 vec_foreach_index (ii, result_val->fp_policies_ids)
637 {
638 vp =
639 pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
640 if (ipsec_policy_is_equal (vp, policy))
641 {
642 vec_foreach_index (iii, fp_spd->fp_policies[policy->type])
643 {
644 if (*(fp_spd->fp_policies[policy->type] + iii) ==
645 *(result_val->fp_policies_ids + ii))
646 {
647 if (vec_len (result_val->fp_policies_ids) == 1)
648 {
649 vec_free (result_val->fp_policies_ids);
650 clib_bihash_add_del_40_8 (&fp_spd->fp_ip6_lookup_hash,
651 &result, 0);
652 }
653 else
654 {
655 vec_del1 (result_val->fp_policies_ids, ii);
656 }
657 vec_del1 (fp_spd->fp_policies[policy->type], iii);
658
659 vec_foreach_index (imt, fp_spd->fp_mask_types[policy->type])
660 {
661 if (*(fp_spd->fp_mask_types[policy->type] + imt) ==
662 vp->fp_mask_type_id)
663 {
664 ipsec_fp_mask_type_entry_t *mte = pool_elt_at_index (
665 im->fp_mask_types, vp->fp_mask_type_id);
666
667 if (mte->refcount == 1)
668 vec_del1 (fp_spd->fp_mask_types[policy->type],
669 imt);
670 break;
671 }
672 }
673
674 res = 0;
675 break;
676 }
677 }
678
679 if (res != 0)
680 continue;
681 else
682 {
683 release_mask_type_index (im, vp->fp_mask_type_id);
684 ipsec_sa_unlock (vp->sa_index);
685 pool_put (im->policies, vp);
686 return 0;
687 }
688 }
689 }
690 return -1;
691}
692
693int
694ipsec_fp_ip4_del_policy (ipsec_main_t *im, ipsec_spd_fp_t *fp_spd,
695 ipsec_policy_t *policy)
696{
697 int res;
698 ipsec_fp_5tuple_t mask = { 0 }, policy_5tuple;
699 clib_bihash_kv_16_8_t kv;
700 clib_bihash_kv_16_8_t result;
701 ipsec_fp_lookup_value_t *result_val =
702 (ipsec_fp_lookup_value_t *) &result.value;
703
704 ipsec_policy_t *vp;
705 u32 ii, iii, imt;
706
707 ipsec_fp_ip4_get_policy_mask (policy, &mask);
708 ipsec_fp_get_policy_5tuple (policy, &policy_5tuple);
709 fill_ip4_hash_policy_kv (im, &policy_5tuple, &mask, &kv);
710 res = clib_bihash_search_inline_2_16_8 (&fp_spd->fp_ip4_lookup_hash, &kv,
711 &result);
712 if (res != 0)
713 return -1;
714
715 res = -1;
716 vec_foreach_index (ii, result_val->fp_policies_ids)
717 {
718 vp =
719 pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
720 if (ipsec_policy_is_equal (vp, policy))
721 {
722 vec_foreach_index (iii, fp_spd->fp_policies[policy->type])
723 {
724 if (*(fp_spd->fp_policies[policy->type] + iii) ==
725 *(result_val->fp_policies_ids + ii))
726 {
727 if (vec_len (result_val->fp_policies_ids) == 1)
728 {
729 vec_free (result_val->fp_policies_ids);
730 clib_bihash_add_del_16_8 (&fp_spd->fp_ip4_lookup_hash,
731 &result, 0);
732 }
733 else
734 {
735 vec_del1 (result_val->fp_policies_ids, ii);
736 }
737 vec_del1 (fp_spd->fp_policies[policy->type], iii);
738
739 vec_foreach_index (imt, fp_spd->fp_mask_types[policy->type])
740 {
741 if (*(fp_spd->fp_mask_types[policy->type] + imt) ==
742 vp->fp_mask_type_id)
743 {
744 ipsec_fp_mask_type_entry_t *mte = pool_elt_at_index (
745 im->fp_mask_types, vp->fp_mask_type_id);
746
747 if (mte->refcount == 1)
748 vec_del1 (fp_spd->fp_mask_types[policy->type],
749 imt);
750 break;
751 }
752 }
753
754 res = 0;
755 break;
756 }
757 }
758
759 if (res != 0)
760 continue;
761 else
762 {
763 release_mask_type_index (im, vp->fp_mask_type_id);
764 ipsec_sa_unlock (vp->sa_index);
765 pool_put (im->policies, vp);
766 return 0;
767 }
768 }
769 }
770 return -1;
771}
772
773int
774ipsec_fp_add_del_policy (void *fp_spd, ipsec_policy_t *policy, int is_add,
775 u32 *stat_index)
776{
777 ipsec_main_t *im = &ipsec_main;
778
779 if (is_add)
780 if (policy->is_ipv6)
781 return ipsec_fp_ip6_add_policy (im, (ipsec_spd_fp_t *) fp_spd, policy,
782 stat_index);
783 else
784 return ipsec_fp_ip4_add_policy (im, (ipsec_spd_fp_t *) fp_spd, policy,
785 stat_index);
786
787 else if (policy->is_ipv6)
788
789 return ipsec_fp_ip6_del_policy (im, (ipsec_spd_fp_t *) fp_spd, policy);
790 else
791 return ipsec_fp_ip4_del_policy (im, (ipsec_spd_fp_t *) fp_spd, policy);
792}
793
Neale Ranns999c8ee2019-02-01 03:31:24 -0800794/*
795 * fd.io coding-style-patch-verification: ON
796 *
797 * Local Variables:
798 * eval: (c-set-style "gnu")
799 * End:
800 */