FD.io VPP  v21.01.1
Vector Packet Processing
ipsec_tun_in.c
Go to the documentation of this file.
1 /*
2  * ipsec_tun_protect_in.c : IPSec interface input node
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 #include <vnet/ipsec/esp.h>
24 #include <vnet/ipsec/ipsec_io.h>
25 #include <vnet/ipsec/ipsec_punt.h>
26 #include <vnet/ipsec/ipsec_tun.h>
27 #include <vnet/ip/ip4_input.h>
28 
29 /* Statistics (not really errors) */
30 #define foreach_ipsec_tun_protect_input_error \
31  _(RX, "good packets received") \
32  _(DISABLED, "ipsec packets received on disabled interface") \
33  _(NO_TUNNEL, "no matching tunnel") \
34  _(TUNNEL_MISMATCH, "SPI-tunnel mismatch") \
35  _(NAT_KEEPALIVE, "NAT Keepalive") \
36  _(TOO_SHORT, "Too Short") \
37  _(SPI_0, "SPI 0")
38 
40 #define _(sym,string) string,
42 #undef _
43 };
44 
45 typedef enum
46 {
47 #define _(sym,str) IPSEC_TUN_PROTECT_INPUT_ERROR_##sym,
49 #undef _
52 
53 typedef enum ipsec_tun_next_t_
54 {
55 #define _(v, s) IPSEC_TUN_PROTECT_NEXT_##v,
57 #undef _
60 
61 typedef struct
62 {
63  union
64  {
67  };
71 
72 static u8 *
74 {
75  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
76  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
78  va_arg (*args, ipsec_tun_protect_input_trace_t *);
79 
80  if (t->is_ip6)
81  s = format (s, "IPSec: %U seq %u",
83  else
84  s = format (s, "IPSec: %U seq %u sa %d",
86  return s;
87 }
88 
91  vlib_buffer_t * b,
92  const esp_header_t * esp, const ip4_header_t * ip4)
93 {
94  if (PREDICT_FALSE (0 == esp->spi))
95  {
96  b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_SPI_0];
97  b->punt_reason = ipsec_punt_reason[(ip4->protocol == IP_PROTOCOL_UDP ?
98  IPSEC_PUNT_IP4_SPI_UDP_0 :
99  IPSEC_PUNT_IP4_NO_SUCH_TUNNEL)];
100  }
101  else
102  {
103  b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL];
104  b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP4_NO_SUCH_TUNNEL];
105  }
106  return IPSEC_INPUT_NEXT_PUNT;
107 }
108 
111  vlib_buffer_t * b, const esp_header_t * esp)
112 {
113  b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL];
114  b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP6_NO_SUCH_TUNNEL];
115 
116  return (IPSEC_INPUT_NEXT_PUNT);
117 }
118 
121  vlib_frame_t * from_frame, int is_ip6)
122 {
123  ipsec_main_t *im = &ipsec_main;
124  vnet_main_t *vnm = im->vnet_main;
126 
127  int is_trace = node->flags & VLIB_NODE_FLAG_TRACE;
128  u32 thread_index = vm->thread_index;
129 
130  u32 n_left_from, *from;
131  u16 nexts[VLIB_FRAME_SIZE], *next;
132  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
133 
134  from = vlib_frame_vector_args (from_frame);
135  n_left_from = from_frame->n_vectors;
136 
137  vlib_get_buffers (vm, from, bufs, n_left_from);
138  b = bufs;
139  next = nexts;
140 
141  clib_memset_u16 (nexts, im->esp4_decrypt_next_index, n_left_from);
142 
143  u64 n_bytes = 0, n_packets = 0;
144  u32 n_disabled = 0, n_no_tunnel = 0;
145 
146  u32 last_sw_if_index = ~0;
147  ipsec_tun_lkup_result_t last_result = {
148  .tun_index = ~0
149  };
150  ipsec4_tunnel_kv_t last_key4;
151  ipsec6_tunnel_kv_t last_key6;
153 
154  vlib_combined_counter_main_t *rx_counter;
155  vlib_combined_counter_main_t *drop_counter;
156 
157  if (is_ip6)
158  clib_memset (&last_key6, 0xff, sizeof (last_key6));
159  else
160  last_key4.key = ~0;
161 
164 
165  while (n_left_from > 0)
166  {
167  u32 sw_if_index0, len0, hdr_sz0;
168  clib_bihash_kv_24_16_t bkey60;
169  clib_bihash_kv_8_16_t bkey40;
170  ipsec4_tunnel_kv_t *key40;
171  ipsec6_tunnel_kv_t *key60;
172  ip4_header_t *ip40;
173  ip6_header_t *ip60;
174  esp_header_t *esp0;
175  u16 buf_rewind0;
176 
177  ip40 =
178  (ip4_header_t *) (b[0]->data + vnet_buffer (b[0])->l3_hdr_offset);
179 
180  key60 = (ipsec6_tunnel_kv_t *) & bkey60;
181  key40 = (ipsec4_tunnel_kv_t *) & bkey40;
182 
183  if (is_ip6)
184  {
185  ip60 = (ip6_header_t *) ip40;
186  esp0 = (esp_header_t *) (ip60 + 1);
187  hdr_sz0 = sizeof (ip6_header_t);
188  }
189  else
190  {
191  /* NAT UDP port 4500 case, don't advance any more */
192  if (ip40->protocol == IP_PROTOCOL_UDP)
193  {
194  esp0 =
195  (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) +
196  sizeof (udp_header_t));
197  hdr_sz0 = 0;
198  buf_rewind0 = ip4_header_bytes (ip40) + sizeof (udp_header_t);
199  }
200  else
201  {
202  esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40));
203  buf_rewind0 = hdr_sz0 = ip4_header_bytes (ip40);
204  }
205  }
206 
207  /* stats for the tunnel include all the data after the IP header
208  just like a norml IP-IP tunnel */
209  vlib_buffer_advance (b[0], hdr_sz0);
210  len0 = vlib_buffer_length_in_chain (vm, b[0]);
211 
212  if (len0 < sizeof (esp_header_t))
213  {
214  if (esp0->spi_bytes[0] == 0xff)
215  b[0]->error =
216  node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NAT_KEEPALIVE];
217  else
218  b[0]->error =
219  node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_TOO_SHORT];
220 
221  next[0] = IPSEC_INPUT_NEXT_DROP;
222  goto trace00;
223  }
224 
225  if (is_ip6)
226  {
227  key60->key.remote_ip = ip60->src_address;
228  key60->key.spi = esp0->spi;
229  key60->key.__pad = 0;
230 
231  if (memcmp (key60, &last_key6, sizeof (last_key6)) == 0)
232  {
233  clib_memcpy_fast (&itr0, &last_result, sizeof (itr0));
234  }
235  else
236  {
237  int rv =
238  clib_bihash_search_inline_24_16 (&im->tun6_protect_by_key,
239  &bkey60);
240  if (!rv)
241  {
242  clib_memcpy_fast (&itr0, &bkey60.value, sizeof (itr0));
243  clib_memcpy_fast (&last_result, &bkey60.value,
244  sizeof (last_result));
245  clib_memcpy_fast (&last_key6, key60, sizeof (last_key6));
246  }
247  else
248  {
249  next[0] = ipsec_ip6_if_no_tunnel (node, b[0], esp0);
250  n_no_tunnel++;
251  goto trace00;
252  }
253  }
254  }
255  else
256  {
257  ipsec4_tunnel_mk_key (key40, &ip40->src_address, esp0->spi);
258 
259  if (key40->key == last_key4.key)
260  {
261  clib_memcpy_fast (&itr0, &last_result, sizeof (itr0));
262  }
263  else
264  {
265  int rv =
266  clib_bihash_search_inline_8_16 (&im->tun4_protect_by_key,
267  &bkey40);
268  if (!rv)
269  {
270  clib_memcpy_fast (&itr0, &bkey40.value, sizeof (itr0));
271  clib_memcpy_fast (&last_result, &bkey40.value,
272  sizeof (last_result));
273  last_key4.key = key40->key;
274  }
275  else
276  {
277  next[0] = ipsec_ip4_if_no_tunnel (node, b[0], esp0, ip40);
278  vlib_buffer_advance (b[0], -buf_rewind0);
279  n_no_tunnel++;
280  goto trace00;
281  }
282  }
283  }
284 
285  vnet_buffer (b[0])->ipsec.sad_index = itr0.sa_index;
286  vnet_buffer (b[0])->ipsec.protect_index = itr0.tun_index;
287 
288  sw_if_index0 = itr0.sw_if_index;
289  vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index0;
290 
291  if (PREDICT_FALSE (!vnet_sw_interface_is_admin_up (vnm, sw_if_index0)))
292  {
294  (drop_counter, thread_index, sw_if_index0, 1, len0);
295  n_disabled++;
296  b[0]->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_DISABLED];
297  next[0] = IPSEC_INPUT_NEXT_DROP;
298  goto trace00;
299  }
300  else
301  {
302  if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index))
303  {
304  n_packets++;
305  n_bytes += len0;
306  }
307  else
308  {
309  if (n_packets && !(itr0.flags & IPSEC_PROTECT_ENCAPED))
310  {
312  (rx_counter, thread_index, last_sw_if_index,
313  n_packets, n_bytes);
314  }
315 
316  last_sw_if_index = sw_if_index0;
317  n_packets = 1;
318  n_bytes = len0;
319  }
320 
321  //IPSEC_TUN_PROTECT_NEXT_DECRYPT;
322  next[0] = im->esp4_decrypt_tun_next_index;
323  }
324  trace00:
325  if (PREDICT_FALSE (is_trace))
326  {
327  if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
328  {
330  vlib_add_trace (vm, node, b[0], sizeof (*tr));
331  if (is_ip6)
332  clib_memcpy (&tr->kv6, &bkey60, sizeof (tr->kv6));
333  else
334  clib_memcpy (&tr->kv4, &bkey40, sizeof (tr->kv4));
335  tr->is_ip6 = is_ip6;
336  tr->seq = (len0 >= sizeof (*esp0) ?
337  clib_host_to_net_u32 (esp0->seq) : ~0);
338  }
339  }
340 
341  /* next */
342  b += 1;
343  next += 1;
344  n_left_from -= 1;
345  }
346 
347  if (n_packets && !(itr0.flags & IPSEC_PROTECT_ENCAPED))
349  thread_index,
350  last_sw_if_index, n_packets, n_bytes);
351 
353  IPSEC_TUN_PROTECT_INPUT_ERROR_RX,
354  from_frame->n_vectors - (n_disabled +
355  n_no_tunnel));
357  IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL,
358  n_no_tunnel);
359 
360  vlib_buffer_enqueue_to_next (vm, node, from, nexts, from_frame->n_vectors);
361 
362  return from_frame->n_vectors;
363 }
364 
367  vlib_frame_t * from_frame)
368 {
369  return ipsec_tun_protect_input_inline (vm, node, from_frame, 0);
370 }
371 
372 /* *INDENT-OFF* */
374  .name = "ipsec4-tun-input",
375  .vector_size = sizeof (u32),
376  .format_trace = format_ipsec_tun_protect_input_trace,
379  .error_strings = ipsec_tun_protect_input_error_strings,
380  .n_next_nodes = IPSEC_TUN_PROTECT_N_NEXT,
381  .next_nodes = {
382  [IPSEC_TUN_PROTECT_NEXT_DROP] = "ip4-drop",
383  [IPSEC_TUN_PROTECT_NEXT_PUNT] = "punt-dispatch",
384  }
385 };
386 /* *INDENT-ON* */
387 
390  vlib_frame_t * from_frame)
391 {
392  return ipsec_tun_protect_input_inline (vm, node, from_frame, 1);
393 }
394 
395 /* *INDENT-OFF* */
397  .name = "ipsec6-tun-input",
398  .vector_size = sizeof (u32),
399  .format_trace = format_ipsec_tun_protect_input_trace,
402  .error_strings = ipsec_tun_protect_input_error_strings,
403  .n_next_nodes = IPSEC_TUN_PROTECT_N_NEXT,
404  .next_nodes = {
405  [IPSEC_TUN_PROTECT_NEXT_DROP] = "ip6-drop",
406  [IPSEC_TUN_PROTECT_NEXT_PUNT] = "punt-dispatch",
407  }
408 };
409 /* *INDENT-ON* */
410 
411 /*
412  * fd.io coding-style-patch-verification: ON
413  *
414  * Local Variables:
415  * eval: (c-set-style "gnu")
416  * End:
417  */
static u16 ipsec_ip6_if_no_tunnel(vlib_node_runtime_t *node, vlib_buffer_t *b, const esp_header_t *esp)
Definition: ipsec_tun_in.c:110
#define CLIB_UNUSED(x)
Definition: clib.h:87
vl_api_wireguard_peer_flags_t flags
Definition: wireguard.api:105
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:239
ip4_address_t src_address
Definition: ip4_packet.h:125
ipsec_tun_protect_input_error_t
Definition: ipsec_tun_in.c:45
vnet_interface_main_t interface_main
Definition: vnet.h:65
#define PREDICT_TRUE(x)
Definition: clib.h:122
unsigned long u64
Definition: types.h:89
#define clib_memcpy_fast(a, b, c)
Definition: string.h:81
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
struct ipsec6_tunnel_kv_t_::@463 key
ipsec_tun_next_t_
Definition: ipsec_tun_in.c:53
u32 thread_index
Definition: main.h:250
vlib_main_t * vm
Definition: in2out_ed.c:1580
#define VLIB_NODE_FN(node)
Definition: node.h:203
u8 * format_ipsec4_tunnel_kv(u8 *s, va_list *args)
Definition: ipsec_format.c:402
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
static uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:402
ip6_address_t src_address
Definition: ip6_packet.h:310
static u16 ipsec_ip4_if_no_tunnel(vlib_node_runtime_t *node, vlib_buffer_t *b, const esp_header_t *esp, const ip4_header_t *ip4)
Definition: ipsec_tun_in.c:90
unsigned char u8
Definition: types.h:56
u8 data[128]
Definition: ipsec_types.api:90
#define clib_memcpy(d, s, n)
Definition: string.h:180
u32 esp4_decrypt_tun_next_index
Definition: ipsec.h:153
ipsec_main_t ipsec_main
Definition: ipsec.c:28
vlib_combined_counter_main_t * combined_sw_if_counters
Definition: interface.h:882
u32 esp4_decrypt_next_index
Definition: ipsec.h:152
description fragment has unexpected format
Definition: map.api:433
vlib_node_registration_t ipsec4_tun_input_node
(constructor) VLIB_REGISTER_NODE (ipsec4_tun_input_node)
Definition: ipsec_tun_in.c:373
static void ipsec4_tunnel_mk_key(ipsec4_tunnel_kv_t *k, const ip4_address_t *ip, u32 spi)
Definition: ipsec_tun.h:62
const cJSON *const b
Definition: cJSON.h:255
unsigned int u32
Definition: types.h:88
clib_bihash_8_16_t tun4_protect_by_key
Definition: ipsec.h:133
#define VLIB_FRAME_SIZE
Definition: node.h:378
bool is_ip6
Definition: ip.api:43
vl_api_fib_path_type_t type
Definition: fib_types.api:123
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
clib_bihash_24_16_t tun6_protect_by_key
Definition: ipsec.h:134
vnet_main_t * vnet_main
Definition: ipsec.h:122
unsigned short u16
Definition: types.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:121
#define always_inline
Definition: ipsec.h:28
vl_api_ip4_address_t ip4
Definition: one.api:376
u32 node_index
Node index.
Definition: node.h:488
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1231
u32 punt_reason
Definition: buffer.h:149
vlib_punt_reason_t ipsec_punt_reason[IPSEC_PUNT_N_REASONS]
Definition: ipsec_punt.c:24
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
ipsec_protect_flags_t flags
Definition: ipsec_tun.h:43
u16 n_vectors
Definition: node.h:397
static_always_inline void vlib_buffer_enqueue_to_next(vlib_main_t *vm, vlib_node_runtime_t *node, u32 *buffers, u16 *nexts, uword count)
Definition: buffer_node.h:339
ip6_address_t remote_ip
Definition: ipsec_tun.h:84
8 octet key, 8 octet key value pair
Definition: bihash_8_16.h:41
u8 spi_bytes[4]
Definition: esp.h:27
u8 * format_ipsec6_tunnel_kv(u8 *s, va_list *args)
Definition: ipsec_format.c:420
enum ipsec_tun_next_t_ ipsec_tun_next_t
u64 value[2]
the value
Definition: bihash_8_16.h:44
#define ARRAY_LEN(x)
Definition: clib.h:67
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1580
result of a lookup in the protection bihash
Definition: ipsec_tun.h:38
u32 seq
Definition: esp.h:29
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:252
static uword ipsec_tun_protect_input_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame, int is_ip6)
Definition: ipsec_tun_in.c:120
static char * ipsec_tun_protect_input_error_strings[]
Definition: ipsec_tun_in.c:39
u32 spi
Definition: esp.h:26
static uword vnet_sw_interface_is_admin_up(vnet_main_t *vnm, u32 sw_if_index)
static_always_inline void clib_memset_u16(void *p, u16 val, uword count)
Definition: string.h:378
VLIB buffer representation.
Definition: buffer.h:102
u64 uword
Definition: types.h:112
#define foreach_ipsec_tun_protect_input_error
Definition: ipsec_tun_in.c:30
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:297
vlib_node_registration_t ipsec6_tun_input_node
(constructor) VLIB_REGISTER_NODE (ipsec6_tun_input_node)
Definition: ipsec_tun_in.c:396
A collection of combined counters.
Definition: counter.h:207
#define vnet_buffer(b)
Definition: buffer.h:417
u16 flags
Copy of main node flags.
Definition: node.h:501
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:634
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:190
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
Definition: buffer_funcs.h:280
#define VLIB_NODE_FLAG_TRACE
Definition: node.h:302
static u8 * format_ipsec_tun_protect_input_trace(u8 *s, va_list *args)
Definition: ipsec_tun_in.c:73
#define foreach_ipsec_input_next
Definition: ipsec_io.h:29
Definition: defs.h:46