FD.io VPP  v19.01.1-17-ge106252
Vector Packet Processing
ipsec_input.c
Go to the documentation of this file.
1 /*
2  * decap.c : IPSec tunnel decapsulation
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 #include <vnet/feature/feature.h>
22 
23 #include <vnet/ipsec/ipsec.h>
24 #include <vnet/ipsec/esp.h>
25 #include <vnet/ipsec/ah.h>
26 
27 #define foreach_ipsec_input_error \
28  _(RX_PKTS, "IPSEC pkts received") \
29  _(DECRYPTION_FAILED, "IPSEC decryption failed")
30 
31 typedef enum
32 {
33 #define _(sym,str) IPSEC_INPUT_ERROR_##sym,
35 #undef _
38 
39 static char *ipsec_input_error_strings[] = {
40 #define _(sym,string) string,
42 #undef _
43 };
44 
45 typedef struct
46 {
52 
53 /* packet trace format function */
54 static u8 *
55 format_ipsec_input_trace (u8 * s, va_list * args)
56 {
57  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
58  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
59  ipsec_input_trace_t *t = va_arg (*args, ipsec_input_trace_t *);
60 
61  if (t->spi == 0 && t->seq == 0)
62  {
63  s = format (s, "esp: no esp packet");
64  return s;
65  }
66 
67  if (t->sa_id != 0)
68  {
69  s =
70  format (s, "esp: sa_id %u spd %u spi %u seq %u", t->sa_id, t->spd,
71  t->spi, t->seq);
72  }
73  else
74  {
75  s =
76  format (s, "esp: no sa spd %u spi %u seq %u", t->spd, t->spi, t->seq);
77  }
78  return s;
79 }
80 
83 {
84  ipsec_main_t *im = &ipsec_main;
85  ipsec_policy_t *p;
86  ipsec_sa_t *s;
87  u32 *i;
88 
90  {
91  p = pool_elt_at_index (spd->policies, *i);
92  s = pool_elt_at_index (im->sad, p->sa_index);
93 
94  if (spi != s->spi)
95  continue;
96 
97  if (s->is_tunnel)
98  {
99  if (da != clib_net_to_host_u32 (s->tunnel_dst_addr.ip4.as_u32))
100  continue;
101 
102  if (sa != clib_net_to_host_u32 (s->tunnel_src_addr.ip4.as_u32))
103  continue;
104 
105  return p;
106  }
107 
108  if (da < clib_net_to_host_u32 (p->laddr.start.ip4.as_u32))
109  continue;
110 
111  if (da > clib_net_to_host_u32 (p->laddr.stop.ip4.as_u32))
112  continue;
113 
114  if (sa < clib_net_to_host_u32 (p->raddr.start.ip4.as_u32))
115  continue;
116 
117  if (sa > clib_net_to_host_u32 (p->raddr.stop.ip4.as_u32))
118  continue;
119 
120  return p;
121  }
122  return 0;
123 }
124 
127  ip6_address_t * ua)
128 {
129  if ((memcmp (a->as_u64, la->as_u64, 2 * sizeof (u64)) >= 0) &&
130  (memcmp (a->as_u64, ua->as_u64, 2 * sizeof (u64)) <= 0))
131  return 1;
132  return 0;
133 }
134 
137  ip6_address_t * sa,
138  ip6_address_t * da, u32 spi)
139 {
140  ipsec_main_t *im = &ipsec_main;
141  ipsec_policy_t *p;
142  ipsec_sa_t *s;
143  u32 *i;
144 
146  {
147  p = pool_elt_at_index (spd->policies, *i);
148  s = pool_elt_at_index (im->sad, p->sa_index);
149 
150  if (spi != s->spi)
151  continue;
152 
153  if (s->is_tunnel)
154  {
155  if (!ip6_address_is_equal (sa, &s->tunnel_src_addr.ip6))
156  continue;
157 
158  if (!ip6_address_is_equal (da, &s->tunnel_dst_addr.ip6))
159  continue;
160 
161  return p;
162  }
163 
164  if (!ip6_addr_match_range (sa, &p->raddr.start.ip6, &p->raddr.stop.ip6))
165  continue;
166 
167  if (!ip6_addr_match_range (da, &p->laddr.start.ip6, &p->laddr.stop.ip6))
168  continue;
169 
170  return p;
171  }
172  return 0;
173 }
174 
176 
178  vlib_node_runtime_t * node,
179  vlib_frame_t * from_frame)
180 {
181  u32 n_left_from, *from, next_index, *to_next;
182  ipsec_main_t *im = &ipsec_main;
183 
184  from = vlib_frame_vector_args (from_frame);
185  n_left_from = from_frame->n_vectors;
186 
187  next_index = node->cached_next_index;
188 
189  while (n_left_from > 0)
190  {
191  u32 n_left_to_next;
192 
193  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
194 
195  while (n_left_from > 0 && n_left_to_next > 0)
196  {
197  u32 bi0, next0;
198  vlib_buffer_t *b0;
199  ip4_header_t *ip0;
200  esp_header_t *esp0;
201  ah_header_t *ah0;
202  ip4_ipsec_config_t *c0;
203  ipsec_spd_t *spd0;
204  ipsec_policy_t *p0 = 0;
205 
206  bi0 = to_next[0] = from[0];
207  from += 1;
208  n_left_from -= 1;
209  to_next += 1;
210  n_left_to_next -= 1;
211 
212  b0 = vlib_get_buffer (vm, bi0);
213  b0->flags |= VNET_BUFFER_F_IS_IP4;
214  b0->flags &= ~VNET_BUFFER_F_IS_IP6;
215  c0 = vnet_feature_next_with_data (&next0, b0, sizeof (c0[0]));
216 
217  spd0 = pool_elt_at_index (im->spds, c0->spd_index);
218 
219  ip0 = vlib_buffer_get_current (b0);
220 
221  if (PREDICT_TRUE
222  (ip0->protocol == IP_PROTOCOL_IPSEC_ESP
223  || ip0->protocol == IP_PROTOCOL_UDP))
224  {
225 #if 0
227  ("packet received from %U to %U spi %u size %u spd_id %u",
230  clib_net_to_host_u32 (esp0->spi),
231  clib_net_to_host_u16 (ip0->length), spd0->id);
232 #endif
233 
234  esp0 = (esp_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0));
235  if (PREDICT_FALSE (ip0->protocol == IP_PROTOCOL_UDP))
236  {
237  esp0 =
238  (esp_header_t *) ((u8 *) esp0 + sizeof (udp_header_t));
239  }
240  /* FIXME TODO missing check whether there is enough data inside
241  * IP/UDP to contain ESP header & stuff ? */
243  clib_net_to_host_u32
244  (ip0->src_address.
245  as_u32),
246  clib_net_to_host_u32
247  (ip0->dst_address.
248  as_u32),
249  clib_net_to_host_u32
250  (esp0->spi));
251 
252  if (PREDICT_TRUE (p0 != 0))
253  {
254  p0->counter.packets++;
255  p0->counter.bytes += clib_net_to_host_u16 (ip0->length);
256  vnet_buffer (b0)->ipsec.sad_index = p0->sa_index;
257  vnet_buffer (b0)->ipsec.flags = 0;
258  next0 = im->esp4_decrypt_next_index;
259  vlib_buffer_advance (b0, ((u8 *) esp0 - (u8 *) ip0));
260  goto trace0;
261  }
262 
263  /* FIXME bypass and discard */
264  trace0:
265  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
266  {
267  ipsec_input_trace_t *tr =
268  vlib_add_trace (vm, node, b0, sizeof (*tr));
269  if (ip0->protocol == IP_PROTOCOL_IPSEC_ESP ||
270  ip0->protocol == IP_PROTOCOL_UDP)
271  {
272  if (p0)
273  tr->sa_id = p0->sa_id;
274  tr->spi = clib_host_to_net_u32 (esp0->spi);
275  tr->seq = clib_host_to_net_u32 (esp0->seq);
276  tr->spd = spd0->id;
277  }
278  }
279 
280  }
281 
282 
283  if (PREDICT_TRUE (ip0->protocol == IP_PROTOCOL_IPSEC_AH))
284  {
285  ah0 = (ah_header_t *) ((u8 *) ip0 + ip4_header_bytes (ip0));
287  clib_net_to_host_u32
288  (ip0->src_address.
289  as_u32),
290  clib_net_to_host_u32
291  (ip0->dst_address.
292  as_u32),
293  clib_net_to_host_u32
294  (ah0->spi));
295 
296  if (PREDICT_TRUE (p0 != 0))
297  {
298  p0->counter.packets++;
299  p0->counter.bytes += clib_net_to_host_u16 (ip0->length);
300  vnet_buffer (b0)->ipsec.sad_index = p0->sa_index;
301  vnet_buffer (b0)->ipsec.flags = 0;
302  next0 = im->ah4_decrypt_next_index;
303  goto trace1;
304  }
305  /* FIXME bypass and discard */
306  trace1:
307  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
308  {
309  ipsec_input_trace_t *tr =
310  vlib_add_trace (vm, node, b0, sizeof (*tr));
311  if (ip0->protocol == IP_PROTOCOL_IPSEC_ESP)
312  {
313  if (p0)
314  tr->sa_id = p0->sa_id;
315  tr->spi = clib_host_to_net_u32 (ah0->spi);
316  tr->seq = clib_host_to_net_u32 (ah0->seq_no);
317  tr->spd = spd0->id;
318  }
319  }
320  }
321 
322  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
323  to_next, n_left_to_next, bi0,
324  next0);
325  }
326  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
327  }
329  IPSEC_INPUT_ERROR_RX_PKTS,
330  from_frame->n_vectors);
331 
332  return from_frame->n_vectors;
333 }
334 
335 
336 /* *INDENT-OFF* */
338  .name = "ipsec4-input-feature",
339  .vector_size = sizeof (u32),
340  .format_trace = format_ipsec_input_trace,
341  .type = VLIB_NODE_TYPE_INTERNAL,
342 
344  .error_strings = ipsec_input_error_strings,
345 
346  .n_next_nodes = IPSEC_INPUT_N_NEXT,
347  .next_nodes = {
348 #define _(s,n) [IPSEC_INPUT_NEXT_##s] = n,
350 #undef _
351  },
352 };
353 /* *INDENT-ON* */
354 
356 
357 
359  vlib_node_runtime_t * node,
360  vlib_frame_t * from_frame)
361 {
362  u32 n_left_from, *from, next_index, *to_next;
363  ipsec_main_t *im = &ipsec_main;
364 
365  from = vlib_frame_vector_args (from_frame);
366  n_left_from = from_frame->n_vectors;
367 
368  next_index = node->cached_next_index;
369 
370  while (n_left_from > 0)
371  {
372  u32 n_left_to_next;
373 
374  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
375 
376  while (n_left_from > 0 && n_left_to_next > 0)
377  {
378  u32 bi0, next0;
379  vlib_buffer_t *b0;
380  ip6_header_t *ip0;
381  esp_header_t *esp0;
382  ip4_ipsec_config_t *c0;
383  ipsec_spd_t *spd0;
384  ipsec_policy_t *p0 = 0;
385  ah_header_t *ah0;
386  u32 header_size = sizeof (ip0[0]);
387 
388  bi0 = to_next[0] = from[0];
389  from += 1;
390  n_left_from -= 1;
391  to_next += 1;
392  n_left_to_next -= 1;
393 
394  b0 = vlib_get_buffer (vm, bi0);
395  b0->flags |= VNET_BUFFER_F_IS_IP6;
396  b0->flags &= ~VNET_BUFFER_F_IS_IP4;
397  c0 = vnet_feature_next_with_data (&next0, b0, sizeof (c0[0]));
398 
399  spd0 = pool_elt_at_index (im->spds, c0->spd_index);
400 
401  ip0 = vlib_buffer_get_current (b0);
402  esp0 = (esp_header_t *) ((u8 *) ip0 + header_size);
403  ah0 = (ah_header_t *) ((u8 *) ip0 + header_size);
404 
405  if (PREDICT_TRUE (ip0->protocol == IP_PROTOCOL_IPSEC_ESP))
406  {
407 #if 0
409  ("packet received from %U to %U spi %u size %u spd_id %u",
411  &ip0->dst_address, clib_net_to_host_u32 (esp0->spi),
412  clib_net_to_host_u16 (ip0->payload_length) + header_size,
413  spd0->id);
414 #endif
416  &ip0->src_address,
417  &ip0->dst_address,
418  clib_net_to_host_u32
419  (esp0->spi));
420 
421  if (PREDICT_TRUE (p0 != 0))
422  {
423  p0->counter.packets++;
424  p0->counter.bytes +=
425  clib_net_to_host_u16 (ip0->payload_length);
426  p0->counter.bytes += header_size;
427  vnet_buffer (b0)->ipsec.sad_index = p0->sa_index;
428  vnet_buffer (b0)->ipsec.flags = 0;
429  next0 = im->esp6_decrypt_next_index;
430  vlib_buffer_advance (b0, header_size);
431  goto trace0;
432  }
433  }
434  else if (ip0->protocol == IP_PROTOCOL_IPSEC_AH)
435  {
437  &ip0->src_address,
438  &ip0->dst_address,
439  clib_net_to_host_u32
440  (ah0->spi));
441 
442  if (PREDICT_TRUE (p0 != 0))
443  {
444  p0->counter.packets++;
445  p0->counter.bytes +=
446  clib_net_to_host_u16 (ip0->payload_length);
447  p0->counter.bytes += header_size;
448  vnet_buffer (b0)->ipsec.sad_index = p0->sa_index;
449  vnet_buffer (b0)->ipsec.flags = 0;
450  next0 = im->ah6_decrypt_next_index;
451  goto trace0;
452  }
453  }
454 
455  trace0:
456  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
457  {
458  ipsec_input_trace_t *tr =
459  vlib_add_trace (vm, node, b0, sizeof (*tr));
460  if (ip0->protocol == IP_PROTOCOL_IPSEC_ESP)
461  {
462  if (p0)
463  tr->sa_id = p0->sa_id;
464  tr->spi = clib_host_to_net_u32 (esp0->spi);
465  tr->seq = clib_host_to_net_u32 (esp0->seq);
466  tr->spd = spd0->id;
467  }
468  }
469 
470  vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
471  n_left_to_next, bi0, next0);
472  }
473  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
474  }
476  IPSEC_INPUT_ERROR_RX_PKTS,
477  from_frame->n_vectors);
478 
479  return from_frame->n_vectors;
480 }
481 
482 
483 /* *INDENT-OFF* */
485  .name = "ipsec6-input-feature",
486  .vector_size = sizeof (u32),
487  .format_trace = format_ipsec_input_trace,
488  .type = VLIB_NODE_TYPE_INTERNAL,
489 
491  .error_strings = ipsec_input_error_strings,
492 
493  .sibling_of = "ipsec4-input-feature",
494 };
495 /* *INDENT-ON* */
496 
497 /*
498  * fd.io coding-style-patch-verification: ON
499  *
500  * Local Variables:
501  * eval: (c-set-style "gnu")
502  * End:
503  */
ip46_address_t stop
Definition: ipsec.h:158
static char * ipsec_input_error_strings[]
Definition: ipsec_input.c:39
u32 * ipv6_inbound_protect_policy_indices
Definition: ipsec.h:241
ipsec_spd_t * spds
Definition: ipsec.h:352
u32 * ipv4_inbound_protect_policy_indices
Definition: ipsec.h:239
#define CLIB_UNUSED(x)
Definition: clib.h:82
ip46_address_t tunnel_src_addr
Definition: ipsec.h:139
u32 ah4_decrypt_next_index
Definition: ipsec.h:391
a
Definition: bitmap.h:538
ip4_address_t src_address
Definition: ip4_packet.h:170
#define PREDICT_TRUE(x)
Definition: clib.h:112
u64 as_u64[2]
Definition: ip6_packet.h:51
unsigned long u64
Definition: types.h:89
static ipsec_policy_t * ipsec_input_protect_policy_match(ipsec_spd_t *spd, u32 sa, u32 da, u32 spi)
Definition: ipsec_input.c:82
u8 is_tunnel
Definition: ipsec.h:136
int i
static uword ip6_addr_match_range(ip6_address_t *a, ip6_address_t *la, ip6_address_t *ua)
Definition: ipsec_input.c:126
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
#define VLIB_NODE_FN(node)
Definition: node.h:201
static vlib_node_registration_t ipsec6_input_node
(constructor) VLIB_REGISTER_NODE (ipsec6_input_node)
Definition: ipsec_input.c:355
static u8 * format_ipsec_input_trace(u8 *s, va_list *args)
Definition: ipsec_input.c:55
ip6_address_t src_address
Definition: ip6_packet.h:378
unsigned char u8
Definition: types.h:56
u32 spi
Definition: ipsec.h:122
format_function_t format_ip4_address
Definition: format.h:75
ipsec_main_t ipsec_main
Definition: ipsec.c:30
unsigned int seq_no
Definition: ah.h:33
#define always_inline
Definition: clib.h:98
ip4_address_t dst_address
Definition: ip4_packet.h:170
u32 esp4_decrypt_next_index
Definition: ipsec.h:389
#define foreach_ipsec_input_next
Definition: ipsec.h:45
unsigned int u32
Definition: types.h:88
ipsec_policy_t * policies
Definition: ipsec.h:235
static_always_inline void * vnet_feature_next_with_data(u32 *next0, vlib_buffer_t *b0, u32 n_data_bytes)
Definition: feature.h:282
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:511
counter_t packets
packet counter
Definition: counter_types.h:28
ipsec_input_error_t
Definition: ipsec_input.c:31
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:214
#define PREDICT_FALSE(x)
Definition: clib.h:111
static vlib_node_registration_t ipsec4_input_node
(constructor) VLIB_REGISTER_NODE (ipsec4_input_node)
Definition: ipsec_input.c:175
ip46_address_range_t laddr
Definition: ipsec.h:216
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Finish enqueueing one buffer forward in the graph.
Definition: buffer_node.h:218
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Get pointer to next frame vector data by (vlib_node_runtime_t, next_index).
Definition: node_funcs.h:368
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1180
ip46_address_t tunnel_dst_addr
Definition: ipsec.h:140
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
format_function_t format_ip6_address
Definition: format.h:93
vlib_main_t * vm
Definition: buffer.c:301
u32 sa_index
Definition: ipsec.h:225
ip46_address_t start
Definition: ipsec.h:158
#define clib_warning(format, args...)
Definition: error.h:59
u32 esp6_decrypt_next_index
Definition: ipsec.h:393
#define ARRAY_LEN(x)
Definition: clib.h:62
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Release pointer to next frame vector data.
Definition: main.c:459
ip46_address_range_t raddr
Definition: ipsec.h:217
ipsec_sa_t * sad
Definition: ipsec.h:353
u32 seq
Definition: esp.h:24
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:233
static uword ip6_address_is_equal(const ip6_address_t *a, const ip6_address_t *b)
Definition: ip6_packet.h:235
u32 spi
Definition: esp.h:23
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:57
struct _vlib_node_registration vlib_node_registration_t
counter_t bytes
byte counter
Definition: counter_types.h:29
#define foreach_ipsec_input_error
Definition: ipsec_input.c:27
u32 ah6_decrypt_next_index
Definition: ipsec.h:395
u16 payload_length
Definition: ip6_packet.h:369
vlib_counter_t counter
Definition: ipsec.h:228
u64 uword
Definition: types.h:112
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:274
u32 id
Definition: ipsec.h:233
#define vnet_buffer(b)
Definition: buffer.h:368
Definition: ah.h:27
#define vec_foreach(var, vec)
Vector iterator.
static int ip4_header_bytes(const ip4_header_t *i)
Definition: ip4_packet.h:235
unsigned int spi
Definition: ah.h:32
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:117
static ipsec_policy_t * ipsec6_input_protect_policy_match(ipsec_spd_t *spd, ip6_address_t *sa, ip6_address_t *da, u32 spi)
Definition: ipsec_input.c:136
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:62
ip6_address_t dst_address
Definition: ip6_packet.h:378