FD.io VPP  v17.01-9-ge7dcee4
Vector Packet Processing
ipsec_if.c
Go to the documentation of this file.
1 /*
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>
23 #if DPDK_CRYPTO==1
25 #else
26 #include <vnet/ipsec/esp.h>
27 #endif
28 
29 #if DPDK_CRYPTO==0
30 /* dummy function */
31 static int
32 add_del_sa_sess (u32 sa_index, u8 is_add)
33 {
34  return 0;
35 }
36 #endif
37 
38 void vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length);
39 
40 static u8 *
41 format_ipsec_name (u8 * s, va_list * args)
42 {
43  u32 dev_instance = va_arg (*args, u32);
44  return format (s, "ipsec%d", dev_instance);
45 }
46 
47 static uword
49  vlib_node_runtime_t * node, vlib_frame_t * frame)
50 {
51  clib_warning ("you shouldn't be here, leaking buffers...");
52  return frame->n_vectors;
53 }
54 
55 /* *INDENT-OFF* */
56 VNET_DEVICE_CLASS (ipsec_device_class, static) =
57 {
58  .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* */
64 
65 /* *INDENT-OFF* */
66 VNET_HW_INTERFACE_CLASS (ipsec_hw_class) =
67 {
68  .name = "IPSec",
69  .build_rewrite = default_build_rewrite,
70 };
71 /* *INDENT-ON* */
72 
73 static int
76 
77 static int
79 {
80  vnet_main_t *vnm = vnet_get_main ();
81  ASSERT (os_get_cpu_number () == 0);
82 
83  return ipsec_add_del_tunnel_if_internal (vnm, a);
84 }
85 
86 int
88 {
90  (u8 *) args, sizeof (*args));
91  return 0;
92 }
93 
94 int
97 {
99  ipsec_main_t *im = &ipsec_main;
101  u32 hw_if_index = ~0;
102  uword *p;
103  ipsec_sa_t *sa;
104 
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)
112  return VNET_API_ERROR_INVALID_VALUE;
113 
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;
126  sa->integ_alg = args->integ_alg;
127  if (args->remote_integ_key_len <= sizeof (args->remote_integ_key))
128  {
131  args->remote_integ_key_len);
132  }
133  sa->crypto_alg = args->crypto_alg;
134  if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key))
135  {
138  args->remote_crypto_key_len);
139  }
140 
142 
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;
149  sa->is_tunnel = 1;
150  sa->seq = 1;
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))
155  {
158  args->local_integ_key_len);
159  }
160  sa->crypto_alg = args->crypto_alg;
161  if (args->local_crypto_key_len <= sizeof (args->local_crypto_key))
162  {
165  args->local_crypto_key_len);
166  }
167 
169 
171  t - im->tunnel_interfaces);
172 
173  if (vec_len (im->free_tunnel_if_indices) > 0)
174  {
175  hw_if_index =
177  1];
178  _vec_len (im->free_tunnel_if_indices) -= 1;
179  }
180  else
181  {
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);
187 
188  hi = vnet_get_hw_interface (vnm, hw_if_index);
190  }
191  t->hw_if_index = hw_if_index;
192 
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);
197 
198  return hw_if_index;
199  }
200  else
201  {
202  /* check if exists */
203  if (!p)
204  return VNET_API_ERROR_INVALID_VALUE;
205 
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 */
210 
211  /* delete input and output SA */
212  sa = pool_elt_at_index (im->sad, t->input_sa_index);
213 
214  if (add_del_sa_sess (t->input_sa_index, args->is_add) < 0)
215  return VNET_API_ERROR_SYSCALL_ERROR_1;
216 
217  pool_put (im->sad, sa);
218 
219  sa = pool_elt_at_index (im->sad, t->output_sa_index);
220 
221  if (add_del_sa_sess (t->output_sa_index, args->is_add) < 0)
222  return VNET_API_ERROR_SYSCALL_ERROR_1;
223 
224  pool_put (im->sad, sa);
225 
227  pool_put (im->tunnel_interfaces, t);
228  }
229  return 0;
230 }
231 
232 int
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 
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;
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]);
289  pool_put (im->tunnel_interfaces, t);
290  }
291  return 0;
292 }
293 
294 int
296  ipsec_if_set_key_type_t type, u8 alg, u8 * key)
297 {
298  ipsec_main_t *im = &ipsec_main;
301  ipsec_sa_t *sa;
302 
303  hi = vnet_get_hw_interface (vnm, hw_if_index);
305 
307  {
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));
312 
313  if (add_del_sa_sess (t->input_sa_index, 0) < 0)
314  return VNET_API_ERROR_SYSCALL_ERROR_1;
315  }
316  else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG)
317  {
318  sa = pool_elt_at_index (im->sad, t->output_sa_index);
319  sa->integ_alg = alg;
320  sa->integ_key_len = vec_len (key);
321  clib_memcpy (sa->integ_key, key, vec_len (key));
322 
323  if (add_del_sa_sess (t->output_sa_index, 0) < 0)
324  return VNET_API_ERROR_SYSCALL_ERROR_1;
325  }
326  else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO)
327  {
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));
332 
333  if (add_del_sa_sess (t->input_sa_index, 0) < 0)
334  return VNET_API_ERROR_SYSCALL_ERROR_1;
335  }
336  else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG)
337  {
338  sa = pool_elt_at_index (im->sad, t->input_sa_index);
339  sa->integ_alg = alg;
340  sa->integ_key_len = vec_len (key);
341  clib_memcpy (sa->integ_key, key, vec_len (key));
342 
343  if (add_del_sa_sess (t->output_sa_index, 0) < 0)
344  return VNET_API_ERROR_SYSCALL_ERROR_1;
345  }
346  else
347  return VNET_API_ERROR_INVALID_VALUE;
348 
349  return 0;
350 }
351 
352 
353 clib_error_t *
355 {
356  ipsec_main_t *im = &ipsec_main;
357 
358  im->ipsec_if_pool_index_by_key = hash_create (0, sizeof (uword));
359 
360  return 0;
361 }
362 
364 
365 
366 /*
367  * fd.io coding-style-patch-verification: ON
368  *
369  * Local Variables:
370  * eval: (c-set-style "gnu")
371  * End:
372  */
vmrglw vmrglh hi
VNET_DEVICE_CLASS(ipsec_device_class, static)
#define hash_set(h, key, value)
Definition: hash.h:254
ipsec_tunnel_if_t * tunnel_interfaces
Definition: ipsec.h:233
ip46_address_t tunnel_src_addr
Definition: ipsec.h:111
#define hash_unset(h, key)
Definition: hash.h:260
a
Definition: bitmap.h:516
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
ipsec_integ_alg_t integ_alg
Definition: ipsec.h:102
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u8 * format_ipsec_if_output_trace(u8 *s, va_list *args)
Definition: ipsec_if_out.c:63
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
int ipsec_add_del_tunnel_if(ipsec_add_del_tunnel_args_t *args)
Definition: ipsec_if.c:87
static int ipsec_add_del_tunnel_if_internal(vnet_main_t *vnm, ipsec_add_del_tunnel_args_t *args)
Definition: ipsec_if.c:95
u8 is_tunnel
Definition: ipsec.h:109
static uword dummy_interface_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: ipsec_if.c:48
void ip4_register_protocol(u32 protocol, u32 node_index)
Definition: ip4_forward.c:1856
vlib_node_registration_t ipsec_if_input_node
(constructor) VLIB_REGISTER_NODE (ipsec_if_input_node)
Definition: ipsec_if_in.c:149
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
uword * ipsec_if_pool_index_by_key
Definition: ipsec.h:251
u8 crypto_key[128]
Definition: ipsec.h:100
u32 spi
Definition: ipsec.h:95
clib_error_t * ipsec_tunnel_if_init(vlib_main_t *vm)
Definition: ipsec_if.c:354
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
u8 integ_key[128]
Definition: ipsec.h:104
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
u8 use_esn
Definition: ipsec.h:106
ip4_address_t remote_ip
Definition: ipsec.h:139
#define clib_warning(format, args...)
Definition: error.h:59
unsigned long u64
Definition: types.h:89
int ipsec_set_interface_key(vnet_main_t *vnm, u32 hw_if_index, ipsec_if_set_key_type_t type, u8 alg, u8 *key)
Definition: ipsec_if.c:295
u32 vnet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u32 hw_class_index, u32 hw_instance)
Definition: interface.c:688
#define hash_get(h, key)
Definition: hash.h:248
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
ipsec_if_set_key_type_t
Definition: ipsec.h:163
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
ip46_address_t tunnel_dst_addr
Definition: ipsec.h:112
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:169
ipsec_main_t ipsec_main
Definition: ipsec.h:260
ipsec_crypto_alg_t crypto_alg
Definition: ipsec.h:142
u16 n_vectors
Definition: node.h:344
void vl_api_rpc_call_main_thread(void *fp, u8 *data, u32 data_length)
Definition: memory_vlib.c:1268
#define clib_memcpy(a, b, c)
Definition: string.h:69
uword * sa_index_by_sa_id
Definition: ipsec.h:250
u32 output_sa_index
Definition: ipsec.h:222
u8 * default_build_rewrite(vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address)
Return a complete, zero-length (aka dummy) rewrite.
Definition: interface.c:1382
int ipsec_add_del_ipsec_gre_tunnel(vnet_main_t *vnm, ipsec_add_del_ipsec_gre_tunnel_args_t *args)
Definition: ipsec_if.c:233
#define hash_create(elts, value_bytes)
Definition: hash.h:658
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
static int ipsec_add_del_tunnel_if_rpc_callback(ipsec_add_del_tunnel_args_t *a)
Definition: ipsec_if.c:78
ipsec_integ_alg_t integ_alg
Definition: ipsec.h:147
ip4_address_t local_ip
Definition: ipsec.h:139
ipsec_sa_t * sad
Definition: ipsec.h:230
u8 integ_key_len
Definition: ipsec.h:103
u32 input_sa_index
Definition: ipsec.h:221
u32 seq
Definition: ipsec.h:117
u64 uword
Definition: types.h:112
u8 crypto_key_len
Definition: ipsec.h:99
static int add_del_sa_sess(u32 sa_index, u8 is_add)
Definition: ipsec_if.c:32
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
VNET_HW_INTERFACE_CLASS(ipsec_hw_class)
u32 * free_tunnel_if_indices
Definition: ipsec.h:234
ipsec_crypto_alg_t crypto_alg
Definition: ipsec.h:98
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
static u8 * format_ipsec_name(u8 *s, va_list *args)
Definition: ipsec_if.c:41
clib_error_t * vnet_sw_interface_set_flags(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: interface.c:539
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u8 use_anti_replay
Definition: ipsec.h:107
vlib_node_registration_t ipsec_if_output_node
(constructor) VLIB_REGISTER_NODE (ipsec_if_output_node)
Definition: ipsec_if_out.c:135
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109