FD.io VPP  v20.05-21-gb1500e9ff
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  {
65  ipsec4_tunnel_key_t key4;
66  ipsec6_tunnel_key_t key6;
67  };
72 
73 static u8 *
75 {
76  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
77  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
79  va_arg (*args, ipsec_tun_protect_input_trace_t *);
80 
81  if (t->is_ip6)
82  s = format (s, "IPSec: %U seq %u sa %d",
84  else
85  s = format (s, "IPSec: %U seq %u sa %d",
87  return s;
88 }
89 
92  vlib_buffer_t * b,
93  const esp_header_t * esp, const ip4_header_t * ip4)
94 {
95  if (PREDICT_FALSE (0 == esp->spi))
96  {
97  b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_SPI_0];
98  b->punt_reason = ipsec_punt_reason[(ip4->protocol == IP_PROTOCOL_UDP ?
99  IPSEC_PUNT_IP4_SPI_UDP_0 :
100  IPSEC_PUNT_IP4_NO_SUCH_TUNNEL)];
101  }
102  else
103  {
104  b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL];
105  b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP4_NO_SUCH_TUNNEL];
106  }
107  return IPSEC_INPUT_NEXT_PUNT;
108 }
109 
112  vlib_buffer_t * b, const esp_header_t * esp)
113 {
114  b->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL];
115  b->punt_reason = ipsec_punt_reason[IPSEC_PUNT_IP6_NO_SUCH_TUNNEL];
116 
117  return (IPSEC_INPUT_NEXT_PUNT);
118 }
119 
122  vlib_frame_t * from_frame, int is_ip6)
123 {
124  ipsec_main_t *im = &ipsec_main;
125  vnet_main_t *vnm = im->vnet_main;
127 
128  int is_trace = node->flags & VLIB_NODE_FLAG_TRACE;
129  u32 thread_index = vm->thread_index;
130 
131  u32 n_left_from, *from;
132  u16 nexts[VLIB_FRAME_SIZE], *next;
133  vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
134 
135  from = vlib_frame_vector_args (from_frame);
136  n_left_from = from_frame->n_vectors;
137 
138  vlib_get_buffers (vm, from, bufs, n_left_from);
139  b = bufs;
140  next = nexts;
141 
142  clib_memset_u16 (nexts, im->esp4_decrypt_next_index, n_left_from);
143 
144  u64 n_bytes = 0, n_packets = 0;
145  u32 n_disabled = 0, n_no_tunnel = 0;
146 
147  u32 last_sw_if_index = ~0;
148  ipsec_tun_lkup_result_t last_result = {
149  .tun_index = ~0
150  };
151  ipsec4_tunnel_key_t last_key4;
152  ipsec6_tunnel_key_t last_key6;
153 
154  vlib_combined_counter_main_t *rx_counter;
155  vlib_combined_counter_main_t *drop_counter;
156  ipsec_tun_protect_t *itp0;
157 
158  if (is_ip6)
159  clib_memset (&last_key6, 0xff, sizeof (last_key6));
160  else
161  last_key4.as_u64 = ~0;
162 
165 
166  while (n_left_from > 0)
167  {
168  u32 sw_if_index0, len0, hdr_sz0;
170  ipsec4_tunnel_key_t key40;
171  ipsec6_tunnel_key_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  if (is_ip6)
181  {
182  ip60 = (ip6_header_t *) ip40;
183  esp0 = (esp_header_t *) (ip60 + 1);
184  hdr_sz0 = sizeof (ip6_header_t);
185  }
186  else
187  {
188  /* NAT UDP port 4500 case, don't advance any more */
189  if (ip40->protocol == IP_PROTOCOL_UDP)
190  {
191  esp0 =
192  (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40) +
193  sizeof (udp_header_t));
194  hdr_sz0 = 0;
195  buf_rewind0 = ip4_header_bytes (ip40) + sizeof (udp_header_t);
196  }
197  else
198  {
199  esp0 = (esp_header_t *) ((u8 *) ip40 + ip4_header_bytes (ip40));
200  buf_rewind0 = hdr_sz0 = ip4_header_bytes (ip40);
201  }
202  }
203 
204  /* stats for the tunnel include all the data after the IP header
205  just like a norml IP-IP tunnel */
206  vlib_buffer_advance (b[0], hdr_sz0);
207  len0 = vlib_buffer_length_in_chain (vm, b[0]);
208 
209  if (len0 < sizeof (esp_header_t))
210  {
211  if (esp0->spi_bytes[0] == 0xff)
212  b[0]->error =
213  node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_NAT_KEEPALIVE];
214  else
215  b[0]->error =
216  node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_TOO_SHORT];
217 
218  next[0] = IPSEC_INPUT_NEXT_DROP;
219  goto trace00;
220  }
221 
222  if (is_ip6)
223  {
224  key60.remote_ip = ip60->src_address;
225  key60.spi = esp0->spi;
226 
227  if (memcmp (&key60, &last_key6, sizeof (last_key6)) == 0)
228  {
229  itr0 = last_result;
230  }
231  else
232  {
233  uword *p = hash_get_mem (im->tun6_protect_by_key, &key60);
234  if (p)
235  {
236  itr0.as_u64 = p[0];
237  last_result = itr0;
238  clib_memcpy_fast (&last_key6, &key60, sizeof (key60));
239  }
240  else
241  {
242  next[0] = ipsec_ip6_if_no_tunnel (node, b[0], esp0);
243  n_no_tunnel++;
244  goto trace00;
245  }
246  }
247  }
248  else
249  {
250  key40.remote_ip = ip40->src_address;
251  key40.spi = esp0->spi;
252 
253  if (key40.as_u64 == last_key4.as_u64)
254  {
255  itr0 = last_result;
256  }
257  else
258  {
259  uword *p = hash_get (im->tun4_protect_by_key, key40.as_u64);
260  if (p)
261  {
262  itr0.as_u64 = p[0];
263  last_result = itr0;
264  last_key4.as_u64 = key40.as_u64;
265  }
266  else
267  {
268  next[0] = ipsec_ip4_if_no_tunnel (node, b[0], esp0, ip40);
269  vlib_buffer_advance (b[0], -buf_rewind0);
270  n_no_tunnel++;
271  goto trace00;
272  }
273  }
274  }
275 
277  vnet_buffer (b[0])->ipsec.sad_index = itr0.sa_index;
278  vnet_buffer (b[0])->ipsec.protect_index = itr0.tun_index;
279 
280  sw_if_index0 = itp0->itp_sw_if_index;
281  vnet_buffer (b[0])->sw_if_index[VLIB_RX] = sw_if_index0;
282 
283  if (PREDICT_FALSE (!vnet_sw_interface_is_admin_up (vnm, sw_if_index0)))
284  {
286  (drop_counter, thread_index, sw_if_index0, 1, len0);
287  n_disabled++;
288  b[0]->error = node->errors[IPSEC_TUN_PROTECT_INPUT_ERROR_DISABLED];
289  next[0] = IPSEC_INPUT_NEXT_DROP;
290  goto trace00;
291  }
292  else
293  {
294  if (PREDICT_TRUE (sw_if_index0 == last_sw_if_index))
295  {
296  n_packets++;
297  n_bytes += len0;
298  }
299  else
300  {
301  if (n_packets && !(itp0->itp_flags & IPSEC_PROTECT_ENCAPED))
302  {
304  (rx_counter, thread_index, last_sw_if_index,
305  n_packets, n_bytes);
306  }
307 
308  last_sw_if_index = sw_if_index0;
309  n_packets = 1;
310  n_bytes = len0;
311  }
312 
313  next[0] = im->esp4_decrypt_tun_next_index; //IPSEC_TUN_PROTECT_NEXT_DECRYPT;
314  }
315  trace00:
316  if (PREDICT_FALSE (is_trace))
317  {
318  if (b[0]->flags & VLIB_BUFFER_IS_TRACED)
319  {
321  vlib_add_trace (vm, node, b[0], sizeof (*tr));
322  if (is_ip6)
323  clib_memcpy (&tr->key6, &key60, sizeof (tr->key6));
324  else
325  clib_memcpy (&tr->key4, &key40, sizeof (tr->key4));
326  tr->is_ip6 = is_ip6;
327  tr->seq = (len0 >= sizeof (*esp0) ?
328  clib_host_to_net_u32 (esp0->seq) : ~0);
329  tr->sa_index = vnet_buffer (b[0])->ipsec.sad_index;
330  }
331  }
332 
333  /* next */
334  b += 1;
335  next += 1;
336  n_left_from -= 1;
337  }
338 
339  if (n_packets && !(itp0->itp_flags & IPSEC_PROTECT_ENCAPED))
340  {
342  thread_index,
343  last_sw_if_index, n_packets, n_bytes);
344  }
345 
347  IPSEC_TUN_PROTECT_INPUT_ERROR_RX,
348  from_frame->n_vectors - (n_disabled +
349  n_no_tunnel));
351  IPSEC_TUN_PROTECT_INPUT_ERROR_NO_TUNNEL,
352  n_no_tunnel);
353 
354  vlib_buffer_enqueue_to_next (vm, node, from, nexts, from_frame->n_vectors);
355 
356  return from_frame->n_vectors;
357 }
358 
361  vlib_frame_t * from_frame)
362 {
363  return ipsec_tun_protect_input_inline (vm, node, from_frame, 0);
364 }
365 
366 /* *INDENT-OFF* */
368  .name = "ipsec4-tun-input",
369  .vector_size = sizeof (u32),
370  .format_trace = format_ipsec_tun_protect_input_trace,
373  .error_strings = ipsec_tun_protect_input_error_strings,
374  .n_next_nodes = IPSEC_TUN_PROTECT_N_NEXT,
375  .next_nodes = {
376  [IPSEC_TUN_PROTECT_NEXT_DROP] = "ip4-drop",
377  [IPSEC_TUN_PROTECT_NEXT_PUNT] = "punt-dispatch",
378  }
379 };
380 /* *INDENT-ON* */
381 
384  vlib_frame_t * from_frame)
385 {
386  return ipsec_tun_protect_input_inline (vm, node, from_frame, 1);
387 }
388 
389 /* *INDENT-OFF* */
391  .name = "ipsec6-tun-input",
392  .vector_size = sizeof (u32),
393  .format_trace = format_ipsec_tun_protect_input_trace,
396  .error_strings = ipsec_tun_protect_input_error_strings,
397  .n_next_nodes = IPSEC_TUN_PROTECT_N_NEXT,
398  .next_nodes = {
399  [IPSEC_TUN_PROTECT_NEXT_DROP] = "ip6-drop",
400  [IPSEC_TUN_PROTECT_NEXT_PUNT] = "punt-dispatch",
401  }
402 };
403 /* *INDENT-ON* */
404 
405 /*
406  * fd.io coding-style-patch-verification: ON
407  *
408  * Local Variables:
409  * eval: (c-set-style "gnu")
410  * End:
411  */
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:111
#define CLIB_UNUSED(x)
Definition: clib.h:86
uword * tun6_protect_by_key
Definition: ipsec.h:129
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:220
ip4_address_t src_address
Definition: ip4_packet.h:170
ipsec_tun_protect_input_error_t
Definition: ipsec_tun_in.c:45
ipsec6_tunnel_key_t key6
Definition: ipsec_tun_in.c:66
vnet_interface_main_t interface_main
Definition: vnet.h:56
#define PREDICT_TRUE(x)
Definition: clib.h:119
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)
ipsec_tun_next_t_
Definition: ipsec_tun_in.c:53
u32 thread_index
Definition: main.h:218
u8 * format_ipsec6_tunnel_key(u8 *s, va_list *args)
Definition: ipsec_format.c:396
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define VLIB_NODE_FN(node)
Definition: node.h:202
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:472
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:91
unsigned char u8
Definition: types.h:56
ipsec4_tunnel_key_t key4
Definition: ipsec_tun_in.c:65
#define clib_memcpy(d, s, n)
Definition: string.h:180
u32 esp4_decrypt_tun_next_index
Definition: ipsec.h:148
ipsec_main_t ipsec_main
Definition: ipsec.c:28
vlib_combined_counter_main_t * combined_sw_if_counters
Definition: interface.h:867
u32 esp4_decrypt_next_index
Definition: ipsec.h:147
vlib_node_registration_t ipsec4_tun_input_node
(constructor) VLIB_REGISTER_NODE (ipsec4_tun_input_node)
Definition: ipsec_tun_in.c:367
unsigned int u32
Definition: types.h:88
#define VLIB_FRAME_SIZE
Definition: node.h:380
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
#define hash_get(h, key)
Definition: hash.h:249
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:534
ipsec_tun_protect_t * ipsec_tun_protect_pool
Pool of tunnel protection objects.
Definition: ipsec_tun.c:33
vnet_main_t * vnet_main
Definition: ipsec.h:118
unsigned short u16
Definition: types.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:118
#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:498
vlib_main_t * vm
Definition: in2out_ed.c:1599
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
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:169
u32 flags
Definition: vhost_user.h:248
u16 n_vectors
Definition: node.h:399
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
u8 spi_bytes[4]
Definition: esp.h:27
enum ipsec_tun_next_t_ ipsec_tun_next_t
#define ARRAY_LEN(x)
Definition: clib.h:66
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1599
u8 data[128]
Definition: ipsec_types.api:89
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:248
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:121
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 void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
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:244
ipsec_protect_flags_t itp_flags
Definition: ipsec_tun.h:78
vlib_node_registration_t ipsec6_tun_input_node
(constructor) VLIB_REGISTER_NODE (ipsec6_tun_input_node)
Definition: ipsec_tun_in.c:390
A collection of combined counters.
Definition: counter.h:188
#define hash_get_mem(h, key)
Definition: hash.h:269
#define vnet_buffer(b)
Definition: buffer.h:417
u16 flags
Copy of main node flags.
Definition: node.h:511
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:235
u8 * format_ipsec4_tunnel_key(u8 *s, va_list *args)
Definition: ipsec_format.c:383
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:304
static u8 * format_ipsec_tun_protect_input_trace(u8 *s, va_list *args)
Definition: ipsec_tun_in.c:74
#define foreach_ipsec_input_next
Definition: ipsec_io.h:29
Definition: defs.h:46
uword * tun4_protect_by_key
Definition: ipsec.h:128