blob: 50e5c41c2190953554c6e0891cb22d78d1d207c2 [file] [log] [blame]
Dave Barachb44e9bc2016-02-19 09:06:23 -05001/*
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
Dave Barach371e4e12016-07-08 09:38:52 -040019extern void vl_msg_api_barrier_sync (void);
20extern void vl_msg_api_barrier_release (void);
Dave Barach6931f592016-05-13 12:55:01 -040021
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
Dave Barach371e4e12016-07-08 09:38:52 -040034typedef enum
35{
Dave Barach6931f592016-05-13 12:55:01 -040036#define _(a,b) a,
37 foreach_state_string_code
38#undef _
39} state_string_enum_t;
40
Dave Barach371e4e12016-07-08 09:38:52 -040041static char *state_strings[] = {
Dave Barach6931f592016-05-13 12:55:01 -040042#define _(a,b) b,
Dave Barach371e4e12016-07-08 09:38:52 -040043 foreach_state_string_code
Dave Barach6931f592016-05-13 12:55:01 -040044#undef _
Dave Barach371e4e12016-07-08 09:38:52 -040045};
Dave Barach6931f592016-05-13 12:55:01 -040046
Dave Barach371e4e12016-07-08 09:38:52 -040047/*
Dave Barachb44e9bc2016-02-19 09:06:23 -050048 * 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
Dave Barach371e4e12016-07-08 09:38:52 -040054u8 *
55vlib_node_serialize (vlib_node_main_t * nm, u8 * vector,
56 u32 max_threads, int include_nexts, int include_stats)
Dave Barachb44e9bc2016-02-19 09:06:23 -050057{
Dave Barach371e4e12016-07-08 09:38:52 -040058 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;
Dave Barach6931f592016-05-13 12:55:01 -040064 vlib_main_t *stat_vm;
Dave Barach371e4e12016-07-08 09:38:52 -040065 u8 *namep;
Dave Barach6931f592016-05-13 12:55:01 -040066 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;
Dave Barach6931f592016-05-13 12:55:01 -040071
Dave Barach371e4e12016-07-08 09:38:52 -040072 vec_reset_length (node_dups);
73
74 if (vec_len (stat_vms) == 0)
Dave Barach6931f592016-05-13 12:55:01 -040075 {
Dave Barach80f54e22017-03-08 19:08:56 -050076 for (i = 0; i < vec_len (vlib_mains); i++)
Dave Barach371e4e12016-07-08 09:38:52 -040077 {
Dave Barach80f54e22017-03-08 19:08:56 -050078 stat_vm = vlib_mains[i];
79 if (stat_vm)
80 vec_add1 (stat_vms, stat_vm);
Dave Barach371e4e12016-07-08 09:38:52 -040081 }
Dave Barach6931f592016-05-13 12:55:01 -040082 }
83
84 threads_to_serialize = clib_min (max_threads, vec_len (stat_vms));
85
Dave Barach371e4e12016-07-08 09:38:52 -040086 /*
Dave Barach6931f592016-05-13 12:55:01 -040087 * Barrier sync across stats scraping.
88 * Otherwise, the counts will be grossly inaccurate.
89 */
Dave Barach371e4e12016-07-08 09:38:52 -040090 vl_msg_api_barrier_sync ();
Dave Barach6931f592016-05-13 12:55:01 -040091
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)
Dave Barach371e4e12016-07-08 09:38:52 -040098 {
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 }
Dave Barach6931f592016-05-13 12:55:01 -0400105
106 nodes = vec_dup (nm->nodes);
Dave Barach371e4e12016-07-08 09:38:52 -0400107
108 vec_add1 (node_dups, nodes);
Dave Barach6931f592016-05-13 12:55:01 -0400109 }
Dave Barach371e4e12016-07-08 09:38:52 -0400110 vl_msg_api_barrier_release ();
111
Dave Barachb44e9bc2016-02-19 09:06:23 -0500112 serialize_open_vector (sm, vector);
Dave Barach6931f592016-05-13 12:55:01 -0400113
Dave Barach371e4e12016-07-08 09:38:52 -0400114 serialize_likely_small_unsigned_integer (sm, vec_len (stat_vms));
115
Dave Barach6931f592016-05-13 12:55:01 -0400116 for (j = 0; j < vec_len (stat_vms); j++)
Dave Barachb44e9bc2016-02-19 09:06:23 -0500117 {
Dave Barach6931f592016-05-13 12:55:01 -0400118 stat_vm = stat_vms[j];
119 nodes = node_dups[j];
120
Dave Barach371e4e12016-07-08 09:38:52 -0400121 serialize_likely_small_unsigned_integer (sm, vec_len (nodes));
Dave Barach6931f592016-05-13 12:55:01 -0400122
123 for (i = 0; i < vec_len (nodes); i++)
Dave Barach371e4e12016-07-08 09:38:52 -0400124 {
125 n = nodes[i];
Dave Barach6931f592016-05-13 12:55:01 -0400126
Dave Barach371e4e12016-07-08 09:38:52 -0400127 l = n->stats_total.clocks - n->stats_last_clear.clocks;
128 v = n->stats_total.vectors - n->stats_last_clear.vectors;
129 c = n->stats_total.calls - n->stats_last_clear.calls;
130 d = n->stats_total.suspends - n->stats_last_clear.suspends;
Dave Barach6931f592016-05-13 12:55:01 -0400131
Dave Barach371e4e12016-07-08 09:38:52 -0400132 state_code = STATE_INTERNAL;
Dave Barach6931f592016-05-13 12:55:01 -0400133
Dave Barach371e4e12016-07-08 09:38:52 -0400134 if (n->type == VLIB_NODE_TYPE_PROCESS)
135 {
136 vlib_process_t *p = vlib_get_process_from_node (vm, n);
Dave Barach6931f592016-05-13 12:55:01 -0400137
Dave Barach371e4e12016-07-08 09:38:52 -0400138 switch (p->flags
139 & (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
140 | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT))
141 {
142 default:
143 if (!(p->flags & VLIB_PROCESS_IS_RUNNING))
144 state_code = STATE_DONE;
145 break;
Dave Barach6931f592016-05-13 12:55:01 -0400146
Dave Barach371e4e12016-07-08 09:38:52 -0400147 case VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK:
148 state_code = STATE_TIME_WAIT;
149 break;
Dave Barach6931f592016-05-13 12:55:01 -0400150
Dave Barach371e4e12016-07-08 09:38:52 -0400151 case VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT:
152 state_code = STATE_EVENT_WAIT;
153 break;
Dave Barach6931f592016-05-13 12:55:01 -0400154
Dave Barach371e4e12016-07-08 09:38:52 -0400155 case (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK):
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 }
Dave Barach6931f592016-05-13 12:55:01 -0400169
Dave Barach371e4e12016-07-08 09:38:52 -0400170 /* See unserialize_cstring */
171 name_bytes = vec_len (n->name);
172 serialize_likely_small_unsigned_integer (sm, name_bytes);
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);
177 serialize_likely_small_unsigned_integer (sm, n->type);
178
179 if (include_nexts)
180 {
181 serialize_likely_small_unsigned_integer
182 (sm, vec_len (n->next_nodes));
183 for (k = 0; k < vec_len (n->next_nodes); k++)
184 serialize_likely_small_unsigned_integer (sm,
185 n->next_nodes[k]);
186 }
187 else
188 serialize_likely_small_unsigned_integer (sm, 0);
189
190 if (include_stats)
191 {
192 /* stats present */
193 serialize_likely_small_unsigned_integer (sm, 1);
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 */
204 serialize_likely_small_unsigned_integer (sm, 0);
205 }
Dave Barach6931f592016-05-13 12:55:01 -0400206 vec_free (nodes);
Dave Barachb44e9bc2016-02-19 09:06:23 -0500207 }
Dave Barachb44e9bc2016-02-19 09:06:23 -0500208 return (serialize_close_vector (sm));
209}
210
Dave Barach371e4e12016-07-08 09:38:52 -0400211vlib_node_t ***
212vlib_node_unserialize (u8 * vector)
Dave Barachb44e9bc2016-02-19 09:06:23 -0500213{
Dave Barach371e4e12016-07-08 09:38:52 -0400214 serialize_main_t _sm, *sm = &_sm;
Dave Barachb44e9bc2016-02-19 09:06:23 -0500215 u32 nnodes, nnexts;
Dave Barach6931f592016-05-13 12:55:01 -0400216 u32 nstat_vms;
Dave Barach371e4e12016-07-08 09:38:52 -0400217 vlib_node_t *node;
218 vlib_node_t **nodes;
219 vlib_node_t ***nodes_by_thread = 0;
Dave Barach6931f592016-05-13 12:55:01 -0400220 int i, j, k;
221 u64 l, v, c, d;
222 state_string_enum_t state_code;
223 int stats_present;
Dave Barachb44e9bc2016-02-19 09:06:23 -0500224
225 serialize_open_vector (sm, vector);
Dave Barach371e4e12016-07-08 09:38:52 -0400226
Dave Barach6931f592016-05-13 12:55:01 -0400227 nstat_vms = unserialize_likely_small_unsigned_integer (sm);
Dave Barachb44e9bc2016-02-19 09:06:23 -0500228
Dave Barach6931f592016-05-13 12:55:01 -0400229 vec_validate (nodes_by_thread, nstat_vms - 1);
230 _vec_len (nodes_by_thread) = 0;
Dave Barachb44e9bc2016-02-19 09:06:23 -0500231
Dave Barach6931f592016-05-13 12:55:01 -0400232 for (i = 0; i < nstat_vms; i++)
Dave Barachb44e9bc2016-02-19 09:06:23 -0500233 {
Dave Barach6931f592016-05-13 12:55:01 -0400234 nnodes = unserialize_likely_small_unsigned_integer (sm);
Dave Barachb44e9bc2016-02-19 09:06:23 -0500235
Dave Barach6931f592016-05-13 12:55:01 -0400236 nodes = 0;
Dave Barach371e4e12016-07-08 09:38:52 -0400237 vec_validate (nodes, nnodes - 1);
Dave Barach6931f592016-05-13 12:55:01 -0400238 vec_add1 (nodes_by_thread, nodes);
239
240 for (j = 0; j < nnodes; j++)
Dave Barach371e4e12016-07-08 09:38:52 -0400241 {
242 node = 0;
243 vec_validate (node, 0);
244 nodes[j] = node;
Dave Barach6931f592016-05-13 12:55:01 -0400245
Dave Barach371e4e12016-07-08 09:38:52 -0400246 unserialize_cstring (sm, (char **) &(node->name));
247 state_code = unserialize_likely_small_unsigned_integer (sm);
248 node->state_string = (u8 *) state_strings[state_code];
Dave Barach6931f592016-05-13 12:55:01 -0400249
Dave Barach371e4e12016-07-08 09:38:52 -0400250 node->type = unserialize_likely_small_unsigned_integer (sm);
251 nnexts = unserialize_likely_small_unsigned_integer (sm);
252 if (nnexts > 0)
253 vec_validate (node->next_nodes, nnexts - 1);
254 for (k = 0; k < nnexts; k++)
255 node->next_nodes[k] =
256 unserialize_likely_small_unsigned_integer (sm);
Dave Barach6931f592016-05-13 12:55:01 -0400257
Dave Barach371e4e12016-07-08 09:38:52 -0400258 stats_present = unserialize_likely_small_unsigned_integer (sm);
Dave Barach6931f592016-05-13 12:55:01 -0400259
Dave Barach371e4e12016-07-08 09:38:52 -0400260 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 }
Dave Barachb44e9bc2016-02-19 09:06:23 -0500280 }
Dave Barach371e4e12016-07-08 09:38:52 -0400281 return nodes_by_thread;
Dave Barachb44e9bc2016-02-19 09:06:23 -0500282}
283
Dave Barach80f54e22017-03-08 19:08:56 -0500284#if TEST_CODE
Dave Barachb44e9bc2016-02-19 09:06:23 -0500285
286static clib_error_t *
287test_node_serialize_command_fn (vlib_main_t * vm,
Dave Barach371e4e12016-07-08 09:38:52 -0400288 unformat_input_t * input,
289 vlib_cli_command_t * cmd)
Dave Barachb44e9bc2016-02-19 09:06:23 -0500290{
Dave Barach371e4e12016-07-08 09:38:52 -0400291 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;
Dave Barach6931f592016-05-13 12:55:01 -0400297 int i, j, k;
Dave Barach371e4e12016-07-08 09:38:52 -0400298 u32 max_threads = (u32) ~ 0;
Dave Barach6931f592016-05-13 12:55:01 -0400299 int include_nexts = 0;
Dave Barach371e4e12016-07-08 09:38:52 -0400300 int include_stats = 0;
Dave Barach6931f592016-05-13 12:55:01 -0400301
Dave Barach371e4e12016-07-08 09:38:52 -0400302 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
Dave Barach6931f592016-05-13 12:55:01 -0400303 {
304 if (unformat (input, "max-threads %d", &max_threads))
Dave Barach371e4e12016-07-08 09:38:52 -0400305 ;
Dave Barach6931f592016-05-13 12:55:01 -0400306 else if (unformat (input, "stats"))
Dave Barach371e4e12016-07-08 09:38:52 -0400307 include_stats = 1;
Dave Barach6931f592016-05-13 12:55:01 -0400308 else if (unformat (input, "nexts"))
Dave Barach371e4e12016-07-08 09:38:52 -0400309 include_nexts = 1;
Dave Barach6931f592016-05-13 12:55:01 -0400310 else
Dave Barach371e4e12016-07-08 09:38:52 -0400311 break;
Dave Barach6931f592016-05-13 12:55:01 -0400312 }
Dave Barachb44e9bc2016-02-19 09:06:23 -0500313
Dave Barach371e4e12016-07-08 09:38:52 -0400314 /*
Dave Barachb44e9bc2016-02-19 09:06:23 -0500315 * 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 */
Dave Barach6931f592016-05-13 12:55:01 -0400319 vec_validate (vector, 16383);
Dave Barachb44e9bc2016-02-19 09:06:23 -0500320 vec_reset_length (vector);
321
Dave Barach371e4e12016-07-08 09:38:52 -0400322 vector = vlib_node_serialize (nm, vector, max_threads,
323 include_nexts, include_stats);
Dave Barachb44e9bc2016-02-19 09:06:23 -0500324
Dave Barach371e4e12016-07-08 09:38:52 -0400325 vlib_cli_output (vm, "result vector %d bytes", vec_len (vector));
Dave Barach6931f592016-05-13 12:55:01 -0400326
327 nodes_by_thread = vlib_node_unserialize (vector);
Dave Barachb44e9bc2016-02-19 09:06:23 -0500328
329 vec_free (vector);
Dave Barach371e4e12016-07-08 09:38:52 -0400330
331 for (i = 0; i < vec_len (nodes_by_thread); i++)
Dave Barachb44e9bc2016-02-19 09:06:23 -0500332 {
Dave Barach6931f592016-05-13 12:55:01 -0400333 nodes = nodes_by_thread[i];
334
335 vlib_cli_output (vm, "thread %d", i);
336
Dave Barach371e4e12016-07-08 09:38:52 -0400337 for (j = 0; j < vec_len (nodes); j++)
338 {
339 node = nodes[j];
Dave Barach6931f592016-05-13 12:55:01 -0400340
Dave Barach371e4e12016-07-08 09:38:52 -0400341 vlib_cli_output (vm, "[%d] %s state %s", j, node->name,
342 node->state_string);
Dave Barach6931f592016-05-13 12:55:01 -0400343
Dave Barach371e4e12016-07-08 09:38:52 -0400344 vlib_cli_output
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);
Dave Barach6931f592016-05-13 12:55:01 -0400350
Dave Barach371e4e12016-07-08 09:38:52 -0400351 for (k = 0; k < vec_len (node->next_nodes); k++)
352 {
353 if (node->next_nodes[k] != ~0)
Ed Warnicke853e7202016-08-12 11:42:26 -0700354 {
355 next_node = nodes[node->next_nodes[k]];
356 vlib_cli_output (vm, " [%d] %s", k, next_node->name);
357 }
Dave Barach371e4e12016-07-08 09:38:52 -0400358 }
359 }
360 }
Dave Barachb44e9bc2016-02-19 09:06:23 -0500361
Dave Barach371e4e12016-07-08 09:38:52 -0400362 for (j = 0; j < vec_len (nodes_by_thread); j++)
Dave Barachb44e9bc2016-02-19 09:06:23 -0500363 {
Dave Barach6931f592016-05-13 12:55:01 -0400364 nodes = nodes_by_thread[j];
365
Dave Barach371e4e12016-07-08 09:38:52 -0400366 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);
Dave Barachb44e9bc2016-02-19 09:06:23 -0500373 }
Dave Barach6931f592016-05-13 12:55:01 -0400374 vec_free (nodes_by_thread);
Dave Barachb44e9bc2016-02-19 09:06:23 -0500375
376 return 0;
377}
378
Dave Barach371e4e12016-07-08 09:38:52 -0400379/* *INDENT-OFF* */
Dave Barachb44e9bc2016-02-19 09:06:23 -0500380VLIB_CLI_COMMAND (test_node_serialize_node, static) = {
381 .path = "test node serialize",
Dave Barach6931f592016-05-13 12:55:01 -0400382 .short_help = "test node serialize [max-threads NN] nexts stats",
Dave Barachb44e9bc2016-02-19 09:06:23 -0500383 .function = test_node_serialize_command_fn,
384};
Dave Barach371e4e12016-07-08 09:38:52 -0400385/* *INDENT-ON* */
Dave Barachb44e9bc2016-02-19 09:06:23 -0500386#endif
Dave Barach371e4e12016-07-08 09:38:52 -0400387
388/*
389 * fd.io coding-style-patch-verification: ON
390 *
391 * Local Variables:
392 * eval: (c-set-style "gnu")
393 * End:
394 */