/* * Copyright (c) 2017-2019 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #ifndef VCL_TEST #include #endif typedef struct { #ifdef VCL_TEST vppcom_endpt_t server_endpt; #else int af_unix_echo_tx; int af_unix_echo_rx; #endif struct sockaddr_storage server_addr; uint32_t server_addr_size; uint32_t cfg_seq_num; vcl_test_session_t ctrl_socket; vcl_test_session_t *test_socket; uint32_t num_test_sockets; uint8_t dump_cfg; } sock_client_main_t; sock_client_main_t vcl_client_main; static int sock_test_cfg_sync (vcl_test_session_t * socket) { sock_client_main_t *scm = &vcl_client_main; vcl_test_session_t *ctrl = &scm->ctrl_socket; vcl_test_cfg_t *rl_cfg = (vcl_test_cfg_t *) socket->rxbuf; int rx_bytes, tx_bytes; if (socket->cfg.verbose) vcl_test_cfg_dump (&socket->cfg, 1 /* is_client */ ); ctrl->cfg.seq_num = ++scm->cfg_seq_num; if (socket->cfg.verbose) { printf ("CLIENT (fd %d): Sending config sent to server.\n", socket->fd); vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ ); } tx_bytes = sock_test_write (socket->fd, (uint8_t *) & ctrl->cfg, sizeof (ctrl->cfg), NULL, ctrl->cfg.verbose); if (tx_bytes < 0) { fprintf (stderr, "CLIENT (fd %d): ERROR: write test cfg failed (%d)!\n", socket->fd, tx_bytes); return tx_bytes; } rx_bytes = sock_test_read (socket->fd, (uint8_t *) socket->rxbuf, sizeof (vcl_test_cfg_t), NULL); if (rx_bytes < 0) return rx_bytes; if (rl_cfg->magic != VCL_TEST_CFG_CTRL_MAGIC) { fprintf (stderr, "CLIENT (fd %d): ERROR: Bad server reply cfg " "-- aborting!\n", socket->fd); return -1; } if ((rx_bytes != sizeof (vcl_test_cfg_t)) || !vcl_test_cfg_verify (rl_cfg, &ctrl->cfg)) { fprintf (stderr, "CLIENT (fd %d): ERROR: Invalid config received " "from server!\n", socket->fd); if (rx_bytes != sizeof (vcl_test_cfg_t)) { fprintf (stderr, "\tRx bytes %d != cfg size %lu\n", rx_bytes, sizeof (vcl_test_cfg_t)); } else { vcl_test_cfg_dump (rl_cfg, 1 /* is_client */ ); fprintf (stderr, "CLIENT (fd %d): Valid config sent to server.\n", socket->fd); vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ ); } return -1; } else if (socket->cfg.verbose) { printf ("CLIENT (fd %d): Got config back from server.\n", socket->fd); vcl_test_cfg_dump (rl_cfg, 1 /* is_client */ ); } ctrl->cfg.ctrl_handle = ((ctrl->cfg.ctrl_handle == ~0) ? rl_cfg->ctrl_handle : ctrl->cfg.ctrl_handle); return 0; } static void echo_test_client () { sock_client_main_t *scm = &vcl_client_main; vcl_test_session_t *ctrl = &scm->ctrl_socket; vcl_test_session_t *tsock; int rx_bytes, tx_bytes, nbytes; uint32_t i, n; int rv; int nfds = 0; fd_set wr_fdset, rd_fdset; fd_set _wfdset, *wfdset = &_wfdset; fd_set _rfdset, *rfdset = &_rfdset; FD_ZERO (&wr_fdset); FD_ZERO (&rd_fdset); memset (&ctrl->stats, 0, sizeof (ctrl->stats)); ctrl->cfg.total_bytes = nbytes = strlen (ctrl->txbuf) + 1; for (n = 0; n != ctrl->cfg.num_test_sessions; n++) { tsock = &scm->test_socket[n]; tsock->cfg = ctrl->cfg; vcl_test_session_buf_alloc (tsock); if (sock_test_cfg_sync (tsock)) return; memcpy (tsock->txbuf, ctrl->txbuf, nbytes); memset (&tsock->stats, 0, sizeof (tsock->stats)); FD_SET (tsock->fd, &wr_fdset); FD_SET (tsock->fd, &rd_fdset); nfds = ((tsock->fd + 1) > nfds) ? (tsock->fd + 1) : nfds; } nfds++; clock_gettime (CLOCK_REALTIME, &ctrl->stats.start); while (n) { _wfdset = wr_fdset; _rfdset = rd_fdset; #ifdef VCL_TEST rv = vppcom_select (nfds, (unsigned long *) rfdset, (unsigned long *) wfdset, NULL, 0); #else { struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 0; rv = select (nfds, rfdset, wfdset, NULL, &timeout); } #endif if (rv < 0) { perror ("select()"); fprintf (stderr, "\nCLIENT: ERROR: select() failed -- " "aborting test!\n"); return; } else if (rv == 0) continue; for (i = 0; i < ctrl->cfg.num_test_sessions; i++) { tsock = &scm->test_socket[i]; if (!((tsock->stats.stop.tv_sec == 0) && (tsock->stats.stop.tv_nsec == 0))) continue; if (FD_ISSET (tsock->fd, wfdset) && (tsock->stats.tx_bytes < ctrl->cfg.total_bytes)) { tx_bytes = sock_test_write (tsock->fd, (uint8_t *) tsock->txbuf, nbytes, &tsock->stats, ctrl->cfg.verbose); if (tx_bytes < 0) { fprintf (stderr, "\nCLIENT: ERROR: sock_test_write(%d) " "failed -- aborting test!\n", tsock->fd); return; } printf ("CLIENT (fd %d): TX (%d bytes) - '%s'\n", tsock->fd, tx_bytes, tsock->txbuf); } if ((FD_ISSET (tsock->fd, rfdset)) && (tsock->stats.rx_bytes < ctrl->cfg.total_bytes)) { rx_bytes = sock_test_read (tsock->fd, (uint8_t *) tsock->rxbuf, nbytes, &tsock->stats); if (rx_bytes > 0) { printf ("CLIENT (fd %d): RX (%d bytes) - '%s'\n", tsock->fd, rx_bytes, tsock->rxbuf); if (tsock->stats.rx_bytes != tsock->stats.tx_bytes) printf ("CLIENT: WARNING: bytes read (%lu) " "!= bytes written (%lu)!\n", tsock->stats.rx_bytes, tsock->stats.tx_bytes); } } if (tsock->stats.rx_bytes >= ctrl->cfg.total_bytes) { clock_gettime (CLOCK_REALTIME, &tsock->stats.stop); n--; } } } clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop); #ifndef VCL_TEST { int fd, errno_val; struct sockaddr_un serveraddr; uint8_t buffer[256]; size_t nbytes = strlen (SOCK_TEST_MIXED_EPOLL_DATA) + 1; struct timeval timeout; /* Open AF_UNIX socket and send an echo to test mixed epoll on server. */ fd = socket (AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { errno_val = errno; perror ("ERROR in echo_test_client(): socket(AF_UNIX) failed"); fprintf (stderr, "CLIENT: ERROR: socket(AF_UNIX, SOCK_STREAM, 0) failed " "(errno = %d)!\n", errno_val); goto out; } memset (&serveraddr, 0, sizeof (serveraddr)); serveraddr.sun_family = AF_UNIX; strcpy (serveraddr.sun_path, SOCK_TEST_AF_UNIX_FILENAME); rv = connect (fd, (struct sockaddr *) &serveraddr, SUN_LEN (&serveraddr)); if (rv < 0) { errno_val = errno; perror ("ERROR in echo_test_client(): connect() failed"); fprintf (stderr, "CLIENT: ERROR: connect(fd %d, \"%s\", %lu) " "failed (errno = %d)!\n", fd, SOCK_TEST_AF_UNIX_FILENAME, SUN_LEN (&serveraddr), errno_val); goto done; } scm->af_unix_echo_tx++; strcpy ((char *) buffer, SOCK_TEST_MIXED_EPOLL_DATA); timeout.tv_sec = 0; timeout.tv_usec = 250000; select (0, NULL, NULL, NULL, &timeout); /* delay .25 secs */ rv = write (fd, buffer, nbytes); if (rv < 0) { errno_val = errno; perror ("ERROR in echo_test_client(): write() failed"); fprintf (stderr, "CLIENT: ERROR: write(fd %d, \"%s\", %lu) " "failed (errno = %d)!\n", fd, buffer, nbytes, errno_val); goto done; } else if (rv < nbytes) { fprintf (stderr, "CLIENT: ERROR: write(fd %d, \"%s\", %lu) " "returned %d!\n", fd, buffer, nbytes, rv); goto done; } printf ("CLIENT (AF_UNIX): TX (%d bytes) - '%s'\n", rv, buffer); memset (buffer, 0, sizeof (buffer)); rv = read (fd, buffer, nbytes); if (rv < 0) { errno_val = errno; perror ("ERROR in echo_test_client(): read() failed"); fprintf (stderr, "CLIENT: ERROR: read(fd %d, %p, %lu) " "failed (errno = %d)!\n", fd, buffer, nbytes, errno_val); goto done; } else if (rv < nbytes) { fprintf (stderr
/*
 * Copyright (c) 2017 Cisco and/or its affiliates.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#undef BIHASH_TYPE
#undef BIHASH_KVP_PER_PAGE

#define BIHASH_TYPE _vec8_8
#define BIHASH_KVP_PER_PAGE 4

#ifndef __included_bihash_vec8_8_h__
#define __included_bihash_vec8_8_h__

#include <vppinfra/heap.h>
#include <vppinfra/format.h>
#include <vppinfra/pool.h>
#include <vppinfra/xxhash.h>
#include <vppinfra/crc32.h>

/** 8 octet key, 8 octet key value pair */
typedef struct
{
  u64 key;			/**< the key */
  u64 value;			/**< the value */
} clib_bihash_kv_vec8_8_t;

/** Decide if a clib_bihash_kv_vec8_8_t instance is free
    @param v- pointer to the (key,value) pair
*/
static inline int
clib_bihash_is_free_vec8_8 (clib_bihash_kv_vec8_8_t * v)
{
  if (v->key == ~0ULL && v->value == ~0ULL)
    return 1;
  return 0;
}

/** Hash a clib_bihash_kv_vec8_8_t instance
    @param v - pointer to the (key,value) pair, hash the key (only)
*/
static inline u64
clib_bihash_hash_vec8_8 (clib_bihash_kv_vec8_8_t * v)
{
  u8 *keyp = (u8 *) (v->key);
  /* Note: to torture-test linear scan, make this fn return a constant */
#ifdef clib_crc32c_uses_intrinsics
  return clib_crc32c (keyp, vec_len (keyp));
#else
  {
    int i, j;
    u64 sum = 0;

    for (i = 0, j = 0; i < vec_len (keyp); i++)
      {
	sum ^= keyp[i] << (j * 8);
	j++;
	if (j == 4)
	  j = 0;
      }

    return clib_xxhash (sum);
  }
#endif
}

/** Format a clib_bihash_kv_vec8_8_t instance
    @param s - u8 * vector under construction
    @param args (vararg) - the (key,value) pair to format
    @return s - the u8 * vector under construction
*/
static inline u8 *
format_bihash_kvp_vec8_8 (u8 * s, va_list * args)
{
  clib_bihash_kv_vec8_8_t *v = va_arg (*args, clib_bihash_kv_vec8_8_t *);

  s = format (s, "key %U value %llu",
	      format_hex_bytes, v->key, vec_len ((u8 *) (v->key)), v->value);
  return s;
}

/** Compare two clib_bihash_kv_vec8_8_t instances
    @param a - first key
    @param b - second key
*/
static inline int
clib_bihash_key_compare_vec8_8 (u64 a_arg, u64 b_arg)
{
  u8 *a = (u8 *) a_arg;
  u8 *b = (u8 *) b_arg;

  if (a_arg == ~0ULL || b_arg == ~0ULL)
    return 0;

  if (vec_len (a) != vec_len (b))
    return 0;

  return memcmp (a, b, vec_len (a)) == 0;
}

#undef __included_bihash_template_h__
#include <vppinfra/bihash_template.h>

#endif /* __included_bihash_vec8_8_h__ */

/*
 * fd.io coding-style-patch-verification: ON
 *
 * Local Variables:
 * eval: (c-set-style "gnu")
 * End:
 */
r, "CLIENT: ERROR: Option -%c " "requires an argument.\n", optopt); break; default: if (isprint (optopt)) fprintf (stderr, "CLIENT: ERROR: Unknown " "option `-%c'.\n", optopt); else fprintf (stderr, "CLIENT: ERROR: Unknown " "option character `\\x%x'.\n", optopt); } /* fall thru */ case 'h': default: print_usage_and_exit (); } if (argc < (optind + 2)) { fprintf (stderr, "CLIENT: ERROR: Insufficient number of arguments!\n"); print_usage_and_exit (); } #ifdef VCL_TEST ctrl->fd = vppcom_app_create ("vcl_test_client"); if (ctrl->fd < 0) { errno = -ctrl->fd; ctrl->fd = -1; } else { ctrl->fd = vppcom_session_create (ctrl->cfg.transport_udp ? VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP, 0 /* is_nonblocking */ ); if (ctrl->fd < 0) { errno = -ctrl->fd; ctrl->fd = -1; } } #else ctrl->fd = socket (ctrl->cfg.address_ip6 ? AF_INET6 : AF_INET, ctrl->cfg.transport_udp ? SOCK_DGRAM : SOCK_STREAM, 0); #endif if (ctrl->fd < 0) { errno_val = errno; perror ("ERROR in main()"); fprintf (stderr, "CLIENT: ERROR: socket " "failed (errno = %d)!\n", errno_val); return ctrl->fd; } memset (&scm->server_addr, 0, sizeof (scm->server_addr)); if (ctrl->cfg.address_ip6) { struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) &scm->server_addr; scm->server_addr_size = sizeof (*server_addr); server_addr->sin6_family = AF_INET6; inet_pton (AF_INET6, argv[optind++], &(server_addr->sin6_addr)); server_addr->sin6_port = htons (atoi (argv[optind])); } else { struct sockaddr_in *server_addr = (struct sockaddr_in *) &scm->server_addr; scm->server_addr_size = sizeof (*server_addr); server_addr->sin_family = AF_INET; inet_pton (AF_INET, argv[optind++], &(server_addr->sin_addr)); server_addr->sin_port = htons (atoi (argv[optind])); } #ifdef VCL_TEST if (ctrl->cfg.address_ip6) { struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) &scm->server_addr; scm->server_endpt.is_ip4 = 0; scm->server_endpt.ip = (uint8_t *) & server_addr->sin6_addr; scm->server_endpt.port = (uint16_t) server_addr->sin6_port; } else { struct sockaddr_in *server_addr = (struct sockaddr_in *) &scm->server_addr; scm->server_endpt.is_ip4 = 1; scm->server_endpt.ip = (uint8_t *) & server_addr->sin_addr; scm->server_endpt.port = (uint16_t) server_addr->sin_port; } #endif do { printf ("\nCLIENT: Connecting to server...\n"); #ifdef VCL_TEST rv = vppcom_session_connect (ctrl->fd, &scm->server_endpt); if (rv) { errno = -rv; rv = -1; } #else rv = connect (ctrl->fd, (struct sockaddr *) &scm->server_addr, scm->server_addr_size); #endif if (rv < 0) { errno_val = errno; perror ("ERROR in main()"); fprintf (stderr, "CLIENT: ERROR: connect failed (errno = %d)!\n", errno_val); return -1; } sock_test_cfg_sync (ctrl); printf ("CLIENT (fd %d): Control socket connected.\n", ctrl->fd); } while (rv < 0); sock_test_connect_test_sockets (ctrl->cfg.num_test_sessions); while (ctrl->cfg.test != VCL_TEST_TYPE_EXIT) { if (scm->dump_cfg) { vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ ); scm->dump_cfg = 0; } switch (ctrl->cfg.test) { case VCL_TEST_TYPE_ECHO: echo_test_client (); break; case VCL_TEST_TYPE_UNI: case VCL_TEST_TYPE_BI: stream_test_client (ctrl->cfg.test); break; case VCL_TEST_TYPE_EXIT: continue; case VCL_TEST_TYPE_NONE: default: break; } switch (post_test) { case VCL_TEST_TYPE_EXIT: switch (ctrl->cfg.test) { case VCL_TEST_TYPE_EXIT: case VCL_TEST_TYPE_UNI: case VCL_TEST_TYPE_BI: case VCL_TEST_TYPE_ECHO: ctrl->cfg.test = VCL_TEST_TYPE_EXIT; continue; case VCL_TEST_TYPE_NONE: default: break; } break; case VCL_TEST_TYPE_NONE: case VCL_TEST_TYPE_ECHO: case VCL_TEST_TYPE_UNI: case VCL_TEST_TYPE_BI: default: break; } memset (ctrl->txbuf, 0, ctrl->txbuf_size); memset (ctrl->rxbuf, 0, ctrl->rxbuf_size); printf ("\nCLIENT: Type some characters and hit \n" "('" VCL_TEST_TOKEN_HELP "' for help): "); if (fgets (ctrl->txbuf, ctrl->txbuf_size, stdin) != NULL) { if (strlen (ctrl->txbuf) == 1) { printf ("\nCLIENT: Nothing to send! Please try again...\n"); continue; } ctrl->txbuf[strlen (ctrl->txbuf) - 1] = 0; // chomp the newline. /* Parse input for keywords */ ctrl->cfg.test = parse_input (); } } exit_client (); #ifdef VCL_TEST vppcom_session_close (ctrl->fd); vppcom_app_destroy (); return 0; #else close (ctrl->fd); return (scm->af_unix_echo_tx == scm->af_unix_echo_rx) ? 0 : -1; #endif } /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */