Line data Source code
1 : /*
2 : *------------------------------------------------------------------
3 : * socket_api.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_printfun
39 : #include <vlibmemory/vl_memory_api_h.h>
40 : #undef vl_printfun
41 :
42 : /* instantiate all the endian swap functions we know about */
43 : #define vl_endianfun
44 : #include <vlibmemory/vl_memory_api_h.h>
45 : #undef vl_endianfun
46 :
47 : #define vl_calcsizefun
48 : #include <vlibmemory/vl_memory_api_h.h>
49 : #undef vl_calcsizefun
50 :
51 : socket_main_t socket_main;
52 :
53 : #define SOCK_API_REG_HANDLE_BIT (1<<31)
54 :
55 : static u32
56 1761 : sock_api_registration_handle (vl_api_registration_t * regp)
57 : {
58 1761 : ASSERT (regp->vl_api_registration_pool_index < SOCK_API_REG_HANDLE_BIT);
59 1761 : return regp->vl_api_registration_pool_index | SOCK_API_REG_HANDLE_BIT;
60 : }
61 :
62 : static u32
63 426170 : socket_api_registration_handle_to_index (u32 reg_index)
64 : {
65 426170 : return (reg_index & ~SOCK_API_REG_HANDLE_BIT);
66 : }
67 :
68 : u8
69 426304 : vl_socket_api_registration_handle_is_valid (u32 reg_handle)
70 : {
71 426304 : return ((reg_handle & SOCK_API_REG_HANDLE_BIT) != 0);
72 : }
73 :
74 : void
75 0 : vl_sock_api_dump_clients (vlib_main_t * vm, api_main_t * am)
76 : {
77 : vl_api_registration_t *reg;
78 0 : socket_main_t *sm = &socket_main;
79 : clib_file_t *f;
80 :
81 : /*
82 : * Must have at least one active client, not counting the
83 : * REGISTRATION_TYPE_SOCKET_LISTEN bind/accept socket
84 : */
85 0 : if (pool_elts (sm->registration_pool) < 2)
86 0 : return;
87 :
88 0 : vlib_cli_output (vm, "Socket clients");
89 0 : vlib_cli_output (vm, "%20s %8s", "Name", "Fildesc");
90 : /* *INDENT-OFF* */
91 0 : pool_foreach (reg, sm->registration_pool)
92 : {
93 0 : if (reg->registration_type == REGISTRATION_TYPE_SOCKET_SERVER) {
94 0 : f = vl_api_registration_file (reg);
95 0 : vlib_cli_output (vm, "%20s %8d", reg->name, f->file_descriptor);
96 : }
97 : }
98 : /* *INDENT-ON* */
99 : }
100 :
101 : vl_api_registration_t *
102 425611 : vl_socket_api_client_handle_to_registration (u32 handle)
103 : {
104 425611 : socket_main_t *sm = &socket_main;
105 425611 : u32 index = socket_api_registration_handle_to_index (handle);
106 425611 : if (pool_is_free_index (sm->registration_pool, index))
107 : {
108 : #if DEBUG > 2
109 : clib_warning ("Invalid index %d\n", index);
110 : #endif
111 0 : return 0;
112 : }
113 425611 : return pool_elt_at_index (sm->registration_pool, index);
114 : }
115 :
116 : void
117 682857 : vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
118 : {
119 : #if CLIB_DEBUG > 1
120 : u32 output_length;
121 : #endif
122 682857 : socket_main_t *sm = &socket_main;
123 682857 : u16 msg_id = ntohs (*(u16 *) elem);
124 682857 : api_main_t *am = vlibapi_get_main ();
125 682857 : msgbuf_t *mb = (msgbuf_t *) (elem - offsetof (msgbuf_t, data));
126 : vl_api_registration_t *sock_rp;
127 682857 : clib_file_main_t *fm = &file_main;
128 : clib_error_t *error;
129 : clib_file_t *cf;
130 :
131 682857 : cf = vl_api_registration_file (rp);
132 682857 : ASSERT (rp->registration_type > REGISTRATION_TYPE_SHMEM);
133 :
134 682857 : if (msg_id >= vec_len (am->msg_data))
135 : {
136 0 : clib_warning ("id out of range: %d", msg_id);
137 0 : vl_msg_api_free ((void *) elem);
138 0 : return;
139 : }
140 :
141 682857 : sock_rp = pool_elt_at_index (sm->registration_pool,
142 : rp->vl_api_registration_pool_index);
143 682857 : ASSERT (sock_rp);
144 :
145 : /* Add the msgbuf_t to the output vector */
146 682857 : vec_add (sock_rp->output_vector, (u8 *) mb, sizeof (*mb));
147 :
148 : /* Try to send the message and save any error like
149 : * we do in the input epoll loop */
150 682857 : vec_add (sock_rp->output_vector, elem, ntohl (mb->data_len));
151 682857 : error = clib_file_write (cf);
152 682857 : unix_save_error (&unix_main, error);
153 :
154 : /* If we didn't finish sending everything, wait for tx space */
155 682857 : if (vec_len (sock_rp->output_vector) > 0
156 10119 : && !(cf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
157 : {
158 660 : cf->flags |= UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
159 660 : fm->file_update (cf, UNIX_FILE_UPDATE_MODIFY);
160 : }
161 :
162 : #if CLIB_DEBUG > 1
163 : output_length = sizeof (*mb) + ntohl (mb->data_len);
164 : clib_warning ("wrote %u bytes to fd %d", output_length,
165 : cf->file_descriptor);
166 : #endif
167 :
168 682857 : vl_msg_api_free ((void *) elem);
169 : }
170 :
171 : void
172 1160 : vl_socket_free_registration_index (u32 pool_index)
173 : {
174 : int i;
175 : vl_api_registration_t *rp;
176 : void vl_api_call_reaper_functions (u32 client_index);
177 :
178 1160 : if (pool_is_free_index (socket_main.registration_pool, pool_index))
179 : {
180 0 : clib_warning ("main pool index %d already free", pool_index);
181 0 : return;
182 : }
183 1160 : rp = pool_elt_at_index (socket_main.registration_pool, pool_index);
184 :
185 1160 : vl_api_call_reaper_functions (
186 : clib_host_to_net_u32 (sock_api_registration_handle (rp)));
187 :
188 1160 : ASSERT (rp->registration_type != REGISTRATION_TYPE_FREE);
189 1202 : for (i = 0; i < vec_len (rp->additional_fds_to_close); i++)
190 42 : if (close (rp->additional_fds_to_close[i]) < 0)
191 0 : clib_unix_warning ("close");
192 1160 : vec_free (rp->additional_fds_to_close);
193 1160 : vec_free (rp->name);
194 1160 : vec_free (rp->unprocessed_input);
195 1160 : vec_free (rp->output_vector);
196 1160 : rp->registration_type = REGISTRATION_TYPE_FREE;
197 1160 : pool_put (socket_main.registration_pool, rp);
198 : }
199 :
200 : void
201 425558 : vl_socket_process_api_msg (vl_api_registration_t * rp, i8 * input_v)
202 : {
203 425558 : msgbuf_t *mbp = (msgbuf_t *) input_v;
204 :
205 425558 : u8 *the_msg = (u8 *) (mbp->data);
206 425558 : socket_main.current_rp = rp;
207 425558 : vl_msg_api_socket_handler (the_msg, ntohl (mbp->data_len));
208 425558 : socket_main.current_rp = 0;
209 425558 : }
210 :
211 : int
212 1103350 : is_being_removed_reg_index (u32 reg_index)
213 : {
214 1103350 : vl_api_registration_t *rp = vl_socket_get_registration (reg_index);
215 1103350 : ALWAYS_ASSERT (rp != 0);
216 1103350 : return (rp->is_being_removed);
217 : }
218 :
219 : static void
220 42 : socket_cleanup_pending_remove_registration_cb (u32 *preg_index)
221 : {
222 42 : vl_api_registration_t *rp = vl_socket_get_registration (*preg_index);
223 42 : if (!rp)
224 : {
225 : /* Might already have gone */
226 0 : return;
227 : }
228 :
229 42 : clib_file_main_t *fm = &file_main;
230 42 : u32 pending_remove_file_index = vl_api_registration_file_index (rp);
231 :
232 42 : clib_file_t *zf = fm->file_pool + pending_remove_file_index;
233 :
234 42 : clib_file_del (fm, zf);
235 42 : vl_socket_free_registration_index (rp - socket_main.registration_pool);
236 : }
237 :
238 : static void
239 42 : vl_socket_request_remove_reg_index (u32 reg_index)
240 : {
241 42 : vl_api_registration_t *rp = vl_socket_get_registration (reg_index);
242 42 : ALWAYS_ASSERT (rp != 0);
243 42 : if (rp->is_being_removed)
244 : {
245 0 : return;
246 : }
247 42 : rp->is_being_removed = 1;
248 42 : vl_api_force_rpc_call_main_thread (
249 : socket_cleanup_pending_remove_registration_cb, (void *) ®_index,
250 : sizeof (u32));
251 : }
252 :
253 : /*
254 : * Read function for API socket.
255 : *
256 : * Read data from socket, invoke SOCKET_READ_EVENT
257 : * for each fully read API message, return 0.
258 : * Store incomplete data for next invocation to continue.
259 : *
260 : * On severe read error, the file is closed.
261 : *
262 : * As reading is single threaded,
263 : * socket_main.input_buffer is used temporarily.
264 : * Even its length is modified, but always restored before return.
265 : *
266 : * Incomplete data is copied into a vector,
267 : * pointer saved in registration's unprocessed_input.
268 : */
269 : clib_error_t *
270 419736 : vl_socket_read_ready (clib_file_t * uf)
271 : {
272 419736 : vlib_main_t *vm = vlib_get_main ();
273 : vl_api_registration_t *rp;
274 : /* n is the size of data read to input_buffer */
275 : int n;
276 : /* msg_buffer vector can point to input_buffer or unprocessed_input */
277 419736 : i8 *msg_buffer = 0;
278 : /* data_for_process is a vector containing one full message, incl msgbuf_t */
279 : u8 *data_for_process;
280 : /* msgbuf_len is the size of one message, including sizeof (msgbuf_t) */
281 : u32 msgbuf_len;
282 419736 : u32 save_input_buffer_length = vec_len (socket_main.input_buffer);
283 : vl_socket_args_for_process_t *a;
284 419736 : u32 reg_index = uf->private_data;
285 419736 : if (is_being_removed_reg_index (reg_index))
286 : {
287 0 : return 0;
288 : }
289 :
290 419736 : rp = vl_socket_get_registration (reg_index);
291 :
292 : /* Ignore unprocessed_input for now, n describes input_buffer for now. */
293 419736 : n = read (uf->file_descriptor, socket_main.input_buffer,
294 419736 : vec_len (socket_main.input_buffer));
295 :
296 419736 : if (n <= 0)
297 : {
298 42 : if (errno != EAGAIN)
299 : {
300 : /* Severe error, close the file. */
301 42 : vl_socket_request_remove_reg_index (reg_index);
302 : }
303 : /* EAGAIN means we do not close the file, but no data to process anyway. */
304 42 : return 0;
305 : }
306 :
307 : /* Fake smaller length teporarily, so input_buffer can be used as msg_buffer. */
308 419694 : vec_set_len (socket_main.input_buffer, n);
309 :
310 : /*
311 : * Look for bugs here. This code is tricky because
312 : * data read from a stream socket does not honor message
313 : * boundaries. In the case of a long message (>4K bytes)
314 : * we have to do (at least) 2 reads, etc.
315 : */
316 : /* Determine msg_buffer. */
317 419694 : if (vec_len (rp->unprocessed_input))
318 : {
319 6599 : vec_append (rp->unprocessed_input, socket_main.input_buffer);
320 6599 : msg_buffer = rp->unprocessed_input;
321 : }
322 : else
323 : {
324 413095 : msg_buffer = socket_main.input_buffer;
325 : }
326 : /* Loop to process any full messages. */
327 419694 : ASSERT (vec_len (msg_buffer) > 0);
328 : do
329 : {
330 : /* Here, we are not sure how big a chunk of message we have left. */
331 : /* Do we at least know how big the full message will be? */
332 432157 : if (vec_len (msg_buffer) <= sizeof (msgbuf_t))
333 : /* No, so fragment is not a full message. */
334 6549 : goto save_and_split;
335 :
336 : /* Now we know how big the full message will be. */
337 425608 : msgbuf_len =
338 425608 : ntohl (((msgbuf_t *) msg_buffer)->data_len) + sizeof (msgbuf_t);
339 :
340 : /* But do we have a full message? */
341 425608 : if (msgbuf_len > vec_len (msg_buffer))
342 : {
343 50 : save_and_split:
344 : /* We don't have the entire message yet. */
345 : /* If msg_buffer is unprocessed_input, nothing needs to be done. */
346 6599 : if (msg_buffer == socket_main.input_buffer)
347 : /* But if we were using the input buffer, save the fragment. */
348 : {
349 6566 : ASSERT (vec_len (rp->unprocessed_input) == 0);
350 6566 : vec_validate (rp->unprocessed_input, vec_len (msg_buffer) - 1);
351 13132 : clib_memcpy_fast (rp->unprocessed_input, msg_buffer,
352 6566 : vec_len (msg_buffer));
353 6566 : vec_set_len (rp->unprocessed_input, vec_len (msg_buffer));
354 : }
355 : /* No more full messages, restore original input_buffer length. */
356 6599 : vec_set_len (socket_main.input_buffer, save_input_buffer_length);
357 6599 : return 0;
358 : }
359 :
360 : /*
361 : * We have at least one full message.
362 : * But msg_buffer can contain more data, so copy one message data
363 : * so we can overwrite its length to what single message has.
364 : */
365 425558 : data_for_process = (u8 *) vec_dup (msg_buffer);
366 425558 : vec_set_len (data_for_process, msgbuf_len);
367 : /* Everything is ready to signal the SOCKET_READ_EVENT. */
368 425558 : pool_get (socket_main.process_args, a);
369 425558 : a->reg_index = reg_index;
370 425558 : a->data = data_for_process;
371 :
372 425558 : vlib_process_signal_event (vm, vl_api_clnt_node.index,
373 : SOCKET_READ_EVENT,
374 425558 : a - socket_main.process_args);
375 425558 : if (vec_len (msg_buffer) > msgbuf_len)
376 : /* There are some fragments left. Shrink the msg_buffer to simplify logic. */
377 12463 : vec_delete (msg_buffer, msgbuf_len, 0);
378 : else
379 : /* We are done with msg_buffer. */
380 413095 : vec_set_len (msg_buffer, 0);
381 : }
382 425558 : while (vec_len (msg_buffer) > 0);
383 :
384 : /* Restore input_buffer, it could have been msg_buffer. */
385 413095 : vec_set_len (socket_main.input_buffer, save_input_buffer_length);
386 413095 : return 0;
387 : }
388 :
389 : clib_error_t *
390 683614 : vl_socket_write_ready (clib_file_t * uf)
391 : {
392 683614 : clib_file_main_t *fm = &file_main;
393 : vl_api_registration_t *rp;
394 : int n;
395 :
396 683614 : u32 reg_index = uf->private_data;
397 683614 : if (is_being_removed_reg_index (reg_index))
398 : {
399 0 : return 0;
400 : }
401 :
402 683614 : rp = pool_elt_at_index (socket_main.registration_pool, reg_index);
403 :
404 : /* Flush output vector. */
405 683614 : size_t total_bytes = vec_len (rp->output_vector);
406 683614 : size_t bytes_to_send, remaining_bytes = total_bytes;
407 683614 : void *p = rp->output_vector;
408 1594400 : while (remaining_bytes > 0)
409 : {
410 921093 : bytes_to_send = remaining_bytes > 4096 ? 4096 : remaining_bytes;
411 921093 : n = send (uf->file_descriptor, p, bytes_to_send, MSG_NOSIGNAL);
412 921093 : if (n < 0)
413 : {
414 10303 : if (errno == EAGAIN)
415 : {
416 10303 : break;
417 : }
418 : #if DEBUG > 2
419 : clib_warning ("write error, close the file...\n");
420 : #endif
421 0 : vl_socket_request_remove_reg_index (reg_index);
422 0 : return 0;
423 : }
424 910790 : remaining_bytes -= bytes_to_send;
425 910790 : p += bytes_to_send;
426 : }
427 :
428 683614 : vec_delete (rp->output_vector, total_bytes - remaining_bytes, 0);
429 683614 : if (vec_len (rp->output_vector) <= 0
430 673311 : && (uf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
431 : {
432 660 : uf->flags &= ~UNIX_FILE_DATA_AVAILABLE_TO_WRITE;
433 660 : fm->file_update (uf, UNIX_FILE_UPDATE_MODIFY);
434 : }
435 :
436 683614 : return 0;
437 : }
438 :
439 : clib_error_t *
440 0 : vl_socket_error_ready (clib_file_t * uf)
441 : {
442 0 : u32 reg_index = uf->private_data;
443 0 : vl_socket_request_remove_reg_index (reg_index);
444 0 : return 0;
445 : }
446 :
447 : void
448 601 : socksvr_file_add (clib_file_main_t * fm, int fd)
449 : {
450 : vl_api_registration_t *rp;
451 601 : clib_file_t template = { 0 };
452 :
453 601 : pool_get (socket_main.registration_pool, rp);
454 601 : clib_memset (rp, 0, sizeof (*rp));
455 :
456 601 : template.read_function = vl_socket_read_ready;
457 601 : template.write_function = vl_socket_write_ready;
458 601 : template.error_function = vl_socket_error_ready;
459 601 : template.file_descriptor = fd;
460 601 : template.description = format (0, "socksrv");
461 601 : template.private_data = rp - socket_main.registration_pool;
462 :
463 601 : rp->registration_type = REGISTRATION_TYPE_SOCKET_SERVER;
464 601 : rp->vl_api_registration_pool_index = rp - socket_main.registration_pool;
465 601 : rp->clib_file_index = clib_file_add (fm, &template);
466 601 : }
467 :
468 : static clib_error_t *
469 601 : socksvr_accept_ready (clib_file_t * uf)
470 : {
471 601 : clib_file_main_t *fm = &file_main;
472 601 : socket_main_t *sm = &socket_main;
473 601 : clib_socket_t *sock = &sm->socksvr_listen_socket;
474 : clib_socket_t client;
475 : clib_error_t *error;
476 :
477 601 : error = clib_socket_accept (sock, &client);
478 601 : if (error)
479 0 : return error;
480 :
481 601 : socksvr_file_add (fm, client.fd);
482 601 : return 0;
483 : }
484 :
485 : static clib_error_t *
486 0 : socksvr_bogus_write (clib_file_t * uf)
487 : {
488 0 : clib_warning ("why am I here?");
489 0 : return 0;
490 : }
491 :
492 : /*
493 : * vl_api_sockclnt_create_t_handler
494 : */
495 : void
496 601 : vl_api_sockclnt_create_t_handler (vl_api_sockclnt_create_t * mp)
497 : {
498 : vl_api_registration_t *regp;
499 : vl_api_sockclnt_create_reply_t *rp;
500 601 : api_main_t *am = vlibapi_get_main ();
501 : hash_pair_t *hp;
502 601 : int rv = 0;
503 601 : u32 nmsg = hash_elts (am->msg_index_by_name_and_crc);
504 601 : u32 i = 0;
505 :
506 601 : regp = socket_main.current_rp;
507 :
508 : /* client already connected through shared memory? */
509 601 : if (!regp || regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
510 : {
511 0 : clib_warning (
512 : "unsupported API call: already connected though shared memory?");
513 0 : return;
514 : }
515 :
516 601 : regp->name = format (0, "%s%c", mp->name, 0);
517 :
518 601 : u32 size = sizeof (*rp) + (nmsg * sizeof (vl_api_message_table_entry_t));
519 601 : rp = vl_msg_api_alloc_zero (size);
520 601 : rp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE_REPLY);
521 601 : rp->index = htonl (sock_api_registration_handle (regp));
522 601 : rp->context = mp->context;
523 601 : rp->response = htonl (rv);
524 601 : rp->count = htons (nmsg);
525 :
526 : /* *INDENT-OFF* */
527 3508670 : hash_foreach_pair (hp, am->msg_index_by_name_and_crc,
528 : ({
529 : rp->message_table[i].index = htons(hp->value[0]);
530 : (void) strncpy_s((char *)rp->message_table[i].name,
531 : 64 /* bytes of space at dst */,
532 : (char *)hp->key,
533 : 64-1 /* chars to copy, without zero byte. */);
534 : i++;
535 : }));
536 : /* *INDENT-ON* */
537 601 : vl_api_send_msg (regp, (u8 *) rp);
538 : }
539 :
540 : /*
541 : * vl_api_sockclnt_delete_t_handler
542 : */
543 : void
544 559 : vl_api_sockclnt_delete_t_handler (vl_api_sockclnt_delete_t * mp)
545 : {
546 : vl_api_registration_t *regp;
547 : vl_api_sockclnt_delete_reply_t *rp;
548 :
549 559 : regp = vl_api_client_index_to_registration (mp->client_index);
550 559 : if (!regp)
551 0 : return;
552 :
553 559 : u32 reg_index = socket_api_registration_handle_to_index (ntohl (mp->index));
554 559 : rp = vl_msg_api_alloc (sizeof (*rp));
555 559 : rp->_vl_msg_id = htons (VL_API_SOCKCLNT_DELETE_REPLY);
556 559 : rp->context = mp->context;
557 :
558 559 : if (!pool_is_free_index (socket_main.registration_pool, reg_index))
559 : {
560 559 : rp->response = htonl (1);
561 559 : vl_api_send_msg (regp, (u8 *) rp);
562 :
563 559 : vl_api_registration_del_file (regp);
564 559 : vl_socket_free_registration_index (reg_index);
565 : }
566 : else
567 : {
568 0 : clib_warning ("unknown client ID %d", reg_index);
569 0 : rp->response = htonl (-1);
570 0 : vl_api_send_msg (regp, (u8 *) rp);
571 : }
572 : }
573 :
574 : clib_error_t *
575 115 : vl_sock_api_send_fd_msg (int socket_fd, int fds[], int n_fds)
576 115 : {
577 115 : struct msghdr mh = { 0 };
578 : struct iovec iov[1];
579 115 : char ctl[CMSG_SPACE (sizeof (int) * n_fds)];
580 : struct cmsghdr *cmsg;
581 115 : char *msg = "fdmsg";
582 : int rv;
583 :
584 115 : iov[0].iov_base = msg;
585 115 : iov[0].iov_len = strlen (msg);
586 115 : mh.msg_iov = iov;
587 115 : mh.msg_iovlen = 1;
588 :
589 115 : clib_memset (&ctl, 0, sizeof (ctl));
590 115 : mh.msg_control = ctl;
591 115 : mh.msg_controllen = sizeof (ctl);
592 115 : cmsg = CMSG_FIRSTHDR (&mh);
593 115 : cmsg->cmsg_len = CMSG_LEN (sizeof (int) * n_fds);
594 115 : cmsg->cmsg_level = SOL_SOCKET;
595 115 : cmsg->cmsg_type = SCM_RIGHTS;
596 115 : clib_memcpy_fast (CMSG_DATA (cmsg), fds, sizeof (int) * n_fds);
597 :
598 115 : while ((rv = sendmsg (socket_fd, &mh, 0)) < 0 && errno == EAGAIN)
599 : ;
600 115 : if (rv < 0)
601 0 : return clib_error_return_unix (0, "sendmsg");
602 115 : return 0;
603 : }
604 :
605 : vl_api_shm_elem_config_t *
606 42 : vl_api_make_shm_config (vl_api_sock_init_shm_t * mp)
607 : {
608 42 : vl_api_shm_elem_config_t *config = 0, *c;
609 : u64 cfg;
610 : int i;
611 :
612 42 : if (!mp->nitems)
613 : {
614 42 : vec_validate (config, 6);
615 42 : config[0].type = VL_API_VLIB_RING;
616 42 : config[0].size = 256;
617 42 : config[0].count = 32;
618 :
619 42 : config[1].type = VL_API_VLIB_RING;
620 42 : config[1].size = 1024;
621 42 : config[1].count = 16;
622 :
623 42 : config[2].type = VL_API_VLIB_RING;
624 42 : config[2].size = 4096;
625 42 : config[2].count = 2;
626 :
627 42 : config[3].type = VL_API_CLIENT_RING;
628 42 : config[3].size = 256;
629 42 : config[3].count = 32;
630 :
631 42 : config[4].type = VL_API_CLIENT_RING;
632 42 : config[4].size = 1024;
633 42 : config[4].count = 16;
634 :
635 42 : config[5].type = VL_API_CLIENT_RING;
636 42 : config[5].size = 4096;
637 42 : config[5].count = 2;
638 :
639 42 : config[6].type = VL_API_QUEUE;
640 42 : config[6].count = 128;
641 42 : config[6].size = sizeof (uword);
642 : }
643 : else
644 : {
645 0 : vec_validate (config, mp->nitems - 1);
646 0 : for (i = 0; i < mp->nitems; i++)
647 : {
648 0 : cfg = mp->configs[i];
649 : /* Pretty much a hack but it avoids defining our own api type
650 : * in memclnt.api */
651 0 : c = (vl_api_shm_elem_config_t *) & cfg;
652 0 : config[i].type = c->type;
653 0 : config[i].count = c->count;
654 0 : config[i].size = c->size;
655 : }
656 : }
657 42 : return config;
658 : }
659 :
660 : /*
661 : * Bootstrap shm api using the socket api
662 : */
663 : void
664 42 : vl_api_sock_init_shm_t_handler (vl_api_sock_init_shm_t * mp)
665 : {
666 : vl_api_sock_init_shm_reply_t *rmp;
667 42 : ssvm_private_t _memfd_private, *memfd = &_memfd_private;
668 42 : svm_map_region_args_t _args, *a = &_args;
669 : vl_api_registration_t *regp;
670 42 : api_main_t *am = vlibapi_get_main ();
671 : svm_region_t *vlib_rp;
672 : clib_file_t *cf;
673 42 : vl_api_shm_elem_config_t *config = 0;
674 : vl_shmem_hdr_t *shmem_hdr;
675 42 : int rv, tries = 1000;
676 :
677 42 : regp = vl_api_client_index_to_registration (mp->client_index);
678 42 : if (regp == 0)
679 : {
680 0 : clib_warning ("API client disconnected");
681 0 : return;
682 : }
683 42 : if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
684 : {
685 0 : clib_warning ("Invalid registration");
686 0 : return;
687 : }
688 :
689 : /*
690 : * Set up a memfd segment of the requested size wherein the
691 : * shmem data structures will be initialized
692 : */
693 42 : clib_memset (memfd, 0, sizeof (*memfd));
694 42 : memfd->ssvm_size = mp->requested_size;
695 42 : memfd->requested_va = 0ULL;
696 42 : memfd->is_server = 1;
697 42 : memfd->name = format (0, "%s%c", regp->name, 0);
698 :
699 42 : if ((rv = ssvm_server_init_memfd (memfd)))
700 0 : goto reply;
701 :
702 : /* delete the unused heap created in ssvm_server_init_memfd and mark it
703 : * accessible again for ASAN */
704 42 : clib_mem_destroy_heap (memfd->sh->heap);
705 42 : clib_mem_unpoison ((void *) memfd->sh->ssvm_va, memfd->ssvm_size);
706 :
707 : /* Remember to close this fd when the socket connection goes away */
708 42 : vec_add1 (regp->additional_fds_to_close, memfd->fd);
709 :
710 : /*
711 : * Create a plausible svm_region in the memfd backed segment
712 : */
713 42 : clib_memset (a, 0, sizeof (*a));
714 42 : a->baseva = memfd->sh->ssvm_va + MMAP_PAGESIZE;
715 42 : a->size = memfd->ssvm_size - MMAP_PAGESIZE;
716 : /* $$$$ might want a different config parameter */
717 42 : a->pvt_heap_size = am->api_pvt_heap_size;
718 42 : a->flags = SVM_FLAGS_MHEAP;
719 42 : svm_region_init_mapped_region (a, (svm_region_t *) a->baseva);
720 :
721 : /*
722 : * Part deux, initialize the svm_region_t shared-memory header
723 : * api allocation rings, and so on.
724 : */
725 42 : config = vl_api_make_shm_config (mp);
726 42 : vlib_rp = (svm_region_t *) a->baseva;
727 42 : vl_init_shmem (vlib_rp, config, 1 /* is_vlib (dont-care) */ ,
728 : 1 /* is_private */ );
729 :
730 : /* Remember who created this. Needs to be post vl_init_shmem */
731 42 : shmem_hdr = (vl_shmem_hdr_t *) vlib_rp->user_ctx;
732 42 : shmem_hdr->clib_file_index = vl_api_registration_file_index (regp);
733 :
734 42 : vec_add1 (am->vlib_private_rps, vlib_rp);
735 42 : memfd->sh->ready = 1;
736 42 : vec_free (config);
737 :
738 : /* Recompute the set of input queues to poll in memclnt_process */
739 42 : vec_reset_length (vl_api_queue_cursizes);
740 :
741 0 : reply:
742 :
743 42 : rmp = vl_msg_api_alloc (sizeof (*rmp));
744 42 : rmp->_vl_msg_id = htons (VL_API_SOCK_INIT_SHM_REPLY);
745 42 : rmp->context = mp->context;
746 42 : rmp->retval = htonl (rv);
747 :
748 : /*
749 : * Note: The reply message needs to make it out the back door
750 : * before we send the magic fd message. That's taken care of by
751 : * the send function.
752 : */
753 42 : vl_socket_api_send (regp, (u8 *) rmp);
754 :
755 42 : if (rv != 0)
756 0 : return;
757 :
758 : /* Send the magic "here's your sign (aka fd)" socket message */
759 42 : cf = vl_api_registration_file (regp);
760 42 : if (!cf)
761 : {
762 0 : clib_warning ("cf removed");
763 0 : return;
764 : }
765 :
766 : /* Wait for reply to be consumed before sending the fd */
767 60 : while (tries-- > 0)
768 : {
769 : int bytes;
770 60 : rv = ioctl (cf->file_descriptor, TIOCOUTQ, &bytes);
771 60 : if (rv < 0)
772 : {
773 0 : clib_unix_warning ("ioctl returned");
774 42 : break;
775 : }
776 60 : if (bytes == 0)
777 42 : break;
778 18 : usleep (1e3);
779 : }
780 :
781 42 : vl_sock_api_send_fd_msg (cf->file_descriptor, &memfd->fd, 1);
782 : }
783 :
784 : #define foreach_vlib_api_msg \
785 : _ (SOCKCLNT_CREATE, sockclnt_create, 0) \
786 : _ (SOCKCLNT_DELETE, sockclnt_delete, 0) \
787 : _ (SOCK_INIT_SHM, sock_init_shm, 0)
788 :
789 : clib_error_t *
790 559 : vl_sock_api_init (vlib_main_t * vm)
791 : {
792 559 : api_main_t *am = vlibapi_get_main ();
793 559 : clib_file_main_t *fm = &file_main;
794 559 : clib_file_t template = { 0 };
795 : vl_api_registration_t *rp;
796 559 : socket_main_t *sm = &socket_main;
797 559 : clib_socket_t *sock = &sm->socksvr_listen_socket;
798 : clib_error_t *error;
799 :
800 : /* If not explicitly configured, do not bind/enable, etc. */
801 559 : if (sm->socket_name == 0)
802 0 : return 0;
803 :
804 : #define _(N, n, t) \
805 : vl_msg_api_config (&(vl_msg_api_msg_config_t){ \
806 : .id = VL_API_##N, \
807 : .name = #n, \
808 : .handler = vl_api_##n##_t_handler, \
809 : .endian = vl_api_##n##_t_endian, \
810 : .format_fn = vl_api_##n##_t_format, \
811 : .size = sizeof (vl_api_##n##_t), \
812 : .traced = t, \
813 : .tojson = vl_api_##n##_t_tojson, \
814 : .fromjson = vl_api_##n##_t_fromjson, \
815 : .calc_size = vl_api_##n##_t_calc_size, \
816 : }); \
817 : am->msg_data[VL_API_##N].replay_allowed = 0;
818 559 : foreach_vlib_api_msg;
819 : #undef _
820 :
821 559 : vec_resize (sm->input_buffer, 4096);
822 :
823 559 : sock->config = (char *) sm->socket_name;
824 559 : sock->flags = CLIB_SOCKET_F_IS_SERVER | CLIB_SOCKET_F_ALLOW_GROUP_WRITE;
825 559 : error = clib_socket_init (sock);
826 559 : if (error)
827 0 : return error;
828 :
829 559 : pool_get (sm->registration_pool, rp);
830 559 : clib_memset (rp, 0, sizeof (*rp));
831 :
832 559 : rp->registration_type = REGISTRATION_TYPE_SOCKET_LISTEN;
833 :
834 559 : template.read_function = socksvr_accept_ready;
835 559 : template.write_function = socksvr_bogus_write;
836 559 : template.file_descriptor = sock->fd;
837 559 : template.description = format (0, "socksvr %s", sock->config);
838 559 : template.private_data = rp - sm->registration_pool;
839 :
840 559 : rp->clib_file_index = clib_file_add (fm, &template);
841 559 : return 0;
842 : }
843 :
844 : static clib_error_t *
845 559 : socket_exit (vlib_main_t * vm)
846 : {
847 559 : socket_main_t *sm = &socket_main;
848 : vl_api_registration_t *rp;
849 :
850 : /* Defensive driving in case something wipes out early */
851 559 : if (sm->registration_pool)
852 : {
853 : u32 index;
854 : /* *INDENT-OFF* */
855 1118 : pool_foreach (rp, sm->registration_pool) {
856 559 : vl_api_registration_del_file (rp);
857 559 : index = rp->vl_api_registration_pool_index;
858 559 : vl_socket_free_registration_index (index);
859 : }
860 : /* *INDENT-ON* */
861 : }
862 :
863 559 : return 0;
864 : }
865 :
866 3355 : VLIB_MAIN_LOOP_EXIT_FUNCTION (socket_exit);
867 :
868 : static clib_error_t *
869 559 : socksvr_config (vlib_main_t * vm, unformat_input_t * input)
870 : {
871 559 : socket_main_t *sm = &socket_main;
872 :
873 1118 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
874 : {
875 559 : if (unformat (input, "socket-name %s", &sm->socket_name))
876 : ;
877 : /* DEPRECATE: default keyword is ignored */
878 0 : else if (unformat (input, "default"))
879 : ;
880 : else
881 : {
882 0 : return clib_error_return (0, "unknown input '%U'",
883 : format_unformat_error, input);
884 : }
885 : }
886 :
887 559 : if (!vec_len (sm->socket_name))
888 0 : sm->socket_name = format (0, "%s/%s", vlib_unix_get_runtime_dir (),
889 : API_SOCKET_FILENAME);
890 559 : vec_terminate_c_string (sm->socket_name);
891 :
892 559 : return 0;
893 : }
894 :
895 7306 : VLIB_CONFIG_FUNCTION (socksvr_config, "socksvr");
896 :
897 : void
898 559 : vlibsocket_reference ()
899 : {
900 559 : }
901 :
902 : /*
903 : * fd.io coding-style-patch-verification: ON
904 : *
905 : * Local Variables:
906 : * eval: (c-set-style "gnu")
907 : * End:
908 : */
|