82f5a11d26f5794b306d1aca70ceaa1665f2fe6e
[vpp.git] / src / vnet / ipsec / ipsec_tun.c
1 /*
2  * ipsec_tun.h : IPSEC tunnel protection
3  *
4  * Copyright (c) 2015 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include <vnet/ipsec/ipsec_tun.h>
19 #include <vnet/ipsec/ipsec_itf.h>
20 #include <vnet/ipsec/esp.h>
21 #include <vnet/udp/udp_local.h>
22 #include <vnet/adj/adj_delegate.h>
23 #include <vnet/adj/adj_midchain.h>
24 #include <vnet/teib/teib.h>
25 #include <vnet/mpls/mpls.h>
26
27 /* instantiate the bihash functions */
28 #include <vppinfra/bihash_8_16.h>
29 #include <vppinfra/bihash_template.c>
30 #include <vppinfra/bihash_24_16.h>
31 #include <vppinfra/bihash_template.c>
32
33 #define IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS (64 * 1024)
34 #define IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE 512 << 20
35
36 /**
37  * The logger
38  */
39 vlib_log_class_t ipsec_tun_protect_logger;
40
41 /**
42  * Pool of tunnel protection objects
43  */
44 ipsec_tun_protect_t *ipsec_tun_protect_pool;
45
46 /**
47  * Adj delegate registered type
48  */
49 static adj_delegate_type_t ipsec_tun_adj_delegate_type;
50
51 /**
52  * Adj index to TX SA mapping
53  */
54 index_t *ipsec_tun_protect_sa_by_adj_index;
55
56 const ip_address_t IP_ADDR_ALL_0 = IP_ADDRESS_V4_ALL_0S;
57
58 /**
59  * The DB of all added per-nh tunnel protectiond
60  */
61 typedef struct ipsec_tun_protect_itf_db_t_
62 {
63   /** A hash table key'd on IP (4 or 6) address */
64   uword *id_hash;
65   /** If the interface is P2P then there is only one protect
66    * object associated with the auto-adj for each NH proto */
67   index_t id_itp;
68 } ipsec_tun_protect_itf_db_t;
69
70 typedef struct ipsec_tun_protect_db_t_
71 {
72   /** Per-interface vector */
73   ipsec_tun_protect_itf_db_t *id_itf;
74 } ipsec_tun_protect_db_t;
75
76 static ipsec_tun_protect_db_t itp_db;
77
78 const static ipsec_tun_protect_itf_db_t IPSEC_TUN_PROTECT_DEFAULT_DB_ENTRY = {
79   .id_itp = INDEX_INVALID,
80 };
81
82 #define ITP_DBG(_itp, _fmt, _args...)                   \
83 {                                                       \
84   vlib_log_debug(ipsec_tun_protect_logger,              \
85                  "[%U]: " _fmt,                         \
86                  format_ipsec_tun_protect,              \
87                  _itp, ##_args);                        \
88 }
89
90 #define ITP_DBG2(_fmt, _args...)                        \
91 {                                                       \
92   vlib_log_debug(ipsec_tun_protect_logger,              \
93                  _fmt, ##_args);                        \
94 }
95
96 static u32 ipsec_tun_node_regs[N_AF];
97
98 void
99 ipsec_tun_register_nodes (ip_address_family_t af)
100 {
101   if (0 == ipsec_tun_node_regs[af]++)
102     {
103       if (AF_IP4 == af)
104         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
105                                ipsec4_tun_input_node.index);
106       else
107         ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
108                                ipsec6_tun_input_node.index);
109       ipsec_register_udp_port (UDP_DST_PORT_ipsec, (AF_IP4 == af));
110     }
111 }
112
113 void
114 ipsec_tun_unregister_nodes (ip_address_family_t af)
115 {
116   ASSERT (0 != ipsec_tun_node_regs[af]);
117   if (0 == --ipsec_tun_node_regs[af])
118     {
119       if (AF_IP4 == af)
120         ip4_unregister_protocol (IP_PROTOCOL_IPSEC_ESP);
121       else
122         ip6_unregister_protocol (IP_PROTOCOL_IPSEC_ESP);
123       ipsec_unregister_udp_port (UDP_DST_PORT_ipsec, (AF_IP4 == af));
124     }
125 }
126
127 static inline const ipsec_tun_protect_t *
128 ipsec_tun_protect_from_const_base (const adj_delegate_t * ad)
129 {
130   if (ad == NULL)
131     return (NULL);
132   return (pool_elt_at_index (ipsec_tun_protect_pool, ad->ad_index));
133 }
134
135 static u32
136 ipsec_tun_protect_get_adj_next (vnet_link_t linkt,
137                                 const ipsec_tun_protect_t *itp)
138 {
139   ipsec_main_t *im;
140   u32 next;
141
142   im = &ipsec_main;
143   next = 0;
144
145   if (!(itp->itp_flags & IPSEC_PROTECT_ITF))
146     {
147       if (ip46_address_is_ip4 (&itp->itp_tun.src))
148         linkt = VNET_LINK_IP4;
149       else
150         linkt = VNET_LINK_IP6;
151     }
152
153   switch (linkt)
154     {
155     case VNET_LINK_IP4:
156       next = im->esp4_encrypt_tun_node_index;
157       break;
158     case VNET_LINK_IP6:
159       next = im->esp6_encrypt_tun_node_index;
160       break;
161     case VNET_LINK_MPLS:
162       next = im->esp_mpls_encrypt_tun_node_index;
163       break;
164     case VNET_LINK_ARP:
165     case VNET_LINK_NSH:
166     case VNET_LINK_ETHERNET:
167       ASSERT (0);
168       break;
169     }
170
171   return (next);
172 }
173
174 static void
175 ipsec_tun_setup_tx_nodes (u32 sw_if_index, const ipsec_tun_protect_t *itp)
176 {
177   vnet_feature_modify_end_node (
178     ip4_main.lookup_main.output_feature_arc_index, sw_if_index,
179     ipsec_tun_protect_get_adj_next (VNET_LINK_IP4, itp));
180   vnet_feature_modify_end_node (
181     ip6_main.lookup_main.output_feature_arc_index, sw_if_index,
182     ipsec_tun_protect_get_adj_next (VNET_LINK_IP6, itp));
183   vnet_feature_modify_end_node (
184     mpls_main.output_feature_arc_index, sw_if_index,
185     ipsec_tun_protect_get_adj_next (VNET_LINK_MPLS, itp));
186 }
187
188 static void
189 ipsec_tun_protect_add_adj (adj_index_t ai, const ipsec_tun_protect_t * itp)
190 {
191   vec_validate_init_empty (ipsec_tun_protect_sa_by_adj_index, ai,
192                            INDEX_INVALID);
193
194   if (NULL == itp)
195     {
196       ipsec_tun_protect_sa_by_adj_index[ai] = INDEX_INVALID;
197       adj_nbr_midchain_reset_next_node (ai);
198     }
199   else
200     {
201       ipsec_tun_protect_sa_by_adj_index[ai] = itp->itp_out_sa;
202       adj_nbr_midchain_update_next_node (
203         ai, ipsec_tun_protect_get_adj_next (adj_get_link_type (ai), itp));
204     }
205 }
206
207 static index_t
208 ipsec_tun_protect_find (u32 sw_if_index, const ip_address_t * nh)
209 {
210   ipsec_tun_protect_itf_db_t *idi;
211   uword *p;
212
213   if (vec_len (itp_db.id_itf) <= sw_if_index)
214     return INDEX_INVALID;
215
216   if (vnet_sw_interface_is_p2p (vnet_get_main (), sw_if_index))
217     return (itp_db.id_itf[sw_if_index].id_itp);
218
219   idi = &itp_db.id_itf[sw_if_index];
220   p = hash_get_mem (idi->id_hash, nh);
221
222   if (NULL == p)
223     {
224       return INDEX_INVALID;
225     }
226   return (p[0]);
227 }
228
229 static void
230 ipsec_tun_protect_rx_db_add (ipsec_main_t * im,
231                              const ipsec_tun_protect_t * itp)
232 {
233   const ipsec_sa_t *sa;
234   u32 sai;
235
236   if (ip46_address_is_zero (&itp->itp_crypto.dst))
237     return;
238
239   /* *INDENT-OFF* */
240   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
241   ({
242       sa = ipsec_sa_get (sai);
243
244       ipsec_tun_lkup_result_t res = {
245         .tun_index = itp - ipsec_tun_protect_pool,
246         .sa_index = sai,
247         .flags = itp->itp_flags,
248         .sw_if_index = itp->itp_sw_if_index,
249       };
250
251       /*
252        * The key is formed from the tunnel's destination
253        * as the packet lookup is done from the packet's source
254        */
255       if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
256         {
257           ipsec4_tunnel_kv_t key = {
258             .value = res,
259           };
260           clib_bihash_kv_8_16_t *bkey = (clib_bihash_kv_8_16_t*)&key;
261
262           ipsec4_tunnel_mk_key(&key, &itp->itp_crypto.dst.ip4,
263                                clib_host_to_net_u32 (sa->spi));
264
265           if (!clib_bihash_is_initialised_8_16 (&im->tun4_protect_by_key))
266             clib_bihash_init_8_16 (&im->tun4_protect_by_key,
267                                    "IPSec IPv4 tunnels",
268                                    IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
269                                    IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
270
271           clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, bkey, 1);
272           ipsec_tun_register_nodes (AF_IP4);
273         }
274       else
275         {
276           ipsec6_tunnel_kv_t key = {
277             .key = {
278               .remote_ip = itp->itp_crypto.dst.ip6,
279               .spi = clib_host_to_net_u32 (sa->spi),
280             },
281             .value = res,
282           };
283           clib_bihash_kv_24_16_t *bkey = (clib_bihash_kv_24_16_t*)&key;
284
285           if (!clib_bihash_is_initialised_24_16 (&im->tun6_protect_by_key))
286             clib_bihash_init_24_16 (&im->tun6_protect_by_key,
287                                     "IPSec IPv6 tunnels",
288                                     IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
289                                     IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
290           clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, bkey, 1);
291           ipsec_tun_register_nodes (AF_IP6);
292         }
293   }))
294   /* *INDENT-ON* */
295 }
296
297 static adj_walk_rc_t
298 ipsec_tun_protect_adj_add (adj_index_t ai, void *arg)
299 {
300   ipsec_tun_protect_t *itp = arg;
301   adj_delegate_add (adj_get (ai), ipsec_tun_adj_delegate_type,
302                     itp - ipsec_tun_protect_pool);
303   ipsec_tun_protect_add_adj (ai, itp);
304
305   if (itp->itp_flags & IPSEC_PROTECT_ITF)
306     ipsec_itf_adj_stack (ai, itp->itp_out_sa);
307
308   return (ADJ_WALK_RC_CONTINUE);
309 }
310
311 static void
312 ipsec_tun_protect_tx_db_add (ipsec_tun_protect_t * itp)
313 {
314   /*
315    * add the delegate to the adj
316    */
317   ipsec_tun_protect_itf_db_t *idi;
318   fib_protocol_t nh_proto;
319   ip46_address_t nh;
320
321   vec_validate_init_empty (itp_db.id_itf,
322                            itp->itp_sw_if_index,
323                            IPSEC_TUN_PROTECT_DEFAULT_DB_ENTRY);
324
325   idi = &itp_db.id_itf[itp->itp_sw_if_index];
326
327   if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index))
328     {
329       if (INDEX_INVALID == idi->id_itp)
330         {
331           ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp);
332         }
333       idi->id_itp = itp - ipsec_tun_protect_pool;
334
335       FOR_EACH_FIB_IP_PROTOCOL (nh_proto)
336         adj_nbr_walk (itp->itp_sw_if_index,
337                       nh_proto, ipsec_tun_protect_adj_add, itp);
338     }
339   else
340     {
341       if (NULL == idi->id_hash)
342         {
343           idi->id_hash =
344             hash_create_mem (0, sizeof (ip_address_t), sizeof (uword));
345           /*
346            * enable the encrypt feature for egress if this is the first addition
347            * on this interface
348            */
349           ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp);
350         }
351
352       hash_set_mem (idi->id_hash, itp->itp_key, itp - ipsec_tun_protect_pool);
353
354       /*
355        * walk all the adjs with the same nh on this interface
356        * to associate them with this protection
357        */
358       nh_proto = ip_address_to_46 (itp->itp_key, &nh);
359
360       adj_nbr_walk_nh (itp->itp_sw_if_index,
361                        nh_proto, &nh, ipsec_tun_protect_adj_add, itp);
362
363       ipsec_tun_register_nodes (FIB_PROTOCOL_IP6 == nh_proto ?
364                                 AF_IP6 : AF_IP4);
365     }
366 }
367
368 static void
369 ipsec_tun_protect_rx_db_remove (ipsec_main_t * im,
370                                 const ipsec_tun_protect_t * itp)
371 {
372   const ipsec_sa_t *sa;
373
374   /* *INDENT-OFF* */
375   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
376   ({
377     if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
378       {
379           ipsec4_tunnel_kv_t key;
380           clib_bihash_kv_8_16_t res, *bkey = (clib_bihash_kv_8_16_t*)&key;
381
382           ipsec4_tunnel_mk_key(&key, &itp->itp_crypto.dst.ip4,
383                                clib_host_to_net_u32 (sa->spi));
384
385           if (!clib_bihash_search_8_16 (&im->tun4_protect_by_key, bkey, &res))
386             {
387               clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, bkey, 0);
388               ipsec_tun_unregister_nodes(AF_IP4);
389             }
390       }
391     else
392       {
393         ipsec6_tunnel_kv_t key = {
394           .key = {
395             .remote_ip = itp->itp_crypto.dst.ip6,
396             .spi = clib_host_to_net_u32 (sa->spi),
397           },
398         };
399         clib_bihash_kv_24_16_t res, *bkey = (clib_bihash_kv_24_16_t*)&key;
400
401         if (!clib_bihash_search_24_16 (&im->tun6_protect_by_key, bkey, &res))
402           {
403             clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, bkey, 0);
404             ipsec_tun_unregister_nodes(AF_IP6);
405           }
406       }
407   }));
408   /* *INDENT-ON* */
409 }
410
411 static adj_walk_rc_t
412 ipsec_tun_protect_adj_remove (adj_index_t ai, void *arg)
413 {
414   ipsec_tun_protect_t *itp = arg;
415
416   adj_delegate_remove (ai, ipsec_tun_adj_delegate_type);
417   ipsec_tun_protect_add_adj (ai, NULL);
418
419   if (itp->itp_flags & IPSEC_PROTECT_ITF)
420     ipsec_itf_adj_unstack (ai);
421
422   return (ADJ_WALK_RC_CONTINUE);
423 }
424
425 static void
426 ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp)
427 {
428   ipsec_tun_protect_itf_db_t *idi;
429   fib_protocol_t nh_proto;
430   ip46_address_t nh;
431
432   nh_proto = ip_address_to_46 (itp->itp_key, &nh);
433   idi = &itp_db.id_itf[itp->itp_sw_if_index];
434
435   if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index))
436     {
437       ipsec_itf_reset_tx_nodes (itp->itp_sw_if_index);
438       idi->id_itp = INDEX_INVALID;
439
440       FOR_EACH_FIB_IP_PROTOCOL (nh_proto)
441         adj_nbr_walk (itp->itp_sw_if_index,
442                       nh_proto, ipsec_tun_protect_adj_remove, itp);
443     }
444   else
445     {
446       adj_nbr_walk_nh (itp->itp_sw_if_index,
447                        nh_proto, &nh, ipsec_tun_protect_adj_remove, itp);
448
449       hash_unset_mem (idi->id_hash, itp->itp_key);
450
451       if (0 == hash_elts (idi->id_hash))
452         {
453           ipsec_itf_reset_tx_nodes (itp->itp_sw_if_index);
454           hash_free (idi->id_hash);
455           idi->id_hash = NULL;
456         }
457       ipsec_tun_unregister_nodes (FIB_PROTOCOL_IP6 == nh_proto ?
458                                   AF_IP6 : AF_IP4);
459     }
460 }
461
462 static void
463 ipsec_tun_protect_set_crypto_addr (ipsec_tun_protect_t * itp)
464 {
465   ipsec_sa_t *sa;
466
467   /* *INDENT-OFF* */
468   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
469   ({
470     if (ipsec_sa_is_set_IS_TUNNEL (sa))
471       {
472         itp->itp_crypto.src = ip_addr_46 (&sa->tunnel.t_dst);
473         itp->itp_crypto.dst = ip_addr_46 (&sa->tunnel.t_src);
474         if (!(itp->itp_flags & IPSEC_PROTECT_ITF))
475           {
476             ipsec_sa_set_IS_PROTECT (sa);
477             itp->itp_flags |= IPSEC_PROTECT_ENCAPED;
478           }
479       }
480     else
481       {
482         itp->itp_crypto.src = itp->itp_tun.src;
483         itp->itp_crypto.dst = itp->itp_tun.dst;
484         itp->itp_flags &= ~IPSEC_PROTECT_ENCAPED;
485       }
486   }));
487   /* *INDENT-ON* */
488 }
489
490 static void
491 ipsec_tun_protect_config (ipsec_main_t * im,
492                           ipsec_tun_protect_t * itp, u32 sa_out, u32 * sas_in)
493 {
494   index_t sai;
495   u32 ii;
496
497   itp->itp_n_sa_in = vec_len (sas_in);
498   for (ii = 0; ii < itp->itp_n_sa_in; ii++)
499     itp->itp_in_sas[ii] = sas_in[ii];
500   itp->itp_out_sa = sa_out;
501
502   ipsec_sa_lock (itp->itp_out_sa);
503
504   if (itp->itp_flags & IPSEC_PROTECT_ITF)
505     ipsec_sa_set_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa));
506
507   /* *INDENT-OFF* */
508   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
509   ({
510     ipsec_sa_lock(sai);
511   }));
512   ipsec_tun_protect_set_crypto_addr(itp);
513   /* *INDENT-ON* */
514
515   /*
516    * add to the DB against each SA
517    */
518   ipsec_tun_protect_rx_db_add (im, itp);
519   ipsec_tun_protect_tx_db_add (itp);
520
521   ITP_DBG (itp, "configured");
522 }
523
524 static void
525 ipsec_tun_protect_unconfig (ipsec_main_t * im, ipsec_tun_protect_t * itp)
526 {
527   ipsec_sa_t *sa;
528   index_t sai;
529
530   /* *INDENT-OFF* */
531   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
532   ({
533     ipsec_sa_unset_IS_PROTECT (sa);
534   }));
535
536   ipsec_tun_protect_rx_db_remove (im, itp);
537   ipsec_tun_protect_tx_db_remove (itp);
538
539   ipsec_sa_unset_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa));
540   ipsec_sa_unlock(itp->itp_out_sa);
541
542   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
543   ({
544     ipsec_sa_unlock(sai);
545   }));
546   /* *INDENT-ON* */
547   ITP_DBG (itp, "unconfigured");
548 }
549
550 static void
551 ipsec_tun_protect_update_from_teib (ipsec_tun_protect_t * itp,
552                                     const teib_entry_t * ne)
553 {
554   if (NULL != ne)
555     {
556       const fib_prefix_t *pfx;
557
558       pfx = teib_entry_get_nh (ne);
559
560       ip46_address_copy (&itp->itp_tun.dst, &pfx->fp_addr);
561     }
562   else
563     ip46_address_reset (&itp->itp_tun.dst);
564 }
565
566 int
567 ipsec_tun_protect_update (u32 sw_if_index,
568                           const ip_address_t * nh, u32 sa_out, u32 * sas_in)
569 {
570   ipsec_tun_protect_t *itp;
571   u32 itpi, ii, *saip;
572   ipsec_main_t *im;
573   int rv;
574
575   if (NULL == nh)
576     nh = &IP_ADDR_ALL_0;
577
578   ITP_DBG2 ("update: %U/%U",
579             format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
580             format_ip_address, nh);
581
582   if (vec_len (sas_in) > ITP_MAX_N_SA_IN)
583     {
584       rv = VNET_API_ERROR_LIMIT_EXCEEDED;
585       goto out;
586     }
587
588   rv = 0;
589   im = &ipsec_main;
590   itpi = ipsec_tun_protect_find (sw_if_index, nh);
591
592   vec_foreach_index (ii, sas_in)
593   {
594     sas_in[ii] = ipsec_sa_find_and_lock (sas_in[ii]);
595     if (~0 == sas_in[ii])
596       {
597         rv = VNET_API_ERROR_INVALID_VALUE;
598         goto out;
599       }
600   }
601
602   sa_out = ipsec_sa_find_and_lock (sa_out);
603
604   if (~0 == sa_out)
605     {
606       rv = VNET_API_ERROR_INVALID_VALUE;
607       goto out;
608     }
609
610   if (INDEX_INVALID == itpi)
611     {
612       vnet_device_class_t *dev_class;
613       vnet_hw_interface_t *hi;
614       vnet_main_t *vnm;
615       u8 is_l2;
616
617       vnm = vnet_get_main ();
618       hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
619       dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
620
621       if (NULL == dev_class->ip_tun_desc)
622         {
623           rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
624           goto out;
625         }
626
627       pool_get_zero (ipsec_tun_protect_pool, itp);
628
629       itp->itp_sw_if_index = sw_if_index;
630       itp->itp_ai = ADJ_INDEX_INVALID;
631
632       itp->itp_n_sa_in = vec_len (sas_in);
633       for (ii = 0; ii < itp->itp_n_sa_in; ii++)
634         itp->itp_in_sas[ii] = sas_in[ii];
635       itp->itp_out_sa = sa_out;
636
637       itp->itp_key = clib_mem_alloc (sizeof (*itp->itp_key));
638       ip_address_copy (itp->itp_key, nh);
639
640       rv = dev_class->ip_tun_desc (sw_if_index,
641                                    &itp->itp_tun.src,
642                                    &itp->itp_tun.dst, &is_l2);
643
644       if (rv)
645         goto out;
646
647       if (ip46_address_is_zero (&itp->itp_tun.src))
648         {
649           /*
650            * must be one of those pesky ipsec interfaces that has no encap.
651            * the encap then MUST come from the tunnel mode SA.
652            */
653           ipsec_sa_t *sa;
654
655           sa = ipsec_sa_get (itp->itp_out_sa);
656
657           if (!ipsec_sa_is_set_IS_TUNNEL (sa))
658             {
659               rv = VNET_API_ERROR_INVALID_DST_ADDRESS;
660               goto out;
661             }
662
663           itp->itp_flags |= IPSEC_PROTECT_ITF;
664         }
665       else if (ip46_address_is_zero (&itp->itp_tun.dst))
666         {
667           /* tunnel has no destination address, presumably because it's p2mp
668              in which case we use the nh that this is protection for */
669           ipsec_tun_protect_update_from_teib
670             (itp, teib_entry_find (sw_if_index, nh));
671         }
672
673       if (is_l2)
674         itp->itp_flags |= IPSEC_PROTECT_L2;
675
676       /*
677        * add to the tunnel DB for ingress
678        *  - if the SA is in trasnport mode, then the packates will arrive
679        *    with the IP src,dst of the protected tunnel, in which case we can
680        *    simply strip the IP header and hand the payload to the protocol
681        *    appropriate input handler
682        *  - if the SA is in tunnel mode then there are two IP headers present
683        *    one for the crytpo tunnel endpoints (described in the SA) and one
684        *    for the tunnel endpoints. The outer IP headers in the srriving
685        *    packets will have the crypto endpoints. So the DB needs to contain
686        *    the crpto endpoint. Once the crypto header is stripped, revealing,
687        *    the tunnel-IP we have 2 choices:
688        *     1) do a tunnel lookup based on the revealed header
689        *     2) skip the tunnel lookup and assume that the packet matches the
690        *        one that is protected here.
691        *    If we did 1) then we would allow our peer to use the SA for tunnel
692        *    X to inject traffic onto tunnel Y, this is not good. If we do 2)
693        *    then we don't verify that the peer is indeed using SA for tunnel
694        *    X and addressing tunnel X. So we take a compromise, once the SA
695        *    matches to tunnel X we veriy that the inner IP matches the value
696        *    of the tunnel we are protecting, else it's dropped.
697        */
698       ipsec_tun_protect_config (im, itp, sa_out, sas_in);
699     }
700   else
701     {
702       /* updating SAs only */
703       itp = pool_elt_at_index (ipsec_tun_protect_pool, itpi);
704
705       ipsec_tun_protect_unconfig (im, itp);
706       ipsec_tun_protect_config (im, itp, sa_out, sas_in);
707     }
708
709   ipsec_sa_unlock (sa_out);
710   vec_foreach (saip, sas_in) ipsec_sa_unlock (*saip);
711   vec_free (sas_in);
712
713 out:
714   return (rv);
715 }
716
717 int
718 ipsec_tun_protect_del (u32 sw_if_index, const ip_address_t * nh)
719 {
720   ipsec_tun_protect_t *itp;
721   ipsec_main_t *im;
722   index_t itpi;
723
724   ITP_DBG2 ("delete: %U/%U",
725             format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
726             format_ip_address, nh);
727
728   im = &ipsec_main;
729   if (NULL == nh)
730     nh = &IP_ADDR_ALL_0;
731
732   itpi = ipsec_tun_protect_find (sw_if_index, nh);
733
734   if (INDEX_INVALID == itpi)
735     return (VNET_API_ERROR_NO_SUCH_ENTRY);
736
737   itp = ipsec_tun_protect_get (itpi);
738   ipsec_tun_protect_unconfig (im, itp);
739
740   if (ADJ_INDEX_INVALID != itp->itp_ai)
741     adj_unlock (itp->itp_ai);
742
743   clib_mem_free (itp->itp_key);
744   pool_put (ipsec_tun_protect_pool, itp);
745
746   return (0);
747 }
748
749 void
750 ipsec_tun_protect_walk (ipsec_tun_protect_walk_cb_t fn, void *ctx)
751 {
752   index_t itpi;
753
754   /* *INDENT-OFF* */
755   pool_foreach_index (itpi, ipsec_tun_protect_pool)
756    {
757     fn (itpi, ctx);
758   }
759   /* *INDENT-ON* */
760 }
761
762 void
763 ipsec_tun_protect_walk_itf (u32 sw_if_index,
764                             ipsec_tun_protect_walk_cb_t fn, void *ctx)
765 {
766   ipsec_tun_protect_itf_db_t *idi;
767   ip_address_t *key;
768   index_t itpi;
769
770   if (vec_len (itp_db.id_itf) <= sw_if_index)
771     return;
772
773   idi = &itp_db.id_itf[sw_if_index];
774
775   /* *INDENT-OFF* */
776   hash_foreach(key, itpi, idi->id_hash,
777   ({
778     fn (itpi, ctx);
779   }));
780   /* *INDENT-ON* */
781   if (INDEX_INVALID != idi->id_itp)
782     fn (idi->id_itp, ctx);
783 }
784
785 static void
786 ipsec_tun_feature_update (u32 sw_if_index, u8 arc_index, u8 is_enable,
787                           void *data)
788 {
789   ipsec_tun_protect_t *itp;
790   index_t itpi;
791
792   if (arc_index != feature_main.device_input_feature_arc_index)
793     return;
794
795   /* Only p2p tunnels supported */
796   itpi = ipsec_tun_protect_find (sw_if_index, &IP_ADDR_ALL_0);
797   if (itpi == INDEX_INVALID)
798     return;
799
800   itp = ipsec_tun_protect_get (itpi);
801
802   if (is_enable)
803     {
804       u32 decrypt_tun = ip46_address_is_ip4 (&itp->itp_crypto.dst) ?
805                           ipsec_main.esp4_decrypt_tun_node_index :
806                           ipsec_main.esp6_decrypt_tun_node_index;
807
808       if (!(itp->itp_flags & IPSEC_PROTECT_FEAT))
809         {
810           itp->itp_flags |= IPSEC_PROTECT_FEAT;
811           vnet_feature_modify_end_node (
812             feature_main.device_input_feature_arc_index, sw_if_index,
813             decrypt_tun);
814         }
815     }
816   else
817     {
818       if (itp->itp_flags & IPSEC_PROTECT_FEAT)
819         {
820           itp->itp_flags &= ~IPSEC_PROTECT_FEAT;
821
822           u32 eth_in =
823             vlib_get_node_by_name (vlib_get_main (), (u8 *) "ethernet-input")
824               ->index;
825
826           vnet_feature_modify_end_node (
827             feature_main.device_input_feature_arc_index, sw_if_index, eth_in);
828         }
829     }
830
831   /* Propagate flag change into lookup entries */
832   ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
833   ipsec_tun_protect_rx_db_add (&ipsec_main, itp);
834 }
835
836 static void
837 ipsec_tun_protect_adj_delegate_adj_deleted (adj_delegate_t * ad)
838 {
839   /* remove our delegate */
840   ipsec_tun_protect_add_adj (ad->ad_adj_index, NULL);
841   adj_delegate_remove (ad->ad_adj_index, ipsec_tun_adj_delegate_type);
842 }
843
844 static void
845 ipsec_tun_protect_adj_delegate_adj_modified (adj_delegate_t * ad)
846 {
847   ipsec_tun_protect_add_adj (ad->ad_adj_index,
848                              ipsec_tun_protect_get (ad->ad_index));
849 }
850
851 static void
852 ipsec_tun_protect_adj_delegate_adj_created (adj_index_t ai)
853 {
854   /* add our delegate if there is protection for this neighbour */
855   ip_address_t ip = IP_ADDRESS_V4_ALL_0S;
856   ip_adjacency_t *adj;
857   index_t itpi;
858
859   if (!adj_is_midchain (ai))
860     return;
861
862   vec_validate_init_empty (ipsec_tun_protect_sa_by_adj_index, ai,
863                            INDEX_INVALID);
864
865   adj = adj_get (ai);
866
867   ip_address_from_46 (&adj->sub_type.midchain.next_hop,
868                       adj->ia_nh_proto, &ip);
869
870   itpi = ipsec_tun_protect_find (adj->rewrite_header.sw_if_index, &ip);
871
872   if (INDEX_INVALID != itpi)
873     ipsec_tun_protect_adj_add (ai, ipsec_tun_protect_get (itpi));
874 }
875
876 static u8 *
877 ipsec_tun_protect_adj_delegate_format (const adj_delegate_t * aed, u8 * s)
878 {
879   const ipsec_tun_protect_t *itp;
880
881   itp = ipsec_tun_protect_from_const_base (aed);
882   s = format (s, "ipsec-tun-protect:\n%U", format_ipsec_tun_protect, itp);
883
884   return (s);
885 }
886
887 static void
888 ipsec_tun_teib_entry_added (const teib_entry_t * ne)
889 {
890   ipsec_tun_protect_t *itp;
891   index_t itpi;
892
893   itpi = ipsec_tun_protect_find (teib_entry_get_sw_if_index (ne),
894                                  teib_entry_get_peer (ne));
895
896   if (INDEX_INVALID == itpi)
897     return;
898
899   itp = ipsec_tun_protect_get (itpi);
900   ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
901   ipsec_tun_protect_update_from_teib (itp, ne);
902   ipsec_tun_protect_set_crypto_addr (itp);
903   ipsec_tun_protect_rx_db_add (&ipsec_main, itp);
904
905   ITP_DBG (itp, "teib-added");
906 }
907
908 static void
909 ipsec_tun_teib_entry_deleted (const teib_entry_t * ne)
910 {
911   ipsec_tun_protect_t *itp;
912   index_t itpi;
913
914   itpi = ipsec_tun_protect_find (teib_entry_get_sw_if_index (ne),
915                                  teib_entry_get_peer (ne));
916
917   if (INDEX_INVALID == itpi)
918     return;
919
920   itp = ipsec_tun_protect_get (itpi);
921   ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
922   ipsec_tun_protect_update_from_teib (itp, NULL);
923   ipsec_tun_protect_set_crypto_addr (itp);
924
925   ITP_DBG (itp, "teib-removed");
926 }
927
928 /**
929  * VFT registered with the adjacency delegate
930  */
931 const static adj_delegate_vft_t ipsec_tun_adj_delegate_vft = {
932   .adv_adj_deleted = ipsec_tun_protect_adj_delegate_adj_deleted,
933   .adv_adj_created = ipsec_tun_protect_adj_delegate_adj_created,
934   .adv_adj_modified = ipsec_tun_protect_adj_delegate_adj_modified,
935   .adv_format = ipsec_tun_protect_adj_delegate_format,
936 };
937
938 const static teib_vft_t ipsec_tun_teib_vft = {
939   .nv_added = ipsec_tun_teib_entry_added,
940   .nv_deleted = ipsec_tun_teib_entry_deleted,
941 };
942
943 void
944 ipsec_tun_table_init (ip_address_family_t af, uword table_size, u32 n_buckets)
945 {
946   ipsec_main_t *im;
947
948   im = &ipsec_main;
949
950   if (AF_IP4 == af)
951     clib_bihash_init_8_16 (&im->tun4_protect_by_key,
952                            "IPSec IPv4 tunnels", n_buckets, table_size);
953   else
954     clib_bihash_init_24_16 (&im->tun6_protect_by_key,
955                             "IPSec IPv6 tunnels", n_buckets, table_size);
956 }
957
958 static clib_error_t *
959 ipsec_tunnel_protect_init (vlib_main_t *vm)
960 {
961   ipsec_main_t *im;
962
963   im = &ipsec_main;
964   clib_bihash_init_24_16 (&im->tun6_protect_by_key,
965                           "IPSec IPv6 tunnels",
966                           IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
967                           IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
968   clib_bihash_init_8_16 (&im->tun4_protect_by_key,
969                          "IPSec IPv4 tunnels",
970                          IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
971                          IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
972
973   ipsec_tun_adj_delegate_type =
974     adj_delegate_register_new_type (&ipsec_tun_adj_delegate_vft);
975
976   ipsec_tun_protect_logger = vlib_log_register_class ("ipsec", "tun");
977
978   teib_register (&ipsec_tun_teib_vft);
979
980   vnet_feature_register (ipsec_tun_feature_update, NULL);
981
982   return 0;
983 }
984
985 VLIB_INIT_FUNCTION (ipsec_tunnel_protect_init);
986
987 /*
988  * fd.io coding-style-patch-verification: ON
989  *
990  * Local Variables:
991  * eval: (c-set-style "gnu")
992  * End:
993  */