FD.io VPP  v19.04.3-1-gdfec10d13
Vector Packet Processing
punt_node.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 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 #include <vlib/punt.h>
17 
18 #define foreach_punt_error \
19  _(DISPATCHED, "dispatched") \
20  _(NO_REASON, "No such punt reason") \
21  _(NO_REG, "No registrations") \
22  _(REP_FAIL, "Replication Faliure")
23 
24 typedef enum punt_error_t_
25 {
26 #define _(v,s) PUNT_ERROR_##v,
28 #undef _
30 } punt_error_t;
31 
32 static char *punt_error_strings[] = {
33 #define _(v,s) [PUNT_ERROR_##v] = s,
35 #undef _
36 };
37 
38 typedef enum punt_next_t_
39 {
42 } punt_next_t;
43 
44 typedef struct punt_trace_t_
45 {
47 } punt_trace_t;
48 
49 /**
50  * Per-thread clone vectors
51  */
52 #ifndef CLIB_MARCH_VARIANT
54 #else
55 extern u32 **punt_clones;
56 #endif
57 
58 static u8 *
59 format_punt_trace (u8 * s, va_list * args)
60 {
61  CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
62  CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
63  punt_trace_t *t = va_arg (*args, punt_trace_t *);
64 
65  s = format (s, "reason: %U", format_vlib_punt_reason, t->pt_reason);
66 
67  return s;
68 }
69 
72  vlib_node_runtime_t * node,
73  u32 thread_index,
74  vlib_buffer_t * b0,
75  u32 bi0,
77  u32 * next_index,
78  u32 * n_left_to_next, u32 ** to_next, u32 * n_dispatched)
79 {
80  /* multiple clients => replicate a copy to each */
81  u16 n_clones0, n_cloned0, clone0;
82  u32 ci0, next0;
83 
84  n_clones0 = vec_len (punt_dp_db[pr0]);
85  vec_validate (punt_clones[thread_index], n_clones0);
86 
87  n_cloned0 = vlib_buffer_clone (vm, bi0,
88  punt_clones[thread_index],
89  n_clones0, 2 * CLIB_CACHE_LINE_BYTES);
90 
91  if (PREDICT_FALSE (n_cloned0 != n_clones0))
92  {
93  b0->error = node->errors[PUNT_ERROR_REP_FAIL];
94  }
95 
96  for (clone0 = 1; clone0 < n_cloned0; clone0++)
97  {
98  ci0 = punt_clones[thread_index][clone0];
99 
100  *to_next[0] = ci0;
101  *to_next += 1;
102  *n_left_to_next -= 1;
103 
104  next0 = punt_dp_db[pr0][clone0];
105 
106  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
107  {
108  vlib_buffer_t *c0;
109  punt_trace_t *t;
110 
111  c0 = vlib_get_buffer (vm, ci0);
112 
113  if (c0 != b0)
114  vlib_buffer_copy_trace_flag (vm, b0, ci0);
115 
116  t = vlib_add_trace (vm, node, c0, sizeof (*t));
117  t->pt_reason = pr0;
118  }
119 
120  vlib_validate_buffer_enqueue_x1 (vm, node, *next_index,
121  *to_next, *n_left_to_next, ci0, next0);
122 
123  /* replications here always go to different next-nodes
124  * so there's no need to check if the to_next frame
125  * is full */
126  }
127  *n_dispatched = *n_dispatched + n_clones0;
128 
129  /* The original buffer is the first clone */
130  next0 = punt_dp_db[pr0][0];
131  *to_next[0] = bi0;
132  return next0;
133 }
134 
137  vlib_node_runtime_t * node,
139  u32 thread_index,
140  u32 bi0,
141  u32 * next_index,
142  u32 * n_left_to_next, u32 ** to_next, u32 * n_dispatched)
143 {
144  vlib_punt_reason_t pr0;
145  vlib_buffer_t *b0;
146  u32 next0;
147 
148  b0 = vlib_get_buffer (vm, bi0);
149  pr0 = b0->punt_reason;
150 
151  if (PREDICT_FALSE (pr0 >= vec_len (punt_dp_db)))
152  {
153  b0->error = node->errors[PUNT_ERROR_NO_REASON];
154  next0 = PUNT_NEXT_DROP;
155  }
156  else
157  {
159  (cm, thread_index, pr0, 1, vlib_buffer_length_in_chain (vm, b0));
160 
161  if (PREDICT_TRUE (1 == vec_len (punt_dp_db[pr0])))
162  {
163  /*
164  * one registered client => give it the packet
165  * This is the most likely outcome.
166  */
167  next0 = punt_dp_db[pr0][0];
168  *n_dispatched = *n_dispatched + 1;
169  }
170  else if (0 == vec_len (punt_dp_db[pr0]))
171  {
172  /* no registered clients => drop */
173  next0 = PUNT_NEXT_DROP;
174  b0->error = node->errors[PUNT_ERROR_NO_REG];
175  }
176  else
177  {
178  /*
179  * multiple registered clients => replicate
180  */
181  next0 = punt_replicate (vm, node, thread_index, b0, bi0, pr0,
182  next_index, n_left_to_next, to_next,
183  n_dispatched);
184  }
185  }
186 
187  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
188  {
189  punt_trace_t *t;
190 
191  t = vlib_add_trace (vm, node, b0, sizeof (*t));
192  t->pt_reason = pr0;
193  }
194 
195  return (next0);
196 }
197 
199  vlib_node_runtime_t * node,
200  vlib_frame_t * frame)
201 {
202  u32 n_left_from, *from, *to_next, next_index, thread_index;
204  u32 n_dispatched;
205 
206  cm = &punt_counters;
207  from = vlib_frame_vector_args (frame);
208  n_left_from = frame->n_vectors;
209  next_index = node->cached_next_index;
210  thread_index = vlib_get_thread_index ();
211  n_dispatched = 0;
212 
213  while (n_left_from > 0)
214  {
215  u32 n_left_to_next;
216 
217  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
218 
219  while (n_left_from > 4 && n_left_to_next > 2)
220  {
221  punt_next_t next0, next1;
222  u32 bi0, bi1;
223 
224  {
225  vlib_buffer_t *b2, *b3;
226 
227  b2 = vlib_get_buffer (vm, from[2]);
228  b3 = vlib_get_buffer (vm, from[3]);
229 
230  vlib_prefetch_buffer_header (b2, LOAD);
231  vlib_prefetch_buffer_header (b3, LOAD);
232  }
233 
234  bi0 = to_next[0] = from[0];
235  bi1 = to_next[1] = from[1];
236  from += 2;
237  n_left_from -= 2;
238 
239  next0 = punt_dispatch_one (vm, node, cm, thread_index, bi0,
240  &next_index, &n_left_to_next,
241  &to_next, &n_dispatched);
242  next1 = punt_dispatch_one (vm, node, cm, thread_index, bi1,
243  &next_index, &n_left_to_next,
244  &to_next, &n_dispatched);
245 
246  to_next += 2;
247  n_left_to_next -= 2;
248 
249  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
250  to_next, n_left_to_next,
251  bi0, bi1, next0, next1);
252  }
253  while (n_left_from > 0 && n_left_to_next > 0)
254  {
255  punt_next_t next0;
256  u32 bi0;
257 
258  bi0 = to_next[0] = from[0];
259  from += 1;
260  n_left_from -= 1;
261 
262  next0 = punt_dispatch_one (vm, node, cm, thread_index, bi0,
263  &next_index, &n_left_to_next,
264  &to_next, &n_dispatched);
265 
266  to_next += 1;
267  n_left_to_next -= 1;
268 
269  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
270  to_next, n_left_to_next,
271  bi0, next0);
272  }
273  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
274  }
275 
276  vlib_node_increment_counter (vm, node->node_index,
277  PUNT_ERROR_DISPATCHED, n_dispatched);
278 
279  return frame->n_vectors;
280 }
281 
282 /* *INDENT-OFF* */
284  .name = "punt-dispatch",
285  .vector_size = sizeof (u32),
286  .format_trace = format_punt_trace,
287  .n_errors = PUNT_N_ERRORS,
288  .error_strings = punt_error_strings,
289  .n_next_nodes = PUNT_N_NEXT,
290  .next_nodes = {
291  [PUNT_NEXT_DROP] = "drop",
292  },
293 };
294 
295 /* *INDENT-ON* */
296 
297 #ifndef CLIB_MARCH_VARIANT
298 clib_error_t *
300 {
302 
303  return NULL;
304 }
305 
307 #endif
308 
309 /*
310  * fd.io coding-style-patch-verification: ON
311  *
312  * Local Variables:
313  * eval: (c-set-style "gnu")
314  * End:
315  */
u32 ** punt_clones
Per-thread clone vectors.
Definition: punt_node.c:53
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:439
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:124
#define CLIB_UNUSED(x)
Definition: clib.h:82
static void vlib_increment_combined_counter(vlib_combined_counter_main_t *cm, u32 thread_index, u32 index, u64 n_packets, u64 n_bytes)
Increment a combined counter.
Definition: counter.h:220
#define PREDICT_TRUE(x)
Definition: clib.h:112
#define NULL
Definition: clib.h:58
enum punt_next_t_ punt_next_t
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define VLIB_NODE_FN(node)
Definition: node.h:201
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:469
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:366
unsigned char u8
Definition: types.h:56
u8 * format_vlib_punt_reason(u8 *s, va_list *args)
Format a punt reason.
Definition: punt.c:132
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:163
static u32 punt_dispatch_one(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_combined_counter_main_t *cm, u32 thread_index, u32 bi0, u32 *next_index, u32 *n_left_to_next, u32 **to_next, u32 *n_dispatched)
Definition: punt_node.c:136
#define always_inline
Definition: clib.h:98
static u8 * format_punt_trace(u8 *s, va_list *args)
Definition: punt_node.c:59
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
unsigned int u32
Definition: types.h:88
struct punt_trace_t_ punt_trace_t
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
clib_error_t * punt_node_init(vlib_main_t *vm)
Definition: punt_node.c:299
vlib_punt_reason_t pt_reason
Definition: punt_node.c:46
unsigned short u16
Definition: types.h:57
#define PREDICT_FALSE(x)
Definition: clib.h:111
#define foreach_punt_error
Definition: punt_node.c:18
#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:368
punt_error_t_
Definition: punt_node.c:24
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1180
punt_next_t
Definition: punt.c:45
u32 punt_reason
Definition: buffer.h:149
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
static void vlib_buffer_copy_trace_flag(vlib_main_t *vm, vlib_buffer_t *b, u32 bi_target)
Definition: trace_funcs.h:147
static u16 vlib_buffer_clone(vlib_main_t *vm, u32 src_buffer, u32 *buffers, u16 n_buffers, u16 head_end_offset)
Create multiple clones of buffer and store them in the supplied array.
static_always_inline uword vlib_get_thread_index(void)
Definition: threads.h:212
vlib_main_t * vm
Definition: buffer.c:312
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:465
static char * punt_error_strings[]
Definition: punt_node.c:32
enum punt_error_t_ punt_error_t
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
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
vlib_combined_counter_main_t punt_counters
Counters per punt-reason.
Definition: punt.c:26
VLIB buffer representation.
Definition: buffer.h:102
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
Definition: node_funcs.h:274
A collection of combined counters.
Definition: counter.h:188
u16 ** punt_dp_db
A DB used in the DP per-reason to dispatch packets to the requested nodes.
Definition: punt.c:103
static u32 vlib_num_workers()
Definition: threads.h:366
vlib_node_registration_t punt_dispatch_node
(constructor) VLIB_REGISTER_NODE (punt_dispatch_node)
Definition: punt_node.c:283
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:59
enum vlib_punt_reason_t_ vlib_punt_reason_t
The &#39;syatem&#39; defined punt reasons.
static u32 punt_replicate(vlib_main_t *vm, vlib_node_runtime_t *node, u32 thread_index, vlib_buffer_t *b0, u32 bi0, vlib_punt_reason_t pr0, u32 *next_index, u32 *n_left_to_next, u32 **to_next, u32 *n_dispatched)
Definition: punt_node.c:71
punt_next_t_
Definition: punt_node.c:38
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85