2 * ipsec_if.c : IPSec interface support
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <vnet/vnet.h>
19 #include <vnet/api_errno.h>
20 #include <vnet/ip/ip.h>
22 #include <vnet/ipsec/ipsec.h>
24 #include <vnet/devices/dpdk/ipsec/esp.h>
26 #include <vnet/ipsec/esp.h>
32 add_del_sa_sess (u32 sa_index, u8 is_add)
38 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
41 format_ipsec_name (u8 * s, va_list * args)
43 u32 dev_instance = va_arg (*args, u32);
44 return format (s, "ipsec%d", dev_instance);
48 dummy_interface_tx (vlib_main_t * vm,
49 vlib_node_runtime_t * node, vlib_frame_t * frame)
51 clib_warning ("you shouldn't be here, leaking buffers...");
52 return frame->n_vectors;
56 VNET_DEVICE_CLASS (ipsec_device_class, static) =
59 .format_device_name = format_ipsec_name,
60 .format_tx_trace = format_ipsec_if_output_trace,
61 .tx_function = dummy_interface_tx,
66 VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
69 .build_rewrite = default_build_rewrite,
74 ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
75 ipsec_add_del_tunnel_args_t * args);
78 ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
80 vnet_main_t *vnm = vnet_get_main ();
81 ASSERT (os_get_cpu_number () == 0);
83 return ipsec_add_del_tunnel_if_internal (vnm, a);
87 ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
89 vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback,
90 (u8 *) args, sizeof (*args));
95 ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
96 ipsec_add_del_tunnel_args_t * args)
99 ipsec_main_t *im = &ipsec_main;
100 vnet_hw_interface_t *hi;
101 u32 hw_if_index = ~0;
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);
110 /* check if same src/dst pair exists */
112 return VNET_API_ERROR_INVALID_VALUE;
114 pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
115 memset (t, 0, sizeof (*t));
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;
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))
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);
133 sa->crypto_alg = args->crypto_alg;
134 if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key))
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);
141 add_del_sa_sess (t->input_sa_index, args->is_add);
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;
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))
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);
160 sa->crypto_alg = args->crypto_alg;
161 if (args->local_crypto_key_len <= sizeof (args->local_crypto_key))
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);
168 add_del_sa_sess (t->output_sa_index, args->is_add);
170 hash_set (im->ipsec_if_pool_index_by_key, key,
171 t - im->tunnel_interfaces);
173 if (vec_len (im->free_tunnel_if_indices) > 0)
176 im->free_tunnel_if_indices[vec_len (im->free_tunnel_if_indices) -
178 _vec_len (im->free_tunnel_if_indices) -= 1;
183 vnet_register_interface (vnm, ipsec_device_class.index,
184 t - im->tunnel_interfaces,
185 ipsec_hw_class.index,
186 t - im->tunnel_interfaces);
188 hi = vnet_get_hw_interface (vnm, hw_if_index);
189 hi->output_node_index = ipsec_if_output_node.index;
191 t->hw_if_index = hw_if_index;
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);
202 /* check if exists */
204 return VNET_API_ERROR_INVALID_VALUE;
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);
211 /* delete input and output SA */
212 sa = pool_elt_at_index (im->sad, t->input_sa_index);
214 if (add_del_sa_sess (t->input_sa_index, args->is_add) < 0)
215 return VNET_API_ERROR_SYSCALL_ERROR_1;
217 pool_put (im->sad, sa);
219 sa = pool_elt_at_index (im->sad, t->output_sa_index);
221 if (add_del_sa_sess (t->output_sa_index, args->is_add) < 0)
222 return VNET_API_ERROR_SYSCALL_ERROR_1;
224 pool_put (im->sad, sa);
226 hash_unset (im->ipsec_if_pool_index_by_key, key);
227 pool_put (im->tunnel_interfaces, t);
233 ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
234 ipsec_add_del_ipsec_gre_tunnel_args_t * args)
236 ipsec_tunnel_if_t *t = 0;
237 ipsec_main_t *im = &ipsec_main;
243 p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
245 return VNET_API_ERROR_INVALID_VALUE;
248 p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
250 return VNET_API_ERROR_INVALID_VALUE;
252 sa = pool_elt_at_index (im->sad, p[0]);
255 key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
257 key = (u64) args->remote_ip.as_u32 << 32 | (u64) sa->spi;
259 p = hash_get (im->ipsec_if_pool_index_by_key, key);
263 /* check if same src/dst pair exists */
265 return VNET_API_ERROR_INVALID_VALUE;
267 pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
268 memset (t, 0, sizeof (*t));
270 t->input_sa_index = isa;
271 t->output_sa_index = osa;
273 hash_set (im->ipsec_if_pool_index_by_key, key,
274 t - im->tunnel_interfaces);
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);
283 /* check if exists */
285 return VNET_API_ERROR_INVALID_VALUE;
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);
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)
298 ipsec_main_t *im = &ipsec_main;
299 vnet_hw_interface_t *hi;
300 ipsec_tunnel_if_t *t;
303 hi = vnet_get_hw_interface (vnm, hw_if_index);
304 t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
306 if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
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));
313 if (add_del_sa_sess (t->input_sa_index, 0) < 0)
314 return VNET_API_ERROR_SYSCALL_ERROR_1;
316 else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
318 sa = pool_elt_at_index (im->sad, t->output_sa_index);
320 sa->integ_key_len = vec_len (key);
321 clib_memcpy (sa->integ_key, key, vec_len (key));
323 if (add_del_sa_sess (t->output_sa_index, 0) < 0)
324 return VNET_API_ERROR_SYSCALL_ERROR_1;
326 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
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));
333 if (add_del_sa_sess (t->input_sa_index, 0) < 0)
334 return VNET_API_ERROR_SYSCALL_ERROR_1;
336 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
338 sa = pool_elt_at_index (im->sad, t->input_sa_index);
340 sa->integ_key_len = vec_len (key);
341 clib_memcpy (sa->integ_key, key, vec_len (key));
343 if (add_del_sa_sess (t->output_sa_index, 0) < 0)
344 return VNET_API_ERROR_SYSCALL_ERROR_1;
347 return VNET_API_ERROR_INVALID_VALUE;
354 ipsec_tunnel_if_init (vlib_main_t * vm)
356 ipsec_main_t *im = &ipsec_main;
358 im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
363 VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
367 * fd.io coding-style-patch-verification: ON
370 * eval: (c-set-style "gnu")