ethernet: check destination mac for L3 in ethernet-input node
[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   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
240   ({
241       sa = ipsec_sa_get (sai);
242
243       ipsec_tun_lkup_result_t res = {
244         .tun_index = itp - ipsec_tun_protect_pool,
245         .sa_index = sai,
246         .flags = itp->itp_flags,
247         .sw_if_index = itp->itp_sw_if_index,
248       };
249
250       /*
251        * The key is formed from the tunnel's destination
252        * as the packet lookup is done from the packet's source
253        */
254       if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
255         {
256           ipsec4_tunnel_kv_t key = {
257             .value = res,
258           };
259           clib_bihash_kv_8_16_t *bkey = (clib_bihash_kv_8_16_t*)&key;
260
261           ipsec4_tunnel_mk_key(&key, &itp->itp_crypto.dst.ip4,
262                                clib_host_to_net_u32 (sa->spi));
263
264           if (!clib_bihash_is_initialised_8_16 (&im->tun4_protect_by_key))
265             clib_bihash_init_8_16 (&im->tun4_protect_by_key,
266                                    "IPSec IPv4 tunnels",
267                                    IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
268                                    IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
269
270           clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, bkey, 1);
271           ipsec_tun_register_nodes (AF_IP4);
272         }
273       else
274         {
275           ipsec6_tunnel_kv_t key = {
276             .key = {
277               .remote_ip = itp->itp_crypto.dst.ip6,
278               .spi = clib_host_to_net_u32 (sa->spi),
279             },
280             .value = res,
281           };
282           clib_bihash_kv_24_16_t *bkey = (clib_bihash_kv_24_16_t*)&key;
283
284           if (!clib_bihash_is_initialised_24_16 (&im->tun6_protect_by_key))
285             clib_bihash_init_24_16 (&im->tun6_protect_by_key,
286                                     "IPSec IPv6 tunnels",
287                                     IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
288                                     IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
289           clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, bkey, 1);
290           ipsec_tun_register_nodes (AF_IP6);
291         }
292   }))
293 }
294
295 static adj_walk_rc_t
296 ipsec_tun_protect_adj_add (adj_index_t ai, void *arg)
297 {
298   ipsec_tun_protect_t *itp = arg;
299   adj_delegate_add (adj_get (ai), ipsec_tun_adj_delegate_type,
300                     itp - ipsec_tun_protect_pool);
301   ipsec_tun_protect_add_adj (ai, itp);
302
303   if (itp->itp_flags & IPSEC_PROTECT_ITF)
304     ipsec_itf_adj_stack (ai, itp->itp_out_sa);
305
306   return (ADJ_WALK_RC_CONTINUE);
307 }
308
309 static void
310 ipsec_tun_protect_tx_db_add (ipsec_tun_protect_t * itp)
311 {
312   /*
313    * add the delegate to the adj
314    */
315   ipsec_tun_protect_itf_db_t *idi;
316   fib_protocol_t nh_proto;
317   ip46_address_t nh;
318
319   vec_validate_init_empty (itp_db.id_itf,
320                            itp->itp_sw_if_index,
321                            IPSEC_TUN_PROTECT_DEFAULT_DB_ENTRY);
322
323   idi = &itp_db.id_itf[itp->itp_sw_if_index];
324
325   if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index))
326     {
327       if (INDEX_INVALID == idi->id_itp)
328         {
329           ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp);
330         }
331       idi->id_itp = itp - ipsec_tun_protect_pool;
332
333       FOR_EACH_FIB_IP_PROTOCOL (nh_proto)
334         adj_nbr_walk (itp->itp_sw_if_index,
335                       nh_proto, ipsec_tun_protect_adj_add, itp);
336     }
337   else
338     {
339       if (NULL == idi->id_hash)
340         {
341           idi->id_hash =
342             hash_create_mem (0, sizeof (ip_address_t), sizeof (uword));
343           /*
344            * enable the encrypt feature for egress if this is the first addition
345            * on this interface
346            */
347           ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp);
348         }
349
350       hash_set_mem (idi->id_hash, itp->itp_key, itp - ipsec_tun_protect_pool);
351
352       /*
353        * walk all the adjs with the same nh on this interface
354        * to associate them with this protection
355        */
356       nh_proto = ip_address_to_46 (itp->itp_key, &nh);
357
358       adj_nbr_walk_nh (itp->itp_sw_if_index,
359                        nh_proto, &nh, ipsec_tun_protect_adj_add, itp);
360
361       ipsec_tun_register_nodes (FIB_PROTOCOL_IP6 == nh_proto ?
362                                 AF_IP6 : AF_IP4);
363     }
364 }
365
366 static void
367 ipsec_tun_protect_rx_db_remove (ipsec_main_t * im,
368                                 const ipsec_tun_protect_t * itp)
369 {
370   const ipsec_sa_t *sa;
371
372   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
373   ({
374     if (ip46_address_is_ip4 (&itp->itp_crypto.dst))
375       {
376           ipsec4_tunnel_kv_t key;
377           clib_bihash_kv_8_16_t res, *bkey = (clib_bihash_kv_8_16_t*)&key;
378
379           ipsec4_tunnel_mk_key(&key, &itp->itp_crypto.dst.ip4,
380                                clib_host_to_net_u32 (sa->spi));
381
382           if (!clib_bihash_search_8_16 (&im->tun4_protect_by_key, bkey, &res))
383             {
384               clib_bihash_add_del_8_16 (&im->tun4_protect_by_key, bkey, 0);
385               ipsec_tun_unregister_nodes(AF_IP4);
386             }
387       }
388     else
389       {
390         ipsec6_tunnel_kv_t key = {
391           .key = {
392             .remote_ip = itp->itp_crypto.dst.ip6,
393             .spi = clib_host_to_net_u32 (sa->spi),
394           },
395         };
396         clib_bihash_kv_24_16_t res, *bkey = (clib_bihash_kv_24_16_t*)&key;
397
398         if (!clib_bihash_search_24_16 (&im->tun6_protect_by_key, bkey, &res))
399           {
400             clib_bihash_add_del_24_16 (&im->tun6_protect_by_key, bkey, 0);
401             ipsec_tun_unregister_nodes(AF_IP6);
402           }
403       }
404   }));
405 }
406
407 static adj_walk_rc_t
408 ipsec_tun_protect_adj_remove (adj_index_t ai, void *arg)
409 {
410   ipsec_tun_protect_t *itp = arg;
411
412   adj_delegate_remove (ai, ipsec_tun_adj_delegate_type);
413   ipsec_tun_protect_add_adj (ai, NULL);
414
415   if (itp->itp_flags & IPSEC_PROTECT_ITF)
416     ipsec_itf_adj_unstack (ai);
417
418   return (ADJ_WALK_RC_CONTINUE);
419 }
420
421 static void
422 ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp)
423 {
424   ipsec_tun_protect_itf_db_t *idi;
425   fib_protocol_t nh_proto;
426   ip46_address_t nh;
427
428   nh_proto = ip_address_to_46 (itp->itp_key, &nh);
429   idi = &itp_db.id_itf[itp->itp_sw_if_index];
430
431   if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index))
432     {
433       ipsec_itf_reset_tx_nodes (itp->itp_sw_if_index);
434       idi->id_itp = INDEX_INVALID;
435
436       FOR_EACH_FIB_IP_PROTOCOL (nh_proto)
437         adj_nbr_walk (itp->itp_sw_if_index,
438                       nh_proto, ipsec_tun_protect_adj_remove, itp);
439     }
440   else
441     {
442       adj_nbr_walk_nh (itp->itp_sw_if_index,
443                        nh_proto, &nh, ipsec_tun_protect_adj_remove, itp);
444
445       hash_unset_mem (idi->id_hash, itp->itp_key);
446
447       if (0 == hash_elts (idi->id_hash))
448         {
449           ipsec_itf_reset_tx_nodes (itp->itp_sw_if_index);
450           hash_free (idi->id_hash);
451           idi->id_hash = NULL;
452         }
453       ipsec_tun_unregister_nodes (FIB_PROTOCOL_IP6 == nh_proto ?
454                                   AF_IP6 : AF_IP4);
455     }
456 }
457
458 static void
459 ipsec_tun_protect_set_crypto_addr (ipsec_tun_protect_t * itp)
460 {
461   ipsec_sa_t *sa;
462
463   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
464   ({
465     if (ipsec_sa_is_set_IS_TUNNEL (sa))
466       {
467         itp->itp_crypto.src = ip_addr_46 (&sa->tunnel.t_dst);
468         itp->itp_crypto.dst = ip_addr_46 (&sa->tunnel.t_src);
469         if (!(itp->itp_flags & IPSEC_PROTECT_ITF))
470           {
471             ipsec_sa_set_IS_PROTECT (sa);
472             itp->itp_flags |= IPSEC_PROTECT_ENCAPED;
473           }
474       }
475     else
476       {
477         itp->itp_crypto.src = itp->itp_tun.src;
478         itp->itp_crypto.dst = itp->itp_tun.dst;
479         itp->itp_flags &= ~IPSEC_PROTECT_ENCAPED;
480       }
481   }));
482 }
483
484 static void
485 ipsec_tun_protect_config (ipsec_main_t * im,
486                           ipsec_tun_protect_t * itp, u32 sa_out, u32 * sas_in)
487 {
488   index_t sai;
489   u32 ii;
490
491   itp->itp_n_sa_in = vec_len (sas_in);
492   for (ii = 0; ii < itp->itp_n_sa_in; ii++)
493     itp->itp_in_sas[ii] = sas_in[ii];
494   itp->itp_out_sa = sa_out;
495
496   ipsec_sa_lock (itp->itp_out_sa);
497
498   if (itp->itp_flags & IPSEC_PROTECT_ITF)
499     ipsec_sa_set_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa));
500
501   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
502   ({
503     ipsec_sa_lock(sai);
504   }));
505   ipsec_tun_protect_set_crypto_addr(itp);
506
507   /*
508    * add to the DB against each SA
509    */
510   ipsec_tun_protect_rx_db_add (im, itp);
511   ipsec_tun_protect_tx_db_add (itp);
512
513   ITP_DBG (itp, "configured");
514 }
515
516 static void
517 ipsec_tun_protect_unconfig (ipsec_main_t * im, ipsec_tun_protect_t * itp)
518 {
519   ipsec_sa_t *sa;
520   index_t sai;
521
522   FOR_EACH_IPSEC_PROTECT_INPUT_SA(itp, sa,
523   ({
524     ipsec_sa_unset_IS_PROTECT (sa);
525   }));
526
527   ipsec_tun_protect_rx_db_remove (im, itp);
528   ipsec_tun_protect_tx_db_remove (itp);
529
530   ipsec_sa_unset_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa));
531   ipsec_sa_unlock(itp->itp_out_sa);
532
533   FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai,
534   ({
535     ipsec_sa_unlock(sai);
536   }));
537   ITP_DBG (itp, "unconfigured");
538 }
539
540 static void
541 ipsec_tun_protect_update_from_teib (ipsec_tun_protect_t * itp,
542                                     const teib_entry_t * ne)
543 {
544   if (NULL != ne)
545     {
546       const fib_prefix_t *pfx;
547
548       pfx = teib_entry_get_nh (ne);
549
550       ip46_address_copy (&itp->itp_tun.dst, &pfx->fp_addr);
551     }
552   else
553     ip46_address_reset (&itp->itp_tun.dst);
554 }
555
556 int
557 ipsec_tun_protect_update (u32 sw_if_index,
558                           const ip_address_t * nh, u32 sa_out, u32 * sas_in)
559 {
560   ipsec_tun_protect_t *itp;
561   u32 itpi, ii, *saip;
562   ipsec_main_t *im;
563   int rv;
564
565   if (NULL == nh)
566     nh = &IP_ADDR_ALL_0;
567
568   ITP_DBG2 ("update: %U/%U",
569             format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
570             format_ip_address, nh);
571
572   if (vec_len (sas_in) > ITP_MAX_N_SA_IN)
573     {
574       rv = VNET_API_ERROR_LIMIT_EXCEEDED;
575       goto out;
576     }
577
578   rv = 0;
579   im = &ipsec_main;
580   itpi = ipsec_tun_protect_find (sw_if_index, nh);
581
582   vec_foreach_index (ii, sas_in)
583   {
584     sas_in[ii] = ipsec_sa_find_and_lock (sas_in[ii]);
585     if (~0 == sas_in[ii])
586       {
587         rv = VNET_API_ERROR_INVALID_VALUE;
588         goto out;
589       }
590   }
591
592   sa_out = ipsec_sa_find_and_lock (sa_out);
593
594   if (~0 == sa_out)
595     {
596       rv = VNET_API_ERROR_INVALID_VALUE;
597       goto out;
598     }
599
600   if (INDEX_INVALID == itpi)
601     {
602       vnet_device_class_t *dev_class;
603       vnet_hw_interface_t *hi;
604       vnet_main_t *vnm;
605       u8 is_l2;
606
607       vnm = vnet_get_main ();
608       hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
609       dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
610
611       if (NULL == dev_class->ip_tun_desc)
612         {
613           rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
614           goto out;
615         }
616
617       pool_get_zero (ipsec_tun_protect_pool, itp);
618
619       itp->itp_sw_if_index = sw_if_index;
620       itp->itp_ai = ADJ_INDEX_INVALID;
621
622       itp->itp_n_sa_in = vec_len (sas_in);
623       for (ii = 0; ii < itp->itp_n_sa_in; ii++)
624         itp->itp_in_sas[ii] = sas_in[ii];
625       itp->itp_out_sa = sa_out;
626
627       itp->itp_key = clib_mem_alloc (sizeof (*itp->itp_key));
628       ip_address_copy (itp->itp_key, nh);
629
630       rv = dev_class->ip_tun_desc (sw_if_index,
631                                    &itp->itp_tun.src,
632                                    &itp->itp_tun.dst, &is_l2);
633
634       if (rv)
635         goto out;
636
637       if (ip46_address_is_zero (&itp->itp_tun.src))
638         {
639           /*
640            * must be one of those pesky ipsec interfaces that has no encap.
641            * the encap then MUST come from the tunnel mode SA.
642            */
643           ipsec_sa_t *sa;
644
645           sa = ipsec_sa_get (itp->itp_out_sa);
646
647           if (!ipsec_sa_is_set_IS_TUNNEL (sa))
648             {
649               rv = VNET_API_ERROR_INVALID_DST_ADDRESS;
650               goto out;
651             }
652
653           itp->itp_flags |= IPSEC_PROTECT_ITF;
654         }
655       else if (ip46_address_is_zero (&itp->itp_tun.dst))
656         {
657           /* tunnel has no destination address, presumably because it's p2mp
658              in which case we use the nh that this is protection for */
659           ipsec_tun_protect_update_from_teib
660             (itp, teib_entry_find (sw_if_index, nh));
661         }
662
663       if (is_l2)
664         itp->itp_flags |= IPSEC_PROTECT_L2;
665
666       /*
667        * add to the tunnel DB for ingress
668        *  - if the SA is in trasnport mode, then the packates will arrive
669        *    with the IP src,dst of the protected tunnel, in which case we can
670        *    simply strip the IP header and hand the payload to the protocol
671        *    appropriate input handler
672        *  - if the SA is in tunnel mode then there are two IP headers present
673        *    one for the crytpo tunnel endpoints (described in the SA) and one
674        *    for the tunnel endpoints. The outer IP headers in the srriving
675        *    packets will have the crypto endpoints. So the DB needs to contain
676        *    the crpto endpoint. Once the crypto header is stripped, revealing,
677        *    the tunnel-IP we have 2 choices:
678        *     1) do a tunnel lookup based on the revealed header
679        *     2) skip the tunnel lookup and assume that the packet matches the
680        *        one that is protected here.
681        *    If we did 1) then we would allow our peer to use the SA for tunnel
682        *    X to inject traffic onto tunnel Y, this is not good. If we do 2)
683        *    then we don't verify that the peer is indeed using SA for tunnel
684        *    X and addressing tunnel X. So we take a compromise, once the SA
685        *    matches to tunnel X we veriy that the inner IP matches the value
686        *    of the tunnel we are protecting, else it's dropped.
687        */
688       ipsec_tun_protect_config (im, itp, sa_out, sas_in);
689     }
690   else
691     {
692       /* updating SAs only */
693       itp = pool_elt_at_index (ipsec_tun_protect_pool, itpi);
694
695       ipsec_tun_protect_unconfig (im, itp);
696       ipsec_tun_protect_config (im, itp, sa_out, sas_in);
697     }
698
699   ipsec_sa_unlock (sa_out);
700   vec_foreach (saip, sas_in) ipsec_sa_unlock (*saip);
701   vec_free (sas_in);
702
703 out:
704   return (rv);
705 }
706
707 int
708 ipsec_tun_protect_del (u32 sw_if_index, const ip_address_t * nh)
709 {
710   ipsec_tun_protect_t *itp;
711   ipsec_main_t *im;
712   index_t itpi;
713
714   ITP_DBG2 ("delete: %U/%U",
715             format_vnet_sw_if_index_name, vnet_get_main (), sw_if_index,
716             format_ip_address, nh);
717
718   im = &ipsec_main;
719   if (NULL == nh)
720     nh = &IP_ADDR_ALL_0;
721
722   itpi = ipsec_tun_protect_find (sw_if_index, nh);
723
724   if (INDEX_INVALID == itpi)
725     return (VNET_API_ERROR_NO_SUCH_ENTRY);
726
727   itp = ipsec_tun_protect_get (itpi);
728   ipsec_tun_protect_unconfig (im, itp);
729
730   if (ADJ_INDEX_INVALID != itp->itp_ai)
731     adj_unlock (itp->itp_ai);
732
733   clib_mem_free (itp->itp_key);
734   pool_put (ipsec_tun_protect_pool, itp);
735
736   return (0);
737 }
738
739 void
740 ipsec_tun_protect_walk (ipsec_tun_protect_walk_cb_t fn, void *ctx)
741 {
742   index_t itpi;
743
744   pool_foreach_index (itpi, ipsec_tun_protect_pool)
745    {
746     fn (itpi, ctx);
747   }
748 }
749
750 void
751 ipsec_tun_protect_walk_itf (u32 sw_if_index,
752                             ipsec_tun_protect_walk_cb_t fn, void *ctx)
753 {
754   ipsec_tun_protect_itf_db_t *idi;
755   ip_address_t *key;
756   index_t itpi;
757
758   if (vec_len (itp_db.id_itf) <= sw_if_index)
759     return;
760
761   idi = &itp_db.id_itf[sw_if_index];
762
763   hash_foreach(key, itpi, idi->id_hash,
764   ({
765     fn (itpi, ctx);
766   }));
767   if (INDEX_INVALID != idi->id_itp)
768     fn (idi->id_itp, ctx);
769 }
770
771 static void
772 ipsec_tun_feature_update (u32 sw_if_index, u8 arc_index, u8 is_enable,
773                           void *data)
774 {
775   ipsec_tun_protect_t *itp;
776   index_t itpi;
777
778   if (arc_index != feature_main.device_input_feature_arc_index)
779     return;
780
781   /* Only p2p tunnels supported */
782   itpi = ipsec_tun_protect_find (sw_if_index, &IP_ADDR_ALL_0);
783   if (itpi == INDEX_INVALID)
784     return;
785
786   itp = ipsec_tun_protect_get (itpi);
787
788   if (is_enable)
789     {
790       u32 decrypt_tun = ip46_address_is_ip4 (&itp->itp_crypto.dst) ?
791                           ipsec_main.esp4_decrypt_tun_node_index :
792                           ipsec_main.esp6_decrypt_tun_node_index;
793
794       if (!(itp->itp_flags & IPSEC_PROTECT_FEAT))
795         {
796           itp->itp_flags |= IPSEC_PROTECT_FEAT;
797           vnet_feature_modify_end_node (
798             feature_main.device_input_feature_arc_index, sw_if_index,
799             decrypt_tun);
800         }
801     }
802   else
803     {
804       if (itp->itp_flags & IPSEC_PROTECT_FEAT)
805         {
806           itp->itp_flags &= ~IPSEC_PROTECT_FEAT;
807
808           u32 eth_in =
809             vlib_get_node_by_name (vlib_get_main (), (u8 *) "ethernet-input")
810               ->index;
811
812           vnet_feature_modify_end_node (
813             feature_main.device_input_feature_arc_index, sw_if_index, eth_in);
814         }
815     }
816
817   /* Propagate flag change into lookup entries */
818   ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
819   ipsec_tun_protect_rx_db_add (&ipsec_main, itp);
820 }
821
822 static void
823 ipsec_tun_protect_adj_delegate_adj_deleted (adj_delegate_t * ad)
824 {
825   /* remove our delegate */
826   ipsec_tun_protect_add_adj (ad->ad_adj_index, NULL);
827   adj_delegate_remove (ad->ad_adj_index, ipsec_tun_adj_delegate_type);
828 }
829
830 static void
831 ipsec_tun_protect_adj_delegate_adj_modified (adj_delegate_t * ad)
832 {
833   ipsec_tun_protect_add_adj (ad->ad_adj_index,
834                              ipsec_tun_protect_get (ad->ad_index));
835 }
836
837 static void
838 ipsec_tun_protect_adj_delegate_adj_created (adj_index_t ai)
839 {
840   /* add our delegate if there is protection for this neighbour */
841   ip_address_t ip = IP_ADDRESS_V4_ALL_0S;
842   ip_adjacency_t *adj;
843   index_t itpi;
844
845   if (!adj_is_midchain (ai))
846     return;
847
848   vec_validate_init_empty (ipsec_tun_protect_sa_by_adj_index, ai,
849                            INDEX_INVALID);
850
851   adj = adj_get (ai);
852
853   ip_address_from_46 (&adj->sub_type.midchain.next_hop,
854                       adj->ia_nh_proto, &ip);
855
856   itpi = ipsec_tun_protect_find (adj->rewrite_header.sw_if_index, &ip);
857
858   if (INDEX_INVALID != itpi)
859     ipsec_tun_protect_adj_add (ai, ipsec_tun_protect_get (itpi));
860 }
861
862 static u8 *
863 ipsec_tun_protect_adj_delegate_format (const adj_delegate_t * aed, u8 * s)
864 {
865   const ipsec_tun_protect_t *itp;
866
867   itp = ipsec_tun_protect_from_const_base (aed);
868   s = format (s, "ipsec-tun-protect:\n%U", format_ipsec_tun_protect, itp);
869
870   return (s);
871 }
872
873 static void
874 ipsec_tun_teib_entry_added (const teib_entry_t * ne)
875 {
876   ipsec_tun_protect_t *itp;
877   index_t itpi;
878
879   itpi = ipsec_tun_protect_find (teib_entry_get_sw_if_index (ne),
880                                  teib_entry_get_peer (ne));
881
882   if (INDEX_INVALID == itpi)
883     return;
884
885   itp = ipsec_tun_protect_get (itpi);
886   ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
887   ipsec_tun_protect_update_from_teib (itp, ne);
888   ipsec_tun_protect_set_crypto_addr (itp);
889   ipsec_tun_protect_rx_db_add (&ipsec_main, itp);
890
891   ITP_DBG (itp, "teib-added");
892 }
893
894 static void
895 ipsec_tun_teib_entry_deleted (const teib_entry_t * ne)
896 {
897   ipsec_tun_protect_t *itp;
898   index_t itpi;
899
900   itpi = ipsec_tun_protect_find (teib_entry_get_sw_if_index (ne),
901                                  teib_entry_get_peer (ne));
902
903   if (INDEX_INVALID == itpi)
904     return;
905
906   itp = ipsec_tun_protect_get (itpi);
907   ipsec_tun_protect_rx_db_remove (&ipsec_main, itp);
908   ipsec_tun_protect_update_from_teib (itp, NULL);
909   ipsec_tun_protect_set_crypto_addr (itp);
910
911   ITP_DBG (itp, "teib-removed");
912 }
913
914 /**
915  * VFT registered with the adjacency delegate
916  */
917 const static adj_delegate_vft_t ipsec_tun_adj_delegate_vft = {
918   .adv_adj_deleted = ipsec_tun_protect_adj_delegate_adj_deleted,
919   .adv_adj_created = ipsec_tun_protect_adj_delegate_adj_created,
920   .adv_adj_modified = ipsec_tun_protect_adj_delegate_adj_modified,
921   .adv_format = ipsec_tun_protect_adj_delegate_format,
922 };
923
924 const static teib_vft_t ipsec_tun_teib_vft = {
925   .nv_added = ipsec_tun_teib_entry_added,
926   .nv_deleted = ipsec_tun_teib_entry_deleted,
927 };
928
929 void
930 ipsec_tun_table_init (ip_address_family_t af, uword table_size, u32 n_buckets)
931 {
932   ipsec_main_t *im;
933
934   im = &ipsec_main;
935
936   if (AF_IP4 == af)
937     clib_bihash_init_8_16 (&im->tun4_protect_by_key,
938                            "IPSec IPv4 tunnels", n_buckets, table_size);
939   else
940     clib_bihash_init_24_16 (&im->tun6_protect_by_key,
941                             "IPSec IPv6 tunnels", n_buckets, table_size);
942 }
943
944 static clib_error_t *
945 ipsec_tunnel_protect_init (vlib_main_t *vm)
946 {
947   ipsec_main_t *im;
948
949   im = &ipsec_main;
950   clib_bihash_init_24_16 (&im->tun6_protect_by_key,
951                           "IPSec IPv6 tunnels",
952                           IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
953                           IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
954   clib_bihash_init_8_16 (&im->tun4_protect_by_key,
955                          "IPSec IPv4 tunnels",
956                          IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS,
957                          IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE);
958
959   ipsec_tun_adj_delegate_type =
960     adj_delegate_register_new_type (&ipsec_tun_adj_delegate_vft);
961
962   ipsec_tun_protect_logger = vlib_log_register_class ("ipsec", "tun");
963
964   teib_register (&ipsec_tun_teib_vft);
965
966   vnet_feature_register (ipsec_tun_feature_update, NULL);
967
968   return 0;
969 }
970
971 VLIB_INIT_FUNCTION (ipsec_tunnel_protect_init);
972
973 /*
974  * fd.io coding-style-patch-verification: ON
975  *
976  * Local Variables:
977  * eval: (c-set-style "gnu")
978  * End:
979  */