blob: 5a0d4898ccb720b64084eb1f5f59a649bd745d8b [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#include <vnet/ipsec/esp.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070024
Matthew Smith2838a232016-06-21 16:05:09 -050025void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
26
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070027static u8 *
28format_ipsec_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070029{
30 u32 dev_instance = va_arg (*args, u32);
31 return format (s, "ipsec%d", dev_instance);
32}
33
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070034static uword
35dummy_interface_tx (vlib_main_t * vm,
36 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -070037{
38 clib_warning ("you shouldn't be here, leaking buffers...");
39 return frame->n_vectors;
40}
41
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +000042static clib_error_t *
43ipsec_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);
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +010052 t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance);
53
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +000054 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
55 {
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +000056 ASSERT (im->cb.check_support_cb);
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +010057
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +000058 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +010059
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +000060 err = im->cb.check_support_cb (sa);
61 if (err)
62 return err;
63
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +010064 if (im->cb.add_del_sa_sess_cb)
65 {
66 err = im->cb.add_del_sa_sess_cb (t->input_sa_index, 1);
67 if (err)
68 return err;
69 }
70
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +000071 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +010072
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +000073 err = im->cb.check_support_cb (sa);
74 if (err)
75 return err;
76
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +010077 if (im->cb.add_del_sa_sess_cb)
78 {
79 err = im->cb.add_del_sa_sess_cb (t->output_sa_index, 1);
80 if (err)
81 return err;
82 }
83
Radu Nicolau3f903392017-01-30 14:33:39 +000084 vnet_hw_interface_set_flags (vnm, hw_if_index,
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +000085 VNET_HW_INTERFACE_FLAG_LINK_UP);
86 }
87 else
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +010088 {
89 vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
90
91 sa = pool_elt_at_index (im->sad, t->input_sa_index);
92
93 if (im->cb.add_del_sa_sess_cb)
94 {
95 err = im->cb.add_del_sa_sess_cb (t->input_sa_index, 0);
96 if (err)
97 return err;
98 }
99
100 sa = pool_elt_at_index (im->sad, t->output_sa_index);
101
102 if (im->cb.add_del_sa_sess_cb)
103 {
104 err = im->cb.add_del_sa_sess_cb (t->output_sa_index, 0);
105 if (err)
106 return err;
107 }
108 }
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000109
110 return /* no error */ 0;
111}
112
Neale Rannsb80c5362016-10-08 13:03:40 +0100113/* *INDENT-OFF* */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700114VNET_DEVICE_CLASS (ipsec_device_class, static) =
115{
Neale Rannsb80c5362016-10-08 13:03:40 +0100116 .name = "IPSec",
117 .format_device_name = format_ipsec_name,
118 .format_tx_trace = format_ipsec_if_output_trace,
119 .tx_function = dummy_interface_tx,
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000120 .admin_up_down_function = ipsec_admin_up_down_function,
Neale Rannsb80c5362016-10-08 13:03:40 +0100121};
122/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
Neale Rannsb80c5362016-10-08 13:03:40 +0100124/* *INDENT-OFF* */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700125VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
126{
Neale Rannsb80c5362016-10-08 13:03:40 +0100127 .name = "IPSec",
128 .build_rewrite = default_build_rewrite,
Matthew Smith922549a2017-05-24 16:18:27 -0500129 .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
Neale Rannsb80c5362016-10-08 13:03:40 +0100130};
131/* *INDENT-ON* */
Matthew Smith2838a232016-06-21 16:05:09 -0500132
133static int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700134ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
Matthew Smith2838a232016-06-21 16:05:09 -0500135{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700136 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion586afd72017-04-05 19:18:20 +0200137 ASSERT (vlib_get_thread_index () == 0);
Matthew Smith2838a232016-06-21 16:05:09 -0500138
Matthew Smithe04d09d2017-05-14 21:47:18 -0500139 return ipsec_add_del_tunnel_if_internal (vnm, a, NULL);
Matthew Smith2838a232016-06-21 16:05:09 -0500140}
141
142int
143ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
144{
145 vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700146 (u8 *) args, sizeof (*args));
Matthew Smith2838a232016-06-21 16:05:09 -0500147 return 0;
148}
149
150int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700151ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
Matthew Smithe04d09d2017-05-14 21:47:18 -0500152 ipsec_add_del_tunnel_args_t * args,
153 u32 * sw_if_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700154{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700155 ipsec_tunnel_if_t *t;
156 ipsec_main_t *im = &ipsec_main;
Matthew Smithe04d09d2017-05-14 21:47:18 -0500157 vnet_hw_interface_t *hi = NULL;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158 u32 hw_if_index = ~0;
159 uword *p;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700160 ipsec_sa_t *sa;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700161
162 u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
163 p = hash_get (im->ipsec_if_pool_index_by_key, key);
164
165 if (args->is_add)
166 {
167 /* check if same src/dst pair exists */
168 if (p)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700169 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700170
171 pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
172 memset (t, 0, sizeof (*t));
173
174 pool_get (im->sad, sa);
175 memset (sa, 0, sizeof (*sa));
176 t->input_sa_index = sa - im->sad;
177 sa->spi = args->remote_spi;
178 sa->tunnel_src_addr.ip4.as_u32 = args->remote_ip.as_u32;
179 sa->tunnel_dst_addr.ip4.as_u32 = args->local_ip.as_u32;
180 sa->is_tunnel = 1;
181 sa->use_esn = args->esn;
182 sa->use_anti_replay = args->anti_replay;
Matthew Smith2838a232016-06-21 16:05:09 -0500183 sa->integ_alg = args->integ_alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700184 if (args->remote_integ_key_len <= sizeof (args->remote_integ_key))
185 {
186 sa->integ_key_len = args->remote_integ_key_len;
187 clib_memcpy (sa->integ_key, args->remote_integ_key,
188 args->remote_integ_key_len);
189 }
Matthew Smith2838a232016-06-21 16:05:09 -0500190 sa->crypto_alg = args->crypto_alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700191 if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key))
192 {
193 sa->crypto_key_len = args->remote_crypto_key_len;
194 clib_memcpy (sa->crypto_key, args->remote_crypto_key,
195 args->remote_crypto_key_len);
196 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197
198 pool_get (im->sad, sa);
199 memset (sa, 0, sizeof (*sa));
200 t->output_sa_index = sa - im->sad;
201 sa->spi = args->local_spi;
202 sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32;
203 sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32;
204 sa->is_tunnel = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 sa->use_esn = args->esn;
206 sa->use_anti_replay = args->anti_replay;
Matthew Smith2838a232016-06-21 16:05:09 -0500207 sa->integ_alg = args->integ_alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700208 if (args->local_integ_key_len <= sizeof (args->local_integ_key))
209 {
210 sa->integ_key_len = args->local_integ_key_len;
211 clib_memcpy (sa->integ_key, args->local_integ_key,
212 args->local_integ_key_len);
213 }
Matthew Smith2838a232016-06-21 16:05:09 -0500214 sa->crypto_alg = args->crypto_alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700215 if (args->local_crypto_key_len <= sizeof (args->local_crypto_key))
216 {
217 sa->crypto_key_len = args->local_crypto_key_len;
218 clib_memcpy (sa->crypto_key, args->local_crypto_key,
219 args->local_crypto_key_len);
220 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700222 hash_set (im->ipsec_if_pool_index_by_key, key,
223 t - im->tunnel_interfaces);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224
225 if (vec_len (im->free_tunnel_if_indices) > 0)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700226 {
227 hw_if_index =
228 im->free_tunnel_if_indices[vec_len (im->free_tunnel_if_indices) -
229 1];
230 _vec_len (im->free_tunnel_if_indices) -= 1;
231 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232 else
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700233 {
234 hw_if_index =
235 vnet_register_interface (vnm, ipsec_device_class.index,
236 t - im->tunnel_interfaces,
237 ipsec_hw_class.index,
238 t - im->tunnel_interfaces);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700239 }
Matthew Smithe04d09d2017-05-14 21:47:18 -0500240
241 hi = vnet_get_hw_interface (vnm, hw_if_index);
242 hi->output_node_index = ipsec_if_output_node.index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 t->hw_if_index = hw_if_index;
244
245 /*1st interface, register protocol */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700246 if (pool_elts (im->tunnel_interfaces) == 1)
247 ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
248 ipsec_if_input_node.index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250 }
251 else
252 {
Matthew Smith01034be2017-05-16 11:51:18 -0500253 vnet_interface_main_t *vim = &vnm->interface_main;
254
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255 /* check if exists */
256 if (!p)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700257 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700259 t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260 hi = vnet_get_hw_interface (vnm, t->hw_if_index);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700261 vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700262 vec_add1 (im->free_tunnel_if_indices, t->hw_if_index);
263
Matthew Smith01034be2017-05-16 11:51:18 -0500264 vnet_interface_counter_lock (vim);
265 vlib_zero_combined_counter (vim->combined_sw_if_counters +
266 VNET_INTERFACE_COUNTER_TX, hi->sw_if_index);
267 vlib_zero_combined_counter (vim->combined_sw_if_counters +
268 VNET_INTERFACE_COUNTER_RX, hi->sw_if_index);
269 vnet_interface_counter_unlock (vim);
270
Ed Warnickecb9cada2015-12-08 15:45:58 -0700271 /* delete input and output SA */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700272 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000273
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274 pool_put (im->sad, sa);
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000275
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700276 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +0000277
Ed Warnickecb9cada2015-12-08 15:45:58 -0700278 pool_put (im->sad, sa);
279
280 hash_unset (im->ipsec_if_pool_index_by_key, key);
281 pool_put (im->tunnel_interfaces, t);
282 }
Matthew Smithe04d09d2017-05-14 21:47:18 -0500283
284 if (sw_if_index)
285 *sw_if_index = hi->sw_if_index;
286
Ed Warnickecb9cada2015-12-08 15:45:58 -0700287 return 0;
288}
289
290int
Matus Fabian694265d2016-08-10 01:55:36 -0700291ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
292 ipsec_add_del_ipsec_gre_tunnel_args_t * args)
293{
294 ipsec_tunnel_if_t *t = 0;
295 ipsec_main_t *im = &ipsec_main;
296 uword *p;
297 ipsec_sa_t *sa;
298 u64 key;
299 u32 isa, osa;
300
301 p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
302 if (!p)
303 return VNET_API_ERROR_INVALID_VALUE;
304 isa = p[0];
305
306 p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
307 if (!p)
308 return VNET_API_ERROR_INVALID_VALUE;
309 osa = p[0];
310 sa = pool_elt_at_index (im->sad, p[0]);
311
312 if (sa->is_tunnel)
313 key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
314 else
315 key = (u64) args->remote_ip.as_u32 << 32 | (u64) sa->spi;
316
317 p = hash_get (im->ipsec_if_pool_index_by_key, key);
318
319 if (args->is_add)
320 {
321 /* check if same src/dst pair exists */
322 if (p)
323 return VNET_API_ERROR_INVALID_VALUE;
324
325 pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
326 memset (t, 0, sizeof (*t));
327
328 t->input_sa_index = isa;
329 t->output_sa_index = osa;
330 t->hw_if_index = ~0;
331 hash_set (im->ipsec_if_pool_index_by_key, key,
332 t - im->tunnel_interfaces);
333
334 /*1st interface, register protocol */
335 if (pool_elts (im->tunnel_interfaces) == 1)
336 ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
337 ipsec_if_input_node.index);
338 }
339 else
340 {
341 /* check if exists */
342 if (!p)
343 return VNET_API_ERROR_INVALID_VALUE;
344
345 t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
346 hash_unset (im->ipsec_if_pool_index_by_key, key);
347 pool_put (im->tunnel_interfaces, t);
348 }
349 return 0;
350}
351
352int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700353ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
354 ipsec_if_set_key_type_t type, u8 alg, u8 * key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700355{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700356 ipsec_main_t *im = &ipsec_main;
357 vnet_hw_interface_t *hi;
358 ipsec_tunnel_if_t *t;
359 ipsec_sa_t *sa;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360
361 hi = vnet_get_hw_interface (vnm, hw_if_index);
362 t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
363
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100364 if (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
365 return VNET_API_ERROR_SYSCALL_ERROR_1;
366
Ed Warnickecb9cada2015-12-08 15:45:58 -0700367 if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
368 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700369 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370 sa->crypto_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700371 sa->crypto_key_len = vec_len (key);
372 clib_memcpy (sa->crypto_key, key, vec_len (key));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373 }
374 else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
375 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700376 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700377 sa->integ_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700378 sa->integ_key_len = vec_len (key);
379 clib_memcpy (sa->integ_key, key, vec_len (key));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380 }
381 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
382 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700383 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384 sa->crypto_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700385 sa->crypto_key_len = vec_len (key);
386 clib_memcpy (sa->crypto_key, key, vec_len (key));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387 }
388 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
389 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700390 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391 sa->integ_alg = alg;
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700392 sa->integ_key_len = vec_len (key);
393 clib_memcpy (sa->integ_key, key, vec_len (key));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394 }
395 else
396 return VNET_API_ERROR_INVALID_VALUE;
397
398 return 0;
399}
400
401
Matthew Smithca514fd2017-10-12 12:06:59 -0500402int
403ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
404 u8 is_outbound)
405{
406 ipsec_main_t *im = &ipsec_main;
407 vnet_hw_interface_t *hi;
408 ipsec_tunnel_if_t *t;
409 ipsec_sa_t *sa, *old_sa;
410 u32 sa_index, old_sa_index;
411 uword *p;
412
413 hi = vnet_get_hw_interface (vnm, hw_if_index);
414 t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
415
416 sa_index = ipsec_get_sa_index_by_sa_id (sa_id);
417 if (sa_index == ~0)
418 {
419 clib_warning ("SA with ID %u not found", sa_id);
420 return VNET_API_ERROR_INVALID_VALUE;
421 }
422
423 if (ipsec_is_sa_used (sa_index))
424 {
425 clib_warning ("SA with ID %u is already in use", sa_id);
426 return VNET_API_ERROR_INVALID_VALUE;
427 }
428
429 sa = pool_elt_at_index (im->sad, sa_index);
430 if (sa->is_tunnel_ip6)
431 {
432 clib_warning ("IPsec interface not supported with IPv6 endpoints");
433 return VNET_API_ERROR_UNIMPLEMENTED;
434 }
435
436 if (!is_outbound)
437 {
438 u64 key;
439
440 old_sa_index = t->input_sa_index;
441 old_sa = pool_elt_at_index (im->sad, old_sa_index);
442
443 /* unset old inbound hash entry. packets should stop arriving */
444 key =
445 (u64) old_sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) old_sa->spi;
446 p = hash_get (im->ipsec_if_pool_index_by_key, key);
447 if (p)
448 hash_unset (im->ipsec_if_pool_index_by_key, key);
449
450 /* set new inbound SA, then set new hash entry */
451 t->input_sa_index = sa_index;
452 key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi;
453 hash_set (im->ipsec_if_pool_index_by_key, key, hi->dev_instance);
454 }
455 else
456 {
457 old_sa_index = t->output_sa_index;
458 old_sa = pool_elt_at_index (im->sad, old_sa_index);
459 t->output_sa_index = sa_index;
460 }
461
462 /* remove sa_id to sa_index mapping on old SA */
463 if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index)
464 hash_unset (im->sa_index_by_sa_id, old_sa->id);
465
466 if (im->cb.add_del_sa_sess_cb)
467 {
468 clib_error_t *err;
469
470 err = im->cb.add_del_sa_sess_cb (old_sa_index, 0);
471 if (err)
472 return VNET_API_ERROR_SYSCALL_ERROR_1;
473 }
474
475 pool_put (im->sad, old_sa);
476
477 return 0;
478}
479
480
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481clib_error_t *
482ipsec_tunnel_if_init (vlib_main_t * vm)
483{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700484 ipsec_main_t *im = &ipsec_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485
486 im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
487
488 return 0;
489}
490
491VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
492
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700493
494/*
495 * fd.io coding-style-patch-verification: ON
496 *
497 * Local Variables:
498 * eval: (c-set-style "gnu")
499 * End:
500 */