String type: Fix off by one error
[vpp.git] / src / vpp / api / api.c
1 /*
2  *------------------------------------------------------------------
3  * api.c - message handler registration
4  *
5  * Copyright (c) 2010-2018 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 <sys/types.h>
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <netinet/in.h>
27 #include <signal.h>
28 #include <pthread.h>
29 #include <unistd.h>
30 #include <time.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <pwd.h>
34 #include <grp.h>
35
36 #include <vppinfra/clib.h>
37 #include <vppinfra/vec.h>
38 #include <vppinfra/hash.h>
39 #include <vppinfra/bitmap.h>
40 #include <vppinfra/fifo.h>
41 #include <vppinfra/time.h>
42 #include <vppinfra/mheap.h>
43 #include <vppinfra/heap.h>
44 #include <vppinfra/pool.h>
45 #include <vppinfra/format.h>
46 #include <vppinfra/error.h>
47
48 #include <vnet/api_errno.h>
49 #include <vnet/vnet.h>
50
51 #include <vlib/vlib.h>
52 #include <vlib/unix/unix.h>
53 #include <vlibapi/api.h>
54 #include <vlibmemory/api.h>
55
56 #undef BIHASH_TYPE
57 #undef __included_bihash_template_h__
58
59 #include <vnet/ip/format.h>
60
61 #include <vpp/api/vpe_msg_enum.h>
62
63 #define vl_typedefs             /* define message structures */
64 #include <vpp/api/vpe_all_api_h.h>
65 #undef vl_typedefs
66 #define vl_endianfun            /* define message structures */
67 #include <vpp/api/vpe_all_api_h.h>
68 #undef vl_endianfun
69 /* instantiate all the print functions we know about */
70 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
71 #define vl_printfun
72 #include <vpp/api/vpe_all_api_h.h>
73 #undef vl_printfun
74 #include <vlibapi/api_helper_macros.h>
75
76 #define foreach_vpe_api_msg                                             \
77 _(CONTROL_PING, control_ping)                                           \
78 _(CLI, cli)                                                             \
79 _(CLI_INBAND, cli_inband)                                               \
80 _(GET_NODE_INDEX, get_node_index)                                       \
81 _(ADD_NODE_NEXT, add_node_next)                                         \
82 _(SHOW_VERSION, show_version)                                           \
83 _(SHOW_THREADS, show_threads)                                           \
84 _(GET_NODE_GRAPH, get_node_graph)                                       \
85 _(GET_NEXT_INDEX, get_next_index)                                       \
86
87 #define QUOTE_(x) #x
88 #define QUOTE(x) QUOTE_(x)
89
90 typedef enum
91 {
92   RESOLVE_IP4_ADD_DEL_ROUTE = 1,
93   RESOLVE_IP6_ADD_DEL_ROUTE,
94 } resolve_t;
95
96 extern vpe_api_main_t vpe_api_main;
97
98 /* Clean up all registrations belonging to the indicated client */
99 static clib_error_t *
100 memclnt_delete_callback (u32 client_index)
101 {
102   vpe_api_main_t *vam = &vpe_api_main;
103   vpe_client_registration_t *rp;
104   uword *p;
105   int stats_memclnt_delete_callback (u32 client_index);
106
107   stats_memclnt_delete_callback (client_index);
108
109 #define _(a)                                                    \
110     p = hash_get (vam->a##_registration_hash, client_index);    \
111     if (p) {                                                    \
112         rp = pool_elt_at_index (vam->a##_registrations, p[0]);  \
113         pool_put (vam->a##_registrations, rp);                  \
114         hash_unset (vam->a##_registration_hash, client_index);  \
115     }
116   foreach_registration_hash;
117 #undef _
118   return 0;
119 }
120
121 VL_MSG_API_REAPER_FUNCTION (memclnt_delete_callback);
122
123 static void
124 vl_api_control_ping_t_handler (vl_api_control_ping_t * mp)
125 {
126   vl_api_control_ping_reply_t *rmp;
127   int rv = 0;
128
129   /* *INDENT-OFF* */
130   REPLY_MACRO2(VL_API_CONTROL_PING_REPLY,
131   ({
132     rmp->vpe_pid = ntohl (getpid());
133   }));
134   /* *INDENT-ON* */
135 }
136
137 static void
138 shmem_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
139 {
140   u8 **shmem_vecp = (u8 **) arg;
141   u8 *shmem_vec;
142   void *oldheap;
143   api_main_t *am = &api_main;
144   u32 offset;
145
146   shmem_vec = *shmem_vecp;
147
148   offset = vec_len (shmem_vec);
149
150   pthread_mutex_lock (&am->vlib_rp->mutex);
151   oldheap = svm_push_data_heap (am->vlib_rp);
152
153   vec_validate (shmem_vec, offset + buffer_bytes - 1);
154
155   clib_memcpy (shmem_vec + offset, buffer, buffer_bytes);
156
157   svm_pop_heap (oldheap);
158   pthread_mutex_unlock (&am->vlib_rp->mutex);
159
160   *shmem_vecp = shmem_vec;
161 }
162
163
164 static void
165 vl_api_cli_t_handler (vl_api_cli_t * mp)
166 {
167   vl_api_cli_reply_t *rp;
168   vl_api_registration_t *reg;
169   vlib_main_t *vm = vlib_get_main ();
170   api_main_t *am = &api_main;
171   unformat_input_t input;
172   u8 *shmem_vec = 0;
173   void *oldheap;
174
175   reg = vl_api_client_index_to_registration (mp->client_index);
176   if (!reg)
177     return;;
178
179   rp = vl_msg_api_alloc (sizeof (*rp));
180   rp->_vl_msg_id = ntohs (VL_API_CLI_REPLY);
181   rp->context = mp->context;
182
183   unformat_init_vector (&input, (u8 *) (uword) mp->cmd_in_shmem);
184
185   vlib_cli_input (vm, &input, shmem_cli_output, (uword) & shmem_vec);
186
187   pthread_mutex_lock (&am->vlib_rp->mutex);
188   oldheap = svm_push_data_heap (am->vlib_rp);
189
190   vec_add1 (shmem_vec, 0);
191
192   svm_pop_heap (oldheap);
193   pthread_mutex_unlock (&am->vlib_rp->mutex);
194
195   rp->reply_in_shmem = (uword) shmem_vec;
196
197   vl_api_send_msg (reg, (u8 *) rp);
198 }
199
200 static void
201 inband_cli_output (uword arg, u8 * buffer, uword buffer_bytes)
202 {
203   u8 **mem_vecp = (u8 **) arg;
204   u8 *mem_vec = *mem_vecp;
205   u32 offset = vec_len (mem_vec);
206
207   vec_validate (mem_vec, offset + buffer_bytes - 1);
208   clib_memcpy (mem_vec + offset, buffer, buffer_bytes);
209   *mem_vecp = mem_vec;
210 }
211
212 static void
213 vl_api_cli_inband_t_handler (vl_api_cli_inband_t * mp)
214 {
215   vl_api_cli_inband_reply_t *rmp;
216   int rv = 0;
217   vlib_main_t *vm = vlib_get_main ();
218   unformat_input_t input;
219   u8 *out_vec = 0;
220   u32 len = 0;
221
222   if (vl_msg_api_get_msg_length (mp) <
223       vl_api_string_len (&mp->cmd) + sizeof (*mp))
224     {
225       rv = -1;
226       goto error;
227     }
228
229   unformat_init_string (&input, (char *) vl_api_from_api_string (&mp->cmd),
230                         vl_api_string_len (&mp->cmd));
231   vlib_cli_input (vm, &input, inband_cli_output, (uword) & out_vec);
232
233   len = vec_len (out_vec);
234
235 error:
236   /* *INDENT-OFF* */
237   REPLY_MACRO3(VL_API_CLI_INBAND_REPLY, len,
238   ({
239     vl_api_to_api_string(len, (const char *)out_vec, &rmp->reply);
240   }));
241   /* *INDENT-ON* */
242   vec_free (out_vec);
243 }
244
245 static void
246 vl_api_show_version_t_handler (vl_api_show_version_t * mp)
247 {
248   vl_api_show_version_reply_t *rmp;
249   int rv = 0;
250   char *vpe_api_get_build_directory (void);
251   char *vpe_api_get_version (void);
252   char *vpe_api_get_build_date (void);
253
254   u32 program_len = strnlen_s ("vpe", 32) + 1;
255   u32 version_len = strnlen_s (vpe_api_get_version (), 32) + 1;
256   u32 build_date_len = strnlen_s (vpe_api_get_build_date (), 32) + 1;
257   u32 build_directory_len =
258     strnlen_s (vpe_api_get_build_directory (), 256) + 1;
259
260   u32 n = program_len + version_len + build_date_len + build_directory_len;
261
262   /* *INDENT-OFF* */
263   REPLY_MACRO3(VL_API_SHOW_VERSION_REPLY, n,
264   ({
265     char *p = (char *)&rmp->program;
266     p += vl_api_to_api_string(program_len, "vpe", (vl_api_string_t *)p);
267     p += vl_api_to_api_string(version_len, vpe_api_get_version(), (vl_api_string_t *)p);
268     p += vl_api_to_api_string(build_date_len, vpe_api_get_build_date(), (vl_api_string_t *)p);
269     vl_api_to_api_string(build_directory_len, vpe_api_get_build_directory(), (vl_api_string_t *)p);
270   }));
271   /* *INDENT-ON* */
272 }
273
274 static void
275 get_thread_data (vl_api_thread_data_t * td, int index)
276 {
277   vlib_worker_thread_t *w = vlib_worker_threads + index;
278   td->id = htonl (index);
279   if (w->name)
280     strncpy ((char *) td->name, (char *) w->name, ARRAY_LEN (td->name) - 1);
281   if (w->registration)
282     strncpy ((char *) td->type, (char *) w->registration->name,
283              ARRAY_LEN (td->type) - 1);
284   td->pid = htonl (w->lwp);
285   td->cpu_id = htonl (w->cpu_id);
286   td->core = htonl (w->core_id);
287   td->cpu_socket = htonl (w->socket_id);
288 }
289
290 static void
291 vl_api_show_threads_t_handler (vl_api_show_threads_t * mp)
292 {
293   vlib_main_t *vm = vlib_get_main ();
294   int rv = 0, count = 0;
295
296 #if !defined(__powerpc64__)
297   vl_api_registration_t *reg;
298   vl_api_show_threads_reply_t *rmp;
299   vl_api_thread_data_t *td;
300   int i, msg_size = 0;
301   count = vec_len (vlib_worker_threads);
302   if (!count)
303     return;
304
305   msg_size = sizeof (*rmp) + sizeof (rmp->thread_data[0]) * count;
306   reg = vl_api_client_index_to_registration (mp->client_index);
307   if (!reg)
308     return;
309
310   rmp = vl_msg_api_alloc (msg_size);
311   clib_memset (rmp, 0, msg_size);
312   rmp->_vl_msg_id = htons (VL_API_SHOW_THREADS_REPLY);
313   rmp->context = mp->context;
314   rmp->count = htonl (count);
315   td = rmp->thread_data;
316
317   for (i = 0; i < count; i++)
318     {
319       get_thread_data (&td[i], i);
320     }
321
322   vl_api_send_msg (reg, (u8 *) rmp);
323 #else
324
325   /* unimplemented support */
326   rv = -9;
327   clib_warning ("power pc does not support show threads api");
328   /* *INDENT-OFF* */
329   REPLY_MACRO2(VL_API_SHOW_THREADS_REPLY,
330   ({
331     rmp->count = htonl(count);
332   }));
333   /* *INDENT-ON* */
334 #endif
335 }
336
337 static void
338 vl_api_get_node_index_t_handler (vl_api_get_node_index_t * mp)
339 {
340   vlib_main_t *vm = vlib_get_main ();
341   vl_api_get_node_index_reply_t *rmp;
342   vlib_node_t *n;
343   int rv = 0;
344   u32 node_index = ~0;
345
346   n = vlib_get_node_by_name (vm, mp->node_name);
347
348   if (n == 0)
349     rv = VNET_API_ERROR_NO_SUCH_NODE;
350   else
351     node_index = n->index;
352
353   /* *INDENT-OFF* */
354   REPLY_MACRO2(VL_API_GET_NODE_INDEX_REPLY,
355   ({
356     rmp->node_index = ntohl(node_index);
357   }));
358   /* *INDENT-ON* */
359 }
360
361 static void
362 vl_api_get_next_index_t_handler (vl_api_get_next_index_t * mp)
363 {
364   vlib_main_t *vm = vlib_get_main ();
365   vl_api_get_next_index_reply_t *rmp;
366   vlib_node_t *node, *next_node;
367   int rv = 0;
368   u32 next_node_index = ~0, next_index = ~0;
369   uword *p;
370
371   node = vlib_get_node_by_name (vm, mp->node_name);
372
373   if (node == 0)
374     {
375       rv = VNET_API_ERROR_NO_SUCH_NODE;
376       goto out;
377     }
378
379   next_node = vlib_get_node_by_name (vm, mp->next_name);
380
381   if (next_node == 0)
382     {
383       rv = VNET_API_ERROR_NO_SUCH_NODE2;
384       goto out;
385     }
386   else
387     next_node_index = next_node->index;
388
389   p = hash_get (node->next_slot_by_node, next_node_index);
390
391   if (p == 0)
392     {
393       rv = VNET_API_ERROR_NO_SUCH_ENTRY;
394       goto out;
395     }
396   else
397     next_index = p[0];
398
399 out:
400   /* *INDENT-OFF* */
401   REPLY_MACRO2(VL_API_GET_NEXT_INDEX_REPLY,
402   ({
403     rmp->next_index = ntohl(next_index);
404   }));
405   /* *INDENT-ON* */
406 }
407
408 static void
409 vl_api_add_node_next_t_handler (vl_api_add_node_next_t * mp)
410 {
411   vlib_main_t *vm = vlib_get_main ();
412   vl_api_add_node_next_reply_t *rmp;
413   vlib_node_t *n, *next;
414   int rv = 0;
415   u32 next_index = ~0;
416
417   n = vlib_get_node_by_name (vm, mp->node_name);
418
419   if (n == 0)
420     {
421       rv = VNET_API_ERROR_NO_SUCH_NODE;
422       goto out;
423     }
424
425   next = vlib_get_node_by_name (vm, mp->next_name);
426
427   if (next == 0)
428     rv = VNET_API_ERROR_NO_SUCH_NODE2;
429   else
430     next_index = vlib_node_add_next (vm, n->index, next->index);
431
432 out:
433   /* *INDENT-OFF* */
434   REPLY_MACRO2(VL_API_GET_NODE_INDEX_REPLY,
435   ({
436     rmp->next_index = ntohl(next_index);
437   }));
438   /* *INDENT-ON* */
439 }
440
441 static void
442 vl_api_get_node_graph_t_handler (vl_api_get_node_graph_t * mp)
443 {
444   int rv = 0;
445   u8 *vector = 0;
446   api_main_t *am = &api_main;
447   vlib_main_t *vm = vlib_get_main ();
448   void *oldheap;
449   vl_api_get_node_graph_reply_t *rmp;
450   static vlib_node_t ***node_dups;
451   static vlib_main_t **stat_vms;
452
453   pthread_mutex_lock (&am->vlib_rp->mutex);
454   oldheap = svm_push_data_heap (am->vlib_rp);
455
456   /*
457    * Keep the number of memcpy ops to a minimum (e.g. 1).
458    */
459   vec_validate (vector, 16384);
460   vec_reset_length (vector);
461
462   vlib_node_get_nodes (vm, 0 /* main threads */ ,
463                        0 /* include stats */ ,
464                        1 /* barrier sync */ ,
465                        &node_dups, &stat_vms);
466   vector = vlib_node_serialize (vm, node_dups, vector, 1 /* include nexts */ ,
467                                 1 /* include stats */ );
468
469   svm_pop_heap (oldheap);
470   pthread_mutex_unlock (&am->vlib_rp->mutex);
471
472   /* *INDENT-OFF* */
473   REPLY_MACRO2(VL_API_GET_NODE_GRAPH_REPLY,
474   ({
475     rmp->reply_in_shmem = (uword) vector;
476   }));
477   /* *INDENT-ON* */
478 }
479
480 #define BOUNCE_HANDLER(nn)                                              \
481 static void vl_api_##nn##_t_handler (                                   \
482     vl_api_##nn##_t *mp)                                                \
483 {                                                                       \
484     vpe_client_registration_t *reg;                                     \
485     vpe_api_main_t * vam = &vpe_api_main;                               \
486     svm_queue_t * q;                                     \
487                                                                         \
488     /* One registration only... */                                      \
489     pool_foreach(reg, vam->nn##_registrations,                          \
490     ({                                                                  \
491         q = vl_api_client_index_to_input_queue (reg->client_index);     \
492         if (q) {                                                        \
493             /*                                                          \
494              * If the queue is stuffed, turf the msg and complain       \
495              * It's unlikely that the intended recipient is             \
496              * alive; avoid deadlock at all costs.                      \
497              */                                                         \
498             if (q->cursize == q->maxsize) {                             \
499                 clib_warning ("ERROR: receiver queue full, drop msg");  \
500                 vl_msg_api_free (mp);                                   \
501                 return;                                                 \
502             }                                                           \
503             vl_msg_api_send_shmem (q, (u8 *)&mp);                       \
504             return;                                                     \
505         }                                                               \
506     }));                                                                \
507     vl_msg_api_free (mp);                                               \
508 }
509
510 static void setup_message_id_table (api_main_t * am);
511
512 /*
513  * vpe_api_hookup
514  * Add vpe's API message handlers to the table.
515  * vlib has already mapped shared memory and
516  * added the client registration handlers.
517  * See .../open-repo/vlib/memclnt_vlib.c:memclnt_process()
518  */
519 static clib_error_t *
520 vpe_api_hookup (vlib_main_t * vm)
521 {
522   api_main_t *am = &api_main;
523
524 #define _(N,n)                                                  \
525     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
526                            vl_api_##n##_t_handler,              \
527                            vl_noop_handler,                     \
528                            vl_api_##n##_t_endian,               \
529                            vl_api_##n##_t_print,                \
530                            sizeof(vl_api_##n##_t), 1);
531   foreach_vpe_api_msg;
532 #undef _
533
534   /*
535    * Trace space for classifier mask+match
536    */
537   am->api_trace_cfg[VL_API_CLASSIFY_ADD_DEL_TABLE].size += 5 * sizeof (u32x4);
538   am->api_trace_cfg[VL_API_CLASSIFY_ADD_DEL_SESSION].size
539     += 5 * sizeof (u32x4);
540
541   /*
542    * Thread-safe API messages
543    */
544   am->is_mp_safe[VL_API_IP_ADD_DEL_ROUTE] = 1;
545   am->is_mp_safe[VL_API_GET_NODE_GRAPH] = 1;
546
547   /*
548    * Set up the (msg_name, crc, message-id) table
549    */
550   setup_message_id_table (am);
551
552   return 0;
553 }
554
555 VLIB_API_INIT_FUNCTION (vpe_api_hookup);
556
557 clib_error_t *
558 vpe_api_init (vlib_main_t * vm)
559 {
560   vpe_api_main_t *am = &vpe_api_main;
561
562   am->vlib_main = vm;
563   am->vnet_main = vnet_get_main ();
564 #define _(a)                                                    \
565   am->a##_registration_hash = hash_create (0, sizeof (uword));
566   foreach_registration_hash;
567 #undef _
568
569   vl_set_memory_region_name ("/vpe-api");
570   vl_mem_api_enable_disable (vm, 1 /* enable it */ );
571
572   return 0;
573 }
574
575 static clib_error_t *
576 api_segment_config (vlib_main_t * vm, unformat_input_t * input)
577 {
578   u8 *chroot_path;
579   u64 baseva, size, pvt_heap_size;
580   int uid, gid, rv;
581   const int max_buf_size = 4096;
582   char *s, *buf;
583   struct passwd _pw, *pw;
584   struct group _grp, *grp;
585   clib_error_t *e;
586   buf = vec_new (char, 128);
587   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
588     {
589       if (unformat (input, "prefix %s", &chroot_path))
590         {
591           vec_add1 (chroot_path, 0);
592           vl_set_memory_root_path ((char *) chroot_path);
593         }
594       else if (unformat (input, "uid %d", &uid))
595         vl_set_memory_uid (uid);
596       else if (unformat (input, "gid %d", &gid))
597         vl_set_memory_gid (gid);
598       else if (unformat (input, "baseva %llx", &baseva))
599         vl_set_global_memory_baseva (baseva);
600       else if (unformat (input, "global-size %lldM", &size))
601         vl_set_global_memory_size (size * (1ULL << 20));
602       else if (unformat (input, "global-size %lldG", &size))
603         vl_set_global_memory_size (size * (1ULL << 30));
604       else if (unformat (input, "global-size %lld", &size))
605         vl_set_global_memory_size (size);
606       else if (unformat (input, "global-pvt-heap-size %lldM", &pvt_heap_size))
607         vl_set_global_pvt_heap_size (pvt_heap_size * (1ULL << 20));
608       else if (unformat (input, "global-pvt-heap-size size %lld",
609                          &pvt_heap_size))
610         vl_set_global_pvt_heap_size (pvt_heap_size);
611       else if (unformat (input, "api-pvt-heap-size %lldM", &pvt_heap_size))
612         vl_set_api_pvt_heap_size (pvt_heap_size * (1ULL << 20));
613       else if (unformat (input, "api-pvt-heap-size size %lld",
614                          &pvt_heap_size))
615         vl_set_api_pvt_heap_size (pvt_heap_size);
616       else if (unformat (input, "api-size %lldM", &size))
617         vl_set_api_memory_size (size * (1ULL << 20));
618       else if (unformat (input, "api-size %lldG", &size))
619         vl_set_api_memory_size (size * (1ULL << 30));
620       else if (unformat (input, "api-size %lld", &size))
621         vl_set_api_memory_size (size);
622       else if (unformat (input, "uid %s", &s))
623         {
624           /* lookup the username */
625           pw = NULL;
626           while (((rv =
627                    getpwnam_r (s, &_pw, buf, vec_len (buf), &pw)) == ERANGE)
628                  && (vec_len (buf) <= max_buf_size))
629             {
630               vec_resize (buf, vec_len (buf) * 2);
631             }
632           if (rv < 0)
633             {
634               e = clib_error_return_code (0, rv,
635                                           CLIB_ERROR_ERRNO_VALID |
636                                           CLIB_ERROR_FATAL,
637                                           "cannot fetch username %s", s);
638               vec_free (s);
639               vec_free (buf);
640               return e;
641             }
642           if (pw == NULL)
643             {
644               e =
645                 clib_error_return_fatal (0, "username %s does not exist", s);
646               vec_free (s);
647               vec_free (buf);
648               return e;
649             }
650           vec_free (s);
651           vl_set_memory_uid (pw->pw_uid);
652         }
653       else if (unformat (input, "gid %s", &s))
654         {
655           /* lookup the group name */
656           grp = NULL;
657           while (((rv =
658                    getgrnam_r (s, &_grp, buf, vec_len (buf), &grp)) == ERANGE)
659                  && (vec_len (buf) <= max_buf_size))
660             {
661               vec_resize (buf, vec_len (buf) * 2);
662             }
663           if (rv != 0)
664             {
665               e = clib_error_return_code (0, rv,
666                                           CLIB_ERROR_ERRNO_VALID |
667                                           CLIB_ERROR_FATAL,
668                                           "cannot fetch group %s", s);
669               vec_free (s);
670               vec_free (buf);
671               return e;
672             }
673           if (grp == NULL)
674             {
675               e = clib_error_return_fatal (0, "group %s does not exist", s);
676               vec_free (s);
677               vec_free (buf);
678               return e;
679             }
680           vec_free (s);
681           vec_free (buf);
682           vl_set_memory_gid (grp->gr_gid);
683         }
684       else
685         return clib_error_return (0, "unknown input `%U'",
686                                   format_unformat_error, input);
687     }
688   return 0;
689 }
690
691 VLIB_EARLY_CONFIG_FUNCTION (api_segment_config, "api-segment");
692
693 void *
694 get_unformat_vnet_sw_interface (void)
695 {
696   return (void *) &unformat_vnet_sw_interface;
697 }
698
699 static u8 *
700 format_arp_event (u8 * s, va_list * args)
701 {
702   vl_api_ip4_arp_event_t *event = va_arg (*args, vl_api_ip4_arp_event_t *);
703
704   s = format (s, "pid %d: ", ntohl (event->pid));
705   s = format (s, "resolution for %U", format_ip4_address, &event->address);
706   return s;
707 }
708
709 static u8 *
710 format_nd_event (u8 * s, va_list * args)
711 {
712   vl_api_ip6_nd_event_t *event = va_arg (*args, vl_api_ip6_nd_event_t *);
713
714   s = format (s, "pid %d: ", ntohl (event->pid));
715   s = format (s, "resolution for %U", format_ip6_address, event->address);
716   return s;
717 }
718
719 static clib_error_t *
720 show_ip_arp_nd_events_fn (vlib_main_t * vm,
721                           unformat_input_t * input, vlib_cli_command_t * cmd)
722 {
723   vpe_api_main_t *am = &vpe_api_main;
724   vl_api_ip4_arp_event_t *arp_event;
725   vl_api_ip6_nd_event_t *nd_event;
726
727   if (pool_elts (am->arp_events) == 0 && pool_elts (am->nd_events) == 0 &&
728       pool_elts (am->wc_ip4_arp_events_registrations) == 0 &&
729       pool_elts (am->wc_ip6_nd_events_registrations) == 0)
730     {
731       vlib_cli_output (vm, "No active arp or nd event registrations");
732       return 0;
733     }
734
735   /* *INDENT-OFF* */
736   pool_foreach (arp_event, am->arp_events,
737   ({
738     vlib_cli_output (vm, "%U", format_arp_event, arp_event);
739   }));
740
741   vpe_client_registration_t *reg;
742   pool_foreach(reg, am->wc_ip4_arp_events_registrations,
743   ({
744     vlib_cli_output (vm, "pid %d: bd mac/ip4 binding events",
745                      ntohl (reg->client_pid));
746   }));
747
748   pool_foreach (nd_event, am->nd_events,
749   ({
750     vlib_cli_output (vm, "%U", format_nd_event, nd_event);
751   }));
752
753   pool_foreach(reg, am->wc_ip6_nd_events_registrations,
754   ({
755     vlib_cli_output (vm, "pid %d: bd mac/ip6 binding events",
756                      ntohl (reg->client_pid));
757   }));
758   /* *INDENT-ON* */
759
760   return 0;
761 }
762
763 /* *INDENT-OFF* */
764 VLIB_CLI_COMMAND (show_ip_arp_nd_events, static) = {
765   .path = "show arp-nd-event registrations",
766   .function = show_ip_arp_nd_events_fn,
767   .short_help = "Show ip4 arp and ip6 nd event registrations",
768 };
769 /* *INDENT-ON* */
770
771 #define vl_msg_name_crc_list
772 #include <vpp/api/vpe_all_api_h.h>
773 #undef vl_msg_name_crc_list
774
775 static void
776 setup_message_id_table (api_main_t * am)
777 {
778 #define _(id,n,crc) vl_msg_api_add_msg_name_crc (am, #n "_" #crc, id);
779   foreach_vl_msg_name_crc_memclnt;
780   foreach_vl_msg_name_crc_vpe;
781 #undef _
782
783 #define vl_api_version_tuple(n,mj, mi, p) \
784   vl_msg_api_add_version (am, #n, mj, mi, p);
785 #include <vpp/api/vpe_all_api_h.h>
786 #undef vl_api_version_tuple
787 }
788
789
790 /*
791  * fd.io coding-style-patch-verification: ON
792  *
793  * Local Variables:
794  * eval: (c-set-style "gnu")
795  * End:
796  */