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 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
26 static u8 * format_ipsec_name (u8 * s, va_list * args)
28 u32 dev_instance = va_arg (*args, u32);
29 return format (s, "ipsec%d", dev_instance);
32 static uword dummy_interface_tx (vlib_main_t * vm,
33 vlib_node_runtime_t * node,
36 clib_warning ("you shouldn't be here, leaking buffers...");
37 return frame->n_vectors;
40 VNET_DEVICE_CLASS (ipsec_device_class,static) = {
42 .format_device_name = format_ipsec_name,
43 .format_tx_trace = format_ipsec_if_output_trace,
44 .tx_function = dummy_interface_tx,
47 VNET_HW_INTERFACE_CLASS (ipsec_hw_class) = {
53 ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm,
54 ipsec_add_del_tunnel_args_t * args);
57 ipsec_add_del_tunnel_if_rpc_callback (ipsec_add_del_tunnel_args_t *a)
59 vnet_main_t * vnm = vnet_get_main();
60 ASSERT(os_get_cpu_number() == 0);
62 return ipsec_add_del_tunnel_if_internal(vnm, a);
66 ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args)
68 vl_api_rpc_call_main_thread (ipsec_add_del_tunnel_if_rpc_callback,
69 (u8 *) args, sizeof(*args));
74 ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, ipsec_add_del_tunnel_args_t * args)
76 ipsec_tunnel_if_t * t;
77 ipsec_main_t * im = &ipsec_main;
78 vnet_hw_interface_t * hi;
83 u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi;
84 p = hash_get (im->ipsec_if_pool_index_by_key, key);
88 /* check if same src/dst pair exists */
90 return VNET_API_ERROR_INVALID_VALUE;
92 pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES);
93 memset (t, 0, sizeof (*t));
95 pool_get (im->sad, sa);
96 memset (sa, 0, sizeof (*sa));
97 t->input_sa_index = sa - im->sad;
98 sa->spi = args->remote_spi;
99 sa->tunnel_src_addr.ip4.as_u32 = args->remote_ip.as_u32;
100 sa->tunnel_dst_addr.ip4.as_u32 = args->local_ip.as_u32;
102 sa->use_esn = args->esn;
103 sa->use_anti_replay = args->anti_replay;
104 sa->integ_alg = args->integ_alg;
105 if (args->remote_integ_key_len <= sizeof(args->remote_integ_key))
107 sa->integ_key_len = args->remote_integ_key_len;
108 clib_memcpy(sa->integ_key, args->remote_integ_key, args->remote_integ_key_len);
110 sa->crypto_alg = args->crypto_alg;
111 if (args->remote_crypto_key_len <= sizeof(args->remote_crypto_key))
113 sa->crypto_key_len = args->remote_crypto_key_len;
114 clib_memcpy(sa->crypto_key, args->remote_crypto_key, args->remote_crypto_key_len);
117 pool_get (im->sad, sa);
118 memset (sa, 0, sizeof (*sa));
119 t->output_sa_index = sa - im->sad;
120 sa->spi = args->local_spi;
121 sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32;
122 sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32;
125 sa->use_esn = args->esn;
126 sa->use_anti_replay = args->anti_replay;
127 sa->integ_alg = args->integ_alg;
128 if (args->local_integ_key_len <= sizeof(args->local_integ_key))
130 sa->integ_key_len = args->local_integ_key_len;
131 clib_memcpy(sa->integ_key, args->local_integ_key, args->local_integ_key_len);
133 sa->crypto_alg = args->crypto_alg;
134 if (args->local_crypto_key_len <= sizeof(args->local_crypto_key))
136 sa->crypto_key_len = args->local_crypto_key_len;
137 clib_memcpy(sa->crypto_key, args->local_crypto_key, args->local_crypto_key_len);
140 hash_set (im->ipsec_if_pool_index_by_key, key, t - im->tunnel_interfaces);
142 if (vec_len (im->free_tunnel_if_indices) > 0)
145 im->free_tunnel_if_indices[vec_len(im->free_tunnel_if_indices)-1];
146 _vec_len (im->free_tunnel_if_indices) -= 1;
150 hw_if_index = vnet_register_interface(vnm, ipsec_device_class.index,
151 t - im->tunnel_interfaces,
152 ipsec_hw_class.index,
153 t - im->tunnel_interfaces);
155 hi = vnet_get_hw_interface (vnm, hw_if_index);
156 hi->output_node_index = ipsec_if_output_node.index;
158 t->hw_if_index = hw_if_index;
160 /*1st interface, register protocol */
161 if (pool_elts(im->tunnel_interfaces) == 1)
162 ip4_register_protocol(IP_PROTOCOL_IPSEC_ESP, ipsec_if_input_node.index);
168 /* check if exists */
170 return VNET_API_ERROR_INVALID_VALUE;
172 t = pool_elt_at_index(im->tunnel_interfaces, p[0]);
173 hi = vnet_get_hw_interface (vnm, t->hw_if_index);
174 vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0); /* admin down */
175 vec_add1 (im->free_tunnel_if_indices, t->hw_if_index);
177 /* delete input and output SA */
178 sa = pool_elt_at_index(im->sad, t->input_sa_index);
179 pool_put (im->sad, sa);
180 sa = pool_elt_at_index(im->sad, t->output_sa_index);
181 pool_put (im->sad, sa);
183 hash_unset (im->ipsec_if_pool_index_by_key, key);
184 pool_put (im->tunnel_interfaces, t);
190 ipsec_set_interface_key(vnet_main_t * vnm, u32 hw_if_index,
191 ipsec_if_set_key_type_t type, u8 alg, u8 * key)
193 ipsec_main_t * im = &ipsec_main;
194 vnet_hw_interface_t * hi;
195 ipsec_tunnel_if_t * t;
198 hi = vnet_get_hw_interface (vnm, hw_if_index);
199 t = pool_elt_at_index (im->tunnel_interfaces, hi->dev_instance);
201 if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_CRYPTO)
203 sa = pool_elt_at_index(im->sad, t->output_sa_index);
204 sa->crypto_alg = alg;
205 sa->crypto_key_len = vec_len(key);
206 clib_memcpy(sa->crypto_key, key, vec_len(key));
208 else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
210 sa = pool_elt_at_index(im->sad, t->output_sa_index);
212 sa->integ_key_len = vec_len(key);
213 clib_memcpy(sa->integ_key, key, vec_len(key));
215 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
217 sa = pool_elt_at_index(im->sad, t->input_sa_index);
218 sa->crypto_alg = alg;
219 sa->crypto_key_len = vec_len(key);
220 clib_memcpy(sa->crypto_key, key, vec_len(key));
222 else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
224 sa = pool_elt_at_index(im->sad, t->input_sa_index);
226 sa->integ_key_len = vec_len(key);
227 clib_memcpy(sa->integ_key, key, vec_len(key));
230 return VNET_API_ERROR_INVALID_VALUE;
237 ipsec_tunnel_if_init (vlib_main_t * vm)
239 ipsec_main_t * im = &ipsec_main;
241 im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
246 VLIB_INIT_FUNCTION (ipsec_tunnel_if_init);