Line data Source code
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 : /* serialized representation of state strings */
20 :
21 : #define foreach_state_string_code \
22 : _(STATE_DONE, "done") \
23 : _(STATE_DISABLED, "disabled") \
24 : _(STATE_TIME_WAIT, "time wait") \
25 : _(STATE_EVENT_WAIT, "event wait") \
26 : _(STATE_ANY_WAIT, "any wait") \
27 : _(STATE_POLLING, "polling") \
28 : _(STATE_INTERRUPT_WAIT, "interrupt wait") \
29 : _(STATE_INTERNAL, "internal")
30 :
31 : typedef enum
32 : {
33 : #define _(a,b) a,
34 : foreach_state_string_code
35 : #undef _
36 : } state_string_enum_t;
37 :
38 : static char *state_strings[] = {
39 : #define _(a,b) b,
40 : foreach_state_string_code
41 : #undef _
42 : };
43 :
44 : /*
45 : * Serialize a vlib_node_main_t. Appends the result to vector.
46 : * Pass 0 to create a new vector, use vec_reset_length(vector)
47 : * to recycle a vector / avoid memory allocation, etc.
48 : * Switch heaps before/after to serialize into API client shared memory.
49 : */
50 : u8 *
51 0 : vlib_node_serialize (vlib_main_t * vm, vlib_node_t *** node_dups, u8 * vector,
52 : int include_nexts, int include_stats)
53 : {
54 0 : serialize_main_t _sm, *sm = &_sm;
55 : vlib_node_t *n;
56 : vlib_node_t **nodes;
57 : u8 *namep;
58 : u32 name_bytes;
59 : uword i, j, k;
60 : u64 l, v, c, d;
61 : state_string_enum_t state_code;
62 :
63 0 : serialize_open_vector (sm, vector);
64 0 : serialize_likely_small_unsigned_integer (sm, vec_len (node_dups));
65 :
66 0 : for (j = 0; j < vec_len (node_dups); j++)
67 : {
68 0 : nodes = node_dups[j];
69 :
70 0 : serialize_likely_small_unsigned_integer (sm, vec_len (nodes));
71 :
72 0 : for (i = 0; i < vec_len (nodes); i++)
73 : {
74 0 : n = nodes[i];
75 :
76 0 : l = n->stats_total.clocks - n->stats_last_clear.clocks;
77 0 : v = n->stats_total.vectors - n->stats_last_clear.vectors;
78 0 : c = n->stats_total.calls - n->stats_last_clear.calls;
79 0 : d = n->stats_total.suspends - n->stats_last_clear.suspends;
80 :
81 0 : state_code = STATE_INTERNAL;
82 :
83 0 : if (n->type == VLIB_NODE_TYPE_PROCESS)
84 : {
85 0 : vlib_process_t *p = vlib_get_process_from_node (vm, n);
86 :
87 0 : switch (p->flags
88 0 : & (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
89 : | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT))
90 : {
91 0 : default:
92 0 : if (!(p->flags & VLIB_PROCESS_IS_RUNNING))
93 0 : state_code = STATE_DONE;
94 0 : break;
95 :
96 0 : case VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK:
97 0 : state_code = STATE_TIME_WAIT;
98 0 : break;
99 :
100 0 : case VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT:
101 0 : state_code = STATE_EVENT_WAIT;
102 0 : break;
103 :
104 0 : case (VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_EVENT | VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK):
105 0 : state_code =
106 : STATE_ANY_WAIT;
107 0 : break;
108 : }
109 : }
110 0 : else if (n->type != VLIB_NODE_TYPE_INTERNAL)
111 : {
112 0 : state_code = STATE_POLLING;
113 0 : if (n->state == VLIB_NODE_STATE_DISABLED)
114 0 : state_code = STATE_DISABLED;
115 0 : else if (n->state == VLIB_NODE_STATE_INTERRUPT)
116 0 : state_code = STATE_INTERRUPT_WAIT;
117 : }
118 :
119 : /* See unserialize_cstring */
120 0 : name_bytes = vec_len (n->name);
121 0 : serialize_likely_small_unsigned_integer (sm, name_bytes);
122 0 : namep = serialize_get (sm, name_bytes);
123 0 : memcpy (namep, n->name, name_bytes);
124 :
125 0 : serialize_likely_small_unsigned_integer (sm, (u64) state_code);
126 0 : serialize_likely_small_unsigned_integer (sm, n->type);
127 0 : serialize_likely_small_unsigned_integer (sm, n->flags);
128 :
129 0 : if (include_nexts)
130 : {
131 0 : serialize_likely_small_unsigned_integer
132 0 : (sm, vec_len (n->next_nodes));
133 0 : for (k = 0; k < vec_len (n->next_nodes); k++)
134 0 : serialize_likely_small_unsigned_integer (sm,
135 0 : n->next_nodes[k]);
136 : }
137 : else
138 0 : serialize_likely_small_unsigned_integer (sm, 0);
139 :
140 0 : if (include_stats)
141 : {
142 : /* stats present */
143 0 : serialize_likely_small_unsigned_integer (sm, 1);
144 : /* total clocks */
145 0 : serialize_integer (sm, l, 8);
146 : /* Total calls */
147 0 : serialize_integer (sm, c, 8);
148 : /* Total vectors */
149 0 : serialize_integer (sm, v, 8);
150 : /* Total suspends */
151 0 : serialize_integer (sm, d, 8);
152 : }
153 : else /* no stats */
154 0 : serialize_likely_small_unsigned_integer (sm, 0);
155 : }
156 : }
157 0 : return (serialize_close_vector (sm));
158 : }
159 :
160 : vlib_node_t ***
161 0 : vlib_node_unserialize (u8 * vector)
162 : {
163 0 : serialize_main_t _sm, *sm = &_sm;
164 : u32 nnodes, nnexts;
165 : u32 nstat_vms;
166 : vlib_node_t *node;
167 : vlib_node_t **nodes;
168 0 : vlib_node_t ***nodes_by_thread = 0;
169 : int i, j, k;
170 : u64 l, v, c, d;
171 : state_string_enum_t state_code;
172 : int stats_present;
173 :
174 0 : serialize_open_vector (sm, vector);
175 :
176 0 : nstat_vms = unserialize_likely_small_unsigned_integer (sm);
177 :
178 0 : vec_validate (nodes_by_thread, nstat_vms - 1);
179 0 : vec_set_len (nodes_by_thread, 0);
180 :
181 0 : for (i = 0; i < nstat_vms; i++)
182 : {
183 0 : nnodes = unserialize_likely_small_unsigned_integer (sm);
184 :
185 0 : nodes = 0;
186 0 : vec_validate (nodes, nnodes - 1);
187 0 : vec_add1 (nodes_by_thread, nodes);
188 :
189 0 : for (j = 0; j < nnodes; j++)
190 : {
191 0 : node = 0;
192 0 : vec_validate (node, 0);
193 0 : nodes[j] = node;
194 :
195 0 : unserialize_cstring (sm, (char **) &(node->name));
196 0 : state_code = unserialize_likely_small_unsigned_integer (sm);
197 0 : node->state_string = (u8 *) state_strings[state_code];
198 :
199 0 : node->type = unserialize_likely_small_unsigned_integer (sm);
200 0 : node->flags = unserialize_likely_small_unsigned_integer (sm);
201 0 : nnexts = unserialize_likely_small_unsigned_integer (sm);
202 0 : if (nnexts > 0)
203 0 : vec_validate (node->next_nodes, nnexts - 1);
204 0 : for (k = 0; k < nnexts; k++)
205 0 : node->next_nodes[k] =
206 0 : unserialize_likely_small_unsigned_integer (sm);
207 :
208 0 : stats_present = unserialize_likely_small_unsigned_integer (sm);
209 :
210 0 : if (stats_present)
211 : {
212 : /* total clocks */
213 0 : unserialize_integer (sm, &l, 8);
214 0 : node->stats_total.clocks = l;
215 0 : node->stats_last_clear.clocks = 0;
216 :
217 : /* Total calls */
218 0 : unserialize_integer (sm, &c, 8);
219 0 : node->stats_total.calls = c;
220 :
221 : /* Total vectors */
222 0 : unserialize_integer (sm, &v, 8);
223 0 : node->stats_total.vectors = v;
224 :
225 : /* Total suspends */
226 0 : unserialize_integer (sm, &d, 8);
227 0 : node->stats_total.suspends = d;
228 : }
229 : }
230 : }
231 0 : return nodes_by_thread;
232 : }
233 :
234 : #if TEST_CODE
235 :
236 : static clib_error_t *
237 : test_node_serialize_command_fn (vlib_main_t * vm,
238 : unformat_input_t * input,
239 : vlib_cli_command_t * cmd)
240 : {
241 : vlib_node_main_t *nm = &vm->node_main;
242 : u8 *vector = 0;
243 : vlib_node_t ***nodes_by_thread;
244 : vlib_node_t **nodes;
245 : vlib_node_t *node;
246 : vlib_node_t *next_node;
247 : int i, j, k;
248 : u32 max_threads = (u32) ~ 0;
249 : int include_nexts = 0;
250 : int include_stats = 0;
251 :
252 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
253 : {
254 : if (unformat (input, "max-threads %d", &max_threads))
255 : ;
256 : else if (unformat (input, "stats"))
257 : include_stats = 1;
258 : else if (unformat (input, "nexts"))
259 : include_nexts = 1;
260 : else
261 : break;
262 : }
263 :
264 : /*
265 : * Keep the number of memcpy ops to a minimum (e.g. 1).
266 : * The current size of the serialized vector is
267 : * slightly under 4K.
268 : */
269 : vec_validate (vector, 16383);
270 : vec_reset_length (vector);
271 :
272 : vector = vlib_node_serialize (nm, vector, max_threads,
273 : include_nexts, include_stats);
274 :
275 : vlib_cli_output (vm, "result vector %d bytes", vec_len (vector));
276 :
277 : nodes_by_thread = vlib_node_unserialize (vector);
278 :
279 : vec_free (vector);
280 :
281 : for (i = 0; i < vec_len (nodes_by_thread); i++)
282 : {
283 : nodes = nodes_by_thread[i];
284 :
285 : vlib_cli_output (vm, "thread %d", i);
286 :
287 : for (j = 0; j < vec_len (nodes); j++)
288 : {
289 : node = nodes[j];
290 :
291 : vlib_cli_output (vm, "[%d] %s state %s", j, node->name,
292 : node->state_string);
293 :
294 : vlib_cli_output
295 : (vm, " clocks %lld calls %lld suspends"
296 : " %lld vectors %lld",
297 : node->stats_total.clocks,
298 : node->stats_total.calls,
299 : node->stats_total.suspends, node->stats_total.vectors);
300 :
301 : for (k = 0; k < vec_len (node->next_nodes); k++)
302 : {
303 : if (node->next_nodes[k] != ~0)
304 : {
305 : next_node = nodes[node->next_nodes[k]];
306 : vlib_cli_output (vm, " [%d] %s", k, next_node->name);
307 : }
308 : }
309 : }
310 : }
311 :
312 : for (j = 0; j < vec_len (nodes_by_thread); j++)
313 : {
314 : nodes = nodes_by_thread[j];
315 :
316 : for (i = 0; i < vec_len (nodes); i++)
317 : {
318 : vec_free (nodes[i]->name);
319 : vec_free (nodes[i]->next_nodes);
320 : vec_free (nodes[i]);
321 : }
322 : vec_free (nodes);
323 : }
324 : vec_free (nodes_by_thread);
325 :
326 : return 0;
327 : }
328 :
329 : /* *INDENT-OFF* */
330 : VLIB_CLI_COMMAND (test_node_serialize_node, static) = {
331 : .path = "test node serialize",
332 : .short_help = "test node serialize [max-threads NN] nexts stats",
333 : .function = test_node_serialize_command_fn,
334 : };
335 : /* *INDENT-ON* */
336 : #endif
337 :
338 : /*
339 : * fd.io coding-style-patch-verification: ON
340 : *
341 : * Local Variables:
342 : * eval: (c-set-style "gnu")
343 : * End:
344 : */
|