blob: a8da046f1a85b2bcbed1abef5cea569b50aacd8f [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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>
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +000023#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 */
31static int
32add_del_sa_sess (u32 sa_index, u8 is_add)
33{
34 return 0;
35}
36#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -070037
Matthew Smith2838a232016-06-21 16:05:09 -050038void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
39
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070040static u8 *
41format_ipsec_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070042{
43 u32 dev_instance = va_arg (*args, u32);
44 return format (s, "ipsec%d", dev_instance);
45}
46
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070047static uword
48dummy_interface_tx (vlib_main_t * vm,
49 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070050{
51 clib_warning ("you shouldn't be here, leaking buffers...");
52 return frame->n_vectors;
53}
54
Neale Rannsb80c5362016-10-08 13:03:40 +010055/* *INDENT-OFF* */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070056VNET_DEVICE_CLASS (ipsec_device_class, static) =
57{
Neale Rannsb80c5362016-10-08 13:03:40 +010058 .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* */
Ed Warnickecb9cada2015-12-08 15:45:58 -070064
Neale Rannsb80c5362016-10-08 13:03:40 +010065/* *INDENT-OFF* */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070066VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
67{
Neale Rannsb80c5362016-10-08 13:03:40 +010068 .name = "IPSec",
69 .build_rewrite = default_build_rewrite,
70};
71/* *INDENT-ON* */
Matthew Smith2838a232016-06-21 16:05:09 -050072
73static int
74ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070075 ipsec_add_del_tunnel_args_t * args);
Matthew Smith2838a232016-06-21 16:05:09 -050076
77static int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070078ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
Matthew Smith2838a232016-06-21 16:05:09 -050079{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070080 vnet_main_t *vnm = vnet_get_main ();
81 ASSERT (os_get_cpu_number () == 0);
Matthew Smith2838a232016-06-21 16:05:09 -050082
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070083 return ipsec_add_del_tunnel_if_internal (vnm, a);
Matthew Smith2838a232016-06-21 16:05:09 -050084}
85
86int
87ipsec_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,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070090 (u8 *) args, sizeof (*args));
Matthew Smith2838a232016-06-21 16:05:09 -050091 return 0;
92}
93
94int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070095ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
96 ipsec_add_del_tunnel_args_t * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070097{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070098 ipsec_tunnel_if_t *t;
99 ipsec_main_t *im = &ipsec_main;
100 vnet_hw_interface_t *hi;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101 u32 hw_if_index = ~0;
102 uword *p;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700103 ipsec_sa_t *sa;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104
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)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700112 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113
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;
Matthew Smith2838a232016-06-21 16:05:09 -0500126 sa->integ_alg = args->integ_alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700127 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 }
Matthew Smith2838a232016-06-21 16:05:09 -0500133 sa->crypto_alg = args->crypto_alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700134 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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000141 add_del_sa_sess (t->input_sa_index, args->is_add);
142
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143 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;
Matthew Smith2838a232016-06-21 16:05:09 -0500153 sa->integ_alg = args->integ_alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700154 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 }
Matthew Smith2838a232016-06-21 16:05:09 -0500160 sa->crypto_alg = args->crypto_alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700161 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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000168 add_del_sa_sess (t->output_sa_index, args->is_add);
169
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700170 hash_set (im->ipsec_if_pool_index_by_key, key,
171 t - im->tunnel_interfaces);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700172
173 if (vec_len (im->free_tunnel_if_indices) > 0)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700174 {
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 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700181 {
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);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700188 hi = vnet_get_hw_interface (vnm, hw_if_index);
189 hi->output_node_index = ipsec_if_output_node.index;
190 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191 t->hw_if_index = hw_if_index;
192
193 /*1st interface, register protocol */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700194 if (pool_elts (im->tunnel_interfaces) == 1)
195 ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
196 ipsec_if_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197
198 return hw_if_index;
199 }
200 else
201 {
202 /* check if exists */
203 if (!p)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700204 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700206 t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207 hi = vnet_get_hw_interface (vnm, t->hw_if_index);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700208 vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209 vec_add1 (im->free_tunnel_if_indices, t->hw_if_index);
210
211 /* delete input and output SA */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700212 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000213
214 if (add_del_sa_sess (t->input_sa_index, args->is_add) < 0)
215 return VNET_API_ERROR_SYSCALL_ERROR_1;
216
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217 pool_put (im->sad, sa);
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000218
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700219 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000220
221 if (add_del_sa_sess (t->output_sa_index, args->is_add) < 0)
222 return VNET_API_ERROR_SYSCALL_ERROR_1;
223
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224 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
232int
Matus Fabian694265d2016-08-10 01:55:36 -0700233ipsec_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
294int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700295ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
296 ipsec_if_set_key_type_t type, u8 alg, u8 * key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700298 ipsec_main_t *im = &ipsec_main;
299 vnet_hw_interface_t *hi;
300 ipsec_tunnel_if_t *t;
301 ipsec_sa_t *sa;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302
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 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700308 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309 sa->crypto_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700310 sa->crypto_key_len = vec_len (key);
311 clib_memcpy (sa->crypto_key, key, vec_len (key));
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000312
313 if (add_del_sa_sess (t->input_sa_index, 0) < 0)
314 return VNET_API_ERROR_SYSCALL_ERROR_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315 }
316 else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
317 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700318 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700319 sa->integ_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700320 sa->integ_key_len = vec_len (key);
321 clib_memcpy (sa->integ_key, key, vec_len (key));
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000322
323 if (add_del_sa_sess (t->output_sa_index, 0) < 0)
324 return VNET_API_ERROR_SYSCALL_ERROR_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700325 }
326 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
327 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700328 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700329 sa->crypto_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700330 sa->crypto_key_len = vec_len (key);
331 clib_memcpy (sa->crypto_key, key, vec_len (key));
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000332
333 if (add_del_sa_sess (t->input_sa_index, 0) < 0)
334 return VNET_API_ERROR_SYSCALL_ERROR_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335 }
336 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
337 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700338 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339 sa->integ_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700340 sa->integ_key_len = vec_len (key);
341 clib_memcpy (sa->integ_key, key, vec_len (key));
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000342
343 if (add_del_sa_sess (t->output_sa_index, 0) < 0)
344 return VNET_API_ERROR_SYSCALL_ERROR_1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345 }
346 else
347 return VNET_API_ERROR_INVALID_VALUE;
348
349 return 0;
350}
351
352
353clib_error_t *
354ipsec_tunnel_if_init (vlib_main_t * vm)
355{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700356 ipsec_main_t *im = &ipsec_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357
358 im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
359
360 return 0;
361}
362
363VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
364
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700365
366/*
367 * fd.io coding-style-patch-verification: ON
368 *
369 * Local Variables:
370 * eval: (c-set-style "gnu")
371 * End:
372 */