FD.io VPP  v18.01-8-g0eacf49
Vector Packet Processing
node_serialize.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 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 #include <vlib/vlib.h>
16 
17 #include <vppinfra/serialize.h>
18 
19 extern void vl_msg_api_barrier_sync (void);
20 extern void vl_msg_api_barrier_release (void);
21 
22 /* serialized representation of state strings */
23 
24 #define foreach_state_string_code \
25 _(STATE_DONE, "done") \
26 _(STATE_DISABLED, "disabled") \
27 _(STATE_TIME_WAIT, "time wait") \
28 _(STATE_EVENT_WAIT, "event wait") \
29 _(STATE_ANY_WAIT, "any wait") \
30 _(STATE_POLLING, "polling") \
31 _(STATE_INTERRUPT_WAIT, "interrupt wait") \
32 _(STATE_INTERNAL, "internal")
33 
34 typedef enum
35 {
36 #define _(a,b) a,
38 #undef _
40 
41 static char *state_strings[] = {
42 #define _(a,b) b,
44 #undef _
45 };
46 
47 /*
48  * Serialize a vlib_node_main_t. Appends the result to vector.
49  * Pass 0 to create a new vector, use vec_reset_length(vector)
50  * to recycle a vector / avoid memory allocation, etc.
51  * Switch heaps before/after to serialize into API client shared memory.
52  */
53 
54 u8 *
56  u32 max_threads, int include_nexts, int include_stats)
57 {
58  serialize_main_t _sm, *sm = &_sm;
59  vlib_main_t *vm = vlib_get_main ();
60  vlib_node_t *n;
61  static vlib_node_t ***node_dups;
62  vlib_node_t **nodes;
63  static vlib_main_t **stat_vms;
64  vlib_main_t *stat_vm;
65  u8 *namep;
66  u32 name_bytes;
67  uword i, j, k;
68  u64 l, v, c, d;
69  state_string_enum_t state_code;
70  u32 threads_to_serialize;
71 
72  vec_reset_length (node_dups);
73 
74  if (vec_len (stat_vms) == 0)
75  {
76  for (i = 0; i < vec_len (vlib_mains); i++)
77  {
78  stat_vm = vlib_mains[i];
79  if (stat_vm)
80  vec_add1 (stat_vms, stat_vm);
81  }
82  }
83 
84  threads_to_serialize = clib_min (max_threads, vec_len (stat_vms));
85 
86  /*
87  * Barrier sync across stats scraping.
88  * Otherwise, the counts will be grossly inaccurate.
89  */
91 
92  for (j = 0; j < threads_to_serialize; j++)
93  {
94  stat_vm = stat_vms[j];
95  nm = &stat_vm->node_main;
96 
97  if (include_stats)
98  {
99  for (i = 0; i < vec_len (nm->nodes); i++)
100  {
101  n = nm->nodes[i];
102  vlib_node_sync_stats (stat_vm, n);
103  }
104  }
105 
106  nodes = vec_dup (nm->nodes);
107 
108  vec_add1 (node_dups, nodes);
109  }
111 
112  serialize_open_vector (sm, vector);
113 
115 
116  for (j = 0; j < vec_len (stat_vms); j++)
117  {
118  stat_vm = stat_vms[j];
119  nodes = node_dups[j];
120 
121  serialize_likely_small_unsigned_integer (sm, vec_len (nodes));
122 
123  for (i = 0; i < vec_len (nodes); i++)
124  {
125  n = nodes[i];
126 
131 
132  state_code = STATE_INTERNAL;
133 
134  if (n->type == VLIB_NODE_TYPE_PROCESS)
135  {
137 
138  switch (p->flags
141  {
142  default:
143  if (!(p->flags & VLIB_PROCESS_IS_RUNNING))
144  state_code = STATE_DONE;
145  break;
146 
148  state_code = STATE_TIME_WAIT;
149  break;
150 
152  state_code = STATE_EVENT_WAIT;
153  break;
154 
156  state_code =
157  STATE_ANY_WAIT;
158  break;
159  }
160  }
161  else if (n->type != VLIB_NODE_TYPE_INTERNAL)
162  {
163  state_code = STATE_POLLING;
164  if (n->state == VLIB_NODE_STATE_DISABLED)
165  state_code = STATE_DISABLED;
166  else if (n->state == VLIB_NODE_STATE_INTERRUPT)
167  state_code = STATE_INTERRUPT_WAIT;
168  }
169 
170  /* See unserialize_cstring */
171  name_bytes = vec_len (n->name);
173  namep = serialize_get (sm, name_bytes);
174  memcpy (namep, n->name, name_bytes);
175 
176  serialize_likely_small_unsigned_integer (sm, (u64) state_code);
178 
179  if (include_nexts)
180  {
182  (sm, vec_len (n->next_nodes));
183  for (k = 0; k < vec_len (n->next_nodes); k++)
185  n->next_nodes[k]);
186  }
187  else
189 
190  if (include_stats)
191  {
192  /* stats present */
194  /* total clocks */
195  serialize_integer (sm, l, 8);
196  /* Total calls */
197  serialize_integer (sm, c, 8);
198  /* Total vectors */
199  serialize_integer (sm, v, 8);
200  /* Total suspends */
201  serialize_integer (sm, d, 8);
202  }
203  else /* no stats */
205  }
206  vec_free (nodes);
207  }
208  return (serialize_close_vector (sm));
209 }
210 
211 vlib_node_t ***
213 {
214  serialize_main_t _sm, *sm = &_sm;
215  u32 nnodes, nnexts;
216  u32 nstat_vms;
217  vlib_node_t *node;
218  vlib_node_t **nodes;
219  vlib_node_t ***nodes_by_thread = 0;
220  int i, j, k;
221  u64 l, v, c, d;
222  state_string_enum_t state_code;
223  int stats_present;
224 
225  serialize_open_vector (sm, vector);
226 
228 
229  vec_validate (nodes_by_thread, nstat_vms - 1);
230  _vec_len (nodes_by_thread) = 0;
231 
232  for (i = 0; i < nstat_vms; i++)
233  {
235 
236  nodes = 0;
237  vec_validate (nodes, nnodes - 1);
238  vec_add1 (nodes_by_thread, nodes);
239 
240  for (j = 0; j < nnodes; j++)
241  {
242  node = 0;
243  vec_validate (node, 0);
244  nodes[j] = node;
245 
246  unserialize_cstring (sm, (char **) &(node->name));
248  node->state_string = (u8 *) state_strings[state_code];
249 
252  if (nnexts > 0)
253  vec_validate (node->next_nodes, nnexts - 1);
254  for (k = 0; k < nnexts; k++)
255  node->next_nodes[k] =
257 
258  stats_present = unserialize_likely_small_unsigned_integer (sm);
259 
260  if (stats_present)
261  {
262  /* total clocks */
263  unserialize_integer (sm, &l, 8);
264  node->stats_total.clocks = l;
265  node->stats_last_clear.clocks = 0;
266 
267  /* Total calls */
268  unserialize_integer (sm, &c, 8);
269  node->stats_total.calls = c;
270 
271  /* Total vectors */
272  unserialize_integer (sm, &v, 8);
273  node->stats_total.vectors = v;
274 
275  /* Total suspends */
276  unserialize_integer (sm, &d, 8);
277  node->stats_total.suspends = d;
278  }
279  }
280  }
281  return nodes_by_thread;
282 }
283 
284 #if TEST_CODE
285 
286 static clib_error_t *
287 test_node_serialize_command_fn (vlib_main_t * vm,
288  unformat_input_t * input,
289  vlib_cli_command_t * cmd)
290 {
291  vlib_node_main_t *nm = &vm->node_main;
292  u8 *vector = 0;
293  vlib_node_t ***nodes_by_thread;
294  vlib_node_t **nodes;
295  vlib_node_t *node;
296  vlib_node_t *next_node;
297  int i, j, k;
298  u32 max_threads = (u32) ~ 0;
299  int include_nexts = 0;
300  int include_stats = 0;
301 
303  {
304  if (unformat (input, "max-threads %d", &max_threads))
305  ;
306  else if (unformat (input, "stats"))
307  include_stats = 1;
308  else if (unformat (input, "nexts"))
309  include_nexts = 1;
310  else
311  break;
312  }
313 
314  /*
315  * Keep the number of memcpy ops to a minimum (e.g. 1).
316  * The current size of the serialized vector is
317  * slightly under 4K.
318  */
319  vec_validate (vector, 16383);
320  vec_reset_length (vector);
321 
322  vector = vlib_node_serialize (nm, vector, max_threads,
323  include_nexts, include_stats);
324 
325  vlib_cli_output (vm, "result vector %d bytes", vec_len (vector));
326 
327  nodes_by_thread = vlib_node_unserialize (vector);
328 
329  vec_free (vector);
330 
331  for (i = 0; i < vec_len (nodes_by_thread); i++)
332  {
333  nodes = nodes_by_thread[i];
334 
335  vlib_cli_output (vm, "thread %d", i);
336 
337  for (j = 0; j < vec_len (nodes); j++)
338  {
339  node = nodes[j];
340 
341  vlib_cli_output (vm, "[%d] %s state %s", j, node->name,
342  node->state_string);
343 
345  (vm, " clocks %lld calls %lld suspends"
346  " %lld vectors %lld",
347  node->stats_total.clocks,
348  node->stats_total.calls,
349  node->stats_total.suspends, node->stats_total.vectors);
350 
351  for (k = 0; k < vec_len (node->next_nodes); k++)
352  {
353  if (node->next_nodes[k] != ~0)
354  {
355  next_node = nodes[node->next_nodes[k]];
356  vlib_cli_output (vm, " [%d] %s", k, next_node->name);
357  }
358  }
359  }
360  }
361 
362  for (j = 0; j < vec_len (nodes_by_thread); j++)
363  {
364  nodes = nodes_by_thread[j];
365 
366  for (i = 0; i < vec_len (nodes); i++)
367  {
368  vec_free (nodes[i]->name);
369  vec_free (nodes[i]->next_nodes);
370  vec_free (nodes[i]);
371  }
372  vec_free (nodes);
373  }
374  vec_free (nodes_by_thread);
375 
376  return 0;
377 }
378 
379 /* *INDENT-OFF* */
380 VLIB_CLI_COMMAND (test_node_serialize_node, static) = {
381  .path = "test node serialize",
382  .short_help = "test node serialize [max-threads NN] nexts stats",
383  .function = test_node_serialize_command_fn,
384 };
385 /* *INDENT-ON* */
386 #endif
387 
388 /*
389  * fd.io coding-style-patch-verification: ON
390  *
391  * Local Variables:
392  * eval: (c-set-style "gnu")
393  * End:
394  */
u32 * next_nodes
Definition: node.h:288
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:432
u8 * state_string
Definition: node.h:322
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:337
#define clib_min(x, y)
Definition: clib.h:340
static u64 unserialize_likely_small_unsigned_integer(serialize_main_t *m)
Definition: serialize.h:254
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:518
state_string_enum_t
#define foreach_state_string_code
u8 * vlib_node_serialize(vlib_node_main_t *nm, u8 *vector, u32 max_threads, int include_nexts, int include_stats)
vlib_main_t ** vlib_mains
Definition: buffer.c:292
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
u8 state
Definition: node.h:265
vlib_node_stats_t stats_last_clear
Definition: node.h:231
vlib_node_t ** nodes
Definition: node.h:640
static void * serialize_get(serialize_main_t *m, uword n_bytes)
Definition: serialize.h:178
unsigned long u64
Definition: types.h:89
vlib_node_stats_t stats_total
Definition: node.h:227
static void serialize_likely_small_unsigned_integer(serialize_main_t *m, u64 x)
Definition: serialize.h:218
#define v
Definition: acl.c:341
struct _unformat_input_t unformat_input_t
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:370
void unserialize_cstring(serialize_main_t *m, char **s)
Definition: serialize.c:178
u8 * name
Definition: node.h:221
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
svmdb_client_t * c
void serialize_open_vector(serialize_main_t *m, u8 *vector)
Definition: serialize.c:908
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:336
void vl_msg_api_barrier_sync(void)
Definition: api_shared.c:383
static void unserialize_integer(serialize_main_t *m, void *x, u32 n_bytes)
Definition: serialize.h:201
static void serialize_integer(serialize_main_t *m, u64 x, u32 n_bytes)
Definition: serialize.h:185
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:154
#define VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT
Definition: node.h:510
unsigned int u32
Definition: types.h:88
static vlib_main_t * vlib_get_main(void)
Definition: global_funcs.h:23
u64 uword
Definition: types.h:112
void vlib_node_sync_stats(vlib_main_t *vm, vlib_node_t *n)
Definition: main.c:570
void vl_msg_api_barrier_release(void)
Definition: api_shared.c:388
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
vlib_node_main_t node_main
Definition: main.h:129
static char * state_strings[]
#define VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
Definition: node.h:509
u16 flags
Definition: node.h:508
vlib_node_type_t type
Definition: node.h:234
static vlib_process_t * vlib_get_process_from_node(vlib_main_t *vm, vlib_node_t *node)
Definition: node_funcs.h:207
vlib_node_t *** vlib_node_unserialize(u8 *vector)
void * serialize_close_vector(serialize_main_t *m)
Definition: serialize.c:918
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:680
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
#define VLIB_PROCESS_IS_RUNNING
Definition: node.h:515