session: add support for memfd segments
[vpp.git] / src / vlibmemory / socket_api.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 <fcntl.h>
25 #include <sys/stat.h>
26
27 #include <vppinfra/byte_order.h>
28 #include <svm/ssvm.h>
29 #include <vlibmemory/api.h>
30
31 #include <vlibmemory/vl_memory_msg_enum.h>
32
33 #define vl_typedefs             /* define message structures */
34 #include <vlibmemory/vl_memory_api_h.h>
35 #undef vl_typedefs
36
37 /* instantiate all the print functions we know about */
38 #define vl_print(handle, ...) vlib_cli_output (handle, __VA_ARGS__)
39 #define vl_printfun
40 #include <vlibmemory/vl_memory_api_h.h>
41 #undef vl_printfun
42
43 /* instantiate all the endian swap functions we know about */
44 #define vl_endianfun
45 #include <vlibmemory/vl_memory_api_h.h>
46 #undef vl_endianfun
47
48 socket_main_t socket_main;
49
50 void
51 vl_sock_api_dump_clients (vlib_main_t * vm, api_main_t * am)
52 {
53   vl_api_registration_t *reg;
54   socket_main_t *sm = &socket_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 = vl_api_registration_file (reg);
71             vlib_cli_output (vm, "%20s %8d", reg->name, f->file_descriptor);
72         }
73     }));
74 /* *INDENT-ON* */
75 }
76
77 void
78 vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
79 {
80 #if CLIB_DEBUG > 1
81   u32 output_length;
82 #endif
83   socket_main_t *sm = &socket_main;
84   u16 msg_id = ntohs (*(u16 *) elem);
85   api_main_t *am = &api_main;
86   msgbuf_t *mb = (msgbuf_t *) (elem - offsetof (msgbuf_t, data));
87   vl_api_registration_t *sock_rp;
88   clib_file_t *cf;
89
90   cf = vl_api_registration_file (rp);
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_socket_free_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_socket_process_api_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_socket_free_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, vl_api_clnt_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_socket_free_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_socket_free_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   if (error)
383     return error;
384
385   socksvr_file_add (fm, client.fd);
386   return 0;
387 }
388
389 static clib_error_t *
390 socksvr_bogus_write (clib_file_t * uf)
391 {
392   clib_warning ("why am I here?");
393   return 0;
394 }
395
396 /*
397  * vl_api_sockclnt_create_t_handler
398  */
399 void
400 vl_api_sockclnt_create_t_handler (vl_api_sockclnt_create_t * mp)
401 {
402   vl_api_registration_t *regp;
403   vl_api_sockclnt_create_reply_t *rp;
404   int rv = 0;
405
406   regp = socket_main.current_rp;
407
408   ASSERT (regp->registration_type == REGISTRATION_TYPE_SOCKET_SERVER);
409
410   regp->name = format (0, "%s%c", mp->name, 0);
411
412   rp = vl_msg_api_alloc (sizeof (*rp));
413   rp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE_REPLY);
414   rp->handle = (uword) regp;
415   rp->index = (uword) regp->vl_api_registration_pool_index;
416   rp->context = mp->context;
417   rp->response = htonl (rv);
418
419   vl_api_send_msg (regp, (u8 *) rp);
420 }
421
422 /*
423  * vl_api_sockclnt_delete_t_handler
424  */
425 void
426 vl_api_sockclnt_delete_t_handler (vl_api_sockclnt_delete_t * mp)
427 {
428   vl_api_registration_t *regp;
429   vl_api_sockclnt_delete_reply_t *rp;
430
431   if (!pool_is_free_index (socket_main.registration_pool, mp->index))
432     {
433       regp = pool_elt_at_index (socket_main.registration_pool, mp->index);
434
435       rp = vl_msg_api_alloc (sizeof (*rp));
436       rp->_vl_msg_id = htons (VL_API_SOCKCLNT_DELETE_REPLY);
437       rp->handle = mp->handle;
438       rp->response = htonl (1);
439
440       vl_api_send_msg (regp, (u8 *) rp);
441
442       vl_api_registration_del_file (regp);
443       vl_socket_free_registration_index (mp->index);
444     }
445   else
446     {
447       clib_warning ("unknown client ID %d", mp->index);
448     }
449 }
450
451 clib_error_t *
452 vl_sock_api_send_fd_msg (int socket_fd, int fd_to_share)
453 {
454   struct msghdr mh = { 0 };
455   struct iovec iov[1];
456   char ctl[CMSG_SPACE (sizeof (int))];
457   char *msg = "memfd";
458   int rv;
459
460   iov[0].iov_base = msg;
461   iov[0].iov_len = strlen (msg);
462   mh.msg_iov = iov;
463   mh.msg_iovlen = 1;
464
465   struct cmsghdr *cmsg;
466   memset (&ctl, 0, sizeof (ctl));
467   mh.msg_control = ctl;
468   mh.msg_controllen = sizeof (ctl);
469   cmsg = CMSG_FIRSTHDR (&mh);
470   cmsg->cmsg_len = CMSG_LEN (sizeof (int));
471   cmsg->cmsg_level = SOL_SOCKET;
472   cmsg->cmsg_type = SCM_RIGHTS;
473   memcpy (CMSG_DATA (cmsg), &fd_to_share, sizeof (int));
474
475   rv = sendmsg (socket_fd, &mh, 0);
476   if (rv < 0)
477     return clib_error_return_unix (0, "sendmsg");
478   return 0;
479 }
480
481 vl_api_shm_elem_config_t *
482 vl_api_make_shm_config (vl_api_sock_init_shm_t * mp)
483 {
484   vl_api_shm_elem_config_t *config = 0, *c;
485   u64 cfg;
486   int i;
487
488   if (!mp->nitems)
489     {
490       vec_validate (config, 3);
491       config[0].type = VL_API_VLIB_RING;
492       config[0].count = 128;
493       config[0].size = 256;
494       config[1].type = VL_API_CLIENT_RING;
495       config[1].count = 128;
496       config[1].size = 1024;
497       config[2].type = VL_API_CLIENT_RING;
498       config[2].count = 8;
499       config[2].size = 4096;
500       config[3].type = VL_API_QUEUE;
501       config[3].count = 128;
502       config[3].size = sizeof (uword);
503     }
504   else
505     {
506       vec_validate (config, mp->nitems - 1);
507       for (i = 0; i < mp->nitems; i++)
508         {
509           cfg = mp->configs[i];
510           /* Pretty much a hack but it avoids defining our own api type
511            * in memclnt.api */
512           c = (vl_api_shm_elem_config_t *) & cfg;
513           config[i].type = c->type;
514           config[i].count = c->count;
515           config[i].size = c->size;
516         }
517     }
518   return config;
519 }
520
521 /*
522  * Bootstrap shm api using the socket api
523  */
524 void
525 vl_api_sock_init_shm_t_handler (vl_api_sock_init_shm_t * mp)
526 {
527   vl_api_sock_init_shm_reply_t *rmp;
528   ssvm_private_t _memfd_private, *memfd = &_memfd_private;
529   svm_map_region_args_t _args, *a = &_args;
530   vl_api_registration_t *regp;
531   api_main_t *am = &api_main;
532   svm_region_t *vlib_rp;
533   clib_file_t *cf;
534   vl_api_shm_elem_config_t *config = 0;
535   vl_shmem_hdr_t *shmem_hdr;
536   int rv;
537
538   regp = vl_api_client_index_to_registration (mp->client_index);
539   if (regp == 0)
540     {
541       clib_warning ("API client disconnected");
542       return;
543     }
544   if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
545     {
546       rv = -31;                 /* VNET_API_ERROR_INVALID_REGISTRATION */
547       goto reply;
548     }
549
550   /*
551    * Set up a memfd segment of the requested size wherein the
552    * shmem data structures will be initialized
553    */
554   memset (memfd, 0, sizeof (*memfd));
555   memfd->ssvm_size = mp->requested_size;
556   memfd->requested_va = 0ULL;
557   memfd->i_am_master = 1;
558   memfd->name = format (0, "%s%c", regp->name, 0);
559
560   if ((rv = ssvm_master_init_memfd (memfd)))
561     goto reply;
562
563   /* Remember to close this fd when the socket connection goes away */
564   vec_add1 (regp->additional_fds_to_close, memfd->fd);
565
566   /*
567    * Create a plausible svm_region in the memfd backed segment
568    */
569   memset (a, 0, sizeof (*a));
570   a->baseva = memfd->sh->ssvm_va + MMAP_PAGESIZE;
571   a->size = memfd->ssvm_size - MMAP_PAGESIZE;
572   /* $$$$ might want a different config parameter */
573   a->pvt_heap_size = am->api_pvt_heap_size;
574   a->flags = SVM_FLAGS_MHEAP;
575   svm_region_init_mapped_region (a, (svm_region_t *) a->baseva);
576
577   /*
578    * Part deux, initialize the svm_region_t shared-memory header
579    * api allocation rings, and so on.
580    */
581   config = vl_api_make_shm_config (mp);
582   vlib_rp = (svm_region_t *) a->baseva;
583   vl_init_shmem (vlib_rp, config, 1 /* is_vlib (dont-care) */ ,
584                  1 /* is_private */ );
585
586   /* Remember who created this. Needs to be post vl_init_shmem */
587   shmem_hdr = (vl_shmem_hdr_t *) vlib_rp->user_ctx;
588   shmem_hdr->clib_file_index = vl_api_registration_file_index (regp);
589
590   vec_add1 (am->vlib_private_rps, vlib_rp);
591   memfd->sh->ready = 1;
592   vec_free (config);
593
594   /* Recompute the set of input queues to poll in memclnt_process */
595   vec_reset_length (vl_api_queue_cursizes);
596
597 reply:
598
599   rmp = vl_msg_api_alloc (sizeof (*rmp));
600   rmp->_vl_msg_id = htons (VL_API_SOCK_INIT_SHM_REPLY);
601   rmp->context = mp->context;
602   rmp->retval = htonl (rv);
603
604   vl_api_send_msg (regp, (u8 *) rmp);
605
606   if (rv != 0)
607     return;
608
609   /*
610    * We need the reply message to make it out the back door
611    * before we send the magic fd message so force a flush
612    */
613   cf = vl_api_registration_file (regp);
614   cf->write_function (cf);
615
616   /* Send the magic "here's your sign (aka fd)" socket message */
617   vl_sock_api_send_fd_msg (cf->file_descriptor, memfd->fd);
618 }
619
620 /*
621  * Create a memory-fd segment.
622  */
623 void
624 vl_api_memfd_segment_create_t_handler (vl_api_memfd_segment_create_t * mp)
625 {
626   vl_api_memfd_segment_create_reply_t *rmp;
627   clib_file_t *cf;
628   ssvm_private_t _memfd_private, *memfd = &_memfd_private;
629   vl_api_registration_t *regp;
630   int rv;
631
632   regp = vl_api_client_index_to_registration (mp->client_index);
633   if (regp == 0)
634     {
635       clib_warning ("API client disconnected");
636       return;
637     }
638
639   memset (memfd, 0, sizeof (*memfd));
640   memfd->ssvm_size = mp->requested_size;
641   memfd->requested_va = 0ULL;
642   memfd->i_am_master = 1;
643   memfd->name = format (0, "%s%c", regp->name, 0);
644
645   /* Set up a memfd segment of the requested size */
646   if ((rv = ssvm_master_init_memfd (memfd)))
647     goto reply;
648
649   /* Remember to close this fd when the socket connection goes away */
650   vec_add1 (regp->additional_fds_to_close, memfd->fd);
651
652 reply:
653
654   rmp = vl_msg_api_alloc (sizeof (*rmp));
655   rmp->_vl_msg_id = htons (VL_API_MEMFD_SEGMENT_CREATE_REPLY);
656   rmp->context = mp->context;
657   rmp->retval = htonl (rv);
658
659   vl_api_send_msg (regp, (u8 *) rmp);
660
661   if (rv != 0)
662     return;
663
664   /*
665    * We need the reply message to make it out the back door
666    * before we send the magic fd message.
667    */
668   cf = vl_api_registration_file (regp);
669   cf->write_function (cf);
670
671   /* send the magic "here's your sign (aka fd)" socket message */
672   vl_sock_api_send_fd_msg (cf->file_descriptor, memfd->fd);
673 }
674
675 #define foreach_vlib_api_msg                            \
676 _(SOCKCLNT_CREATE, sockclnt_create)                     \
677 _(SOCKCLNT_DELETE, sockclnt_delete)                     \
678 _(SOCK_INIT_SHM, sock_init_shm)                         \
679 _(MEMFD_SEGMENT_CREATE, memfd_segment_create)
680
681 clib_error_t *
682 vl_sock_api_init (vlib_main_t * vm)
683 {
684   clib_file_main_t *fm = &file_main;
685   clib_file_t template = { 0 };
686   vl_api_registration_t *rp;
687   socket_main_t *sm = &socket_main;
688   clib_socket_t *sock = &sm->socksvr_listen_socket;
689   clib_error_t *error;
690
691   /* If not explicitly configured, do not bind/enable, etc. */
692   if (sm->socket_name == 0)
693     return 0;
694
695 #define _(N,n)                                                  \
696     vl_msg_api_set_handlers(VL_API_##N, #n,                     \
697                            vl_api_##n##_t_handler,              \
698                            vl_noop_handler,                     \
699                            vl_api_##n##_t_endian,               \
700                            vl_api_##n##_t_print,                \
701                            sizeof(vl_api_##n##_t), 1);
702   foreach_vlib_api_msg;
703 #undef _
704
705   vec_resize (sm->input_buffer, 4096);
706
707   sock->config = (char *) sm->socket_name;
708
709   /* mkdir of file socket, only under /run  */
710   if (strncmp (sock->config, "/run", 4) == 0)
711     {
712       u8 *tmp = format (0, "%s", sock->config);
713       int i = vec_len (tmp);
714       while (i && tmp[--i] != '/')
715         ;
716
717       tmp[i] = 0;
718
719       if (i)
720         vlib_unix_recursive_mkdir ((char *) tmp);
721       vec_free (tmp);
722     }
723
724   sock->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_SEQPACKET |
725     CLIB_SOCKET_F_ALLOW_GROUP_WRITE;
726   error = clib_socket_init (sock);
727   if (error)
728     return error;
729
730   pool_get (sm->registration_pool, rp);
731   memset (rp, 0, sizeof (*rp));
732
733   rp->registration_type = REGISTRATION_TYPE_SOCKET_LISTEN;
734
735   template.read_function = socksvr_accept_ready;
736   template.write_function = socksvr_bogus_write;
737   template.file_descriptor = sock->fd;
738   template.private_data = rp - sm->registration_pool;
739
740   rp->clib_file_index = clib_file_add (fm, &template);
741   return 0;
742 }
743
744 static clib_error_t *
745 socket_exit (vlib_main_t * vm)
746 {
747   socket_main_t *sm = &socket_main;
748   vl_api_registration_t *rp;
749
750   /* Defensive driving in case something wipes out early */
751   if (sm->registration_pool)
752     {
753       u32 index;
754         /* *INDENT-OFF* */
755         pool_foreach (rp, sm->registration_pool, ({
756           vl_api_registration_del_file (rp);
757           index = rp->vl_api_registration_pool_index;
758           vl_socket_free_registration_index (index);
759         }));
760 /* *INDENT-ON* */
761     }
762
763   return 0;
764 }
765
766 VLIB_MAIN_LOOP_EXIT_FUNCTION (socket_exit);
767
768 static clib_error_t *
769 socksvr_config (vlib_main_t * vm, unformat_input_t * input)
770 {
771   socket_main_t *sm = &socket_main;
772
773   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
774     {
775       if (unformat (input, "socket-name %s", &sm->socket_name))
776         ;
777       else if (unformat (input, "default"))
778         {
779           sm->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
780         }
781       else
782         {
783           return clib_error_return (0, "unknown input '%U'",
784                                     format_unformat_error, input);
785         }
786     }
787   return 0;
788 }
789
790 VLIB_CONFIG_FUNCTION (socksvr_config, "socksvr");
791
792 clib_error_t *
793 vlibsocket_init (vlib_main_t * vm)
794 {
795   return 0;
796 }
797
798 VLIB_INIT_FUNCTION (vlibsocket_init);
799
800 /*
801  * fd.io coding-style-patch-verification: ON
802  *
803  * Local Variables:
804  * eval: (c-set-style "gnu")
805  * End:
806  */