udp: fix csum computation when offload disabled
[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 int
28 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   if (is_outbound)
34     {
35       *type = (is_ipv6 ?
36                IPSEC_SPD_POLICY_IP6_OUTBOUND : IPSEC_SPD_POLICY_IP4_OUTBOUND);
37       return (0);
38     }
39   else
40     {
41       switch (action)
42         {
43         case IPSEC_POLICY_ACTION_PROTECT:
44           *type = (is_ipv6 ?
45                    IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT :
46                    IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT);
47           return (0);
48         case IPSEC_POLICY_ACTION_BYPASS:
49           *type = (is_ipv6 ?
50                    IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS :
51                    IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS);
52           return (0);
53         case IPSEC_POLICY_ACTION_DISCARD:
54           *type = (is_ipv6 ?
55                    IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD :
56                    IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD);
57           return (0);
58         case IPSEC_POLICY_ACTION_RESOLVE:
59           break;
60         }
61     }
62
63   /* Unsupported type */
64   return (-1);
65 }
66
67 static_always_inline int
68 ipsec_is_policy_inbound (ipsec_policy_t *policy)
69 {
70   if (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
71       policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
72       policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD ||
73       policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT ||
74       policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS ||
75       policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD)
76     return 1;
77
78   return 0;
79 }
80
81 static_always_inline int
82 ipsec_is_fp_enabled (ipsec_main_t *im, ipsec_spd_t *spd,
83                      ipsec_policy_t *policy)
84 {
85   if ((im->fp_spd_ipv4_out_is_enabled &&
86        PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip4_out_lookup_hash_idx) &&
87        policy->type == IPSEC_SPD_POLICY_IP4_OUTBOUND) ||
88       (im->fp_spd_ipv4_in_is_enabled &&
89        PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip4_in_lookup_hash_idx) &&
90        (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
91         policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
92         policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD)) ||
93       (im->fp_spd_ipv6_in_is_enabled &&
94        PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip6_in_lookup_hash_idx) &&
95        (policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT ||
96         policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_BYPASS ||
97         policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_DISCARD)) ||
98       (im->fp_spd_ipv6_out_is_enabled &&
99        PREDICT_TRUE (INDEX_INVALID != spd->fp_spd.ip6_out_lookup_hash_idx) &&
100        policy->type == IPSEC_SPD_POLICY_IP6_OUTBOUND))
101     return 1;
102   return 0;
103 }
104
105 int
106 ipsec_add_del_policy (vlib_main_t * vm,
107                       ipsec_policy_t * policy, int is_add, u32 * stat_index)
108 {
109   ipsec_main_t *im = &ipsec_main;
110   ipsec_spd_t *spd = 0;
111   ipsec_policy_t *vp;
112   u32 spd_index;
113   uword *p;
114
115   p = hash_get (im->spd_index_by_spd_id, policy->id);
116
117   if (!p)
118     return VNET_API_ERROR_SYSCALL_ERROR_1;
119
120   spd_index = p[0];
121   spd = pool_elt_at_index (im->spds, spd_index);
122   if (!spd)
123     return VNET_API_ERROR_SYSCALL_ERROR_1;
124
125   if (im->output_flow_cache_flag && !policy->is_ipv6 &&
126       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       if (im->epoch_count == 0xFFFFFFFF)
136         {
137           /* Reset all the entries in flow cache */
138           clib_memset_u8 (im->ipsec4_out_spd_hash_tbl, 0,
139                           im->ipsec4_out_spd_hash_num_buckets *
140                             (sizeof (*(im->ipsec4_out_spd_hash_tbl))));
141         }
142       /* Increment epoch counter by 1 */
143       clib_atomic_fetch_add_relax (&im->epoch_count, 1);
144       /* Reset spd flow cache counter since all old entries are stale */
145       clib_atomic_store_relax_n (&im->ipsec4_out_spd_flow_cache_entries, 0);
146     }
147
148   if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
149        policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_BYPASS ||
150        policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_DISCARD) &&
151       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       if (im->input_epoch_count == 0xFFFFFFFF)
161         {
162           /* Reset all the entries in flow cache */
163           clib_memset_u8 (im->ipsec4_in_spd_hash_tbl, 0,
164                           im->ipsec4_in_spd_hash_num_buckets *
165                             (sizeof (*(im->ipsec4_in_spd_hash_tbl))));
166         }
167       /* Increment epoch counter by 1 */
168       clib_atomic_fetch_add_relax (&im->input_epoch_count, 1);
169       /* Reset spd flow cache counter since all old entries are stale */
170       im->ipsec4_in_spd_flow_cache_entries = 0;
171     }
172
173   if (is_add)
174     {
175       u32 policy_index;
176       u32 i;
177
178       if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
179         {
180           index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
181
182           if (INDEX_INVALID == sa_index)
183             return VNET_API_ERROR_SYSCALL_ERROR_1;
184           policy->sa_index = sa_index;
185         }
186       else
187         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       if (ipsec_is_fp_enabled (im, spd, policy))
194         return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 1,
195                                         stat_index);
196
197       pool_get (im->policies, vp);
198       clib_memcpy (vp, policy, sizeof (*vp));
199       policy_index = vp - im->policies;
200
201       vlib_validate_combined_counter (&ipsec_spd_policy_counters,
202                                       policy_index);
203       vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
204
205       vec_foreach_index (i, spd->policies[policy->type])
206         {
207           ipsec_policy_t *p =
208             pool_elt_at_index (im->policies, spd->policies[policy->type][i]);
209
210           if (p->priority <= vp->priority)
211             {
212               break;
213             }
214         }
215
216       vec_insert_elts (spd->policies[policy->type], &policy_index, 1, i);
217
218       *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       if (ipsec_is_fp_enabled (im, spd, policy))
230
231         {
232           if (policy->policy == IPSEC_POLICY_ACTION_PROTECT)
233             {
234               index_t sa_index = ipsec_sa_find_and_lock (policy->sa_id);
235
236               if (INDEX_INVALID == sa_index)
237                 return VNET_API_ERROR_SYSCALL_ERROR_1;
238               policy->sa_index = sa_index;
239               ipsec_sa_unlock_id (policy->sa_id);
240             }
241           else
242             policy->sa_index = INDEX_INVALID;
243
244           return ipsec_fp_add_del_policy ((void *) &spd->fp_spd, policy, 0,
245                                           stat_index);
246         }
247
248       vec_foreach_index (ii, (spd->policies[policy->type]))
249       {
250         vp = pool_elt_at_index (im->policies,
251                                 spd->policies[policy->type][ii]);
252         if (ipsec_policy_is_equal (vp, policy))
253           {
254             vec_delete (spd->policies[policy->type], 1, ii);
255             ipsec_sa_unlock (vp->sa_index);
256             pool_put (im->policies, vp);
257             break;
258           }
259       }
260     }
261
262   return 0;
263 }
264
265 static_always_inline void
266 ipsec_fp_release_mask_type (ipsec_main_t *im, u32 mask_type_index)
267 {
268   ipsec_fp_mask_type_entry_t *mte =
269     pool_elt_at_index (im->fp_mask_types, mask_type_index);
270   mte->refcount--;
271   if (mte->refcount == 0)
272     {
273       /* this entry is not in use anymore */
274       ASSERT (clib_memset (mte, 0xae, sizeof (*mte)) == EOK);
275       pool_put (im->fp_mask_types, mte);
276     }
277 }
278
279 static_always_inline u32
280 find_mask_type_index (ipsec_main_t *im, ipsec_fp_5tuple_t *mask)
281 {
282   ipsec_fp_mask_type_entry_t *mte;
283
284   pool_foreach (mte, im->fp_mask_types)
285     {
286       if (memcmp (&mte->mask, mask, sizeof (*mask)) == 0)
287         return (mte - im->fp_mask_types);
288     }
289
290   return ~0;
291 }
292
293 static_always_inline void
294 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   ipsec_fp_lookup_value_t *kv_val = (ipsec_fp_lookup_value_t *) &kv->value;
298   u64 *pmatch = (u64 *) match->kv_40_8.key;
299   u64 *pmask = (u64 *) mask->kv_40_8.key;
300   u64 *pkey = (u64 *) kv->key;
301
302   *pkey++ = *pmatch++ & *pmask++;
303   *pkey++ = *pmatch++ & *pmask++;
304   *pkey++ = *pmatch++ & *pmask++;
305   *pkey++ = *pmatch++ & *pmask++;
306   *pkey = *pmatch & *pmask;
307
308   kv_val->as_u64 = 0;
309 }
310
311 static_always_inline void
312 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   ipsec_fp_lookup_value_t *kv_val = (ipsec_fp_lookup_value_t *) &kv->value;
316   u64 *pmatch = (u64 *) match->kv_16_8.key;
317   u64 *pmask = (u64 *) mask->kv_16_8.key;
318   u64 *pkey = (u64 *) kv->key;
319
320   *pkey++ = *pmatch++ & *pmask++;
321   *pkey = *pmatch & *pmask;
322
323   kv_val->as_u64 = 0;
324 }
325
326 static_always_inline u16
327 mask_out_highest_set_bit_u16 (u16 x)
328 {
329   x |= x >> 8;
330   x |= x >> 4;
331   x |= x >> 2;
332   x |= x >> 1;
333   return ~x;
334 }
335
336 static_always_inline u32
337 mask_out_highest_set_bit_u32 (u32 x)
338 {
339   x |= x >> 16;
340   x |= x >> 8;
341   x |= x >> 4;
342   x |= x >> 2;
343   x |= x >> 1;
344   return ~x;
345 }
346
347 static_always_inline u64
348 mask_out_highest_set_bit_u64 (u64 x)
349 {
350   x |= x >> 32;
351   x |= x >> 16;
352   x |= x >> 8;
353   x |= x >> 4;
354   x |= x >> 2;
355   x |= x >> 1;
356   return ~x;
357 }
358
359 static_always_inline void
360 ipsec_fp_get_policy_ports_mask (ipsec_policy_t *policy,
361                                 ipsec_fp_5tuple_t *mask)
362 {
363   if (PREDICT_TRUE ((policy->protocol == IP_PROTOCOL_TCP) ||
364                     (policy->protocol == IP_PROTOCOL_UDP) ||
365                     (policy->protocol == IP_PROTOCOL_SCTP)))
366     {
367       mask->lport = policy->lport.start ^ policy->lport.stop;
368       mask->rport = policy->rport.start ^ policy->rport.stop;
369
370       mask->lport = mask_out_highest_set_bit_u16 (mask->lport);
371
372       mask->rport = mask_out_highest_set_bit_u16 (mask->rport);
373     }
374   else
375     {
376       mask->lport = 0;
377       mask->rport = 0;
378     }
379
380   mask->protocol = (policy->protocol == IPSEC_POLICY_PROTOCOL_ANY) ? 0 : ~0;
381 }
382
383 static_always_inline void
384 ipsec_fp_ip4_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask,
385                               bool inbound)
386 {
387   u32 *pladdr_start = (u32 *) &policy->laddr.start.ip4;
388   u32 *pladdr_stop = (u32 *) &policy->laddr.stop.ip4;
389   u32 *plmask = (u32 *) &mask->laddr;
390   u32 *praddr_start = (u32 *) &policy->raddr.start.ip4;
391   u32 *praddr_stop = (u32 *) &policy->raddr.stop.ip4;
392   u32 *prmask = (u32 *) &mask->raddr;
393
394   clib_memset_u8 (mask, 0xff, sizeof (ipsec_fp_5tuple_t));
395   clib_memset_u8 (&mask->l3_zero_pad, 0, sizeof (mask->l3_zero_pad));
396
397   if (inbound && (policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT &&
398                   policy->sa_index != INDEX_INVALID))
399     {
400       ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
401
402       if (ipsec_sa_is_set_IS_TUNNEL (s))
403         goto set_spi_mask;
404     }
405
406   /* find bits where start != stop */
407   *plmask = *pladdr_start ^ *pladdr_stop;
408   *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   *plmask = clib_host_to_net_u32 (
415     mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*plmask)));
416
417   *prmask = clib_host_to_net_u32 (
418     mask_out_highest_set_bit_u32 (clib_net_to_host_u32 (*prmask)));
419
420 set_spi_mask:
421   if (inbound)
422     {
423       if (policy->type != IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT)
424         mask->spi = 0;
425
426       mask->protocol = 0;
427     }
428   else
429     {
430       mask->action = 0;
431       ipsec_fp_get_policy_ports_mask (policy, mask);
432     }
433 }
434
435 static_always_inline void
436 ipsec_fp_ip6_get_policy_mask (ipsec_policy_t *policy, ipsec_fp_5tuple_t *mask,
437                               bool inbound)
438 {
439   u64 *pladdr_start = (u64 *) &policy->laddr.start;
440   u64 *pladdr_stop = (u64 *) &policy->laddr.stop;
441   u64 *plmask = (u64 *) &mask->ip6_laddr;
442   u64 *praddr_start = (u64 *) &policy->raddr.start;
443   u64 *praddr_stop = (u64 *) &policy->raddr.stop;
444   u64 *prmask = (u64 *) &mask->ip6_raddr;
445
446   clib_memset_u8 (mask, 0xff, sizeof (ipsec_fp_5tuple_t));
447
448   if (inbound && (policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT &&
449                   policy->sa_index != INDEX_INVALID))
450     {
451       ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
452
453       if (ipsec_sa_is_set_IS_TUNNEL (s))
454         goto set_spi_mask;
455     }
456
457   *plmask = (*pladdr_start++ ^ *pladdr_stop++);
458
459   *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   *plmask = clib_host_to_net_u64 (
467     mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*plmask)));
468
469   if (*plmask++ & clib_host_to_net_u64 (0x1))
470     {
471       *plmask = (*pladdr_start ^ *pladdr_stop);
472       *plmask = clib_host_to_net_u64 (
473         mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*plmask)));
474     }
475   else
476     *plmask = 0;
477
478   *prmask = clib_host_to_net_u64 (
479     mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*prmask)));
480
481   if (*prmask++ & clib_host_to_net_u64 (0x1))
482     {
483       *prmask = (*praddr_start ^ *praddr_stop);
484       *prmask = clib_host_to_net_u64 (
485         mask_out_highest_set_bit_u64 (clib_net_to_host_u64 (*prmask)));
486     }
487   else
488     *prmask = 0;
489 set_spi_mask:
490   if (inbound)
491     {
492       if (policy->type != IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT)
493         mask->spi = 0;
494
495       mask->protocol = 0;
496     }
497   else
498     {
499       mask->action = 0;
500       ipsec_fp_get_policy_ports_mask (policy, mask);
501     }
502 }
503
504 static_always_inline void
505 ipsec_fp_get_policy_5tuple (ipsec_policy_t *policy, ipsec_fp_5tuple_t *tuple,
506                             bool inbound)
507 {
508   memset (tuple, 0, sizeof (*tuple));
509   tuple->is_ipv6 = policy->is_ipv6;
510   if (tuple->is_ipv6)
511     {
512       tuple->ip6_laddr = policy->laddr.start.ip6;
513       tuple->ip6_raddr = policy->raddr.start.ip6;
514     }
515   else
516     {
517       tuple->laddr = policy->laddr.start.ip4;
518       tuple->raddr = policy->raddr.start.ip4;
519     }
520
521   if (inbound)
522     {
523
524       if ((policy->type == IPSEC_SPD_POLICY_IP4_INBOUND_PROTECT ||
525            policy->type == IPSEC_SPD_POLICY_IP6_INBOUND_PROTECT) &&
526           policy->sa_index != INDEX_INVALID)
527         {
528           ipsec_sa_t *s = ipsec_sa_get (policy->sa_index);
529
530           tuple->spi = s->spi;
531           if (ipsec_sa_is_set_IS_TUNNEL (s))
532             {
533               if (tuple->is_ipv6)
534                 {
535                   tuple->ip6_laddr = s->tunnel.t_dst.ip.ip6;
536                   tuple->ip6_raddr = s->tunnel.t_src.ip.ip6;
537                 }
538               else
539                 {
540                   tuple->laddr = s->tunnel.t_dst.ip.ip4;
541                   tuple->raddr = s->tunnel.t_src.ip.ip4;
542                 }
543             }
544         }
545       else
546         tuple->spi = INDEX_INVALID;
547       tuple->action = policy->type;
548       return;
549     }
550
551   tuple->protocol = policy->protocol;
552   tuple->lport = policy->lport.start;
553   tuple->rport = policy->rport.start;
554 }
555
556 static_always_inline int
557 ipsec_fp_mask_type_idx_cmp (ipsec_fp_mask_id_t *mask_id, u32 *idx)
558 {
559   return mask_id->mask_type_idx == *idx;
560 }
561
562 int
563 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   ipsec_fp_lookup_value_t *result_val =
573     (ipsec_fp_lookup_value_t *) &result.value;
574   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   bool inbound = ipsec_is_policy_inbound (policy);
579   clib_bihash_16_8_t *bihash_table =
580     inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
581                                  fp_spd->ip4_in_lookup_hash_idx) :
582                     pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
583                                  fp_spd->ip4_out_lookup_hash_idx);
584
585   ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound);
586   pool_get (im->policies, vp);
587   policy_index = vp - im->policies;
588   vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
589   vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
590   *stat_index = policy_index;
591   mask_index = find_mask_type_index (im, &mask);
592
593   if (mask_index == ~0)
594     {
595       /* mask type not found, we need to create a new entry */
596       pool_get (im->fp_mask_types, mte);
597       mask_index = mte - im->fp_mask_types;
598       mte->refcount = 0;
599     }
600   else
601     mte = im->fp_mask_types + mask_index;
602
603   policy->fp_mask_type_id = mask_index;
604   ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
605
606   fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv);
607
608   res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
609   if (res != 0)
610     {
611       /* key was not found crate a new entry */
612       vec_add1 (key_val->fp_policies_ids, policy_index);
613       res = clib_bihash_add_del_16_8 (bihash_table, &kv, 1);
614
615       if (res != 0)
616         goto error;
617     }
618   else
619     {
620       u32 i;
621       u32 *old_fp_policies_ids = result_val->fp_policies_ids;
622
623       vec_foreach_index (i, result_val->fp_policies_ids)
624         {
625           ipsec_policy_t *p =
626             pool_elt_at_index (im->policies, result_val->fp_policies_ids[i]);
627
628           if (p->priority <= policy->priority)
629             {
630               break;
631             }
632         }
633
634       vec_insert_elts (result_val->fp_policies_ids, &policy_index, 1, i);
635
636       if (result_val->fp_policies_ids != old_fp_policies_ids)
637         {
638           res = clib_bihash_add_del_16_8 (bihash_table, &result, 1);
639
640           if (res != 0)
641             goto error;
642         }
643     }
644
645   if (mte->refcount == 0)
646     {
647       clib_memcpy (&mte->mask, &mask, sizeof (mask));
648       mte->refcount = 0;
649     }
650
651   searched_idx =
652     vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index,
653                               ipsec_fp_mask_type_idx_cmp);
654   if (~0 == searched_idx)
655     {
656       ipsec_fp_mask_id_t mask_id = { mask_index, 1 };
657       vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id);
658     }
659   else
660     (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++;
661
662   mte->refcount++;
663   clib_memcpy (vp, policy, sizeof (*vp));
664
665   return 0;
666
667 error:
668   pool_put (im->policies, vp);
669   ipsec_fp_release_mask_type (im, mask_index);
670   return -1;
671 }
672
673 int
674 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   ipsec_fp_lookup_value_t *result_val =
685     (ipsec_fp_lookup_value_t *) &result.value;
686   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   bool inbound = ipsec_is_policy_inbound (policy);
691
692   ipsec_fp_ip6_get_policy_mask (policy, &mask, inbound);
693   pool_get (im->policies, vp);
694   policy_index = vp - im->policies;
695   vlib_validate_combined_counter (&ipsec_spd_policy_counters, policy_index);
696   vlib_zero_combined_counter (&ipsec_spd_policy_counters, policy_index);
697   *stat_index = policy_index;
698   mask_index = find_mask_type_index (im, &mask);
699   clib_bihash_40_8_t *bihash_table =
700     inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
701                                  fp_spd->ip6_in_lookup_hash_idx) :
702                     pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
703                                  fp_spd->ip6_out_lookup_hash_idx);
704
705   if (mask_index == ~0)
706     {
707       /* mask type not found, we need to create a new entry */
708       pool_get (im->fp_mask_types, mte);
709       mask_index = mte - im->fp_mask_types;
710       mte->refcount = 0;
711     }
712   else
713     mte = im->fp_mask_types + mask_index;
714
715   policy->fp_mask_type_id = mask_index;
716   ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
717
718   fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv);
719
720   res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
721   if (res != 0)
722     {
723       /* key was not found crate a new entry */
724       vec_add1 (key_val->fp_policies_ids, policy_index);
725       res = clib_bihash_add_del_40_8 (bihash_table, &kv, 1);
726       if (res != 0)
727         goto error;
728     }
729   else
730     {
731       u32 i;
732       u32 *old_fp_policies_ids = result_val->fp_policies_ids;
733
734       vec_foreach_index (i, result_val->fp_policies_ids)
735         {
736           ipsec_policy_t *p =
737             pool_elt_at_index (im->policies, result_val->fp_policies_ids[i]);
738
739           if (p->priority <= policy->priority)
740             {
741               break;
742             }
743         }
744
745       vec_insert_elts (result_val->fp_policies_ids, &policy_index, 1, i);
746
747       if (result_val->fp_policies_ids != old_fp_policies_ids)
748         {
749           res = clib_bihash_add_del_40_8 (bihash_table, &result, 1);
750
751           if (res != 0)
752             goto error;
753         }
754     }
755
756   if (mte->refcount == 0)
757     {
758       clib_memcpy (&mte->mask, &mask, sizeof (mask));
759       mte->refcount = 0;
760     }
761
762   searched_idx =
763     vec_search_with_function (fp_spd->fp_mask_ids[policy->type], &mask_index,
764                               ipsec_fp_mask_type_idx_cmp);
765   if (~0 == searched_idx)
766     {
767       ipsec_fp_mask_id_t mask_id = { mask_index, 1 };
768       vec_add1 (fp_spd->fp_mask_ids[policy->type], mask_id);
769     }
770   else
771     (fp_spd->fp_mask_ids[policy->type] + searched_idx)->refcount++;
772
773   mte->refcount++;
774   clib_memcpy (vp, policy, sizeof (*vp));
775
776   return 0;
777
778 error:
779   pool_put (im->policies, vp);
780   ipsec_fp_release_mask_type (im, mask_index);
781   return -1;
782 }
783
784 int
785 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   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   ipsec_fp_lookup_value_t *result_val =
793     (ipsec_fp_lookup_value_t *) &result.value;
794   bool inbound = ipsec_is_policy_inbound (policy);
795   clib_bihash_40_8_t *bihash_table =
796     inbound ? pool_elt_at_index (im->fp_ip6_lookup_hashes_pool,
797                                  fp_spd->ip6_in_lookup_hash_idx) :
798                     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   ipsec_fp_ip6_get_policy_mask (policy, &mask, inbound);
805   ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
806   fill_ip6_hash_policy_kv (&policy_5tuple, &mask, &kv);
807   res = clib_bihash_search_inline_2_40_8 (bihash_table, &kv, &result);
808   if (res != 0)
809     return -1;
810
811   vec_foreach_index (ii, result_val->fp_policies_ids)
812     {
813       vp =
814         pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
815       if (ipsec_policy_is_equal (vp, policy))
816         {
817           if (vec_len (result_val->fp_policies_ids) == 1)
818             {
819               vec_free (result_val->fp_policies_ids);
820               clib_bihash_add_del_40_8 (bihash_table, &result, 0);
821             }
822           else
823             vec_delete (result_val->fp_policies_ids, 1, ii);
824
825           vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
826             {
827               if ((fp_spd->fp_mask_ids[policy->type] + imt)->mask_type_idx ==
828                   vp->fp_mask_type_id)
829                 {
830
831                   if ((fp_spd->fp_mask_ids[policy->type] + imt)->refcount-- ==
832                       1)
833                     vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
834
835                   break;
836                 }
837             }
838
839           ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
840           ipsec_sa_unlock (vp->sa_index);
841           pool_put (im->policies, vp);
842           return 0;
843         }
844     }
845   return -1;
846 }
847
848 int
849 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   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   ipsec_fp_lookup_value_t *result_val =
857     (ipsec_fp_lookup_value_t *) &result.value;
858   bool inbound = ipsec_is_policy_inbound (policy);
859   ipsec_policy_t *vp;
860   u32 ii, imt;
861   clib_bihash_16_8_t *bihash_table =
862     inbound ? pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
863                                  fp_spd->ip4_in_lookup_hash_idx) :
864                     pool_elt_at_index (im->fp_ip4_lookup_hashes_pool,
865                                  fp_spd->ip4_out_lookup_hash_idx);
866
867   ipsec_fp_ip4_get_policy_mask (policy, &mask, inbound);
868   ipsec_fp_get_policy_5tuple (policy, &policy_5tuple, inbound);
869   fill_ip4_hash_policy_kv (&policy_5tuple, &mask, &kv);
870   res = clib_bihash_search_inline_2_16_8 (bihash_table, &kv, &result);
871
872   if (res != 0)
873     return -1;
874
875   vec_foreach_index (ii, result_val->fp_policies_ids)
876     {
877       vp =
878         pool_elt_at_index (im->policies, *(result_val->fp_policies_ids + ii));
879       if (ipsec_policy_is_equal (vp, policy))
880         {
881           if (vec_len (result_val->fp_policies_ids) == 1)
882             {
883               vec_free (result_val->fp_policies_ids);
884               clib_bihash_add_del_16_8 (bihash_table, &result, 0);
885             }
886           else
887             vec_delete (result_val->fp_policies_ids, 1, ii);
888
889           vec_foreach_index (imt, fp_spd->fp_mask_ids[policy->type])
890             {
891               if ((fp_spd->fp_mask_ids[policy->type] + imt)->mask_type_idx ==
892                   vp->fp_mask_type_id)
893                 {
894
895                   if ((fp_spd->fp_mask_ids[policy->type] + imt)->refcount-- ==
896                       1)
897                     vec_del1 (fp_spd->fp_mask_ids[policy->type], imt);
898
899                   break;
900                 }
901             }
902           ipsec_fp_release_mask_type (im, vp->fp_mask_type_id);
903           ipsec_sa_unlock (vp->sa_index);
904           pool_put (im->policies, vp);
905           return 0;
906         }
907     }
908   return -1;
909 }
910
911 int
912 ipsec_fp_add_del_policy (void *fp_spd, ipsec_policy_t *policy, int is_add,
913                          u32 *stat_index)
914 {
915   ipsec_main_t *im = &ipsec_main;
916
917   if (is_add)
918     if (policy->is_ipv6)
919       return ipsec_fp_ip6_add_policy (im, (ipsec_spd_fp_t *) fp_spd, policy,
920                                       stat_index);
921     else
922       return ipsec_fp_ip4_add_policy (im, (ipsec_spd_fp_t *) fp_spd, policy,
923                                       stat_index);
924
925   else if (policy->is_ipv6)
926
927     return ipsec_fp_ip6_del_policy (im, (ipsec_spd_fp_t *) fp_spd, policy);
928   else
929     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  */