FD.io VPP  v21.01.1
Vector Packet Processing
ipsec_itf.c
Go to the documentation of this file.
1 /*
2  * ipsec_itf.c: IPSec dedicated interface type
3  *
4  * Copyright (c) 2020 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/ip/ip.h>
19 #include <vnet/ipsec/ipsec_itf.h>
20 #include <vnet/ipsec/ipsec_tun.h>
21 #include <vnet/ipsec/ipsec.h>
22 #include <vnet/adj/adj_midchain.h>
24 
25 /* bitmap of Allocated IPSEC_ITF instances */
27 
28 /* pool of interfaces */
30 
32 
35 {
36  return (pool_elt_at_index (ipsec_itf_pool, ii));
37 }
38 
39 static ipsec_itf_t *
41 {
42  if (vec_len (ipsec_itf_index_by_sw_if_index) <= sw_if_index)
43  return NULL;
45  if (ti == ~0)
46  return NULL;
47  return pool_elt_at_index (ipsec_itf_pool, ti);
48 }
49 
50 static u8 *
51 format_ipsec_itf_name (u8 * s, va_list * args)
52 {
53  u32 dev_instance = va_arg (*args, u32);
54  return format (s, "ipsec%d", dev_instance);
55 }
56 
57 void
59 {
61 }
62 
63 void
65 {
66  const vnet_hw_interface_t *hw;
67 
69 
71  {
72  const ipsec_sa_t *sa;
73 
74  sa = ipsec_sa_get (sai);
75 
76  /* *INDENT-OFF* */
77  const fib_prefix_t dst = {
78  .fp_len = (ipsec_sa_is_set_IS_TUNNEL_V6(sa) ? 128 : 32),
79  .fp_proto = (ipsec_sa_is_set_IS_TUNNEL_V6(sa)?
82  .fp_addr = sa->tunnel_dst_addr,
83  };
84  /* *INDENT-ON* */
85 
87  }
88  else
90 }
91 
92 static adj_walk_rc_t
94 {
95  ipsec_tun_protect_t *itp = arg;
96 
98 
99  return (ADJ_WALK_RC_CONTINUE);
100 }
101 
102 static void
104 {
105  ipsec_tun_protect_t *itp;
107 
108  itp = ipsec_tun_protect_get (itpi);
109 
110  /*
111  * walk all the adjacencies on the interface and restack them
112  */
114  {
116  }
117 }
118 
119 static walk_rc_t
121 {
122  const ipsec_itf_t *itf = arg;
123 
124  ipsec_itf_restack (itpi, itf);
125 
126  return (WALK_CONTINUE);
127 }
128 
129 static clib_error_t *
131 {
133  ipsec_itf_t *itf;
134  u32 hw_flags;
135 
136  hi = vnet_get_hw_interface (vnm, hw_if_index);
137  hw_flags = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP ?
139  vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
140 
142 
143  if (itf)
146 
147  return (NULL);
148 }
149 
150 static int
152  ip46_address_t * src, ip46_address_t * dst, u8 * is_l2)
153 {
154  ip46_address_reset (src);
155  ip46_address_reset (dst);
156  *is_l2 = 0;
157 
158  return (0);
159 }
160 
161 static u8 *
163 {
164  /*
165  * passing the adj code a NULL rewrite means 'i don't have one cos
166  * t'other end is unresolved'. That's not the case here. For the ipsec
167  * tunnel there are just no bytes of encap to apply in the adj.
168  * So return a zero length rewrite. Encap will be added by a tunnel mode SA.
169  */
170  u8 *rewrite = NULL;
171 
172  vec_validate (rewrite, 0);
173  vec_reset_length (rewrite);
174 
175  return (rewrite);
176 }
177 
178 static u8 *
181  vnet_link_t link_type, const void *dst_address)
182 {
183  return (ipsec_itf_build_rewrite ());
184 }
185 
186 void
188 {
191 }
192 
193 /* *INDENT-OFF* */
194 VNET_DEVICE_CLASS (ipsec_itf_device_class) = {
195  .name = "IPSEC Tunnel",
196  .format_device_name = format_ipsec_itf_name,
197  .admin_up_down_function = ipsec_itf_admin_up_down,
198  .ip_tun_desc = ipsec_itf_tunnel_desc,
199 };
200 
201 VNET_HW_INTERFACE_CLASS(ipsec_hw_interface_class) = {
202  .name = "IPSec",
203  .build_rewrite = ipsec_itf_build_rewrite_i,
204  .update_adjacency = ipsec_itf_update_adj,
206 };
207 VNET_HW_INTERFACE_CLASS(ipsec_p2mp_hw_interface_class) = {
208  .name = "IPSec",
209  .build_rewrite = ipsec_itf_build_rewrite_i,
210  .update_adjacency = ipsec_itf_update_adj,
212 };
213 /* *INDENT-ON* */
214 
215 /*
216  * Maintain a bitmap of allocated ipsec_itf instance numbers.
217  */
218 #define IPSEC_ITF_MAX_INSTANCE (16 * 1024)
219 
220 static u32
222 {
223  /*
224  * Check for dynamically allocated instance number.
225  */
226  if (~0 == want)
227  {
228  u32 bit;
229 
231  if (bit >= IPSEC_ITF_MAX_INSTANCE)
232  {
233  return ~0;
234  }
236  return bit;
237  }
238 
239  /*
240  * In range?
241  */
242  if (want >= IPSEC_ITF_MAX_INSTANCE)
243  {
244  return ~0;
245  }
246 
247  /*
248  * Already in use?
249  */
251  {
252  return ~0;
253  }
254 
255  /*
256  * Grant allocation request.
257  */
259 
260  return want;
261 }
262 
263 static int
265 {
266  if (instance >= IPSEC_ITF_MAX_INSTANCE)
267  {
268  return -1;
269  }
270 
271  if (clib_bitmap_get (ipsec_itf_instances, instance) == 0)
272  {
273  return -1;
274  }
275 
277  return 0;
278 }
279 
280 int
281 ipsec_itf_create (u32 user_instance, tunnel_mode_t mode, u32 * sw_if_indexp)
282 {
283  vnet_main_t *vnm = vnet_get_main ();
284  u32 instance, hw_if_index;
287 
288  ASSERT (sw_if_indexp);
289 
290  *sw_if_indexp = (u32) ~ 0;
291 
292  /*
293  * Allocate a ipsec_itf instance. Either select on dynamically
294  * or try to use the desired user_instance number.
295  */
296  instance = ipsec_itf_instance_alloc (user_instance);
297  if (instance == ~0)
298  return VNET_API_ERROR_INVALID_REGISTRATION;
299 
300  pool_get (ipsec_itf_pool, ipsec_itf);
301 
302  /* tunnel index (or instance) */
303  u32 t_idx = ipsec_itf - ipsec_itf_pool;
304 
305  ipsec_itf->ii_mode = mode;
306  ipsec_itf->ii_user_instance = instance;
307 
308  hw_if_index = vnet_register_interface (vnm,
309  ipsec_itf_device_class.index,
310  ipsec_itf->ii_user_instance,
311  (mode == TUNNEL_MODE_P2P ?
312  ipsec_hw_interface_class.index :
313  ipsec_p2mp_hw_interface_class.index),
314  t_idx);
315 
316  hi = vnet_get_hw_interface (vnm, hw_if_index);
317 
319  INDEX_INVALID);
321 
322  ipsec_itf->ii_sw_if_index = *sw_if_indexp = hi->sw_if_index;
323 
324  return 0;
325 }
326 
327 int
329 {
330  vnet_main_t *vnm = vnet_get_main ();
331 
332  if (pool_is_free_index (vnm->interface_main.sw_interfaces, sw_if_index))
333  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
334 
335  vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
336  if (hw == 0 || hw->dev_class_index != ipsec_itf_device_class.index)
337  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
338 
340  ipsec_itf = ipsec_itf_find_by_sw_if_index (sw_if_index);
341  if (NULL == ipsec_itf)
342  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
343 
345  return VNET_API_ERROR_INVALID_SW_IF_INDEX;
346 
348  pool_put (ipsec_itf_pool, ipsec_itf);
349 
350  return 0;
351 }
352 
353 static clib_error_t *
355  unformat_input_t * input, vlib_cli_command_t * cmd)
356 {
357  unformat_input_t _line_input, *line_input = &_line_input;
361  int rv;
362 
363  error = NULL;
364  instance = sw_if_index = ~0;
365  mac_address_set_zero (&mac);
366 
367  if (unformat_user (input, unformat_line_input, line_input))
368  {
369  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
370  {
371  if (unformat (line_input, "instance %d", &instance))
372  ;
373  else
374  {
375  error = clib_error_return (0, "unknown input: %U",
376  format_unformat_error, line_input);
377  break;
378  }
379  }
380 
381  unformat_free (line_input);
382 
383  if (error)
384  return error;
385  }
386 
387  rv = ipsec_itf_create (instance, TUNNEL_MODE_P2P, &sw_if_index);
388 
389  if (rv)
390  return clib_error_return (0, "iPSec interface create failed");
391 
393  sw_if_index);
394  return 0;
395 }
396 
397 /*?
398  * Create a IPSec interface.
399  *
400  * @cliexpar
401  * The following two command syntaxes are equivalent:
402  * @cliexcmd{ipsec itf create [instance <instance>]}
403  * Example of how to create a ipsec interface:
404  * @cliexcmd{ipsec itf create}
405 ?*/
406 /* *INDENT-OFF* */
407 VLIB_CLI_COMMAND (ipsec_itf_create_command, static) = {
408  .path = "ipsec itf create",
409  .short_help = "ipsec itf create [instance <instance>]",
410  .function = ipsec_itf_create_cli,
411 };
412 /* *INDENT-ON* */
413 
414 static clib_error_t *
416  unformat_input_t * input, vlib_cli_command_t * cmd)
417 {
418  vnet_main_t *vnm;
420  int rv;
421 
422  vnm = vnet_get_main ();
423  sw_if_index = ~0;
424 
426  {
427  if (unformat
428  (input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
429  ;
430  else
431  break;
432  }
433 
434  if (~0 != sw_if_index)
435  {
436  rv = ipsec_itf_delete (sw_if_index);
437 
438  if (rv)
439  return clib_error_return (0, "ipsec interface delete failed");
440  }
441  else
442  return clib_error_return (0, "no such interface: %U",
443  format_unformat_error, input);
444 
445  return 0;
446 }
447 
448 /*?
449  * Delete a IPSEC_ITF interface.
450  *
451  * @cliexpar
452  * The following two command syntaxes are equivalent:
453  * @cliexcmd{ipsec itf delete <interface>}
454  * Example of how to create a ipsec_itf interface:
455  * @cliexcmd{ipsec itf delete ipsec0}
456 ?*/
457 /* *INDENT-OFF* */
458 VLIB_CLI_COMMAND (ipsec_itf_delete_command, static) = {
459  .path = "ipsec itf delete",
460  .short_help = "ipsec itf delete <interface>",
461  .function = ipsec_itf_delete_cli,
462 };
463 /* *INDENT-ON* */
464 
465 static clib_error_t *
467  unformat_input_t * input, vlib_cli_command_t * cmd)
468 {
469  index_t ii;
470 
471  /* *INDENT-OFF* */
472  pool_foreach_index (ii, ipsec_itf_pool)
473  {
474  vlib_cli_output (vm, "%U", format_ipsec_itf, ii);
475  }
476  /* *INDENT-ON* */
477 
478  return NULL;
479 }
480 
481 /**
482  * show IPSEC tunnel protection hash tables
483  */
484 /* *INDENT-OFF* */
485 VLIB_CLI_COMMAND (ipsec_interface_show_node, static) =
486 {
487  .path = "show ipsec interface",
488  .function = ipsec_interface_show,
489  .short_help = "show ipsec interface",
490 };
491 /* *INDENT-ON* */
492 
493 /*
494  * fd.io coding-style-patch-verification: ON
495  *
496  * Local Variables:
497  * eval: (c-set-style "gnu")
498  * End:
499  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
ipsec_itf_t * ipsec_itf_get(index_t ii)
Definition: ipsec_itf.c:34
static u8 * format_ipsec_itf_name(u8 *s, va_list *args)
Definition: ipsec_itf.c:51
#define pool_foreach_index(i, v)
Definition: pool.h:569
vl_api_mac_address_t mac
Definition: l2.api:502
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
vnet_interface_main_t interface_main
Definition: vnet.h:65
static clib_error_t * ipsec_itf_admin_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: ipsec_itf.c:130
void adj_midchain_delegate_stack(adj_index_t ai, u32 fib_index, const fib_prefix_t *pfx)
create/attach a midchain delegate and stack it on the prefix passed
static int ipsec_itf_instance_free(u32 instance)
Definition: ipsec_itf.c:264
a non-broadcast multiple access interface
Definition: interface.h:391
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u32 index_t
A Data-Path Object is an object that represents actions that are applied to packets are they are swit...
Definition: dpo.h:41
void ipsec_tun_protect_walk_itf(u32 sw_if_index, ipsec_tun_protect_walk_cb_t fn, void *ctx)
Definition: ipsec_tun.c:849
vl_api_address_t src
Definition: gre.api:54
static uword * clib_bitmap_set(uword *ai, uword i, uword value)
Sets the ith bit of a bitmap to new_value Removes trailing zeros from the bitmap. ...
Definition: bitmap.h:167
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:989
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:794
vlib_main_t * vm
Definition: in2out_ed.c:1580
unformat_function_t unformat_vnet_sw_interface
static adj_walk_rc_t ipsec_itf_adj_stack_cb(adj_index_t ai, void *arg)
Definition: ipsec_itf.c:93
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, vnet_hw_interface_flags_t flags)
Definition: interface.c:509
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:251
static clib_error_t * ipsec_itf_delete_cli(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ipsec_itf.c:415
format_function_t format_vnet_sw_if_index_name
unsigned char u8
Definition: types.h:56
static void ipsec_itf_restack(index_t itpi, const ipsec_itf_t *itf)
Definition: ipsec_itf.c:103
enum fib_protocol_t_ fib_protocol_t
Protocol Type.
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
static_always_inline void mac_address_set_zero(mac_address_t *mac)
Definition: mac_address.h:146
enum walk_rc_t_ walk_rc_t
Walk return code.
VNET_DEVICE_CLASS(ipsec_itf_device_class)
static void ip46_address_reset(ip46_address_t *ip46)
Definition: ip46_address.h:74
void ipsec_itf_adj_unstack(adj_index_t ai)
Definition: ipsec_itf.c:58
enum adj_walk_rc_t_ adj_walk_rc_t
return codes from a adjacency walker callback function
description fragment has unexpected format
Definition: map.api:433
vnet_hw_interface_flags_t flags
Definition: interface.h:538
Aggregate type for a prefix.
Definition: fib_types.h:202
#define clib_error_return(e, args...)
Definition: error.h:99
static ipsec_itf_t * ipsec_itf_pool
Definition: ipsec_itf.c:29
unsigned int u32
Definition: types.h:88
unformat_function_t unformat_line_input
Definition: format.h:282
typedef ipsec_itf
Definition: ipsec.api:398
Definition: cJSON.c:84
u32 tx_fib_index
Definition: ipsec_sa.h:210
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:546
u32 adj_get_sw_if_index(adj_index_t ai)
Return the sw interface index of the adjacency.
Definition: adj.c:519
vl_api_ip_proto_t proto
Definition: acl_types.api:51
struct _unformat_input_t unformat_input_t
static ipsec_itf_t * ipsec_itf_find_by_sw_if_index(u32 sw_if_index)
Definition: ipsec_itf.c:40
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:301
vl_api_address_t dst
Definition: gre.api:55
static ipsec_sa_t * ipsec_sa_get(u32 sa_index)
Definition: ipsec.h:290
vl_api_tunnel_mode_t mode
Definition: gre.api:48
ip46_address_t tunnel_dst_addr
Definition: ipsec_sa.h:198
A dedicated IPSec interface type.
Definition: ipsec_itf.h:94
VNET_HW_INTERFACE_CLASS(ipsec_hw_interface_class)
#define UNFORMAT_END_OF_INPUT
Definition: format.h:144
void ipsec_itf_adj_stack(adj_index_t ai, u32 sai)
Definition: ipsec_itf.c:64
void adj_nbr_midchain_update_rewrite(adj_index_t adj_index, adj_midchain_fixup_t fixup, const void *fixup_data, adj_flags_t flags, u8 *rewrite)
adj_nbr_midchain_update_rewrite
Definition: adj_midchain.c:440
static u32 * ipsec_itf_index_by_sw_if_index
Definition: ipsec_itf.c:31
#define pool_is_free_index(P, I)
Use free bitmap to query whether given index is free.
Definition: pool.h:298
u32 adj_index_t
An index for adjacencies.
Definition: adj_types.h:30
static uword clib_bitmap_get(uword *ai, uword i)
Gets the ith bit value from a bitmap.
Definition: bitmap.h:197
void adj_nbr_walk(u32 sw_if_index, fib_protocol_t adj_nh_proto, adj_walk_cb_t cb, void *ctx)
Walk all adjacencies on a link for a given next-hop protocol.
Definition: adj_nbr.c:571
#define IPSEC_ITF_MAX_INSTANCE
Definition: ipsec_itf.c:218
void adj_midchain_delegate_unstack(adj_index_t ai)
unstack a midchain delegate (this stacks it on a drop)
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:158
#define ASSERT(truth)
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:696
static int ipsec_itf_tunnel_desc(u32 sw_if_index, ip46_address_t *src, ip46_address_t *dst, u8 *is_l2)
Definition: ipsec_itf.c:151
int ii_user_instance
Definition: ipsec_itf.h:97
u32 ii_sw_if_index
Definition: ipsec_itf.h:98
enum vnet_link_t_ vnet_link_t
Link Type: A description of the protocol of packets on the link.
void vnet_delete_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
Definition: interface.c:1011
static ipsec_tun_protect_t * ipsec_tun_protect_get(u32 index)
Definition: ipsec_tun.h:185
int ipsec_itf_delete(u32 sw_if_index)
Definition: ipsec_itf.c:328
void ipsec_itf_update_adj(vnet_main_t *vnm, u32 sw_if_index, adj_index_t ai)
Definition: ipsec_itf.c:187
static uword * ipsec_itf_instances
Definition: ipsec_itf.c:26
vl_api_ip4_address_t hi
Definition: arp.api:37
tunnel_mode_t ii_mode
Definition: ipsec_itf.h:96
static walk_rc_t ipsec_tun_protect_walk_state_change(index_t itpi, void *arg)
Definition: ipsec_itf.c:120
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u32 instance
Definition: gre.api:51
#define INDEX_INVALID
Invalid index - used when no index is known blazoned capitals INVALID speak volumes where ~0 does not...
Definition: dpo.h:47
u64 uword
Definition: types.h:112
static void unformat_free(unformat_input_t *i)
Definition: format.h:162
vnet_sw_interface_t * sw_interfaces
Definition: interface.h:873
a point 2 point interface
Definition: interface.h:387
#define FOR_EACH_FIB_IP_PROTOCOL(_item)
Definition: fib_types.h:69
u8 * format_ipsec_itf(u8 *s, va_list *a)
Definition: ipsec_format.c:434
static clib_error_t * ipsec_itf_create_cli(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ipsec_itf.c:354
int ipsec_itf_create(u32 user_instance, tunnel_mode_t mode, u32 *sw_if_indexp)
Definition: ipsec_itf.c:281
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
static u8 * ipsec_itf_build_rewrite_i(vnet_main_t *vnm, u32 sw_if_index, vnet_link_t link_type, const void *dst_address)
Definition: ipsec_itf.c:179
static uword clib_bitmap_first_clear(uword *ai)
Return the lowest numbered clear bit in a bitmap.
Definition: bitmap.h:451
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:556
static u8 * ipsec_itf_build_rewrite(void)
Definition: ipsec_itf.c:162
enum tunnel_mode_t_ tunnel_mode_t
vl_api_interface_index_t sw_if_index
Definition: wireguard.api:34
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:978
static clib_error_t * ipsec_interface_show(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: ipsec_itf.c:466
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:170
static u32 ipsec_itf_instance_alloc(u32 want)
Definition: ipsec_itf.c:221