Add p2p flag to IPsec tunnel interface hw class
[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   return format (s, "ipsec%d", dev_instance);
32 }
33
34 static uword
35 dummy_interface_tx (vlib_main_t * vm,
36                     vlib_node_runtime_t * node, vlib_frame_t * frame)
37 {
38   clib_warning ("you shouldn't be here, leaking buffers...");
39   return frame->n_vectors;
40 }
41
42 static clib_error_t *
43 ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
44 {
45   ipsec_main_t *im = &ipsec_main;
46   clib_error_t *err = 0;
47   ipsec_tunnel_if_t *t;
48   vnet_hw_interface_t *hi;
49   ipsec_sa_t *sa;
50
51   hi = vnet_get_hw_interface (vnm, hw_if_index);
52   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
53     {
54       t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance);
55       ASSERT (im->cb.check_support_cb);
56       sa = pool_elt_at_index (im->sad, t->input_sa_index);
57       err = im->cb.check_support_cb (sa);
58       if (err)
59         return err;
60
61       sa = pool_elt_at_index (im->sad, t->output_sa_index);
62       err = im->cb.check_support_cb (sa);
63       if (err)
64         return err;
65
66       vnet_hw_interface_set_flags (vnm, hw_if_index,
67                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
68     }
69   else
70     vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
71
72   return /* no error */ 0;
73 }
74
75 /* *INDENT-OFF* */
76 VNET_DEVICE_CLASS (ipsec_device_class, static) =
77 {
78   .name = "IPSec",
79   .format_device_name = format_ipsec_name,
80   .format_tx_trace = format_ipsec_if_output_trace,
81   .tx_function = dummy_interface_tx,
82   .admin_up_down_function = ipsec_admin_up_down_function,
83 };
84 /* *INDENT-ON* */
85
86 /* *INDENT-OFF* */
87 VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
88 {
89   .name = "IPSec",
90   .build_rewrite = default_build_rewrite,
91   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
92 };
93 /* *INDENT-ON* */
94
95 static int
96 ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
97 {
98   vnet_main_t *vnm = vnet_get_main ();
99   ASSERT (vlib_get_thread_index () == 0);
100
101   return ipsec_add_del_tunnel_if_internal (vnm, a, NULL);
102 }
103
104 int
105 ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
106 {
107   vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback,
108                                (u8 *) args, sizeof (*args));
109   return 0;
110 }
111
112 int
113 ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
114                                   ipsec_add_del_tunnel_args_t * args,
115                                   u32 * sw_if_index)
116 {
117   ipsec_tunnel_if_t *t;
118   ipsec_main_t *im = &ipsec_main;
119   vnet_hw_interface_t *hi = NULL;
120   u32 hw_if_index = ~0;
121   uword *p;
122   ipsec_sa_t *sa;
123
124   u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
125   p = hash_get (im->ipsec_if_pool_index_by_key, key);
126
127   if (args->is_add)
128     {
129       /* check if same src/dst pair exists */
130       if (p)
131         return VNET_API_ERROR_INVALID_VALUE;
132
133       pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
134       memset (t, 0, sizeof (*t));
135
136       pool_get (im->sad, sa);
137       memset (sa, 0, sizeof (*sa));
138       t->input_sa_index = sa - im->sad;
139       sa->spi = args->remote_spi;
140       sa->tunnel_src_addr.ip4.as_u32 = args->remote_ip.as_u32;
141       sa->tunnel_dst_addr.ip4.as_u32 = args->local_ip.as_u32;
142       sa->is_tunnel = 1;
143       sa->use_esn = args->esn;
144       sa->use_anti_replay = args->anti_replay;
145       sa->integ_alg = args->integ_alg;
146       if (args->remote_integ_key_len <= sizeof (args->remote_integ_key))
147         {
148           sa->integ_key_len = args->remote_integ_key_len;
149           clib_memcpy (sa->integ_key, args->remote_integ_key,
150                        args->remote_integ_key_len);
151         }
152       sa->crypto_alg = args->crypto_alg;
153       if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key))
154         {
155           sa->crypto_key_len = args->remote_crypto_key_len;
156           clib_memcpy (sa->crypto_key, args->remote_crypto_key,
157                        args->remote_crypto_key_len);
158         }
159
160       if (im->cb.add_del_sa_sess_cb &&
161           im->cb.add_del_sa_sess_cb (t->input_sa_index, args->is_add) < 0)
162         return VNET_API_ERROR_SYSCALL_ERROR_1;
163
164       pool_get (im->sad, sa);
165       memset (sa, 0, sizeof (*sa));
166       t->output_sa_index = sa - im->sad;
167       sa->spi = args->local_spi;
168       sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32;
169       sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32;
170       sa->is_tunnel = 1;
171       sa->seq = 1;
172       sa->use_esn = args->esn;
173       sa->use_anti_replay = args->anti_replay;
174       sa->integ_alg = args->integ_alg;
175       if (args->local_integ_key_len <= sizeof (args->local_integ_key))
176         {
177           sa->integ_key_len = args->local_integ_key_len;
178           clib_memcpy (sa->integ_key, args->local_integ_key,
179                        args->local_integ_key_len);
180         }
181       sa->crypto_alg = args->crypto_alg;
182       if (args->local_crypto_key_len <= sizeof (args->local_crypto_key))
183         {
184           sa->crypto_key_len = args->local_crypto_key_len;
185           clib_memcpy (sa->crypto_key, args->local_crypto_key,
186                        args->local_crypto_key_len);
187         }
188
189       if (im->cb.add_del_sa_sess_cb &&
190           im->cb.add_del_sa_sess_cb (t->output_sa_index, args->is_add) < 0)
191         return VNET_API_ERROR_SYSCALL_ERROR_1;
192
193       hash_set (im->ipsec_if_pool_index_by_key, key,
194                 t - im->tunnel_interfaces);
195
196       if (vec_len (im->free_tunnel_if_indices) > 0)
197         {
198           hw_if_index =
199             im->free_tunnel_if_indices[vec_len (im->free_tunnel_if_indices) -
200                                        1];
201           _vec_len (im->free_tunnel_if_indices) -= 1;
202         }
203       else
204         {
205           hw_if_index =
206             vnet_register_interface (vnm, ipsec_device_class.index,
207                                      t - im->tunnel_interfaces,
208                                      ipsec_hw_class.index,
209                                      t - im->tunnel_interfaces);
210         }
211
212       hi = vnet_get_hw_interface (vnm, hw_if_index);
213       hi->output_node_index = ipsec_if_output_node.index;
214       t->hw_if_index = hw_if_index;
215
216       /*1st interface, register protocol */
217       if (pool_elts (im->tunnel_interfaces) == 1)
218         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
219                                ipsec_if_input_node.index);
220
221     }
222   else
223     {
224       vnet_interface_main_t *vim = &vnm->interface_main;
225
226       /* check if exists */
227       if (!p)
228         return VNET_API_ERROR_INVALID_VALUE;
229
230       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
231       hi = vnet_get_hw_interface (vnm, t->hw_if_index);
232       vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0);    /* admin down */
233       vec_add1 (im->free_tunnel_if_indices, t->hw_if_index);
234
235       vnet_interface_counter_lock (vim);
236       vlib_zero_combined_counter (vim->combined_sw_if_counters +
237                                   VNET_INTERFACE_COUNTER_TX, hi->sw_if_index);
238       vlib_zero_combined_counter (vim->combined_sw_if_counters +
239                                   VNET_INTERFACE_COUNTER_RX, hi->sw_if_index);
240       vnet_interface_counter_unlock (vim);
241
242       /* delete input and output SA */
243       sa = pool_elt_at_index (im->sad, t->input_sa_index);
244
245       if (im->cb.add_del_sa_sess_cb &&
246           im->cb.add_del_sa_sess_cb (t->input_sa_index, args->is_add) < 0)
247         return VNET_API_ERROR_SYSCALL_ERROR_1;
248
249       pool_put (im->sad, sa);
250
251       sa = pool_elt_at_index (im->sad, t->output_sa_index);
252
253       if (im->cb.add_del_sa_sess_cb &&
254           im->cb.add_del_sa_sess_cb (t->output_sa_index, args->is_add) < 0)
255         return VNET_API_ERROR_SYSCALL_ERROR_1;
256
257       pool_put (im->sad, sa);
258
259       hash_unset (im->ipsec_if_pool_index_by_key, key);
260       pool_put (im->tunnel_interfaces, t);
261     }
262
263   if (sw_if_index)
264     *sw_if_index = hi->sw_if_index;
265
266   return 0;
267 }
268
269 int
270 ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
271                                 ipsec_add_del_ipsec_gre_tunnel_args_t * args)
272 {
273   ipsec_tunnel_if_t *t = 0;
274   ipsec_main_t *im = &ipsec_main;
275   uword *p;
276   ipsec_sa_t *sa;
277   u64 key;
278   u32 isa, osa;
279
280   p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
281   if (!p)
282     return VNET_API_ERROR_INVALID_VALUE;
283   isa = p[0];
284
285   p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
286   if (!p)
287     return VNET_API_ERROR_INVALID_VALUE;
288   osa = p[0];
289   sa = pool_elt_at_index (im->sad, p[0]);
290
291   if (sa->is_tunnel)
292     key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
293   else
294     key = (u64) args->remote_ip.as_u32 << 32 | (u64) sa->spi;
295
296   p = hash_get (im->ipsec_if_pool_index_by_key, key);
297
298   if (args->is_add)
299     {
300       /* check if same src/dst pair exists */
301       if (p)
302         return VNET_API_ERROR_INVALID_VALUE;
303
304       pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
305       memset (t, 0, sizeof (*t));
306
307       t->input_sa_index = isa;
308       t->output_sa_index = osa;
309       t->hw_if_index = ~0;
310       hash_set (im->ipsec_if_pool_index_by_key, key,
311                 t - im->tunnel_interfaces);
312
313       /*1st interface, register protocol */
314       if (pool_elts (im->tunnel_interfaces) == 1)
315         ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
316                                ipsec_if_input_node.index);
317     }
318   else
319     {
320       /* check if exists */
321       if (!p)
322         return VNET_API_ERROR_INVALID_VALUE;
323
324       t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
325       hash_unset (im->ipsec_if_pool_index_by_key, key);
326       pool_put (im->tunnel_interfaces, t);
327     }
328   return 0;
329 }
330
331 int
332 ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
333                          ipsec_if_set_key_type_t type, u8 alg, u8 * key)
334 {
335   ipsec_main_t *im = &ipsec_main;
336   vnet_hw_interface_t *hi;
337   ipsec_tunnel_if_t *t;
338   ipsec_sa_t *sa;
339
340   hi = vnet_get_hw_interface (vnm, hw_if_index);
341   t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
342
343   if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
344     {
345       sa = pool_elt_at_index (im->sad, t->output_sa_index);
346       sa->crypto_alg = alg;
347       sa->crypto_key_len = vec_len (key);
348       clib_memcpy (sa->crypto_key, key, vec_len (key));
349
350       if (im->cb.add_del_sa_sess_cb &&
351           im->cb.add_del_sa_sess_cb (t->output_sa_index, 0) < 0)
352         return VNET_API_ERROR_SYSCALL_ERROR_1;
353     }
354   else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
355     {
356       sa = pool_elt_at_index (im->sad, t->output_sa_index);
357       sa->integ_alg = alg;
358       sa->integ_key_len = vec_len (key);
359       clib_memcpy (sa->integ_key, key, vec_len (key));
360
361       if (im->cb.add_del_sa_sess_cb &&
362           im->cb.add_del_sa_sess_cb (t->output_sa_index, 0) < 0)
363         return VNET_API_ERROR_SYSCALL_ERROR_1;
364     }
365   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
366     {
367       sa = pool_elt_at_index (im->sad, t->input_sa_index);
368       sa->crypto_alg = alg;
369       sa->crypto_key_len = vec_len (key);
370       clib_memcpy (sa->crypto_key, key, vec_len (key));
371
372       if (im->cb.add_del_sa_sess_cb &&
373           im->cb.add_del_sa_sess_cb (t->input_sa_index, 0) < 0)
374         return VNET_API_ERROR_SYSCALL_ERROR_1;
375     }
376   else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
377     {
378       sa = pool_elt_at_index (im->sad, t->input_sa_index);
379       sa->integ_alg = alg;
380       sa->integ_key_len = vec_len (key);
381       clib_memcpy (sa->integ_key, key, vec_len (key));
382
383       if (im->cb.add_del_sa_sess_cb &&
384           im->cb.add_del_sa_sess_cb (t->input_sa_index, 0) < 0)
385         return VNET_API_ERROR_SYSCALL_ERROR_1;
386     }
387   else
388     return VNET_API_ERROR_INVALID_VALUE;
389
390   return 0;
391 }
392
393
394 clib_error_t *
395 ipsec_tunnel_if_init (vlib_main_t * vm)
396 {
397   ipsec_main_t *im = &ipsec_main;
398
399   im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
400
401   return 0;
402 }
403
404 VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
405
406
407 /*
408  * fd.io coding-style-patch-verification: ON
409  *
410  * Local Variables:
411  * eval: (c-set-style "gnu")
412  * End:
413  */