blob: 65d04dc266f4fd961dd0a265e7fb59a3b8d4ebbd [file] [log] [blame]
Dave Barach371e4e12016-07-08 09:38:52 -04001/*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002 *------------------------------------------------------------------
Dave Barach371e4e12016-07-08 09:38:52 -04003 * memory_vlib.c
Ed Warnickecb9cada2015-12-08 15:45:58 -07004 *
5 * Copyright (c) 2009 Cisco and/or its affiliates.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *------------------------------------------------------------------
18 */
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24#include <sys/types.h>
Dave Barach80f54e22017-03-08 19:08:56 -050025#include <sys/stat.h>
26#include <fcntl.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070027#include <signal.h>
28#include <pthread.h>
29#include <vppinfra/vec.h>
30#include <vppinfra/hash.h>
31#include <vppinfra/pool.h>
32#include <vppinfra/format.h>
33#include <vppinfra/byte_order.h>
34#include <vppinfra/elog.h>
35#include <stdarg.h>
36#include <vlib/vlib.h>
37#include <vlib/unix/unix.h>
38#include <vlibapi/api.h>
39#include <vlibmemory/api.h>
40
Dave Barach49fe0462017-09-12 17:06:56 -040041/**
42 * @file
43 * @brief Binary API messaging via shared memory
44 * Low-level, primary provisioning interface
45 */
46/*? %%clicmd:group_label Binary API CLI %% ?*/
47/*? %%syscfg:group_label Binary API configuration %% ?*/
48
Ed Warnickecb9cada2015-12-08 15:45:58 -070049#define TRACE_VLIB_MEMORY_QUEUE 0
50
Dave Barach371e4e12016-07-08 09:38:52 -040051#include <vlibmemory/vl_memory_msg_enum.h> /* enumerate all vlib messages */
Ed Warnickecb9cada2015-12-08 15:45:58 -070052
Dave Barach371e4e12016-07-08 09:38:52 -040053#define vl_typedefs /* define message structures */
54#include <vlibmemory/vl_memory_api_h.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070055#undef vl_typedefs
56
57/* instantiate all the print functions we know about */
58#define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
59#define vl_printfun
Dave Barach371e4e12016-07-08 09:38:52 -040060#include <vlibmemory/vl_memory_api_h.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070061#undef vl_printfun
62
63static inline void *
Dave Barach371e4e12016-07-08 09:38:52 -040064vl_api_memclnt_create_t_print (vl_api_memclnt_create_t * a, void *handle)
Ed Warnickecb9cada2015-12-08 15:45:58 -070065{
Dave Barach371e4e12016-07-08 09:38:52 -040066 vl_print (handle, "vl_api_memclnt_create_t:\n");
67 vl_print (handle, "name: %s\n", a->name);
68 vl_print (handle, "input_queue: 0x%wx\n", a->input_queue);
69 vl_print (handle, "context: %u\n", (unsigned) a->context);
70 vl_print (handle, "ctx_quota: %ld\n", (long) a->ctx_quota);
71 return handle;
Ed Warnickecb9cada2015-12-08 15:45:58 -070072}
73
74static inline void *
Dave Barach371e4e12016-07-08 09:38:52 -040075vl_api_memclnt_delete_t_print (vl_api_memclnt_delete_t * a, void *handle)
Ed Warnickecb9cada2015-12-08 15:45:58 -070076{
Dave Barach371e4e12016-07-08 09:38:52 -040077 vl_print (handle, "vl_api_memclnt_delete_t:\n");
78 vl_print (handle, "index: %u\n", (unsigned) a->index);
79 vl_print (handle, "handle: 0x%wx\n", a->handle);
80 return handle;
Ed Warnickecb9cada2015-12-08 15:45:58 -070081}
82
Dave Barach987e11d2017-02-27 13:10:27 -050083static inline void *
84vl_api_trace_plugin_msg_ids_t_print (vl_api_trace_plugin_msg_ids_t * a,
85 void *handle)
86{
87 vl_print (handle, "vl_api_trace_plugin_msg_ids: %s first %u last %u\n",
88 a->plugin_name,
89 clib_host_to_net_u16 (a->first_msg_id),
90 clib_host_to_net_u16 (a->last_msg_id));
91 return handle;
92}
93
Ed Warnickecb9cada2015-12-08 15:45:58 -070094/* instantiate all the endian swap functions we know about */
95#define vl_endianfun
Dave Barach371e4e12016-07-08 09:38:52 -040096#include <vlibmemory/vl_memory_api_h.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070097#undef vl_endianfun
98
Dave Barach59b25652017-09-10 15:04:27 -040099extern void vl_socket_api_send (vl_api_registration_t * rp, u8 * elem);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100
Dave Barach371e4e12016-07-08 09:38:52 -0400101void
102vl_msg_api_send (vl_api_registration_t * rp, u8 * elem)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103{
Dave Barach371e4e12016-07-08 09:38:52 -0400104 if (PREDICT_FALSE (rp->registration_type > REGISTRATION_TYPE_SHMEM))
105 {
106 vl_socket_api_send (rp, elem);
107 }
108 else
109 {
Dave Barach59b25652017-09-10 15:04:27 -0400110 vl_msg_api_send_shmem (rp->vl_input_queue, (u8 *) & elem);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111 }
112}
113
Dave Barach557d1282016-11-10 14:22:49 -0500114u8 *
115vl_api_serialize_message_table (api_main_t * am, u8 * vector)
Dave Barach371e4e12016-07-08 09:38:52 -0400116{
Dave Barach557d1282016-11-10 14:22:49 -0500117 serialize_main_t _sm, *sm = &_sm;
118 hash_pair_t *hp;
119 u32 nmsg = hash_elts (am->msg_index_by_name_and_crc);
120
121 serialize_open_vector (sm, vector);
122
123 /* serialize the count */
124 serialize_integer (sm, nmsg, sizeof (u32));
125
Dave Barach987e11d2017-02-27 13:10:27 -0500126 /* *INDENT-OFF* */
127 hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
128 ({
129 serialize_likely_small_unsigned_integer (sm, hp->value[0]);
130 serialize_cstring (sm, (char *) hp->key);
131 }));
132 /* *INDENT-ON* */
Dave Barach557d1282016-11-10 14:22:49 -0500133
134 return serialize_close_vector (sm);
Dave Barach371e4e12016-07-08 09:38:52 -0400135}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136
137/*
Dave Barach52851e62017-08-07 09:35:25 -0400138 * vl_api_memclnt_create_internal
139 */
140
141u32
142vl_api_memclnt_create_internal (char *name, unix_shared_memory_queue_t * q)
143{
144 vl_api_registration_t **regpp;
145 vl_api_registration_t *regp;
146 svm_region_t *svm;
147 void *oldheap;
148 api_main_t *am = &api_main;
149
150 ASSERT (vlib_get_thread_index () == 0);
151 pool_get (am->vl_clients, regpp);
152
153 svm = am->vlib_rp;
154
155 pthread_mutex_lock (&svm->mutex);
156 oldheap = svm_push_data_heap (svm);
157 *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
158
159 regp = *regpp;
160 memset (regp, 0, sizeof (*regp));
161 regp->registration_type = REGISTRATION_TYPE_SHMEM;
162 regp->vl_api_registration_pool_index = regpp - am->vl_clients;
Florin Coras780fc392017-10-03 14:26:10 -0400163 regp->vlib_rp = svm;
164 regp->shmem_hdr = am->shmem_hdr;
Dave Barach52851e62017-08-07 09:35:25 -0400165
166 regp->vl_input_queue = q;
167 regp->name = format (0, "%s%c", name, 0);
168
169 pthread_mutex_unlock (&svm->mutex);
170 svm_pop_heap (oldheap);
171 return vl_msg_api_handle_from_index_and_epoch
172 (regp->vl_api_registration_pool_index,
173 am->shmem_hdr->application_restarts);
174}
175
176
177/*
Ed Warnickecb9cada2015-12-08 15:45:58 -0700178 * vl_api_memclnt_create_t_handler
179 */
Dave Barach371e4e12016-07-08 09:38:52 -0400180void
181vl_api_memclnt_create_t_handler (vl_api_memclnt_create_t * mp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182{
Dave Barach371e4e12016-07-08 09:38:52 -0400183 vl_api_registration_t **regpp;
184 vl_api_registration_t *regp;
185 vl_api_memclnt_create_reply_t *rp;
186 svm_region_t *svm;
187 unix_shared_memory_queue_t *q;
Dave Barach557d1282016-11-10 14:22:49 -0500188 int rv = 0;
Dave Barach371e4e12016-07-08 09:38:52 -0400189 void *oldheap;
190 api_main_t *am = &api_main;
Dave Barach59b25652017-09-10 15:04:27 -0400191 u8 *serialized_message_table_in_shmem;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192
Dave Barach371e4e12016-07-08 09:38:52 -0400193 /*
194 * This is tortured. Maintain a vlib-address-space private
195 * pool of client registrations. We use the shared-memory virtual
196 * address of client structure as a handle, to allow direct
197 * manipulation of context quota vbls from the client library.
198 *
199 * This scheme causes trouble w/ API message trace replay, since
200 * some random VA from clib_mem_alloc() certainly won't
201 * occur in the Linux sim. The (very) few places
202 * that care need to use the pool index.
203 *
204 * Putting the registration object(s) into a pool in shared memory and
205 * using the pool index as a handle seems like a great idea.
206 * Unfortunately, each and every reference to that pool would need
207 * to be protected by a mutex:
208 *
209 * Client VLIB
210 * ------ ----
211 * convert pool index to
212 * pointer.
213 * <deschedule>
214 * expand pool
215 * <deschedule>
216 * kaboom!
217 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700218
Dave Barach371e4e12016-07-08 09:38:52 -0400219 pool_get (am->vl_clients, regpp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700220
Dave Barach371e4e12016-07-08 09:38:52 -0400221 svm = am->vlib_rp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700222
Dave Barach371e4e12016-07-08 09:38:52 -0400223 pthread_mutex_lock (&svm->mutex);
224 oldheap = svm_push_data_heap (svm);
225 *regpp = clib_mem_alloc (sizeof (vl_api_registration_t));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700226
Dave Barach371e4e12016-07-08 09:38:52 -0400227 regp = *regpp;
228 memset (regp, 0, sizeof (*regp));
229 regp->registration_type = REGISTRATION_TYPE_SHMEM;
230 regp->vl_api_registration_pool_index = regpp - am->vl_clients;
Dave Barach59b25652017-09-10 15:04:27 -0400231 regp->vlib_rp = svm;
232 regp->shmem_hdr = am->shmem_hdr;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700233
Dave Barach371e4e12016-07-08 09:38:52 -0400234 q = regp->vl_input_queue = (unix_shared_memory_queue_t *) (uword)
235 mp->input_queue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236
Dave Barach371e4e12016-07-08 09:38:52 -0400237 regp->name = format (0, "%s", mp->name);
238 vec_add1 (regp->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700239
Dave Barach59b25652017-09-10 15:04:27 -0400240 serialized_message_table_in_shmem = vl_api_serialize_message_table (am, 0);
241
Dave Barach371e4e12016-07-08 09:38:52 -0400242 pthread_mutex_unlock (&svm->mutex);
243 svm_pop_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244
Dave Barach371e4e12016-07-08 09:38:52 -0400245 rp = vl_msg_api_alloc (sizeof (*rp));
246 rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_REPLY);
247 rp->handle = (uword) regp;
248 rp->index = vl_msg_api_handle_from_index_and_epoch
249 (regp->vl_api_registration_pool_index,
250 am->shmem_hdr->application_restarts);
251 rp->context = mp->context;
252 rp->response = ntohl (rv);
Dave Barach59b25652017-09-10 15:04:27 -0400253 rp->message_table = pointer_to_uword (serialized_message_table_in_shmem);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254
Dave Barach371e4e12016-07-08 09:38:52 -0400255 vl_msg_api_send_shmem (q, (u8 *) & rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256}
257
Dave Barachb64e4e22017-03-14 09:10:56 -0400258static int
259call_reaper_functions (u32 client_index)
Dave Barach371e4e12016-07-08 09:38:52 -0400260{
Dave Barachb64e4e22017-03-14 09:10:56 -0400261 clib_error_t *error = 0;
262 _vl_msg_api_function_list_elt_t *i;
263
264 i = api_main.reaper_function_registrations;
265 while (i)
266 {
267 error = i->f (client_index);
268 if (error)
269 clib_error_report (error);
270 i = i->next_init_function;
271 }
Dave Barach371e4e12016-07-08 09:38:52 -0400272 return 0;
273}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700274
275/*
276 * vl_api_memclnt_delete_t_handler
277 */
Dave Barach371e4e12016-07-08 09:38:52 -0400278void
279vl_api_memclnt_delete_t_handler (vl_api_memclnt_delete_t * mp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280{
Dave Barach371e4e12016-07-08 09:38:52 -0400281 vl_api_registration_t **regpp;
282 vl_api_registration_t *regp;
283 vl_api_memclnt_delete_reply_t *rp;
284 svm_region_t *svm;
285 void *oldheap;
286 api_main_t *am = &api_main;
287 u32 handle, client_index, epoch;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288
Dave Barach371e4e12016-07-08 09:38:52 -0400289 handle = mp->index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290
Dave Barachb64e4e22017-03-14 09:10:56 -0400291 if (call_reaper_functions (handle))
Dave Barach371e4e12016-07-08 09:38:52 -0400292 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293
Dave Barach371e4e12016-07-08 09:38:52 -0400294 epoch = vl_msg_api_handle_get_epoch (handle);
295 client_index = vl_msg_api_handle_get_index (handle);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296
Dave Barach371e4e12016-07-08 09:38:52 -0400297 if (epoch != (am->shmem_hdr->application_restarts & VL_API_EPOCH_MASK))
298 {
299 clib_warning
300 ("Stale clnt delete index %d old epoch %d cur epoch %d",
301 client_index, epoch,
302 (am->shmem_hdr->application_restarts & VL_API_EPOCH_MASK));
303 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700304 }
305
Dave Barach371e4e12016-07-08 09:38:52 -0400306 regpp = am->vl_clients + client_index;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700307
Dave Barach371e4e12016-07-08 09:38:52 -0400308 if (!pool_is_free (am->vl_clients, regpp))
309 {
Dave Barach59b25652017-09-10 15:04:27 -0400310 int i;
Dave Barach371e4e12016-07-08 09:38:52 -0400311 regp = *regpp;
312 svm = am->vlib_rp;
Dave Barach59b25652017-09-10 15:04:27 -0400313 int private_registration = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700314
Dave Barach59b25652017-09-10 15:04:27 -0400315 /*
316 * Note: the API message handling path will set am->vlib_rp
317 * as appropriate for pairwise / private memory segments
318 */
Dave Barach371e4e12016-07-08 09:38:52 -0400319 rp = vl_msg_api_alloc (sizeof (*rp));
320 rp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE_REPLY);
321 rp->handle = mp->handle;
322 rp->response = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700323
Dave Barach371e4e12016-07-08 09:38:52 -0400324 vl_msg_api_send_shmem (regp->vl_input_queue, (u8 *) & rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700325
Dave Barach371e4e12016-07-08 09:38:52 -0400326 if (client_index != regp->vl_api_registration_pool_index)
327 {
328 clib_warning ("mismatch client_index %d pool_index %d",
329 client_index, regp->vl_api_registration_pool_index);
330 vl_msg_api_free (rp);
331 return;
332 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333
Dave Barach59b25652017-09-10 15:04:27 -0400334 /* For horizontal scaling, add a hash table... */
335 for (i = 0; i < vec_len (am->vlib_private_rps); i++)
336 {
337 /* Is this a pairwise / private API segment? */
338 if (am->vlib_private_rps[i] == svm)
339 {
340 /* Note: account for the memfd header page */
341 u64 virtual_base = svm->virtual_base - MMAP_PAGESIZE;
342 u64 virtual_size = svm->virtual_size + MMAP_PAGESIZE;
343
344 /*
345 * Kill the registration pool element before we make
346 * the index vanish forever
347 */
348 pool_put_index (am->vl_clients,
349 regp->vl_api_registration_pool_index);
350
351 vec_delete (am->vlib_private_rps, 1, i);
352 /* Kill it, accounting for the memfd header page */
353 if (munmap ((void *) virtual_base, virtual_size) < 0)
354 clib_unix_warning ("munmap");
355 /* Reset the queue-length-address cache */
356 vec_reset_length (vl_api_queue_cursizes);
357 private_registration = 1;
358 break;
359 }
360 }
361
Dave Barach371e4e12016-07-08 09:38:52 -0400362 /* No dangling references, please */
363 *regpp = 0;
364
Dave Barach59b25652017-09-10 15:04:27 -0400365 if (private_registration == 0)
366 {
367 pool_put_index (am->vl_clients,
368 regp->vl_api_registration_pool_index);
369 pthread_mutex_lock (&svm->mutex);
370 oldheap = svm_push_data_heap (svm);
371 /* Poison the old registration */
372 memset (regp, 0xF1, sizeof (*regp));
373 clib_mem_free (regp);
374 pthread_mutex_unlock (&svm->mutex);
375 svm_pop_heap (oldheap);
376 /*
377 * These messages must be freed manually, since they're set up
378 * as "bounce" messages. In the private_registration == 1 case,
379 * we kill the shared-memory segment which contains the message
380 * with munmap.
381 */
382 vl_msg_api_free (mp);
383 }
Dave Barach371e4e12016-07-08 09:38:52 -0400384 }
385 else
386 {
387 clib_warning ("unknown client ID %d", mp->index);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388 }
389}
390
Dave Barach371e4e12016-07-08 09:38:52 -0400391void
392vl_api_get_first_msg_id_t_handler (vl_api_get_first_msg_id_t * mp)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393{
Dave Barach371e4e12016-07-08 09:38:52 -0400394 vl_api_get_first_msg_id_reply_t *rmp;
395 unix_shared_memory_queue_t *q;
396 uword *p;
397 api_main_t *am = &api_main;
398 vl_api_msg_range_t *rp;
399 u8 name[64];
400 u16 first_msg_id = ~0;
401 int rv = -7; /* VNET_API_ERROR_INVALID_VALUE */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402
Dave Barach371e4e12016-07-08 09:38:52 -0400403 q = vl_api_client_index_to_input_queue (mp->client_index);
404 if (!q)
405 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406
Dave Barach371e4e12016-07-08 09:38:52 -0400407 if (am->msg_range_by_name == 0)
408 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409
Dave Barach371e4e12016-07-08 09:38:52 -0400410 strncpy ((char *) name, (char *) mp->name, ARRAY_LEN (name) - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700411
Dave Barach371e4e12016-07-08 09:38:52 -0400412 p = hash_get_mem (am->msg_range_by_name, name);
413 if (p == 0)
414 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415
Dave Barach371e4e12016-07-08 09:38:52 -0400416 rp = vec_elt_at_index (am->msg_ranges, p[0]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417
Dave Barach371e4e12016-07-08 09:38:52 -0400418 first_msg_id = rp->first_msg_id;
419 rv = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420
421out:
422
Dave Barach371e4e12016-07-08 09:38:52 -0400423 rmp = vl_msg_api_alloc (sizeof (*rmp));
424 rmp->_vl_msg_id = ntohs (VL_API_GET_FIRST_MSG_ID_REPLY);
425 rmp->context = mp->context;
426 rmp->retval = ntohl (rv);
427 rmp->first_msg_id = ntohs (first_msg_id);
428 vl_msg_api_send_shmem (q, (u8 *) & rmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700429}
430
Dave Barach59b25652017-09-10 15:04:27 -0400431/**
432 * client answered a ping, stave off the grim reaper...
433 */
434
435void
436 vl_api_memclnt_keepalive_reply_t_handler
437 (vl_api_memclnt_keepalive_reply_t * mp)
438{
439 vl_api_registration_t *regp;
440 vlib_main_t *vm = vlib_get_main ();
441
442 regp = vl_api_client_index_to_registration (mp->context);
443 if (regp)
444 {
445 regp->last_heard = vlib_time_now (vm);
446 regp->unanswered_pings = 0;
447 }
448 else
449 clib_warning ("BUG: anonymous memclnt_keepalive_reply");
450}
451
452/**
453 * We can send ourselves these messages if someone uses the
454 * builtin binary api test tool...
455 */
456static void
457vl_api_memclnt_keepalive_t_handler (vl_api_memclnt_keepalive_t * mp)
458{
459 vl_api_memclnt_keepalive_reply_t *rmp;
460 api_main_t *am;
461 vl_shmem_hdr_t *shmem_hdr;
462
463 am = &api_main;
464 shmem_hdr = am->shmem_hdr;
465
466 rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp));
467 memset (rmp, 0, sizeof (*rmp));
468 rmp->_vl_msg_id = ntohs (VL_API_MEMCLNT_KEEPALIVE_REPLY);
469 rmp->context = mp->context;
470 vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) & rmp);
471}
472
Dave Barach0d056e52017-09-28 15:11:16 -0400473void
474vl_api_api_versions_t_handler (vl_api_api_versions_t * mp)
475{
476 api_main_t *am = &api_main;
477 vl_api_api_versions_reply_t *rmp;
478 unix_shared_memory_queue_t *q;
479 u32 nmsg = vec_len (am->api_version_list);
480 int msg_size = sizeof (*rmp) + sizeof (rmp->api_versions[0]) * nmsg;
481 int i;
482
483 q = vl_api_client_index_to_input_queue (mp->client_index);
484 if (q == 0)
485 return;
486
487 rmp = vl_msg_api_alloc (msg_size);
488 memset (rmp, 0, msg_size);
489 rmp->_vl_msg_id = ntohs (VL_API_API_VERSIONS_REPLY);
490
491 /* fill in the message */
492 rmp->context = mp->context;
493 rmp->count = htonl (nmsg);
494
495 for (i = 0; i < nmsg; ++i)
496 {
497 api_version_t *vl = &am->api_version_list[i];
498 rmp->api_versions[i].major = htonl (vl->major);
499 rmp->api_versions[i].minor = htonl (vl->minor);
500 rmp->api_versions[i].patch = htonl (vl->patch);
Ole Troan7504e992017-10-10 08:43:35 +0200501 strncpy ((char *) rmp->api_versions[i].name, vl->name, 64 - 1);
Dave Barach0d056e52017-09-28 15:11:16 -0400502 }
503
504 vl_msg_api_send_shmem (q, (u8 *) & rmp);
505
506}
507
Dave Barach59b25652017-09-10 15:04:27 -0400508#define foreach_vlib_api_msg \
509_(MEMCLNT_CREATE, memclnt_create) \
510_(MEMCLNT_DELETE, memclnt_delete) \
511_(GET_FIRST_MSG_ID, get_first_msg_id) \
512_(MEMCLNT_KEEPALIVE, memclnt_keepalive) \
Dave Barach0d056e52017-09-28 15:11:16 -0400513_(MEMCLNT_KEEPALIVE_REPLY, memclnt_keepalive_reply) \
514_(API_VERSIONS, api_versions)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
516/*
517 * vl_api_init
518 */
Dave Barach371e4e12016-07-08 09:38:52 -0400519static int
Neale Rannse72be392017-04-26 13:59:20 -0700520memory_api_init (const char *region_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521{
Dave Barach371e4e12016-07-08 09:38:52 -0400522 int rv;
Dave Barach59b25652017-09-10 15:04:27 -0400523 api_main_t *am = &api_main;
Dave Barach371e4e12016-07-08 09:38:52 -0400524 vl_msg_api_msg_config_t cfg;
525 vl_msg_api_msg_config_t *c = &cfg;
526
Dave Barach0691d6e2017-01-05 10:08:52 -0500527 memset (c, 0, sizeof (*c));
528
Dave Barach371e4e12016-07-08 09:38:52 -0400529 if ((rv = vl_map_shmem (region_name, 1 /* is_vlib */ )) < 0)
530 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700531
532#define _(N,n) do { \
533 c->id = VL_API_##N; \
534 c->name = #n; \
535 c->handler = vl_api_##n##_t_handler; \
536 c->cleanup = vl_noop_handler; \
537 c->endian = vl_api_##n##_t_endian; \
538 c->print = vl_api_##n##_t_print; \
539 c->size = sizeof(vl_api_##n##_t); \
540 c->traced = 1; /* trace, so these msgs print */ \
541 c->replay = 0; /* don't replay client create/delete msgs */ \
Dave Barach0691d6e2017-01-05 10:08:52 -0500542 c->message_bounce = 0; /* don't bounce this message */ \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700543 vl_msg_api_config(c);} while (0);
Dave Barach371e4e12016-07-08 09:38:52 -0400544
545 foreach_vlib_api_msg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700546#undef _
547
Dave Barach59b25652017-09-10 15:04:27 -0400548 /*
549 * special-case freeing of memclnt_delete messages, so we can
550 * simply munmap pairwise / private API segments...
551 */
552 am->message_bounce[VL_API_MEMCLNT_DELETE] = 1;
553 am->is_mp_safe[VL_API_MEMCLNT_KEEPALIVE_REPLY] = 1;
554
Dave Barach371e4e12016-07-08 09:38:52 -0400555 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556}
557
558#define foreach_histogram_bucket \
559_(400) \
560_(200) \
561_(100) \
562_(10)
563
Dave Barach371e4e12016-07-08 09:38:52 -0400564typedef enum
565{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700566#define _(n) SLEEP_##n##_US,
Dave Barach371e4e12016-07-08 09:38:52 -0400567 foreach_histogram_bucket
Ed Warnickecb9cada2015-12-08 15:45:58 -0700568#undef _
569 SLEEP_N_BUCKETS,
570} histogram_index_t;
571
572static u64 vector_rate_histogram[SLEEP_N_BUCKETS];
573
Dave Barach371e4e12016-07-08 09:38:52 -0400574static void memclnt_queue_callback (vlib_main_t * vm);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700575
Dave Barach987e11d2017-02-27 13:10:27 -0500576/*
577 * Callback to send ourselves a plugin numbering-space trace msg
578 */
579static void
580send_one_plugin_msg_ids_msg (u8 * name, u16 first_msg_id, u16 last_msg_id)
581{
582 vl_api_trace_plugin_msg_ids_t *mp;
583 api_main_t *am = &api_main;
584 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
585 unix_shared_memory_queue_t *q;
586
587 mp = vl_msg_api_alloc_as_if_client (sizeof (*mp));
588 memset (mp, 0, sizeof (*mp));
589
590 mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_TRACE_PLUGIN_MSG_IDS);
591 strncpy ((char *) mp->plugin_name, (char *) name,
592 sizeof (mp->plugin_name) - 1);
593 mp->first_msg_id = clib_host_to_net_u16 (first_msg_id);
594 mp->last_msg_id = clib_host_to_net_u16 (last_msg_id);
595
596 q = shmem_hdr->vl_input_queue;
597
598 vl_msg_api_send_shmem (q, (u8 *) & mp);
599}
600
Dave Barach59b25652017-09-10 15:04:27 -0400601static void
602send_memclnt_keepalive (vl_api_registration_t * regp, f64 now)
603{
604 vl_api_memclnt_keepalive_t *mp;
605 unix_shared_memory_queue_t *q;
606 api_main_t *am = &api_main;
607 svm_region_t *save_vlib_rp = am->vlib_rp;
608 vl_shmem_hdr_t *save_shmem_hdr = am->shmem_hdr;
609
610 q = regp->vl_input_queue;
611
612 /*
613 * If the queue head is moving, assume that the client is processing
614 * messages and skip the ping. This heuristic may fail if the queue
615 * is in the same position as last time, net of wrapping; in which
616 * case, the client will receive a keepalive.
617 */
618 if (regp->last_queue_head != q->head)
619 {
620 regp->last_heard = now;
621 regp->unanswered_pings = 0;
622 regp->last_queue_head = q->head;
623 return;
624 }
625
626 /*
627 * push/pop shared memory segment, so this routine
628 * will work with "normal" as well as "private segment"
629 * memory clients..
630 */
631
632 am->vlib_rp = regp->vlib_rp;
633 am->shmem_hdr = regp->shmem_hdr;
634
635 mp = vl_msg_api_alloc (sizeof (*mp));
636 memset (mp, 0, sizeof (*mp));
637 mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_MEMCLNT_KEEPALIVE);
638 mp->context = mp->client_index =
639 vl_msg_api_handle_from_index_and_epoch
640 (regp->vl_api_registration_pool_index,
641 am->shmem_hdr->application_restarts);
642
643 regp->unanswered_pings++;
644
645 /* Failure-to-send due to a stuffed queue is absolutely expected */
646 if (unix_shared_memory_queue_add (q, (u8 *) & mp, 1 /* nowait */ ))
647 vl_msg_api_free (mp);
648
649 am->vlib_rp = save_vlib_rp;
650 am->shmem_hdr = save_shmem_hdr;
651}
652
653static void
654dead_client_scan (api_main_t * am, vl_shmem_hdr_t * shm, f64 now)
655{
656
657 vl_api_registration_t **regpp;
658 vl_api_registration_t *regp;
659 static u32 *dead_indices;
660 static u32 *confused_indices;
661
662 vec_reset_length (dead_indices);
663 vec_reset_length (confused_indices);
664
665 /* *INDENT-OFF* */
666 pool_foreach (regpp, am->vl_clients,
667 ({
668 regp = *regpp;
669 if (regp)
670 {
671 /* If we haven't heard from this client recently... */
672 if (regp->last_heard < (now - 10.0))
673 {
674 if (regp->unanswered_pings == 2)
675 {
676 unix_shared_memory_queue_t *q;
677 q = regp->vl_input_queue;
678 if (kill (q->consumer_pid, 0) >=0)
679 {
680 clib_warning ("REAPER: lazy binary API client '%s'",
681 regp->name);
682 regp->unanswered_pings = 0;
683 regp->last_heard = now;
684 }
685 else
686 {
687 clib_warning ("REAPER: binary API client '%s' died",
688 regp->name);
689 vec_add1(dead_indices, regpp - am->vl_clients);
690 }
691 }
692 else
693 send_memclnt_keepalive (regp, now);
694 }
695 else
696 regp->unanswered_pings = 0;
697 }
698 else
699 {
700 clib_warning ("NULL client registration index %d",
701 regpp - am->vl_clients);
702 vec_add1 (confused_indices, regpp - am->vl_clients);
703 }
704 }));
705 /* *INDENT-ON* */
706 /* This should "never happen," but if it does, fix it... */
707 if (PREDICT_FALSE (vec_len (confused_indices) > 0))
708 {
709 int i;
710 for (i = 0; i < vec_len (confused_indices); i++)
711 {
712 pool_put_index (am->vl_clients, confused_indices[i]);
713 }
714 }
715
716 if (PREDICT_FALSE (vec_len (dead_indices) > 0))
717 {
718 int i;
719 svm_region_t *svm;
720 void *oldheap;
721
722 /* Allow the application to clean up its registrations */
723 for (i = 0; i < vec_len (dead_indices); i++)
724 {
725 regpp = pool_elt_at_index (am->vl_clients, dead_indices[i]);
726 if (regpp)
727 {
728 u32 handle;
729
730 handle = vl_msg_api_handle_from_index_and_epoch
731 (dead_indices[i], shm->application_restarts);
732 (void) call_reaper_functions (handle);
733 }
734 }
735
736 svm = am->vlib_rp;
737 pthread_mutex_lock (&svm->mutex);
738 oldheap = svm_push_data_heap (svm);
739
740 for (i = 0; i < vec_len (dead_indices); i++)
741 {
742 regpp = pool_elt_at_index (am->vl_clients, dead_indices[i]);
743 if (regpp)
744 {
745 /* Is this a pairwise SVM segment? */
746 if ((*regpp)->vlib_rp != svm)
747 {
748 int i;
749 svm_region_t *dead_rp = (*regpp)->vlib_rp;
750 /* Note: account for the memfd header page */
751 u64 virtual_base = dead_rp->virtual_base - MMAP_PAGESIZE;
752 u64 virtual_size = dead_rp->virtual_size + MMAP_PAGESIZE;
753
754 /* For horizontal scaling, add a hash table... */
755 for (i = 0; i < vec_len (am->vlib_private_rps); i++)
756 if (am->vlib_private_rps[i] == dead_rp)
757 {
758 vec_delete (am->vlib_private_rps, 1, i);
759 goto found;
760 }
761 clib_warning ("private rp %llx AWOL", dead_rp);
762
763 found:
764 /* Kill it, accounting for the memfd header page */
765 if (munmap ((void *) virtual_base, virtual_size) < 0)
766 clib_unix_warning ("munmap");
767 /* Reset the queue-length-address cache */
768 vec_reset_length (vl_api_queue_cursizes);
769 }
770 else
771 {
772 /* Poison the old registration */
773 memset (*regpp, 0xF3, sizeof (**regpp));
774 clib_mem_free (*regpp);
775 }
776 /* no dangling references, please */
777 *regpp = 0;
778 }
779 else
780 {
781 svm_pop_heap (oldheap);
782 clib_warning ("Duplicate free, client index %d",
783 regpp - am->vl_clients);
784 oldheap = svm_push_data_heap (svm);
785 }
786 }
787
788 svm_client_scan_this_region_nolock (am->vlib_rp);
789
790 pthread_mutex_unlock (&svm->mutex);
791 svm_pop_heap (oldheap);
792 for (i = 0; i < vec_len (dead_indices); i++)
793 pool_put_index (am->vl_clients, dead_indices[i]);
794 }
795}
796
797
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798static uword
799memclnt_process (vlib_main_t * vm,
Dave Barach371e4e12016-07-08 09:38:52 -0400800 vlib_node_runtime_t * node, vlib_frame_t * f)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801{
Dave Barach371e4e12016-07-08 09:38:52 -0400802 uword mp;
803 vl_shmem_hdr_t *shm;
804 unix_shared_memory_queue_t *q;
805 clib_error_t *e;
806 int rv;
807 api_main_t *am = &api_main;
808 f64 dead_client_scan_time;
809 f64 sleep_time, start_time;
810 f64 vector_rate;
Dave Barach59b25652017-09-10 15:04:27 -0400811 clib_error_t *socksvr_api_init (vlib_main_t * vm);
812 clib_error_t *error;
Dave Barach987e11d2017-02-27 13:10:27 -0500813 int i;
Dave Barach59b25652017-09-10 15:04:27 -0400814 vl_socket_args_for_process_t *a;
815 uword event_type;
816 uword *event_data = 0;
817 int private_segment_rotor = 0;
818 svm_region_t *vlib_rp;
819 f64 now;
Dave Barach371e4e12016-07-08 09:38:52 -0400820
821 vlib_set_queue_signal_callback (vm, memclnt_queue_callback);
822
823 if ((rv = memory_api_init (am->region_name)) < 0)
824 {
Dave Barach59b25652017-09-10 15:04:27 -0400825 clib_warning ("memory_api_init returned %d, quitting...", rv);
826 return 0;
827 }
828
829 if ((error = socksvr_api_init (vm)))
830 {
831 clib_error_report (error);
832 clib_warning ("socksvr_api_init failed, quitting...");
833 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700834 }
835
Dave Barach371e4e12016-07-08 09:38:52 -0400836 shm = am->shmem_hdr;
837 ASSERT (shm);
838 q = shm->vl_input_queue;
839 ASSERT (q);
Dave Barach7939f902017-10-04 10:03:52 -0400840 /* Make a note so we can always find the primary region easily */
841 am->vlib_primary_rp = am->vlib_rp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700842
Dave Barach371e4e12016-07-08 09:38:52 -0400843 e = vlib_call_init_exit_functions
844 (vm, vm->api_init_function_registrations, 1 /* call_once */ );
845 if (e)
846 clib_error_report (e);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847
Dave Barach59b25652017-09-10 15:04:27 -0400848 sleep_time = 10.0;
849 dead_client_scan_time = vlib_time_now (vm) + 10.0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700850
Dave Barach987e11d2017-02-27 13:10:27 -0500851 /*
852 * Send plugin message range messages for each plugin we loaded
853 */
854 for (i = 0; i < vec_len (am->msg_ranges); i++)
855 {
856 vl_api_msg_range_t *rp = am->msg_ranges + i;
857 send_one_plugin_msg_ids_msg (rp->name, rp->first_msg_id,
858 rp->last_msg_id);
859 }
860
Dave Barach49fe0462017-09-12 17:06:56 -0400861 /*
Dave Barach49fe0462017-09-12 17:06:56 -0400862 * Save the api message table snapshot, if configured
863 */
864 if (am->save_msg_table_filename)
865 {
866 int fd, rv;
867 u8 *chroot_file;
Dave Barach59b25652017-09-10 15:04:27 -0400868 u8 *serialized_message_table;
869
870 /*
871 * Snapshoot the api message table.
872 */
Dave Barach49fe0462017-09-12 17:06:56 -0400873 if (strstr ((char *) am->save_msg_table_filename, "..")
874 || index ((char *) am->save_msg_table_filename, '/'))
875 {
876 clib_warning ("illegal save-message-table filename '%s'",
877 am->save_msg_table_filename);
878 goto skip_save;
879 }
880
881 chroot_file = format (0, "/tmp/%s%c", am->save_msg_table_filename, 0);
882
883 fd = creat ((char *) chroot_file, 0644);
884
885 if (fd < 0)
886 {
887 clib_unix_warning ("creat");
888 goto skip_save;
889 }
Dave Barach59b25652017-09-10 15:04:27 -0400890
891 serialized_message_table = vl_api_serialize_message_table (am, 0);
892
Dave Barach49fe0462017-09-12 17:06:56 -0400893 rv = write (fd, serialized_message_table,
894 vec_len (serialized_message_table));
895
896 if (rv != vec_len (serialized_message_table))
897 clib_unix_warning ("write");
898
899 rv = close (fd);
900 if (rv < 0)
901 clib_unix_warning ("close");
902
903 vec_free (chroot_file);
Dave Barach59b25652017-09-10 15:04:27 -0400904 vec_free (serialized_message_table);
Dave Barach49fe0462017-09-12 17:06:56 -0400905 }
906
907skip_save:
Dave Barach49fe0462017-09-12 17:06:56 -0400908
Dave Barach371e4e12016-07-08 09:38:52 -0400909 /* $$$ pay attention to frame size, control CPU usage */
910 while (1)
911 {
Dave Barach371e4e12016-07-08 09:38:52 -0400912 i8 *headp;
913 int need_broadcast;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700914
Dave Barach371e4e12016-07-08 09:38:52 -0400915 /*
916 * There's a reason for checking the queue before
917 * sleeping. If the vlib application crashes, it's entirely
918 * possible for a client to enqueue a connect request
919 * during the process restart interval.
920 *
921 * Unless some force of physics causes the new incarnation
922 * of the application to process the request, the client will
923 * sit and wait for Godot...
924 */
925 vector_rate = vlib_last_vector_length_per_node (vm);
926 start_time = vlib_time_now (vm);
927 while (1)
928 {
929 pthread_mutex_lock (&q->mutex);
930 if (q->cursize == 0)
931 {
932 vm->api_queue_nonempty = 0;
933 pthread_mutex_unlock (&q->mutex);
934
935 if (TRACE_VLIB_MEMORY_QUEUE)
936 {
937 /* *INDENT-OFF* */
938 ELOG_TYPE_DECLARE (e) =
939 {
940 .format = "q-underflow: len %d",
941 .format_args = "i4",
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942 };
Dave Barach371e4e12016-07-08 09:38:52 -0400943 /* *INDENT-ON* */
944 struct
945 {
946 u32 len;
947 } *ed;
948 ed = ELOG_DATA (&vm->elog_main, e);
949 ed->len = 0;
950 }
951 sleep_time = 20.0;
952 break;
953 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700954
Dave Barach371e4e12016-07-08 09:38:52 -0400955 headp = (i8 *) (q->data + sizeof (uword) * q->head);
956 clib_memcpy (&mp, headp, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700957
Dave Barach371e4e12016-07-08 09:38:52 -0400958 q->head++;
959 need_broadcast = (q->cursize == q->maxsize / 2);
960 q->cursize--;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700961
Dave Barach371e4e12016-07-08 09:38:52 -0400962 if (PREDICT_FALSE (q->head == q->maxsize))
963 q->head = 0;
964 pthread_mutex_unlock (&q->mutex);
965 if (need_broadcast)
966 (void) pthread_cond_broadcast (&q->condvar);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700967
Dave Barach371e4e12016-07-08 09:38:52 -0400968 vl_msg_api_handler_with_vm_node (am, (void *) mp, vm, node);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700969
Dave Barach371e4e12016-07-08 09:38:52 -0400970 /* Allow no more than 10us without a pause */
971 if (vlib_time_now (vm) > start_time + 10e-6)
972 {
973 int index = SLEEP_400_US;
974 if (vector_rate > 40.0)
975 sleep_time = 400e-6;
976 else if (vector_rate > 20.0)
977 {
978 index = SLEEP_200_US;
979 sleep_time = 200e-6;
980 }
981 else if (vector_rate >= 1.0)
982 {
983 index = SLEEP_100_US;
984 sleep_time = 100e-6;
985 }
986 else
987 {
988 index = SLEEP_10_US;
989 sleep_time = 10e-6;
990 }
991 vector_rate_histogram[index] += 1;
992 break;
993 }
994 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700995
Dave Barach59b25652017-09-10 15:04:27 -0400996 /*
997 * see if we have any private api shared-memory segments
998 * If so, push required context variables, and process
999 * a message.
1000 */
1001 if (PREDICT_FALSE (vec_len (am->vlib_private_rps)))
Dave Barach371e4e12016-07-08 09:38:52 -04001002 {
Dave Barach59b25652017-09-10 15:04:27 -04001003 unix_shared_memory_queue_t *save_vlib_input_queue = q;
1004 vl_shmem_hdr_t *save_shmem_hdr = am->shmem_hdr;
1005 svm_region_t *save_vlib_rp = am->vlib_rp;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006
Dave Barach59b25652017-09-10 15:04:27 -04001007 vlib_rp = am->vlib_rp = am->vlib_private_rps[private_segment_rotor];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001008
Dave Barach59b25652017-09-10 15:04:27 -04001009 am->shmem_hdr = (void *) vlib_rp->user_ctx;
1010 q = am->shmem_hdr->vl_input_queue;
1011
1012 pthread_mutex_lock (&q->mutex);
1013 if (q->cursize > 0)
Dave Barach371e4e12016-07-08 09:38:52 -04001014 {
Dave Barach59b25652017-09-10 15:04:27 -04001015 headp = (i8 *) (q->data + sizeof (uword) * q->head);
1016 clib_memcpy (&mp, headp, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017
Dave Barach59b25652017-09-10 15:04:27 -04001018 q->head++;
1019 need_broadcast = (q->cursize == q->maxsize / 2);
1020 q->cursize--;
1021
1022 if (PREDICT_FALSE (q->head == q->maxsize))
1023 q->head = 0;
1024 pthread_mutex_unlock (&q->mutex);
1025 if (need_broadcast)
1026 (void) pthread_cond_broadcast (&q->condvar);
1027
1028 pthread_mutex_unlock (&q->mutex);
1029
1030 vl_msg_api_handler_with_vm_node (am, (void *) mp, vm, node);
1031 }
1032 else
1033 pthread_mutex_unlock (&q->mutex);
1034
1035 q = save_vlib_input_queue;
1036 am->shmem_hdr = save_shmem_hdr;
1037 am->vlib_rp = save_vlib_rp;
1038
1039 private_segment_rotor++;
1040 if (private_segment_rotor >= vec_len (am->vlib_private_rps))
1041 private_segment_rotor = 0;
1042 }
1043
1044 vlib_process_wait_for_event_or_clock (vm, sleep_time);
1045 vec_reset_length (event_data);
1046 event_type = vlib_process_get_events (vm, &event_data);
1047 now = vlib_time_now (vm);
1048
1049 switch (event_type)
1050 {
1051 case QUEUE_SIGNAL_EVENT:
1052 vm->queue_signal_pending = 0;
1053 break;
1054
1055 case SOCKET_READ_EVENT:
1056 for (i = 0; i < vec_len (event_data); i++)
Dave Barach371e4e12016-07-08 09:38:52 -04001057 {
Dave Barach59b25652017-09-10 15:04:27 -04001058 a = pool_elt_at_index (socket_main.process_args, event_data[i]);
1059 vl_api_socket_process_msg (a->clib_file, a->regp,
1060 (i8 *) a->data);
1061 vec_free (a->data);
1062 pool_put (socket_main.process_args, a);
Dave Barach371e4e12016-07-08 09:38:52 -04001063 }
Dave Barach59b25652017-09-10 15:04:27 -04001064 break;
Dave Barach371e4e12016-07-08 09:38:52 -04001065
Dave Barach59b25652017-09-10 15:04:27 -04001066 /* Timeout... */
1067 case -1:
1068 break;
1069
1070 default:
1071 clib_warning ("unknown event type %d", event_type);
1072 break;
1073 }
1074
1075 if (now > dead_client_scan_time)
1076 {
1077 dead_client_scan (am, shm, now);
1078 dead_client_scan_time = vlib_time_now (vm) + 10.0;
Dave Barach371e4e12016-07-08 09:38:52 -04001079 }
1080
1081 if (TRACE_VLIB_MEMORY_QUEUE)
1082 {
1083 /* *INDENT-OFF* */
1084 ELOG_TYPE_DECLARE (e) = {
1085 .format = "q-awake: len %d",
1086 .format_args = "i4",
1087 };
1088 /* *INDENT-ON* */
1089 struct
1090 {
1091 u32 len;
1092 } *ed;
1093 ed = ELOG_DATA (&vm->elog_main, e);
1094 ed->len = q->cursize;
1095 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096 }
1097
Dave Barach371e4e12016-07-08 09:38:52 -04001098 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001099}
Dave Barach49fe0462017-09-12 17:06:56 -04001100/* *INDENT-OFF* */
Dave Barach59b25652017-09-10 15:04:27 -04001101VLIB_REGISTER_NODE (memclnt_node) =
1102{
1103 .function = memclnt_process,
1104 .type = VLIB_NODE_TYPE_PROCESS,
1105 .name = "api-rx-from-ring",
1106 .state = VLIB_NODE_STATE_DISABLED,
Dave Barach49fe0462017-09-12 17:06:56 -04001107};
1108/* *INDENT-ON* */
1109
Ed Warnickecb9cada2015-12-08 15:45:58 -07001110
1111static clib_error_t *
Dave Barach371e4e12016-07-08 09:38:52 -04001112vl_api_show_histogram_command (vlib_main_t * vm,
1113 unformat_input_t * input,
1114 vlib_cli_command_t * cli_cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115{
Dave Barach371e4e12016-07-08 09:38:52 -04001116 u64 total_counts = 0;
1117 int i;
1118
1119 for (i = 0; i < SLEEP_N_BUCKETS; i++)
1120 {
1121 total_counts += vector_rate_histogram[i];
Ed Warnickecb9cada2015-12-08 15:45:58 -07001122 }
1123
Dave Barach371e4e12016-07-08 09:38:52 -04001124 if (total_counts == 0)
1125 {
1126 vlib_cli_output (vm, "No control-plane activity.");
1127 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001128 }
1129
1130#define _(n) \
1131 do { \
1132 f64 percent; \
1133 percent = ((f64) vector_rate_histogram[SLEEP_##n##_US]) \
1134 / (f64) total_counts; \
1135 percent *= 100.0; \
1136 vlib_cli_output (vm, "Sleep %3d us: %llu, %.2f%%",n, \
1137 vector_rate_histogram[SLEEP_##n##_US], \
1138 percent); \
1139 } while (0);
Dave Barach371e4e12016-07-08 09:38:52 -04001140 foreach_histogram_bucket;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001141#undef _
1142
Dave Barach371e4e12016-07-08 09:38:52 -04001143 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001144}
1145
Dave Barach49fe0462017-09-12 17:06:56 -04001146/*?
1147 * Display the binary api sleep-time histogram
1148?*/
Dave Barach371e4e12016-07-08 09:38:52 -04001149/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001150VLIB_CLI_COMMAND (cli_show_api_histogram_command, static) =
1151{
1152 .path = "show api histogram",
1153 .short_help = "show api histogram",
1154 .function = vl_api_show_histogram_command,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001155};
Dave Barach371e4e12016-07-08 09:38:52 -04001156/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001157
1158static clib_error_t *
Dave Barach371e4e12016-07-08 09:38:52 -04001159vl_api_clear_histogram_command (vlib_main_t * vm,
1160 unformat_input_t * input,
1161 vlib_cli_command_t * cli_cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001162{
Dave Barach371e4e12016-07-08 09:38:52 -04001163 int i;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001164
Dave Barach371e4e12016-07-08 09:38:52 -04001165 for (i = 0; i < SLEEP_N_BUCKETS; i++)
1166 vector_rate_histogram[i] = 0;
1167 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001168}
1169
Dave Barach49fe0462017-09-12 17:06:56 -04001170/*?
1171 * Clear the binary api sleep-time histogram
1172?*/
Dave Barach371e4e12016-07-08 09:38:52 -04001173/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001174VLIB_CLI_COMMAND (cli_clear_api_histogram_command, static) =
1175{
1176 .path = "clear api histogram",
1177 .short_help = "clear api histogram",
1178 .function = vl_api_clear_histogram_command,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001179};
Dave Barach371e4e12016-07-08 09:38:52 -04001180/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001181
Dave Barach59b25652017-09-10 15:04:27 -04001182volatile int **vl_api_queue_cursizes;
1183
Dave Barach371e4e12016-07-08 09:38:52 -04001184static void
1185memclnt_queue_callback (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001186{
Dave Barach59b25652017-09-10 15:04:27 -04001187 int i;
1188 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001189
Dave Barach59b25652017-09-10 15:04:27 -04001190 if (PREDICT_FALSE (vec_len (vl_api_queue_cursizes) !=
1191 1 + vec_len (am->vlib_private_rps)))
Dave Barach16c75df2016-05-31 14:05:46 -04001192 {
Dave Barach16c75df2016-05-31 14:05:46 -04001193 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
Dave Barach371e4e12016-07-08 09:38:52 -04001194 unix_shared_memory_queue_t *q;
1195
Dave Barach16c75df2016-05-31 14:05:46 -04001196 if (shmem_hdr == 0)
Dave Barach371e4e12016-07-08 09:38:52 -04001197 return;
1198
Dave Barach16c75df2016-05-31 14:05:46 -04001199 q = shmem_hdr->vl_input_queue;
1200 if (q == 0)
Dave Barach371e4e12016-07-08 09:38:52 -04001201 return;
Dave Barach59b25652017-09-10 15:04:27 -04001202
1203 vec_add1 (vl_api_queue_cursizes, &q->cursize);
1204
1205 for (i = 0; i < vec_len (am->vlib_private_rps); i++)
1206 {
1207 svm_region_t *vlib_rp = am->vlib_private_rps[i];
1208
1209 shmem_hdr = (void *) vlib_rp->user_ctx;
1210 q = shmem_hdr->vl_input_queue;
1211 vec_add1 (vl_api_queue_cursizes, &q->cursize);
1212 }
Dave Barach16c75df2016-05-31 14:05:46 -04001213 }
Dave Barach371e4e12016-07-08 09:38:52 -04001214
Dave Barach59b25652017-09-10 15:04:27 -04001215 for (i = 0; i < vec_len (vl_api_queue_cursizes); i++)
Dave Barach16c75df2016-05-31 14:05:46 -04001216 {
Dave Barach59b25652017-09-10 15:04:27 -04001217 if (*vl_api_queue_cursizes[i])
1218 {
1219 vm->queue_signal_pending = 1;
1220 vm->api_queue_nonempty = 1;
1221 vlib_process_signal_event (vm, memclnt_node.index,
1222 /* event_type */ QUEUE_SIGNAL_EVENT,
1223 /* event_data */ 0);
1224 break;
1225 }
Dave Barach16c75df2016-05-31 14:05:46 -04001226 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001227}
1228
Dave Barach371e4e12016-07-08 09:38:52 -04001229void
1230vl_enable_disable_memory_api (vlib_main_t * vm, int enable)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001231{
Dave Barach371e4e12016-07-08 09:38:52 -04001232 vlib_node_set_state (vm, memclnt_node.index,
1233 (enable
1234 ? VLIB_NODE_STATE_POLLING
1235 : VLIB_NODE_STATE_DISABLED));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001236}
1237
1238static uword
1239api_rx_from_node (vlib_main_t * vm,
Dave Barach371e4e12016-07-08 09:38:52 -04001240 vlib_node_runtime_t * node, vlib_frame_t * frame)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001241{
Dave Barach371e4e12016-07-08 09:38:52 -04001242 uword n_packets = frame->n_vectors;
1243 uword n_left_from;
1244 u32 *from;
1245 static u8 *long_msg;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001246
Dave Barach371e4e12016-07-08 09:38:52 -04001247 vec_validate (long_msg, 4095);
1248 n_left_from = frame->n_vectors;
1249 from = vlib_frame_args (frame);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001250
Dave Barach371e4e12016-07-08 09:38:52 -04001251 while (n_left_from > 0)
1252 {
1253 u32 bi0;
1254 vlib_buffer_t *b0;
1255 void *msg;
1256 uword msg_len;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001257
Dave Barach371e4e12016-07-08 09:38:52 -04001258 bi0 = from[0];
1259 b0 = vlib_get_buffer (vm, bi0);
1260 from += 1;
1261 n_left_from -= 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001262
Dave Barach371e4e12016-07-08 09:38:52 -04001263 msg = b0->data + b0->current_data;
1264 msg_len = b0->current_length;
1265 if (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
1266 {
1267 ASSERT (long_msg != 0);
1268 _vec_len (long_msg) = 0;
1269 vec_add (long_msg, msg, msg_len);
1270 while (b0->flags & VLIB_BUFFER_NEXT_PRESENT)
1271 {
1272 b0 = vlib_get_buffer (vm, b0->next_buffer);
1273 msg = b0->data + b0->current_data;
1274 msg_len = b0->current_length;
1275 vec_add (long_msg, msg, msg_len);
1276 }
1277 msg = long_msg;
1278 }
1279 vl_msg_api_handler_no_trace_no_free (msg);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001280 }
1281
Dave Barach371e4e12016-07-08 09:38:52 -04001282 /* Free what we've been given. */
1283 vlib_buffer_free (vm, vlib_frame_args (frame), n_packets);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001284
Dave Barach371e4e12016-07-08 09:38:52 -04001285 return n_packets;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001286}
1287
Dave Barach371e4e12016-07-08 09:38:52 -04001288/* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001289VLIB_REGISTER_NODE (api_rx_from_node_node,static) = {
1290 .function = api_rx_from_node,
1291 .type = VLIB_NODE_TYPE_INTERNAL,
1292 .vector_size = 4,
1293 .name = "api-rx-from-node",
1294};
Dave Barach371e4e12016-07-08 09:38:52 -04001295/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001296
1297static clib_error_t *
1298setup_memclnt_exit (vlib_main_t * vm)
1299{
Dave Barach371e4e12016-07-08 09:38:52 -04001300 atexit (vl_unmap_shmem);
1301 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001302}
1303
1304VLIB_INIT_FUNCTION (setup_memclnt_exit);
1305
Dave Barach59b25652017-09-10 15:04:27 -04001306u8 *
1307format_api_message_rings (u8 * s, va_list * args)
1308{
1309 api_main_t *am = va_arg (*args, api_main_t *);
1310 vl_shmem_hdr_t *shmem_hdr = va_arg (*args, vl_shmem_hdr_t *);
1311 int main_segment = va_arg (*args, int);
1312 ring_alloc_t *ap;
1313 int i;
1314
1315 if (shmem_hdr == 0)
1316 return format (s, "%8s %8s %8s %8s %8s\n",
1317 "Owner", "Size", "Nitems", "Hits", "Misses");
1318
1319 ap = shmem_hdr->vl_rings;
1320
1321 for (i = 0; i < vec_len (shmem_hdr->vl_rings); i++)
1322 {
1323 s = format (s, "%8s %8d %8d %8d %8d\n",
1324 "vlib", ap->size, ap->nitems, ap->hits, ap->misses);
1325 ap++;
1326 }
1327
1328 ap = shmem_hdr->client_rings;
1329
1330 for (i = 0; i < vec_len (shmem_hdr->client_rings); i++)
1331 {
1332 s = format (s, "%8s %8d %8d %8d %8d\n",
1333 "clnt", ap->size, ap->nitems, ap->hits, ap->misses);
1334 ap++;
1335 }
1336
1337 if (main_segment)
1338 {
1339 s = format (s, "%d ring miss fallback allocations\n", am->ring_misses);
1340 s = format
1341 (s,
1342 "%d application restarts, %d reclaimed msgs, %d garbage collects\n",
1343 shmem_hdr->application_restarts, shmem_hdr->restart_reclaims,
1344 shmem_hdr->garbage_collects);
1345 }
1346 return s;
1347}
1348
Ed Warnickecb9cada2015-12-08 15:45:58 -07001349
1350static clib_error_t *
Dave Barach371e4e12016-07-08 09:38:52 -04001351vl_api_ring_command (vlib_main_t * vm,
1352 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001353{
Dave Barach371e4e12016-07-08 09:38:52 -04001354 int i;
Dave Barach371e4e12016-07-08 09:38:52 -04001355 vl_shmem_hdr_t *shmem_hdr;
1356 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001357
Dave Barach7939f902017-10-04 10:03:52 -04001358 /* First, dump the primary region rings.. */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001359
Dave Barach7939f902017-10-04 10:03:52 -04001360 if (am->vlib_primary_rp == 0 || am->vlib_primary_rp->user_ctx == 0)
Dave Barach371e4e12016-07-08 09:38:52 -04001361 {
1362 vlib_cli_output (vm, "Shared memory segment not initialized...\n");
1363 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001364 }
1365
Dave Barach7939f902017-10-04 10:03:52 -04001366 shmem_hdr = (void *) am->vlib_primary_rp->user_ctx;
1367
Dave Barach59b25652017-09-10 15:04:27 -04001368 vlib_cli_output (vm, "Main API segment rings:");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001369
Dave Barach59b25652017-09-10 15:04:27 -04001370 vlib_cli_output (vm, "%U", format_api_message_rings, am,
1371 0 /* print header */ , 0 /* notused */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001372
Dave Barach59b25652017-09-10 15:04:27 -04001373 vlib_cli_output (vm, "%U", format_api_message_rings, am,
1374 shmem_hdr, 1 /* main segment */ );
1375
1376 for (i = 0; i < vec_len (am->vlib_private_rps); i++)
Dave Barach371e4e12016-07-08 09:38:52 -04001377 {
Dave Barach59b25652017-09-10 15:04:27 -04001378 svm_region_t *vlib_rp = am->vlib_private_rps[i];
1379 shmem_hdr = (void *) vlib_rp->user_ctx;
1380 vl_api_registration_t **regpp;
Dave Barach7939f902017-10-04 10:03:52 -04001381 vl_api_registration_t *regp = 0;
Dave Barach59b25652017-09-10 15:04:27 -04001382
1383 /* For horizontal scaling, add a hash table... */
1384 /* *INDENT-OFF* */
1385 pool_foreach (regpp, am->vl_clients,
1386 ({
1387 regp = *regpp;
1388 if (regp && regp->vlib_rp == vlib_rp)
1389 {
1390 vlib_cli_output (vm, "%s segment rings:", regp->name);
1391 goto found;
1392 }
1393 }));
Dave Barach7939f902017-10-04 10:03:52 -04001394 vlib_cli_output (vm, "regp %llx not found?", regp);
1395 continue;
Dave Barach59b25652017-09-10 15:04:27 -04001396 /* *INDENT-ON* */
1397 found:
1398 vlib_cli_output (vm, "%U", format_api_message_rings, am,
Dave Barach7939f902017-10-04 10:03:52 -04001399 0 /* print header */ , 0 /* notused */ );
1400 vlib_cli_output (vm, "%U", format_api_message_rings, am,
Dave Barach59b25652017-09-10 15:04:27 -04001401 shmem_hdr, 0 /* main segment */ );
Ed Warnickecb9cada2015-12-08 15:45:58 -07001402 }
1403
Dave Barach371e4e12016-07-08 09:38:52 -04001404 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001405}
1406
Dave Barach371e4e12016-07-08 09:38:52 -04001407void dump_socket_clients (vlib_main_t * vm, api_main_t * am)
1408 __attribute__ ((weak));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001409
Dave Barach371e4e12016-07-08 09:38:52 -04001410void
1411dump_socket_clients (vlib_main_t * vm, api_main_t * am)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001412{
1413}
1414
1415static clib_error_t *
Dave Barach371e4e12016-07-08 09:38:52 -04001416vl_api_client_command (vlib_main_t * vm,
1417 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001418{
Dave Barach371e4e12016-07-08 09:38:52 -04001419 vl_api_registration_t **regpp, *regp;
1420 unix_shared_memory_queue_t *q;
1421 char *health;
1422 api_main_t *am = &api_main;
1423 u32 *confused_indices = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001424
Dave Barach371e4e12016-07-08 09:38:52 -04001425 if (!pool_elts (am->vl_clients))
1426 goto socket_clients;
1427 vlib_cli_output (vm, "Shared memory clients");
1428 vlib_cli_output (vm, "%16s %8s %14s %18s %s",
1429 "Name", "PID", "Queue Length", "Queue VA", "Health");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001430
Dave Barach371e4e12016-07-08 09:38:52 -04001431 /* *INDENT-OFF* */
1432 pool_foreach (regpp, am->vl_clients,
1433 ({
1434 regp = *regpp;
1435
1436 if (regp)
1437 {
Dave Barach59b25652017-09-10 15:04:27 -04001438 if (regp->unanswered_pings > 0)
1439 health = "questionable";
Dave Barach371e4e12016-07-08 09:38:52 -04001440 else
Dave Barach59b25652017-09-10 15:04:27 -04001441 health = "OK";
1442
1443 q = regp->vl_input_queue;
1444
Dave Barach371e4e12016-07-08 09:38:52 -04001445 vlib_cli_output (vm, "%16s %8d %14d 0x%016llx %s\n",
1446 regp->name, q->consumer_pid, q->cursize,
1447 q, health);
1448 }
1449 else
1450 {
1451 clib_warning ("NULL client registration index %d",
1452 regpp - am->vl_clients);
1453 vec_add1 (confused_indices, regpp - am->vl_clients);
1454 }
1455 }));
1456 /* *INDENT-ON* */
1457
1458 /* This should "never happen," but if it does, fix it... */
1459 if (PREDICT_FALSE (vec_len (confused_indices) > 0))
1460 {
1461 int i;
1462 for (i = 0; i < vec_len (confused_indices); i++)
1463 {
1464 pool_put_index (am->vl_clients, confused_indices[i]);
1465 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001466 }
Dave Barach371e4e12016-07-08 09:38:52 -04001467 vec_free (confused_indices);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001468
Dave Barach371e4e12016-07-08 09:38:52 -04001469 if (am->missing_clients)
1470 vlib_cli_output (vm, "%u messages with missing clients",
1471 am->missing_clients);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001472socket_clients:
Dave Barach371e4e12016-07-08 09:38:52 -04001473 dump_socket_clients (vm, am);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001474
Dave Barach371e4e12016-07-08 09:38:52 -04001475 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001476}
1477
Calvin16649372016-07-28 13:52:05 -04001478static clib_error_t *
1479vl_api_status_command (vlib_main_t * vm,
1480 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
1481{
1482 api_main_t *am = &api_main;
1483
1484 // check if rx_trace and tx_trace are not null pointers
1485
1486 if (am->rx_trace == 0)
1487 {
1488 vlib_cli_output (vm, "RX Trace disabled\n");
1489 }
1490 else
1491 {
1492 if (am->rx_trace->enabled == 0)
1493 vlib_cli_output (vm, "RX Trace disabled\n");
1494 else
1495 vlib_cli_output (vm, "RX Trace enabled\n");
1496 }
1497
1498 if (am->tx_trace == 0)
1499 {
1500 vlib_cli_output (vm, "TX Trace disabled\n");
1501 }
1502 else
1503 {
1504 if (am->tx_trace->enabled == 0)
1505 vlib_cli_output (vm, "TX Trace disabled\n");
1506 else
1507 vlib_cli_output (vm, "TX Trace enabled\n");
1508 }
1509
1510 return 0;
1511}
1512
Dave Barach371e4e12016-07-08 09:38:52 -04001513/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001514VLIB_CLI_COMMAND (cli_show_api_command, static) =
1515{
1516 .path = "show api",
1517 .short_help = "Show API information",
Ed Warnickecb9cada2015-12-08 15:45:58 -07001518};
Dave Barach371e4e12016-07-08 09:38:52 -04001519/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001520
Dave Barach49fe0462017-09-12 17:06:56 -04001521/*?
1522 * Display binary api message allocation ring statistics
1523?*/
Dave Barach371e4e12016-07-08 09:38:52 -04001524/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001525VLIB_CLI_COMMAND (cli_show_api_ring_command, static) =
1526{
1527 .path = "show api ring-stats",
1528 .short_help = "Message ring statistics",
1529 .function = vl_api_ring_command,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001530};
Dave Barach371e4e12016-07-08 09:38:52 -04001531/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001532
Dave Barach49fe0462017-09-12 17:06:56 -04001533/*?
1534 * Display current api client connections
1535?*/
Dave Barach371e4e12016-07-08 09:38:52 -04001536/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001537VLIB_CLI_COMMAND (cli_show_api_clients_command, static) =
1538{
1539 .path = "show api clients",
1540 .short_help = "Client information",
1541 .function = vl_api_client_command,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001542};
Dave Barach371e4e12016-07-08 09:38:52 -04001543/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001544
Dave Barach49fe0462017-09-12 17:06:56 -04001545/*?
1546 * Display the current api message tracing status
1547?*/
Calvin16649372016-07-28 13:52:05 -04001548/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001549VLIB_CLI_COMMAND (cli_show_api_status_command, static) =
1550{
1551 .path = "show api trace-status",
1552 .short_help = "Display API trace status",
1553 .function = vl_api_status_command,
Calvin16649372016-07-28 13:52:05 -04001554};
1555/* *INDENT-ON* */
1556
Ed Warnickecb9cada2015-12-08 15:45:58 -07001557static clib_error_t *
Dave Barach371e4e12016-07-08 09:38:52 -04001558vl_api_message_table_command (vlib_main_t * vm,
1559 unformat_input_t * input,
1560 vlib_cli_command_t * cli_cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001561{
Dave Barach371e4e12016-07-08 09:38:52 -04001562 api_main_t *am = &api_main;
1563 int i;
1564 int verbose = 0;
1565
1566 if (unformat (input, "verbose"))
1567 verbose = 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001568
1569
Dave Barach371e4e12016-07-08 09:38:52 -04001570 if (verbose == 0)
1571 vlib_cli_output (vm, "%-4s %s", "ID", "Name");
1572 else
1573 vlib_cli_output (vm, "%-4s %-40s %6s %7s", "ID", "Name", "Bounce",
1574 "MP-safe");
Ed Warnickecb9cada2015-12-08 15:45:58 -07001575
Dave Barach371e4e12016-07-08 09:38:52 -04001576 for (i = 1; i < vec_len (am->msg_names); i++)
1577 {
1578 if (verbose == 0)
1579 {
1580 vlib_cli_output (vm, "%-4d %s", i,
1581 am->msg_names[i] ? am->msg_names[i] :
1582 " [no handler]");
1583 }
1584 else
1585 {
1586 vlib_cli_output (vm, "%-4d %-40s %6d %7d", i,
1587 am->msg_names[i] ? am->msg_names[i] :
1588 " [no handler]", am->message_bounce[i],
1589 am->is_mp_safe[i]);
1590 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001591 }
1592
Dave Barach371e4e12016-07-08 09:38:52 -04001593 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001594}
1595
Dave Barach49fe0462017-09-12 17:06:56 -04001596/*?
1597 * Display the current api message decode tables
1598?*/
Dave Barach371e4e12016-07-08 09:38:52 -04001599/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001600VLIB_CLI_COMMAND (cli_show_api_message_table_command, static) =
1601{
1602 .path = "show api message-table",
1603 .short_help = "Message Table",
1604 .function = vl_api_message_table_command,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001605};
Dave Barach371e4e12016-07-08 09:38:52 -04001606/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001607
Ed Warnickecb9cada2015-12-08 15:45:58 -07001608static clib_error_t *
Dave Barach371e4e12016-07-08 09:38:52 -04001609vl_api_trace_command (vlib_main_t * vm,
1610 unformat_input_t * input, vlib_cli_command_t * cli_cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001611{
Dave Barach371e4e12016-07-08 09:38:52 -04001612 u32 nitems = 1024;
1613 vl_api_trace_which_t which = VL_API_TRACE_RX;
Dave Barach371e4e12016-07-08 09:38:52 -04001614 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001615
Dave Barach371e4e12016-07-08 09:38:52 -04001616 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
1617 {
1618 if (unformat (input, "rx nitems %u", &nitems) || unformat (input, "rx"))
1619 goto configure;
1620 else if (unformat (input, "tx nitems %u", &nitems)
1621 || unformat (input, "tx"))
1622 {
1623 which = VL_API_TRACE_RX;
1624 goto configure;
1625 }
1626 else if (unformat (input, "on rx"))
1627 {
1628 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
1629 }
1630 else if (unformat (input, "on tx"))
1631 {
1632 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 1);
1633 }
1634 else if (unformat (input, "on"))
1635 {
1636 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 1);
1637 }
1638 else if (unformat (input, "off"))
1639 {
1640 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
1641 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
1642 }
1643 else if (unformat (input, "free"))
1644 {
1645 vl_msg_api_trace_onoff (am, VL_API_TRACE_RX, 0);
1646 vl_msg_api_trace_onoff (am, VL_API_TRACE_TX, 0);
1647 vl_msg_api_trace_free (am, VL_API_TRACE_RX);
1648 vl_msg_api_trace_free (am, VL_API_TRACE_TX);
1649 }
Dave Barach371e4e12016-07-08 09:38:52 -04001650 else if (unformat (input, "debug on"))
1651 {
1652 am->msg_print_flag = 1;
1653 }
1654 else if (unformat (input, "debug off"))
1655 {
1656 am->msg_print_flag = 0;
1657 }
1658 else
1659 return clib_error_return (0, "unknown input `%U'",
1660 format_unformat_error, input);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001661 }
Dave Barach371e4e12016-07-08 09:38:52 -04001662 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001663
Dave Barach371e4e12016-07-08 09:38:52 -04001664configure:
1665 if (vl_msg_api_trace_configure (am, which, nitems))
1666 {
1667 vlib_cli_output (vm, "warning: trace configure error (%d, %d)",
1668 which, nitems);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001669 }
1670
Dave Barach371e4e12016-07-08 09:38:52 -04001671 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001672}
1673
Dave Barach49fe0462017-09-12 17:06:56 -04001674/*?
1675 * Control the binary API trace mechanism
1676?*/
Dave Barach371e4e12016-07-08 09:38:52 -04001677/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001678VLIB_CLI_COMMAND (trace, static) =
1679{
1680 .path = "set api-trace [on][on tx][on rx][off][free][debug on][debug off]",
1681 .short_help = "API trace",
1682 .function = vl_api_trace_command,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001683};
Dave Barach371e4e12016-07-08 09:38:52 -04001684/* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001685
1686clib_error_t *
1687vlibmemory_init (vlib_main_t * vm)
1688{
Dave Barach309bef22016-01-22 16:09:52 -05001689 api_main_t *am = &api_main;
Dave Barachb3d93da2016-08-03 14:34:38 -04001690 svm_map_region_args_t _a, *a = &_a;
Dave Barach59b25652017-09-10 15:04:27 -04001691 clib_error_t *error;
Dave Barachc3799992016-08-15 11:12:27 -04001692
Dave Barachb3d93da2016-08-03 14:34:38 -04001693 memset (a, 0, sizeof (*a));
1694 a->root_path = am->root_path;
1695 a->name = SVM_GLOBAL_REGION_NAME;
Dave Barachc3799992016-08-15 11:12:27 -04001696 a->baseva = (am->global_baseva != 0) ?
Dave Barachb3d93da2016-08-03 14:34:38 -04001697 am->global_baseva : SVM_GLOBAL_REGION_BASEVA;
1698 a->size = (am->global_size != 0) ? am->global_size : SVM_GLOBAL_REGION_SIZE;
1699 a->flags = SVM_FLAGS_NODATA;
1700 a->uid = am->api_uid;
1701 a->gid = am->api_gid;
Dave Barachc3799992016-08-15 11:12:27 -04001702 a->pvt_heap_size =
1703 (am->global_pvt_heap_size !=
1704 0) ? am->global_pvt_heap_size : SVM_PVT_MHEAP_SIZE;
Dave Barachb3d93da2016-08-03 14:34:38 -04001705
1706 svm_region_init_args (a);
Dave Barach59b25652017-09-10 15:04:27 -04001707
1708 error = vlib_call_init_function (vm, vlibsocket_init);
1709
1710 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001711}
1712
1713VLIB_INIT_FUNCTION (vlibmemory_init);
1714
Dave Barach371e4e12016-07-08 09:38:52 -04001715void
Neale Rannse72be392017-04-26 13:59:20 -07001716vl_set_memory_region_name (const char *name)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001717{
Dave Barach371e4e12016-07-08 09:38:52 -04001718 api_main_t *am = &api_main;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001719
Dave Barach371e4e12016-07-08 09:38:52 -04001720 am->region_name = name;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001721}
1722
Dave Barach371e4e12016-07-08 09:38:52 -04001723static int
1724range_compare (vl_api_msg_range_t * a0, vl_api_msg_range_t * a1)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001725{
Dave Barach371e4e12016-07-08 09:38:52 -04001726 int len0, len1, clen;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001727
Dave Barach371e4e12016-07-08 09:38:52 -04001728 len0 = vec_len (a0->name);
1729 len1 = vec_len (a1->name);
1730 clen = len0 < len1 ? len0 : len1;
1731 return (strncmp ((char *) a0->name, (char *) a1->name, clen));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001732}
1733
Dave Barach371e4e12016-07-08 09:38:52 -04001734static u8 *
1735format_api_msg_range (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001736{
Dave Barach371e4e12016-07-08 09:38:52 -04001737 vl_api_msg_range_t *rp = va_arg (*args, vl_api_msg_range_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001738
Dave Barach371e4e12016-07-08 09:38:52 -04001739 if (rp == 0)
Dave Barach49fe0462017-09-12 17:06:56 -04001740 s = format (s, "%-50s%9s%9s", "Name", "First-ID", "Last-ID");
Dave Barach371e4e12016-07-08 09:38:52 -04001741 else
Dave Barach49fe0462017-09-12 17:06:56 -04001742 s = format (s, "%-50s%9d%9d", rp->name, rp->first_msg_id,
Dave Barach371e4e12016-07-08 09:38:52 -04001743 rp->last_msg_id);
1744
1745 return s;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001746}
1747
1748static clib_error_t *
Dave Barach371e4e12016-07-08 09:38:52 -04001749vl_api_show_plugin_command (vlib_main_t * vm,
1750 unformat_input_t * input,
1751 vlib_cli_command_t * cli_cmd)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001752{
Dave Barach371e4e12016-07-08 09:38:52 -04001753 api_main_t *am = &api_main;
1754 vl_api_msg_range_t *rp = 0;
1755 int i;
1756
1757 if (vec_len (am->msg_ranges) == 0)
1758 {
1759 vlib_cli_output (vm, "No plugin API message ranges configured...");
1760 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001761 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001762
Dave Barach371e4e12016-07-08 09:38:52 -04001763 rp = vec_dup (am->msg_ranges);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001764
Dave Barach371e4e12016-07-08 09:38:52 -04001765 vec_sort_with_function (rp, range_compare);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001766
Dave Barach371e4e12016-07-08 09:38:52 -04001767 vlib_cli_output (vm, "Plugin API message ID ranges...\n");
1768 vlib_cli_output (vm, "%U", format_api_msg_range, 0 /* header */ );
1769
1770 for (i = 0; i < vec_len (rp); i++)
1771 vlib_cli_output (vm, "%U", format_api_msg_range, rp + i);
1772
Dave Barachdfbee412017-03-02 18:24:10 -05001773 vec_free (rp);
1774
Dave Barach371e4e12016-07-08 09:38:52 -04001775 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001776}
1777
Dave Barach49fe0462017-09-12 17:06:56 -04001778/*?
1779 * Display the plugin binary API message range table
1780?*/
Dave Barach371e4e12016-07-08 09:38:52 -04001781/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04001782VLIB_CLI_COMMAND (cli_show_api_plugin_command, static) =
1783{
1784 .path = "show api plugin",
1785 .short_help = "show api plugin",
1786 .function = vl_api_show_plugin_command,
Ed Warnickecb9cada2015-12-08 15:45:58 -07001787};
Dave Barach371e4e12016-07-08 09:38:52 -04001788/* *INDENT-ON* */
Dave Barach4e281a42015-12-14 11:13:29 -05001789
Dave Barach371e4e12016-07-08 09:38:52 -04001790static void
1791vl_api_rpc_call_t_handler (vl_api_rpc_call_t * mp)
Dave Barach4e281a42015-12-14 11:13:29 -05001792{
Dave Barach11b8dbf2017-04-24 10:46:54 -04001793 vl_api_rpc_call_reply_t *rmp;
Dave Barach371e4e12016-07-08 09:38:52 -04001794 int (*fp) (void *);
Dave Barach4e281a42015-12-14 11:13:29 -05001795 i32 rv = 0;
Dave Barach371e4e12016-07-08 09:38:52 -04001796 vlib_main_t *vm = vlib_get_main ();
Dave Barach4e281a42015-12-14 11:13:29 -05001797
1798 if (mp->function == 0)
1799 {
1800 rv = -1;
1801 clib_warning ("rpc NULL function pointer");
1802 }
Dave Barach371e4e12016-07-08 09:38:52 -04001803
Dave Barach4e281a42015-12-14 11:13:29 -05001804 else
1805 {
1806 if (mp->need_barrier_sync)
Dave Barach371e4e12016-07-08 09:38:52 -04001807 vlib_worker_thread_barrier_sync (vm);
Dave Barach4e281a42015-12-14 11:13:29 -05001808
Dave Barach371e4e12016-07-08 09:38:52 -04001809 fp = uword_to_pointer (mp->function, int (*)(void *));
1810 rv = fp (mp->data);
Dave Barach4e281a42015-12-14 11:13:29 -05001811
1812 if (mp->need_barrier_sync)
Dave Barach371e4e12016-07-08 09:38:52 -04001813 vlib_worker_thread_barrier_release (vm);
Dave Barach4e281a42015-12-14 11:13:29 -05001814 }
1815
1816 if (mp->send_reply)
1817 {
Dave Barach371e4e12016-07-08 09:38:52 -04001818 unix_shared_memory_queue_t *q =
1819 vl_api_client_index_to_input_queue (mp->client_index);
Dave Barach4e281a42015-12-14 11:13:29 -05001820 if (q)
Dave Barach371e4e12016-07-08 09:38:52 -04001821 {
1822 rmp = vl_msg_api_alloc_as_if_client (sizeof (*rmp));
Dave Barach11b8dbf2017-04-24 10:46:54 -04001823 rmp->_vl_msg_id = ntohs (VL_API_RPC_CALL_REPLY);
Dave Barach371e4e12016-07-08 09:38:52 -04001824 rmp->context = mp->context;
1825 rmp->retval = rv;
1826 vl_msg_api_send_shmem (q, (u8 *) & rmp);
1827 }
Dave Barach4e281a42015-12-14 11:13:29 -05001828 }
1829 if (mp->multicast)
1830 {
1831 clib_warning ("multicast not yet implemented...");
1832 }
1833}
1834
Dave Barach371e4e12016-07-08 09:38:52 -04001835static void
Dave Barach11b8dbf2017-04-24 10:46:54 -04001836vl_api_rpc_call_reply_t_handler (vl_api_rpc_call_reply_t * mp)
Dave Barach4e281a42015-12-14 11:13:29 -05001837{
Dave Barach371e4e12016-07-08 09:38:52 -04001838 clib_warning ("unimplemented");
1839}
1840
John Lo7e9743a2017-09-23 08:59:58 -04001841always_inline void
1842vl_api_rpc_call_main_thread_inline (void *fp, u8 * data, u32 data_length,
1843 u8 force_rpc)
Dave Barach371e4e12016-07-08 09:38:52 -04001844{
1845 vl_api_rpc_call_t *mp;
Dave Barach4e281a42015-12-14 11:13:29 -05001846 api_main_t *am = &api_main;
1847 vl_shmem_hdr_t *shmem_hdr = am->shmem_hdr;
Dave Barache9183632016-10-04 16:53:56 -04001848 unix_shared_memory_queue_t *q;
Dave Barach4e281a42015-12-14 11:13:29 -05001849
Dave Barache9183632016-10-04 16:53:56 -04001850 /* Main thread: call the function directly */
John Lo7e9743a2017-09-23 08:59:58 -04001851 if ((force_rpc == 0) && (vlib_get_thread_index () == 0))
Dave Barache9183632016-10-04 16:53:56 -04001852 {
1853 vlib_main_t *vm = vlib_get_main ();
1854 void (*call_fp) (void *);
1855
1856 vlib_worker_thread_barrier_sync (vm);
1857
1858 call_fp = fp;
1859 call_fp (data);
1860
1861 vlib_worker_thread_barrier_release (vm);
1862 return;
1863 }
1864
1865 /* Any other thread, actually do an RPC call... */
Dave Barach4e281a42015-12-14 11:13:29 -05001866 mp = vl_msg_api_alloc_as_if_client (sizeof (*mp) + data_length);
Dave Barache9183632016-10-04 16:53:56 -04001867
Dave Barach4e281a42015-12-14 11:13:29 -05001868 memset (mp, 0, sizeof (*mp));
Damjan Marionf1213b82016-03-13 02:22:06 +01001869 clib_memcpy (mp->data, data, data_length);
Dave Barach4e281a42015-12-14 11:13:29 -05001870 mp->_vl_msg_id = ntohs (VL_API_RPC_CALL);
Dave Barach371e4e12016-07-08 09:38:52 -04001871 mp->function = pointer_to_uword (fp);
Dave Barach4e281a42015-12-14 11:13:29 -05001872 mp->need_barrier_sync = 1;
Dave Barach371e4e12016-07-08 09:38:52 -04001873
Dave Barache9183632016-10-04 16:53:56 -04001874 /*
1875 * Use the "normal" control-plane mechanism for the main thread.
1876 * Well, almost. if the main input queue is full, we cannot
1877 * block. Otherwise, we can expect a barrier sync timeout.
1878 */
1879 q = shmem_hdr->vl_input_queue;
1880
1881 while (pthread_mutex_trylock (&q->mutex))
1882 vlib_worker_thread_barrier_check ();
1883
1884 while (PREDICT_FALSE (unix_shared_memory_queue_is_full (q)))
1885 {
1886 pthread_mutex_unlock (&q->mutex);
1887 vlib_worker_thread_barrier_check ();
1888 while (pthread_mutex_trylock (&q->mutex))
1889 vlib_worker_thread_barrier_check ();
1890 }
1891
1892 vl_msg_api_send_shmem_nolock (q, (u8 *) & mp);
1893
1894 pthread_mutex_unlock (&q->mutex);
Dave Barach4e281a42015-12-14 11:13:29 -05001895}
1896
John Lo7e9743a2017-09-23 08:59:58 -04001897/*
1898 * Check if called from worker threads.
1899 * If so, make rpc call of fp through shmem.
1900 * Otherwise, call fp directly
1901 */
1902void
1903vl_api_rpc_call_main_thread (void *fp, u8 * data, u32 data_length)
1904{
1905 vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */
1906 0);
1907}
1908
1909/*
1910 * Always make rpc call of fp through shmem, useful for calling from threads
1911 * not setup as worker threads, such as DPDK callback thread
1912 */
1913void
1914vl_api_force_rpc_call_main_thread (void *fp, u8 * data, u32 data_length)
1915{
1916 vl_api_rpc_call_main_thread_inline (fp, data, data_length, /*force_rpc */
1917 1);
1918}
1919
Dave Barach987e11d2017-02-27 13:10:27 -05001920static void
1921vl_api_trace_plugin_msg_ids_t_handler (vl_api_trace_plugin_msg_ids_t * mp)
1922{
Dave Barachdfbee412017-03-02 18:24:10 -05001923 api_main_t *am = &api_main;
1924 vl_api_msg_range_t *rp;
1925 uword *p;
Dave Barach987e11d2017-02-27 13:10:27 -05001926
Dave Barachdfbee412017-03-02 18:24:10 -05001927 /* Noop (except for tracing) during normal operation */
1928 if (am->replay_in_progress == 0)
1929 return;
1930
1931 p = hash_get_mem (am->msg_range_by_name, mp->plugin_name);
1932 if (p == 0)
1933 {
1934 clib_warning ("WARNING: traced plugin '%s' not in current image",
1935 mp->plugin_name);
1936 return;
1937 }
1938
1939 rp = vec_elt_at_index (am->msg_ranges, p[0]);
1940 if (rp->first_msg_id != clib_net_to_host_u16 (mp->first_msg_id))
1941 {
1942 clib_warning ("WARNING: traced plugin '%s' first message id %d not %d",
1943 mp->plugin_name, clib_net_to_host_u16 (mp->first_msg_id),
1944 rp->first_msg_id);
1945 }
1946
1947 if (rp->last_msg_id != clib_net_to_host_u16 (mp->last_msg_id))
1948 {
1949 clib_warning ("WARNING: traced plugin '%s' last message id %d not %d",
1950 mp->plugin_name, clib_net_to_host_u16 (mp->last_msg_id),
1951 rp->last_msg_id);
1952 }
1953}
Dave Barach987e11d2017-02-27 13:10:27 -05001954
Dave Barach4e281a42015-12-14 11:13:29 -05001955#define foreach_rpc_api_msg \
1956_(RPC_CALL,rpc_call) \
Dave Barach11b8dbf2017-04-24 10:46:54 -04001957_(RPC_CALL_REPLY,rpc_call_reply)
Dave Barach4e281a42015-12-14 11:13:29 -05001958
Dave Barach987e11d2017-02-27 13:10:27 -05001959#define foreach_plugin_trace_msg \
1960_(TRACE_PLUGIN_MSG_IDS,trace_plugin_msg_ids)
1961
Dave Barach69128d02017-09-26 10:54:34 -04001962/*
1963 * Set the rpc callback at our earliest possible convenience.
1964 * This avoids ordering issues between thread_init() -> start_workers and
1965 * an init function which we could define here. If we ever intend to use
1966 * vlib all by itself, we can't create a link-time dependency on
1967 * an init function here and a typical "call foo_init first"
1968 * guitar lick.
1969 */
1970
1971extern void *rpc_call_main_thread_cb_fn;
1972
Dave Barach4e281a42015-12-14 11:13:29 -05001973static clib_error_t *
Dave Barach371e4e12016-07-08 09:38:52 -04001974rpc_api_hookup (vlib_main_t * vm)
Dave Barach4e281a42015-12-14 11:13:29 -05001975{
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001976 api_main_t *am = &api_main;
Dave Barach4e281a42015-12-14 11:13:29 -05001977#define _(N,n) \
1978 vl_msg_api_set_handlers(VL_API_##N, #n, \
1979 vl_api_##n##_t_handler, \
1980 vl_noop_handler, \
1981 vl_noop_handler, \
1982 vl_api_##n##_t_print, \
Dave Barach371e4e12016-07-08 09:38:52 -04001983 sizeof(vl_api_##n##_t), 0 /* do not trace */);
1984 foreach_rpc_api_msg;
Dave Barach4e281a42015-12-14 11:13:29 -05001985#undef _
Dave Barach987e11d2017-02-27 13:10:27 -05001986
1987#define _(N,n) \
1988 vl_msg_api_set_handlers(VL_API_##N, #n, \
1989 vl_api_##n##_t_handler, \
1990 vl_noop_handler, \
1991 vl_noop_handler, \
1992 vl_api_##n##_t_print, \
1993 sizeof(vl_api_##n##_t), 1 /* do trace */);
1994 foreach_plugin_trace_msg;
1995#undef _
Colin Tregenza Dancereb1ac172017-09-06 20:23:24 +01001996
1997 /* No reason to halt the parade to create a trace record... */
1998 am->is_mp_safe[VL_API_TRACE_PLUGIN_MSG_IDS] = 1;
Dave Barach69128d02017-09-26 10:54:34 -04001999 rpc_call_main_thread_cb_fn = vl_api_rpc_call_main_thread;
Dave Barach371e4e12016-07-08 09:38:52 -04002000 return 0;
Dave Barach4e281a42015-12-14 11:13:29 -05002001}
2002
Dave Barach371e4e12016-07-08 09:38:52 -04002003VLIB_API_INIT_FUNCTION (rpc_api_hookup);
2004
Dave Barach80f54e22017-03-08 19:08:56 -05002005typedef enum
2006{
2007 DUMP,
2008 CUSTOM_DUMP,
2009 REPLAY,
2010 INITIALIZERS,
2011} vl_api_replay_t;
2012
2013u8 *
2014format_vl_msg_api_trace_status (u8 * s, va_list * args)
2015{
2016 api_main_t *am = va_arg (*args, api_main_t *);
2017 vl_api_trace_which_t which = va_arg (*args, vl_api_trace_which_t);
2018 vl_api_trace_t *tp;
2019 char *trace_name;
2020
2021 switch (which)
2022 {
2023 case VL_API_TRACE_TX:
2024 tp = am->tx_trace;
2025 trace_name = "TX trace";
2026 break;
2027
2028 case VL_API_TRACE_RX:
2029 tp = am->rx_trace;
2030 trace_name = "RX trace";
2031 break;
2032
2033 default:
2034 abort ();
2035 }
2036
2037 if (tp == 0)
2038 {
2039 s = format (s, "%s: not yet configured.\n", trace_name);
2040 return s;
2041 }
2042
2043 s = format (s, "%s: used %d of %d items, %s enabled, %s wrapped\n",
2044 trace_name, vec_len (tp->traces), tp->nitems,
2045 tp->enabled ? "is" : "is not", tp->wrapped ? "has" : "has not");
2046 return s;
2047}
2048
2049void vl_msg_api_custom_dump_configure (api_main_t * am)
2050 __attribute__ ((weak));
2051void
2052vl_msg_api_custom_dump_configure (api_main_t * am)
2053{
2054}
2055
2056static void
2057vl_msg_api_process_file (vlib_main_t * vm, u8 * filename,
2058 u32 first_index, u32 last_index,
2059 vl_api_replay_t which)
2060{
2061 vl_api_trace_file_header_t *hp;
2062 int i, fd;
2063 struct stat statb;
2064 size_t file_size;
2065 u8 *msg;
2066 u8 endian_swap_needed = 0;
2067 api_main_t *am = &api_main;
2068 u8 *tmpbuf = 0;
2069 u32 nitems;
2070 void **saved_print_handlers = 0;
2071
2072 fd = open ((char *) filename, O_RDONLY);
2073
2074 if (fd < 0)
2075 {
2076 vlib_cli_output (vm, "Couldn't open %s\n", filename);
2077 return;
2078 }
2079
2080 if (fstat (fd, &statb) < 0)
2081 {
2082 vlib_cli_output (vm, "Couldn't stat %s\n", filename);
2083 close (fd);
2084 return;
2085 }
2086
2087 if (!(statb.st_mode & S_IFREG) || (statb.st_size < sizeof (*hp)))
2088 {
2089 vlib_cli_output (vm, "File not plausible: %s\n", filename);
2090 close (fd);
2091 return;
2092 }
2093
2094 file_size = statb.st_size;
2095 file_size = (file_size + 4095) & ~(4096);
2096
2097 hp = mmap (0, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
2098
2099 if (hp == (vl_api_trace_file_header_t *) MAP_FAILED)
2100 {
2101 vlib_cli_output (vm, "mmap failed: %s\n", filename);
2102 close (fd);
2103 return;
2104 }
2105 close (fd);
2106
2107 if ((clib_arch_is_little_endian && hp->endian == VL_API_BIG_ENDIAN)
2108 || (clib_arch_is_big_endian && hp->endian == VL_API_LITTLE_ENDIAN))
2109 endian_swap_needed = 1;
2110
2111 if (endian_swap_needed)
2112 nitems = ntohl (hp->nitems);
2113 else
2114 nitems = hp->nitems;
2115
2116 if (last_index == (u32) ~ 0)
2117 {
2118 last_index = nitems - 1;
2119 }
2120
2121 if (first_index >= nitems || last_index >= nitems)
2122 {
2123 vlib_cli_output (vm, "Range (%d, %d) outside file range (0, %d)\n",
2124 first_index, last_index, nitems - 1);
2125 munmap (hp, file_size);
2126 return;
2127 }
2128 if (hp->wrapped)
2129 vlib_cli_output (vm,
2130 "Note: wrapped/incomplete trace, results may vary\n");
2131
2132 if (which == CUSTOM_DUMP)
2133 {
2134 saved_print_handlers = (void **) vec_dup (am->msg_print_handlers);
2135 vl_msg_api_custom_dump_configure (am);
2136 }
2137
2138
2139 msg = (u8 *) (hp + 1);
2140
2141 for (i = 0; i < first_index; i++)
2142 {
2143 trace_cfg_t *cfgp;
2144 int size;
2145 u16 msg_id;
2146
2147 size = clib_host_to_net_u32 (*(u32 *) msg);
2148 msg += sizeof (u32);
2149
2150 if (clib_arch_is_little_endian)
2151 msg_id = ntohs (*((u16 *) msg));
2152 else
2153 msg_id = *((u16 *) msg);
2154
2155 cfgp = am->api_trace_cfg + msg_id;
2156 if (!cfgp)
2157 {
2158 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
2159 munmap (hp, file_size);
2160 return;
2161 }
2162 msg += size;
2163 }
2164
2165 if (which == REPLAY)
2166 am->replay_in_progress = 1;
2167
2168 for (; i <= last_index; i++)
2169 {
2170 trace_cfg_t *cfgp;
2171 u16 *msg_idp;
2172 u16 msg_id;
2173 int size;
2174
2175 if (which == DUMP)
2176 vlib_cli_output (vm, "---------- trace %d -----------\n", i);
2177
2178 size = clib_host_to_net_u32 (*(u32 *) msg);
2179 msg += sizeof (u32);
2180
2181 if (clib_arch_is_little_endian)
2182 msg_id = ntohs (*((u16 *) msg));
2183 else
2184 msg_id = *((u16 *) msg);
2185
2186 cfgp = am->api_trace_cfg + msg_id;
2187 if (!cfgp)
2188 {
2189 vlib_cli_output (vm, "Ugh: msg id %d no trace config\n", msg_id);
2190 munmap (hp, file_size);
2191 vec_free (tmpbuf);
2192 am->replay_in_progress = 0;
2193 return;
2194 }
2195
2196 /* Copy the buffer (from the read-only mmap'ed file) */
2197 vec_validate (tmpbuf, size - 1 + sizeof (uword));
2198 clib_memcpy (tmpbuf + sizeof (uword), msg, size);
2199 memset (tmpbuf, 0xf, sizeof (uword));
2200
2201 /*
2202 * Endian swap if needed. All msg data is supposed to be
2203 * in network byte order. All msg handlers are supposed to
2204 * know that. The generic message dumpers don't know that.
2205 * One could fix apigen, I suppose.
2206 */
2207 if ((which == DUMP && clib_arch_is_little_endian) || endian_swap_needed)
2208 {
2209 void (*endian_fp) (void *);
2210 if (msg_id >= vec_len (am->msg_endian_handlers)
2211 || (am->msg_endian_handlers[msg_id] == 0))
2212 {
2213 vlib_cli_output (vm, "Ugh: msg id %d no endian swap\n", msg_id);
2214 munmap (hp, file_size);
2215 vec_free (tmpbuf);
2216 am->replay_in_progress = 0;
2217 return;
2218 }
2219 endian_fp = am->msg_endian_handlers[msg_id];
2220 (*endian_fp) (tmpbuf + sizeof (uword));
2221 }
2222
2223 /* msg_id always in network byte order */
2224 if (clib_arch_is_little_endian)
2225 {
2226 msg_idp = (u16 *) (tmpbuf + sizeof (uword));
2227 *msg_idp = msg_id;
2228 }
2229
2230 switch (which)
2231 {
2232 case CUSTOM_DUMP:
2233 case DUMP:
2234 if (msg_id < vec_len (am->msg_print_handlers) &&
2235 am->msg_print_handlers[msg_id])
2236 {
2237 u8 *(*print_fp) (void *, void *);
2238
2239 print_fp = (void *) am->msg_print_handlers[msg_id];
2240 (*print_fp) (tmpbuf + sizeof (uword), vm);
2241 }
2242 else
2243 {
2244 vlib_cli_output (vm, "Skipping msg id %d: no print fcn\n",
2245 msg_id);
2246 break;
2247 }
2248 break;
2249
2250 case INITIALIZERS:
2251 if (msg_id < vec_len (am->msg_print_handlers) &&
2252 am->msg_print_handlers[msg_id])
2253 {
2254 u8 *s;
2255 int j;
2256 u8 *(*print_fp) (void *, void *);
2257
2258 print_fp = (void *) am->msg_print_handlers[msg_id];
2259
2260 vlib_cli_output (vm, "/*");
2261
2262 (*print_fp) (tmpbuf + sizeof (uword), vm);
2263 vlib_cli_output (vm, "*/\n");
2264
2265 s = format (0, "static u8 * vl_api_%s_%d[%d] = {",
2266 am->msg_names[msg_id], i,
2267 am->api_trace_cfg[msg_id].size);
2268
2269 for (j = 0; j < am->api_trace_cfg[msg_id].size; j++)
2270 {
2271 if ((j & 7) == 0)
2272 s = format (s, "\n ");
2273 s = format (s, "0x%02x,", tmpbuf[sizeof (uword) + j]);
2274 }
2275 s = format (s, "\n};\n%c", 0);
2276 vlib_cli_output (vm, (char *) s);
2277 vec_free (s);
2278 }
2279 break;
2280
2281 case REPLAY:
2282 if (msg_id < vec_len (am->msg_print_handlers) &&
2283 am->msg_print_handlers[msg_id] && cfgp->replay_enable)
2284 {
2285 void (*handler) (void *);
2286
2287 handler = (void *) am->msg_handlers[msg_id];
2288
2289 if (!am->is_mp_safe[msg_id])
2290 vl_msg_api_barrier_sync ();
2291 (*handler) (tmpbuf + sizeof (uword));
2292 if (!am->is_mp_safe[msg_id])
2293 vl_msg_api_barrier_release ();
2294 }
2295 else
2296 {
2297 if (cfgp->replay_enable)
2298 vlib_cli_output (vm, "Skipping msg id %d: no handler\n",
2299 msg_id);
2300 break;
2301 }
2302 break;
2303 }
2304
2305 _vec_len (tmpbuf) = 0;
2306 msg += size;
2307 }
2308
2309 if (saved_print_handlers)
2310 {
2311 clib_memcpy (am->msg_print_handlers, saved_print_handlers,
2312 vec_len (am->msg_print_handlers) * sizeof (void *));
2313 vec_free (saved_print_handlers);
2314 }
2315
2316 munmap (hp, file_size);
2317 vec_free (tmpbuf);
2318 am->replay_in_progress = 0;
2319}
2320
2321static clib_error_t *
2322api_trace_command_fn (vlib_main_t * vm,
2323 unformat_input_t * input, vlib_cli_command_t * cmd)
2324{
2325 u32 nitems = 256 << 10;
2326 api_main_t *am = &api_main;
2327 vl_api_trace_which_t which = VL_API_TRACE_RX;
2328 u8 *filename;
2329 u32 first = 0;
2330 u32 last = (u32) ~ 0;
2331 FILE *fp;
2332 int rv;
2333
2334 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2335 {
2336 if (unformat (input, "on") || unformat (input, "enable"))
2337 {
2338 if (unformat (input, "nitems %d", &nitems))
2339 ;
2340 vl_msg_api_trace_configure (am, which, nitems);
2341 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
2342 }
2343 else if (unformat (input, "off"))
2344 {
2345 vl_msg_api_trace_onoff (am, which, 0);
2346 }
2347 else if (unformat (input, "save %s", &filename))
2348 {
2349 u8 *chroot_filename;
2350 if (strstr ((char *) filename, "..")
2351 || index ((char *) filename, '/'))
2352 {
2353 vlib_cli_output (vm, "illegal characters in filename '%s'",
2354 filename);
2355 return 0;
2356 }
2357
2358 chroot_filename = format (0, "/tmp/%s%c", filename, 0);
2359
2360 vec_free (filename);
2361
2362 fp = fopen ((char *) chroot_filename, "w");
2363 if (fp == NULL)
2364 {
2365 vlib_cli_output (vm, "Couldn't create %s\n", chroot_filename);
2366 return 0;
2367 }
2368 rv = vl_msg_api_trace_save (am, which, fp);
2369 fclose (fp);
2370 if (rv == -1)
2371 vlib_cli_output (vm, "API Trace data not present\n");
2372 else if (rv == -2)
2373 vlib_cli_output (vm, "File for writing is closed\n");
2374 else if (rv == -10)
2375 vlib_cli_output (vm, "Error while writing header to file\n");
2376 else if (rv == -11)
2377 vlib_cli_output (vm, "Error while writing trace to file\n");
2378 else if (rv == -12)
2379 vlib_cli_output (vm,
2380 "Error while writing end of buffer trace to file\n");
2381 else if (rv == -13)
2382 vlib_cli_output (vm,
2383 "Error while writing start of buffer trace to file\n");
2384 else if (rv < 0)
2385 vlib_cli_output (vm, "Unkown error while saving: %d", rv);
2386 else
2387 vlib_cli_output (vm, "API trace saved to %s\n", chroot_filename);
2388 vec_free (chroot_filename);
2389 }
2390 else if (unformat (input, "dump %s", &filename))
2391 {
2392 vl_msg_api_process_file (vm, filename, first, last, DUMP);
2393 }
2394 else if (unformat (input, "custom-dump %s", &filename))
2395 {
2396 vl_msg_api_process_file (vm, filename, first, last, CUSTOM_DUMP);
2397 }
2398 else if (unformat (input, "replay %s", &filename))
2399 {
2400 vl_msg_api_process_file (vm, filename, first, last, REPLAY);
2401 }
2402 else if (unformat (input, "initializers %s", &filename))
2403 {
2404 vl_msg_api_process_file (vm, filename, first, last, INITIALIZERS);
2405 }
2406 else if (unformat (input, "tx"))
2407 {
2408 which = VL_API_TRACE_TX;
2409 }
2410 else if (unformat (input, "first %d", &first))
2411 {
2412 ;
2413 }
2414 else if (unformat (input, "last %d", &last))
2415 {
2416 ;
2417 }
2418 else if (unformat (input, "status"))
2419 {
2420 vlib_cli_output (vm, "%U", format_vl_msg_api_trace_status,
2421 am, which);
2422 }
2423 else if (unformat (input, "free"))
2424 {
2425 vl_msg_api_trace_onoff (am, which, 0);
2426 vl_msg_api_trace_free (am, which);
2427 }
2428 else if (unformat (input, "post-mortem-on"))
2429 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
2430 else if (unformat (input, "post-mortem-off"))
2431 vl_msg_api_post_mortem_dump_enable_disable (0 /* enable */ );
2432 else
2433 return clib_error_return (0, "unknown input `%U'",
2434 format_unformat_error, input);
2435 }
2436 return 0;
2437}
2438
Dave Barach49fe0462017-09-12 17:06:56 -04002439/*?
2440 * Display, replay, or save a binary API trace
2441?*/
2442
Dave Barach80f54e22017-03-08 19:08:56 -05002443/* *INDENT-OFF* */
Dave Barach49fe0462017-09-12 17:06:56 -04002444VLIB_CLI_COMMAND (api_trace_command, static) =
2445{
2446 .path = "api trace",
2447 .short_help =
2448 "api trace [on|off][dump|save|replay <file>][status][free][post-mortem-on]",
2449 .function = api_trace_command_fn,
Dave Barach80f54e22017-03-08 19:08:56 -05002450};
2451/* *INDENT-ON* */
2452
2453static clib_error_t *
2454api_config_fn (vlib_main_t * vm, unformat_input_t * input)
2455{
2456 u32 nitems = 256 << 10;
2457 vl_api_trace_which_t which = VL_API_TRACE_RX;
2458 api_main_t *am = &api_main;
2459
2460 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2461 {
2462 if (unformat (input, "on") || unformat (input, "enable"))
2463 {
2464 if (unformat (input, "nitems %d", &nitems))
2465 ;
2466 vl_msg_api_trace_configure (am, which, nitems);
2467 vl_msg_api_trace_onoff (am, which, 1 /* on */ );
2468 vl_msg_api_post_mortem_dump_enable_disable (1 /* enable */ );
2469 }
Dave Barach49fe0462017-09-12 17:06:56 -04002470 else if (unformat (input, "save-api-table %s",
2471 &am->save_msg_table_filename))
2472 ;
Dave Barach80f54e22017-03-08 19:08:56 -05002473 else
2474 return clib_error_return (0, "unknown input `%U'",
2475 format_unformat_error, input);
2476 }
2477 return 0;
2478}
2479
Dave Barach49fe0462017-09-12 17:06:56 -04002480/*?
2481 * This module has three configuration parameters:
2482 * "on" or "enable" - enables binary api tracing
2483 * "nitems <nnn>" - sets the size of the circular buffer to <nnn>
2484 * "save-api-table <filename>" - dumps the API message table to /tmp/<filename>
2485?*/
Dave Barach80f54e22017-03-08 19:08:56 -05002486VLIB_CONFIG_FUNCTION (api_config_fn, "api-trace");
2487
Dave Barach10d8cc62017-05-30 09:30:07 -04002488static clib_error_t *
2489api_queue_config_fn (vlib_main_t * vm, unformat_input_t * input)
2490{
2491 api_main_t *am = &api_main;
2492 u32 nitems;
2493
2494 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2495 {
2496 if (unformat (input, "length %d", &nitems) ||
2497 (unformat (input, "len %d", &nitems)))
2498 {
2499 if (nitems >= 1024)
2500 am->vlib_input_queue_length = nitems;
2501 else
2502 clib_warning ("vlib input queue length %d too small, ignored",
2503 nitems);
2504 }
2505 else
2506 return clib_error_return (0, "unknown input `%U'",
2507 format_unformat_error, input);
2508 }
2509 return 0;
2510}
2511
2512VLIB_CONFIG_FUNCTION (api_queue_config_fn, "api-queue");
2513
Dave Barach49fe0462017-09-12 17:06:56 -04002514static u8 *
2515extract_name (u8 * s)
2516{
2517 u8 *rv;
2518
2519 rv = vec_dup (s);
2520
2521 while (vec_len (rv) && rv[vec_len (rv)] != '_')
2522 _vec_len (rv)--;
2523
2524 rv[vec_len (rv)] = 0;
2525
2526 return rv;
2527}
2528
2529static u8 *
2530extract_crc (u8 * s)
2531{
2532 int i;
2533 u8 *rv;
2534
2535 rv = vec_dup (s);
2536
2537 for (i = vec_len (rv) - 1; i >= 0; i--)
2538 {
2539 if (rv[i] == '_')
2540 {
2541 vec_delete (rv, i + 1, 0);
2542 break;
2543 }
2544 }
2545 return rv;
2546}
2547
2548typedef struct
2549{
2550 u8 *name_and_crc;
2551 u8 *name;
2552 u8 *crc;
2553 u32 msg_index;
2554 int which;
2555} msg_table_unserialize_t;
2556
2557static int
2558table_id_cmp (void *a1, void *a2)
2559{
2560 msg_table_unserialize_t *n1 = a1;
2561 msg_table_unserialize_t *n2 = a2;
2562
2563 return (n1->msg_index - n2->msg_index);
2564}
2565
2566static int
2567table_name_and_crc_cmp (void *a1, void *a2)
2568{
2569 msg_table_unserialize_t *n1 = a1;
2570 msg_table_unserialize_t *n2 = a2;
2571
2572 return strcmp ((char *) n1->name_and_crc, (char *) n2->name_and_crc);
2573}
2574
2575static clib_error_t *
2576dump_api_table_file_command_fn (vlib_main_t * vm,
2577 unformat_input_t * input,
2578 vlib_cli_command_t * cmd)
2579{
2580 u8 *filename = 0;
2581 api_main_t *am = &api_main;
2582 serialize_main_t _sm, *sm = &_sm;
2583 clib_error_t *error;
2584 u32 nmsgs;
2585 u32 msg_index;
2586 u8 *name_and_crc;
2587 int compare_current = 0;
2588 int numeric_sort = 0;
2589 msg_table_unserialize_t *table = 0, *item;
2590 u32 i;
2591 u32 ndifferences = 0;
2592
2593 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
2594 {
2595 if (unformat (input, "file %s", &filename))
2596 ;
2597 else if (unformat (input, "compare-current")
2598 || unformat (input, "compare"))
2599 compare_current = 1;
2600 else if (unformat (input, "numeric"))
2601 numeric_sort = 1;
2602 else
2603 return clib_error_return (0, "unknown input `%U'",
2604 format_unformat_error, input);
2605 }
2606
2607 if (numeric_sort && compare_current)
2608 return clib_error_return
2609 (0, "Comparison and numeric sorting are incompatible");
2610
2611 if (filename == 0)
2612 return clib_error_return (0, "File not specified");
2613
2614 /* Load the serialized message table from the table dump */
2615
Dave Barach59b25652017-09-10 15:04:27 -04002616 error = unserialize_open_clib_file (sm, (char *) filename);
Dave Barach49fe0462017-09-12 17:06:56 -04002617
2618 if (error)
2619 return error;
2620
2621 unserialize_integer (sm, &nmsgs, sizeof (u32));
2622
2623 for (i = 0; i < nmsgs; i++)
2624 {
2625 msg_index = unserialize_likely_small_unsigned_integer (sm);
2626 unserialize_cstring (sm, (char **) &name_and_crc);
2627 vec_add2 (table, item, 1);
2628 item->msg_index = msg_index;
2629 item->name_and_crc = name_and_crc;
2630 item->name = extract_name (name_and_crc);
2631 item->crc = extract_crc (name_and_crc);
2632 item->which = 0; /* file */
2633 }
2634 serialize_close (sm);
2635
2636 /* Compare with the current image? */
2637 if (compare_current)
2638 {
2639 /* Append the current message table */
Dave Barach59b25652017-09-10 15:04:27 -04002640 u8 *tblv = vl_api_serialize_message_table (am, 0);
Dave Barach49fe0462017-09-12 17:06:56 -04002641
2642 serialize_open_vector (sm, tblv);
2643 unserialize_integer (sm, &nmsgs, sizeof (u32));
2644
2645 for (i = 0; i < nmsgs; i++)
2646 {
2647 msg_index = unserialize_likely_small_unsigned_integer (sm);
2648 unserialize_cstring (sm, (char **) &name_and_crc);
2649
2650 vec_add2 (table, item, 1);
2651 item->msg_index = msg_index;
2652 item->name_and_crc = name_and_crc;
2653 item->name = extract_name (name_and_crc);
2654 item->crc = extract_crc (name_and_crc);
2655 item->which = 1; /* current_image */
2656 }
Dave Barach59b25652017-09-10 15:04:27 -04002657 vec_free (tblv);
Dave Barach49fe0462017-09-12 17:06:56 -04002658 }
2659
2660 /* Sort the table. */
2661 if (numeric_sort)
2662 vec_sort_with_function (table, table_id_cmp);
2663 else
2664 vec_sort_with_function (table, table_name_and_crc_cmp);
2665
2666 if (compare_current)
2667 {
2668 ndifferences = 0;
2669
2670 /*
2671 * In this case, the recovered table will have two entries per
2672 * API message. So, if entries i and i+1 match, the message definitions
2673 * are identical. Otherwise, the crc is different, or a message is
2674 * present in only one of the tables.
2675 */
2676 vlib_cli_output (vm, "%=60s %s", "Message Name", "Result");
2677
2678 for (i = 0; i < vec_len (table);)
2679 {
2680 /* Last message lonely? */
2681 if (i == vec_len (table) - 1)
2682 {
2683 ndifferences++;
2684 goto last_unique;
2685 }
2686
2687 /* Identical pair? */
2688 if (!strncmp
2689 ((char *) table[i].name_and_crc,
2690 (char *) table[i + 1].name_and_crc,
2691 vec_len (table[i].name_and_crc)))
2692 {
2693 i += 2;
2694 continue;
2695 }
2696
2697 ndifferences++;
2698
2699 /* Only in one of two tables? */
2700 if (strncmp ((char *) table[i].name, (char *) table[i + 1].name,
2701 vec_len (table[i].name)))
2702 {
2703 last_unique:
2704 vlib_cli_output (vm, "%-60s only in %s",
2705 table[i].name, table[i].which ?
2706 "image" : "file");
2707 i++;
2708 continue;
2709 }
2710 /* In both tables, but with different signatures */
2711 vlib_cli_output (vm, "%-60s definition changed", table[i].name);
2712 i += 2;
2713 }
2714 if (ndifferences == 0)
2715 vlib_cli_output (vm, "No api message signature differences found.");
2716 else
2717 vlib_cli_output (vm, "Found %u api message signature differences",
2718 ndifferences);
2719 goto cleanup;
2720 }
2721
2722 /* Dump the table, sorted as shown above */
2723 vlib_cli_output (vm, "%=60s %=8s %=10s", "Message name", "MsgID", "CRC");
2724
2725 for (i = 0; i < vec_len (table); i++)
2726 {
2727 item = table + i;
2728 vlib_cli_output (vm, "%-60s %8u %10s", item->name,
2729 item->msg_index, item->crc);
2730 }
2731
2732cleanup:
2733 for (i = 0; i < vec_len (table); i++)
2734 {
2735 vec_free (table[i].name_and_crc);
2736 vec_free (table[i].name);
2737 vec_free (table[i].crc);
2738 }
2739
2740 vec_free (table);
2741
2742 return 0;
2743}
2744
2745/*?
2746 * Displays a serialized API message decode table, sorted by message name
2747 *
2748 * @cliexpar
2749 * @cliexstart{show api dump file <filename>}
2750 * Message name MsgID CRC
2751 * accept_session 407 8e2a127e
2752 * accept_session_reply 408 67d8c22a
2753 * add_node_next 549 e4202993
2754 * add_node_next_reply 550 e89d6eed
2755 * etc.
2756 * @cliexend
2757?*/
2758
2759/*?
2760 * Compares a serialized API message decode table with the current image
2761 *
2762 * @cliexpar
2763 * @cliexstart{show api dump file <filename> compare}
2764 * ip_add_del_route definition changed
2765 * ip_table_add_del definition changed
2766 * l2_macs_event only in image
2767 * vnet_ip4_fib_counters only in file
2768 * vnet_ip4_nbr_counters only in file
2769 * @cliexend
2770?*/
2771
2772/*?
Dave Barach905c14a2017-09-25 08:47:59 -04002773 * Display a serialized API message decode table, compare a saved
2774 * decode table with the current image, to establish API differences.
2775 *
Dave Barach49fe0462017-09-12 17:06:56 -04002776?*/
2777/* *INDENT-OFF* */
2778VLIB_CLI_COMMAND (dump_api_table_file, static) =
2779{
2780 .path = "show api dump",
2781 .short_help = "show api dump file <filename> [numeric | compare-current]",
2782 .function = dump_api_table_file_command_fn,
2783};
2784/* *INDENT-ON* */
2785
Dave Barach371e4e12016-07-08 09:38:52 -04002786/*
2787 * fd.io coding-style-patch-verification: ON
2788 *
2789 * Local Variables:
2790 * eval: (c-set-style "gnu")
2791 * End:
2792 */