2e0dae0a35d1ad045652d892fc5c9f48c0405a7d
[vpp.git] / src / vnet / ipsec / ipsec_if.c
1 /*
2  * ipsec_if.c : IPSec interface support
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/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
21
22 #include <vnet/ipsec/ipsec.h>
23 #include <vnet/ipsec/esp.h>
24
25 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
26
27 static u8 *
28 format_ipsec_name (u8 * s, va_list * args)
29 {
30   u32 dev_instance = va_arg (*args, u32);
31   ipsec_main_t *im = &ipsec_main;
32   ipsec_tunnel_if_t *t = im->tunnel_interfaces + dev_instance;
33
34   return format (s, "ipsec%d", t->show_instance);
35 }
36
37 /* Statistics (not really errors) */
38 #define foreach_ipsec_if_tx_error    \
39 _(TX, "good packets transmitted")
40
41 static char *ipsec_if_tx_error_strings[] = {
42 #define _(sym,string) string,
43   foreach_ipsec_if_tx_error
44 #undef _
45 };
46
47 typedef enum
48 {
49 #define _(sym,str) IPSEC_IF_OUTPUT_ERROR_##sym,
50   foreach_ipsec_if_tx_error
51 #undef _
52     IPSEC_IF_TX_N_ERROR,
53 } ipsec_if_tx_error_t;
54
55 typedef struct
56 {
57   u32 spi;
58   u32 seq;
59 } ipsec_if_tx_trace_t;
60
61 u8 *
62 format_ipsec_if_tx_trace (u8 * s, va_list * args)
63 {
64   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
65   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
66   ipsec_if_tx_trace_t *t = va_arg (*args, ipsec_if_tx_trace_t *);
67
68   s = format (s, "IPSec: spi %u seq %u", t->spi, t->seq);
69   return s;
70 }
71
72 static uword
73 ipsec_if_tx_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
74                      vlib_frame_t * from_frame)
75 {
76   ipsec_main_t *im = &ipsec_main;
77   vnet_main_t *vnm = im->vnet_main;
78   vnet_interface_main_t *vim = &vnm->interface_main;
79   u32 *from, *to_next = 0, next_index;
80   u32 n_left_from, sw_if_index0, last_sw_if_index = ~0;
81   u32 thread_index = vm->thread_index;
82   u32 n_bytes = 0, n_packets = 0;
83
84   from = vlib_frame_vector_args (from_frame);
85   n_left_from = from_frame->n_vectors;
86   next_index = node->cached_next_index;
87
88   while (n_left_from > 0)
89     {
90       u32 n_left_to_next;
91
92       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
93
94       while (n_left_from > 0 && n_left_to_next > 0)
95         {
96           u32 bi0, next0, len0;
97           vlib_buffer_t *b0;
98           ipsec_tunnel_if_t *t0;
99           vnet_hw_interface_t *hi0;
100
101           bi0 = to_next[0] = from[0];
102           from += 1;
103           n_left_from -= 1;
104           to_next += 1;
105           n_left_to_next -= 1;
106           b0 = vlib_get_buffer (vm, bi0);
107           sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_TX];
108           hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
109           t0 = pool_elt_at_index (im->tunnel_interfaces, hi0->dev_instance);
110           vnet_buffer (b0)->ipsec.sad_index = t0->output_sa_index;
111           next0 = IPSEC_OUTPUT_NEXT_ESP4_ENCRYPT;
112
113           len0 = vlib_buffer_length_in_chain (vm, b0);
114
115           if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index))
116             {
117               n_packets++;
118               n_bytes += len0;
119             }
120           else
121             {
122               vlib_increment_combined_counter (vim->combined_sw_if_counters +
123                                                VNET_INTERFACE_COUNTER_TX,
124                                                thread_index, sw_if_index0,
125                                                n_packets, n_bytes);
126               last_sw_if_index = sw_if_index0;
127               n_packets = 1;
128               n_bytes = len0;
129             }
130
131           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
132             {
133               ipsec_if_tx_trace_t *tr =
134                 vlib_add_trace (vm, node, b0, sizeof (*tr));
135               ipsec_sa_t *sa0 =
136                 pool_elt_at_index (im->sad, t0->output_sa_index);
137               tr->spi = sa0->spi;
138               tr->seq = sa0->seq;
139             }
140
141           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
142                                            n_left_to_next, bi0, next0);
143         }
144       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
145     }
146
147   if (last_sw_if_index != ~0)
148     {
149       vlib_increment_combined_counter (vim->combined_sw_if_counters +
150                                        VNET_INTERFACE_COUNTER_TX,
151                                        thread_index,
152                                        last_sw_if_index, n_packets, n_bytes);
153     }
154
155   return from_frame->n_vectors;
156 }
157
158
159 static clib_error_t *
160 ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
161 {
162   ipsec_main_t *im = &ipsec_main;
163   clib_error_t *err = 0;
164   ipsec_tunnel_if_t *t;
165   vnet_hw_interface_t *hi;
166   ipsec_sa_t *sa;
167
168   hi = vnet_get_hw_interface (vnm, hw_if_index);
169   t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance);
170
171   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
172     {
173       sa = pool_elt_at_index (im->sad, t->input_sa_index);
174
175       err = ipsec_check_support_cb (im, sa);
176       if (err)
177         return err;
178
179       err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 1);
180       if (err)
181         return err;
182
183       sa = pool_elt_at_index (im->sad, t->output_sa_index);
184
185       err = ipsec_check_support_cb (im, sa);
186       if (err)
187         return err;
188
189       err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 1);
190       if (err)
191         return err;
192
193       vnet_hw_interface_set_flags (vnm, hw_if_index,
194                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
195     }
196   else
197     {
198       vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
199       sa = pool_elt_at_index (im->sad, t->input_sa_index);
200       err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 0);
201       if (err)
202         return err;
203       sa = pool_elt_at_index (im->sad, t->output_sa_index);
204       err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 0);
205       if (err)
206         return err;
207     }
208
209   return /* no error */ 0;
210 }
211
212
213 /* *INDENT-OFF* */
214 VNET_DEVICE_CLASS (ipsec_device_class, static) =
215 {
216   .name = "IPSec",
217   .format_device_name = format_ipsec_name,
218   .format_tx_trace = format_ipsec_if_tx_trace,
219   .tx_function = ipsec_if_tx_node_fn,
220   .tx_function_n_errors = IPSEC_IF_TX_N_ERROR,
221   .tx_function_error_strings = ipsec_if_tx_error_strings,
222   .admin_up_down_function = ipsec_admin_up_down_function,
223 };
224 /* *INDENT-ON* */
225
226 /* *INDENT-OFF* */
227 VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
228 {
229   .name = "IPSec",
230   .build_rewrite = default_build_rewrite,
231   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
232 };
233 /* *INDENT-ON* */
234
235 static int
236 ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
237 {
238   vnet_main_t *vnm = vnet_get_main ();
239   ASSERT (vlib_get_thread_index () == 0);
240
241   return ipsec_add_del_tunnel_if_internal (vnm, a, NULL);
242 }
243
244 int
245 ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
246 {
247   vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback,
248                                (u8 *) args, sizeof (*args));
249   return 0;
250 }
251
252 int
253 ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
254                                   ipsec_add_del_tunnel_args_t * args,
255                                   u32 * sw_if_index)
256 {
257   ipsec_tunnel_if_t *t;
258   ipsec_main_t *im = &ipsec_main;
259   vnet_hw_interface_t *hi = NULL;
260   u32 hw_if_index = ~0;
261   uword *p;
262   ipsec_sa_t *sa;
263   u32 dev_instance;
264   u32 slot;
265
266   u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
267   p = hash_get (im->ipsec_if_pool_index_by_key, key);
268
269   if (args->is_add)
270     {
271       /* check if same src/dst pair exists */
272       if (p)
273         return VNET_API_ERROR_INVALID_VALUE;
274
275       pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
276       clib_memset (t, 0, sizeof (*t));
277
278       dev_instance = t - im->tunnel_interfaces;
279       if (args->renumber)
280         t->show_instance = args->show_instance;
281       else
282         t->show_instance = dev_instance;
283
284       if (hash_get (im->ipsec_if_real_dev_by_show_dev, t->show_instance))
285         {
286           pool_put (im->tunnel_interfaces, t);
287           return VNET_API_ERROR_INSTANCE_IN_USE;
288         }
289
290       hash_set (im->ipsec_if_real_dev_by_show_dev, t->show_instance,
291                 dev_instance);
292
293       pool_get (im->sad, sa);
294       clib_memset (sa, 0, sizeof (*sa));
295       t->input_sa_index = sa - im->sad;
296       sa->spi = args->remote_spi;
297       sa->tunnel_src_addr.ip4.as_u32 = args->remote_ip.as_u32;
298       sa->tunnel_dst_addr.ip4.as_u32 = args->local_ip.as_u32;
299       sa->is_tunnel = 1;
300       sa->use_esn = args->esn;
301       sa->use_anti_replay = args->anti_replay;
302       sa->integ_alg = args->integ_alg;
303       sa->udp_encap = args->udp_encap;
304       if (args->remote_integ_key_len <= sizeof (args->remote_integ_key))
305         {
306           sa->integ_key_len = args->remote_integ_key_len;
307           clib_memcpy (sa->integ_key, args->remote_integ_key,
308                        args->remote_integ_key_len);
309         }
310       sa->crypto_alg = args->crypto_alg;
311       if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key))
312         {
313           sa->crypto_key_len = args->remote_crypto_key_len;
314           clib_memcpy (sa->crypto_key, args->remote_crypto_key,
315                        args->remote_crypto_key_len);
316         }
317
318       pool_get (im->sad, sa);
319       clib_memset (sa, 0, sizeof (*sa));
320       t->output_sa_index = sa - im->sad;
321       sa->spi = args->local_spi;
322       sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32;
323       sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32;
324       sa->is_tunnel = 1;
325       sa->use_esn = args->esn;
326       sa->use_anti_replay = args->anti_replay;
327       sa->integ_alg = args->integ_alg;
328       sa->udp_encap = args->udp_encap;
329       if (args->local_integ_key_len <= sizeof (args->local_integ_key))
330         {
331           sa->integ_key_len = args->local_integ_key_len;
332           clib_memcpy (sa->integ_key, args->local_integ_key,
333                        args->local_integ_key_len);
334         }
335       sa->crypto_alg = args->crypto_alg;
336       if (args->local_crypto_key_len <= sizeof (args->local_crypto_key))
337         {
338           sa->crypto_key_len = args->local_crypto_key_len;
339           clib_memcpy (sa->crypto_key, args->local_crypto_key,
340                        args->local_crypto_key_len);
341         }
342
343       hash_set (im->ipsec_if_pool_index_by_key, key,
344                 t - im->tunnel_interfaces);
345
346       hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index,
347                                              t - im->tunnel_interfaces,
348                                              ipsec_hw_class.index,
349                                              t - im->tunnel_interfaces);
350
351       hi = vnet_get_hw_interface (vnm, hw_if_index);
352
353       slot = vlib_node_add_next_with_slot
354         (vnm->vlib_main, hi->tx_node_index, im->esp4_encrypt_node_index,
355          IPSEC_OUTPUT_NEXT_ESP4_ENCRYPT);
356
357       ASSERT (slot == IPSEC_OUTPUT_NEXT_ESP4_ENCRYPT);
358
359       t->hw_if_index = hw_if_index;
360
361       vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
362                                    hi->sw_if_index, 1, 0, 0);
363
364       /*1st interface, register protocol */
365       if (pool_elts (im->tunnel_interfaces) == 1)
366         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
367                                ipsec_if_input_node.index);
368
369     }
370   else
371     {
372       /* check if exists */
373       if (!p)
374         return VNET_API_ERROR_INVALID_VALUE;
375
376       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
377       hi = vnet_get_hw_interface (vnm, t->hw_if_index);
378       vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0);    /* admin down */
379
380       vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
381                                    hi->sw_if_index, 0, 0, 0);
382
383       vnet_delete_hw_interface (vnm, t->hw_if_index);
384
385       /* delete input and output SA */
386
387       sa = pool_elt_at_index (im->sad, t->input_sa_index);
388       pool_put (im->sad, sa);
389
390       sa = pool_elt_at_index (im->sad, t->output_sa_index);
391       pool_put (im->sad, sa);
392
393       hash_unset (im->ipsec_if_pool_index_by_key, key);
394       hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance);
395
396       pool_put (im->tunnel_interfaces, t);
397     }
398
399   if (sw_if_index)
400     *sw_if_index = hi->sw_if_index;
401
402   return 0;
403 }
404
405 int
406 ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
407                                 ipsec_add_del_ipsec_gre_tunnel_args_t * args)
408 {
409   ipsec_tunnel_if_t *t = 0;
410   ipsec_main_t *im = &ipsec_main;
411   uword *p;
412   ipsec_sa_t *sa;
413   u64 key;
414   u32 isa, osa;
415
416   p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
417   if (!p)
418     return VNET_API_ERROR_INVALID_VALUE;
419   isa = p[0];
420
421   p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
422   if (!p)
423     return VNET_API_ERROR_INVALID_VALUE;
424   osa = p[0];
425   sa = pool_elt_at_index (im->sad, p[0]);
426
427   if (sa->is_tunnel)
428     key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
429   else
430     key = (u64) args->remote_ip.as_u32 << 32 | (u64) sa->spi;
431
432   p = hash_get (im->ipsec_if_pool_index_by_key, key);
433
434   if (args->is_add)
435     {
436       /* check if same src/dst pair exists */
437       if (p)
438         return VNET_API_ERROR_INVALID_VALUE;
439
440       pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
441       clib_memset (t, 0, sizeof (*t));
442
443       t->input_sa_index = isa;
444       t->output_sa_index = osa;
445       t->hw_if_index = ~0;
446       hash_set (im->ipsec_if_pool_index_by_key, key,
447                 t - im->tunnel_interfaces);
448
449       /*1st interface, register protocol */
450       if (pool_elts (im->tunnel_interfaces) == 1)
451         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
452                                ipsec_if_input_node.index);
453     }
454   else
455     {
456       /* check if exists */
457       if (!p)
458         return VNET_API_ERROR_INVALID_VALUE;
459
460       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
461       hash_unset (im->ipsec_if_pool_index_by_key, key);
462       pool_put (im->tunnel_interfaces, t);
463     }
464   return 0;
465 }
466
467 int
468 ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
469                          ipsec_if_set_key_type_t type, u8 alg, u8 * key)
470 {
471   ipsec_main_t *im = &ipsec_main;
472   vnet_hw_interface_t *hi;
473   ipsec_tunnel_if_t *t;
474   ipsec_sa_t *sa;
475
476   hi = vnet_get_hw_interface (vnm, hw_if_index);
477   t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
478
479   if (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
480     return VNET_API_ERROR_SYSCALL_ERROR_1;
481
482   if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
483     {
484       sa = pool_elt_at_index (im->sad, t->output_sa_index);
485       sa->crypto_alg = alg;
486       sa->crypto_key_len = vec_len (key);
487       clib_memcpy (sa->crypto_key, key, vec_len (key));
488     }
489   else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
490     {
491       sa = pool_elt_at_index (im->sad, t->output_sa_index);
492       sa->integ_alg = alg;
493       sa->integ_key_len = vec_len (key);
494       clib_memcpy (sa->integ_key, key, vec_len (key));
495     }
496   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
497     {
498       sa = pool_elt_at_index (im->sad, t->input_sa_index);
499       sa->crypto_alg = alg;
500       sa->crypto_key_len = vec_len (key);
501       clib_memcpy (sa->crypto_key, key, vec_len (key));
502     }
503   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
504     {
505       sa = pool_elt_at_index (im->sad, t->input_sa_index);
506       sa->integ_alg = alg;
507       sa->integ_key_len = vec_len (key);
508       clib_memcpy (sa->integ_key, key, vec_len (key));
509     }
510   else
511     return VNET_API_ERROR_INVALID_VALUE;
512
513   return 0;
514 }
515
516
517 int
518 ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
519                         u8 is_outbound)
520 {
521   ipsec_main_t *im = &ipsec_main;
522   vnet_hw_interface_t *hi;
523   ipsec_tunnel_if_t *t;
524   ipsec_sa_t *sa, *old_sa;
525   u32 sa_index, old_sa_index;
526   uword *p;
527
528   hi = vnet_get_hw_interface (vnm, hw_if_index);
529   t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
530
531   sa_index = ipsec_get_sa_index_by_sa_id (sa_id);
532   if (sa_index == ~0)
533     {
534       clib_warning ("SA with ID %u not found", sa_id);
535       return VNET_API_ERROR_INVALID_VALUE;
536     }
537
538   if (ipsec_is_sa_used (sa_index))
539     {
540       clib_warning ("SA with ID %u is already in use", sa_id);
541       return VNET_API_ERROR_INVALID_VALUE;
542     }
543
544   sa = pool_elt_at_index (im->sad, sa_index);
545   if (sa->is_tunnel_ip6)
546     {
547       clib_warning ("IPsec interface not supported with IPv6 endpoints");
548       return VNET_API_ERROR_UNIMPLEMENTED;
549     }
550
551   if (!is_outbound)
552     {
553       u64 key;
554
555       old_sa_index = t->input_sa_index;
556       old_sa = pool_elt_at_index (im->sad, old_sa_index);
557
558       /* unset old inbound hash entry. packets should stop arriving */
559       key =
560         (u64) old_sa->tunnel_src_addr.ip4.as_u32 << 32 | (u64) old_sa->spi;
561       p = hash_get (im->ipsec_if_pool_index_by_key, key);
562       if (p)
563         hash_unset (im->ipsec_if_pool_index_by_key, key);
564
565       /* set new inbound SA, then set new hash entry */
566       t->input_sa_index = sa_index;
567       key = (u64) sa->tunnel_src_addr.ip4.as_u32 << 32 | (u64) sa->spi;
568       hash_set (im->ipsec_if_pool_index_by_key, key, hi->dev_instance);
569     }
570   else
571     {
572       old_sa_index = t->output_sa_index;
573       old_sa = pool_elt_at_index (im->sad, old_sa_index);
574       t->output_sa_index = sa_index;
575     }
576
577   /* remove sa_id to sa_index mapping on old SA */
578   if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index)
579     hash_unset (im->sa_index_by_sa_id, old_sa->id);
580
581   if (!ipsec_add_del_sa_sess_cb (im, old_sa_index, 0))
582     {
583       clib_warning ("IPsec backend add/del callback returned error");
584       return VNET_API_ERROR_SYSCALL_ERROR_1;
585     }
586   pool_put (im->sad, old_sa);
587
588   return 0;
589 }
590
591
592 clib_error_t *
593 ipsec_tunnel_if_init (vlib_main_t * vm)
594 {
595   ipsec_main_t *im = &ipsec_main;
596
597   im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
598   im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword));
599
600   return 0;
601 }
602
603 VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
604
605
606 /*
607  * fd.io coding-style-patch-verification: ON
608  *
609  * Local Variables:
610  * eval: (c-set-style "gnu")
611  * End:
612  */