blob: 304c52eac7c10b139fed83292488df1916608f9d [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>
Pierre Pfister4c422f92018-12-10 11:19:08 +010021#include <vnet/fib/fib.h>
Kingwel Xie00bff192019-03-07 01:25:32 -050022#include <vnet/udp/udp.h>
Neale Ranns25edf142019-03-22 08:12:48 +000023#include <vnet/adj/adj_midchain.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070024
25#include <vnet/ipsec/ipsec.h>
Sergio Gonzalez Monroya10f62b2016-11-25 13:36:12 +000026#include <vnet/ipsec/esp.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070027
Matthew Smith2838a232016-06-21 16:05:09 -050028void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
29
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -070030static u8 *
31format_ipsec_name (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -070032{
33 u32 dev_instance = va_arg (*args, u32);
Matthew Smith8e1039a2018-04-12 07:32:56 -050034 ipsec_main_t *im = &ipsec_main;
35 ipsec_tunnel_if_t *t = im->tunnel_interfaces + dev_instance;
36
37 return format (s, "ipsec%d", t->show_instance);
Ed Warnickecb9cada2015-12-08 15:45:58 -070038}
39
Klement Sekera31da2e32018-06-24 22:49:55 +020040/* Statistics (not really errors) */
41#define foreach_ipsec_if_tx_error \
42_(TX, "good packets transmitted")
43
Neale Ranns25edf142019-03-22 08:12:48 +000044static void
45ipsec_if_tunnel_stack (adj_index_t ai)
Klement Sekeraa98346f2018-05-16 10:52:45 +020046{
Neale Ranns25edf142019-03-22 08:12:48 +000047 ipsec_main_t *ipm = &ipsec_main;
48 ipsec_tunnel_if_t *it;
49 ip_adjacency_t *adj;
50 u32 sw_if_index;
Klement Sekera31da2e32018-06-24 22:49:55 +020051
Neale Ranns25edf142019-03-22 08:12:48 +000052 adj = adj_get (ai);
53 sw_if_index = adj->rewrite_header.sw_if_index;
54
55 if ((vec_len (ipm->ipsec_if_by_sw_if_index) <= sw_if_index) ||
56 (~0 == ipm->ipsec_if_by_sw_if_index[sw_if_index]))
57 return;
58
59 it = pool_elt_at_index (ipm->tunnel_interfaces,
60 ipm->ipsec_if_by_sw_if_index[sw_if_index]);
61
62 if (!vnet_hw_interface_is_link_up (vnet_get_main (), it->hw_if_index))
63 {
64 adj_midchain_delegate_unstack (ai);
65 }
66 else
67 {
68 ipsec_sa_t *sa;
69
70 sa = ipsec_sa_get (it->output_sa_index);
71
72 fib_prefix_t pfx = {
73 .fp_addr = sa->tunnel_dst_addr,
74 .fp_len = (sa->is_tunnel_ip6 ? 128 : 32),
75 .fp_proto = (sa->is_tunnel_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4),
76 };
77
78 adj_midchain_delegate_stack (ai, sa->tx_fib_index, &pfx);
79 }
80}
81
82/**
83 * @brief Call back when restacking all adjacencies on a GRE interface
84 */
85static adj_walk_rc_t
86ipsec_if_adj_walk_cb (adj_index_t ai, void *ctx)
Klement Sekera31da2e32018-06-24 22:49:55 +020087{
Neale Ranns25edf142019-03-22 08:12:48 +000088 ipsec_if_tunnel_stack (ai);
Klement Sekera31da2e32018-06-24 22:49:55 +020089
Neale Ranns25edf142019-03-22 08:12:48 +000090 return (ADJ_WALK_RC_CONTINUE);
Klement Sekeraa98346f2018-05-16 10:52:45 +020091}
92
Neale Ranns77eb28f2019-03-04 14:13:14 +000093static void
Neale Ranns25edf142019-03-22 08:12:48 +000094ipsec_if_tunnel_restack (ipsec_tunnel_if_t * it)
Neale Rannsfe480f62019-02-28 12:03:58 +000095{
Neale Ranns25edf142019-03-22 08:12:48 +000096 fib_protocol_t proto;
Neale Rannsfe480f62019-02-28 12:03:58 +000097
Neale Ranns25edf142019-03-22 08:12:48 +000098 /*
99 * walk all the adjacencies on th GRE interface and restack them
100 */
101 FOR_EACH_FIB_IP_PROTOCOL (proto)
102 {
103 adj_nbr_walk (it->sw_if_index, proto, ipsec_if_adj_walk_cb, NULL);
104 }
Neale Rannsfe480f62019-02-28 12:03:58 +0000105}
106
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000107static clib_error_t *
108ipsec_admin_up_down_function (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
109{
110 ipsec_main_t *im = &ipsec_main;
111 clib_error_t *err = 0;
112 ipsec_tunnel_if_t *t;
113 vnet_hw_interface_t *hi;
114 ipsec_sa_t *sa;
115
116 hi = vnet_get_hw_interface (vnm, hw_if_index);
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100117 t = pool_elt_at_index (im->tunnel_interfaces, hi->hw_instance);
Neale Rannsfe480f62019-02-28 12:03:58 +0000118 t->flags = flags;
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100119
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000120 if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
121 {
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000122 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100123
Klement Sekerab4d30532018-11-08 13:00:02 +0100124 err = ipsec_check_support_cb (im, sa);
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000125 if (err)
126 return err;
127
Klement Sekerab4d30532018-11-08 13:00:02 +0100128 err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 1);
129 if (err)
130 return err;
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100131
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000132 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100133
Klement Sekerab4d30532018-11-08 13:00:02 +0100134 err = ipsec_check_support_cb (im, sa);
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000135 if (err)
136 return err;
137
Klement Sekerab4d30532018-11-08 13:00:02 +0100138 err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 1);
139 if (err)
140 return err;
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100141
Radu Nicolau3f903392017-01-30 14:33:39 +0000142 vnet_hw_interface_set_flags (vnm, hw_if_index,
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000143 VNET_HW_INTERFACE_FLAG_LINK_UP);
144 }
145 else
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100146 {
147 vnet_hw_interface_set_flags (vnm, hw_if_index, 0 /* down */ );
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100148 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Klement Sekerab4d30532018-11-08 13:00:02 +0100149 err = ipsec_add_del_sa_sess_cb (im, t->input_sa_index, 0);
150 if (err)
151 return err;
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100152 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Klement Sekerab4d30532018-11-08 13:00:02 +0100153 err = ipsec_add_del_sa_sess_cb (im, t->output_sa_index, 0);
154 if (err)
155 return err;
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100156 }
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000157
Neale Ranns25edf142019-03-22 08:12:48 +0000158 ipsec_if_tunnel_restack (t);
159
160 return (NULL);
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000161}
162
Neale Ranns25edf142019-03-22 08:12:48 +0000163static u8 *
164ipsec_if_build_rewrite (vnet_main_t * vnm,
165 u32 sw_if_index,
166 vnet_link_t link_type, const void *dst_address)
167{
168 return (NULL);
169}
170
171static void
172ipsec_if_update_adj (vnet_main_t * vnm, u32 sw_if_index, adj_index_t ai)
173{
174 adj_nbr_midchain_update_rewrite
175 (ai, NULL, NULL, ADJ_FLAG_MIDCHAIN_IP_STACK,
176 ipsec_if_build_rewrite (vnm, sw_if_index, adj_get_link_type (ai), NULL));
177
178 ipsec_if_tunnel_stack (ai);
179}
Klement Sekera31da2e32018-06-24 22:49:55 +0200180
Neale Rannsb80c5362016-10-08 13:03:40 +0100181/* *INDENT-OFF* */
Neale Ranns77eb28f2019-03-04 14:13:14 +0000182VNET_DEVICE_CLASS (ipsec_device_class) =
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700183{
Neale Rannsb80c5362016-10-08 13:03:40 +0100184 .name = "IPSec",
185 .format_device_name = format_ipsec_name,
Sergio Gonzalez Monroyd04b60b2017-01-20 15:35:23 +0000186 .admin_up_down_function = ipsec_admin_up_down_function,
Neale Rannsb80c5362016-10-08 13:03:40 +0100187};
188/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189
Neale Rannsb80c5362016-10-08 13:03:40 +0100190/* *INDENT-OFF* */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700191VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
192{
Neale Rannsb80c5362016-10-08 13:03:40 +0100193 .name = "IPSec",
194 .build_rewrite = default_build_rewrite,
Neale Ranns25edf142019-03-22 08:12:48 +0000195 .update_adjacency = ipsec_if_update_adj,
Matthew Smith922549a2017-05-24 16:18:27 -0500196 .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
Neale Rannsb80c5362016-10-08 13:03:40 +0100197};
198/* *INDENT-ON* */
Matthew Smith2838a232016-06-21 16:05:09 -0500199
200static int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700201ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t * a)
Matthew Smith2838a232016-06-21 16:05:09 -0500202{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700203 vnet_main_t *vnm = vnet_get_main ();
Damjan Marion586afd72017-04-05 19:18:20 +0200204 ASSERT (vlib_get_thread_index () == 0);
Matthew Smith2838a232016-06-21 16:05:09 -0500205
Matthew Smithe04d09d2017-05-14 21:47:18 -0500206 return ipsec_add_del_tunnel_if_internal (vnm, a, NULL);
Matthew Smith2838a232016-06-21 16:05:09 -0500207}
208
209int
210ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
211{
212 vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback,
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700213 (u8 *) args, sizeof (*args));
Matthew Smith2838a232016-06-21 16:05:09 -0500214 return 0;
215}
216
Neale Ranns8d7c5022019-02-06 01:41:05 -0800217static u32
218ipsec_tun_mk_input_sa_id (u32 ti)
219{
220 return (0x80000000 | ti);
221}
222
223static u32
224ipsec_tun_mk_output_sa_id (u32 ti)
225{
226 return (0xc0000000 | ti);
227}
228
Matthew Smith2838a232016-06-21 16:05:09 -0500229int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700230ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
Matthew Smithe04d09d2017-05-14 21:47:18 -0500231 ipsec_add_del_tunnel_args_t * args,
232 u32 * sw_if_index)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700234 ipsec_tunnel_if_t *t;
235 ipsec_main_t *im = &ipsec_main;
Matthew Smithe04d09d2017-05-14 21:47:18 -0500236 vnet_hw_interface_t *hi = NULL;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 u32 hw_if_index = ~0;
238 uword *p;
Matthew Smith8e1039a2018-04-12 07:32:56 -0500239 u32 dev_instance;
Neale Ranns8d7c5022019-02-06 01:41:05 -0800240 ipsec_key_t crypto_key, integ_key;
241 ipsec_sa_flags_t flags;
242 int rv;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400243 int is_ip6 = args->is_ip6;
244 ipsec4_tunnel_key_t key4;
245 ipsec6_tunnel_key_t key6;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400247 if (!is_ip6)
248 {
249 key4.remote_ip = args->remote_ip.ip4.as_u32;
250 key4.spi = clib_host_to_net_u32 (args->remote_spi);
251 p = hash_get (im->ipsec4_if_pool_index_by_key, key4.as_u64);
252 }
253 else
254 {
255 key6.remote_ip = args->remote_ip.ip6;
256 key6.spi = clib_host_to_net_u32 (args->remote_spi);
257 p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key6);
258 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259
260 if (args->is_add)
261 {
262 /* check if same src/dst pair exists */
263 if (p)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700264 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265
Neale Rannsfe480f62019-02-28 12:03:58 +0000266 pool_get_aligned_zero (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
Matthew Smith8e1039a2018-04-12 07:32:56 -0500268 dev_instance = t - im->tunnel_interfaces;
269 if (args->renumber)
270 t->show_instance = args->show_instance;
271 else
272 t->show_instance = dev_instance;
273
274 if (hash_get (im->ipsec_if_real_dev_by_show_dev, t->show_instance))
275 {
276 pool_put (im->tunnel_interfaces, t);
277 return VNET_API_ERROR_INSTANCE_IN_USE;
278 }
279
280 hash_set (im->ipsec_if_real_dev_by_show_dev, t->show_instance,
281 dev_instance);
282
Neale Ranns8d7c5022019-02-06 01:41:05 -0800283 flags = IPSEC_SA_FLAG_IS_TUNNEL;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400284 if (args->is_ip6)
285 flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6;
Neale Ranns8d7c5022019-02-06 01:41:05 -0800286 if (args->udp_encap)
287 flags |= IPSEC_SA_FLAG_UDP_ENCAP;
288 if (args->esn)
289 flags |= IPSEC_SA_FLAG_USE_EXTENDED_SEQ_NUM;
290 if (args->anti_replay)
291 flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292
Neale Ranns8d7c5022019-02-06 01:41:05 -0800293 ipsec_mk_key (&crypto_key,
294 args->remote_crypto_key, args->remote_crypto_key_len);
295 ipsec_mk_key (&integ_key,
296 args->remote_integ_key, args->remote_integ_key_len);
297
298 rv = ipsec_sa_add (ipsec_tun_mk_input_sa_id (dev_instance),
299 args->remote_spi,
300 IPSEC_PROTOCOL_ESP,
301 args->crypto_alg,
302 &crypto_key,
303 args->integ_alg,
304 &integ_key,
305 flags,
306 args->tx_table_id,
307 &args->remote_ip,
308 &args->local_ip, &t->input_sa_index);
309
310 if (rv)
Neale Rannsaf3f0782019-03-26 08:21:25 +0000311 return VNET_API_ERROR_INVALID_SRC_ADDRESS;
Neale Ranns8d7c5022019-02-06 01:41:05 -0800312
313 ipsec_mk_key (&crypto_key,
314 args->local_crypto_key, args->local_crypto_key_len);
315 ipsec_mk_key (&integ_key,
316 args->local_integ_key, args->local_integ_key_len);
317
318 rv = ipsec_sa_add (ipsec_tun_mk_output_sa_id (dev_instance),
319 args->local_spi,
320 IPSEC_PROTOCOL_ESP,
321 args->crypto_alg,
322 &crypto_key,
323 args->integ_alg,
324 &integ_key,
325 flags,
326 args->tx_table_id,
327 &args->local_ip,
328 &args->remote_ip, &t->output_sa_index);
329
330 if (rv)
Neale Rannsaf3f0782019-03-26 08:21:25 +0000331 return VNET_API_ERROR_INVALID_DST_ADDRESS;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400333 /* copy the key */
334 if (is_ip6)
335 hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key6,
336 t - im->tunnel_interfaces);
337 else
338 hash_set (im->ipsec4_if_pool_index_by_key, key4.as_u64,
339 t - im->tunnel_interfaces);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700340
Matthew Smith8e1039a2018-04-12 07:32:56 -0500341 hw_if_index = vnet_register_interface (vnm, ipsec_device_class.index,
342 t - im->tunnel_interfaces,
343 ipsec_hw_class.index,
344 t - im->tunnel_interfaces);
Matthew Smithe04d09d2017-05-14 21:47:18 -0500345
346 hi = vnet_get_hw_interface (vnm, hw_if_index);
Klement Sekera31da2e32018-06-24 22:49:55 +0200347
Ed Warnickecb9cada2015-12-08 15:45:58 -0700348 t->hw_if_index = hw_if_index;
Neale Rannsfe480f62019-02-28 12:03:58 +0000349 t->sw_if_index = hi->sw_if_index;
350
Neale Ranns25edf142019-03-22 08:12:48 +0000351 /* Add the new tunnel to the DB of tunnels per sw_if_index ... */
352 vec_validate_init_empty (im->ipsec_if_by_sw_if_index, t->sw_if_index,
353 ~0);
354 im->ipsec_if_by_sw_if_index[t->sw_if_index] = dev_instance;
355
356 vnet_feature_enable_disable ("ip4-output",
357 "esp4-encrypt-tun",
358 t->sw_if_index, 1,
359 &t->output_sa_index,
360 sizeof (t->output_sa_index));
361 vnet_feature_enable_disable ("ip6-output",
362 "esp6-encrypt-tun",
363 t->sw_if_index, 1,
364 &t->output_sa_index,
365 sizeof (t->output_sa_index));
366
Ed Warnickecb9cada2015-12-08 15:45:58 -0700367 /*1st interface, register protocol */
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700368 if (pool_elts (im->tunnel_interfaces) == 1)
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400369 {
370 ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
371 ipsec4_if_input_node.index);
372 ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
373 ipsec6_if_input_node.index);
374 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700375
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376 }
377 else
378 {
Neale Rannsc80cc9a2019-03-20 14:10:23 +0000379 u32 ti;
380
Ed Warnickecb9cada2015-12-08 15:45:58 -0700381 /* check if exists */
382 if (!p)
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700383 return VNET_API_ERROR_INVALID_VALUE;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384
Neale Rannsc80cc9a2019-03-20 14:10:23 +0000385 ti = p[0];
386 t = pool_elt_at_index (im->tunnel_interfaces, ti);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387 hi = vnet_get_hw_interface (vnm, t->hw_if_index);
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700388 vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */
Matthew Smith537eeec2018-04-09 11:49:20 -0500389
Neale Ranns25edf142019-03-22 08:12:48 +0000390 vnet_feature_enable_disable ("ip4-output",
391 "esp4-encrypt-tun",
392 hi->sw_if_index, 0,
393 &t->output_sa_index,
394 sizeof (t->output_sa_index));
395 vnet_feature_enable_disable ("ip6-output",
396 "esp6-encrypt-tun",
397 hi->sw_if_index, 0,
398 &t->output_sa_index,
399 sizeof (t->output_sa_index));
Matthew Smith8e1039a2018-04-12 07:32:56 -0500400 vnet_delete_hw_interface (vnm, t->hw_if_index);
Matthew Smith01034be2017-05-16 11:51:18 -0500401
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400402 if (is_ip6)
403 hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key6);
404 else
405 hash_unset (im->ipsec4_if_pool_index_by_key, key4.as_u64);
406
Matthew Smith8e1039a2018-04-12 07:32:56 -0500407 hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance);
Neale Ranns25edf142019-03-22 08:12:48 +0000408 im->ipsec_if_by_sw_if_index[t->sw_if_index] = ~0;
Matthew Smith8e1039a2018-04-12 07:32:56 -0500409
Ed Warnickecb9cada2015-12-08 15:45:58 -0700410 pool_put (im->tunnel_interfaces, t);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800411
412 /* delete input and output SA */
Neale Rannsc80cc9a2019-03-20 14:10:23 +0000413 ipsec_sa_del (ipsec_tun_mk_input_sa_id (ti));
414 ipsec_sa_del (ipsec_tun_mk_output_sa_id (ti));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415 }
Matthew Smithe04d09d2017-05-14 21:47:18 -0500416
417 if (sw_if_index)
418 *sw_if_index = hi->sw_if_index;
419
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 return 0;
421}
422
423int
Matus Fabian694265d2016-08-10 01:55:36 -0700424ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm,
425 ipsec_add_del_ipsec_gre_tunnel_args_t * args)
426{
427 ipsec_tunnel_if_t *t = 0;
428 ipsec_main_t *im = &ipsec_main;
429 uword *p;
430 ipsec_sa_t *sa;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400431 ipsec4_tunnel_key_t key;
Matus Fabian694265d2016-08-10 01:55:36 -0700432 u32 isa, osa;
433
434 p = hash_get (im->sa_index_by_sa_id, args->local_sa_id);
435 if (!p)
436 return VNET_API_ERROR_INVALID_VALUE;
437 isa = p[0];
438
439 p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id);
440 if (!p)
441 return VNET_API_ERROR_INVALID_VALUE;
442 osa = p[0];
443 sa = pool_elt_at_index (im->sad, p[0]);
444
Damjan Mariond709cbc2019-03-26 13:16:42 +0100445 if (ipsec_sa_is_set_IS_TUNNEL (sa))
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400446 {
447 key.remote_ip = sa->tunnel_dst_addr.ip4.as_u32;
448 key.spi = clib_host_to_net_u32 (sa->spi);
449 }
Matus Fabian694265d2016-08-10 01:55:36 -0700450 else
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400451 {
452 key.remote_ip = args->remote_ip.as_u32;
453 key.spi = clib_host_to_net_u32 (sa->spi);
454 }
Matus Fabian694265d2016-08-10 01:55:36 -0700455
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400456 p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64);
Matus Fabian694265d2016-08-10 01:55:36 -0700457
458 if (args->is_add)
459 {
460 /* check if same src/dst pair exists */
461 if (p)
462 return VNET_API_ERROR_INVALID_VALUE;
463
464 pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
Dave Barachb7b92992018-10-17 10:38:51 -0400465 clib_memset (t, 0, sizeof (*t));
Matus Fabian694265d2016-08-10 01:55:36 -0700466
467 t->input_sa_index = isa;
468 t->output_sa_index = osa;
469 t->hw_if_index = ~0;
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400470 hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64,
Matus Fabian694265d2016-08-10 01:55:36 -0700471 t - im->tunnel_interfaces);
472
473 /*1st interface, register protocol */
474 if (pool_elts (im->tunnel_interfaces) == 1)
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400475 {
476 ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP,
477 ipsec4_if_input_node.index);
478 /* TBD, GRE IPSec6
479 *
480 ip6_register_protocol (IP_PROTOCOL_IPSEC_ESP,
481 ipsec6_if_input_node.index);
482 */
483 }
Matus Fabian694265d2016-08-10 01:55:36 -0700484 }
485 else
486 {
487 /* check if exists */
488 if (!p)
489 return VNET_API_ERROR_INVALID_VALUE;
490
491 t = pool_elt_at_index (im->tunnel_interfaces, p[0]);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400492 hash_unset (im->ipsec4_if_pool_index_by_key, key.as_u64);
Matus Fabian694265d2016-08-10 01:55:36 -0700493 pool_put (im->tunnel_interfaces, t);
494 }
495 return 0;
496}
497
498int
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700499ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index,
500 ipsec_if_set_key_type_t type, u8 alg, u8 * key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700502 ipsec_main_t *im = &ipsec_main;
503 vnet_hw_interface_t *hi;
504 ipsec_tunnel_if_t *t;
505 ipsec_sa_t *sa;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506
507 hi = vnet_get_hw_interface (vnm, hw_if_index);
508 t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
509
Sergio Gonzalez Monroydb93cd92017-08-26 15:22:05 +0100510 if (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
511 return VNET_API_ERROR_SYSCALL_ERROR_1;
512
Ed Warnickecb9cada2015-12-08 15:45:58 -0700513 if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
514 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700515 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Damjan Marionb966e8b2019-03-20 16:07:09 +0100516 ipsec_sa_set_crypto_alg (sa, alg);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800517 ipsec_mk_key (&sa->crypto_key, key, vec_len (key));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518 }
519 else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
520 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700521 sa = pool_elt_at_index (im->sad, t->output_sa_index);
Damjan Marionb966e8b2019-03-20 16:07:09 +0100522 ipsec_sa_set_integ_alg (sa, alg);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800523 ipsec_mk_key (&sa->integ_key, key, vec_len (key));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524 }
525 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
526 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700527 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Damjan Marionb966e8b2019-03-20 16:07:09 +0100528 ipsec_sa_set_crypto_alg (sa, alg);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800529 ipsec_mk_key (&sa->crypto_key, key, vec_len (key));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530 }
531 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
532 {
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700533 sa = pool_elt_at_index (im->sad, t->input_sa_index);
Damjan Marionb966e8b2019-03-20 16:07:09 +0100534 ipsec_sa_set_integ_alg (sa, alg);
Neale Ranns8d7c5022019-02-06 01:41:05 -0800535 ipsec_mk_key (&sa->integ_key, key, vec_len (key));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536 }
537 else
538 return VNET_API_ERROR_INVALID_VALUE;
539
540 return 0;
541}
542
543
Matthew Smithca514fd2017-10-12 12:06:59 -0500544int
545ipsec_set_interface_sa (vnet_main_t * vnm, u32 hw_if_index, u32 sa_id,
546 u8 is_outbound)
547{
548 ipsec_main_t *im = &ipsec_main;
549 vnet_hw_interface_t *hi;
550 ipsec_tunnel_if_t *t;
551 ipsec_sa_t *sa, *old_sa;
552 u32 sa_index, old_sa_index;
553 uword *p;
554
555 hi = vnet_get_hw_interface (vnm, hw_if_index);
556 t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
557
558 sa_index = ipsec_get_sa_index_by_sa_id (sa_id);
559 if (sa_index == ~0)
560 {
561 clib_warning ("SA with ID %u not found", sa_id);
562 return VNET_API_ERROR_INVALID_VALUE;
563 }
564
565 if (ipsec_is_sa_used (sa_index))
566 {
567 clib_warning ("SA with ID %u is already in use", sa_id);
568 return VNET_API_ERROR_INVALID_VALUE;
569 }
570
571 sa = pool_elt_at_index (im->sad, sa_index);
Matthew Smithca514fd2017-10-12 12:06:59 -0500572
573 if (!is_outbound)
574 {
Matthew Smithca514fd2017-10-12 12:06:59 -0500575 old_sa_index = t->input_sa_index;
576 old_sa = pool_elt_at_index (im->sad, old_sa_index);
577
Damjan Mariond709cbc2019-03-26 13:16:42 +0100578 if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ^
579 ipsec_sa_is_set_IS_TUNNEL_V6 (old_sa))
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400580 {
581 clib_warning ("IPsec interface SA endpoints type can't be changed");
582 return VNET_API_ERROR_INVALID_VALUE;
583 }
Matthew Smithca514fd2017-10-12 12:06:59 -0500584
Damjan Mariond709cbc2019-03-26 13:16:42 +0100585 if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa))
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400586 {
587 ipsec6_tunnel_key_t key;
588
589 /* unset old inbound hash entry. packets should stop arriving */
590 key.remote_ip = old_sa->tunnel_src_addr.ip6;
591 key.spi = clib_host_to_net_u32 (old_sa->spi);
592
593 p = hash_get_mem (im->ipsec6_if_pool_index_by_key, &key);
594 if (p)
595 hash_unset_mem_free (&im->ipsec6_if_pool_index_by_key, &key);
596
597 /* set new inbound SA, then set new hash entry */
598 t->input_sa_index = sa_index;
599 key.remote_ip = sa->tunnel_src_addr.ip6;
600 key.spi = clib_host_to_net_u32 (sa->spi);
601
602 hash_set_mem_alloc (&im->ipsec6_if_pool_index_by_key, &key,
603 hi->dev_instance);
604 }
605 else
606 {
607 ipsec4_tunnel_key_t key;
608
609 /* unset old inbound hash entry. packets should stop arriving */
610 key.remote_ip = old_sa->tunnel_src_addr.ip4.as_u32;
611 key.spi = clib_host_to_net_u32 (old_sa->spi);
612
613 p = hash_get (im->ipsec4_if_pool_index_by_key, key.as_u64);
614 if (p)
615 hash_unset (im->ipsec4_if_pool_index_by_key, key.as_u64);
616
617 /* set new inbound SA, then set new hash entry */
618 t->input_sa_index = sa_index;
619 key.remote_ip = sa->tunnel_src_addr.ip4.as_u32;
620 key.spi = clib_host_to_net_u32 (sa->spi);
621
622 hash_set (im->ipsec4_if_pool_index_by_key, key.as_u64,
623 hi->dev_instance);
624 }
Matthew Smithca514fd2017-10-12 12:06:59 -0500625 }
626 else
627 {
628 old_sa_index = t->output_sa_index;
629 old_sa = pool_elt_at_index (im->sad, old_sa_index);
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400630
Damjan Mariond709cbc2019-03-26 13:16:42 +0100631 if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa) ^
632 ipsec_sa_is_set_IS_TUNNEL_V6 (old_sa))
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400633 {
634 clib_warning ("IPsec interface SA endpoints type can't be changed");
635 return VNET_API_ERROR_INVALID_VALUE;
636 }
637
Matthew Smithca514fd2017-10-12 12:06:59 -0500638 t->output_sa_index = sa_index;
639 }
640
641 /* remove sa_id to sa_index mapping on old SA */
642 if (ipsec_get_sa_index_by_sa_id (old_sa->id) == old_sa_index)
643 hash_unset (im->sa_index_by_sa_id, old_sa->id);
644
Matthew Smith41b25cf2018-12-05 14:41:21 -0600645 if (ipsec_add_del_sa_sess_cb (im, old_sa_index, 0))
Matthew Smithca514fd2017-10-12 12:06:59 -0500646 {
Klement Sekerab4d30532018-11-08 13:00:02 +0100647 clib_warning ("IPsec backend add/del callback returned error");
648 return VNET_API_ERROR_SYSCALL_ERROR_1;
Matthew Smithca514fd2017-10-12 12:06:59 -0500649 }
Matthew Smithca514fd2017-10-12 12:06:59 -0500650 pool_put (im->sad, old_sa);
651
652 return 0;
653}
654
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400655
Ed Warnickecb9cada2015-12-08 15:45:58 -0700656clib_error_t *
657ipsec_tunnel_if_init (vlib_main_t * vm)
658{
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700659 ipsec_main_t *im = &ipsec_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700660
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400661 /* initialize the ipsec-if ip4 hash */
662 im->ipsec4_if_pool_index_by_key =
663 hash_create (0, sizeof (ipsec4_tunnel_key_t));
664 /* initialize the ipsec-if ip6 hash */
665 im->ipsec6_if_pool_index_by_key = hash_create_mem (0,
666 sizeof
667 (ipsec6_tunnel_key_t),
668 sizeof (uword));
Matthew Smith8e1039a2018-04-12 07:32:56 -0500669 im->ipsec_if_real_dev_by_show_dev = hash_create (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700670
Kingwel Xie1ba5bc82019-03-20 07:21:58 -0400671 udp_register_dst_port (vm, UDP_DST_PORT_ipsec, ipsec4_if_input_node.index,
Kingwel Xie00bff192019-03-07 01:25:32 -0500672 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673 return 0;
674}
675
676VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);
677
Keith Burns (alagalah)166a9d42016-08-06 11:00:56 -0700678
679/*
680 * fd.io coding-style-patch-verification: ON
681 *
682 * Local Variables:
683 * eval: (c-set-style "gnu")
684 * End:
685 */