FD.io VPP  v21.01.1
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 Failure")
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 
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  t = vlib_add_trace (vm, node, c0, sizeof (*t));
113  t->pt_reason = pr0;
114  }
115 
116  vlib_validate_buffer_enqueue_x1 (vm, node, *next_index,
117  *to_next, *n_left_to_next, ci0, next0);
118 
119  /* replications here always go to different next-nodes
120  * so there's no need to check if the to_next frame
121  * is full */
122  }
123  *n_dispatched = *n_dispatched + n_cloned0;
124 
125  /* The original buffer is the first clone */
126  next0 = punt_dp_db[pr0][0];
127  /*
128  * Note: the original buffer is enqueued in punt_dispatch_node.
129  * Don't do it here.
130  *
131  * *to_next[0] = bi0;
132  */
133  return next0;
134 }
135 
140  u32 thread_index,
141  u32 bi0,
142  u32 * next_index,
143  u32 * n_left_to_next, u32 ** to_next, u32 * n_dispatched)
144 {
145  vlib_punt_reason_t pr0;
146  vlib_buffer_t *b0;
147  u32 next0;
148 
149  b0 = vlib_get_buffer (vm, bi0);
150  pr0 = b0->punt_reason;
151 
152  if (PREDICT_FALSE (pr0 >= vec_len (punt_dp_db)))
153  {
154  b0->error = node->errors[PUNT_ERROR_NO_REASON];
155  next0 = PUNT_NEXT_DROP;
156  }
157  else
158  {
160  (cm, thread_index, pr0, 1, vlib_buffer_length_in_chain (vm, b0));
161 
162  if (PREDICT_TRUE (1 == vec_len (punt_dp_db[pr0])))
163  {
164  /*
165  * one registered client => give it the packet
166  * This is the most likely outcome.
167  */
168  next0 = punt_dp_db[pr0][0];
169  *n_dispatched = *n_dispatched + 1;
170  }
171  else if (0 == vec_len (punt_dp_db[pr0]))
172  {
173  /* no registered clients => drop */
174  next0 = PUNT_NEXT_DROP;
175  b0->error = node->errors[PUNT_ERROR_NO_REG];
176  }
177  else
178  {
179  /*
180  * multiple registered clients => replicate
181  */
182  next0 = punt_replicate (vm, node, thread_index, b0, bi0, pr0,
183  next_index, n_left_to_next, to_next,
184  n_dispatched);
185  }
186  }
187 
188  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
189  {
190  punt_trace_t *t;
191 
192  t = vlib_add_trace (vm, node, b0, sizeof (*t));
193  t->pt_reason = pr0;
194  }
195 
196  return (next0);
197 }
198 
202 {
203  u32 n_left_from, *from, *to_next, next_index, thread_index;
205  u32 n_dispatched;
206 
207  cm = &punt_counters;
208  from = vlib_frame_vector_args (frame);
209  n_left_from = frame->n_vectors;
210  next_index = node->cached_next_index;
211  thread_index = vlib_get_thread_index ();
212  n_dispatched = 0;
213 
214  while (n_left_from > 0)
215  {
216  u32 n_left_to_next;
217 
218  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
219 
220  while (n_left_from > 4 && n_left_to_next > 2)
221  {
222  punt_next_t next0, next1;
223  u32 bi0, bi1;
224 
225  {
226  vlib_buffer_t *b2, *b3;
227 
228  b2 = vlib_get_buffer (vm, from[2]);
229  b3 = vlib_get_buffer (vm, from[3]);
230 
231  vlib_prefetch_buffer_header (b2, LOAD);
232  vlib_prefetch_buffer_header (b3, LOAD);
233  }
234 
235  bi0 = to_next[0] = from[0];
236  bi1 = to_next[1] = from[1];
237  from += 2;
238  n_left_from -= 2;
239 
240  next0 = punt_dispatch_one (vm, node, cm, thread_index, bi0,
241  &next_index, &n_left_to_next,
242  &to_next, &n_dispatched);
243  next1 = punt_dispatch_one (vm, node, cm, thread_index, bi1,
244  &next_index, &n_left_to_next,
245  &to_next, &n_dispatched);
246 
247  to_next += 2;
248  n_left_to_next -= 2;
249 
250  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
251  to_next, n_left_to_next,
252  bi0, bi1, next0, next1);
253  }
254  while (n_left_from > 0 && n_left_to_next > 0)
255  {
256  punt_next_t next0;
257  u32 bi0;
258 
259  bi0 = to_next[0] = from[0];
260  from += 1;
261  n_left_from -= 1;
262 
263  next0 = punt_dispatch_one (vm, node, cm, thread_index, bi0,
264  &next_index, &n_left_to_next,
265  &to_next, &n_dispatched);
266 
267  to_next += 1;
268  n_left_to_next -= 1;
269 
270  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
271  to_next, n_left_to_next,
272  bi0, next0);
273  }
274  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
275  }
276 
277  vlib_node_increment_counter (vm, node->node_index,
278  PUNT_ERROR_DISPATCHED, n_dispatched);
279 
280  return frame->n_vectors;
281 }
282 
283 /* *INDENT-OFF* */
285  .name = "punt-dispatch",
286  .vector_size = sizeof (u32),
287  .format_trace = format_punt_trace,
288  .n_errors = PUNT_N_ERRORS,
289  .error_strings = punt_error_strings,
290  .n_next_nodes = PUNT_N_NEXT,
291  .next_nodes = {
292  [PUNT_NEXT_DROP] = "drop",
293  },
294 };
295 
296 /* *INDENT-ON* */
297 
298 #ifndef CLIB_MARCH_VARIANT
299 clib_error_t *
301 {
303 
304  return NULL;
305 }
306 
308 #endif
309 
310 /*
311  * fd.io coding-style-patch-verification: ON
312  *
313  * Local Variables:
314  * eval: (c-set-style "gnu")
315  * End:
316  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:509
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:87
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:239
static char * punt_error_strings[]
Definition: punt_node.c:32
#define PREDICT_TRUE(x)
Definition: clib.h:122
vlib_main_t * vm
Definition: in2out_ed.c:1580
#define VLIB_NODE_FN(node)
Definition: node.h:203
vlib_error_t * errors
Vector of errors for this node.
Definition: node.h:470
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:402
unsigned char u8
Definition: types.h:56
u8 * format_vlib_punt_reason(u8 *s, va_list *args)
Format a punt reason.
Definition: punt.c:148
static u8 * format_punt_trace(u8 *s, va_list *args)
Definition: punt_node.c:59
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:173
struct punt_trace_t_ punt_trace_t
description fragment has unexpected format
Definition: map.api:433
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:207
unsigned int u32
Definition: types.h:88
u32 ** punt_clones
Per-thread clone vectors.
Definition: punt_node.c:53
#define foreach_punt_error
Definition: punt_node.c:18
vlib_error_t error
Error code for buffers to be enqueued to error handler.
Definition: buffer.h:136
vnet_crypto_main_t * cm
Definition: quic_crypto.c:53
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:137
vlib_punt_reason_t pt_reason
Definition: punt_node.c:46
unsigned short u16
Definition: types.h:57
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
#define PREDICT_FALSE(x)
Definition: clib.h:121
#define always_inline
Definition: ipsec.h:28
#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:224
#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:391
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1231
u32 punt_reason
Definition: buffer.h:149
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:170
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:219
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:483
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1580
clib_error_t * punt_node_init(vlib_main_t *vm)
Definition: punt_node.c:300
punt_error_t_
Definition: punt_node.c:24
punt_next_t
Definition: punt_node.c:48
punt_error_t
Definition: punt_node.c:36
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1581
vlib_combined_counter_main_t punt_counters
Counters per punt-reason.
Definition: punt.c:27
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:297
punt_next_t_
Definition: punt_node.c:38
A collection of combined counters.
Definition: counter.h:207
u16 ** punt_dp_db
A DB used in the DP per-reason to dispatch packets to the requested nodes.
Definition: punt.c:119
static u32 vlib_num_workers()
Definition: threads.h:377
void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace.c:634
#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 vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:85
vlib_node_registration_t punt_dispatch_node
(constructor) VLIB_REGISTER_NODE (punt_dispatch_node)
Definition: punt_node.c:284