FD.io VPP  v18.07.1-19-g511ce25
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 
45 
46 /* Debug aid */
47 u32 vl (void *p) __attribute__ ((weak));
48 
49 u32
50 vl (void *p)
51 {
52  return vec_len (p);
53 }
54 
55 int
57 {
59  int n, current_rx_index;
60  msgbuf_t *mbp = 0;
61  f64 timeout;
62 
63  if (scm->socket_fd == 0)
64  return -1;
65 
66  if (wait)
67  timeout = clib_time_now (&scm->clib_time) + wait;
68 
69  while (1)
70  {
71  current_rx_index = vec_len (scm->socket_rx_buffer);
72  while (vec_len (scm->socket_rx_buffer) <
73  sizeof (*mbp) + 2 /* msg id */ )
74  {
75  vec_validate (scm->socket_rx_buffer, current_rx_index
76  + scm->socket_buffer_size - 1);
77  _vec_len (scm->socket_rx_buffer) = current_rx_index;
78  n = read (scm->socket_fd, scm->socket_rx_buffer + current_rx_index,
79  scm->socket_buffer_size);
80  if (n < 0)
81  {
82  clib_unix_warning ("socket_read");
83  return -1;
84  }
85  _vec_len (scm->socket_rx_buffer) += n;
86  }
87 
88 #if CLIB_DEBUG > 1
89  if (n > 0)
90  clib_warning ("read %d bytes", n);
91 #endif
92 
93  if (mbp == 0)
94  mbp = (msgbuf_t *) (scm->socket_rx_buffer);
95 
96  if (vec_len (scm->socket_rx_buffer) >= ntohl (mbp->data_len)
97  + sizeof (*mbp))
98  {
99  vl_msg_api_socket_handler ((void *) (mbp->data));
100 
101  if (vec_len (scm->socket_rx_buffer) == ntohl (mbp->data_len)
102  + sizeof (*mbp))
103  _vec_len (scm->socket_rx_buffer) = 0;
104  else
105  vec_delete (scm->socket_rx_buffer, ntohl (mbp->data_len)
106  + sizeof (*mbp), 0);
107  mbp = 0;
108 
109  /* Quit if we're out of data, and not expecting a ping reply */
110  if (vec_len (scm->socket_rx_buffer) == 0
111  && scm->control_pings_outstanding == 0)
112  break;
113  }
114 
115  if (wait && clib_time_now (&scm->clib_time) >= timeout)
116  return -1;
117  }
118  return 0;
119 }
120 
121 int
123 {
125  int n;
126 
127  msgbuf_t msgbuf = {
128  .q = 0,
129  .gc_mark_timestamp = 0,
130  .data_len = htonl (scm->socket_tx_nbytes),
131  };
132 
133  n = write (scm->socket_fd, &msgbuf, sizeof (msgbuf));
134  if (n < sizeof (msgbuf))
135  {
136  clib_unix_warning ("socket write (msgbuf)");
137  return -1;
138  }
139 
140  n = write (scm->socket_fd, scm->socket_tx_buffer, scm->socket_tx_nbytes);
141  if (n < scm->socket_tx_nbytes)
142  {
143  clib_unix_warning ("socket write (msg)");
144  return -1;
145  }
146 
147  return n;
148 }
149 
150 void *
152 {
153  socket_client_main.socket_tx_nbytes = nbytes;
154  return ((void *) socket_client_main.socket_tx_buffer);
155 }
156 
157 void
159 {
161 
163  {
166  }
167  if (scm->socket_fd && (close (scm->socket_fd) < 0))
168  clib_unix_warning ("close");
169  scm->socket_fd = 0;
170 }
171 
172 void
174 {
176  scm->socket_enable = enable;
177 }
178 
179 clib_error_t *
180 vl_sock_api_recv_fd_msg (int socket_fd, int *my_fd, u32 wait)
181 {
183  char msgbuf[16];
184  char ctl[CMSG_SPACE (sizeof (int)) + CMSG_SPACE (sizeof (struct ucred))];
185  struct msghdr mh = { 0 };
186  struct iovec iov[1];
187  ssize_t size = 0;
188  struct ucred *cr = 0;
189  struct cmsghdr *cmsg;
190  pid_t pid __attribute__ ((unused));
191  uid_t uid __attribute__ ((unused));
192  gid_t gid __attribute__ ((unused));
193  f64 timeout;
194 
195  iov[0].iov_base = msgbuf;
196  iov[0].iov_len = 5;
197  mh.msg_iov = iov;
198  mh.msg_iovlen = 1;
199  mh.msg_control = ctl;
200  mh.msg_controllen = sizeof (ctl);
201 
202  memset (ctl, 0, sizeof (ctl));
203 
204  if (wait != ~0)
205  {
206  timeout = clib_time_now (&scm->clib_time) + wait;
207  while (size != 5 && clib_time_now (&scm->clib_time) < timeout)
208  size = recvmsg (socket_fd, &mh, MSG_DONTWAIT);
209  }
210  else
211  size = recvmsg (socket_fd, &mh, 0);
212 
213  if (size != 5)
214  {
215  return (size == 0) ? clib_error_return (0, "disconnected") :
216  clib_error_return_unix (0, "recvmsg: malformed message (fd %d)",
217  socket_fd);
218  }
219 
220  cmsg = CMSG_FIRSTHDR (&mh);
221  while (cmsg)
222  {
223  if (cmsg->cmsg_level == SOL_SOCKET)
224  {
225  if (cmsg->cmsg_type == SCM_CREDENTIALS)
226  {
227  cr = (struct ucred *) CMSG_DATA (cmsg);
228  uid = cr->uid;
229  gid = cr->gid;
230  pid = cr->pid;
231  }
232  else if (cmsg->cmsg_type == SCM_RIGHTS)
233  {
234  clib_memcpy (my_fd, CMSG_DATA (cmsg), sizeof (int));
235  }
236  }
237  cmsg = CMSG_NXTHDR (&mh, cmsg);
238  }
239  return 0;
240 }
241 
244 {
246  ssvm_private_t *memfd = &scm->memfd_segment;
247  i32 retval = ntohl (mp->retval);
248  api_main_t *am = &api_main;
249  clib_error_t *error;
250  int my_fd = -1;
251  u8 *new_name;
252 
253  if (retval)
254  {
255  clib_warning ("failed to init shmem");
256  return;
257  }
258 
259  /*
260  * Check the socket for the magic fd
261  */
262  error = vl_sock_api_recv_fd_msg (scm->socket_fd, &my_fd, 5);
263  if (error)
264  {
265  clib_error_report (error);
266  retval = -99;
267  return;
268  }
269 
270  memset (memfd, 0, sizeof (*memfd));
271  memfd->fd = my_fd;
272 
273  /* Note: this closes memfd.fd */
274  retval = ssvm_slave_init_memfd (memfd);
275  if (retval)
276  clib_warning ("WARNING: segment map returned %d", retval);
277 
278  /*
279  * Pivot to the memory client segment that vpp just created
280  */
281  am->vlib_rp = (void *) (memfd->requested_va + MMAP_PAGESIZE);
282  am->shmem_hdr = (void *) am->vlib_rp->user_ctx;
283 
284  new_name = format (0, "%v[shm]%c", scm->name, 0);
286  vl_client_connect_to_vlib_no_map ("pvt", (char *) new_name,
287  32 /* input_queue_length */ );
289  vec_free (new_name);
290 }
291 
292 static void
294 {
296  if (!mp->response)
297  scm->socket_enable = 1;
298 }
299 
300 #define foreach_sock_client_api_msg \
301 _(SOCKCLNT_CREATE_REPLY, sockclnt_create_reply) \
302 _(SOCK_INIT_SHM_REPLY, sock_init_shm_reply) \
303 
304 static void
305 noop_handler (void *notused)
306 {
307 }
308 
309 void
311 {
312 
313 #define _(N,n) \
314  vl_msg_api_set_handlers(VL_API_##N, #n, \
315  vl_api_##n##_t_handler, \
316  noop_handler, \
317  vl_api_##n##_t_endian, \
318  vl_api_##n##_t_print, \
319  sizeof(vl_api_##n##_t), 1);
321 #undef _
322 }
323 
324 int
325 vl_socket_client_connect (char *socket_path, char *client_name,
326  u32 socket_buffer_size)
327 {
330  clib_socket_t *sock;
331  clib_error_t *error;
332 
333  /* Already connected? */
334  if (scm->socket_fd)
335  return (-2);
336 
337  /* bogus call? */
338  if (socket_path == 0 || client_name == 0)
339  return (-3);
340 
341  sock = &scm->client_socket;
342  sock->config = socket_path;
344 
345  if ((error = clib_socket_init (sock)))
346  {
347  clib_error_report (error);
348  return (-1);
349  }
350 
352 
353  scm->socket_fd = sock->fd;
354  scm->socket_buffer_size = socket_buffer_size ? socket_buffer_size :
358  _vec_len (scm->socket_rx_buffer) = 0;
359  _vec_len (scm->socket_tx_buffer) = 0;
360  scm->name = format (0, "%s", client_name);
361 
362  mp = vl_socket_client_msg_alloc (sizeof (*mp));
363  mp->_vl_msg_id = htons (VL_API_SOCKCLNT_CREATE);
364  strncpy ((char *) mp->name, client_name, sizeof (mp->name) - 1);
365  mp->name[sizeof (mp->name) - 1] = 0;
366  mp->context = 0xfeedface;
367 
368  if (vl_socket_client_write () <= 0)
369  return (-1);
370 
371  if (vl_socket_client_read (1))
372  return (-1);
373 
374  clib_time_init (&scm->clib_time);
375  return (0);
376 }
377 
378 int
380 {
382  int rv, i;
383  u64 *cfg;
384 
385  mp = vl_socket_client_msg_alloc (sizeof (*mp) +
386  vec_len (config) * sizeof (u64));
387  memset (mp, 0, sizeof (*mp));
388  mp->_vl_msg_id = clib_host_to_net_u16 (VL_API_SOCK_INIT_SHM);
389  mp->client_index = ~0;
390  mp->requested_size = 64 << 20;
391 
392  if (config)
393  {
394  for (i = 0; i < vec_len (config); i++)
395  {
396  cfg = (u64 *) & config[i];
397  mp->configs[i] = *cfg;
398  }
399  mp->nitems = vec_len (config);
400  }
401  rv = vl_socket_client_write ();
402  if (rv <= 0)
403  return rv;
404 
405  if (vl_socket_client_read (1))
406  return -1;
407 
408  return 0;
409 }
410 
411 clib_error_t *
412 vl_socket_client_recv_fd_msg (int *fd_to_recv, u32 wait)
413 {
415  if (!scm->socket_fd)
416  return clib_error_return (0, "no socket");
417  return vl_sock_api_recv_fd_msg (scm->client_socket.fd, fd_to_recv, wait);
418 }
419 
420 /*
421  * fd.io coding-style-patch-verification: ON
422  *
423  * Local Variables:
424  * eval: (c-set-style "gnu")
425  * End:
426  */
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
clib_error_t * vl_socket_client_recv_fd_msg(int *fd_to_recv, u32 wait)
void vl_msg_api_socket_handler(void *the_msg)
Definition: api_shared.c:643
uword requested_va
Definition: ssvm.h:87
u8 vl_mem_client_is_connected(void)
ssvm_private_t memfd_segment
Definition: socket_client.h:41
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)
Definition: socket_client.c:56
unsigned long u64
Definition: types.h:89
static void noop_handler(void *notused)
static f64 clib_time_now(clib_time_t *c)
Definition: time.h:203
int i
clib_error_t * clib_socket_init(clib_socket_t *s)
Definition: socket.c:376
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:137
u8 data[0]
actual message begins here
Definition: api_common.h:140
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
u32 vl(void *p)
Definition: socket_client.c:50
void vl_socket_client_enable_disable(int enable)
unsigned char u8
Definition: types.h:56
double f64
Definition: types.h:142
static void vl_api_sock_init_shm_reply_t_handler(vl_api_sock_init_shm_reply_t *mp)
clib_error_t * vl_sock_api_recv_fd_msg(int socket_fd, int *my_fd, u32 wait)
#define SOCKET_CLIENT_DEFAULT_BUFFER_SIZE
Definition: socket_client.h:46
void * vl_socket_client_msg_alloc(int nbytes)
clib_time_t clib_time
Definition: socket_client.h:40
volatile void * user_ctx
Definition: svm_common.h:47
svm_region_t * vlib_rp
Current binary api segment descriptor.
Definition: api_common.h:254
#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:264
unsigned int u32
Definition: types.h:88
u64 configs[nitems]
Definition: memclnt.api:185
static void vl_api_sockclnt_create_reply_t_handler(vl_api_sockclnt_create_reply_t *mp)
uword size
int vl_socket_client_init_shm(vl_api_shm_elem_config_t *config)
void vl_sock_client_install_message_handlers(void)
#define clib_error_return_unix(e, args...)
Definition: error.h:102
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:201
socket_client_main_t socket_client_main
Definition: socket_client.c:44
void vl_socket_client_disconnect(void)
clib_socket_t client_socket
Definition: socket_client.h:31
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
#define clib_warning(format, args...)
Definition: error.h:59
#define clib_memcpy(a, b, c)
Definition: string.h:75
int fd
memfd segments
Definition: ssvm.h:92
signed int i32
Definition: types.h:81
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:786
u32 data_len
message length not including header
Definition: api_common.h:138
Message header structure.
Definition: api_common.h:135
#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 CLIB_SOCKET_F_SEQPACKET
Definition: socket.h:63
#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)
#define clib_unix_warning(format, args...)
Definition: error.h:68
void ssvm_delete_memfd(ssvm_private_t *memfd)
Definition: ssvm.c:318
int vl_socket_client_write(void)
api_main_t api_main
Definition: api_shared.c:35
int ssvm_slave_init_memfd(ssvm_private_t *memfd)
Initialize memfd segment slave.
Definition: ssvm.c:266
#define foreach_sock_client_api_msg