FD.io VPP  v17.01.1-3-gc6833f8
Vector Packet Processing
mpls_output.c
Go to the documentation of this file.
1 /*
2  * mpls_output.c: MPLS Adj rewrite
3  *
4  * Copyright (c) 2012-2014 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 <vlib/vlib.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/ip/ip.h>
21 #include <vnet/mpls/mpls.h>
22 
23 typedef struct {
24  /* Adjacency taken. */
27 
28  /* Packet data, possibly *after* rewrite. */
29  u8 packet_data[64 - 1*sizeof(u32)];
31 
32 static u8 *
33 format_mpls_output_trace (u8 * s, va_list * args)
34 {
35  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
36  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
37  mpls_output_trace_t * t = va_arg (*args, mpls_output_trace_t *);
38  vnet_main_t * vnm = vnet_get_main();
39  uword indent = format_get_indent (s);
40 
41  s = format (s, "adj-idx %d : %U flow hash: 0x%08x",
42  t->adj_index,
44  t->flow_hash);
45  s = format (s, "\n%U%U",
46  format_white_space, indent,
48  vnm, t->adj_index,
49  t->packet_data, sizeof (t->packet_data));
50  return s;
51 }
52 
53 static inline uword
55  vlib_node_runtime_t * node,
56  vlib_frame_t * from_frame,
57  int is_midchain)
58 {
59  u32 n_left_from, next_index, * from, * to_next, cpu_index;
60  vlib_node_runtime_t * error_node;
61  u32 n_left_to_next;
62 
63  cpu_index = os_get_cpu_number();
64  error_node = vlib_node_get_runtime (vm, mpls_output_node.index);
65  from = vlib_frame_vector_args (from_frame);
66  n_left_from = from_frame->n_vectors;
67  next_index = node->cached_next_index;
68 
69  while (n_left_from > 0)
70  {
71  vlib_get_next_frame (vm, node, next_index,
72  to_next, n_left_to_next);
73 
74  while (n_left_from >= 4 && n_left_to_next >= 2)
75  {
76  ip_adjacency_t * adj0;
78  vlib_buffer_t * p0;
79  u32 pi0, rw_len0, adj_index0, next0, error0;
80 
81  ip_adjacency_t * adj1;
83  vlib_buffer_t * p1;
84  u32 pi1, rw_len1, adj_index1, next1, error1;
85 
86  /* Prefetch next iteration. */
87  {
88  vlib_buffer_t * p2, * p3;
89 
90  p2 = vlib_get_buffer (vm, from[2]);
91  p3 = vlib_get_buffer (vm, from[3]);
92 
93  vlib_prefetch_buffer_header (p2, STORE);
94  vlib_prefetch_buffer_header (p3, STORE);
95 
96  CLIB_PREFETCH (p2->data, sizeof (hdr0[0]), STORE);
97  CLIB_PREFETCH (p3->data, sizeof (hdr1[0]), STORE);
98  }
99 
100  pi0 = to_next[0] = from[0];
101  pi1 = to_next[1] = from[1];
102 
103  from += 2;
104  n_left_from -= 2;
105  to_next += 2;
106  n_left_to_next -= 2;
107 
108  p0 = vlib_get_buffer (vm, pi0);
109  p1 = vlib_get_buffer (vm, pi1);
110 
111  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
112  adj_index1 = vnet_buffer (p1)->ip.adj_index[VLIB_TX];
113 
114  /* We should never rewrite a pkt using the MISS adjacency */
115  ASSERT(adj_index0);
116  ASSERT(adj_index1);
117 
118  adj0 = adj_get(adj_index0);
119  adj1 = adj_get(adj_index1);
120  hdr0 = vlib_buffer_get_current (p0);
121  hdr1 = vlib_buffer_get_current (p1);
122 
123  /* Guess we are only writing on simple Ethernet header. */
124  vnet_rewrite_two_headers (adj0[0], adj1[0], hdr0, hdr1,
125  sizeof (ethernet_header_t));
126 
127  /* Update packet buffer attributes/set output interface. */
128  rw_len0 = adj0[0].rewrite_header.data_bytes;
129  rw_len1 = adj1[0].rewrite_header.data_bytes;
130 
131  if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
134  cpu_index, adj_index0,
135  /* packet increment */ 0,
136  /* byte increment */ rw_len0-sizeof(ethernet_header_t));
137  if (PREDICT_FALSE (rw_len1 > sizeof(ethernet_header_t)))
140  cpu_index, adj_index1,
141  /* packet increment */ 0,
142  /* byte increment */ rw_len1-sizeof(ethernet_header_t));
143 
144  /* Check MTU of outgoing interface. */
146  adj0[0].rewrite_header.max_l3_packet_bytes))
147  {
148  p0->current_data -= rw_len0;
149  p0->current_length += rw_len0;
150 
151  vnet_buffer (p0)->sw_if_index[VLIB_TX] =
152  adj0[0].rewrite_header.sw_if_index;
153  next0 = adj0[0].rewrite_header.next_index;
154  error0 = IP4_ERROR_NONE;
155 
156  if (is_midchain)
157  {
158  adj0->sub_type.midchain.fixup_func(vm, adj0, p0);
159  }
160  }
161  else
162  {
163  error0 = IP4_ERROR_MTU_EXCEEDED;
164  next0 = MPLS_OUTPUT_NEXT_DROP;
165  }
167  adj1[0].rewrite_header.max_l3_packet_bytes))
168  {
169  p1->current_data -= rw_len1;
170  p1->current_length += rw_len1;
171 
172  vnet_buffer (p1)->sw_if_index[VLIB_TX] =
173  adj1[0].rewrite_header.sw_if_index;
174  next1 = adj1[0].rewrite_header.next_index;
175  error1 = IP4_ERROR_NONE;
176 
177  if (is_midchain)
178  {
179  adj1->sub_type.midchain.fixup_func(vm, adj1, p1);
180  }
181  }
182  else
183  {
184  error1 = IP4_ERROR_MTU_EXCEEDED;
185  next1 = MPLS_OUTPUT_NEXT_DROP;
186  }
187 
188  p0->error = error_node->errors[error0];
189  p1->error = error_node->errors[error1];
190 
192  {
193  mpls_output_trace_t *tr = vlib_add_trace (vm, node,
194  p0, sizeof (*tr));
195  tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX];
196  tr->flow_hash = vnet_buffer(p0)->ip.flow_hash;
197  }
199  {
200  mpls_output_trace_t *tr = vlib_add_trace (vm, node,
201  p1, sizeof (*tr));
202  tr->adj_index = vnet_buffer(p1)->ip.adj_index[VLIB_TX];
203  tr->flow_hash = vnet_buffer(p1)->ip.flow_hash;
204  }
205 
206  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
207  to_next, n_left_to_next,
208  pi0, pi1, next0, next1);
209  }
210 
211  while (n_left_from > 0 && n_left_to_next > 0)
212  {
213  ip_adjacency_t * adj0;
214  mpls_unicast_header_t *hdr0;
215  vlib_buffer_t * p0;
216  u32 pi0, rw_len0, adj_index0, next0, error0;
217 
218  pi0 = to_next[0] = from[0];
219 
220  p0 = vlib_get_buffer (vm, pi0);
221 
222  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
223 
224  /* We should never rewrite a pkt using the MISS adjacency */
225  ASSERT(adj_index0);
226 
227  adj0 = adj_get(adj_index0);
228  hdr0 = vlib_buffer_get_current (p0);
229 
230  /* Guess we are only writing on simple Ethernet header. */
231  vnet_rewrite_one_header (adj0[0], hdr0,
232  sizeof (ethernet_header_t));
233 
234  /* Update packet buffer attributes/set output interface. */
235  rw_len0 = adj0[0].rewrite_header.data_bytes;
236 
237  if (PREDICT_FALSE (rw_len0 > sizeof(ethernet_header_t)))
240  cpu_index, adj_index0,
241  /* packet increment */ 0,
242  /* byte increment */ rw_len0-sizeof(ethernet_header_t));
243 
244  /* Check MTU of outgoing interface. */
246  adj0[0].rewrite_header.max_l3_packet_bytes))
247  {
248  p0->current_data -= rw_len0;
249  p0->current_length += rw_len0;
250 
251  vnet_buffer (p0)->sw_if_index[VLIB_TX] =
252  adj0[0].rewrite_header.sw_if_index;
253  next0 = adj0[0].rewrite_header.next_index;
254  error0 = IP4_ERROR_NONE;
255 
256  if (is_midchain)
257  {
258  adj0->sub_type.midchain.fixup_func(vm, adj0, p0);
259  }
260  }
261  else
262  {
263  error0 = IP4_ERROR_MTU_EXCEEDED;
264  next0 = MPLS_OUTPUT_NEXT_DROP;
265  }
266  p0->error = error_node->errors[error0];
267 
268  from += 1;
269  n_left_from -= 1;
270  to_next += 1;
271  n_left_to_next -= 1;
272 
274  {
275  mpls_output_trace_t *tr = vlib_add_trace (vm, node,
276  p0, sizeof (*tr));
277  tr->adj_index = vnet_buffer(p0)->ip.adj_index[VLIB_TX];
278  tr->flow_hash = vnet_buffer(p0)->ip.flow_hash;
279  }
280 
281  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
282  to_next, n_left_to_next,
283  pi0, next0);
284  }
285 
286  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
287  }
289  MPLS_ERROR_PKTS_ENCAP,
290  from_frame->n_vectors);
291 
292  return from_frame->n_vectors;
293 }
294 
295 static char * mpls_error_strings[] = {
296 #define mpls_error(n,s) s,
297 #include "error.def"
298 #undef mpls_error
299 };
300 
301 static inline uword
303  vlib_node_runtime_t * node,
304  vlib_frame_t * from_frame)
305 {
306  return (mpls_output_inline(vm, node, from_frame, /* is_midchain */ 0));
307 }
308 
310  .function = mpls_output,
311  .name = "mpls-output",
312  /* Takes a vector of packets. */
313  .vector_size = sizeof (u32),
314  .n_errors = MPLS_N_ERROR,
315  .error_strings = mpls_error_strings,
316 
317  .n_next_nodes = MPLS_OUTPUT_N_NEXT,
318  .next_nodes = {
319 #define _(s,n) [MPLS_OUTPUT_NEXT_##s] = n,
321 #undef _
322  },
323 
324  .format_trace = format_mpls_output_trace,
325 };
326 
328 
329 static inline uword
331  vlib_node_runtime_t * node,
332  vlib_frame_t * from_frame)
333 {
334  return (mpls_output_inline(vm, node, from_frame, /* is_midchain */ 1));
335 }
336 
338  .function = mpls_midchain,
339  .name = "mpls-midchain",
340  .vector_size = sizeof (u32),
341 
342  .format_trace = format_mpls_output_trace,
343 
344  .sibling_of = "mpls-output",
345 };
346 
348 
349 /**
350  * @brief Next index values from the MPLS incomplete adj node
351  */
352 #define foreach_mpls_adj_incomplete_next \
353 _(DROP, "error-drop") \
354 _(IP4, "ip4-arp") \
355 _(IP6, "ip6-discover-neighbor")
356 
357 typedef enum {
358 #define _(s,n) MPLS_ADJ_INCOMPLETE_NEXT_##s,
360 #undef _
363 
364 /**
365  * @brief A struct to hold tracing information for the MPLS label imposition
366  * node.
367  */
369 {
372 
373 
374 /**
375  * @brief Graph node for incomplete MPLS adjacency.
376  * This node will push traffic to either the v4-arp or v6-nd node
377  * based on the next-hop proto of the adj.
378  * We pay a cost for this 'routing' node, but an incomplete adj is the
379  * exception case.
380  */
381 static inline uword
383  vlib_node_runtime_t * node,
384  vlib_frame_t * from_frame)
385 {
386  u32 n_left_from, next_index, * from, * to_next;
387 
388  from = vlib_frame_vector_args (from_frame);
389  n_left_from = from_frame->n_vectors;
390  next_index = node->cached_next_index;
391 
392  while (n_left_from > 0)
393  {
394  u32 n_left_to_next;
395 
396  vlib_get_next_frame (vm, node, next_index,
397  to_next, n_left_to_next);
398 
399  while (n_left_from > 0 && n_left_to_next > 0)
400  {
401  u32 pi0, next0, adj_index0;
402  ip_adjacency_t * adj0;
403  vlib_buffer_t * p0;
404 
405  pi0 = to_next[0] = from[0];
406  p0 = vlib_get_buffer (vm, pi0);
407  from += 1;
408  n_left_from -= 1;
409  to_next += 1;
410  n_left_to_next -= 1;
411 
412  adj_index0 = vnet_buffer (p0)->ip.adj_index[VLIB_TX];
413  ASSERT(adj_index0);
414 
415  adj0 = adj_get(adj_index0);
416 
418  {
419  next0 = MPLS_ADJ_INCOMPLETE_NEXT_IP4;
420  }
421  else
422  {
423  next0 = MPLS_ADJ_INCOMPLETE_NEXT_IP6;
424  }
425 
427  {
429  vlib_add_trace (vm, node, p0, sizeof (*tr));
430  tr->next = next0;
431  }
432 
433  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
434  to_next, n_left_to_next,
435  pi0, next0);
436  }
437 
438  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
439  }
440 
441  return from_frame->n_vectors;
442 }
443 
444 static u8 *
446 {
447  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
448  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
450  uword indent;
451 
452  t = va_arg (*args, mpls_adj_incomplete_trace_t *);
453  indent = format_get_indent (s);
454 
455  s = format (s, "%Unext:%d",
456  format_white_space, indent,
457  t->next);
458  return (s);
459 }
460 
462  .function = mpls_adj_incomplete,
463  .name = "mpls-adj-incomplete",
464  .format_trace = format_mpls_adj_incomplete_trace,
465  /* Takes a vector of packets. */
466  .vector_size = sizeof (u32),
467  .n_errors = MPLS_N_ERROR,
468  .error_strings = mpls_error_strings,
469 
470  .n_next_nodes = MPLS_ADJ_INCOMPLETE_N_NEXT,
471  .next_nodes = {
472 #define _(s,n) [MPLS_ADJ_INCOMPLETE_NEXT_##s] = n,
474 #undef _
475  },
476 };
477 
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
#define vnet_rewrite_one_header(rw0, p0, most_likely_size)
Definition: rewrite.h:253
#define CLIB_UNUSED(x)
Definition: clib.h:79
#define PREDICT_TRUE(x)
Definition: clib.h:98
IP unicast adjacency.
Definition: lookup.h:188
A struct to hold tracing information for the MPLS label imposition node.
Definition: mpls_output.c:368
static u8 * format_mpls_adj_incomplete_trace(u8 *s, va_list *args)
Definition: mpls_output.c:445
vlib_error_t * errors
Definition: node.h:419
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:100
union ip_adjacency_t_::@175 sub_type
static u8 * format_mpls_output_trace(u8 *s, va_list *args)
Definition: mpls_output.c:33
vlib_node_registration_t mpls_midchain_node
(constructor) VLIB_REGISTER_NODE (mpls_midchain_node)
Definition: mpls_output.c:337
vlib_node_registration_t mpls_output_node
(constructor) VLIB_REGISTER_NODE (mpls_output_node)
Definition: mpls_output.c:309
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
static ip_adjacency_t * adj_get(adj_index_t adj_index)
Get a pointer to an adjacency object from its index.
Definition: adj.h:117
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:78
format_function_t format_ip_adjacency_packet_data
Definition: format.h:59
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:194
u8 * format_white_space(u8 *s, va_list *va)
Definition: std-formats.c:113
mpls_adj_incomplete_next_t
Definition: mpls_output.c:357
static uword format_get_indent(u8 *s)
Definition: format.h:72
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:82
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
static uword mpls_adj_incomplete(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Graph node for incomplete MPLS adjacency.
Definition: mpls_output.c:382
#define PREDICT_FALSE(x)
Definition: clib.h:97
#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:216
#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:350
vlib_combined_counter_main_t adjacency_counters
Adjacency packet counters.
Definition: adj.c:30
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:121
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1113
static uword mpls_output(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: mpls_output.c:302
u16 n_vectors
Definition: node.h:344
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
#define foreach_mpls_adj_incomplete_next
Next index values from the MPLS incomplete adj node.
Definition: mpls_output.c:352
static vlib_node_runtime_t * vlib_node_get_runtime(vlib_main_t *vm, u32 node_index)
Get node runtime by node index.
Definition: node_funcs.h:88
u16 cached_next_index
Definition: node.h:463
static uword mpls_output_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame, int is_midchain)
Definition: mpls_output.c:54
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)
#define foreach_mpls_output_next
Definition: mpls.h:145
unsigned int u32
Definition: types.h:88
#define vnet_buffer(b)
Definition: buffer.h:361
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:95
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
static char * mpls_error_strings[]
Definition: mpls_output.c:295
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:253
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:170
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
u8 data[0]
Packet data.
Definition: buffer.h:158
struct mpls_adj_incomplete_trace_t_ mpls_adj_incomplete_trace_t
A struct to hold tracing information for the MPLS label imposition node.
u8 packet_data[64-1 *sizeof(u32)]
Definition: mpls_output.c:29
vlib_node_registration_t mpls_adj_incomplete_node
(constructor) VLIB_REGISTER_NODE (mpls_adj_incomplete_node)
Definition: mpls_output.c:461
#define vnet_rewrite_two_headers(rw0, rw1, p0, p1, most_likely_size)
Definition: rewrite.h:258
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:85
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
static uword mpls_midchain(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: mpls_output.c:330
format_function_t format_ip_adjacency
Definition: format.h:58
struct ip_adjacency_t_::@175::@177 midchain
IP_LOOKUP_NEXT_MIDCHAIN.