ipsec: VPP-1316 calculate IP/TCP/UDP inner checksums
[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 = vlib_get_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_ESP_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       ASSERT (im->cb.check_support_cb);
174
175       sa = pool_elt_at_index (im->sad, t->input_sa_index);
176
177       err = im->cb.check_support_cb (sa);
178       if (err)
179         return err;
180
181       if (im->cb.add_del_sa_sess_cb)
182         {
183           err = im->cb.add_del_sa_sess_cb (t->input_sa_index, 1);
184           if (err)
185             return err;
186         }
187
188       sa = pool_elt_at_index (im->sad, t->output_sa_index);
189
190       err = im->cb.check_support_cb (sa);
191       if (err)
192         return err;
193
194       if (im->cb.add_del_sa_sess_cb)
195         {
196           err = im->cb.add_del_sa_sess_cb (t->output_sa_index, 1);
197           if (err)
198             return err;
199         }
200
201       vnet_hw_interface_set_flags (vnm, hw_if_index,
202                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
203     }
204   else
205     {
206       vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
207
208       sa = pool_elt_at_index (im->sad, t->input_sa_index);
209
210       if (im->cb.add_del_sa_sess_cb)
211         {
212           err = im->cb.add_del_sa_sess_cb (t->input_sa_index, 0);
213           if (err)
214             return err;
215         }
216
217       sa = pool_elt_at_index (im->sad, t->output_sa_index);
218
219       if (im->cb.add_del_sa_sess_cb)
220         {
221           err = im->cb.add_del_sa_sess_cb (t->output_sa_index, 0);
222           if (err)
223             return err;
224         }
225     }
226
227   return /* no error */ 0;
228 }
229
230
231 /* *INDENT-OFF* */
232 VNET_DEVICE_CLASS (ipsec_device_class, static) =
233 {
234   .name = "IPSec",
235   .format_device_name = format_ipsec_name,
236   .format_tx_trace = format_ipsec_if_tx_trace,
237   .tx_function = ipsec_if_tx_node_fn,
238   .tx_function_n_errors = IPSEC_IF_TX_N_ERROR,
239   .tx_function_error_strings = ipsec_if_tx_error_strings,
240   .admin_up_down_function = ipsec_admin_up_down_function,
241 };
242 /* *INDENT-ON* */
243
244 /* *INDENT-OFF* */
245 VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
246 {
247   .name = "IPSec",
248   .build_rewrite = default_build_rewrite,
249   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
250 };
251 /* *INDENT-ON* */
252
253 static int
254 ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
255 {
256   vnet_main_t *vnm = vnet_get_main ();
257   ASSERT (vlib_get_thread_index () == 0);
258
259   return ipsec_add_del_tunnel_if_internal (vnm, a, NULL);
260 }
261
262 int
263 ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
264 {
265   vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback,
266                                (u8 *) args, sizeof (*args));
267   return 0;
268 }
269
270 int
271 ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
272                                   ipsec_add_del_tunnel_args_t * args,
273                                   u32 * sw_if_index)
274 {
275   ipsec_tunnel_if_t *t;
276   ipsec_main_t *im = &ipsec_main;
277   vnet_hw_interface_t *hi = NULL;
278   u32 hw_if_index = ~0;
279   uword *p;
280   ipsec_sa_t *sa;
281   u32 dev_instance;
282   u32 slot;
283
284   u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
285   p = hash_get (im->ipsec_if_pool_index_by_key, key);
286
287   if (args->is_add)
288     {
289       /* check if same src/dst pair exists */
290       if (p)
291         return VNET_API_ERROR_INVALID_VALUE;
292
293       pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
294       memset (t, 0, sizeof (*t));
295
296       dev_instance = t - im->tunnel_interfaces;
297       if (args->renumber)
298         t->show_instance = args->show_instance;
299       else
300         t->show_instance = dev_instance;
301
302       if (hash_get (im->ipsec_if_real_dev_by_show_dev, t->show_instance))
303         {
304           pool_put (im->tunnel_interfaces, t);
305           return VNET_API_ERROR_INSTANCE_IN_USE;
306         }
307
308       hash_set (im->ipsec_if_real_dev_by_show_dev, t->show_instance,
309                 dev_instance);
310
311       pool_get (im->sad, sa);
312       memset (sa, 0, sizeof (*sa));
313       t->input_sa_index = sa - im->sad;
314       sa->spi = args->remote_spi;
315       sa->tunnel_src_addr.ip4.as_u32 = args->remote_ip.as_u32;
316       sa->tunnel_dst_addr.ip4.as_u32 = args->local_ip.as_u32;
317       sa->is_tunnel = 1;
318       sa->use_esn = args->esn;
319       sa->use_anti_replay = args->anti_replay;
320       sa->integ_alg = args->integ_alg;
321       if (args->remote_integ_key_len <= sizeof (args->remote_integ_key))
322         {
323           sa->integ_key_len = args->remote_integ_key_len;
324           clib_memcpy (sa->integ_key, args->remote_integ_key,
325                        args->remote_integ_key_len);
326         }
327       sa->crypto_alg = args->crypto_alg;
328       if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key))
329         {
330           sa->crypto_key_len = args->remote_crypto_key_len;
331           clib_memcpy (sa->crypto_key, args->remote_crypto_key,
332                        args->remote_crypto_key_len);
333         }
334
335       pool_get (im->sad, sa);
336       memset (sa, 0, sizeof (*sa));
337       t->output_sa_index = sa - im->sad;
338       sa->spi = args->local_spi;
339       sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32;
340       sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32;
341       sa->is_tunnel = 1;
342       sa->use_esn = args->esn;
343       sa->use_anti_replay = args->anti_replay;
344       sa->integ_alg = args->integ_alg;
345       if (args->local_integ_key_len <= sizeof (args->local_integ_key))
346         {
347           sa->integ_key_len = args->local_integ_key_len;
348           clib_memcpy (sa->integ_key, args->local_integ_key,
349                        args->local_integ_key_len);
350         }
351       sa->crypto_alg = args->crypto_alg;
352       if (args->local_crypto_key_len <= sizeof (args->local_crypto_key))
353         {
354           sa->crypto_key_len = args->local_crypto_key_len;
355           clib_memcpy (sa->crypto_key, args->local_crypto_key,
356                        args->local_crypto_key_len);
357         }
358
359       hash_set (im->ipsec_if_pool_index_by_key, key,
360                 t - im->tunnel_interfaces);
361
362       hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index,
363                                              t - im->tunnel_interfaces,
364                                              ipsec_hw_class.index,
365                                              t - im->tunnel_interfaces);
366
367       hi = vnet_get_hw_interface (vnm, hw_if_index);
368
369       slot = vlib_node_add_named_next_with_slot
370         (vnm->vlib_main, hi->tx_node_index, "esp-encrypt",
371          IPSEC_OUTPUT_NEXT_ESP_ENCRYPT);
372
373       ASSERT (slot == IPSEC_OUTPUT_NEXT_ESP_ENCRYPT);
374
375       t->hw_if_index = hw_if_index;
376
377       vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
378                                    hi->sw_if_index, 1, 0, 0);
379
380       /*1st interface, register protocol */
381       if (pool_elts (im->tunnel_interfaces) == 1)
382         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
383                                ipsec_if_input_node.index);
384
385     }
386   else
387     {
388       /* check if exists */
389       if (!p)
390         return VNET_API_ERROR_INVALID_VALUE;
391
392       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
393       hi = vnet_get_hw_interface (vnm, t->hw_if_index);
394       vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0);    /* admin down */
395
396       vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
397                                    hi->sw_if_index, 0, 0, 0);
398
399       vnet_delete_hw_interface (vnm, t->hw_if_index);
400
401       /* delete input and output SA */
402
403       sa = pool_elt_at_index (im->sad, t->input_sa_index);
404       pool_put (im->sad, sa);
405
406       sa = pool_elt_at_index (im->sad, t->output_sa_index);
407       pool_put (im->sad, sa);
408
409       hash_unset (im->ipsec_if_pool_index_by_key, key);
410       hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance);
411
412       pool_put (im->tunnel_interfaces, t);
413     }
414
415   if (sw_if_index)
416     *sw_if_index = hi->sw_if_index;
417
418   return 0;
419 }
420
421 int
422 ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
423                                 ipsec_add_del_ipsec_gre_tunnel_args_t * args)
424 {
425   ipsec_tunnel_if_t *t = 0;
426   ipsec_main_t *im = &ipsec_main;
427   uword *p;
428   ipsec_sa_t *sa;
429   u64 key;
430   u32 isa, osa;
431
432   p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
433   if (!p)
434     return VNET_API_ERROR_INVALID_VALUE;
435   isa = p[0];
436
437   p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
438   if (!p)
439     return VNET_API_ERROR_INVALID_VALUE;
440   osa = p[0];
441   sa = pool_elt_at_index (im->sad, p[0]);
442
443   if (sa->is_tunnel)
444     key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
445   else
446     key = (u64) args->remote_ip.as_u32 << 32 | (u64) sa->spi;
447
448   p = hash_get (im->ipsec_if_pool_index_by_key, key);
449
450   if (args->is_add)
451     {
452       /* check if same src/dst pair exists */
453       if (p)
454         return VNET_API_ERROR_INVALID_VALUE;
455
456       pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
457       memset (t, 0, sizeof (*t));
458
459       t->input_sa_index = isa;
460       t->output_sa_index = osa;
461       t->hw_if_index = ~0;
462       hash_set (im->ipsec_if_pool_index_by_key, key,
463                 t - im->tunnel_interfaces);
464
465       /*1st interface, register protocol */
466       if (pool_elts (im->tunnel_interfaces) == 1)
467         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
468                                ipsec_if_input_node.index);
469     }
470   else
471     {
472       /* check if exists */
473       if (!p)
474         return VNET_API_ERROR_INVALID_VALUE;
475
476       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
477       hash_unset (im->ipsec_if_pool_index_by_key, key);
478       pool_put (im->tunnel_interfaces, t);
479     }
480   return 0;
481 }
482
483 int
484 ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
485                          ipsec_if_set_key_type_t type, u8 alg, u8 * key)
486 {
487   ipsec_main_t *im = &ipsec_main;
488   vnet_hw_interface_t *hi;
489   ipsec_tunnel_if_t *t;
490   ipsec_sa_t *sa;
491
492   hi = vnet_get_hw_interface (vnm, hw_if_index);
493   t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
494
495   if (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
496     return VNET_API_ERROR_SYSCALL_ERROR_1;
497
498   if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
499     {
500       sa = pool_elt_at_index (im->sad, t->output_sa_index);
501       sa->crypto_alg = alg;
502       sa->crypto_key_len = vec_len (key);
503       clib_memcpy (sa->crypto_key, key, vec_len (key));
504     }
505   else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
506     {
507       sa = pool_elt_at_index (im->sad, t->output_sa_index);
508       sa->integ_alg = alg;
509       sa->integ_key_len = vec_len (key);
510       clib_memcpy (sa->integ_key, key, vec_len (key));
511     }
512   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
513     {
514       sa = pool_elt_at_index (im->sad, t->input_sa_index);
515       sa->crypto_alg = alg;
516       sa->crypto_key_len = vec_len (key);
517       clib_memcpy (sa->crypto_key, key, vec_len (key));
518     }
519   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
520     {
521       sa = pool_elt_at_index (im->sad, t->input_sa_index);
522       sa->integ_alg = alg;
523       sa->integ_key_len = vec_len (key);
524       clib_memcpy (sa->integ_key, key, vec_len (key));
525     }
526   else
527     return VNET_API_ERROR_INVALID_VALUE;
528
529   return 0;
530 }
531
532
533 int
534 ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
535                         u8 is_outbound)
536 {
537   ipsec_main_t *im = &ipsec_main;
538   vnet_hw_interface_t *hi;
539   ipsec_tunnel_if_t *t;
540   ipsec_sa_t *sa, *old_sa;
541   u32 sa_index, old_sa_index;
542   uword *p;
543
544   hi = vnet_get_hw_interface (vnm, hw_if_index);
545   t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
546
547   sa_index = ipsec_get_sa_index_by_sa_id (sa_id);
548   if (sa_index == ~0)
549     {
550       clib_warning ("SA with ID %u not found", sa_id);
551       return VNET_API_ERROR_INVALID_VALUE;
552     }
553
554   if (ipsec_is_sa_used (sa_index))
555     {
556       clib_warning ("SA with ID %u is already in use", sa_id);
557       return VNET_API_ERROR_INVALID_VALUE;
558     }
559
560   sa = pool_elt_at_index (im->sad, sa_index);
561   if (sa->is_tunnel_ip6)
562     {
563       clib_warning ("IPsec interface not supported with IPv6 endpoints");
564       return VNET_API_ERROR_UNIMPLEMENTED;
565     }
566
567   if (!is_outbound)
568     {
569       u64 key;
570
571       old_sa_index = t->input_sa_index;
572       old_sa = pool_elt_at_index (im->sad, old_sa_index);
573
574       /* unset old inbound hash entry. packets should stop arriving */
575       key =
576         (u64) old_sa->tunnel_src_addr.ip4.as_u32 << 32 | (u64) old_sa->spi;
577       p = hash_get (im->ipsec_if_pool_index_by_key, key);
578       if (p)
579         hash_unset (im->ipsec_if_pool_index_by_key, key);
580
581       /* set new inbound SA, then set new hash entry */
582       t->input_sa_index = sa_index;
583       key = (u64) sa->tunnel_src_addr.ip4.as_u32 << 32 | (u64) sa->spi;
584       hash_set (im->ipsec_if_pool_index_by_key, key, hi->dev_instance);
585     }
586   else
587     {
588       old_sa_index = t->output_sa_index;
589       old_sa = pool_elt_at_index (im->sad, old_sa_index);
590       t->output_sa_index = sa_index;
591     }
592
593   /* remove sa_id to sa_index mapping on old SA */
594   if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index)
595     hash_unset (im->sa_index_by_sa_id, old_sa->id);
596
597   if (im->cb.add_del_sa_sess_cb)
598     {
599       clib_error_t *err;
600
601       err = im->cb.add_del_sa_sess_cb (old_sa_index, 0);
602       if (err)
603         return VNET_API_ERROR_SYSCALL_ERROR_1;
604     }
605
606   pool_put (im->sad, old_sa);
607
608   return 0;
609 }
610
611
612 clib_error_t *
613 ipsec_tunnel_if_init (vlib_main_t * vm)
614 {
615   ipsec_main_t *im = &ipsec_main;
616
617   im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
618   im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword));
619
620   return 0;
621 }
622
623 VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
624
625
626 /*
627  * fd.io coding-style-patch-verification: ON
628  *
629  * Local Variables:
630  * eval: (c-set-style "gnu")
631  * End:
632  */