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