FD.io VPP  v18.07-rc0-415-g6c78436
Vector Packet Processing
node.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /**
16  * @file
17  * @brief L2-GRE over IPSec packet processing.
18  *
19  * Removes GRE header from the packet and sends it to the l2-input node.
20 */
21 
22 #include <vlib/vlib.h>
23 #include <vnet/pg/pg.h>
25 #include <vppinfra/sparse_vec.h>
26 
27 #define foreach_ipsec_gre_input_next \
28 _(PUNT, "error-punt") \
29 _(DROP, "error-drop") \
30 _(L2_INPUT, "l2-input")
31 
32 typedef enum {
33 #define _(s,n) IPSEC_GRE_INPUT_NEXT_##s,
35 #undef _
38 
39 typedef struct {
45 
46 u8 * format_ipsec_gre_rx_trace (u8 * s, va_list * args)
47 {
48  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50  ipsec_gre_rx_trace_t * t = va_arg (*args, ipsec_gre_rx_trace_t *);
51 
52  s = format (s, "GRE: tunnel %d len %d src %U dst %U",
53  t->tunnel_id, clib_net_to_host_u16(t->length),
56  return s;
57 }
58 
59 /**
60  * @brief L2-GRE over IPSec input node.
61  * @node ipsec-gre-input
62  *
63  * This node remove GRE header.
64  *
65  * @param vm vlib_main_t corresponding to the current thread.
66  * @param node vlib_node_runtime_t data for this node.
67  * @param from_frame vlib_frame_t whose contents should be dispatched.
68  *
69  * @par Graph mechanics: buffer metadata, next index usage
70  *
71  * <em>Uses:</em>
72  * - <code>ip->src_address</code> and <code>ip->dst_address</code>
73  * - Match tunnel by source and destination addresses in GRE IP header.
74  *
75  * <em>Sets:</em>
76  * - <code>vnet_buffer(b)->gre.src</code>
77  * - Save tunnel source IPv4 address.
78  * - <code>vnet_buffer(b)->gre.dst</code>
79  * - Save tunnel destination IPv4 address.
80  * - <code>vnet_buffer(b)->sw_if_index[VLIB_RX]</code>
81  * - Set input sw_if_index to IPSec-GRE tunnel for learning.
82  *
83  * <em>Next Index:</em>
84  * - Dispatches the packet to the l2-input node.
85 */
86 static uword
88  vlib_node_runtime_t * node,
89  vlib_frame_t * from_frame)
90 {
92  u32 n_left_from, next_index, * from, * to_next;
93  u64 cached_tunnel_key = (u64) ~0;
94  u32 cached_tunnel_sw_if_index = 0, tunnel_sw_if_index;
95  u32 tun_src0, tun_dst0;
96  u32 tun_src1, tun_dst1;
97 
98  from = vlib_frame_vector_args (from_frame);
99  n_left_from = from_frame->n_vectors;
100 
101  next_index = node->cached_next_index;
102 
103  while (n_left_from > 0)
104  {
105  u32 n_left_to_next;
106 
107  vlib_get_next_frame (vm, node, next_index,
108  to_next, n_left_to_next);
109 
110  while (n_left_from >= 4 && n_left_to_next >= 2)
111  {
112  u32 bi0, bi1;
113  vlib_buffer_t * b0, * b1;
114  gre_header_t * h0, * h1;
115  u16 version0, version1, protocol0, protocol1;
116  int verr0, verr1;
117  u32 next0, next1;
118  ip4_header_t *ip0, *ip1;
119 
120  /* Prefetch next iteration. */
121  {
122  vlib_buffer_t * p2, * p3;
123 
124  p2 = vlib_get_buffer (vm, from[2]);
125  p3 = vlib_get_buffer (vm, from[3]);
126 
127  vlib_prefetch_buffer_header (p2, LOAD);
128  vlib_prefetch_buffer_header (p3, LOAD);
129 
130  CLIB_PREFETCH (p2->data, sizeof (h0[0]), LOAD);
131  CLIB_PREFETCH (p3->data, sizeof (h1[0]), LOAD);
132  }
133 
134  bi0 = from[0];
135  bi1 = from[1];
136  to_next[0] = bi0;
137  to_next[1] = bi1;
138  from += 2;
139  to_next += 2;
140  n_left_to_next -= 2;
141  n_left_from -= 2;
142 
143  b0 = vlib_get_buffer (vm, bi0);
144  b1 = vlib_get_buffer (vm, bi1);
145 
146  /* ip4_local hands us the ip header, not the gre header */
147  ip0 = vlib_buffer_get_current (b0);
148  ip1 = vlib_buffer_get_current (b1);
149 
150  /* Save src + dst ip4 address */
151  tun_src0 = ip0->src_address.as_u32;
152  tun_dst0 = ip0->dst_address.as_u32;
153  tun_src1 = ip1->src_address.as_u32;
154  tun_dst1 = ip1->dst_address.as_u32;
155 
156  vlib_buffer_advance (b0, sizeof (*ip0));
157  vlib_buffer_advance (b1, sizeof (*ip1));
158 
159  h0 = vlib_buffer_get_current (b0);
160  h1 = vlib_buffer_get_current (b1);
161 
162  protocol0 = clib_net_to_host_u16 (h0->protocol);
163  protocol1 = clib_net_to_host_u16 (h1->protocol);
164  if (PREDICT_TRUE(protocol0 == 0x0001))
165  {
166  next0 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
167  b0->error = node->errors[IPSEC_GRE_ERROR_NONE];
168  }
169  else
170  {
171  clib_warning("unknown GRE protocol: %d", protocol0);
172  b0->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
173  next0 = IPSEC_GRE_INPUT_NEXT_DROP;
174  }
175  if (PREDICT_TRUE(protocol1 == 0x0001))
176  {
177  next1 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
178  b1->error = node->errors[IPSEC_GRE_ERROR_NONE];
179  }
180  else
181  {
182  clib_warning("unknown GRE protocol: %d", protocol1);
183  b1->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
184  next1 = IPSEC_GRE_INPUT_NEXT_DROP;
185  }
186 
187  version0 = clib_net_to_host_u16 (h0->flags_and_version);
188  verr0 = version0 & GRE_VERSION_MASK;
189  version1 = clib_net_to_host_u16 (h1->flags_and_version);
190  verr1 = version1 & GRE_VERSION_MASK;
191 
192  b0->error = verr0 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
193  : b0->error;
194  next0 = verr0 ? IPSEC_GRE_INPUT_NEXT_DROP : next0;
195  b1->error = verr1 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
196  : b1->error;
197  next1 = verr1 ? IPSEC_GRE_INPUT_NEXT_DROP : next1;
198 
199  /* For L2 payload set input sw_if_index to GRE tunnel for learning */
200  if (PREDICT_TRUE(next0 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
201  {
202  u64 key = ((u64)(tun_dst0) << 32) | (u64)(tun_src0);
203 
204  if (cached_tunnel_key != key)
205  {
207  ipsec_gre_tunnel_t * t;
208  uword * p;
209 
210  p = hash_get (igm->tunnel_by_key, key);
211  if (!p)
212  {
213  next0 = IPSEC_GRE_INPUT_NEXT_DROP;
214  b0->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
215  goto drop0;
216  }
217  t = pool_elt_at_index (igm->tunnels, p[0]);
218  hi = vnet_get_hw_interface (igm->vnet_main,
219  t->hw_if_index);
220  tunnel_sw_if_index = hi->sw_if_index;
221  cached_tunnel_sw_if_index = tunnel_sw_if_index;
222  }
223  else
224  {
225  tunnel_sw_if_index = cached_tunnel_sw_if_index;
226  }
227  vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
228  }
229 
230 drop0:
231  /* For L2 payload set input sw_if_index to GRE tunnel for learning */
232  if (PREDICT_TRUE(next1 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
233  {
234  u64 key = ((u64)(tun_dst1) << 32) | (u64)(tun_src1);
235 
236  if (cached_tunnel_key != key)
237  {
239  ipsec_gre_tunnel_t * t;
240  uword * p;
241 
242  p = hash_get (igm->tunnel_by_key, key);
243  if (!p)
244  {
245  next1 = IPSEC_GRE_INPUT_NEXT_DROP;
246  b1->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
247  goto drop1;
248  }
249  t = pool_elt_at_index (igm->tunnels, p[0]);
250  hi = vnet_get_hw_interface (igm->vnet_main,
251  t->hw_if_index);
252  tunnel_sw_if_index = hi->sw_if_index;
253  cached_tunnel_sw_if_index = tunnel_sw_if_index;
254  }
255  else
256  {
257  tunnel_sw_if_index = cached_tunnel_sw_if_index;
258  }
259  vnet_buffer(b1)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
260  }
261 
262 drop1:
263  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
264  {
265  ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
266  b0, sizeof (*tr));
267  tr->tunnel_id = ~0;
268  tr->length = ip0->length;
269  tr->src.as_u32 = ip0->src_address.as_u32;
270  tr->dst.as_u32 = ip0->dst_address.as_u32;
271  }
272 
273  if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
274  {
275  ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
276  b1, sizeof (*tr));
277  tr->tunnel_id = ~0;
278  tr->length = ip1->length;
279  tr->src.as_u32 = ip1->src_address.as_u32;
280  tr->dst.as_u32 = ip1->dst_address.as_u32;
281  }
282 
283  vlib_buffer_advance (b0, sizeof (*h0));
284  vlib_buffer_advance (b1, sizeof (*h1));
285 
286  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
287  to_next, n_left_to_next,
288  bi0, bi1, next0, next1);
289  }
290 
291  while (n_left_from > 0 && n_left_to_next > 0)
292  {
293  u32 bi0;
294  vlib_buffer_t * b0;
295  gre_header_t * h0;
296  ip4_header_t * ip0;
297  u16 version0, protocol0;
298  int verr0;
299  u32 next0;
300  u32 tun_src0, tun_dst0;
301 
302  bi0 = from[0];
303  to_next[0] = bi0;
304  from += 1;
305  to_next += 1;
306  n_left_from -= 1;
307  n_left_to_next -= 1;
308 
309  b0 = vlib_get_buffer (vm, bi0);
310  ip0 = vlib_buffer_get_current (b0);
311 
312  tun_src0 = ip0->src_address.as_u32;
313  tun_dst0 = ip0->dst_address.as_u32;
314 
315  vlib_buffer_advance (b0, sizeof (*ip0));
316 
317  h0 = vlib_buffer_get_current (b0);
318 
319  protocol0 = clib_net_to_host_u16 (h0->protocol);
320  if (PREDICT_TRUE(protocol0 == 0x0001))
321  {
322  next0 = IPSEC_GRE_INPUT_NEXT_L2_INPUT;
323  b0->error = node->errors[IPSEC_GRE_ERROR_NONE];
324  }
325  else
326  {
327  clib_warning("unknown GRE protocol: %d", protocol0);
328  b0->error = node->errors[IPSEC_GRE_ERROR_UNKNOWN_PROTOCOL];
329  next0 = IPSEC_GRE_INPUT_NEXT_DROP;
330  }
331 
332  version0 = clib_net_to_host_u16 (h0->flags_and_version);
333  verr0 = version0 & GRE_VERSION_MASK;
334  b0->error = verr0 ? node->errors[IPSEC_GRE_ERROR_UNSUPPORTED_VERSION]
335  : b0->error;
336  next0 = verr0 ? IPSEC_GRE_INPUT_NEXT_DROP : next0;
337 
338  /* For L2 payload set input sw_if_index to GRE tunnel for learning */
339  if (PREDICT_FALSE(next0 == IPSEC_GRE_INPUT_NEXT_L2_INPUT))
340  {
341  u64 key = ((u64)(tun_dst0) << 32) | (u64)(tun_src0);
342 
343  if (cached_tunnel_key != key)
344  {
346  ipsec_gre_tunnel_t * t;
347  uword * p;
348 
349  p = hash_get (igm->tunnel_by_key, key);
350  if (!p)
351  {
352  next0 = IPSEC_GRE_INPUT_NEXT_DROP;
353  b0->error = node->errors[IPSEC_GRE_ERROR_NO_SUCH_TUNNEL];
354  goto drop;
355  }
356  t = pool_elt_at_index (igm->tunnels, p[0]);
357  hi = vnet_get_hw_interface (igm->vnet_main,
358  t->hw_if_index);
359  tunnel_sw_if_index = hi->sw_if_index;
360  cached_tunnel_sw_if_index = tunnel_sw_if_index;
361  }
362  else
363  {
364  tunnel_sw_if_index = cached_tunnel_sw_if_index;
365  }
366  vnet_buffer(b0)->sw_if_index[VLIB_RX] = tunnel_sw_if_index;
367  }
368 
369 drop:
370  if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
371  {
372  ipsec_gre_rx_trace_t *tr = vlib_add_trace (vm, node,
373  b0, sizeof (*tr));
374  tr->tunnel_id = ~0;
375  tr->length = ip0->length;
376  tr->src.as_u32 = ip0->src_address.as_u32;
377  tr->dst.as_u32 = ip0->dst_address.as_u32;
378  }
379 
380  vlib_buffer_advance (b0, sizeof (*h0));
381 
382  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
383  to_next, n_left_to_next,
384  bi0, next0);
385  }
386 
387  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
388  }
390  IPSEC_GRE_ERROR_PKTS_DECAP, from_frame->n_vectors);
391  return from_frame->n_vectors;
392 }
393 
394 static char * ipsec_gre_error_strings[] = {
395 #define ipsec_gre_error(n,s) s,
396 #include "error.def"
397 #undef ipsec_gre_error
398 };
399 
401  .function = ipsec_gre_input,
402  .name = "ipsec-gre-input",
403  /* Takes a vector of packets. */
404  .vector_size = sizeof (u32),
405 
406  .n_errors = IPSEC_GRE_N_ERROR,
407  .error_strings = ipsec_gre_error_strings,
408 
409  .n_next_nodes = IPSEC_GRE_INPUT_N_NEXT,
410  .next_nodes = {
411 #define _(s,n) [IPSEC_GRE_INPUT_NEXT_##s] = n,
413 #undef _
414  },
415 
416  .format_trace = format_ipsec_gre_rx_trace,
417 };
418 
420 
422 {
423  {
424  clib_error_t * error;
426  if (error)
427  clib_error_report (error);
428  }
429 
430  return 0;
431 }
432 
vmrglw vmrglh hi
#define CLIB_UNUSED(x)
Definition: clib.h:79
vlib_node_registration_t ipsec_gre_input_node
(constructor) VLIB_REGISTER_NODE (ipsec_gre_input_node)
Definition: node.c:400
ip4_address_t src_address
Definition: ip4_packet.h:169
L2-GRE over IPSec packet processing.
#define PREDICT_TRUE(x)
Definition: clib.h:106
unsigned long u64
Definition: types.h:89
static vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:451
static clib_error_t * ipsec_gre_init(vlib_main_t *vm)
Definition: ipsec_gre.c:372
unsigned char u8
Definition: types.h:56
u8 * format_ipsec_gre_rx_trace(u8 *s, va_list *args)
Definition: node.c:46
ipsec_gre_tunnel_t * tunnels
pool of tunnel instances
Definition: ipsec_gre.h:70
static uword ipsec_gre_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
L2-GRE over IPSec input node.
Definition: node.c:87
format_function_t format_ip4_address
Definition: format.h:81
#define foreach_ipsec_gre_input_next
Definition: node.c:27
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
ip4_address_t dst_address
Definition: ip4_packet.h:169
ipsec_gre_main_t ipsec_gre_main
Definition: ipsec_gre.c:25
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:184
#define GRE_VERSION_MASK
Definition: packet.h:52
unsigned int u32
Definition: types.h:88
#define vlib_call_init_function(vm, x)
Definition: init.h:227
ip4_address_t src
Definition: node.c:42
uword * tunnel_by_key
hash mapping src/dst addr pair to tunnel
Definition: ipsec_gre.h:72
#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:461
static clib_error_t * ipsec_gre_input_init(vlib_main_t *vm)
Definition: node.c:421
unsigned short u16
Definition: types.h:57
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:202
ip4_address_t dst
Definition: node.c:43
#define PREDICT_FALSE(x)
Definition: clib.h:105
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Finish enqueueing two buffers forward in the graph.
Definition: buffer_node.h:70
#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:364
u16 flags_and_version
Definition: packet.h:40
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:135
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1168
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:153
L2-GRE over IPSec errors.
u16 n_vectors
Definition: node.h:380
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:77
vlib_main_t * vm
Definition: buffer.c:294
u16 protocol
Definition: packet.h:55
#define clib_warning(format, args...)
Definition: error.h:59
IPSec-GRE state.
Definition: ipsec_gre.h:68
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:454
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:492
IPSec-GRE tunnel parameters.
Definition: ipsec_gre.h:50
static char * ipsec_gre_error_strings[]
Definition: node.c:394
#define clib_error_report(e)
Definition: error.h:113
static void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:215
vnet_main_t * vnet_main
convenience
Definition: ipsec_gre.h:80
ipsec_gre_input_next_t
Definition: node.c:32
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
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:267
#define vnet_buffer(b)
Definition: buffer.h:360
u8 data[0]
Packet data.
Definition: buffer.h:172
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:111
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:57
VLIB_NODE_FUNCTION_MULTIARCH(ethernet_input_not_l2_node, ethernet_input_not_l2)
Definition: node.c:1207
Definition: defs.h:46