blob: 18067d1d85edcde18e7d518b48a7fb3e06158e23 [file] [log] [blame]
Dave Barach371e4e12016-07-08 09:38:52 -04001/*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002 *------------------------------------------------------------------
3 * api_shared.c - API message handling, common code for both clients
4 * and the vlib process itself.
Dave Barach371e4e12016-07-08 09:38:52 -04005 *
Ed Warnickecb9cada2015-12-08 15:45:58 -07006 *
7 * Copyright (c) 2009 Cisco and/or its affiliates.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at:
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *------------------------------------------------------------------
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
Dave Barach072f8de2016-12-02 13:31:25 -050024#include <stddef.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070025#include <string.h>
26#include <sys/types.h>
27#include <sys/mman.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <unistd.h>
31#include <vppinfra/format.h>
32#include <vppinfra/byte_order.h>
33#include <vppinfra/error.h>
34#include <vlib/vlib.h>
35#include <vlib/unix/unix.h>
36#include <vlibapi/api.h>
37#include <vppinfra/elog.h>
38
39api_main_t api_main;
40
Dave Barach371e4e12016-07-08 09:38:52 -040041void vl_msg_api_barrier_sync (void) __attribute__ ((weak));
42void
43vl_msg_api_barrier_sync (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -070044{
Ed Warnickecb9cada2015-12-08 15:45:58 -070045}
46
Dave Barach371e4e12016-07-08 09:38:52 -040047void vl_msg_api_barrier_release (void) __attribute__ ((weak));
48void
49vl_msg_api_barrier_release (void)
50{
51}
52
53void
54vl_msg_api_increment_missing_client_counter (void)
55{
56 api_main_t *am = &api_main;
57 am->missing_clients++;
58}
59
60typedef enum
61{
62 DUMP,
63 CUSTOM_DUMP,
64 REPLAY,
65 INITIALIZERS,
Ed Warnickecb9cada2015-12-08 15:45:58 -070066} vl_api_replay_t;
67
Dave Barach371e4e12016-07-08 09:38:52 -040068int
69vl_msg_api_rx_trace_enabled (api_main_t * am)
Ed Warnickecb9cada2015-12-08 15:45:58 -070070{
Dave Barach371e4e12016-07-08 09:38:52 -040071 return (am->rx_trace && am->rx_trace->enabled);
Ed Warnickecb9cada2015-12-08 15:45:58 -070072}
73
Dave Barach371e4e12016-07-08 09:38:52 -040074int
75vl_msg_api_tx_trace_enabled (api_main_t * am)
Ed Warnickecb9cada2015-12-08 15:45:58 -070076{
Dave Barach371e4e12016-07-08 09:38:52 -040077 return (am->tx_trace && am->tx_trace->enabled);
Ed Warnickecb9cada2015-12-08 15:45:58 -070078}
79
80/*
81 * vl_msg_api_trace
82 */
Dave Barach371e4e12016-07-08 09:38:52 -040083void
84vl_msg_api_trace (api_main_t * am, vl_api_trace_t * tp, void *msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -070085{
Dave Barach371e4e12016-07-08 09:38:52 -040086 u8 **this_trace;
87 u8 **old_trace;
88 u8 *msg_copy;
Dave Barach072f8de2016-12-02 13:31:25 -050089 u32 length;
Dave Barach371e4e12016-07-08 09:38:52 -040090 trace_cfg_t *cfgp;
91 u16 msg_id = ntohs (*((u16 *) msg));
Dave Barach072f8de2016-12-02 13:31:25 -050092 msgbuf_t *header = (msgbuf_t *) (((u8 *) msg) - offsetof (msgbuf_t, data));
Ed Warnickecb9cada2015-12-08 15:45:58 -070093
Dave Barach371e4e12016-07-08 09:38:52 -040094 cfgp = am->api_trace_cfg + msg_id;
Ed Warnickecb9cada2015-12-08 15:45:58 -070095
Dave Barach371e4e12016-07-08 09:38:52 -040096 if (!cfgp || !cfgp->trace_enable)
97 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
Dave Barach371e4e12016-07-08 09:38:52 -040099 msg_copy = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100
Dave Barach371e4e12016-07-08 09:38:52 -0400101 if (tp->nitems == 0)
102 {
103 clib_warning ("tp->nitems is 0");
104 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105 }
106
Dave Barach371e4e12016-07-08 09:38:52 -0400107 if (vec_len (tp->traces) < tp->nitems)
108 {
109 vec_add1 (tp->traces, 0);
110 this_trace = tp->traces + vec_len (tp->traces) - 1;
111 }
112 else
113 {
114 tp->wrapped = 1;
115 old_trace = tp->traces + tp->curindex++;
116 if (tp->curindex == tp->nitems)
117 tp->curindex = 0;
118 vec_free (*old_trace);
119 this_trace = old_trace;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120 }
121
Dave Barach072f8de2016-12-02 13:31:25 -0500122 length = clib_net_to_host_u32 (header->data_len);
123
124 vec_validate (msg_copy, length - 1);
125 clib_memcpy (msg_copy, msg, length);
Dave Barach371e4e12016-07-08 09:38:52 -0400126 *this_trace = msg_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127}
128
Dave Barach371e4e12016-07-08 09:38:52 -0400129int
130vl_msg_api_trace_onoff (api_main_t * am, vl_api_trace_which_t which,
131 int onoff)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132{
Dave Barach371e4e12016-07-08 09:38:52 -0400133 vl_api_trace_t *tp;
134 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135
Dave Barach371e4e12016-07-08 09:38:52 -0400136 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137 {
138 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400139 tp = am->tx_trace;
140 if (tp == 0)
141 {
142 vl_msg_api_trace_configure (am, which, 1024);
143 tp = am->tx_trace;
144 }
145 break;
146
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -0400148 tp = am->rx_trace;
149 if (tp == 0)
150 {
151 vl_msg_api_trace_configure (am, which, 1024);
152 tp = am->rx_trace;
153 }
154 break;
155
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400157 /* duh? */
158 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159 }
160
Dave Barach371e4e12016-07-08 09:38:52 -0400161 /* Configured? */
162 if (tp == 0 || tp->nitems == 0)
163 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164
Dave Barach371e4e12016-07-08 09:38:52 -0400165 rv = tp->enabled;
166 tp->enabled = onoff;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167
Dave Barach371e4e12016-07-08 09:38:52 -0400168 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169}
170
Dave Barach371e4e12016-07-08 09:38:52 -0400171int
172vl_msg_api_trace_free (api_main_t * am, vl_api_trace_which_t which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700173{
Dave Barach371e4e12016-07-08 09:38:52 -0400174 vl_api_trace_t *tp;
175 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176
Dave Barach371e4e12016-07-08 09:38:52 -0400177 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178 {
179 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400180 tp = am->tx_trace;
181 break;
182
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -0400184 tp = am->rx_trace;
185 break;
186
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400188 /* duh? */
189 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190 }
191
Dave Barach371e4e12016-07-08 09:38:52 -0400192 /* Configured? */
193 if (!tp || tp->nitems == 0)
194 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
Dave Barach371e4e12016-07-08 09:38:52 -0400196 tp->curindex = 0;
197 tp->wrapped = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198
Dave Barach371e4e12016-07-08 09:38:52 -0400199 for (i = 0; i < vec_len (tp->traces); i++)
200 {
201 vec_free (tp->traces[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700202 }
Dave Barach371e4e12016-07-08 09:38:52 -0400203 vec_free (tp->traces);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204
Dave Barach371e4e12016-07-08 09:38:52 -0400205 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206}
207
Dave Barach371e4e12016-07-08 09:38:52 -0400208int
209vl_msg_api_trace_save (api_main_t * am, vl_api_trace_which_t which, FILE * fp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700210{
Dave Barach371e4e12016-07-08 09:38:52 -0400211 vl_api_trace_t *tp;
212 vl_api_trace_file_header_t fh;
213 int i;
214 u8 *msg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215
Dave Barach371e4e12016-07-08 09:38:52 -0400216 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217 {
218 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400219 tp = am->tx_trace;
220 break;
221
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -0400223 tp = am->rx_trace;
224 break;
225
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400227 /* duh? */
228 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700229 }
230
Dave Barach371e4e12016-07-08 09:38:52 -0400231 /* Configured, data present? */
232 if (tp == 0 || tp->nitems == 0 || vec_len (tp->traces) == 0)
233 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234
Dave Barach371e4e12016-07-08 09:38:52 -0400235 /* "Dare to be stupid" check */
236 if (fp == 0)
237 {
238 return -2;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239 }
240
Dave Barach371e4e12016-07-08 09:38:52 -0400241 /* Write the file header */
242 fh.nitems = vec_len (tp->traces);
243 fh.endian = tp->endian;
244 fh.wrapped = tp->wrapped;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245
Dave Barach371e4e12016-07-08 09:38:52 -0400246 if (fwrite (&fh, sizeof (fh), 1, fp) != 1)
247 {
248 return (-10);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 }
250
Dave Barach371e4e12016-07-08 09:38:52 -0400251 /* No-wrap case */
252 if (tp->wrapped == 0)
253 {
254 /*
255 * Note: vec_len return 0 when fed a NULL pointer.
256 * Unfortunately, the static analysis tool doesn't
257 * figure it out, hence the suppressed warnings.
258 * What a great use of my time.
259 */
260 for (i = 0; i < vec_len (tp->traces); i++)
261 {
Dave Barach072f8de2016-12-02 13:31:25 -0500262 u32 msg_length;
Dave Barach371e4e12016-07-08 09:38:52 -0400263 /*sa_ignore NO_NULL_CHK */
264 msg = tp->traces[i];
265 /*
266 * This retarded check required to pass
267 * [sic] SA-checking.
268 */
269 if (!msg)
270 continue;
Dave Barach072f8de2016-12-02 13:31:25 -0500271
272 msg_length = clib_host_to_net_u32 (vec_len (msg));
273 if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
274 != sizeof (msg_length))
275 {
276 return (-14);
277 }
Dave Barach371e4e12016-07-08 09:38:52 -0400278 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
279 {
280 return (-11);
281 }
282 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283 }
Dave Barach371e4e12016-07-08 09:38:52 -0400284 else
285 {
286 /* Wrap case: write oldest -> end of buffer */
287 for (i = tp->curindex; i < vec_len (tp->traces); i++)
288 {
Dave Barach072f8de2016-12-02 13:31:25 -0500289 u32 msg_length;
Dave Barach371e4e12016-07-08 09:38:52 -0400290 msg = tp->traces[i];
291 /*
292 * This retarded check required to pass
293 * [sic] SA-checking
294 */
295 if (!msg)
296 continue;
297
Dave Barach072f8de2016-12-02 13:31:25 -0500298 msg_length = clib_host_to_net_u32 (vec_len (msg));
299 if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
300 != sizeof (msg_length))
301 {
302 return (-14);
303 }
304
Dave Barach371e4e12016-07-08 09:38:52 -0400305 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
306 {
307 return (-12);
308 }
309 }
310 /* write beginning of buffer -> oldest-1 */
311 for (i = 0; i < tp->curindex; i++)
312 {
Dave Barach072f8de2016-12-02 13:31:25 -0500313 u32 msg_length;
Dave Barach371e4e12016-07-08 09:38:52 -0400314 /*sa_ignore NO_NULL_CHK */
315 msg = tp->traces[i];
316 /*
317 * This retarded check required to pass
318 * [sic] SA-checking
319 */
320 if (!msg)
321 continue;
322
Dave Barach072f8de2016-12-02 13:31:25 -0500323 msg_length = clib_host_to_net_u32 (vec_len (msg));
324 if (fwrite (&msg_length, 1, sizeof (msg_length), fp)
325 != sizeof (msg_length))
326 {
327 return (-14);
328 }
329
Dave Barach371e4e12016-07-08 09:38:52 -0400330 if (fwrite (msg, 1, vec_len (msg), fp) != vec_len (msg))
331 {
332 return (-13);
333 }
334 }
335 }
336 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700337}
338
Dave Barach371e4e12016-07-08 09:38:52 -0400339int
340vl_msg_api_trace_configure (api_main_t * am, vl_api_trace_which_t which,
341 u32 nitems)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342{
Dave Barach371e4e12016-07-08 09:38:52 -0400343 vl_api_trace_t *tp;
344 int was_on = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700345
Dave Barach371e4e12016-07-08 09:38:52 -0400346 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700347 {
348 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400349 tp = am->tx_trace;
350 if (tp == 0)
351 {
352 vec_validate (am->tx_trace, 0);
353 tp = am->tx_trace;
354 }
355 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700356
Dave Barach371e4e12016-07-08 09:38:52 -0400357 case VL_API_TRACE_RX:
358 tp = am->rx_trace;
359 if (tp == 0)
360 {
361 vec_validate (am->rx_trace, 0);
362 tp = am->rx_trace;
363 }
364
365 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366
367 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400368 return -1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700369
370 }
371
Dave Barach371e4e12016-07-08 09:38:52 -0400372 if (tp->enabled)
373 {
374 was_on = vl_msg_api_trace_onoff (am, which, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700375 }
Dave Barach371e4e12016-07-08 09:38:52 -0400376 if (tp->traces)
377 {
378 vl_msg_api_trace_free (am, which);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700379 }
380
Dave Barach371e4e12016-07-08 09:38:52 -0400381 memset (tp, 0, sizeof (*tp));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382
Dave Barach371e4e12016-07-08 09:38:52 -0400383 if (clib_arch_is_big_endian)
384 {
385 tp->endian = VL_API_BIG_ENDIAN;
386 }
387 else
388 {
389 tp->endian = VL_API_LITTLE_ENDIAN;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390 }
391
Dave Barach371e4e12016-07-08 09:38:52 -0400392 tp->nitems = nitems;
393 if (was_on)
394 {
395 (void) vl_msg_api_trace_onoff (am, which, was_on);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396 }
Dave Barach371e4e12016-07-08 09:38:52 -0400397 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700398}
399
Dave Barach371e4e12016-07-08 09:38:52 -0400400always_inline void
401msg_handler_internal (api_main_t * am,
402 void *the_msg, int trace_it, int do_it, int free_it)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403{
Dave Barach371e4e12016-07-08 09:38:52 -0400404 u16 id = ntohs (*((u16 *) the_msg));
405 u8 *(*print_fp) (void *, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406
Dave Barach371e4e12016-07-08 09:38:52 -0400407 if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
408 {
409 if (trace_it)
410 vl_msg_api_trace (am, am->rx_trace, the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700411
Dave Barach371e4e12016-07-08 09:38:52 -0400412 if (am->msg_print_flag)
413 {
414 fformat (stdout, "[%d]: %s\n", id, am->msg_names[id]);
415 print_fp = (void *) am->msg_print_handlers[id];
416 if (print_fp == 0)
417 {
418 fformat (stdout, " [no registered print fn]\n");
419 }
420 else
421 {
422 (*print_fp) (the_msg, stdout);
423 }
424 }
425
426 if (do_it)
427 {
428 if (!am->is_mp_safe[id])
429 vl_msg_api_barrier_sync ();
430 (*am->msg_handlers[id]) (the_msg);
431 if (!am->is_mp_safe[id])
432 vl_msg_api_barrier_release ();
433 }
434 }
435 else
436 {
437 clib_warning ("no handler for msg id %d", id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700438 }
439
Dave Barach371e4e12016-07-08 09:38:52 -0400440 if (free_it)
441 vl_msg_api_free (the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442}
443
444/* set to 1 if you want before/after message handler event logging */
445#define ELOG_API_MESSAGE_HANDLERS 0
446
447#if ELOG_API_MESSAGE_HANDLERS > 0
Dave Barach371e4e12016-07-08 09:38:52 -0400448static u32
449elog_id_for_msg_name (vlib_main_t * vm, char *msg_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450{
Dave Barach371e4e12016-07-08 09:38:52 -0400451 uword *p, r;
452 static uword *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453 u8 *name_copy;
454
Dave Barach371e4e12016-07-08 09:38:52 -0400455 if (!h)
456 h = hash_create_string (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700457
458 p = hash_get_mem (h, msg_name);
459 if (p)
460 return p[0];
461 r = elog_string (&vm->elog_main, "%s", msg_name);
462
463 name_copy = format (0, "%s%c", msg_name, 0);
464
465 hash_set_mem (h, name_copy, r);
466
467 return r;
468}
469#endif
470
471/* This is only to be called from a vlib/vnet app */
Dave Barach371e4e12016-07-08 09:38:52 -0400472void
473vl_msg_api_handler_with_vm_node (api_main_t * am,
474 void *the_msg, vlib_main_t * vm,
475 vlib_node_runtime_t * node)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700476{
Dave Barach371e4e12016-07-08 09:38:52 -0400477 u16 id = ntohs (*((u16 *) the_msg));
478 u8 *(*handler) (void *, void *, void *);
479
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480#if ELOG_API_MESSAGE_HANDLERS > 0
Dave Barach371e4e12016-07-08 09:38:52 -0400481 {
482 /* *INDENT-OFF* */
483 ELOG_TYPE_DECLARE (e) =
484 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485 .format = "api-msg: %s",
486 .format_args = "T4",
487 };
Dave Barach371e4e12016-07-08 09:38:52 -0400488 /* *INDENT-ON* */
489 struct
490 {
491 u32 c;
492 } *ed;
493 ed = ELOG_DATA (&vm->elog_main, e);
494 if (id < vec_len (am->msg_names))
495 ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
496 else
497 ed->c = elog_id_for_msg_name (vm, "BOGUS");
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498 }
Dave Barach371e4e12016-07-08 09:38:52 -0400499#endif
500
501 if (id < vec_len (am->msg_handlers) && am->msg_handlers[id])
502 {
503 handler = (void *) am->msg_handlers[id];
504
505 if (am->rx_trace && am->rx_trace->enabled)
506 vl_msg_api_trace (am, am->rx_trace, the_msg);
507
508 if (!am->is_mp_safe[id])
509 vl_msg_api_barrier_sync ();
510 (*handler) (the_msg, vm, node);
511 if (!am->is_mp_safe[id])
512 vl_msg_api_barrier_release ();
513 }
514 else
515 {
516 clib_warning ("no hander for msg id %d", id);
517 }
518
519 /*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700520 * Special-case, so we can e.g. bounce messages off the vnet
521 * main thread without copying them...
522 */
523 if (!(am->message_bounce[id]))
Dave Barach371e4e12016-07-08 09:38:52 -0400524 vl_msg_api_free (the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700525
526#if ELOG_API_MESSAGE_HANDLERS > 0
Dave Barach371e4e12016-07-08 09:38:52 -0400527 {
528 /* *INDENT-OFF* */
529 ELOG_TYPE_DECLARE (e) = {
530 .format = "api-msg-done: %s",
531 .format_args = "T4",
532 };
533 /* *INDENT-ON* */
534
535 struct
Ed Warnickecb9cada2015-12-08 15:45:58 -0700536 {
Dave Barach371e4e12016-07-08 09:38:52 -0400537 u32 c;
538 } *ed;
539 ed = ELOG_DATA (&vm->elog_main, e);
540 if (id < vec_len (am->msg_names))
541 ed->c = elog_id_for_msg_name (vm, am->msg_names[id]);
542 else
543 ed->c = elog_id_for_msg_name (vm, "BOGUS");
544 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545#endif
546}
547
Dave Barach371e4e12016-07-08 09:38:52 -0400548void
549vl_msg_api_handler (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550{
Dave Barach371e4e12016-07-08 09:38:52 -0400551 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700552
Dave Barach371e4e12016-07-08 09:38:52 -0400553 msg_handler_internal (am, the_msg,
554 (am->rx_trace
555 && am->rx_trace->enabled) /* trace_it */ ,
556 1 /* do_it */ , 1 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700557}
558
Dave Barach371e4e12016-07-08 09:38:52 -0400559void
560vl_msg_api_handler_no_free (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561{
Dave Barach371e4e12016-07-08 09:38:52 -0400562 api_main_t *am = &api_main;
563 msg_handler_internal (am, the_msg,
564 (am->rx_trace
565 && am->rx_trace->enabled) /* trace_it */ ,
566 1 /* do_it */ , 0 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700567}
568
Dave Barach371e4e12016-07-08 09:38:52 -0400569void
570vl_msg_api_handler_no_trace_no_free (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700571{
Dave Barach371e4e12016-07-08 09:38:52 -0400572 api_main_t *am = &api_main;
573 msg_handler_internal (am, the_msg, 0 /* trace_it */ , 1 /* do_it */ ,
574 0 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700575}
576
577/*
578 * Add a trace record to the API message trace buffer, if
579 * API message tracing is enabled. Handy for adding sufficient
580 * data to the trace to reproduce autonomous state, as opposed to
Dave Barach371e4e12016-07-08 09:38:52 -0400581 * state downloaded via control-plane API messages. Example: the NAT
Ed Warnickecb9cada2015-12-08 15:45:58 -0700582 * application creates database entries based on packet traffic, not
583 * control-plane messages.
584 *
585 */
Dave Barach371e4e12016-07-08 09:38:52 -0400586void
587vl_msg_api_trace_only (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700588{
Dave Barach371e4e12016-07-08 09:38:52 -0400589 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700590
Dave Barach371e4e12016-07-08 09:38:52 -0400591 msg_handler_internal (am, the_msg,
592 (am->rx_trace
593 && am->rx_trace->enabled) /* trace_it */ ,
594 0 /* do_it */ , 0 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700595}
596
Dave Barach371e4e12016-07-08 09:38:52 -0400597void
598vl_msg_api_cleanup_handler (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599{
Dave Barach371e4e12016-07-08 09:38:52 -0400600 api_main_t *am = &api_main;
601 u16 id = ntohs (*((u16 *) the_msg));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700602
Dave Barach371e4e12016-07-08 09:38:52 -0400603 if (PREDICT_FALSE (id >= vec_len (am->msg_cleanup_handlers)))
604 {
605 clib_warning ("_vl_msg_id too large: %d\n", id);
606 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700607 }
Dave Barach371e4e12016-07-08 09:38:52 -0400608 if (am->msg_cleanup_handlers[id])
609 (*am->msg_cleanup_handlers[id]) (the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610
Dave Barach371e4e12016-07-08 09:38:52 -0400611 vl_msg_api_free (the_msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700612}
613
614/*
615 * vl_msg_api_replay_handler
616 */
Dave Barach371e4e12016-07-08 09:38:52 -0400617void
618vl_msg_api_replay_handler (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700619{
Dave Barach371e4e12016-07-08 09:38:52 -0400620 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700621
Dave Barach371e4e12016-07-08 09:38:52 -0400622 u16 id = ntohs (*((u16 *) the_msg));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700623
Dave Barach371e4e12016-07-08 09:38:52 -0400624 if (PREDICT_FALSE (id >= vec_len (am->msg_handlers)))
625 {
626 clib_warning ("_vl_msg_id too large: %d\n", id);
627 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700628 }
Dave Barach371e4e12016-07-08 09:38:52 -0400629 /* do NOT trace the message... */
630 if (am->msg_handlers[id])
631 (*am->msg_handlers[id]) (the_msg);
632 /* do NOT free the message buffer... */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700633}
Dave Barach371e4e12016-07-08 09:38:52 -0400634
Ed Warnickecb9cada2015-12-08 15:45:58 -0700635/*
636 * vl_msg_api_socket_handler
637 */
Dave Barach371e4e12016-07-08 09:38:52 -0400638void
639vl_msg_api_socket_handler (void *the_msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640{
Dave Barach371e4e12016-07-08 09:38:52 -0400641 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642
Dave Barach371e4e12016-07-08 09:38:52 -0400643 msg_handler_internal (am, the_msg,
644 (am->rx_trace
645 && am->rx_trace->enabled) /* trace_it */ ,
646 1 /* do_it */ , 0 /* free_it */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647}
648
649#define foreach_msg_api_vector \
650_(msg_names) \
651_(msg_handlers) \
652_(msg_cleanup_handlers) \
653_(msg_endian_handlers) \
654_(msg_print_handlers) \
655_(api_trace_cfg) \
656_(message_bounce) \
657_(is_mp_safe)
658
Dave Barach371e4e12016-07-08 09:38:52 -0400659void
660vl_msg_api_config (vl_msg_api_msg_config_t * c)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661{
Dave Barach371e4e12016-07-08 09:38:52 -0400662 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663
Dave Barach371e4e12016-07-08 09:38:52 -0400664 ASSERT (c->id > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665
666#define _(a) vec_validate (am->a, c->id);
Dave Barach371e4e12016-07-08 09:38:52 -0400667 foreach_msg_api_vector;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700668#undef _
669
Dave Barach371e4e12016-07-08 09:38:52 -0400670 am->msg_names[c->id] = c->name;
671 am->msg_handlers[c->id] = c->handler;
672 am->msg_cleanup_handlers[c->id] = c->cleanup;
673 am->msg_endian_handlers[c->id] = c->endian;
674 am->msg_print_handlers[c->id] = c->print;
675 am->message_bounce[c->id] = c->message_bounce;
676 am->is_mp_safe[c->id] = c->is_mp_safe;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700677
Dave Barach371e4e12016-07-08 09:38:52 -0400678 am->api_trace_cfg[c->id].size = c->size;
679 am->api_trace_cfg[c->id].trace_enable = c->traced;
680 am->api_trace_cfg[c->id].replay_enable = c->replay;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700681}
682
Dave Barach371e4e12016-07-08 09:38:52 -0400683/*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684 * vl_msg_api_set_handlers
685 * preserve the old API for a while
686 */
Dave Barach371e4e12016-07-08 09:38:52 -0400687void
688vl_msg_api_set_handlers (int id, char *name, void *handler, void *cleanup,
689 void *endian, void *print, int size, int traced)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700690{
Dave Barach371e4e12016-07-08 09:38:52 -0400691 vl_msg_api_msg_config_t cfg;
692 vl_msg_api_msg_config_t *c = &cfg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700693
Dave Barach0691d6e2017-01-05 10:08:52 -0500694 memset (c, 0, sizeof (*c));
695
Dave Barach371e4e12016-07-08 09:38:52 -0400696 c->id = id;
697 c->name = name;
698 c->handler = handler;
699 c->cleanup = cleanup;
700 c->endian = endian;
701 c->print = print;
Dave Barach371e4e12016-07-08 09:38:52 -0400702 c->traced = traced;
703 c->replay = 1;
704 c->message_bounce = 0;
705 c->is_mp_safe = 0;
706 vl_msg_api_config (c);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707}
708
Dave Barach371e4e12016-07-08 09:38:52 -0400709void
710vl_msg_api_set_cleanup_handler (int msg_id, void *fp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711{
Dave Barach371e4e12016-07-08 09:38:52 -0400712 api_main_t *am = &api_main;
713 ASSERT (msg_id > 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714
Dave Barach371e4e12016-07-08 09:38:52 -0400715 vec_validate (am->msg_cleanup_handlers, msg_id);
716 am->msg_cleanup_handlers[msg_id] = fp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700717}
718
Dave Barach371e4e12016-07-08 09:38:52 -0400719void
720vl_msg_api_queue_handler (unix_shared_memory_queue_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721{
Dave Barach371e4e12016-07-08 09:38:52 -0400722 uword msg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700723
Dave Barach371e4e12016-07-08 09:38:52 -0400724 while (!unix_shared_memory_queue_sub (q, (u8 *) & msg, 0))
725 vl_msg_api_handler ((void *) msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726}
727
Dave Barach371e4e12016-07-08 09:38:52 -0400728vl_api_trace_t *
729vl_msg_api_trace_get (api_main_t * am, vl_api_trace_which_t which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700730{
Dave Barach371e4e12016-07-08 09:38:52 -0400731 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700732 {
733 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -0400734 return am->rx_trace;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -0400736 return am->tx_trace;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737 default:
Dave Barach371e4e12016-07-08 09:38:52 -0400738 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739 }
740}
741
Dave Barach371e4e12016-07-08 09:38:52 -0400742void
743vl_noop_handler (void *mp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700744{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745}
746
Dave Barach371e4e12016-07-08 09:38:52 -0400747clib_error_t *
748vl_api_init (vlib_main_t * vm)
749{
750 static u8 once;
751 api_main_t *am = &api_main;
752
753 if (once)
754 return 0;
755
756 once = 1;
757
758 am->region_name = "/unset";
759 /*
760 * Eventually passed to fchown, -1 => "current user"
761 * instead of 0 => "root". A very fine disctinction at best.
762 */
763 if (am->api_uid == 0)
764 am->api_uid = -1;
765 if (am->api_gid == 0)
766 am->api_gid = -1;
767
768 return (0);
769}
770
771void vl_msg_api_custom_dump_configure (api_main_t * am)
772 __attribute__ ((weak));
773void
774vl_msg_api_custom_dump_configure (api_main_t * am)
775{
776}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700777
778VLIB_INIT_FUNCTION (vl_api_init);
779
Dave Barach371e4e12016-07-08 09:38:52 -0400780static void
781vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
782 u32 first_index, u32 last_index,
783 vl_api_replay_t which)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700784{
Dave Barach371e4e12016-07-08 09:38:52 -0400785 vl_api_trace_file_header_t *hp;
786 int i, fd;
787 struct stat statb;
788 size_t file_size;
789 u8 *msg;
790 u8 endian_swap_needed = 0;
791 api_main_t *am = &api_main;
Dave Barach072f8de2016-12-02 13:31:25 -0500792 u8 *tmpbuf = 0;
Dave Barach371e4e12016-07-08 09:38:52 -0400793 u32 nitems;
794 void **saved_print_handlers = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700795
Dave Barach371e4e12016-07-08 09:38:52 -0400796 fd = open ((char *) filename, O_RDONLY);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700797
Dave Barach371e4e12016-07-08 09:38:52 -0400798 if (fd < 0)
799 {
800 vlib_cli_output (vm, "Couldn't open %s\n", filename);
801 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700802 }
803
Dave Barach371e4e12016-07-08 09:38:52 -0400804 if (fstat (fd, &statb) < 0)
805 {
806 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
Dave Barachb2a6e252016-07-27 10:00:58 -0400807 close (fd);
Dave Barach371e4e12016-07-08 09:38:52 -0400808 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700809 }
810
Dave Barach371e4e12016-07-08 09:38:52 -0400811 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
812 {
813 vlib_cli_output (vm, "File not plausible: %s\n", filename);
Ed Warnicke853e7202016-08-12 11:42:26 -0700814 close (fd);
Dave Barach371e4e12016-07-08 09:38:52 -0400815 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700816 }
817
Dave Barach371e4e12016-07-08 09:38:52 -0400818 file_size = statb.st_size;
819 file_size = (file_size + 4095) & ~(4096);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700820
Dave Barach371e4e12016-07-08 09:38:52 -0400821 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822
Dave Barach371e4e12016-07-08 09:38:52 -0400823 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
824 {
825 vlib_cli_output (vm, "mmap failed: %s\n", filename);
826 close (fd);
827 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828 }
Dave Barach371e4e12016-07-08 09:38:52 -0400829 close (fd);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700830
Dave Barach371e4e12016-07-08 09:38:52 -0400831 if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
832 || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
833 endian_swap_needed = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834
Dave Barach371e4e12016-07-08 09:38:52 -0400835 if (endian_swap_needed)
836 nitems = ntohl (hp->nitems);
837 else
838 nitems = hp->nitems;
839
840 if (last_index == (u32) ~ 0)
841 {
842 last_index = nitems - 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700843 }
Dave Barach371e4e12016-07-08 09:38:52 -0400844
845 if (first_index >= nitems || last_index >= nitems)
846 {
847 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
848 first_index, last_index, nitems - 1);
Dave Barachac0798d2016-07-26 10:30:50 -0400849 munmap (hp, file_size);
Dave Barach371e4e12016-07-08 09:38:52 -0400850 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700851 }
Dave Barach371e4e12016-07-08 09:38:52 -0400852 if (hp->wrapped)
853 vlib_cli_output (vm,
854 "Note: wrapped/incomplete trace, results may vary\n");
855
856 if (which == CUSTOM_DUMP)
857 {
858 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
859 vl_msg_api_custom_dump_configure (am);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700860 }
861
862
Dave Barach371e4e12016-07-08 09:38:52 -0400863 msg = (u8 *) (hp + 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700864
Dave Barach371e4e12016-07-08 09:38:52 -0400865 for (i = 0; i < first_index; i++)
866 {
867 trace_cfg_t *cfgp;
868 int size;
869 u16 msg_id;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700870
Dave Barach072f8de2016-12-02 13:31:25 -0500871 size = clib_host_to_net_u32 (*(u32 *) msg);
872 msg += sizeof (u32);
873
Dave Barach371e4e12016-07-08 09:38:52 -0400874 if (clib_arch_is_little_endian)
875 msg_id = ntohs (*((u16 *) msg));
876 else
877 msg_id = *((u16 *) msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700878
Dave Barach371e4e12016-07-08 09:38:52 -0400879 cfgp = am->api_trace_cfg + msg_id;
880 if (!cfgp)
881 {
882 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
Dave Barach8d2e0e02016-11-09 11:28:36 -0500883 munmap (hp, file_size);
Dave Barach371e4e12016-07-08 09:38:52 -0400884 return;
885 }
Dave Barach371e4e12016-07-08 09:38:52 -0400886 msg += size;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700887 }
888
Dave Barach371e4e12016-07-08 09:38:52 -0400889 for (; i <= last_index; i++)
890 {
891 trace_cfg_t *cfgp;
892 u16 *msg_idp;
893 u16 msg_id;
894 int size;
895
896 if (which == DUMP)
897 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
898
Dave Barach072f8de2016-12-02 13:31:25 -0500899 size = clib_host_to_net_u32 (*(u32 *) msg);
900 msg += sizeof (u32);
901
Dave Barach371e4e12016-07-08 09:38:52 -0400902 if (clib_arch_is_little_endian)
903 msg_id = ntohs (*((u16 *) msg));
904 else
905 msg_id = *((u16 *) msg);
906
907 cfgp = am->api_trace_cfg + msg_id;
908 if (!cfgp)
909 {
910 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
Dave Barach8d2e0e02016-11-09 11:28:36 -0500911 munmap (hp, file_size);
Dave Barach072f8de2016-12-02 13:31:25 -0500912 vec_free (tmpbuf);
Dave Barach371e4e12016-07-08 09:38:52 -0400913 return;
914 }
Dave Barach371e4e12016-07-08 09:38:52 -0400915
916 /* Copy the buffer (from the read-only mmap'ed file) */
917 vec_validate (tmpbuf, size - 1 + sizeof (uword));
918 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
919 memset (tmpbuf, 0xf, sizeof (uword));
920
921 /*
922 * Endian swap if needed. All msg data is supposed to be
923 * in network byte order. All msg handlers are supposed to
924 * know that. The generic message dumpers don't know that.
925 * One could fix apigen, I suppose.
926 */
927 if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
928 {
929 void (*endian_fp) (void *);
930 if (msg_id >= vec_len (am->msg_endian_handlers)
931 || (am->msg_endian_handlers[msg_id] == 0))
932 {
933 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
Dave Barachf5179c72016-11-11 17:27:51 -0500934 munmap (hp, file_size);
Dave Barach072f8de2016-12-02 13:31:25 -0500935 vec_free (tmpbuf);
Dave Barach371e4e12016-07-08 09:38:52 -0400936 return;
937 }
938 endian_fp = am->msg_endian_handlers[msg_id];
939 (*endian_fp) (tmpbuf + sizeof (uword));
940 }
941
942 /* msg_id always in network byte order */
943 if (clib_arch_is_little_endian)
944 {
945 msg_idp = (u16 *) (tmpbuf + sizeof (uword));
946 *msg_idp = msg_id;
947 }
948
949 switch (which)
950 {
951 case CUSTOM_DUMP:
952 case DUMP:
953 if (msg_id < vec_len (am->msg_print_handlers) &&
954 am->msg_print_handlers[msg_id])
955 {
956 u8 *(*print_fp) (void *, void *);
957
958 print_fp = (void *) am->msg_print_handlers[msg_id];
959 (*print_fp) (tmpbuf + sizeof (uword), vm);
960 }
961 else
962 {
963 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
964 msg_id);
965 break;
966 }
967 break;
968
969 case INITIALIZERS:
970 if (msg_id < vec_len (am->msg_print_handlers) &&
971 am->msg_print_handlers[msg_id])
972 {
973 u8 *s;
974 int j;
975 u8 *(*print_fp) (void *, void *);
976
977 print_fp = (void *) am->msg_print_handlers[msg_id];
978
979 vlib_cli_output (vm, "/*");
980
981 (*print_fp) (tmpbuf + sizeof (uword), vm);
982 vlib_cli_output (vm, "*/\n");
983
984 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
985 am->msg_names[msg_id], i,
986 am->api_trace_cfg[msg_id].size);
987
988 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
989 {
990 if ((j & 7) == 0)
991 s = format (s, "\n ");
992 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
993 }
994 s = format (s, "\n};\n%c", 0);
995 vlib_cli_output (vm, (char *) s);
996 vec_free (s);
997 }
998 break;
999
1000 case REPLAY:
1001 if (msg_id < vec_len (am->msg_print_handlers) &&
1002 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
1003 {
1004 void (*handler) (void *);
1005
1006 handler = (void *) am->msg_handlers[msg_id];
1007
1008 if (!am->is_mp_safe[msg_id])
1009 vl_msg_api_barrier_sync ();
1010 (*handler) (tmpbuf + sizeof (uword));
1011 if (!am->is_mp_safe[msg_id])
1012 vl_msg_api_barrier_release ();
1013 }
1014 else
1015 {
1016 if (cfgp->replay_enable)
1017 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
1018 msg_id);
1019 break;
1020 }
1021 break;
1022 }
1023
1024 _vec_len (tmpbuf) = 0;
1025 msg += size;
1026 }
1027
1028 if (saved_print_handlers)
1029 {
1030 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
1031 vec_len (am->msg_print_handlers) * sizeof (void *));
1032 vec_free (saved_print_handlers);
1033 }
1034
1035 munmap (hp, file_size);
Dave Barach072f8de2016-12-02 13:31:25 -05001036 vec_free (tmpbuf);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001037}
1038
Dave Barach371e4e12016-07-08 09:38:52 -04001039u8 *
1040format_vl_msg_api_trace_status (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041{
Dave Barach371e4e12016-07-08 09:38:52 -04001042 api_main_t *am = va_arg (*args, api_main_t *);
1043 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
1044 vl_api_trace_t *tp;
1045 char *trace_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001046
Dave Barach371e4e12016-07-08 09:38:52 -04001047 switch (which)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 {
1049 case VL_API_TRACE_TX:
Dave Barach371e4e12016-07-08 09:38:52 -04001050 tp = am->tx_trace;
1051 trace_name = "TX trace";
1052 break;
1053
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054 case VL_API_TRACE_RX:
Dave Barach371e4e12016-07-08 09:38:52 -04001055 tp = am->rx_trace;
1056 trace_name = "RX trace";
1057 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001058
1059 default:
Dave Barach371e4e12016-07-08 09:38:52 -04001060 abort ();
Ed Warnickecb9cada2015-12-08 15:45:58 -07001061 }
1062
Dave Barach371e4e12016-07-08 09:38:52 -04001063 if (tp == 0)
1064 {
1065 s = format (s, "%s: not yet configured.\n", trace_name);
1066 return s;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067 }
1068
Dave Barach371e4e12016-07-08 09:38:52 -04001069 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
1070 trace_name, vec_len (tp->traces), tp->nitems,
1071 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
1072 return s;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001073}
1074
1075static u8 post_mortem_dump_enabled;
1076
1077static clib_error_t *
1078api_trace_command_fn (vlib_main_t * vm,
Dave Barach371e4e12016-07-08 09:38:52 -04001079 unformat_input_t * input, vlib_cli_command_t * cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001080{
Dave Barach371e4e12016-07-08 09:38:52 -04001081 u32 nitems = 256 << 10;
1082 api_main_t *am = &api_main;
1083 vl_api_trace_which_t which = VL_API_TRACE_RX;
1084 u8 *filename;
1085 u32 first = 0;
1086 u32 last = (u32) ~ 0;
1087 FILE *fp;
1088 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001089
Dave Barach371e4e12016-07-08 09:38:52 -04001090 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1091 {
1092 if (unformat (input, "on") || unformat (input, "enable"))
1093 {
1094 if (unformat (input, "nitems %d", &nitems))
1095 ;
1096 vl_msg_api_trace_configure (am, which, nitems);
1097 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1098 }
1099 else if (unformat (input, "off"))
1100 {
1101 vl_msg_api_trace_onoff (am, which, 0);
1102 }
1103 else if (unformat (input, "save %s", &filename))
1104 {
1105 u8 *chroot_filename;
1106 if (strstr ((char *) filename, "..")
1107 || index ((char *) filename, '/'))
1108 {
1109 vlib_cli_output (vm, "illegal characters in filename '%s'",
1110 filename);
1111 return 0;
1112 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001113
Dave Barach371e4e12016-07-08 09:38:52 -04001114 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115
Dave Barach371e4e12016-07-08 09:38:52 -04001116 vec_free (filename);
1117
1118 fp = fopen ((char *) chroot_filename, "w");
1119 if (fp == NULL)
1120 {
1121 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
1122 return 0;
1123 }
1124 rv = vl_msg_api_trace_save (am, which, fp);
1125 fclose (fp);
rootdd9f1332016-07-27 08:01:31 -07001126 if (rv == -1)
Ed Warnicke853e7202016-08-12 11:42:26 -07001127 vlib_cli_output (vm, "API Trace data not present\n");
rootdd9f1332016-07-27 08:01:31 -07001128 else if (rv == -2)
Ed Warnicke853e7202016-08-12 11:42:26 -07001129 vlib_cli_output (vm, "File for writing is closed\n");
rootdd9f1332016-07-27 08:01:31 -07001130 else if (rv == -10)
Ed Warnicke853e7202016-08-12 11:42:26 -07001131 vlib_cli_output (vm, "Error while writing header to file\n");
rootdd9f1332016-07-27 08:01:31 -07001132 else if (rv == -11)
Ed Warnicke853e7202016-08-12 11:42:26 -07001133 vlib_cli_output (vm, "Error while writing trace to file\n");
rootdd9f1332016-07-27 08:01:31 -07001134 else if (rv == -12)
Ed Warnicke853e7202016-08-12 11:42:26 -07001135 vlib_cli_output (vm,
1136 "Error while writing end of buffer trace to file\n");
rootdd9f1332016-07-27 08:01:31 -07001137 else if (rv == -13)
Ed Warnicke853e7202016-08-12 11:42:26 -07001138 vlib_cli_output (vm,
1139 "Error while writing start of buffer trace to file\n");
rootdd9f1332016-07-27 08:01:31 -07001140 else if (rv < 0)
1141 vlib_cli_output (vm, "Unkown error while saving: %d", rv);
Dave Barach371e4e12016-07-08 09:38:52 -04001142 else
1143 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
1144 vec_free (chroot_filename);
1145 }
1146 else if (unformat (input, "dump %s", &filename))
1147 {
1148 vl_msg_api_process_file (vm, filename, first, last, DUMP);
1149 }
1150 else if (unformat (input, "custom-dump %s", &filename))
1151 {
1152 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
1153 }
1154 else if (unformat (input, "replay %s", &filename))
1155 {
1156 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
1157 }
1158 else if (unformat (input, "initializers %s", &filename))
1159 {
1160 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
1161 }
1162 else if (unformat (input, "tx"))
1163 {
1164 which = VL_API_TRACE_TX;
1165 }
1166 else if (unformat (input, "first %d", &first))
1167 {
1168 ;
1169 }
1170 else if (unformat (input, "last %d", &last))
1171 {
1172 ;
1173 }
1174 else if (unformat (input, "status"))
1175 {
1176 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
1177 am, which);
1178 }
1179 else if (unformat (input, "free"))
1180 {
1181 vl_msg_api_trace_onoff (am, which, 0);
1182 vl_msg_api_trace_free (am, which);
1183 }
1184 else if (unformat (input, "post-mortem-on"))
1185 post_mortem_dump_enabled = 1;
1186 else if (unformat (input, "post-mortem-off"))
1187 post_mortem_dump_enabled = 0;
1188 else
1189 return clib_error_return (0, "unknown input `%U'",
1190 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001191 }
Dave Barach371e4e12016-07-08 09:38:52 -04001192 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001193}
1194
Dave Barach371e4e12016-07-08 09:38:52 -04001195/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001196VLIB_CLI_COMMAND (api_trace_command, static) = {
1197 .path = "api trace",
Dave Barach371e4e12016-07-08 09:38:52 -04001198 .short_help =
Ed Warnickecb9cada2015-12-08 15:45:58 -07001199 "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
1200 .function = api_trace_command_fn,
1201};
Dave Barach371e4e12016-07-08 09:38:52 -04001202/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001203
1204static clib_error_t *
1205api_config_fn (vlib_main_t * vm, unformat_input_t * input)
1206{
Dave Barach371e4e12016-07-08 09:38:52 -04001207 u32 nitems = 256 << 10;
1208 vl_api_trace_which_t which = VL_API_TRACE_RX;
1209 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001210
Dave Barach371e4e12016-07-08 09:38:52 -04001211 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1212 {
1213 if (unformat (input, "on") || unformat (input, "enable"))
1214 {
1215 if (unformat (input, "nitems %d", &nitems))
1216 ;
1217 vl_msg_api_trace_configure (am, which, nitems);
1218 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
1219 post_mortem_dump_enabled = 1;
1220 }
1221 else
1222 return clib_error_return (0, "unknown input `%U'",
1223 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001224 }
Dave Barach371e4e12016-07-08 09:38:52 -04001225 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001226}
1227
1228VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
1229
Dave Barach371e4e12016-07-08 09:38:52 -04001230void
1231vl_msg_api_post_mortem_dump (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001232{
Dave Barach371e4e12016-07-08 09:38:52 -04001233 api_main_t *am = &api_main;
1234 FILE *fp;
1235 char filename[64];
1236 int rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001237
Dave Barach371e4e12016-07-08 09:38:52 -04001238 if (post_mortem_dump_enabled == 0)
1239 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001240
Dave Barach371e4e12016-07-08 09:38:52 -04001241 snprintf (filename, sizeof (filename), "/tmp/api_post_mortem.%d",
1242 getpid ());
Ed Warnickecb9cada2015-12-08 15:45:58 -07001243
Dave Barach371e4e12016-07-08 09:38:52 -04001244 fp = fopen (filename, "w");
1245 if (fp == NULL)
1246 {
1247 rv = write (2, "Couldn't create ", 16);
1248 rv = write (2, filename, strlen (filename));
1249 rv = write (2, "\n", 1);
1250 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001251 }
Dave Barach371e4e12016-07-08 09:38:52 -04001252 rv = vl_msg_api_trace_save (am, VL_API_TRACE_RX, fp);
1253 fclose (fp);
1254 if (rv < 0)
1255 {
1256 rv = write (2, "Failed to save post-mortem API trace to ", 40);
1257 rv = write (2, filename, strlen (filename));
1258 rv = write (2, "\n", 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001259 }
Dave Barach371e4e12016-07-08 09:38:52 -04001260
Ed Warnickecb9cada2015-12-08 15:45:58 -07001261}
1262
1263/* Layered message handling support */
1264
Dave Barach371e4e12016-07-08 09:38:52 -04001265void
1266vl_msg_api_register_pd_handler (void *fp, u16 msg_id_host_byte_order)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001267{
Dave Barach371e4e12016-07-08 09:38:52 -04001268 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001269
Dave Barach371e4e12016-07-08 09:38:52 -04001270 /* Mild idiot proofing */
1271 if (msg_id_host_byte_order > 10000)
1272 clib_warning ("msg_id_host_byte_order endian issue? %d arg vs %d",
1273 msg_id_host_byte_order,
1274 clib_net_to_host_u16 (msg_id_host_byte_order));
1275 vec_validate (am->pd_msg_handlers, msg_id_host_byte_order);
1276 am->pd_msg_handlers[msg_id_host_byte_order] = fp;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001277}
1278
Dave Barach371e4e12016-07-08 09:38:52 -04001279int
1280vl_msg_api_pd_handler (void *mp, int rv)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001281{
Dave Barach371e4e12016-07-08 09:38:52 -04001282 api_main_t *am = &api_main;
1283 int (*fp) (void *, int);
1284 u16 msg_id;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001285
Dave Barach371e4e12016-07-08 09:38:52 -04001286 if (clib_arch_is_little_endian)
1287 msg_id = clib_net_to_host_u16 (*((u16 *) mp));
1288 else
1289 msg_id = *((u16 *) mp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001290
Dave Barach371e4e12016-07-08 09:38:52 -04001291 if (msg_id >= vec_len (am->pd_msg_handlers)
1292 || am->pd_msg_handlers[msg_id] == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001293 return rv;
Dave Barach371e4e12016-07-08 09:38:52 -04001294
1295 fp = am->pd_msg_handlers[msg_id];
1296 rv = (*fp) (mp, rv);
1297 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001298}
1299
Dave Barach371e4e12016-07-08 09:38:52 -04001300void
1301vl_msg_api_set_first_available_msg_id (u16 first_avail)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302{
Dave Barach371e4e12016-07-08 09:38:52 -04001303 api_main_t *am = &api_main;
1304
1305 am->first_available_msg_id = first_avail;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001306}
1307
Dave Barach371e4e12016-07-08 09:38:52 -04001308u16
1309vl_msg_api_get_msg_ids (char *name, int n)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001310{
Dave Barach371e4e12016-07-08 09:38:52 -04001311 api_main_t *am = &api_main;
1312 u8 *name_copy;
1313 vl_api_msg_range_t *rp;
1314 uword *p;
1315 u16 rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001316
Dave Barach371e4e12016-07-08 09:38:52 -04001317 if (am->msg_range_by_name == 0)
1318 am->msg_range_by_name = hash_create_string (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001319
Dave Barach371e4e12016-07-08 09:38:52 -04001320 name_copy = format (0, "%s%c", name, 0);
1321
1322 p = hash_get_mem (am->msg_range_by_name, name_copy);
1323 if (p)
1324 {
1325 clib_warning ("WARNING: duplicate message range registration for '%s'",
1326 name_copy);
1327 vec_free (name_copy);
1328 return ((u16) ~ 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001329 }
1330
Dave Barach371e4e12016-07-08 09:38:52 -04001331 if (n < 0 || n > 1024)
1332 {
1333 clib_warning
1334 ("WARNING: bad number of message-IDs (%d) requested by '%s'",
1335 n, name_copy);
1336 vec_free (name_copy);
1337 return ((u16) ~ 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001338 }
1339
Dave Barach371e4e12016-07-08 09:38:52 -04001340 vec_add2 (am->msg_ranges, rp, 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001341
Dave Barach371e4e12016-07-08 09:38:52 -04001342 rv = rp->first_msg_id = am->first_available_msg_id;
1343 am->first_available_msg_id += n;
1344 rp->last_msg_id = am->first_available_msg_id - 1;
1345 rp->name = name_copy;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001346
Dave Barach371e4e12016-07-08 09:38:52 -04001347 hash_set_mem (am->msg_range_by_name, name_copy, rp - am->msg_ranges);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001348
Dave Barach371e4e12016-07-08 09:38:52 -04001349 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001350}
Dave Barach371e4e12016-07-08 09:38:52 -04001351
Dave Barach557d1282016-11-10 14:22:49 -05001352void
1353vl_msg_api_add_msg_name_crc (api_main_t * am, char *string, u32 id)
1354{
1355 uword *p;
1356
1357 if (am->msg_index_by_name_and_crc == 0)
1358 am->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
1359
1360 p = hash_get_mem (am->msg_index_by_name_and_crc, string);
1361 if (p)
1362 {
1363 clib_warning ("attempt to redefine '%s' ignored...", string);
1364 return;
1365 }
1366
1367 hash_set_mem (am->msg_index_by_name_and_crc, string, id);
1368}
1369
1370
Dave Barach371e4e12016-07-08 09:38:52 -04001371/*
1372 * fd.io coding-style-patch-verification: ON
1373 *
1374 * Local Variables:
1375 * eval: (c-set-style "gnu")
1376 * End:
1377 */