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