FD.io VPP  v16.09
Vector Packet Processing
encap.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 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 Functions for encapsulating VXLAN GPE tunnels
18  *
19 */
20 #include <vppinfra/error.h>
21 #include <vppinfra/hash.h>
22 #include <vnet/vnet.h>
23 #include <vnet/ip/ip.h>
24 #include <vnet/ethernet/ethernet.h>
26 
27 /** Statistics (not really errors) */
28 #define foreach_vxlan_gpe_encap_error \
29 _(ENCAPSULATED, "good packets encapsulated")
30 
31 /**
32  * @brief VXLAN GPE encap error strings
33  */
34 static char * vxlan_gpe_encap_error_strings[] = {
35 #define _(sym,string) string,
37 #undef _
38 };
39 
40 /**
41  * @brief Struct for VXLAN GPE errors/counters
42  */
43 typedef enum {
44 #define _(sym,str) VXLAN_GPE_ENCAP_ERROR_##sym,
46 #undef _
49 
50 /**
51  * @brief Struct for defining VXLAN GPE next nodes
52  */
53 typedef enum {
59 
60 /**
61  * @brief Struct for tracing VXLAN GPE encapsulated packets
62  */
63 typedef struct {
66 
67 /**
68  * @brief Trace of packets encapsulated in VXLAN GPE
69  *
70  * @param *s
71  * @param *args
72  *
73  * @return *s
74  *
75  */
76 u8 * format_vxlan_gpe_encap_trace (u8 * s, va_list * args)
77 {
78  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
79  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
81  = va_arg (*args, vxlan_gpe_encap_trace_t *);
82 
83  s = format (s, "VXLAN-GPE-ENCAP: tunnel %d", t->tunnel_index);
84  return s;
85 }
86 
87 /**
88  * @brief Instantiates UDP + VXLAN-GPE header then set next node to IP4|6 lookup
89  *
90  * @param *ngm
91  * @param *b0
92  * @param *t0 contains rewrite header
93  * @param *next0 relative index of next dispatch function (next node)
94  * @param is_v4 Is this IPv4? (or IPv6)
95  *
96  */
97 always_inline void
99  vxlan_gpe_tunnel_t * t0, u32 * next0, u8 is_v4)
100 {
101  ASSERT(sizeof(ip4_vxlan_gpe_header_t) == 36);
102  ASSERT(sizeof(ip6_vxlan_gpe_header_t) == 56);
103 
104  if (is_v4)
105  {
106  ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, 36, 1);
108 
109  }
110  else
111  {
112  ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, 56, 0);
114  }
115 }
116 
117 /**
118  * @brief Instantiates UDP + VXLAN-GPE header then set next node to IP4|6 lookup for two packets
119  *
120  * @param *ngm
121  * @param *b0 Packet0
122  * @param *b1 Packet1
123  * @param *t0 contains rewrite header for Packet0
124  * @param *t1 contains rewrite header for Packet1
125  * @param *next0 relative index of next dispatch function (next node) for Packet0
126  * @param *next1 relative index of next dispatch function (next node) for Packet1
127  * @param is_v4 Is this IPv4? (or IPv6)
128  *
129  */
130 always_inline void
132  vxlan_gpe_tunnel_t * t0, vxlan_gpe_tunnel_t * t1, u32 * next0,
133  u32 * next1, u8 is_v4)
134 {
135  ASSERT(sizeof(ip4_vxlan_gpe_header_t) == 36);
136  ASSERT(sizeof(ip6_vxlan_gpe_header_t) == 56);
137 
138  if (is_v4)
139  {
140  ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, 36, 1);
141  ip_udp_encap_one (ngm->vlib_main, b1, t1->rewrite, 36, 1);
142  next0[0] = next1[0] = VXLAN_GPE_ENCAP_NEXT_IP4_LOOKUP;
143  }
144  else
145  {
146  ip_udp_encap_one (ngm->vlib_main, b0, t0->rewrite, 56, 0);
147  ip_udp_encap_one (ngm->vlib_main, b1, t1->rewrite, 56, 0);
148  next0[0] = next1[0] = VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP;
149  }
150 }
151 
152 /**
153  * @brief Common processing for IPv4 and IPv6 VXLAN GPE encap dispatch functions
154  *
155  * It is worth noting that other than trivial UDP forwarding (transit), VXLAN GPE
156  * tunnels are "establish local". This means that we don't have a TX interface as yet
157  * as we need to look up where the outer-header dest is. By setting the TX index in the
158  * buffer metadata to the encap FIB, we can do a lookup to get the adjacency and real TX.
159  *
160  * vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
161  *
162  * @node vxlan-gpe-input
163  * @param *vm
164  * @param *node
165  * @param *from_frame
166  *
167  * @return from_frame->n_vectors
168  *
169  */
170 static uword
172  vlib_node_runtime_t * node,
173  vlib_frame_t * from_frame)
174 {
175  u32 n_left_from, next_index, *from, *to_next;
177  vnet_main_t * vnm = ngm->vnet_main;
179  u32 pkts_encapsulated = 0;
180  u32 cpu_index = os_get_cpu_number ();
181  u32 stats_sw_if_index, stats_n_packets, stats_n_bytes;
182 
183  from = vlib_frame_vector_args (from_frame);
184  n_left_from = from_frame->n_vectors;
185 
186  next_index = node->cached_next_index;
187  stats_sw_if_index = node->runtime_data[0];
188  stats_n_packets = stats_n_bytes = 0;
189 
190  while (n_left_from > 0)
191  {
192  u32 n_left_to_next;
193 
194  vlib_get_next_frame(vm, node, next_index, to_next, n_left_to_next);
195 
196  while (n_left_from >= 4 && n_left_to_next >= 2)
197  {
198  u32 bi0, bi1;
199  vlib_buffer_t * b0, *b1;
200  u32 next0, next1;
201  u32 sw_if_index0, sw_if_index1, len0, len1;
202  vnet_hw_interface_t * hi0, *hi1;
203  vxlan_gpe_tunnel_t * t0, *t1;
204  u8 is_ip4_0, is_ip4_1;
205 
206  next0 = next1 = VXLAN_GPE_ENCAP_NEXT_IP4_LOOKUP;
207 
208  /* Prefetch next iteration. */
209  {
210  vlib_buffer_t * p2, *p3;
211 
212  p2 = vlib_get_buffer (vm, from[2]);
213  p3 = vlib_get_buffer (vm, from[3]);
214 
215  vlib_prefetch_buffer_header(p2, LOAD);
216  vlib_prefetch_buffer_header(p3, LOAD);
217 
220  }
221 
222  bi0 = from[0];
223  bi1 = from[1];
224  to_next[0] = bi0;
225  to_next[1] = bi1;
226  from += 2;
227  to_next += 2;
228  n_left_to_next -= 2;
229  n_left_from -= 2;
230 
231  b0 = vlib_get_buffer (vm, bi0);
232  b1 = vlib_get_buffer (vm, bi1);
233 
234  /* 1-wide cache? */
235  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_TX];
236  sw_if_index1 = vnet_buffer(b1)->sw_if_index[VLIB_TX];
237  hi0 = vnet_get_sup_hw_interface (vnm, vnet_buffer(b0)->sw_if_index[VLIB_TX]);
238  hi1 = vnet_get_sup_hw_interface (vnm, vnet_buffer(b1)->sw_if_index[VLIB_TX]);
239 
240  t0 = pool_elt_at_index(ngm->tunnels, hi0->dev_instance);
241  t1 = pool_elt_at_index(ngm->tunnels, hi1->dev_instance);
242 
243  is_ip4_0 = (t0->flags & VXLAN_GPE_TUNNEL_IS_IPV4);
244  is_ip4_1 = (t1->flags & VXLAN_GPE_TUNNEL_IS_IPV4);
245 
246  if (PREDICT_TRUE(is_ip4_0 == is_ip4_1))
247  {
248  vxlan_gpe_encap_two_inline (ngm, b0, b1, t0, t1, &next0, &next1,is_ip4_0);
249  }
250  else
251  {
252  vxlan_gpe_encap_one_inline (ngm, b0, t0, &next0, is_ip4_0);
253  vxlan_gpe_encap_one_inline (ngm, b1, t1, &next1, is_ip4_1);
254  }
255 
256  /* Reset to look up tunnel partner in the configured FIB */
257  vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
258  vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_fib_index;
259  vnet_buffer(b0)->sw_if_index[VLIB_RX] = sw_if_index0;
260  vnet_buffer(b1)->sw_if_index[VLIB_RX] = sw_if_index1;
261  pkts_encapsulated += 2;
262 
263  len0 = vlib_buffer_length_in_chain (vm, b0);
264  len1 = vlib_buffer_length_in_chain (vm, b0);
265  stats_n_packets += 2;
266  stats_n_bytes += len0 + len1;
267 
268  /* Batch stats increment on the same vxlan tunnel so counter is not
269  incremented per packet. Note stats are still incremented for deleted
270  and admin-down tunnel where packets are dropped. It is not worthwhile
271  to check for this rare case and affect normal path performance. */
272  if (PREDICT_FALSE((sw_if_index0 != stats_sw_if_index)
273  || (sw_if_index1 != stats_sw_if_index)))
274  {
275  stats_n_packets -= 2;
276  stats_n_bytes -= len0 + len1;
277  if (sw_if_index0 == sw_if_index1)
278  {
279  if (stats_n_packets)
282  cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
283  stats_sw_if_index = sw_if_index0;
284  stats_n_packets = 2;
285  stats_n_bytes = len0 + len1;
286  }
287  else
288  {
291  cpu_index, sw_if_index0, 1, len0);
294  cpu_index, sw_if_index1, 1, len1);
295  }
296  }
297 
299  {
300  vxlan_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b0, sizeof(*tr));
301  tr->tunnel_index = t0 - ngm->tunnels;
302  }
303 
305  {
306  vxlan_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b1,
307  sizeof(*tr));
308  tr->tunnel_index = t1 - ngm->tunnels;
309  }
310 
311  vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
312  n_left_to_next, bi0, bi1, next0, next1);
313  }
314 
315  while (n_left_from > 0 && n_left_to_next > 0)
316  {
317  u32 bi0;
318  vlib_buffer_t * b0;
320  u32 sw_if_index0, len0;
321  vnet_hw_interface_t * hi0;
322  vxlan_gpe_tunnel_t * t0;
323  u8 is_ip4_0;
324 
325  bi0 = from[0];
326  to_next[0] = bi0;
327  from += 1;
328  to_next += 1;
329  n_left_from -= 1;
330  n_left_to_next -= 1;
331 
332  b0 = vlib_get_buffer (vm, bi0);
333 
334  /* 1-wide cache? */
335  sw_if_index0 = vnet_buffer(b0)->sw_if_index[VLIB_TX];
336  hi0 = vnet_get_sup_hw_interface (vnm, vnet_buffer(b0)->sw_if_index[VLIB_TX]);
337 
338  t0 = pool_elt_at_index(ngm->tunnels, hi0->dev_instance);
339 
340  is_ip4_0 = (t0->flags & VXLAN_GPE_TUNNEL_IS_IPV4);
341 
342  vxlan_gpe_encap_one_inline (ngm, b0, t0, &next0, is_ip4_0);
343 
344  /* Reset to look up tunnel partner in the configured FIB */
345  vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
346  vnet_buffer(b0)->sw_if_index[VLIB_RX] = sw_if_index0;
347  pkts_encapsulated++;
348 
349  len0 = vlib_buffer_length_in_chain (vm, b0);
350  stats_n_packets += 1;
351  stats_n_bytes += len0;
352 
353  /* Batch stats increment on the same vxlan tunnel so counter is not
354  * incremented per packet. Note stats are still incremented for deleted
355  * and admin-down tunnel where packets are dropped. It is not worthwhile
356  * to check for this rare case and affect normal path performance. */
357  if (PREDICT_FALSE(sw_if_index0 != stats_sw_if_index))
358  {
359  stats_n_packets -= 1;
360  stats_n_bytes -= len0;
361  if (stats_n_packets)
364  cpu_index, stats_sw_if_index, stats_n_packets, stats_n_bytes);
365  stats_n_packets = 1;
366  stats_n_bytes = len0;
367  stats_sw_if_index = sw_if_index0;
368  }
370  {
371  vxlan_gpe_encap_trace_t *tr = vlib_add_trace (vm, node, b0,
372  sizeof(*tr));
373  tr->tunnel_index = t0 - ngm->tunnels;
374  }
375  vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
376  n_left_to_next, bi0, next0);
377  }
378 
379  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
380  }
382  VXLAN_GPE_ENCAP_ERROR_ENCAPSULATED,
383  pkts_encapsulated);
384  /* Increment any remaining batch stats */
385  if (stats_n_packets)
386  {
389  stats_sw_if_index, stats_n_packets, stats_n_bytes);
390  node->runtime_data[0] = stats_sw_if_index;
391  }
392 
393  return from_frame->n_vectors;
394 }
395 
397  .function = vxlan_gpe_encap,
398  .name = "vxlan-gpe-encap",
399  .vector_size = sizeof (u32),
400  .format_trace = format_vxlan_gpe_encap_trace,
402 
404  .error_strings = vxlan_gpe_encap_error_strings,
405 
406  .n_next_nodes = VXLAN_GPE_ENCAP_N_NEXT,
407 
408  .next_nodes = {
409  [VXLAN_GPE_ENCAP_NEXT_IP4_LOOKUP] = "ip4-lookup",
410  [VXLAN_GPE_ENCAP_NEXT_IP6_LOOKUP] = "ip6-lookup",
411  [VXLAN_GPE_ENCAP_NEXT_DROP] = "error-drop",
412  },
413 };
414 
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:457
#define CLIB_UNUSED(x)
Definition: clib.h:79
u32 flags
flags
Definition: vxlan_gpe.h:116
#define foreach_vxlan_gpe_encap_error
Statistics (not really errors)
Definition: encap.c:28
Struct for tracing VXLAN GPE encapsulated packets.
Definition: encap.c:63
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
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:64
#define PREDICT_TRUE(x)
Definition: clib.h:98
VXLAN GPE definitions.
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:112
vnet_main_t * vnet_main
State convenience vnet_main_t.
Definition: vxlan_gpe.h:164
static uword vxlan_gpe_encap(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Common processing for IPv4 and IPv6 VXLAN GPE encap dispatch functions.
Definition: encap.c:171
static void vxlan_gpe_encap_one_inline(vxlan_gpe_main_t *ngm, vlib_buffer_t *b0, vxlan_gpe_tunnel_t *t0, u32 *next0, u8 is_v4)
Instantiates UDP + VXLAN-GPE header then set next node to IP4|6 lookup.
Definition: encap.c:98
#define always_inline
Definition: clib.h:84
vlib_combined_counter_main_t * combined_sw_if_counters
Definition: interface.h:501
u8 * format_vxlan_gpe_encap_trace(u8 *s, va_list *args)
Trace of packets encapsulated in VXLAN GPE.
Definition: encap.c:76
vxlan_gpe_encap_next_t
Struct for defining VXLAN GPE next nodes.
Definition: encap.c:53
u8 * rewrite
Rewrite string.
Definition: vxlan_gpe.h:92
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
Struct for VXLAN GPE tunnel.
Definition: vxlan_gpe.h:90
static void vxlan_gpe_encap_two_inline(vxlan_gpe_main_t *ngm, vlib_buffer_t *b0, vlib_buffer_t *b1, vxlan_gpe_tunnel_t *t0, vxlan_gpe_tunnel_t *t1, u32 *next0, u32 *next1, u8 is_v4)
Instantiates UDP + VXLAN-GPE header then set next node to IP4|6 lookup for two packets.
Definition: encap.c:131
vxlan_gpe_encap_error_t
Struct for VXLAN GPE errors/counters.
Definition: encap.c:43
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
vxlan_gpe_main_t vxlan_gpe_main
Definition: vxlan_gpe.c:23
vlib_main_t * vlib_main
State convenience vlib_main_t.
Definition: vxlan_gpe.h:162
#define PREDICT_FALSE(x)
Definition: clib.h:97
static void ip_udp_encap_one(vlib_main_t *vm, vlib_buffer_t *b0, u8 *ec0, word ec_len, u8 is_ip4)
Definition: udp.h:118
#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:130
#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:348
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1111
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
#define ARRAY_LEN(x)
Definition: clib.h:59
u16 cached_next_index
Definition: node.h:462
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 cpu_index, u32 index, u32 packet_increment, u32 byte_increment)
Increment a combined counter.
Definition: counter.h:241
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:335
Struct for VXLAN GPE node state.
Definition: vxlan_gpe.h:146
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:93
vxlan_gpe_tunnel_t * tunnels
vector of encap tunnel instances
Definition: vxlan_gpe.h:148
u64 uword
Definition: types.h:112
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
Definition: defs.h:47
unsigned char u8
Definition: types.h:56
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:251
static char * vxlan_gpe_encap_error_strings[]
VXLAN GPE encap error strings.
Definition: encap.c:34
u32 encap_fib_index
FIB indices - tunnel partner lookup here.
Definition: vxlan_gpe.h:103
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:163
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 data[0]
Packet data.
Definition: buffer.h:151
vlib_node_registration_t vxlan_gpe_encap_node
(constructor) VLIB_REGISTER_NODE (vxlan_gpe_encap_node)
Definition: encap.c:396
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
#define VXLAN_GPE_TUNNEL_IS_IPV4
Flags for vxlan_gpe_tunnel_t.
Definition: vxlan_gpe.h:120
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
uword runtime_data[(128-1 *sizeof(vlib_node_function_t *)-1 *sizeof(vlib_error_t *)-11 *sizeof(u32)-5 *sizeof(u16))/sizeof(uword)]
Definition: node.h:472
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
Definition: defs.h:46