sock api: add infra for bootstrapping shm clients
[vpp.git] / src / vlibmemory / socksvr_vlib.c
1 /*
2  *------------------------------------------------------------------
3  * socksvr_vlib.c
4  *
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 <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <sys/ioctl.h>
24 #include <vppinfra/byte_order.h>
25 #include <svm/memfd.h>
26
27 #include <fcntl.h>
28 #include <sys/stat.h>
29
30 #include <vlibmemory/api.h>
31
32 #include <vlibmemory/vl_memory_msg_enum.h>
33
34 #define vl_typedefs             /* define message structures */
35 #include <vlibmemory/vl_memory_api_h.h>
36 #undef vl_typedefs
37
38 /* instantiate all the print functions we know about */
39 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
40 #define vl_printfun
41 #include <vlibmemory/vl_memory_api_h.h>
42 #undef vl_printfun
43
44 /* instantiate all the endian swap functions we know about */
45 #define vl_endianfun
46 #include <vlibmemory/vl_memory_api_h.h>
47 #undef vl_endianfun
48
49 void
50 dump_socket_clients (vlib_main_t * vm, api_main_t * am)
51 {
52   vl_api_registration_t *reg;
53   socket_main_t *sm = &socket_main;
54   clib_file_main_t *fm = &file_main;
55   clib_file_t *f;
56
57   /*
58    * Must have at least one active client, not counting the
59    * REGISTRATION_TYPE_SOCKET_LISTEN bind/accept socket
60    */
61   if (pool_elts (sm->registration_pool) < 2)
62     return;
63
64   vlib_cli_output (vm, "Socket clients");
65   vlib_cli_output (vm, "%20s %8s", "Name", "Fildesc");
66     /* *INDENT-OFF* */
67     pool_foreach (reg, sm->registration_pool,
68     ({
69         if (reg->registration_type == REGISTRATION_TYPE_SOCKET_SERVER) {
70             f = pool_elt_at_index (fm->file_pool, reg->clib_file_index);
71             vlib_cli_output (vm, "%20s %8d",
72                              reg->name, f->file_descriptor);
73         }
74     }));
75 /* *INDENT-ON* */
76 }
77
78 void
79 vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
80 {
81 #if CLIB_DEBUG > 1
82   u32 output_length;
83 #endif
84   socket_main_t *sm = &socket_main;
85   u16 msg_id = ntohs (*(u16 *) elem);
86   api_main_t *am = &api_main;
87   msgbuf_t *mb = (msgbuf_t *) (elem - offsetof (msgbuf_t, data));
88   clib_file_t *cf = clib_file_get (&file_main, rp->clib_file_index);
89   vl_api_registration_t *sock_rp;
90
91   ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
92
93   if (msg_id >= vec_len (am->api_trace_cfg))
94     {
95       clib_warning ("id out of range: %d", msg_id);
96       vl_msg_api_free ((void *) elem);
97       return;
98     }
99
100   sock_rp = pool_elt_at_index (sm->registration_pool,
101                                rp->vl_api_registration_pool_index);
102   ASSERT (sock_rp);
103
104   /* Add the msgbuf_t to the output vector */
105   vl_socket_add_pending_output_no_flush (cf, sock_rp, (u8 *) mb,
106                                          sizeof (*mb));
107   /* Send the message */
108   vl_socket_add_pending_output (cf, sock_rp, elem, ntohl (mb->data_len));
109
110 #if CLIB_DEBUG > 1
111   output_length = sizeof (*mb) + ntohl (mb->data_len);
112   clib_warning ("wrote %u bytes to fd %d", output_length,
113                 cf->file_descriptor);
114 #endif
115
116   vl_msg_api_free ((void *) elem);
117 }
118
119 void
120 vl_free_socket_registration_index (u32 pool_index)
121 {
122   int i;
123   vl_api_registration_t *rp;
124   if (pool_is_free_index (socket_main.registration_pool, pool_index))
125     {
126       clib_warning ("main pool index %d already free", pool_index);
127       return;
128     }
129   rp = pool_elt_at_index (socket_main.registration_pool, pool_index);
130
131   ASSERT (rp->registration_type != REGISTRATION_TYPE_FREE);
132   for (i = 0; i < vec_len (rp->additional_fds_to_close); i++)
133     if (close (rp->additional_fds_to_close[i]) < 0)
134       clib_unix_warning ("close");
135   vec_free (rp->additional_fds_to_close);
136   vec_free (rp->name);
137   vec_free (rp->unprocessed_input);
138   vec_free (rp->output_vector);
139   rp->registration_type = REGISTRATION_TYPE_FREE;
140   pool_put (socket_main.registration_pool, rp);
141 }
142
143 void
144 vl_api_socket_process_msg (clib_file_t * uf, vl_api_registration_t * rp,
145                            i8 * input_v)
146 {
147   msgbuf_t *mbp = (msgbuf_t *) input_v;
148
149   u8 *the_msg = (u8 *) (mbp->data);
150   socket_main.current_uf = uf;
151   socket_main.current_rp = rp;
152   vl_msg_api_socket_handler (the_msg);
153   socket_main.current_uf = 0;
154   socket_main.current_rp = 0;
155 }
156
157 clib_error_t *
158 vl_socket_read_ready (clib_file_t * uf)
159 {
160   clib_file_main_t *fm = &file_main;
161   vlib_main_t *vm = vlib_get_main ();
162   vl_api_registration_t *rp;
163   int n;
164   i8 *msg_buffer = 0;
165   u8 *data_for_process;
166   u32 msg_len;
167   u32 save_input_buffer_length = vec_len (socket_main.input_buffer);
168   vl_socket_args_for_process_t *a;
169   msgbuf_t *mbp;
170   int mbp_set = 0;
171
172   rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
173
174   n = read (uf->file_descriptor, socket_main.input_buffer,
175             vec_len (socket_main.input_buffer));
176
177   if (n <= 0 && errno != EAGAIN)
178     {
179       clib_file_del (fm, uf);
180
181       if (!pool_is_free (socket_main.registration_pool, rp))
182         {
183           u32 index = rp - socket_main.registration_pool;
184           vl_free_socket_registration_index (index);
185         }
186       else
187         {
188           clib_warning ("client index %d already free?",
189                         rp->vl_api_registration_pool_index);
190         }
191       return 0;
192     }
193
194   _vec_len (socket_main.input_buffer) = n;
195
196   /*
197    * Look for bugs here. This code is tricky because
198    * data read from a stream socket does not honor message
199    * boundaries. In the case of a long message (>4K bytes)
200    * we have to do (at least) 2 reads, etc.
201    */
202   do
203     {
204       if (vec_len (rp->unprocessed_input))
205         {
206           vec_append (rp->unprocessed_input, socket_main.input_buffer);
207           msg_buffer = rp->unprocessed_input;
208         }
209       else
210         {
211           msg_buffer = socket_main.input_buffer;
212           mbp_set = 0;
213         }
214
215       if (mbp_set == 0)
216         {
217           /* Any chance that we have a complete message? */
218           if (vec_len (msg_buffer) <= sizeof (msgbuf_t))
219             goto save_and_split;
220
221           mbp = (msgbuf_t *) msg_buffer;
222           msg_len = ntohl (mbp->data_len);
223           mbp_set = 1;
224         }
225
226       /* We don't have the entire message yet. */
227       if (mbp_set == 0
228           || (msg_len + sizeof (msgbuf_t)) > vec_len (msg_buffer))
229         {
230         save_and_split:
231           /* if we were using the input buffer save the fragment */
232           if (msg_buffer == socket_main.input_buffer)
233             {
234               ASSERT (vec_len (rp->unprocessed_input) == 0);
235               vec_validate (rp->unprocessed_input, vec_len (msg_buffer) - 1);
236               clib_memcpy (rp->unprocessed_input, msg_buffer,
237                            vec_len (msg_buffer));
238               _vec_len (rp->unprocessed_input) = vec_len (msg_buffer);
239             }
240           _vec_len (socket_main.input_buffer) = save_input_buffer_length;
241           return 0;
242         }
243
244       data_for_process = (u8 *) vec_dup (msg_buffer);
245       _vec_len (data_for_process) = (msg_len + sizeof (msgbuf_t));
246       pool_get (socket_main.process_args, a);
247       a->clib_file = uf;
248       a->regp = rp;
249       a->data = data_for_process;
250
251       vlib_process_signal_event (vm, memclnt_node.index,
252                                  SOCKET_READ_EVENT,
253                                  a - socket_main.process_args);
254       if (n > (msg_len + sizeof (*mbp)))
255         vec_delete (msg_buffer, msg_len + sizeof (*mbp), 0);
256       else
257         _vec_len (msg_buffer) = 0;
258       n -= msg_len + sizeof (msgbuf_t);
259       msg_len = 0;
260       mbp_set = 0;
261     }
262   while (n > 0);
263
264   _vec_len (socket_main.input_buffer) = save_input_buffer_length;
265
266   return 0;
267 }
268
269 void
270 vl_socket_add_pending_output (clib_file_t * uf,
271                               vl_api_registration_t * rp,
272                               u8 * buffer, uword buffer_bytes)
273 {
274   clib_file_main_t *fm = &file_main;
275
276   vec_add (rp->output_vector, buffer, buffer_bytes);
277   if (vec_len (rp->output_vector) > 0)
278     {
279       int skip_update = 0 != (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE);
280       uf->flags |= UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
281       if (!skip_update)
282         fm->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
283     }
284 }
285
286 void
287 vl_socket_add_pending_output_no_flush (clib_file_t * uf,
288                                        vl_api_registration_t * rp,
289                                        u8 * buffer, uword buffer_bytes)
290 {
291   vec_add (rp->output_vector, buffer, buffer_bytes);
292 }
293
294 static void
295 socket_del_pending_output (clib_file_t * uf,
296                            vl_api_registration_t * rp, uword n_bytes)
297 {
298   clib_file_main_t *fm = &file_main;
299
300   vec_delete (rp->output_vector, n_bytes, 0);
301   if (vec_len (rp->output_vector) <= 0)
302     {
303       int skip_update = 0 == (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE);
304       uf->flags &= ~UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
305       if (!skip_update)
306         fm->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
307     }
308 }
309
310 clib_error_t *
311 vl_socket_write_ready (clib_file_t * uf)
312 {
313   clib_file_main_t *fm = &file_main;
314   vl_api_registration_t *rp;
315   int n;
316
317   rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
318
319   /* Flush output vector. */
320   n = write (uf->file_descriptor,
321              rp->output_vector, vec_len (rp->output_vector));
322   if (n < 0)
323     {
324 #if DEBUG > 2
325       clib_warning ("write error, close the file...\n");
326 #endif
327       clib_file_del (fm, uf);
328
329       vl_free_socket_registration_index (rp - socket_main.registration_pool);
330       return 0;
331     }
332
333   else if (n > 0)
334     socket_del_pending_output (uf, rp, n);
335
336   return 0;
337 }
338
339 clib_error_t *
340 vl_socket_error_ready (clib_file_t * uf)
341 {
342   vl_api_registration_t *rp;
343   clib_file_main_t *fm = &file_main;
344
345   rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
346   clib_file_del (fm, uf);
347   vl_free_socket_registration_index (rp - socket_main.registration_pool);
348
349   return 0;
350 }
351
352 void
353 socksvr_file_add (clib_file_main_t * fm, int fd)
354 {
355   vl_api_registration_t *rp;
356   clib_file_t template = { 0 };
357
358   pool_get (socket_main.registration_pool, rp);
359   memset (rp, 0, sizeof (*rp));
360
361   template.read_function = vl_socket_read_ready;
362   template.write_function = vl_socket_write_ready;
363   template.error_function = vl_socket_error_ready;
364   template.file_descriptor = fd;
365   template.private_data = rp - socket_main.registration_pool;
366
367   rp->registration_type = REGISTRATION_TYPE_SOCKET_SERVER;
368   rp->vl_api_registration_pool_index = rp - socket_main.registration_pool;
369   rp->clib_file_index = clib_file_add (fm, &template);
370 }
371
372 static clib_error_t *
373 socksvr_accept_ready (clib_file_t * uf)
374 {
375   clib_file_main_t *fm = &file_main;
376   socket_main_t *sm = &socket_main;
377   clib_socket_t *sock = &sm->socksvr_listen_socket;
378   clib_socket_t client;
379   clib_error_t *error;
380
381   error = clib_socket_accept (sock, &client);
382
383   if (error)
384     return error;
385
386   socksvr_file_add (fm, client.fd);
387   return 0;
388 }
389
390 static clib_error_t *
391 socksvr_bogus_write (clib_file_t * uf)
392 {
393   clib_warning ("why am I here?");
394   return 0;
395 }
396
397 /*
398  * vl_api_sockclnt_create_t_handler
399  */
400 void
401 vl_api_sockclnt_create_t_handler (vl_api_sockclnt_create_t * mp)
402 {
403   vl_api_registration_t *regp;
404   vl_api_sockclnt_create_reply_t *rp;
405   int rv = 0;
406
407   regp = socket_main.current_rp;
408
409   ASSERT (regp->registration_type == REGISTRATION_TYPE_SOCKET_SERVER);
410
411   regp->name = format (0, "%s%c", mp->name, 0);
412
413   rp = vl_msg_api_alloc (sizeof (*rp));
414   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE_REPLY);
415   rp->handle = (uword) regp;
416   rp->index = (uword) regp->vl_api_registration_pool_index;
417   rp->context = mp->context;
418   rp->response = htonl (rv);
419
420   vl_msg_api_send (regp, (u8 *) rp);
421 }
422
423 /*
424  * vl_api_sockclnt_delete_t_handler
425  */
426 void
427 vl_api_sockclnt_delete_t_handler (vl_api_sockclnt_delete_t * mp)
428 {
429   vl_api_registration_t *regp;
430   vl_api_sockclnt_delete_reply_t *rp;
431
432   if (!pool_is_free_index (socket_main.registration_pool, mp->index))
433     {
434       regp = pool_elt_at_index (socket_main.registration_pool, mp->index);
435
436       rp = vl_msg_api_alloc (sizeof (*rp));
437       rp->_vl_msg_id = htons (VL_API_SOCKCLNT_DELETE_REPLY);
438       rp->handle = mp->handle;
439       rp->response = htonl (1);
440
441       vl_msg_api_send (regp, (u8 *) rp);
442
443       clib_file_del (&file_main, file_main.file_pool + regp->clib_file_index);
444
445       vl_free_socket_registration_index (mp->index);
446     }
447   else
448     {
449       clib_warning ("unknown client ID %d", mp->index);
450     }
451 }
452
453 static clib_error_t *
454 send_fd_msg (int socket_fd, int fd_to_share)
455 {
456   struct msghdr mh = { 0 };
457   struct iovec iov[1];
458   char ctl[CMSG_SPACE (sizeof (int))];
459   char *msg = "memfd";
460   int rv;
461
462   iov[0].iov_base = msg;
463   iov[0].iov_len = strlen (msg);
464   mh.msg_iov = iov;
465   mh.msg_iovlen = 1;
466
467   struct cmsghdr *cmsg;
468   memset (&ctl, 0, sizeof (ctl));
469   mh.msg_control = ctl;
470   mh.msg_controllen = sizeof (ctl);
471   cmsg = CMSG_FIRSTHDR (&mh);
472   cmsg->cmsg_len = CMSG_LEN (sizeof (int));
473   cmsg->cmsg_level = SOL_SOCKET;
474   cmsg->cmsg_type = SCM_RIGHTS;
475   memcpy (CMSG_DATA (cmsg), &fd_to_share, sizeof (int));
476
477   rv = sendmsg (socket_fd, &mh, 0);
478   if (rv < 0)
479     return clib_error_return_unix (0, "sendmsg");
480   return 0;
481 }
482
483 vl_api_shm_elem_config_t *
484 vl_api_make_shm_config (vl_api_sock_init_shm_t * mp)
485 {
486   vl_api_shm_elem_config_t *config = 0, *c;
487   u64 cfg;
488   int i;
489
490   if (!mp->nitems)
491     {
492       vec_validate (config, 3);
493       config[0].type = VL_API_VLIB_RING;
494       config[0].count = 128;
495       config[0].size = 256;
496       config[1].type = VL_API_CLIENT_RING;
497       config[1].count = 128;
498       config[1].size = 1024;
499       config[2].type = VL_API_CLIENT_RING;
500       config[2].count = 8;
501       config[2].size = 4096;
502       config[3].type = VL_API_QUEUE;
503       config[3].count = 128;
504       config[3].size = sizeof (uword);
505     }
506   else
507     {
508       vec_validate (config, mp->nitems - 1);
509       for (i = 0; i < mp->nitems; i++)
510         {
511           cfg = mp->configs[i];
512           /* Pretty much a hack but it avoids defining our own api type
513            * in memclnt.api */
514           c = (vl_api_shm_elem_config_t *) & cfg;
515           config[i].type = c->type;
516           config[i].count = c->count;
517           config[i].size = c->size;
518         }
519     }
520   return config;
521 }
522
523 /*
524  * Bootstrap shm api using the socket api
525  */
526 void
527 vl_api_sock_init_shm_t_handler (vl_api_sock_init_shm_t * mp)
528 {
529   vl_api_sock_init_shm_reply_t *rmp;
530   memfd_private_t _memfd_private, *memfd = &_memfd_private;
531   svm_map_region_args_t _args, *a = &_args;
532   vl_api_registration_t *regp;
533   api_main_t *am = &api_main;
534   svm_region_t *vlib_rp;
535   clib_file_t *cf;
536   vl_api_shm_elem_config_t *config = 0;
537   int rv;
538
539   regp = vl_api_client_index_to_registration (mp->client_index);
540   if (regp == 0)
541     {
542       clib_warning ("API client disconnected");
543       return;
544     }
545   if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
546     {
547       rv = -31;                 /* VNET_API_ERROR_INVALID_REGISTRATION */
548       goto reply;
549     }
550
551   /*
552    * Set up a memfd segment of the requested size wherein the
553    * shmem data structures will be initialized
554    */
555   memset (memfd, 0, sizeof (*memfd));
556   memfd->memfd_size = mp->requested_size;
557   memfd->requested_va = 0ULL;
558   memfd->i_am_master = 1;
559   memfd->name = format (0, "%s%c", regp->name, 0);
560
561   if ((rv = memfd_master_init (memfd, mp->client_index)))
562     goto reply;
563
564   /* Remember to close this fd when the socket connection goes away */
565   vec_add1 (regp->additional_fds_to_close, memfd->fd);
566
567   /*
568    * Create a plausible svm_region in the memfd backed segment
569    */
570   memset (a, 0, sizeof (*a));
571   a->baseva = memfd->sh->memfd_va + MMAP_PAGESIZE;
572   a->size = memfd->memfd_size - MMAP_PAGESIZE;
573   /* $$$$ might want a different config parameter */
574   a->pvt_heap_size = am->api_pvt_heap_size;
575   a->flags = SVM_FLAGS_MHEAP;
576   svm_region_init_mapped_region (a, (svm_region_t *) a->baseva);
577
578   /*
579    * Part deux, initialize the svm_region_t shared-memory header
580    * api allocation rings, and so on.
581    */
582   config = vl_api_make_shm_config (mp);
583   vlib_rp = (svm_region_t *) a->baseva;
584   vl_init_shmem (vlib_rp, config, 1 /* is_vlib (dont-care) */ ,
585                  1 /* is_private */ );
586   vec_add1 (am->vlib_private_rps, vlib_rp);
587   memfd->sh->ready = 1;
588   vec_free (config);
589
590   /* Recompute the set of input queues to poll in memclnt_process */
591   vec_reset_length (vl_api_queue_cursizes);
592
593 reply:
594
595   rmp = vl_msg_api_alloc (sizeof (*rmp));
596   rmp->_vl_msg_id = htons (VL_API_SOCK_INIT_SHM_REPLY);
597   rmp->context = mp->context;
598   rmp->retval = htonl (rv);
599
600   vl_msg_api_send (regp, (u8 *) rmp);
601
602   if (rv != 0)
603     return;
604
605   /*
606    * We need the reply message to make it out the back door
607    * before we send the magic fd message so force a flush
608    */
609   cf = clib_file_get (&file_main, regp->clib_file_index);
610   cf->write_function (cf);
611
612   /* Send the magic "here's your sign (aka fd)" socket message */
613   send_fd_msg (cf->file_descriptor, memfd->fd);
614 }
615
616 /*
617  * Create a memory-fd segment.
618  */
619 void
620 vl_api_memfd_segment_create_t_handler (vl_api_memfd_segment_create_t * mp)
621 {
622   vl_api_memfd_segment_create_reply_t *rmp;
623   clib_file_t *cf;
624   memfd_private_t _memfd_private, *memfd = &_memfd_private;
625   vl_api_registration_t *regp;
626   int rv;
627
628   regp = vl_api_client_index_to_registration (mp->client_index);
629   if (regp == 0)
630     {
631       clib_warning ("API client disconnected");
632       return;
633     }
634
635   memset (memfd, 0, sizeof (*memfd));
636   memfd->memfd_size = mp->requested_size;
637   memfd->requested_va = 0ULL;
638   memfd->i_am_master = 1;
639   memfd->name = format (0, "%s%c", regp->name, 0);
640
641   /* Set up a memfd segment of the requested size */
642   if ((rv = memfd_master_init (memfd, mp->client_index)))
643     goto reply;
644
645   /* Remember to close this fd when the socket connection goes away */
646   vec_add1 (regp->additional_fds_to_close, memfd->fd);
647
648 reply:
649
650   rmp = vl_msg_api_alloc (sizeof (*rmp));
651   rmp->_vl_msg_id = htons (VL_API_MEMFD_SEGMENT_CREATE_REPLY);
652   rmp->context = mp->context;
653   rmp->retval = htonl (rv);
654
655   vl_msg_api_send (regp, (u8 *) rmp);
656
657   if (rv != 0)
658     return;
659
660   /*
661    * We need the reply message to make it out the back door
662    * before we send the magic fd message.
663    */
664   cf = file_main.file_pool + regp->clib_file_index;
665   cf->write_function (cf);
666
667   /* send the magic "here's your sign (aka fd)" socket message */
668   send_fd_msg (cf->file_descriptor, memfd->fd);
669 }
670
671 #define foreach_vlib_api_msg                            \
672 _(SOCKCLNT_CREATE, sockclnt_create)                     \
673 _(SOCKCLNT_DELETE, sockclnt_delete)                     \
674 _(SOCK_INIT_SHM, sock_init_shm)                         \
675 _(MEMFD_SEGMENT_CREATE, memfd_segment_create)
676
677 clib_error_t *
678 socksvr_api_init (vlib_main_t * vm)
679 {
680   clib_file_main_t *fm = &file_main;
681   clib_file_t template = { 0 };
682   vl_api_registration_t *rp;
683   socket_main_t *sm = &socket_main;
684   clib_socket_t *sock = &sm->socksvr_listen_socket;
685   clib_error_t *error;
686
687   /* If not explicitly configured, do not bind/enable, etc. */
688   if (sm->socket_name == 0)
689     return 0;
690
691 #define _(N,n)                                                  \
692     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
693                            vl_api_##n##_t_handler,              \
694                            vl_noop_handler,                     \
695                            vl_api_##n##_t_endian,               \
696                            vl_api_##n##_t_print,                \
697                            sizeof(vl_api_##n##_t), 1);
698   foreach_vlib_api_msg;
699 #undef _
700
701   vec_resize (sm->input_buffer, 4096);
702
703   sock->config = (char *) sm->socket_name;
704
705   /* mkdir of file socket, only under /run  */
706   if (strncmp (sock->config, "/run", 4) == 0)
707     {
708       u8 *tmp = format (0, "%s", sock->config);
709       int i = vec_len (tmp);
710       while (i && tmp[--i] != '/')
711         ;
712
713       tmp[i] = 0;
714
715       if (i)
716         vlib_unix_recursive_mkdir ((char *) tmp);
717       vec_free (tmp);
718     }
719
720   sock->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_SEQPACKET |
721     CLIB_SOCKET_F_ALLOW_GROUP_WRITE;
722   error = clib_socket_init (sock);
723   if (error)
724     return error;
725
726   pool_get (sm->registration_pool, rp);
727   memset (rp, 0, sizeof (*rp));
728
729   rp->registration_type = REGISTRATION_TYPE_SOCKET_LISTEN;
730
731   template.read_function = socksvr_accept_ready;
732   template.write_function = socksvr_bogus_write;
733   template.file_descriptor = sock->fd;
734   template.private_data = rp - sm->registration_pool;
735
736   rp->clib_file_index = clib_file_add (fm, &template);
737   return 0;
738 }
739
740 static clib_error_t *
741 socket_exit (vlib_main_t * vm)
742 {
743   clib_file_main_t *fm = &file_main;
744   socket_main_t *sm = &socket_main;
745   vl_api_registration_t *rp;
746
747   /* Defensive driving in case something wipes out early */
748   if (sm->registration_pool)
749     {
750       u32 index;
751         /* *INDENT-OFF* */
752         pool_foreach (rp, sm->registration_pool, ({
753             clib_file_del (fm, fm->file_pool + rp->clib_file_index);
754             index = rp->vl_api_registration_pool_index;
755             vl_free_socket_registration_index (index);
756         }));
757 /* *INDENT-ON* */
758     }
759
760   return 0;
761 }
762
763 VLIB_MAIN_LOOP_EXIT_FUNCTION (socket_exit);
764
765 static clib_error_t *
766 socksvr_config (vlib_main_t * vm, unformat_input_t * input)
767 {
768   socket_main_t *sm = &socket_main;
769
770   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
771     {
772       if (unformat (input, "socket-name %s", &sm->socket_name))
773         ;
774       else if (unformat (input, "default"))
775         {
776           sm->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
777         }
778       else
779         {
780           return clib_error_return (0, "unknown input '%U'",
781                                     format_unformat_error, input);
782         }
783     }
784   return 0;
785 }
786
787 VLIB_CONFIG_FUNCTION (socksvr_config, "socksvr");
788
789 clib_error_t *
790 vlibsocket_init (vlib_main_t * vm)
791 {
792   return 0;
793 }
794
795 VLIB_INIT_FUNCTION (vlibsocket_init);
796
797 /*
798  * fd.io coding-style-patch-verification: ON
799  *
800  * Local Variables:
801  * eval: (c-set-style "gnu")
802  * End:
803  */