b8cba1495844c8499352947e327220838a2687f5
[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       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       clib_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       clib_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       sa->udp_encap = args->udp_encap;
322       if (args->remote_integ_key_len <= sizeof (args->remote_integ_key))
323         {
324           sa->integ_key_len = args->remote_integ_key_len;
325           clib_memcpy (sa->integ_key, args->remote_integ_key,
326                        args->remote_integ_key_len);
327         }
328       sa->crypto_alg = args->crypto_alg;
329       if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key))
330         {
331           sa->crypto_key_len = args->remote_crypto_key_len;
332           clib_memcpy (sa->crypto_key, args->remote_crypto_key,
333                        args->remote_crypto_key_len);
334         }
335
336       pool_get (im->sad, sa);
337       clib_memset (sa, 0, sizeof (*sa));
338       t->output_sa_index = sa - im->sad;
339       sa->spi = args->local_spi;
340       sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32;
341       sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32;
342       sa->is_tunnel = 1;
343       sa->use_esn = args->esn;
344       sa->use_anti_replay = args->anti_replay;
345       sa->integ_alg = args->integ_alg;
346       sa->udp_encap = args->udp_encap;
347       if (args->local_integ_key_len <= sizeof (args->local_integ_key))
348         {
349           sa->integ_key_len = args->local_integ_key_len;
350           clib_memcpy (sa->integ_key, args->local_integ_key,
351                        args->local_integ_key_len);
352         }
353       sa->crypto_alg = args->crypto_alg;
354       if (args->local_crypto_key_len <= sizeof (args->local_crypto_key))
355         {
356           sa->crypto_key_len = args->local_crypto_key_len;
357           clib_memcpy (sa->crypto_key, args->local_crypto_key,
358                        args->local_crypto_key_len);
359         }
360
361       hash_set (im->ipsec_if_pool_index_by_key, key,
362                 t - im->tunnel_interfaces);
363
364       hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index,
365                                              t - im->tunnel_interfaces,
366                                              ipsec_hw_class.index,
367                                              t - im->tunnel_interfaces);
368
369       hi = vnet_get_hw_interface (vnm, hw_if_index);
370
371       slot = vlib_node_add_next_with_slot
372         (vnm->vlib_main, hi->tx_node_index, im->esp4_encrypt_node_index,
373          IPSEC_OUTPUT_NEXT_ESP4_ENCRYPT);
374
375       ASSERT (slot == IPSEC_OUTPUT_NEXT_ESP4_ENCRYPT);
376
377       t->hw_if_index = hw_if_index;
378
379       vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
380                                    hi->sw_if_index, 1, 0, 0);
381
382       /*1st interface, register protocol */
383       if (pool_elts (im->tunnel_interfaces) == 1)
384         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
385                                ipsec_if_input_node.index);
386
387     }
388   else
389     {
390       /* check if exists */
391       if (!p)
392         return VNET_API_ERROR_INVALID_VALUE;
393
394       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
395       hi = vnet_get_hw_interface (vnm, t->hw_if_index);
396       vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0);    /* admin down */
397
398       vnet_feature_enable_disable ("interface-output", "ipsec-if-output",
399                                    hi->sw_if_index, 0, 0, 0);
400
401       vnet_delete_hw_interface (vnm, t->hw_if_index);
402
403       /* delete input and output SA */
404
405       sa = pool_elt_at_index (im->sad, t->input_sa_index);
406       pool_put (im->sad, sa);
407
408       sa = pool_elt_at_index (im->sad, t->output_sa_index);
409       pool_put (im->sad, sa);
410
411       hash_unset (im->ipsec_if_pool_index_by_key, key);
412       hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance);
413
414       pool_put (im->tunnel_interfaces, t);
415     }
416
417   if (sw_if_index)
418     *sw_if_index = hi->sw_if_index;
419
420   return 0;
421 }
422
423 int
424 ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
425                                 ipsec_add_del_ipsec_gre_tunnel_args_t * args)
426 {
427   ipsec_tunnel_if_t *t = 0;
428   ipsec_main_t *im = &ipsec_main;
429   uword *p;
430   ipsec_sa_t *sa;
431   u64 key;
432   u32 isa, osa;
433
434   p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
435   if (!p)
436     return VNET_API_ERROR_INVALID_VALUE;
437   isa = p[0];
438
439   p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
440   if (!p)
441     return VNET_API_ERROR_INVALID_VALUE;
442   osa = p[0];
443   sa = pool_elt_at_index (im->sad, p[0]);
444
445   if (sa->is_tunnel)
446     key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
447   else
448     key = (u64) args->remote_ip.as_u32 << 32 | (u64) sa->spi;
449
450   p = hash_get (im->ipsec_if_pool_index_by_key, key);
451
452   if (args->is_add)
453     {
454       /* check if same src/dst pair exists */
455       if (p)
456         return VNET_API_ERROR_INVALID_VALUE;
457
458       pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
459       clib_memset (t, 0, sizeof (*t));
460
461       t->input_sa_index = isa;
462       t->output_sa_index = osa;
463       t->hw_if_index = ~0;
464       hash_set (im->ipsec_if_pool_index_by_key, key,
465                 t - im->tunnel_interfaces);
466
467       /*1st interface, register protocol */
468       if (pool_elts (im->tunnel_interfaces) == 1)
469         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
470                                ipsec_if_input_node.index);
471     }
472   else
473     {
474       /* check if exists */
475       if (!p)
476         return VNET_API_ERROR_INVALID_VALUE;
477
478       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
479       hash_unset (im->ipsec_if_pool_index_by_key, key);
480       pool_put (im->tunnel_interfaces, t);
481     }
482   return 0;
483 }
484
485 int
486 ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
487                          ipsec_if_set_key_type_t type, u8 alg, u8 * key)
488 {
489   ipsec_main_t *im = &ipsec_main;
490   vnet_hw_interface_t *hi;
491   ipsec_tunnel_if_t *t;
492   ipsec_sa_t *sa;
493
494   hi = vnet_get_hw_interface (vnm, hw_if_index);
495   t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
496
497   if (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
498     return VNET_API_ERROR_SYSCALL_ERROR_1;
499
500   if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
501     {
502       sa = pool_elt_at_index (im->sad, t->output_sa_index);
503       sa->crypto_alg = alg;
504       sa->crypto_key_len = vec_len (key);
505       clib_memcpy (sa->crypto_key, key, vec_len (key));
506     }
507   else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
508     {
509       sa = pool_elt_at_index (im->sad, t->output_sa_index);
510       sa->integ_alg = alg;
511       sa->integ_key_len = vec_len (key);
512       clib_memcpy (sa->integ_key, key, vec_len (key));
513     }
514   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
515     {
516       sa = pool_elt_at_index (im->sad, t->input_sa_index);
517       sa->crypto_alg = alg;
518       sa->crypto_key_len = vec_len (key);
519       clib_memcpy (sa->crypto_key, key, vec_len (key));
520     }
521   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
522     {
523       sa = pool_elt_at_index (im->sad, t->input_sa_index);
524       sa->integ_alg = alg;
525       sa->integ_key_len = vec_len (key);
526       clib_memcpy (sa->integ_key, key, vec_len (key));
527     }
528   else
529     return VNET_API_ERROR_INVALID_VALUE;
530
531   return 0;
532 }
533
534
535 int
536 ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
537                         u8 is_outbound)
538 {
539   ipsec_main_t *im = &ipsec_main;
540   vnet_hw_interface_t *hi;
541   ipsec_tunnel_if_t *t;
542   ipsec_sa_t *sa, *old_sa;
543   u32 sa_index, old_sa_index;
544   uword *p;
545
546   hi = vnet_get_hw_interface (vnm, hw_if_index);
547   t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
548
549   sa_index = ipsec_get_sa_index_by_sa_id (sa_id);
550   if (sa_index == ~0)
551     {
552       clib_warning ("SA with ID %u not found", sa_id);
553       return VNET_API_ERROR_INVALID_VALUE;
554     }
555
556   if (ipsec_is_sa_used (sa_index))
557     {
558       clib_warning ("SA with ID %u is already in use", sa_id);
559       return VNET_API_ERROR_INVALID_VALUE;
560     }
561
562   sa = pool_elt_at_index (im->sad, sa_index);
563   if (sa->is_tunnel_ip6)
564     {
565       clib_warning ("IPsec interface not supported with IPv6 endpoints");
566       return VNET_API_ERROR_UNIMPLEMENTED;
567     }
568
569   if (!is_outbound)
570     {
571       u64 key;
572
573       old_sa_index = t->input_sa_index;
574       old_sa = pool_elt_at_index (im->sad, old_sa_index);
575
576       /* unset old inbound hash entry. packets should stop arriving */
577       key =
578         (u64) old_sa->tunnel_src_addr.ip4.as_u32 << 32 | (u64) old_sa->spi;
579       p = hash_get (im->ipsec_if_pool_index_by_key, key);
580       if (p)
581         hash_unset (im->ipsec_if_pool_index_by_key, key);
582
583       /* set new inbound SA, then set new hash entry */
584       t->input_sa_index = sa_index;
585       key = (u64) sa->tunnel_src_addr.ip4.as_u32 << 32 | (u64) sa->spi;
586       hash_set (im->ipsec_if_pool_index_by_key, key, hi->dev_instance);
587     }
588   else
589     {
590       old_sa_index = t->output_sa_index;
591       old_sa = pool_elt_at_index (im->sad, old_sa_index);
592       t->output_sa_index = sa_index;
593     }
594
595   /* remove sa_id to sa_index mapping on old SA */
596   if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index)
597     hash_unset (im->sa_index_by_sa_id, old_sa->id);
598
599   if (im->cb.add_del_sa_sess_cb)
600     {
601       clib_error_t *err;
602
603       err = im->cb.add_del_sa_sess_cb (old_sa_index, 0);
604       if (err)
605         return VNET_API_ERROR_SYSCALL_ERROR_1;
606     }
607
608   pool_put (im->sad, old_sa);
609
610   return 0;
611 }
612
613
614 clib_error_t *
615 ipsec_tunnel_if_init (vlib_main_t * vm)
616 {
617   ipsec_main_t *im = &ipsec_main;
618
619   im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
620   im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword));
621
622   return 0;
623 }
624
625 VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
626
627
628 /*
629  * fd.io coding-style-patch-verification: ON
630  *
631  * Local Variables:
632  * eval: (c-set-style "gnu")
633  * End:
634  */