FD.io VPP  v21.10.1-2-g0a485f517
Vector Packet Processing
sock_test_client.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <unistd.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <ctype.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <stdio.h>
23 #include <time.h>
24 #include <arpa/inet.h>
25 #include <hs_apps/vcl/sock_test.h>
26 #include <fcntl.h>
27 #include <sys/un.h>
28 
29 typedef struct
30 {
33  struct sockaddr_storage server_addr;
34  uint32_t server_addr_size;
35  uint32_t cfg_seq_num;
38  uint32_t num_test_sockets;
39  uint8_t dump_cfg;
41 
43 
44 static int
46 {
48  vcl_test_session_t *ctrl = &scm->ctrl_socket;
49  vcl_test_cfg_t *rl_cfg = (vcl_test_cfg_t *) socket->rxbuf;
50  int rx_bytes, tx_bytes;
51 
52  if (socket->cfg.verbose)
53  vcl_test_cfg_dump (&socket->cfg, 1 /* is_client */ );
54 
55  ctrl->cfg.seq_num = ++scm->cfg_seq_num;
56  if (socket->cfg.verbose)
57  {
58  stinf ("(fd %d): Sending config sent to server.\n", socket->fd);
59  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
60  }
61  tx_bytes = sock_test_write (socket->fd, (uint8_t *) & ctrl->cfg,
62  sizeof (ctrl->cfg), NULL, ctrl->cfg.verbose);
63  if (tx_bytes < 0)
64  stabrt ("(fd %d): write test cfg failed (%d)!", socket->fd, tx_bytes);
65 
66  rx_bytes = sock_test_read (socket->fd, (uint8_t *) socket->rxbuf,
67  sizeof (vcl_test_cfg_t), NULL);
68  if (rx_bytes < 0)
69  return rx_bytes;
70 
71  if (rl_cfg->magic != VCL_TEST_CFG_CTRL_MAGIC)
72  stabrt ("(fd %d): Bad server reply cfg -- aborting!\n", socket->fd);
73 
74  if ((rx_bytes != sizeof (vcl_test_cfg_t))
75  || !vcl_test_cfg_verify (rl_cfg, &ctrl->cfg))
76  stabrt ("(fd %d): Invalid config received from server!\n", socket->fd);
77 
78  if (socket->cfg.verbose)
79  {
80  stinf ("(fd %d): Got config back from server.", socket->fd);
81  vcl_test_cfg_dump (rl_cfg, 1 /* is_client */ );
82  }
83  ctrl->cfg.ctrl_handle = ((ctrl->cfg.ctrl_handle == ~0) ?
84  rl_cfg->ctrl_handle : ctrl->cfg.ctrl_handle);
85 
86  return 0;
87 }
88 
89 static void
91 {
92  int fd, rv;
93  struct sockaddr_un serveraddr;
94  uint8_t buffer[256];
95  size_t nbytes = strlen (SOCK_TEST_MIXED_EPOLL_DATA) + 1;
96  struct timeval timeout;
97 
98  /* Open AF_UNIX socket and send an echo to test mixed epoll on server.
99  */
100  fd = socket (AF_UNIX, SOCK_STREAM, 0);
101  if (fd < 0)
102  stfail ("socket()");
103 
104  memset (&serveraddr, 0, sizeof (serveraddr));
105  serveraddr.sun_family = AF_UNIX;
106  strncpy (serveraddr.sun_path, SOCK_TEST_AF_UNIX_FILENAME,
107  sizeof (serveraddr.sun_path));
108  rv = connect (fd, (struct sockaddr *) &serveraddr, SUN_LEN (&serveraddr));
109  if (rv < 0)
110  stfail ("connect()");
111 
112  scm->af_unix_echo_tx++;
113  strncpy ((char *) buffer, SOCK_TEST_MIXED_EPOLL_DATA, sizeof (buffer));
114  timeout.tv_sec = 0;
115  timeout.tv_usec = 250000;
116  select (0, NULL, NULL, NULL, &timeout); /* delay .25 secs */
117  rv = write (fd, buffer, nbytes);
118  if (rv < 0)
119  stfail ("write()");
120 
121  if (rv < nbytes)
122  stabrt ("write(fd %d, \"%s\", %lu) returned %d!", fd, buffer, nbytes, rv);
123 
124  stinf ("(AF_UNIX): TX (%d bytes) - '%s'\n", rv, buffer);
125  memset (buffer, 0, sizeof (buffer));
126  rv = read (fd, buffer, nbytes);
127  if (rv < 0)
128  stfail ("read()");
129 
130  if (rv < nbytes)
131  stabrt ("read(fd %d, %p, %lu) returned %d!\n", fd, buffer, nbytes, rv);
132 
133  if (!strncmp (SOCK_TEST_MIXED_EPOLL_DATA, (const char *) buffer, nbytes))
134  {
135  stinf ("(AF_UNIX): RX (%d bytes) - '%s'\n", rv, buffer);
136  scm->af_unix_echo_rx++;
137  }
138  else
139  stabrt ("(AF_UNIX): RX (%d bytes) - '%s'\n", rv, buffer);
140 
141  close (fd);
142 }
143 
144 static void
146 {
148  vcl_test_session_t *ctrl = &scm->ctrl_socket;
149  vcl_test_session_t *tsock;
150  int rx_bytes, tx_bytes, nbytes;
151  uint32_t i, n;
152  int rv;
153  int nfds = 0;
154  fd_set wr_fdset, rd_fdset;
155  fd_set _wfdset, *wfdset = &_wfdset;
156  fd_set _rfdset, *rfdset = &_rfdset;
157 
158  FD_ZERO (&wr_fdset);
159  FD_ZERO (&rd_fdset);
160  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
161  ctrl->cfg.total_bytes = nbytes = strlen (ctrl->txbuf) + 1;
162  for (n = 0; n != ctrl->cfg.num_test_sessions; n++)
163  {
164  tsock = &scm->test_socket[n];
165  tsock->cfg = ctrl->cfg;
167  if (sock_test_cfg_sync (tsock))
168  return;
169 
170  memcpy (tsock->txbuf, ctrl->txbuf, nbytes);
171  memset (&tsock->stats, 0, sizeof (tsock->stats));
172 
173  FD_SET (tsock->fd, &wr_fdset);
174  FD_SET (tsock->fd, &rd_fdset);
175  nfds = ((tsock->fd + 1) > nfds) ? (tsock->fd + 1) : nfds;
176  }
177 
178  nfds++;
179  clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
180  while (n)
181  {
182  _wfdset = wr_fdset;
183  _rfdset = rd_fdset;
184 
185  struct timeval timeout;
186  timeout.tv_sec = 0;
187  timeout.tv_usec = 0;
188  rv = select (nfds, rfdset, wfdset, NULL, &timeout);
189 
190  if (rv < 0)
191  stfail ("select()");
192 
193  if (rv == 0)
194  continue;
195 
196  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
197  {
198  tsock = &scm->test_socket[i];
199  if (!((tsock->stats.stop.tv_sec == 0) &&
200  (tsock->stats.stop.tv_nsec == 0)))
201  continue;
202 
203  if (FD_ISSET (tsock->fd, wfdset) &&
204  (tsock->stats.tx_bytes < ctrl->cfg.total_bytes))
205  {
206  tx_bytes = sock_test_write (tsock->fd, (uint8_t *) tsock->txbuf,
207  nbytes, &tsock->stats,
208  ctrl->cfg.verbose);
209  if (tx_bytes < 0)
210  stabrt ("sock_test_write(%d) failed -- aborting test!",
211  tsock->fd);
212 
213  stinf ("(fd %d): TX (%d bytes) - '%s'", tsock->fd, tx_bytes,
214  tsock->txbuf);
215  }
216 
217  if ((FD_ISSET (tsock->fd, rfdset)) &&
218  (tsock->stats.rx_bytes < ctrl->cfg.total_bytes))
219  {
220  rx_bytes = sock_test_read (tsock->fd, (uint8_t *) tsock->rxbuf,
221  nbytes, &tsock->stats);
222  if (rx_bytes > 0)
223  {
224  stinf ("(fd %d): RX (%d bytes)\n", tsock->fd, rx_bytes);
225 
226  if (tsock->stats.rx_bytes != tsock->stats.tx_bytes)
227  stinf ("bytes read (%lu) != bytes written (%lu)!\n",
228  tsock->stats.rx_bytes, tsock->stats.tx_bytes);
229  }
230  }
231 
232  if (tsock->stats.rx_bytes >= ctrl->cfg.total_bytes)
233  {
234  clock_gettime (CLOCK_REALTIME, &tsock->stats.stop);
235  n--;
236  }
237  }
238  }
239  clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
240 
242 
243  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
244  {
245  tsock = &scm->test_socket[i];
246  tsock->stats.start = ctrl->stats.start;
247 
248  if (ctrl->cfg.verbose)
249  {
250  static char buf[64];
251 
252  snprintf (buf, sizeof (buf), "CLIENT (fd %d) RESULTS", tsock->fd);
253  vcl_test_stats_dump (buf, &tsock->stats,
254  1 /* show_rx */ , 1 /* show tx */ ,
255  ctrl->cfg.verbose);
256  }
257 
258  vcl_test_stats_accumulate (&ctrl->stats, &tsock->stats);
259  }
260 
261  if (ctrl->cfg.verbose)
262  {
263  vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
264  1 /* show_rx */ , 1 /* show tx */ ,
265  ctrl->cfg.verbose);
266  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
267 
268  if (ctrl->cfg.verbose > 1)
269  {
270  stinf (" ctrl socket info\n"
272  " fd: %d (0x%08x)\n"
273  " rxbuf: %p\n"
274  " rxbuf size: %u (0x%08x)\n"
275  " txbuf: %p\n"
276  " txbuf size: %u (0x%08x)\n"
278  ctrl->fd, (uint32_t) ctrl->fd,
279  ctrl->rxbuf, ctrl->rxbuf_size, ctrl->rxbuf_size,
280  ctrl->txbuf, ctrl->txbuf_size, ctrl->txbuf_size);
281  }
282  }
283 }
284 
285 static void
287 {
289  vcl_test_session_t *ctrl = &scm->ctrl_socket;
290  vcl_test_session_t *tsock;
291  int tx_bytes, rv, nfds = 0;;
292  uint32_t i, n;
293  fd_set wr_fdset, rd_fdset;
294  fd_set _wfdset, *wfdset = &_wfdset;
295  fd_set _rfdset, *rfdset = (test == VCL_TEST_TYPE_BI) ? &_rfdset : 0;
296 
297  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
298  ctrl->cfg.ctrl_handle = ~0;
299 
301  "CLIENT (fd %d): %s-directional Stream Test!\n\n"
302  "CLIENT (fd %d): Sending config to server on ctrl socket...\n",
303  ctrl->fd, test == VCL_TEST_TYPE_BI ? "Bi" : "Uni", ctrl->fd);
304 
305  if (sock_test_cfg_sync (ctrl))
306  stabrt ("test cfg sync failed -- aborting!");
307 
308  FD_ZERO (&wr_fdset);
309  FD_ZERO (&rd_fdset);
310  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
311  for (n = 0; n != ctrl->cfg.num_test_sessions; n++)
312  {
313  tsock = &scm->test_socket[n];
314  tsock->cfg = ctrl->cfg;
316  stinf ("(fd %d): Sending config to server on test socket %d...\n",
317  tsock->fd, n);
318  sock_test_cfg_sync (tsock);
319 
320  /* Fill payload with incrementing uint32's */
321  for (i = 0; i < tsock->txbuf_size; i++)
322  tsock->txbuf[i] = i & 0xff;
323 
324  memset (&tsock->stats, 0, sizeof (tsock->stats));
325  FD_SET (tsock->fd, &wr_fdset);
326  FD_SET (tsock->fd, &rd_fdset);
327  nfds = ((tsock->fd + 1) > nfds) ? (tsock->fd + 1) : nfds;
328  }
329 
330  nfds++;
331  clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
332  while (n)
333  {
334  _wfdset = wr_fdset;
335  _rfdset = rd_fdset;
336 
337  struct timeval timeout;
338  timeout.tv_sec = 0;
339  timeout.tv_usec = 0;
340  rv = select (nfds, rfdset, wfdset, NULL, &timeout);
341 
342  if (rv < 0)
343  stfail ("select()");
344 
345  if (rv == 0)
346  continue;
347 
348  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
349  {
350  tsock = &scm->test_socket[i];
351  if (!((tsock->stats.stop.tv_sec == 0) &&
352  (tsock->stats.stop.tv_nsec == 0)))
353  continue;
354 
355  if ((test == VCL_TEST_TYPE_BI) &&
356  FD_ISSET (tsock->fd, rfdset) &&
357  (tsock->stats.rx_bytes < ctrl->cfg.total_bytes))
358  {
359  (void) sock_test_read (tsock->fd,
360  (uint8_t *) tsock->rxbuf,
361  tsock->rxbuf_size, &tsock->stats);
362  }
363 
364  if (FD_ISSET (tsock->fd, wfdset) &&
365  (tsock->stats.tx_bytes < ctrl->cfg.total_bytes))
366  {
367  tx_bytes = sock_test_write (tsock->fd, (uint8_t *) tsock->txbuf,
368  ctrl->cfg.txbuf_size, &tsock->stats,
369  ctrl->cfg.verbose);
370  if (tx_bytes < 0)
371  stabrt ("sock_test_write(%d) failed -- aborting test!",
372  tsock->fd);
373  }
374 
375  if (((test == VCL_TEST_TYPE_UNI) &&
376  (tsock->stats.tx_bytes >= ctrl->cfg.total_bytes)) ||
377  ((test == VCL_TEST_TYPE_BI) &&
378  (tsock->stats.rx_bytes >= ctrl->cfg.total_bytes)))
379  {
380  clock_gettime (CLOCK_REALTIME, &tsock->stats.stop);
381  n--;
382  }
383  }
384  }
385  clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
386 
387  stinf ("(fd %d): Sending config to server on ctrl socket...\n", ctrl->fd);
388 
389  if (sock_test_cfg_sync (ctrl))
390  stabrt ("test cfg sync failed -- aborting!");
391 
392  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
393  {
394  tsock = &scm->test_socket[i];
395 
396  if (ctrl->cfg.verbose)
397  {
398  static char buf[64];
399 
400  snprintf (buf, sizeof (buf), "CLIENT (fd %d) RESULTS", tsock->fd);
401  vcl_test_stats_dump (buf, &tsock->stats,
402  test == VCL_TEST_TYPE_BI /* show_rx */ ,
403  1 /* show tx */ , ctrl->cfg.verbose);
404  }
405 
406  vcl_test_stats_accumulate (&ctrl->stats, &tsock->stats);
407  }
408 
409  vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
410  test == VCL_TEST_TYPE_BI /* show_rx */ ,
411  1 /* show tx */ , ctrl->cfg.verbose);
412  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
413 
414  if (ctrl->cfg.verbose)
415  {
416  stinf (" ctrl socket info\n"
418  " fd: %d (0x%08x)\n"
419  " rxbuf: %p\n"
420  " rxbuf size: %u (0x%08x)\n"
421  " txbuf: %p\n"
422  " txbuf size: %u (0x%08x)\n"
424  ctrl->fd, (uint32_t) ctrl->fd,
425  ctrl->rxbuf, ctrl->rxbuf_size, ctrl->rxbuf_size,
426  ctrl->txbuf, ctrl->txbuf_size, ctrl->txbuf_size);
427  }
428 
429  ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
430  if (sock_test_cfg_sync (ctrl))
431  stabrt ("post-test cfg sync failed!");
432 
433  stinf ("(fd %d): %s-directional Stream Test Complete!\n"
434  SOCK_TEST_BANNER_STRING "\n", ctrl->fd,
435  test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
436 }
437 
438 static void
440 {
442  vcl_test_session_t *ctrl = &scm->ctrl_socket;
443  vcl_test_session_t *tsock;
444  int i;
445 
446  stinf ("af_unix_echo_tx %d, af_unix_echo_rx %d\n",
447  scm->af_unix_echo_tx, scm->af_unix_echo_rx);
448  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
449  {
450  tsock = &scm->test_socket[i];
451  tsock->cfg.test = VCL_TEST_TYPE_EXIT;
452 
453  /* coverity[COPY_PASTE_ERROR] */
454  if (ctrl->cfg.verbose)
455  {
456  stinf ("\(fd %d): Sending exit cfg to server...\n", tsock->fd);
457  vcl_test_cfg_dump (&tsock->cfg, 1 /* is_client */ );
458  }
459  (void) sock_test_write (tsock->fd, (uint8_t *) & tsock->cfg,
460  sizeof (tsock->cfg), &tsock->stats,
461  ctrl->cfg.verbose);
462  }
463 
464  ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
465  if (ctrl->cfg.verbose)
466  {
467  stinf ("\n(fd %d): Sending exit cfg to server...\n", ctrl->fd);
468  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
469  }
470  (void) sock_test_write (ctrl->fd, (uint8_t *) & ctrl->cfg,
471  sizeof (ctrl->cfg), &ctrl->stats,
472  ctrl->cfg.verbose);
473  stinf ("\nCLIENT: So long and thanks for all the fish!\n\n");
474  sleep (1);
475 }
476 
477 static int
478 sock_test_connect_test_sockets (uint32_t num_test_sockets)
479 {
481  vcl_test_session_t *ctrl = &scm->ctrl_socket;
482  vcl_test_session_t *tsock;
483  int i, rv;
484 
485  if (num_test_sockets < 1)
486  {
487  errno = EINVAL;
488  return -1;
489  }
490 
491  if (num_test_sockets < scm->num_test_sockets)
492  {
493  for (i = scm->num_test_sockets - 1; i >= num_test_sockets; i--)
494  {
495  tsock = &scm->test_socket[i];
496  close (tsock->fd);
497  free (tsock->txbuf);
498  free (tsock->rxbuf);
499  }
500  }
501 
502  else if (num_test_sockets > scm->num_test_sockets)
503  {
504  tsock = realloc (scm->test_socket,
505  sizeof (vcl_test_session_t) * num_test_sockets);
506  if (!tsock)
507  stfail ("realloc()");
508 
509  memset (&tsock[scm->num_test_sockets], 0,
510  sizeof (vcl_test_session_t) * (num_test_sockets -
511  scm->num_test_sockets));
512 
513  scm->test_socket = tsock;
514  for (i = scm->num_test_sockets; i < num_test_sockets; i++)
515  {
516  tsock = &scm->test_socket[i];
517  tsock->fd = socket (ctrl->cfg.address_ip6 ? AF_INET6 : AF_INET,
518  ctrl->cfg.transport_udp ?
519  SOCK_DGRAM : SOCK_STREAM, 0);
520 
521  if (tsock->fd < 0)
522  stfail ("socket()");
523 
524  rv = connect (tsock->fd, (struct sockaddr *) &scm->server_addr,
525  scm->server_addr_size);
526 
527  if (rv < 0)
528  stfail ("connect()");
529 
530  if (fcntl (tsock->fd, F_SETFL, O_NONBLOCK) < 0)
531  stfail ("fcntl");
532 
533  tsock->cfg = ctrl->cfg;
535  sock_test_cfg_sync (tsock);
536 
537  stinf ("(fd %d): Test socket %d connected", tsock->fd, i);
538  }
539  }
540 
541  scm->num_test_sockets = num_test_sockets;
542  stinf ("All sockets (%d) connected!\n", scm->num_test_sockets + 1);
543  return 0;
544 }
545 
546 static void
548 {
550  vcl_test_session_t *ctrl = &scm->ctrl_socket;
551  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_TXBUF_SIZE);
552  uint64_t txbuf_size = strtoull ((const char *) p, NULL, 10);
553 
554  if (txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
555  {
556  ctrl->cfg.txbuf_size = txbuf_size;
557  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
558  vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
559  (uint8_t **) & ctrl->txbuf, &ctrl->txbuf_size);
560  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
561  }
562  else
563  stabrt ("Invalid txbuf size (%lu) < minimum buf size (%u)!",
564  txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
565 }
566 
567 static void
569 {
571  vcl_test_session_t *ctrl = &scm->ctrl_socket;
572  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_WRITES);
573  uint32_t num_writes = strtoul ((const char *) p, NULL, 10);
574 
575  if (num_writes > 0)
576  {
577  ctrl->cfg.num_writes = num_writes;
578  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
579  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
580  }
581  else
582  stabrt ("Invalid num writes: %u", num_writes);
583 }
584 
585 static void
587 {
589  vcl_test_session_t *ctrl = &scm->ctrl_socket;
590  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_TEST_SESS);
591  uint32_t num_test_sockets = strtoul ((const char *) p, NULL, 10);
592 
593  if ((num_test_sockets > 0) &&
594  (num_test_sockets <= VCL_TEST_CFG_MAX_TEST_SESS))
595  {
596  ctrl->cfg.num_test_sessions = num_test_sockets;
597  sock_test_connect_test_sockets (num_test_sockets);
598 
599  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
600  }
601  else
602  stabrt ("Invalid num test sockets: %u, (%d max)\n", num_test_sockets,
604 }
605 
606 static void
608 {
610  vcl_test_session_t *ctrl = &scm->ctrl_socket;
611  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_RXBUF_SIZE);
612  uint64_t rxbuf_size = strtoull ((const char *) p, NULL, 10);
613 
614  if (rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
615  {
616  ctrl->cfg.rxbuf_size = rxbuf_size;
617  vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
618  (uint8_t **) & ctrl->rxbuf, &ctrl->rxbuf_size);
619  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
620  }
621  else
622  stabrt ("Invalid rxbuf size (%lu) < minimum buf size (%u)!",
623  rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
624 }
625 
626 static void
628 {
630  vcl_test_session_t *ctrl = &scm->ctrl_socket;
631 
632  ctrl->cfg.verbose = ctrl->cfg.verbose ? 0 : 1;
633  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
634 }
635 
636 static vcl_test_t
638 {
640  vcl_test_session_t *ctrl = &scm->ctrl_socket;
642 
643  if (!strncmp (VCL_TEST_TOKEN_EXIT, ctrl->txbuf,
644  strlen (VCL_TEST_TOKEN_EXIT)))
646 
647  else if (!strncmp (VCL_TEST_TOKEN_HELP, ctrl->txbuf,
648  strlen (VCL_TEST_TOKEN_HELP)))
649  dump_help ();
650 
651  else if (!strncmp (VCL_TEST_TOKEN_SHOW_CFG, ctrl->txbuf,
652  strlen (VCL_TEST_TOKEN_SHOW_CFG)))
653  scm->dump_cfg = 1;
654 
655  else if (!strncmp (VCL_TEST_TOKEN_VERBOSE, ctrl->txbuf,
656  strlen (VCL_TEST_TOKEN_VERBOSE)))
658 
659  else if (!strncmp (VCL_TEST_TOKEN_TXBUF_SIZE, ctrl->txbuf,
660  strlen (VCL_TEST_TOKEN_TXBUF_SIZE)))
662 
663  else if (!strncmp (VCL_TEST_TOKEN_NUM_TEST_SESS, ctrl->txbuf,
666 
667  else if (!strncmp (VCL_TEST_TOKEN_NUM_WRITES, ctrl->txbuf,
668  strlen (VCL_TEST_TOKEN_NUM_WRITES)))
670 
671  else if (!strncmp (VCL_TEST_TOKEN_RXBUF_SIZE, ctrl->txbuf,
672  strlen (VCL_TEST_TOKEN_RXBUF_SIZE)))
674 
675  else if (!strncmp (VCL_TEST_TOKEN_RUN_UNI, ctrl->txbuf,
676  strlen (VCL_TEST_TOKEN_RUN_UNI)))
677  rv = ctrl->cfg.test = VCL_TEST_TYPE_UNI;
678 
679  else if (!strncmp (VCL_TEST_TOKEN_RUN_BI, ctrl->txbuf,
680  strlen (VCL_TEST_TOKEN_RUN_BI)))
681  rv = ctrl->cfg.test = VCL_TEST_TYPE_BI;
682 
683  else
685 
686  return rv;
687 }
688 
689 void
691 {
692  stinf ("sock_test_client [OPTIONS] <ipaddr> <port>\n"
693  " OPTIONS\n"
694  " -h Print this message and exit.\n"
695  " -6 Use IPv6\n"
696  " -u Use UDP transport layer\n"
697  " -c Print test config before test.\n"
698  " -w <dir> Write test results to <dir>.\n"
699  " -X Exit after running test.\n"
700  " -E Run Echo test.\n"
701  " -N <num-writes> Test Cfg: number of writes.\n"
702  " -R <rxbuf-size> Test Cfg: rx buffer size.\n"
703  " -T <txbuf-size> Test Cfg: tx buffer size.\n"
704  " -U Run Uni-directional test.\n"
705  " -B Run Bi-directional test.\n"
706  " -V Verbose mode.\n");
707  exit (1);
708 }
709 
710 int
711 main (int argc, char **argv)
712 {
714  vcl_test_session_t *ctrl = &scm->ctrl_socket;
715  int c, rv;
716  vcl_test_t post_test = VCL_TEST_TYPE_NONE;
717 
718  vcl_test_cfg_init (&ctrl->cfg);
720 
721  opterr = 0;
722  while ((c = getopt (argc, argv, "chn:w:XE:I:N:R:T:UBV6D")) != -1)
723  switch (c)
724  {
725  case 'c':
726  scm->dump_cfg = 1;
727  break;
728 
729  case 's':
730  if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
731  if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions) != 1)
732  {
733  stinf ("ERROR: Invalid value for option -%c!", c);
735  }
736  if (!ctrl->cfg.num_test_sessions ||
737  (ctrl->cfg.num_test_sessions > FD_SETSIZE))
738  {
739  stinf ("ERROR: Invalid number of "
740  "sockets (%d) specified for option -%c!\n"
741  " Valid range is 1 - %d\n",
742  ctrl->cfg.num_test_sessions, c, FD_SETSIZE);
744  }
745  break;
746 
747  case 'w':
748  stinf ("Writing test results to files is TBD.\n");
749  break;
750 
751  case 'X':
752  post_test = VCL_TEST_TYPE_EXIT;
753  break;
754 
755  case 'E':
756  if (strlen (optarg) > ctrl->txbuf_size)
757  {
758  stinf ("ERROR: Option -%c value larger than txbuf size (%d)!",
759  optopt, ctrl->txbuf_size);
761  }
762  strncpy (ctrl->txbuf, optarg, ctrl->txbuf_size);
763  ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
764  break;
765 
766  case 'I':
767  if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
768  if (sscanf (optarg, "%d", &ctrl->cfg.num_test_sessions) != 1)
769  {
770  stinf ("ERROR: Invalid value for option -%c!\n", c);
772  }
774  {
775  stinf ("ERROR: value greater than max number test sockets (%d)!",
778  }
779  break;
780 
781  case 'N':
782  if (sscanf (optarg, "0x%lx", &ctrl->cfg.num_writes) != 1)
783  if (sscanf (optarg, "%ld", &ctrl->cfg.num_writes) != 1)
784  {
785  stinf ("ERROR: Invalid value for option -%c!", c);
787  }
788  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
789  break;
790 
791  case 'R':
792  if (sscanf (optarg, "0x%lx", &ctrl->cfg.rxbuf_size) != 1)
793  if (sscanf (optarg, "%ld", &ctrl->cfg.rxbuf_size) != 1)
794  {
795  stinf ("ERROR: Invalid value for option -%c!", c);
797  }
799  {
800  ctrl->rxbuf_size = ctrl->cfg.rxbuf_size;
801  vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
802  (uint8_t **) & ctrl->rxbuf,
803  &ctrl->rxbuf_size);
804  }
805  else
806  {
807  stinf ("ERROR: rxbuf size (%lu) less than minumum (%u)\n",
810  }
811 
812  break;
813 
814  case 'T':
815  if (sscanf (optarg, "0x%lx", &ctrl->cfg.txbuf_size) != 1)
816  if (sscanf (optarg, "%ld", &ctrl->cfg.txbuf_size) != 1)
817  {
818  stinf ("ERROR: Invalid value for option -%c!", c);
820  }
822  {
823  ctrl->txbuf_size = ctrl->cfg.txbuf_size;
824  vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
825  (uint8_t **) & ctrl->txbuf,
826  &ctrl->txbuf_size);
827  ctrl->cfg.total_bytes =
828  ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
829  }
830  else
831  {
832  stinf ("ERROR: txbuf size (%lu) less than minumum (%u)!",
835  }
836  break;
837 
838  case 'U':
839  ctrl->cfg.test = VCL_TEST_TYPE_UNI;
840  break;
841 
842  case 'B':
843  ctrl->cfg.test = VCL_TEST_TYPE_BI;
844  break;
845 
846  case 'V':
847  ctrl->cfg.verbose = 1;
848  break;
849 
850  case '6':
851  ctrl->cfg.address_ip6 = 1;
852  break;
853 
854  case 'D':
855  ctrl->cfg.transport_udp = 1;
856  break;
857 
858  case '?':
859  switch (optopt)
860  {
861  case 'E':
862  case 'I':
863  case 'N':
864  case 'R':
865  case 'T':
866  case 'w':
867  stinf ("ERROR: Option -%c requires an argument.\n", optopt);
868  break;
869 
870  default:
871  if (isprint (optopt))
872  stinf ("ERROR: Unknown option `-%c'.\n", optopt);
873  else
874  stinf ("ERROR: Unknown option character `\\x%x'.\n", optopt);
875  }
876  /* fall thru */
877  case 'h':
878  default:
880  }
881 
882  if (argc < (optind + 2))
883  {
884  stinf ("ERROR: Insufficient number of arguments!\n");
886  }
887 
888  ctrl->fd = socket (ctrl->cfg.address_ip6 ? AF_INET6 : AF_INET,
889  ctrl->cfg.transport_udp ? SOCK_DGRAM : SOCK_STREAM, 0);
890 
891  if (ctrl->fd < 0)
892  stfail ("socket()");
893 
894  memset (&scm->server_addr, 0, sizeof (scm->server_addr));
895  if (ctrl->cfg.address_ip6)
896  {
897  struct sockaddr_in6 *server_addr =
898  (struct sockaddr_in6 *) &scm->server_addr;
899  scm->server_addr_size = sizeof (*server_addr);
900  server_addr->sin6_family = AF_INET6;
901  inet_pton (AF_INET6, argv[optind++], &(server_addr->sin6_addr));
902  server_addr->sin6_port = htons (atoi (argv[optind]));
903  }
904  else
905  {
906  struct sockaddr_in *server_addr =
907  (struct sockaddr_in *) &scm->server_addr;
908  scm->server_addr_size = sizeof (*server_addr);
909  server_addr->sin_family = AF_INET;
910  inet_pton (AF_INET, argv[optind++], &(server_addr->sin_addr));
911  server_addr->sin_port = htons (atoi (argv[optind]));
912  }
913 
914  do
915  {
916  stinf ("\nConnecting to server...\n");
917 
918  rv = connect (ctrl->fd, (struct sockaddr *) &scm->server_addr,
919  scm->server_addr_size);
920 
921  if (rv < 0)
922  stfail ("connect()");
923 
924  sock_test_cfg_sync (ctrl);
925  stinf ("(fd %d): Control socket connected.\n", ctrl->fd);
926  }
927  while (rv < 0);
928 
930 
931  while (ctrl->cfg.test != VCL_TEST_TYPE_EXIT)
932  {
933  if (scm->dump_cfg)
934  {
935  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
936  scm->dump_cfg = 0;
937  }
938 
939  switch (ctrl->cfg.test)
940  {
941  case VCL_TEST_TYPE_ECHO:
942  echo_test_client ();
943  break;
944 
945  case VCL_TEST_TYPE_UNI:
946  case VCL_TEST_TYPE_BI:
947  stream_test_client (ctrl->cfg.test);
948  break;
949 
950  case VCL_TEST_TYPE_EXIT:
951  continue;
952 
953  case VCL_TEST_TYPE_NONE:
954  default:
955  break;
956  }
957  switch (post_test)
958  {
959  case VCL_TEST_TYPE_EXIT:
960  switch (ctrl->cfg.test)
961  {
962  case VCL_TEST_TYPE_EXIT:
963  case VCL_TEST_TYPE_UNI:
964  case VCL_TEST_TYPE_BI:
965  case VCL_TEST_TYPE_ECHO:
966  ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
967  continue;
968 
969  case VCL_TEST_TYPE_NONE:
970  default:
971  break;
972  }
973  break;
974 
975  case VCL_TEST_TYPE_NONE:
976  case VCL_TEST_TYPE_ECHO:
977  case VCL_TEST_TYPE_UNI:
978  case VCL_TEST_TYPE_BI:
979  default:
980  break;
981  }
982 
983  memset (ctrl->txbuf, 0, ctrl->txbuf_size);
984  memset (ctrl->rxbuf, 0, ctrl->rxbuf_size);
985 
986  stinf ("\nType some characters and hit <return>\n"
987  "('" VCL_TEST_TOKEN_HELP "' for help): ");
988 
989  if (fgets (ctrl->txbuf, ctrl->txbuf_size, stdin) != NULL)
990  {
991  if (strlen (ctrl->txbuf) == 1)
992  {
993  stinf ("\nNothing to send! Please try again...\n");
994  continue;
995  }
996  ctrl->txbuf[strlen (ctrl->txbuf) - 1] = 0; // chomp the newline.
997 
998  /* Parse input for keywords */
999  ctrl->cfg.test = parse_input ();
1000  }
1001  }
1002 
1003  exit_client ();
1004  close (ctrl->fd);
1005  return (scm->af_unix_echo_tx == scm->af_unix_echo_rx) ? 0 : -1;
1006 }
1007 
1008 /*
1009  * fd.io coding-style-patch-verification: ON
1010  *
1011  * Local Variables:
1012  * eval: (c-set-style "gnu")
1013  * End:
1014  */
vcl_test_cfg_t::seq_num
uint32_t seq_num
Definition: vcl_test.h:95
parse_input
static vcl_test_t parse_input()
Definition: sock_test_client.c:637
vcl_test_cfg_t::magic
uint32_t magic
Definition: vcl_test.h:94
buffer
char * buffer
Definition: cJSON.h:163
realloc
void * realloc(void *p, size_t size)
Definition: mem.c:67
VCL_TEST_TYPE_EXIT
@ VCL_TEST_TYPE_EXIT
Definition: vcl_test.h:82
sock_client_main_t::server_addr
struct sockaddr_storage server_addr
Definition: sock_test_client.c:33
VCL_TEST_TYPE_NONE
@ VCL_TEST_TYPE_NONE
Definition: vcl_test.h:78
vcl_test_cfg_t::address_ip6
uint32_t address_ip6
Definition: vcl_test.h:103
SOCK_TEST_MIXED_EPOLL_DATA
#define SOCK_TEST_MIXED_EPOLL_DATA
Definition: sock_test.h:26
stabrt
#define stabrt(_fmt, _args...)
Definition: sock_test.h:41
stinf
#define stinf(_fmt, _args...)
Definition: sock_test.h:32
SOCK_TEST_AF_UNIX_FILENAME
#define SOCK_TEST_AF_UNIX_FILENAME
Definition: sock_test.h:25
vcl_test_cfg_t::rxbuf_size
uint64_t rxbuf_size
Definition: vcl_test.h:105
vcl_test_cfg_t::test
uint32_t test
Definition: vcl_test.h:96
VCL_TEST_TOKEN_NUM_WRITES
#define VCL_TEST_TOKEN_NUM_WRITES
Definition: vcl_test.h:54
sock_client_main_t::server_addr_size
uint32_t server_addr_size
Definition: sock_test_client.c:34
vcl_test_cfg_dump
static void vcl_test_cfg_dump(vcl_test_cfg_t *cfg, uint8_t is_client)
Definition: vcl_test.h:298
main
int main(int argc, char **argv)
Definition: sock_test_client.c:711
cfg_rxbuf_size_set
static void cfg_rxbuf_size_set(void)
Definition: sock_test_client.c:607
VCL_TEST_TOKEN_TXBUF_SIZE
#define VCL_TEST_TOKEN_TXBUF_SIZE
Definition: vcl_test.h:52
vcl_test_cfg_t::ctrl_handle
uint32_t ctrl_handle
Definition: vcl_test.h:98
vcl_test_session::rxbuf
char * rxbuf
Definition: vcl_test.h:136
SOCK_TEST_BANNER_STRING
#define SOCK_TEST_BANNER_STRING
Definition: sock_test.h:29
VCL_TEST_TOKEN_RUN_BI
#define VCL_TEST_TOKEN_RUN_BI
Definition: vcl_test.h:58
dump_help
static void dump_help(void)
Definition: vcl_test.h:566
vcl_test_stats_t::tx_bytes
uint64_t tx_bytes
Definition: vcl_test.h:118
sock_client_main_t
Definition: sock_test_client.c:29
VCL_TEST_TOKEN_HELP
#define VCL_TEST_TOKEN_HELP
Definition: vcl_test.h:49
stfail
#define stfail(_fn)
Definition: sock_test.h:46
sock_test_cfg_sync
static int sock_test_cfg_sync(vcl_test_session_t *socket)
Definition: sock_test_client.c:45
sock_test_read
static int sock_test_read(int fd, uint8_t *buf, uint32_t nbytes, vcl_test_stats_t *stats)
Definition: sock_test.h:54
VCL_TEST_TOKEN_SHOW_CFG
#define VCL_TEST_TOKEN_SHOW_CFG
Definition: vcl_test.h:56
VCL_TEST_TYPE_ECHO
@ VCL_TEST_TYPE_ECHO
Definition: vcl_test.h:79
vcl_test_session
Definition: vcl_test.h:125
sock_client_main_t::af_unix_echo_tx
int af_unix_echo_tx
Definition: sock_test_client.c:31
vcl_test_cfg_t::transport_udp
uint32_t transport_udp
Definition: vcl_test.h:104
vcl_test_stats_t::start
struct timespec start
Definition: vcl_test.h:121
vcl_test_session_buf_alloc
static void vcl_test_session_buf_alloc(vcl_test_session_t *ts)
Definition: vcl_test.h:253
c
svmdb_client_t * c
Definition: vpp_get_metrics.c:48
vcl_test_buf_alloc
static void vcl_test_buf_alloc(vcl_test_cfg_t *cfg, uint8_t is_rxbuf, uint8_t **buf, uint32_t *bufsize)
Definition: vcl_test.h:230
vcl_test_stats_t::stop
struct timespec stop
Definition: vcl_test.h:122
stream_test_client
static void stream_test_client(vcl_test_t test)
Definition: sock_test_client.c:286
if
if(node->flags &VLIB_NODE_FLAG_TRACE) vnet_interface_output_trace(vm
cfg_num_writes_set
static void cfg_num_writes_set(void)
Definition: sock_test_client.c:568
vcl_test_t
vcl_test_t
Definition: vcl_test.h:76
time.h
vcl_test_stats_dump
static void vcl_test_stats_dump(char *header, vcl_test_stats_t *stats, uint8_t show_rx, uint8_t show_tx, uint8_t verbose)
Definition: vcl_test.h:336
vcl_test_cfg_t::txbuf_size
uint64_t txbuf_size
Definition: vcl_test.h:106
VCL_TEST_TYPE_BI
@ VCL_TEST_TYPE_BI
Definition: vcl_test.h:81
vcl_test_cfg_t::total_bytes
uint64_t total_bytes
Definition: vcl_test.h:108
sock_client_main_t::ctrl_socket
vcl_test_session_t ctrl_socket
Definition: sock_test_client.c:36
VCL_TEST_CFG_BUF_SIZE_MIN
#define VCL_TEST_CFG_BUF_SIZE_MIN
Definition: vcl_test.h:67
vcl_test_cfg_t::num_test_sessions
uint32_t num_test_sessions
Definition: vcl_test.h:99
vcl_test_session::txbuf
char * txbuf
Definition: vcl_test.h:135
cfg_num_test_sockets_set
static void cfg_num_test_sockets_set(void)
Definition: sock_test_client.c:586
vcl_test_cfg_t::verbose
uint32_t verbose
Definition: vcl_test.h:102
echo_test_client
static void echo_test_client(void)
Definition: sock_test_client.c:145
sock_client_main_t::cfg_seq_num
uint32_t cfg_seq_num
Definition: sock_test_client.c:35
sock_test_connect_test_sockets
static int sock_test_connect_test_sockets(uint32_t num_test_sockets)
Definition: sock_test_client.c:478
VCL_TEST_SEPARATOR_STRING
#define VCL_TEST_SEPARATOR_STRING
Definition: vcl_test.h:74
vcl_test_session::stats
vcl_test_stats_t stats
Definition: vcl_test.h:138
vcl_test_session::fd
int fd
Definition: vcl_test.h:130
VCL_TEST_CFG_MAX_TEST_SESS
#define VCL_TEST_CFG_MAX_TEST_SESS
Definition: vcl_test.h:68
vcl_test_session::rxbuf_size
uint32_t rxbuf_size
Definition: vcl_test.h:134
vcl_test_stats_t::rx_bytes
uint64_t rx_bytes
Definition: vcl_test.h:114
buf
u64 buf
Definition: application.c:493
vcl_test_stats_accumulate
static void vcl_test_stats_accumulate(vcl_test_stats_t *accum, vcl_test_stats_t *incr)
Definition: vcl_test.h:188
vcl_test_cfg_verify
static int vcl_test_cfg_verify(vcl_test_cfg_t *cfg, vcl_test_cfg_t *valid_cfg)
Definition: vcl_test.h:216
sock_client_main_t::af_unix_echo_rx
int af_unix_echo_rx
Definition: sock_test_client.c:32
exit_client
static void exit_client(void)
Definition: sock_test_client.c:439
sock_client_main_t::test_socket
vcl_test_session_t * test_socket
Definition: sock_test_client.c:37
VCL_TEST_TOKEN_EXIT
#define VCL_TEST_TOKEN_EXIT
Definition: vcl_test.h:50
VCL_TEST_TOKEN_VERBOSE
#define VCL_TEST_TOKEN_VERBOSE
Definition: vcl_test.h:51
sock_client_echo_af_unix
static void sock_client_echo_af_unix(sock_client_main_t *scm)
Definition: sock_test_client.c:90
sock_test.h
VCL_TEST_TOKEN_RXBUF_SIZE
#define VCL_TEST_TOKEN_RXBUF_SIZE
Definition: vcl_test.h:55
cfg_txbuf_size_set
static void cfg_txbuf_size_set(void)
Definition: sock_test_client.c:547
i
int i
Definition: flowhash_template.h:376
free
void free(void *p)
Definition: mem.c:42
VCL_TEST_CFG_CTRL_MAGIC
#define VCL_TEST_CFG_CTRL_MAGIC
Definition: vcl_test.h:63
vcl_test_cfg_init
static void vcl_test_cfg_init(vcl_test_cfg_t *cfg)
Definition: vcl_test.h:201
VCL_TEST_TOKEN_RUN_UNI
#define VCL_TEST_TOKEN_RUN_UNI
Definition: vcl_test.h:57
sock_client_main_t::dump_cfg
uint8_t dump_cfg
Definition: sock_test_client.c:39
rv
int __clib_unused rv
Definition: application.c:491
vcl_test_session::cfg
vcl_test_cfg_t cfg
Definition: vcl_test.h:137
sock_client_main_t::num_test_sockets
uint32_t num_test_sockets
Definition: sock_test_client.c:38
sock_test_write
static int sock_test_write(int fd, uint8_t *buf, uint32_t nbytes, vcl_test_stats_t *stats, uint32_t verbose)
Definition: sock_test.h:87
vcl_test_cfg_t
Definition: vcl_test.h:92
sock_client_main
sock_client_main_t sock_client_main
Definition: sock_test_client.c:42
print_usage_and_exit
void print_usage_and_exit(void)
Definition: sock_test_client.c:690
vcl_test_cfg_t::num_writes
uint64_t num_writes
Definition: vcl_test.h:107
cfg_verbose_toggle
static void cfg_verbose_toggle(void)
Definition: sock_test_client.c:627
vcl_test_session::txbuf_size
uint32_t txbuf_size
Definition: vcl_test.h:133
VCL_TEST_TOKEN_NUM_TEST_SESS
#define VCL_TEST_TOKEN_NUM_TEST_SESS
Definition: vcl_test.h:53
VCL_TEST_TYPE_UNI
@ VCL_TEST_TYPE_UNI
Definition: vcl_test.h:80