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