FD.io VPP  v17.04.2-2-ga8f93f8
Vector Packet Processing
mpls_input.c
Go to the documentation of this file.
1 /*
2  * node.c: MPLS input
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/mpls/mpls.h>
21 #include <vnet/feature/feature.h>
22 
23 typedef struct {
27 
28 #define foreach_mpls_input_next \
29 _(DROP, "error-drop") \
30 _(LOOKUP, "mpls-lookup")
31 
32 typedef enum {
33 #define _(s,n) MPLS_INPUT_NEXT_##s,
35 #undef _
38 
39 static u8 *
40 format_mpls_input_trace (u8 * s, va_list * args)
41 {
42  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
43  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
44  mpls_input_trace_t * t = va_arg (*args, mpls_input_trace_t *);
45  char * next_name;
46  u32 label;
47  next_name = "BUG!";
48  label = clib_net_to_host_u32(t->label_net_byte_order);
49 
50 #define _(a,b) if (t->next_index == MPLS_INPUT_NEXT_##a) next_name = b;
52 #undef _
53 
54  s = format (s, "MPLS: next %s[%d] label %d ttl %d",
55  next_name, t->next_index,
57  vnet_mpls_uc_get_ttl(label));
58 
59  return s;
60 }
61 
63 
64 typedef struct {
70 
71 static inline uword
73  vlib_node_runtime_t * node,
74  vlib_frame_t * from_frame)
75 {
76  u32 n_left_from, next_index, * from, * to_next;
78  mpls_main_t * mm;
79  u32 cpu_index = os_get_cpu_number();
81  vnet_main_t * vnm = vnet_get_main();
82 
83  from = vlib_frame_vector_args (from_frame);
84  n_left_from = from_frame->n_vectors;
86  mm = rt->mpls_main;
87  /*
88  * Force an initial lookup every time, in case the control-plane
89  * changed the label->FIB mapping.
90  */
91  rt->last_label = ~0;
92 
93  next_index = node->cached_next_index;
94 
97 
98  while (n_left_from > 0)
99  {
100  u32 n_left_to_next;
101 
102  vlib_get_next_frame (vm, node, next_index,
103  to_next, n_left_to_next);
104 
105  while (n_left_from >= 4 && n_left_to_next >= 2)
106  {
107  u32 bi0, next0, sw_if_index0;
108  u32 bi1, next1, sw_if_index1;
109  vlib_buffer_t *b0, *b1;
110  char *h0, *h1;
111 
112  /* Prefetch next iteration. */
113  {
114  vlib_buffer_t * p2, * p3;
115 
116  p2 = vlib_get_buffer (vm, from[2]);
117  p3 = vlib_get_buffer (vm, from[3]);
118 
119  vlib_prefetch_buffer_header (p2, STORE);
120  vlib_prefetch_buffer_header (p3, STORE);
121 
122  CLIB_PREFETCH (p2->data, sizeof (h0[0]), STORE);
123  CLIB_PREFETCH (p3->data, sizeof (h1[0]), STORE);
124  }
125 
126  bi0 = to_next[0] = from[0];
127  bi1 = to_next[1] = from[1];
128 
129  from += 2;
130  to_next += 2;
131  n_left_from -= 2;
132  n_left_to_next -= 2;
133 
134  b0 = vlib_get_buffer (vm, bi0);
135  b1 = vlib_get_buffer (vm, bi1);
136 
137  h0 = vlib_buffer_get_current (b0);
138  h1 = vlib_buffer_get_current (b1);
139 
140  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
141  sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
142 
143  /* TTL expired? */
144  if (PREDICT_FALSE(h0[3] == 0))
145  {
146  next0 = MPLS_INPUT_NEXT_DROP;
147  b0->error = node->errors[MPLS_ERROR_TTL_EXPIRED];
148  }
149  else
150  {
151  next0 = MPLS_INPUT_NEXT_LOOKUP;
153  sw_if_index0, &next0, b0);
154  vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
155  }
156 
157  if (PREDICT_FALSE(h1[3] == 0))
158  {
159  next1 = MPLS_INPUT_NEXT_DROP;
160  b1->error = node->errors[MPLS_ERROR_TTL_EXPIRED];
161  }
162  else
163  {
164  next1 = MPLS_INPUT_NEXT_LOOKUP;
166  sw_if_index1, &next1, b1);
167  vlib_increment_simple_counter (cm, cpu_index, sw_if_index1, 1);
168  }
169 
171  {
172  mpls_input_trace_t *tr = vlib_add_trace (vm, node,
173  b0, sizeof (*tr));
174  tr->next_index = next0;
175  tr->label_net_byte_order = *((u32*)h0);
176  }
178  {
179  mpls_input_trace_t *tr = vlib_add_trace (vm, node,
180  b1, sizeof (*tr));
181  tr->next_index = next1;
182  tr->label_net_byte_order = *((u32*)h1);
183  }
184 
185  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
186  to_next, n_left_to_next,
187  bi0, bi1,
188  next0, next1);
189  }
190 
191  while (n_left_from > 0 && n_left_to_next > 0)
192  {
193  u32 sw_if_index0, next0, bi0;
194  vlib_buffer_t * b0;
195  char * h0;
196 
197  bi0 = from[0];
198  to_next[0] = bi0;
199  from += 1;
200  to_next += 1;
201  n_left_from -= 1;
202  n_left_to_next -= 1;
203 
204  b0 = vlib_get_buffer (vm, bi0);
205  h0 = vlib_buffer_get_current (b0);
206  sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX];
207 
208  /* TTL expired? */
209  if (PREDICT_FALSE(h0[3] == 0))
210  {
211  next0 = MPLS_INPUT_NEXT_DROP;
212  b0->error = node->errors[MPLS_ERROR_TTL_EXPIRED];
213  }
214  else
215  {
216  next0 = MPLS_INPUT_NEXT_LOOKUP;
217  vnet_feature_arc_start(mm->input_feature_arc_index, sw_if_index0, &next0, b0);
218  vlib_increment_simple_counter (cm, cpu_index, sw_if_index0, 1);
219  }
220 
222  {
223  mpls_input_trace_t *tr = vlib_add_trace (vm, node,
224  b0, sizeof (*tr));
225  tr->next_index = next0;
226  tr->label_net_byte_order = *(u32*)h0;
227  }
228 
229  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
230  to_next, n_left_to_next,
231  bi0, next0);
232  }
233 
234  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
235  }
237  MPLS_ERROR_PKTS_DECAP, from_frame->n_vectors);
238  return from_frame->n_vectors;
239 }
240 
241 static uword
243  vlib_node_runtime_t * node,
244  vlib_frame_t * from_frame)
245 {
246  return mpls_input_inline (vm, node, from_frame);
247 }
248 
249 static char * mpls_error_strings[] = {
250 #define mpls_error(n,s) s,
251 #include "error.def"
252 #undef mpls_error
253 };
254 
256  .function = mpls_input,
257  .name = "mpls-input",
258  /* Takes a vector of packets. */
259  .vector_size = sizeof (u32),
260 
261  .runtime_data_bytes = sizeof(mpls_input_runtime_t),
262 
263  .n_errors = MPLS_N_ERROR,
264  .error_strings = mpls_error_strings,
265 
266  .n_next_nodes = MPLS_INPUT_N_NEXT,
267  .next_nodes = {
268 #define _(s,n) [MPLS_INPUT_NEXT_##s] = n,
270 #undef _
271  },
272 
274  .format_trace = format_mpls_input_trace,
275 };
276 
278 
279 static void
281 {
283  pg_node_t * pn;
284 
285  pn = pg_get_node (mpls_input_node.index);
287 
289  rt->last_label = (u32) ~0;
290  rt->last_inner_fib_index = 0;
291  rt->last_outer_fib_index = 0;
292  rt->mpls_main = &mpls_main;
293 
294  ethernet_register_input_type (vm, ETHERNET_TYPE_MPLS_UNICAST,
295  mpls_input_node.index);
296 }
297 
299 {
300  clib_error_t * error;
301 
302  error = vlib_call_init_function (vm, mpls_init);
303  if (error)
304  clib_error_report (error);
305 
306  mpls_setup_nodes (vm);
307 
308  return 0;
309 }
310 
312 
314 {
317  rt->last_label = (u32) ~0;
318  rt->last_inner_fib_index = 0;
319  rt->last_outer_fib_index = 0;
320  rt->mpls_main = &mpls_main;
321  return 0;
322 }
323 
#define CLIB_UNUSED(x)
Definition: clib.h:79
vnet_main_t * vnet_get_main(void)
Definition: misc.c:46
vnet_interface_main_t interface_main
Definition: vnet.h:57
u8 input_feature_arc_index
Definition: mpls.h:74
static char * mpls_error_strings[]
Definition: mpls_input.c:249
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
struct _vlib_node_registration vlib_node_registration_t
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:418
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:418
static pg_node_t * pg_get_node(uword node_index)
Definition: pg.h:350
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:164
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
format_function_t format_mpls_unicast_header_net_byte_order
Definition: mpls.h:90
VLIB_WORKER_INIT_FUNCTION(mpls_input_worker_init)
static clib_error_t * mpls_input_worker_init(vlib_main_t *vm)
Definition: mpls_input.c:313
static u32 vnet_mpls_uc_get_ttl(mpls_label_t label_exp_s_ttl)
Definition: packet.h:92
A collection of simple counters.
Definition: counter.h:58
#define vlib_call_init_function(vm, x)
Definition: init.h:162
vlib_node_registration_t mpls_input_node
(constructor) VLIB_REGISTER_NODE (mpls_input_node)
Definition: mpls_input.c:62
uword os_get_cpu_number(void)
Definition: unix-misc.c:224
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:188
static void * vlib_node_get_runtime_data(vlib_main_t *vm, u32 node_index)
Get node runtime private data by node index.
Definition: node_funcs.h:109
#define PREDICT_FALSE(x)
Definition: clib.h:97
static u32 vnet_mpls_uc_get_label(mpls_label_t label_exp_s_ttl)
Definition: packet.h:77
vlib_simple_counter_main_t * sw_if_counters
Definition: interface.h:625
mpls_input_next_t
Definition: mpls_input.c:32
#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_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:113
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1115
u16 n_vectors
Definition: node.h:344
mpls_main_t mpls_main
Definition: mpls.c:25
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
vlib_main_t * vm
Definition: buffer.c:276
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:85
unformat_function_t unformat_pg_mpls_header
Definition: mpls.h:107
unformat_function_t * unformat_edit
Definition: pg.h:307
#define foreach_mpls_input_next
Definition: mpls_input.c:28
static u8 * format_mpls_input_trace(u8 *s, va_list *args)
Definition: mpls_input.c:40
static void mpls_setup_nodes(vlib_main_t *vm)
Definition: mpls_input.c:280
static clib_error_t * mpls_input_init(vlib_main_t *vm)
Definition: mpls_input.c:298
u16 cached_next_index
Next frame index that vector arguments were last enqueued to last time this node ran.
Definition: node.h:455
unsigned int u32
Definition: types.h:88
#define clib_error_report(e)
Definition: error.h:125
void ethernet_register_input_type(vlib_main_t *vm, ethernet_type_t type, u32 node_index)
Definition: node.c:1296
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 clib_error_t * mpls_init(vlib_main_t *vm)
Definition: mpls.c:500
unsigned char u8
Definition: types.h:56
static uword mpls_input(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: mpls_input.c:242
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:253
#define vnet_buffer(b)
Definition: buffer.h:294
#define VLIB_NODE_FUNCTION_MULTIARCH(node, fn)
Definition: node.h:158
static uword mpls_input_inline(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: mpls_input.c:72
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:143
u8 data[0]
Packet data.
Definition: buffer.h:152
mpls_main_t * mpls_main
Definition: mpls_input.c:68
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:74
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 void vlib_increment_simple_counter(vlib_simple_counter_main_t *cm, u32 cpu_index, u32 index, u64 increment)
Increment a simple counter.
Definition: counter.h:78
Definition: pg.h:304
Definition: defs.h:46
static_always_inline void vnet_feature_arc_start(u8 arc, u32 sw_if_index, u32 *next0, vlib_buffer_t *b0)
Definition: feature.h:201