FD.io VPP  v21.06
Vector Packet Processing
socket_client.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * socket_client.c - API message handling over sockets, client code.
4  *
5  * Copyright (c) 2017 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 #define __USE_GNU
22 #define _GNU_SOURCE
23 #include <sys/socket.h>
24 
25 #include <svm/ssvm.h>
28 
30 
31 #define vl_typedefs /* define message structures */
33 #undef vl_typedefs
34 
35 #define vl_endianfun /* define message structures */
37 #undef vl_endianfun
38 
39 /* instantiate all the print functions we know about */
40 #define vl_print(handle, ...) clib_warning (__VA_ARGS__)
41 #define vl_printfun
43 #undef vl_printfun
44 
47 
48 /* Debug aid */
49 u32 vl (void *p) __attribute__ ((weak));
50 
51 u32
52 vl (void *p)
53 {
54  return vec_len (p);
55 }
56 
57 static socket_client_main_t *
59 {
61  socket_client_ctx = ctx;
62  return old;
63 }
64 
65 static void
67 {
68  socket_client_ctx = old_ctx;
69 }
70 
71 static int
73 {
74  u32 data_len = 0, msg_size;
75  int n, current_rx_index;
76  msgbuf_t *mbp = 0;
77  f64 timeout;
78 
79  if (scm->socket_fd == 0)
80  return -1;
81 
82  if (wait)
83  timeout = clib_time_now (&scm->clib_time) + wait;
84 
85  while (1)
86  {
87  while (vec_len (scm->socket_rx_buffer) < sizeof (*mbp))
88  {
89  current_rx_index = vec_len (scm->socket_rx_buffer);
90  vec_validate (scm->socket_rx_buffer, current_rx_index
91  + scm->socket_buffer_size - 1);
92  _vec_len (scm->socket_rx_buffer) = current_rx_index;
93  n = read (scm->socket_fd, scm->socket_rx_buffer + current_rx_index,
94  scm->socket_buffer_size);
95  if (n < 0)
96  {
97  if (errno == EAGAIN)
98  continue;
99 
100  clib_unix_warning ("socket_read");
101  return -1;
102  }
103  _vec_len (scm->socket_rx_buffer) += n;
104  }
105 
106 #if CLIB_DEBUG > 1
107  if (n > 0)
108  clib_warning ("read %d bytes", n);
109 #endif
110 
111  mbp = (msgbuf_t *) (scm->socket_rx_buffer);
112  data_len = ntohl (mbp->data_len);
113  current_rx_index = vec_len (scm->socket_rx_buffer);
114  vec_validate (scm->socket_rx_buffer, current_rx_index + data_len);
115  _vec_len (scm->socket_rx_buffer) = current_rx_index;
116  mbp = (msgbuf_t *) (scm->socket_rx_buffer);
117  msg_size = data_len + sizeof (*mbp);
118 
119  while (vec_len (scm->socket_rx_buffer) < msg_size)
120  {
121  n = read (scm->socket_fd,
123  msg_size - vec_len (scm->socket_rx_buffer));
124  if (n < 0)
125  {
126  if (errno == EAGAIN)
127  continue;
128 
129  clib_unix_warning ("socket_read");
130  return -1;
131  }
132  _vec_len (scm->socket_rx_buffer) += n;
133  }
134 
135  if (vec_len (scm->socket_rx_buffer) >= data_len + sizeof (*mbp))
136  {
137  vl_msg_api_socket_handler ((void *) (mbp->data));
138 
139  if (vec_len (scm->socket_rx_buffer) == data_len + sizeof (*mbp))
140  _vec_len (scm->socket_rx_buffer) = 0;
141  else
142  vec_delete (scm->socket_rx_buffer, data_len + sizeof (*mbp), 0);
143  mbp = 0;
144 
145  /* Quit if we're out of data, and not expecting a ping reply */
146  if (vec_len (scm->socket_rx_buffer) == 0
147  && scm->control_pings_outstanding == 0)
148  break;
149  }
150  if (wait && clib_time_now (&scm->clib_time) >= timeout)
151  return -1;
152  }
153  return 0;
154 }
155 
156 int
158 {
159  return vl_socket_client_read_internal (socket_client_ctx, wait);
160 }
161 
162 int
164 {
165  socket_client_main_t *old_ctx;
166  int rv;
167 
168  old_ctx = vl_socket_client_ctx_push (scm);
169  rv = vl_socket_client_read_internal (scm, wait);
170  vl_socket_client_ctx_pop (old_ctx);
171  return rv;
172 }
173 
174 static int
176 {
177  int n;
178 
179  msgbuf_t msgbuf = {
180  .q = 0,
181  .gc_mark_timestamp = 0,
182  .data_len = htonl (scm->socket_tx_nbytes),
183  };
184 
185  n = write (scm->socket_fd, &msgbuf, sizeof (msgbuf));
186  if (n < sizeof (msgbuf))
187  {
188  clib_unix_warning ("socket write (msgbuf)");
189  return -1;
190  }
191 
192  n = write (scm->socket_fd, scm->socket_tx_buffer, scm->socket_tx_nbytes);
193  if (n < scm->socket_tx_nbytes)
194  {
195  clib_unix_warning ("socket write (msg)");
196  return -1;
197  }
198 
199  return n;
200 }
201 
202 int
204 {
205  return vl_socket_client_write_internal (socket_client_ctx);
206 }
207 
208 int
210 {
211  socket_client_main_t *old_ctx;
212  int rv;
213 
214  old_ctx = vl_socket_client_ctx_push (scm);
216  vl_socket_client_ctx_pop (old_ctx);
217  return rv;
218 }
219 
220 void *
222 {
223  scm->socket_tx_nbytes = nbytes;
224  return ((void *) scm->socket_tx_buffer);
225 }
226 
227 void *
229 {
230  return vl_socket_client_msg_alloc2 (socket_client_ctx, nbytes);
231 }
232 
233 void
235 {
237  {
240  }
241  if (scm->socket_fd && (close (scm->socket_fd) < 0))
242  clib_unix_warning ("close");
243  scm->socket_fd = 0;
244 }
245 
246 void
248 {
249  vl_socket_client_disconnect2 (socket_client_ctx);
250 }
251 
252 void
254 {
255  scm->socket_enable = enable;
256 }
257 
258 void
260 {
261  vl_socket_client_enable_disable2 (socket_client_ctx, enable);
262 }
263 
264 static clib_error_t *
266  int n_fds, u32 wait)
267 {
268  char msgbuf[16];
269  char ctl[CMSG_SPACE (sizeof (int) * n_fds)
270  + CMSG_SPACE (sizeof (struct ucred))];
271  struct msghdr mh = { 0 };
272  struct iovec iov[1];
273  ssize_t size = 0;
274  struct ucred *cr = 0;
275  struct cmsghdr *cmsg;
276  pid_t pid __attribute__ ((unused));
277  uid_t uid __attribute__ ((unused));
278  gid_t gid __attribute__ ((unused));
279  int socket_fd;
280  f64 timeout;
281 
282  socket_fd = scm->client_socket.fd;
283 
284  iov[0].iov_base = msgbuf;
285  iov[0].iov_len = 5;
286  mh.msg_iov = iov;
287  mh.msg_iovlen = 1;
288  mh.msg_control = ctl;
289  mh.msg_controllen = sizeof (ctl);
290 
291  clib_memset (ctl, 0, sizeof (ctl));
292 
293  if (wait != ~0)
294  {
295  timeout = clib_time_now (&scm->clib_time) + wait;
296  while (size != 5 && clib_time_now (&scm->clib_time) < timeout)
297  size = recvmsg (socket_fd, &mh, MSG_DONTWAIT);
298  }
299  else
300  size = recvmsg (socket_fd, &mh, 0);
301 
302  if (size != 5)
303  {
304  return (size == 0) ? clib_error_return (0, "disconnected") :
305  clib_error_return_unix (0, "recvmsg: malformed message (fd %d)",
306  socket_fd);
307  }
308 
309  cmsg = CMSG_FIRSTHDR (&mh);
310  while (cmsg)
311  {
312  if (cmsg->cmsg_level == SOL_SOCKET)
313  {
314  if (cmsg->cmsg_type == SCM_CREDENTIALS)
315  {
316  cr = (struct ucred *) CMSG_DATA (cmsg);
317  uid = cr->uid;
318  gid = cr->gid;
319  pid = cr->pid;
320  }
321  else if (cmsg->cmsg_type == SCM_RIGHTS)
322  {
323  clib_memcpy_fast (fds, CMSG_DATA (cmsg), sizeof (int) * n_fds);
324  }
325  }
326  cmsg = CMSG_NXTHDR (&mh, cmsg);
327  }
328  return 0;
329 }
330 
331 clib_error_t *
332 vl_sock_api_recv_fd_msg (int socket_fd, int fds[], int n_fds, u32 wait)
333 {
334  return vl_sock_api_recv_fd_msg_internal (socket_client_ctx, fds, n_fds,
335  wait);
336 }
337 
338 clib_error_t *
340  int fds[], int n_fds, u32 wait)
341 {
342  socket_client_main_t *old_ctx;
344 
345  old_ctx = vl_socket_client_ctx_push (scm);
346  error = vl_sock_api_recv_fd_msg_internal (scm, fds, n_fds, wait);
347  vl_socket_client_ctx_pop (old_ctx);
348  return error;
349 }
350 
353 {
355  ssvm_private_t *memfd = &scm->memfd_segment;
356  i32 retval = ntohl (mp->retval);
359  int my_fd = -1;
360  u8 *new_name;
361 
362  if (retval)
363  {
364  clib_warning ("failed to init shmem");
365  return;
366  }
367 
368  /*
369  * Check the socket for the magic fd
370  */
371  error = vl_sock_api_recv_fd_msg (scm->socket_fd, &my_fd, 1, 5);
372  if (error)
373  {
374  clib_error_report (error);
375  retval = -99;
376  return;
377  }
378 
379  clib_memset (memfd, 0, sizeof (*memfd));
380  memfd->fd = my_fd;
381 
382  /* Note: this closes memfd.fd */
383  retval = ssvm_client_init_memfd (memfd);
384  if (retval)
385  clib_warning ("WARNING: segment map returned %d", retval);
386 
387  /*
388  * Pivot to the memory client segment that vpp just created
389  */
390  am->vlib_rp = (void *) (memfd->requested_va + MMAP_PAGESIZE);
391  am->shmem_hdr = (void *) am->vlib_rp->user_ctx;
392 
393  new_name = format (0, "%v[shm]%c", scm->name, 0);
395  if (scm->want_shm_pthread)
396  {
397  vl_client_connect_to_vlib_no_map ("pvt", (char *) new_name,
398  32 /* input_queue_length */ );
399  }
400  else
401  {
403  (char *) new_name, 32
404  /* input_queue_length */
405  );
406  }
408  vec_free (new_name);
409 }
410 
411 static void
413 {
415  if (!mp->response)
416  {
417  scm->socket_enable = 1;
418  scm->client_index = clib_net_to_host_u32 (mp->index);
419  }
420 }
421 
422 #define foreach_sock_client_api_msg \
423 _(SOCKCLNT_CREATE_REPLY, sockclnt_create_reply) \
424 _(SOCK_INIT_SHM_REPLY, sock_init_shm_reply) \
425 
426 static void
427 noop_handler (void *notused)
428 {
429 }
430 
431 void
433 {
434 
435 #define _(N,n) \
436  vl_msg_api_set_handlers(VL_API_##N, #n, \
437  vl_api_##n##_t_handler, \
438  noop_handler, \
439  vl_api_##n##_t_endian, \
440  vl_api_##n##_t_print, \
441  sizeof(vl_api_##n##_t), 1);
443 #undef _
444 }
445 
446 int
448  char *socket_path, char *client_name,
449  u32 socket_buffer_size)
450 {
452  clib_socket_t *sock;
454 
455  /* Already connected? */
456  if (scm->socket_fd)
457  return (-2);
458 
459  /* bogus call? */
460  if (socket_path == 0 || client_name == 0)
461  return (-3);
462 
463  sock = &scm->client_socket;
464  sock->config = socket_path;
465  sock->flags = CLIB_SOCKET_F_IS_CLIENT;
466 
467  if ((error = clib_socket_init (sock)))
468  {
469  clib_error_report (error);
470  return (-1);
471  }
472 
474 
475  scm->socket_fd = sock->fd;
476  scm->socket_buffer_size = socket_buffer_size ? socket_buffer_size :
480  _vec_len (scm->socket_rx_buffer) = 0;
481  _vec_len (scm->socket_tx_buffer) = 0;
482  scm->name = format (0, "%s", client_name);
483 
484  mp = vl_socket_client_msg_alloc2 (scm, sizeof (*mp));
485  mp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE);
486  strncpy ((char *) mp->name, client_name, sizeof (mp->name) - 1);
487  mp->name[sizeof (mp->name) - 1] = 0;
488  mp->context = 0xfeedface;
489 
490  clib_time_init (&scm->clib_time);
491 
492  if (vl_socket_client_write_internal (scm) <= 0)
493  return (-1);
494 
495  if (vl_socket_client_read_internal (scm, 5))
496  return (-1);
497 
498  return (0);
499 }
500 
501 int
502 vl_socket_client_connect (char *socket_path, char *client_name,
503  u32 socket_buffer_size)
504 {
505  return vl_socket_client_connect_internal (socket_client_ctx, socket_path,
506  client_name, socket_buffer_size);
507 }
508 
509 int
511  char *client_name, u32 socket_buffer_size)
512 {
513  socket_client_main_t *old_ctx;
514  int rv;
515 
516  old_ctx = vl_socket_client_ctx_push (scm);
517  rv = vl_socket_client_connect_internal (socket_client_ctx, socket_path,
518  client_name, socket_buffer_size);
519  vl_socket_client_ctx_pop (old_ctx);
520  return rv;
521 }
522 
523 int
525  vl_api_shm_elem_config_t * config,
526  int want_pthread)
527 {
529  int rv, i;
530  u64 *cfg;
531 
532  scm->want_shm_pthread = want_pthread;
533 
534  mp = vl_socket_client_msg_alloc2 (scm, sizeof (*mp) +
535  vec_len (config) * sizeof (u64));
536  clib_memset (mp, 0, sizeof (*mp));
537  mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_SOCK_INIT_SHM);
538  mp->client_index = clib_host_to_net_u32 (scm->client_index);
539  mp->requested_size = 64 << 20;
540 
541  if (config)
542  {
543  for (i = 0; i < vec_len (config); i++)
544  {
545  cfg = (u64 *) & config[i];
546  mp->configs[i] = *cfg;
547  }
548  mp->nitems = vec_len (config);
549  }
551  if (rv <= 0)
552  return rv;
553 
554  if (vl_socket_client_read_internal (scm, 1))
555  return -1;
556 
557  return 0;
558 }
559 
560 int
562  int want_pthread)
563 {
564  return vl_socket_client_init_shm_internal (socket_client_ctx, config,
565  want_pthread);
566 }
567 
568 int
570  vl_api_shm_elem_config_t * config,
571  int want_pthread)
572 {
573  socket_client_main_t *old_ctx;
574  int rv;
575 
576  old_ctx = vl_socket_client_ctx_push (scm);
577  rv = vl_socket_client_init_shm_internal (socket_client_ctx, config,
578  want_pthread);
579  vl_socket_client_ctx_pop (old_ctx);
580  return rv;
581 }
582 
583 clib_error_t *
585  int n_fds, u32 wait)
586 {
587  if (!scm->socket_fd)
588  return clib_error_return (0, "no socket");
589  return vl_sock_api_recv_fd_msg_internal (scm, fds, n_fds, wait);
590 }
591 
592 clib_error_t *
593 vl_socket_client_recv_fd_msg (int fds[], int n_fds, u32 wait)
594 {
595  return vl_socket_client_recv_fd_msg2 (socket_client_ctx, fds, n_fds, wait);
596 }
597 
598 /*
599  * fd.io coding-style-patch-verification: ON
600  *
601  * Local Variables:
602  * eval: (c-set-style "gnu")
603  * End:
604  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:524
int vl_socket_client_init_shm(vl_api_shm_elem_config_t *config, int want_pthread)
void vl_msg_api_socket_handler(void *the_msg)
Definition: api_shared.c:800
uword requested_va
Definition: ssvm.h:85
u8 vl_mem_client_is_connected(void)
ssvm_private_t memfd_segment
Definition: socket_client.h:42
int ssvm_client_init_memfd(ssvm_private_t *memfd)
Initialize memfd segment client.
Definition: ssvm.c:292
int vl_client_connect_to_vlib_no_map(const char *svm_name, const char *client_name, int rx_queue_size)
int vl_socket_client_read(int wait)
int vl_socket_client_read2(socket_client_main_t *scm, int wait)
unsigned long u64
Definition: types.h:89
int vl_socket_client_connect_internal(socket_client_main_t *scm, char *socket_path, char *client_name, u32 socket_buffer_size)
static void noop_handler(void *notused)
clib_memset(h->entries, 0, sizeof(h->entries[0]) *entries)
static f64 clib_time_now(clib_time_t *c)
Definition: time.h:230
int vl_socket_client_connect(char *socket_path, char *client_name, u32 socket_buffer_size)
svm_queue_t * q
message allocated in this shmem ring
Definition: api_common.h:142
u8 data[0]
actual message begins here
Definition: api_common.h:145
static int vl_socket_client_read_internal(socket_client_main_t *scm, int wait)
Definition: socket_client.c:72
u32 vl(void *p)
Definition: socket_client.c:52
clib_error_t * vl_socket_client_recv_fd_msg2(socket_client_main_t *scm, int fds[], int n_fds, u32 wait)
void vl_socket_client_enable_disable(int enable)
int vl_socket_client_connect2(socket_client_main_t *scm, char *socket_path, char *client_name, u32 socket_buffer_size)
int vl_socket_client_write2(socket_client_main_t *scm)
unsigned char u8
Definition: types.h:56
__clib_export clib_error_t * clib_socket_init(clib_socket_t *s)
Definition: socket.c:390
double f64
Definition: types.h:142
void vl_socket_client_enable_disable2(socket_client_main_t *scm, int enable)
unsigned int u32
Definition: types.h:88
static void vl_api_sock_init_shm_reply_t_handler(vl_api_sock_init_shm_reply_t *mp)
#define SOCKET_CLIENT_DEFAULT_BUFFER_SIZE
Definition: socket_client.h:49
void * vl_socket_client_msg_alloc(int nbytes)
static int vl_socket_client_write_internal(socket_client_main_t *scm)
clib_time_t clib_time
Definition: socket_client.h:41
volatile void * user_ctx
Definition: svm_common.h:48
description fragment has unexpected format
Definition: map.api:433
static socket_client_main_t * vl_socket_client_ctx_push(socket_client_main_t *ctx)
Definition: socket_client.c:58
svm_region_t * vlib_rp
Current binary api segment descriptor.
Definition: api_common.h:284
#define clib_error_return(e, args...)
Definition: error.h:99
struct vl_shmem_hdr_ * shmem_hdr
Binary API shared-memory segment header pointer.
Definition: api_common.h:294
int __clib_unused rv
Definition: application.c:491
u64 configs[nitems]
Definition: memclnt.api:194
Definition: cJSON.c:88
int vl_socket_client_init_shm_internal(socket_client_main_t *scm, vl_api_shm_elem_config_t *config, int want_pthread)
void vl_socket_client_disconnect2(socket_client_main_t *scm)
static void vl_api_sockclnt_create_reply_t_handler(vl_api_sockclnt_create_reply_t *mp)
long ctx[MAX_CONNS]
Definition: main.c:144
clib_error_t * vl_sock_api_recv_fd_msg2(socket_client_main_t *scm, int socket_fd, int fds[], int n_fds, u32 wait)
void vl_sock_client_install_message_handlers(void)
u8 data_len
Definition: ikev2_types.api:24
#define clib_error_return_unix(e, args...)
Definition: error.h:102
u32 size
Definition: vhost_user.h:125
clib_error_t * vl_sock_api_recv_fd_msg(int socket_fd, int fds[], int n_fds, u32 wait)
int vl_client_connect_to_vlib_no_rx_pthread_no_map(const char *svm_name, const char *client_name, int rx_queue_size)
API main structure, used by both vpp and binary API clients.
Definition: api_common.h:228
int vl_socket_client_init_shm2(socket_client_main_t *scm, vl_api_shm_elem_config_t *config, int want_pthread)
__thread socket_client_main_t * socket_client_ctx
Definition: socket_client.c:46
socket_client_main_t socket_client_main
Definition: socket_client.c:45
clib_error_t * vl_socket_client_recv_fd_msg(int fds[], int n_fds, u32 wait)
void vl_socket_client_disconnect(void)
clib_socket_t client_socket
Definition: socket_client.h:32
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:395
static clib_error_t * vl_sock_api_recv_fd_msg_internal(socket_client_main_t *scm, int fds[], int n_fds, u32 wait)
#define clib_warning(format, args...)
Definition: error.h:59
int fd
memfd segments
Definition: ssvm.h:93
signed int i32
Definition: types.h:77
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:876
__clib_export void clib_time_init(clib_time_t *c)
Definition: time.c:207
u32 data_len
message length not including header
Definition: api_common.h:143
Message header structure.
Definition: api_common.h:140
#define CLIB_SOCKET_F_IS_CLIENT
Definition: socket.h:59
#define clib_error_report(e)
Definition: error.h:113
struct _socket_t clib_socket_t
static_always_inline void * clib_memcpy_fast(void *restrict dst, const void *restrict src, size_t n)
Definition: string.h:92
#define MMAP_PAGESIZE
Definition: ssvm.h:42
void vl_client_install_client_message_handlers(void)
void vl_client_disconnect_from_vlib_no_unmap(void)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u32 client_index
Client index allocated by VPP.
Definition: socket_client.h:30
u32 pid
Definition: dhcp.api:164
#define clib_unix_warning(format, args...)
Definition: error.h:68
void ssvm_delete_memfd(ssvm_private_t *memfd)
Definition: ssvm.c:347
static api_main_t * vlibapi_get_main(void)
Definition: api_common.h:390
void * vl_socket_client_msg_alloc2(socket_client_main_t *scm, int nbytes)
int vl_socket_client_write(void)
int socket_enable
Can temporarily disable the connection but still can keep it around...
Definition: socket_client.h:28
app_main_t * am
Definition: application.c:489
static void vl_socket_client_ctx_pop(socket_client_main_t *old_ctx)
Definition: socket_client.c:66
#define foreach_sock_client_api_msg