FD.io VPP  v20.01-48-g3e0dafb74
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_clones0;
124 
125  /* The original buffer is the first clone */
126  next0 = punt_dp_db[pr0][0];
127  *to_next[0] = bi0;
128  return next0;
129 }
130 
135  u32 thread_index,
136  u32 bi0,
137  u32 * next_index,
138  u32 * n_left_to_next, u32 ** to_next, u32 * n_dispatched)
139 {
140  vlib_punt_reason_t pr0;
141  vlib_buffer_t *b0;
142  u32 next0;
143 
144  b0 = vlib_get_buffer (vm, bi0);
145  pr0 = b0->punt_reason;
146 
147  if (PREDICT_FALSE (pr0 >= vec_len (punt_dp_db)))
148  {
149  b0->error = node->errors[PUNT_ERROR_NO_REASON];
150  next0 = PUNT_NEXT_DROP;
151  }
152  else
153  {
155  (cm, thread_index, pr0, 1, vlib_buffer_length_in_chain (vm, b0));
156 
157  if (PREDICT_TRUE (1 == vec_len (punt_dp_db[pr0])))
158  {
159  /*
160  * one registered client => give it the packet
161  * This is the most likely outcome.
162  */
163  next0 = punt_dp_db[pr0][0];
164  *n_dispatched = *n_dispatched + 1;
165  }
166  else if (0 == vec_len (punt_dp_db[pr0]))
167  {
168  /* no registered clients => drop */
169  next0 = PUNT_NEXT_DROP;
170  b0->error = node->errors[PUNT_ERROR_NO_REG];
171  }
172  else
173  {
174  /*
175  * multiple registered clients => replicate
176  */
177  next0 = punt_replicate (vm, node, thread_index, b0, bi0, pr0,
178  next_index, n_left_to_next, to_next,
179  n_dispatched);
180  }
181  }
182 
183  if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
184  {
185  punt_trace_t *t;
186 
187  t = vlib_add_trace (vm, node, b0, sizeof (*t));
188  t->pt_reason = pr0;
189  }
190 
191  return (next0);
192 }
193 
197 {
198  u32 n_left_from, *from, *to_next, next_index, thread_index;
200  u32 n_dispatched;
201 
202  cm = &punt_counters;
203  from = vlib_frame_vector_args (frame);
204  n_left_from = frame->n_vectors;
205  next_index = node->cached_next_index;
206  thread_index = vlib_get_thread_index ();
207  n_dispatched = 0;
208 
209  while (n_left_from > 0)
210  {
211  u32 n_left_to_next;
212 
213  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
214 
215  while (n_left_from > 4 && n_left_to_next > 2)
216  {
217  punt_next_t next0, next1;
218  u32 bi0, bi1;
219 
220  {
221  vlib_buffer_t *b2, *b3;
222 
223  b2 = vlib_get_buffer (vm, from[2]);
224  b3 = vlib_get_buffer (vm, from[3]);
225 
226  vlib_prefetch_buffer_header (b2, LOAD);
227  vlib_prefetch_buffer_header (b3, LOAD);
228  }
229 
230  bi0 = to_next[0] = from[0];
231  bi1 = to_next[1] = from[1];
232  from += 2;
233  n_left_from -= 2;
234 
235  next0 = punt_dispatch_one (vm, node, cm, thread_index, bi0,
236  &next_index, &n_left_to_next,
237  &to_next, &n_dispatched);
238  next1 = punt_dispatch_one (vm, node, cm, thread_index, bi1,
239  &next_index, &n_left_to_next,
240  &to_next, &n_dispatched);
241 
242  to_next += 2;
243  n_left_to_next -= 2;
244 
245  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
246  to_next, n_left_to_next,
247  bi0, bi1, next0, next1);
248  }
249  while (n_left_from > 0 && n_left_to_next > 0)
250  {
251  punt_next_t next0;
252  u32 bi0;
253 
254  bi0 = to_next[0] = from[0];
255  from += 1;
256  n_left_from -= 1;
257 
258  next0 = punt_dispatch_one (vm, node, cm, thread_index, bi0,
259  &next_index, &n_left_to_next,
260  &to_next, &n_dispatched);
261 
262  to_next += 1;
263  n_left_to_next -= 1;
264 
265  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
266  to_next, n_left_to_next,
267  bi0, next0);
268  }
269  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
270  }
271 
272  vlib_node_increment_counter (vm, node->node_index,
273  PUNT_ERROR_DISPATCHED, n_dispatched);
274 
275  return frame->n_vectors;
276 }
277 
278 /* *INDENT-OFF* */
280  .name = "punt-dispatch",
281  .vector_size = sizeof (u32),
282  .format_trace = format_punt_trace,
283  .n_errors = PUNT_N_ERRORS,
284  .error_strings = punt_error_strings,
285  .n_next_nodes = PUNT_N_NEXT,
286  .next_nodes = {
287  [PUNT_NEXT_DROP] = "drop",
288  },
289 };
290 
291 /* *INDENT-ON* */
292 
293 #ifndef CLIB_MARCH_VARIANT
294 clib_error_t *
296 {
298 
299  return NULL;
300 }
301 
303 #endif
304 
305 /*
306  * fd.io coding-style-patch-verification: ON
307  *
308  * Local Variables:
309  * eval: (c-set-style "gnu")
310  * End:
311  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:440
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
static char * punt_error_strings[]
Definition: punt_node.c:32
#define PREDICT_TRUE(x)
Definition: clib.h:112
#define NULL
Definition: clib.h:58
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:424
#define VLIB_NODE_FN(node)
Definition: node.h:202
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: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
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
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:203
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:41
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:132
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:111
#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: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:338
vlib_main_t * vm
Definition: in2out_ed.c:1810
static void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:1150
u32 punt_reason
Definition: buffer.h:149
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:169
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:218
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:456
vlib_main_t vlib_node_runtime_t * node
Definition: in2out_ed.c:1810
clib_error_t * punt_node_init(vlib_main_t *vm)
Definition: punt_node.c:295
punt_error_t_
Definition: punt_node.c:24
punt_next_t
Definition: punt_node.c:51
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
punt_error_t
Definition: punt_node.c:39
#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:244
punt_next_t_
Definition: punt_node.c:38
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:372
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
Definition: in2out_ed.c:1811
#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:279