quic: fix coverity warning
[vpp.git] / src / vnet / ipsec / ipsec_spd_policy.c
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 static int
28 ipsec_spd_entry_sort (void *a1, void *a2)
29 {
30   ipsec_main_t *im = &ipsec_main;
31   u32 *id1 = a1;
32   u32 *id2 = a2;
33   ipsec_policy_t *p1, *p2;
34
35   p1 = pool_elt_at_index (im->policies, *id1);
36   p2 = pool_elt_at_index (im->policies, *id2);
37   if (p1 && p2)
38     return p2->priority - p1->priority;
39
40   return 0;
41 }
42
43 int
44 ipsec_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:
70           *type = (is_ipv6 ?
71                    IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD :
72                    IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD);
73           return (0);
74         case IPSEC_POLICY_ACTION_RESOLVE:
75           break;
76         }
77     }
78
79   /* Unsupported type */
80   return (-1);
81 }
82
83 int
84 ipsec_add_del_policy (vlib_main_t * vm,
85                       ipsec_policy_t * policy, int is_add, u32 * stat_index)
86 {
87   ipsec_main_t *im = &ipsec_main;
88   ipsec_spd_t *spd = 0;
89   ipsec_policy_t *vp;
90   u32 spd_index;
91   uword *p;
92
93   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
103   if (im->output_flow_cache_flag && !policy->is_ipv6 &&
104       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
126   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
151   if (is_add)
152     {
153       u32 policy_index;
154
155       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
166       /**
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
175       pool_get (im->policies, vp);
176       clib_memcpy (vp, policy, sizeof (*vp));
177       policy_index = vp - im->policies;
178
179       vlib_validate_combined_counter (&ipsec_spd_policy_counters,
180                                       policy_index);
181       vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
182       vec_add1 (spd->policies[policy->type], policy_index);
183       vec_sort_with_function (spd->policies[policy->type],
184                               ipsec_spd_entry_sort);
185       *stat_index = policy_index;
186     }
187   else
188     {
189       u32 ii;
190
191       /**
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
204       vec_foreach_index (ii, (spd->policies[policy->type]))
205       {
206         vp = pool_elt_at_index (im->policies,
207                                 spd->policies[policy->type][ii]);
208         if (ipsec_policy_is_equal (vp, policy))
209           {
210             vec_delete (spd->policies[policy->type], 1, ii);
211             ipsec_sa_unlock (vp->sa_index);
212             pool_put (im->policies, vp);
213             break;
214           }
215       }
216     }
217
218   return 0;
219 }
220
221 static_always_inline void
222 release_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
235 static_always_inline u32
236 find_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
249 static_always_inline void
250 fill_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
268 static_always_inline void
269 fill_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
283 static_always_inline u16
284 get_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
293 static_always_inline u32
294 get_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
304 static_always_inline void
305 ipsec_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
352 static_always_inline int
353 ipsec_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
397 static_always_inline void
398 ipsec_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
419 int
420 ipsec_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
503 error:
504   pool_put (im->policies, vp);
505   release_mask_type_index (im, mask_index);
506   return -1;
507 }
508
509 int
510 ipsec_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
607 error:
608   pool_put (im->policies, vp);
609   release_mask_type_index (im, mask_index);
610   return -1;
611 }
612
613 int
614 ipsec_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
693 int
694 ipsec_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
773 int
774 ipsec_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
794 /*
795  * fd.io coding-style-patch-verification: ON
796  *
797  * Local Variables:
798  * eval: (c-set-style "gnu")
799  * End:
800  */