blob: 173bada2315fbb55bb28afa43f1b11d216d64fdf [file] [log] [blame]
Dave Wallace543852a2017-08-03 02:11:34 -04001/*
Florin Coras5e062572019-03-14 19:07:51 -07002 * Copyright (c) 2017-2019 Cisco and/or its affiliates.
Dave Wallace543852a2017-08-03 02:11:34 -04003 * 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
Dave Wallacee4d5a652018-06-24 21:21:21 -040016#include <unistd.h>
17#include <errno.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <stdio.h>
21#include <string.h>
22#include <time.h>
23#include <ctype.h>
24#include <sys/stat.h>
25#include <fcntl.h>
26#include <vcl/vcl_test.h>
27#include <sys/epoll.h>
Dave Barach6a5adc32018-07-04 10:56:23 -040028#include <vppinfra/mem.h>
Florin Coras293aa052018-08-30 18:49:13 -070029#include <pthread.h>
Dave Wallace543852a2017-08-03 02:11:34 -040030
Dave Wallacee4d5a652018-06-24 21:21:21 -040031typedef struct
32{
33 uint8_t is_alloc;
34 int fd;
35 uint8_t *buf;
36 uint32_t buf_size;
Florin Coras1502fc32018-10-05 00:50:30 -070037 vcl_test_cfg_t cfg;
38 vcl_test_stats_t stats;
Dave Wallacee4d5a652018-06-24 21:21:21 -040039 vppcom_endpt_t endpt;
40 uint8_t ip[16];
Florin Coras2cba8532018-09-11 16:33:36 -070041 vppcom_data_segments_t ds;
Florin Coras293aa052018-08-30 18:49:13 -070042} vcl_test_server_conn_t;
Dave Wallacee4d5a652018-06-24 21:21:21 -040043
44typedef struct
45{
Florin Coras293aa052018-08-30 18:49:13 -070046 uint16_t port;
Dave Wallacee4d5a652018-06-24 21:21:21 -040047 uint32_t address_ip6;
Florin Coras293aa052018-08-30 18:49:13 -070048 u8 proto;
49 u8 workers;
50 vppcom_endpt_t endpt;
51} vcl_test_server_cfg_t;
Dave Wallacee4d5a652018-06-24 21:21:21 -040052
Dave Wallacee4d5a652018-06-24 21:21:21 -040053typedef struct
54{
Florin Coras293aa052018-08-30 18:49:13 -070055 uint32_t wrk_index;
Dave Wallacee4d5a652018-06-24 21:21:21 -040056 int listen_fd;
Dave Wallacee4d5a652018-06-24 21:21:21 -040057 int epfd;
Florin Coras1502fc32018-10-05 00:50:30 -070058 struct epoll_event wait_events[VCL_TEST_CFG_MAX_EPOLL_EVENTS];
Dave Wallacee4d5a652018-06-24 21:21:21 -040059 size_t conn_pool_size;
Florin Coras293aa052018-08-30 18:49:13 -070060 vcl_test_server_conn_t *conn_pool;
Dave Wallacee4d5a652018-06-24 21:21:21 -040061 int nfds;
Florin Coras293aa052018-08-30 18:49:13 -070062 pthread_t thread_handle;
63} vcl_test_server_worker_t;
Dave Wallacee4d5a652018-06-24 21:21:21 -040064
Florin Coras293aa052018-08-30 18:49:13 -070065typedef struct
66{
67 vcl_test_server_cfg_t cfg;
68 vcl_test_server_worker_t *workers;
69
70 struct sockaddr_storage servaddr;
71 volatile int worker_fails;
72 volatile int active_workers;
Florin Coras2cba8532018-09-11 16:33:36 -070073 u8 use_ds;
Florin Coras293aa052018-08-30 18:49:13 -070074} vcl_test_server_main_t;
75
76static __thread int __wrk_index = 0;
77
Florin Coras1502fc32018-10-05 00:50:30 -070078static vcl_test_server_main_t vcl_server_main;
Florin Coras293aa052018-08-30 18:49:13 -070079
Dave Wallacee4d5a652018-06-24 21:21:21 -040080static inline void
Florin Coras293aa052018-08-30 18:49:13 -070081conn_pool_expand (vcl_test_server_worker_t * wrk, size_t expand_size)
Dave Wallacee4d5a652018-06-24 21:21:21 -040082{
Florin Coras293aa052018-08-30 18:49:13 -070083 vcl_test_server_conn_t *conn_pool;
84 size_t new_size = wrk->conn_pool_size + expand_size;
Dave Wallacee4d5a652018-06-24 21:21:21 -040085 int i;
86
Florin Coras293aa052018-08-30 18:49:13 -070087 conn_pool = realloc (wrk->conn_pool, new_size * sizeof (*wrk->conn_pool));
Dave Wallacee4d5a652018-06-24 21:21:21 -040088 if (conn_pool)
89 {
Florin Coras293aa052018-08-30 18:49:13 -070090 for (i = wrk->conn_pool_size; i < new_size; i++)
Dave Wallacee4d5a652018-06-24 21:21:21 -040091 {
Florin Coras293aa052018-08-30 18:49:13 -070092 vcl_test_server_conn_t *conn = &conn_pool[i];
Dave Wallacee4d5a652018-06-24 21:21:21 -040093 memset (conn, 0, sizeof (*conn));
Florin Coras1502fc32018-10-05 00:50:30 -070094 vcl_test_cfg_init (&conn->cfg);
95 vcl_test_buf_alloc (&conn->cfg, 1 /* is_rxbuf */ ,
96 &conn->buf, &conn->buf_size);
Dave Wallacee4d5a652018-06-24 21:21:21 -040097 conn->cfg.txbuf_size = conn->cfg.rxbuf_size;
98 }
99
Florin Coras293aa052018-08-30 18:49:13 -0700100 wrk->conn_pool = conn_pool;
101 wrk->conn_pool_size = new_size;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400102 }
103 else
104 {
Florin Coras293aa052018-08-30 18:49:13 -0700105 vterr ("conn_pool_expand()", -errno);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400106 }
107}
108
Florin Coras293aa052018-08-30 18:49:13 -0700109static inline vcl_test_server_conn_t *
110conn_pool_alloc (vcl_test_server_worker_t * wrk)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400111{
Florin Coras539663c2018-09-28 14:59:37 -0700112 int i, expand = 0;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400113
Florin Coras539663c2018-09-28 14:59:37 -0700114again:
Florin Coras293aa052018-08-30 18:49:13 -0700115 for (i = 0; i < wrk->conn_pool_size; i++)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400116 {
Florin Coras293aa052018-08-30 18:49:13 -0700117 if (!wrk->conn_pool[i].is_alloc)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400118 {
Florin Coras293aa052018-08-30 18:49:13 -0700119 wrk->conn_pool[i].endpt.ip = wrk->conn_pool[i].ip;
120 wrk->conn_pool[i].is_alloc = 1;
121 return (&wrk->conn_pool[i]);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400122 }
123 }
124
Florin Coras539663c2018-09-28 14:59:37 -0700125 if (expand == 0)
126 {
127 conn_pool_expand (wrk, 2 * wrk->conn_pool_size);
128 expand = 1;
129 goto again;
130 }
131 vtwrn ("Failed to allocate connection even after expand");
Dave Wallacee4d5a652018-06-24 21:21:21 -0400132 return 0;
133}
134
135static inline void
Florin Coras293aa052018-08-30 18:49:13 -0700136conn_pool_free (vcl_test_server_conn_t * conn)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400137{
138 conn->fd = 0;
139 conn->is_alloc = 0;
140}
141
142static inline void
Florin Coras1502fc32018-10-05 00:50:30 -0700143sync_config_and_reply (vcl_test_server_conn_t * conn, vcl_test_cfg_t * rx_cfg)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400144{
145 conn->cfg = *rx_cfg;
Florin Coras1502fc32018-10-05 00:50:30 -0700146 vcl_test_buf_alloc (&conn->cfg, 1 /* is_rxbuf */ ,
147 &conn->buf, &conn->buf_size);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400148 conn->cfg.txbuf_size = conn->cfg.rxbuf_size;
149
150 if (conn->cfg.verbose)
151 {
Florin Coras293aa052018-08-30 18:49:13 -0700152 vtinf ("(fd %d): Replying to cfg message!\n", conn->fd);
Florin Coras1502fc32018-10-05 00:50:30 -0700153 vcl_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
Dave Wallacee4d5a652018-06-24 21:21:21 -0400154 }
155 (void) vcl_test_write (conn->fd, (uint8_t *) & conn->cfg,
156 sizeof (conn->cfg), NULL, conn->cfg.verbose);
157}
158
159static void
Florin Coras6d4bb422018-09-04 22:07:27 -0700160vts_server_start_stop (vcl_test_server_worker_t * wrk,
Florin Coras1502fc32018-10-05 00:50:30 -0700161 vcl_test_server_conn_t * conn, vcl_test_cfg_t * rx_cfg)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400162{
Florin Coras1502fc32018-10-05 00:50:30 -0700163 u8 is_bi = rx_cfg->test == VCL_TEST_TYPE_BI;
Florin Coras6d4bb422018-09-04 22:07:27 -0700164 vcl_test_server_conn_t *tc;
165 char buf[64];
Florin Coras1502fc32018-10-05 00:50:30 -0700166 int i;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400167
168 if (rx_cfg->ctrl_handle == conn->fd)
169 {
Florin Coras293aa052018-08-30 18:49:13 -0700170 for (i = 0; i < wrk->conn_pool_size; i++)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400171 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700172 tc = &wrk->conn_pool[i];
173 if (tc->cfg.ctrl_handle != conn->fd)
174 continue;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400175
Florin Coras1502fc32018-10-05 00:50:30 -0700176 vcl_test_stats_accumulate (&conn->stats, &tc->stats);
177 if (vcl_comp_tspec (&conn->stats.stop, &tc->stats.stop) < 0)
178 conn->stats.stop = tc->stats.stop;
179 /* Client delays sending of disconnect */
180 conn->stats.stop.tv_sec -= VCL_TEST_DELAY_DISCONNECT;
Florin Coras6d4bb422018-09-04 22:07:27 -0700181 if (conn->cfg.verbose)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400182 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700183 sprintf (buf, "SERVER (fd %d) RESULTS", tc->fd);
Florin Coras1502fc32018-10-05 00:50:30 -0700184 vcl_test_stats_dump (buf, &tc->stats, 1 /* show_rx */ ,
185 is_bi /* show tx */ , conn->cfg.verbose);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400186 }
187 }
188
Florin Coras1502fc32018-10-05 00:50:30 -0700189 vcl_test_stats_dump ("SERVER RESULTS", &conn->stats, 1 /* show_rx */ ,
190 is_bi /* show_tx */ , conn->cfg.verbose);
191 vcl_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
Dave Wallacee4d5a652018-06-24 21:21:21 -0400192 if (conn->cfg.verbose)
193 {
Florin Coras1502fc32018-10-05 00:50:30 -0700194 vtinf (" vcl server main\n"
195 VCL_TEST_SEPARATOR_STRING
Florin Coras6d4bb422018-09-04 22:07:27 -0700196 " buf: %p\n"
197 " buf size: %u (0x%08x)\n"
Florin Coras1502fc32018-10-05 00:50:30 -0700198 VCL_TEST_SEPARATOR_STRING,
Florin Coras6d4bb422018-09-04 22:07:27 -0700199 conn->buf, conn->buf_size, conn->buf_size);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400200 }
201
202 sync_config_and_reply (conn, rx_cfg);
Florin Coras2cba8532018-09-11 16:33:36 -0700203 memset (&conn->stats, 0, sizeof (conn->stats));
Dave Wallacee4d5a652018-06-24 21:21:21 -0400204 }
205 else
206 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700207 if (rx_cfg->ctrl_handle == ~0)
Florin Coras1502fc32018-10-05 00:50:30 -0700208 {
209 rx_cfg->ctrl_handle = conn->fd;
210 vtinf ("Set control fd %d for test!", conn->fd);
211 }
212 else
213 {
214 vtinf ("Starting %s-directional Stream Test (fd %d)!",
215 is_bi ? "Bi" : "Uni", conn->fd);
216 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400217
218 sync_config_and_reply (conn, rx_cfg);
219
220 /* read the 1st chunk, record start time */
221 memset (&conn->stats, 0, sizeof (conn->stats));
222 clock_gettime (CLOCK_REALTIME, &conn->stats.start);
223 }
224}
225
Dave Wallacee4d5a652018-06-24 21:21:21 -0400226static inline void
Florin Coras6d4bb422018-09-04 22:07:27 -0700227vts_server_rx (vcl_test_server_conn_t * conn, int rx_bytes)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400228{
Florin Coras1502fc32018-10-05 00:50:30 -0700229 vcl_test_server_main_t *vsm = &vcl_server_main;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400230 int client_fd = conn->fd;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400231
Florin Coras1502fc32018-10-05 00:50:30 -0700232 if (conn->cfg.test == VCL_TEST_TYPE_BI)
Florin Coras2cba8532018-09-11 16:33:36 -0700233 {
Florin Coras1502fc32018-10-05 00:50:30 -0700234 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700235 {
236 (void) vcl_test_write (client_fd, conn->ds[0].data, conn->ds[0].len,
237 &conn->stats, conn->cfg.verbose);
238 if (conn->ds[1].len)
239 (void) vcl_test_write (client_fd, conn->ds[1].data,
240 conn->ds[1].len, &conn->stats,
241 conn->cfg.verbose);
242 }
243 else
244 (void) vcl_test_write (client_fd, conn->buf, rx_bytes, &conn->stats,
245 conn->cfg.verbose);
246 }
247
Florin Coras1502fc32018-10-05 00:50:30 -0700248 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700249 vppcom_session_free_segments (conn->fd, conn->ds);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400250
251 if (conn->stats.rx_bytes >= conn->cfg.total_bytes)
Florin Coras6d4bb422018-09-04 22:07:27 -0700252 clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400253}
254
Florin Coras293aa052018-08-30 18:49:13 -0700255static void
Florin Coras6d4bb422018-09-04 22:07:27 -0700256vts_server_echo (vcl_test_server_conn_t * conn, int rx_bytes)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400257{
Florin Coras1502fc32018-10-05 00:50:30 -0700258 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras293aa052018-08-30 18:49:13 -0700259 int tx_bytes, nbytes, pos;
260
Florin Coras1502fc32018-10-05 00:50:30 -0700261 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700262 vppcom_data_segment_copy (conn->buf, conn->ds, rx_bytes);
263
264 /* If it looks vaguely like a string, make sure it's terminated */
Florin Coras293aa052018-08-30 18:49:13 -0700265 pos = rx_bytes < conn->buf_size ? rx_bytes : conn->buf_size - 1;
266 ((char *) conn->buf)[pos] = 0;
267 vtinf ("(fd %d): RX (%d bytes) - '%s'", conn->fd, rx_bytes, conn->buf);
268
269 if (conn->cfg.verbose)
270 vtinf ("(fd %d): Echoing back", conn->fd);
271
272 nbytes = strlen ((const char *) conn->buf) + 1;
273 tx_bytes = vcl_test_write (conn->fd, conn->buf, nbytes, &conn->stats,
274 conn->cfg.verbose);
275 if (tx_bytes >= 0)
276 vtinf ("(fd %d): TX (%d bytes) - '%s'", conn->fd, tx_bytes, conn->buf);
277}
278
Florin Coras1502fc32018-10-05 00:50:30 -0700279static void
Florin Coras6d4bb422018-09-04 22:07:27 -0700280vts_new_client (vcl_test_server_worker_t * wrk)
Florin Coras293aa052018-08-30 18:49:13 -0700281{
Florin Coras293aa052018-08-30 18:49:13 -0700282 vcl_test_server_conn_t *conn;
Florin Coras1502fc32018-10-05 00:50:30 -0700283 struct epoll_event ev;
284 int rv, client_fd;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400285
Florin Coras293aa052018-08-30 18:49:13 -0700286 conn = conn_pool_alloc (wrk);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400287 if (!conn)
288 {
Florin Coras293aa052018-08-30 18:49:13 -0700289 vtwrn ("No free connections!");
Dave Wallacee4d5a652018-06-24 21:21:21 -0400290 return;
291 }
292
Florin Coras293aa052018-08-30 18:49:13 -0700293 client_fd = vppcom_session_accept (wrk->listen_fd, &conn->endpt, 0);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400294 if (client_fd < 0)
295 {
Florin Coras293aa052018-08-30 18:49:13 -0700296 vterr ("vppcom_session_accept()", client_fd);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400297 return;
298 }
Florin Coras1502fc32018-10-05 00:50:30 -0700299 conn->fd = client_fd;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400300
Florin Coras293aa052018-08-30 18:49:13 -0700301 vtinf ("Got a connection -- fd = %d (0x%08x)!", client_fd, client_fd);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400302
Florin Coras1502fc32018-10-05 00:50:30 -0700303 ev.events = EPOLLIN;
304 ev.data.u64 = conn - wrk->conn_pool;
305 rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, client_fd, &ev);
306 if (rv < 0)
307 {
308 vterr ("vppcom_epoll_ctl()", rv);
309 return;
310 }
311 wrk->nfds++;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400312}
313
Florin Coras1502fc32018-10-05 00:50:30 -0700314static void
Dave Wallacee4d5a652018-06-24 21:21:21 -0400315print_usage_and_exit (void)
316{
317 fprintf (stderr,
Florin Coras1502fc32018-10-05 00:50:30 -0700318 "vcl_test_server [OPTIONS] <port>\n"
Dave Wallacee4d5a652018-06-24 21:21:21 -0400319 " OPTIONS\n"
320 " -h Print this message and exit.\n"
321 " -6 Use IPv6\n"
Florin Coras293aa052018-08-30 18:49:13 -0700322 " -w <num> Number of workers\n"
Ping Yu34a3a082018-11-30 19:16:17 -0500323 " -D Use UDP transport layer\n"
Dave Wallace03dd90a2019-03-25 19:34:50 -0400324 " -L Use TLS transport layer\n");
Dave Wallacee4d5a652018-06-24 21:21:21 -0400325 exit (1);
326}
327
Florin Coras293aa052018-08-30 18:49:13 -0700328static void
Florin Coras1502fc32018-10-05 00:50:30 -0700329vcl_test_init_endpoint_addr (vcl_test_server_main_t * vsm)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400330{
Florin Coras1502fc32018-10-05 00:50:30 -0700331 struct sockaddr_storage *servaddr = &vsm->servaddr;
Florin Coras293aa052018-08-30 18:49:13 -0700332 memset (servaddr, 0, sizeof (*servaddr));
Dave Wallacee4d5a652018-06-24 21:21:21 -0400333
Florin Coras1502fc32018-10-05 00:50:30 -0700334 if (vsm->cfg.address_ip6)
Florin Coras293aa052018-08-30 18:49:13 -0700335 {
336 struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) servaddr;
337 server_addr->sin6_family = AF_INET6;
338 server_addr->sin6_addr = in6addr_any;
Florin Coras1502fc32018-10-05 00:50:30 -0700339 server_addr->sin6_port = htons (vsm->cfg.port);
Florin Coras293aa052018-08-30 18:49:13 -0700340 }
341 else
342 {
343 struct sockaddr_in *server_addr = (struct sockaddr_in *) servaddr;
344 server_addr->sin_family = AF_INET;
345 server_addr->sin_addr.s_addr = htonl (INADDR_ANY);
Florin Coras1502fc32018-10-05 00:50:30 -0700346 server_addr->sin_port = htons (vsm->cfg.port);
Florin Coras293aa052018-08-30 18:49:13 -0700347 }
348
Florin Coras1502fc32018-10-05 00:50:30 -0700349 if (vsm->cfg.address_ip6)
Florin Coras293aa052018-08-30 18:49:13 -0700350 {
351 struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) servaddr;
Florin Coras1502fc32018-10-05 00:50:30 -0700352 vsm->cfg.endpt.is_ip4 = 0;
353 vsm->cfg.endpt.ip = (uint8_t *) & server_addr->sin6_addr;
354 vsm->cfg.endpt.port = (uint16_t) server_addr->sin6_port;
Florin Coras293aa052018-08-30 18:49:13 -0700355 }
356 else
357 {
358 struct sockaddr_in *server_addr = (struct sockaddr_in *) servaddr;
Florin Coras1502fc32018-10-05 00:50:30 -0700359 vsm->cfg.endpt.is_ip4 = 1;
360 vsm->cfg.endpt.ip = (uint8_t *) & server_addr->sin_addr;
361 vsm->cfg.endpt.port = (uint16_t) server_addr->sin_port;
Florin Coras293aa052018-08-30 18:49:13 -0700362 }
363}
364
Florin Coras6d4bb422018-09-04 22:07:27 -0700365static void
Florin Coras1502fc32018-10-05 00:50:30 -0700366vcl_test_server_process_opts (vcl_test_server_main_t * vsm, int argc,
Florin Coras293aa052018-08-30 18:49:13 -0700367 char **argv)
368{
369 int v, c;
370
Florin Coras1502fc32018-10-05 00:50:30 -0700371 vsm->cfg.proto = VPPCOM_PROTO_TCP;
Dave Barach6a5adc32018-07-04 10:56:23 -0400372
Dave Wallacee4d5a652018-06-24 21:21:21 -0400373 opterr = 0;
Dave Wallace03dd90a2019-03-25 19:34:50 -0400374 while ((c = getopt (argc, argv, "6DLsw:")) != -1)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400375 switch (c)
376 {
377 case '6':
Florin Coras1502fc32018-10-05 00:50:30 -0700378 vsm->cfg.address_ip6 = 1;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400379 break;
380
381 case 'D':
Florin Coras1502fc32018-10-05 00:50:30 -0700382 vsm->cfg.proto = VPPCOM_PROTO_UDP;
Florin Coras293aa052018-08-30 18:49:13 -0700383 break;
384
Dave Wallace03dd90a2019-03-25 19:34:50 -0400385 case 'L':
Ping Yu34a3a082018-11-30 19:16:17 -0500386 vsm->cfg.proto = VPPCOM_PROTO_TLS;
387 break;
388
Florin Coras293aa052018-08-30 18:49:13 -0700389 case 'w':
390 v = atoi (optarg);
391 if (v > 1)
Florin Coras1502fc32018-10-05 00:50:30 -0700392 vsm->cfg.workers = v;
Florin Coras293aa052018-08-30 18:49:13 -0700393 else
394 vtwrn ("Invalid number of workers %d", v);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400395 break;
Florin Coras2cba8532018-09-11 16:33:36 -0700396 case 's':
Florin Coras1502fc32018-10-05 00:50:30 -0700397 vsm->use_ds = 1;
Florin Coras2cba8532018-09-11 16:33:36 -0700398 break;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400399 case '?':
400 switch (optopt)
401 {
402 default:
403 if (isprint (optopt))
Florin Coras6d4bb422018-09-04 22:07:27 -0700404 vtwrn ("Unknown option `-%c'.", optopt);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400405 else
Florin Coras6d4bb422018-09-04 22:07:27 -0700406 vtwrn ("Unknown option character `\\x%x'.", optopt);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400407 }
408 /* fall thru */
409 case 'h':
410 default:
411 print_usage_and_exit ();
412 }
413
414 if (argc < (optind + 1))
415 {
416 fprintf (stderr, "SERVER: ERROR: Insufficient number of arguments!\n");
417 print_usage_and_exit ();
418 }
419
420 if (sscanf (argv[optind], "%d", &v) == 1)
Florin Coras1502fc32018-10-05 00:50:30 -0700421 vsm->cfg.port = (uint16_t) v;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400422 else
423 {
424 fprintf (stderr, "SERVER: ERROR: Invalid port (%s)!\n", argv[optind]);
425 print_usage_and_exit ();
426 }
427
Florin Coras1502fc32018-10-05 00:50:30 -0700428 vcl_test_init_endpoint_addr (vsm);
Florin Coras293aa052018-08-30 18:49:13 -0700429}
Dave Wallacee4d5a652018-06-24 21:21:21 -0400430
Florin Coras293aa052018-08-30 18:49:13 -0700431int
Florin Coras1502fc32018-10-05 00:50:30 -0700432vts_handle_cfg (vcl_test_server_worker_t * wrk, vcl_test_cfg_t * rx_cfg,
Florin Coras6d4bb422018-09-04 22:07:27 -0700433 vcl_test_server_conn_t * conn, int rx_bytes)
Florin Coras293aa052018-08-30 18:49:13 -0700434{
435 if (rx_cfg->verbose)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400436 {
Florin Coras293aa052018-08-30 18:49:13 -0700437 vtinf ("(fd %d): Received a cfg msg!", conn->fd);
Florin Coras1502fc32018-10-05 00:50:30 -0700438 vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
Dave Wallacee4d5a652018-06-24 21:21:21 -0400439 }
440
Florin Coras293aa052018-08-30 18:49:13 -0700441 if (rx_bytes != sizeof (*rx_cfg))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400442 {
Florin Coras293aa052018-08-30 18:49:13 -0700443 vtinf ("(fd %d): Invalid cfg msg size %d expected %lu!", conn->fd,
444 rx_bytes, sizeof (*rx_cfg));
445 conn->cfg.rxbuf_size = 0;
446 conn->cfg.num_writes = 0;
447 if (conn->cfg.verbose)
Florin Coras460dce62018-07-27 05:45:06 -0700448 {
Florin Coras293aa052018-08-30 18:49:13 -0700449 vtinf ("(fd %d): Replying to cfg msg", conn->fd);
Florin Coras1502fc32018-10-05 00:50:30 -0700450 vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
Florin Coras460dce62018-07-27 05:45:06 -0700451 }
Florin Coras293aa052018-08-30 18:49:13 -0700452 vcl_test_write (conn->fd, (uint8_t *) & conn->cfg,
453 sizeof (conn->cfg), NULL, conn->cfg.verbose);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400454 return -1;
455 }
456
Florin Coras293aa052018-08-30 18:49:13 -0700457 switch (rx_cfg->test)
458 {
Florin Coras1502fc32018-10-05 00:50:30 -0700459 case VCL_TEST_TYPE_NONE:
460 case VCL_TEST_TYPE_ECHO:
Florin Coras293aa052018-08-30 18:49:13 -0700461 sync_config_and_reply (conn, rx_cfg);
462 break;
463
Florin Coras1502fc32018-10-05 00:50:30 -0700464 case VCL_TEST_TYPE_BI:
465 case VCL_TEST_TYPE_UNI:
Florin Coras6d4bb422018-09-04 22:07:27 -0700466 vts_server_start_stop (wrk, conn, rx_cfg);
Florin Coras293aa052018-08-30 18:49:13 -0700467 break;
468
Florin Coras1502fc32018-10-05 00:50:30 -0700469 case VCL_TEST_TYPE_EXIT:
470 vtinf ("Session fd %d closing!", conn->fd);
471 clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
Florin Coras293aa052018-08-30 18:49:13 -0700472 vppcom_session_close (conn->fd);
473 conn_pool_free (conn);
Florin Coras293aa052018-08-30 18:49:13 -0700474 wrk->nfds--;
475 break;
476
477 default:
478 vtwrn ("Unknown test type %d", rx_cfg->test);
Florin Coras1502fc32018-10-05 00:50:30 -0700479 vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
Florin Coras293aa052018-08-30 18:49:13 -0700480 break;
481 }
482
483 return 0;
484}
485
486static void
Florin Coras6d4bb422018-09-04 22:07:27 -0700487vts_worker_init (vcl_test_server_worker_t * wrk)
Florin Coras293aa052018-08-30 18:49:13 -0700488{
Florin Coras1502fc32018-10-05 00:50:30 -0700489 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras293aa052018-08-30 18:49:13 -0700490 struct epoll_event listen_ev;
491 int rv;
492
493 __wrk_index = wrk->wrk_index;
494
495 vtinf ("Initializing worker ...");
496
Florin Coras1502fc32018-10-05 00:50:30 -0700497 conn_pool_expand (wrk, VCL_TEST_CFG_MAX_TEST_SESS + 1);
Florin Coras293aa052018-08-30 18:49:13 -0700498 if (wrk->wrk_index)
Florin Corasde9f08b2018-09-07 14:32:58 -0700499 if (vppcom_worker_register ())
500 vtfail ("vppcom_worker_register()", 1);
Florin Coras293aa052018-08-30 18:49:13 -0700501
Florin Coras1502fc32018-10-05 00:50:30 -0700502 wrk->listen_fd = vppcom_session_create (vsm->cfg.proto,
Florin Coras293aa052018-08-30 18:49:13 -0700503 0 /* is_nonblocking */ );
504 if (wrk->listen_fd < 0)
505 vtfail ("vppcom_session_create()", wrk->listen_fd);
506
Ping Yu34a3a082018-11-30 19:16:17 -0500507
508 if (vsm->cfg.proto == VPPCOM_PROTO_TLS)
509 {
510 vppcom_session_tls_add_cert (wrk->listen_fd, vcl_test_crt_rsa,
511 vcl_test_crt_rsa_len);
512 vppcom_session_tls_add_key (wrk->listen_fd, vcl_test_key_rsa,
513 vcl_test_key_rsa_len);
514 }
515
Florin Coras1502fc32018-10-05 00:50:30 -0700516 rv = vppcom_session_bind (wrk->listen_fd, &vsm->cfg.endpt);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400517 if (rv < 0)
Florin Coras293aa052018-08-30 18:49:13 -0700518 vtfail ("vppcom_session_bind()", rv);
519
Florin Coras1502fc32018-10-05 00:50:30 -0700520 if (!(vsm->cfg.proto == VPPCOM_PROTO_UDP))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400521 {
Florin Coras293aa052018-08-30 18:49:13 -0700522 rv = vppcom_session_listen (wrk->listen_fd, 10);
523 if (rv < 0)
524 vtfail ("vppcom_session_listen()", rv);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400525 }
Florin Coras293aa052018-08-30 18:49:13 -0700526
527 wrk->epfd = vppcom_epoll_create ();
528 if (wrk->epfd < 0)
529 vtfail ("vppcom_epoll_create()", wrk->epfd);
530
531 listen_ev.events = EPOLLIN;
532 listen_ev.data.u32 = ~0;
533 rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, wrk->listen_fd,
534 &listen_ev);
535 if (rv < 0)
536 vtfail ("vppcom_epoll_ctl", rv);
537
Florin Coras1502fc32018-10-05 00:50:30 -0700538 vsm->active_workers += 1;
539 vtinf ("Waiting for a client to connect on port %d ...", vsm->cfg.port);
Florin Coras293aa052018-08-30 18:49:13 -0700540}
541
Florin Coras2cba8532018-09-11 16:33:36 -0700542static int
543vts_conn_expect_config (vcl_test_server_conn_t * conn)
544{
Florin Coras1502fc32018-10-05 00:50:30 -0700545 if (conn->cfg.test == VCL_TEST_TYPE_ECHO)
Florin Coras2cba8532018-09-11 16:33:36 -0700546 return 1;
547
548 return (conn->stats.rx_bytes < 128
Florin Coras1502fc32018-10-05 00:50:30 -0700549 || conn->stats.rx_bytes > conn->cfg.total_bytes);
Florin Coras2cba8532018-09-11 16:33:36 -0700550}
551
Florin Coras1502fc32018-10-05 00:50:30 -0700552static vcl_test_cfg_t *
Florin Coras2cba8532018-09-11 16:33:36 -0700553vts_conn_read_config (vcl_test_server_conn_t * conn)
554{
Florin Coras1502fc32018-10-05 00:50:30 -0700555 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras2cba8532018-09-11 16:33:36 -0700556
Florin Coras1502fc32018-10-05 00:50:30 -0700557 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700558 {
559 /* We could avoid the copy if the first segment is big enough but this
560 * just simplifies things */
Florin Coras1502fc32018-10-05 00:50:30 -0700561 vppcom_data_segment_copy (conn->buf, conn->ds, sizeof (vcl_test_cfg_t));
Florin Coras2cba8532018-09-11 16:33:36 -0700562 }
Florin Coras1502fc32018-10-05 00:50:30 -0700563 return (vcl_test_cfg_t *) conn->buf;
Florin Coras2cba8532018-09-11 16:33:36 -0700564}
565
566static inline int
567vts_conn_read (vcl_test_server_conn_t * conn)
568{
Florin Coras1502fc32018-10-05 00:50:30 -0700569 vcl_test_server_main_t *vsm = &vcl_server_main;
570 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700571 return vcl_test_read_ds (conn->fd, conn->ds, &conn->stats);
572 else
573 return vcl_test_read (conn->fd, conn->buf, conn->buf_size, &conn->stats);
574}
575
576static inline int
577vts_conn_has_ascii (vcl_test_server_conn_t * conn)
578{
Florin Coras1502fc32018-10-05 00:50:30 -0700579 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras2cba8532018-09-11 16:33:36 -0700580
Florin Coras1502fc32018-10-05 00:50:30 -0700581 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700582 return isascii (conn->ds[0].data[0]);
583 else
584 return isascii (conn->buf[0]);
585}
586
Florin Coras293aa052018-08-30 18:49:13 -0700587static void *
Florin Coras6d4bb422018-09-04 22:07:27 -0700588vts_worker_loop (void *arg)
Florin Coras293aa052018-08-30 18:49:13 -0700589{
Florin Coras1502fc32018-10-05 00:50:30 -0700590 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras293aa052018-08-30 18:49:13 -0700591 vcl_test_server_worker_t *wrk = arg;
592 vcl_test_server_conn_t *conn;
593 int i, rx_bytes, num_ev;
Florin Coras1502fc32018-10-05 00:50:30 -0700594 vcl_test_cfg_t *rx_cfg;
Florin Coras293aa052018-08-30 18:49:13 -0700595
596 if (wrk->wrk_index)
Florin Coras6d4bb422018-09-04 22:07:27 -0700597 vts_worker_init (wrk);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400598
599 while (1)
600 {
Florin Coras293aa052018-08-30 18:49:13 -0700601 num_ev = vppcom_epoll_wait (wrk->epfd, wrk->wait_events,
Florin Coras1502fc32018-10-05 00:50:30 -0700602 VCL_TEST_CFG_MAX_EPOLL_EVENTS, 60000.0);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400603 if (num_ev < 0)
604 {
Florin Coras293aa052018-08-30 18:49:13 -0700605 vterr ("vppcom_epoll_wait()", num_ev);
606 goto fail;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400607 }
608 else if (num_ev == 0)
609 {
Florin Coras293aa052018-08-30 18:49:13 -0700610 vtinf ("vppcom_epoll_wait() timeout!");
Dave Wallacee4d5a652018-06-24 21:21:21 -0400611 continue;
612 }
613 for (i = 0; i < num_ev; i++)
614 {
Florin Coras293aa052018-08-30 18:49:13 -0700615 conn = &wrk->conn_pool[wrk->wait_events[i].data.u32];
616 if (wrk->wait_events[i].events & (EPOLLHUP | EPOLLRDHUP))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400617 {
618 vppcom_session_close (conn->fd);
Florin Coras21795132018-09-09 09:40:51 -0700619 wrk->nfds -= 1;
620 if (!wrk->nfds)
621 {
622 vtinf ("All client connections closed\n");
623 goto done;
624 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400625 continue;
626 }
Florin Coras293aa052018-08-30 18:49:13 -0700627 if (wrk->wait_events[i].data.u32 == ~0)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400628 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700629 vts_new_client (wrk);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400630 continue;
631 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400632
Florin Coras293aa052018-08-30 18:49:13 -0700633 if (EPOLLIN & wrk->wait_events[i].events)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400634 {
Florin Coras21795132018-09-09 09:40:51 -0700635 read_again:
Florin Coras2cba8532018-09-11 16:33:36 -0700636 rx_bytes = vts_conn_read (conn);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400637
Florin Coras293aa052018-08-30 18:49:13 -0700638 if (rx_bytes <= 0)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400639 {
640 if (errno == ECONNRESET)
641 {
Florin Coras293aa052018-08-30 18:49:13 -0700642 vtinf ("Connection reset by remote peer.\n");
643 goto fail;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400644 }
645 else
646 continue;
647 }
648
Florin Coras2cba8532018-09-11 16:33:36 -0700649 if (vts_conn_expect_config (conn))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400650 {
Florin Coras2cba8532018-09-11 16:33:36 -0700651 rx_cfg = vts_conn_read_config (conn);
Florin Coras1502fc32018-10-05 00:50:30 -0700652 if (rx_cfg->magic == VCL_TEST_CFG_CTRL_MAGIC)
Florin Coras293aa052018-08-30 18:49:13 -0700653 {
Florin Coras1502fc32018-10-05 00:50:30 -0700654 if (vsm->use_ds)
655 vppcom_session_free_segments (conn->fd, conn->ds);
Florin Coras2cba8532018-09-11 16:33:36 -0700656 vts_handle_cfg (wrk, rx_cfg, conn, rx_bytes);
657 if (!wrk->nfds)
658 {
659 vtinf ("All client connections closed\n");
660 goto done;
661 }
662 continue;
Florin Coras293aa052018-08-30 18:49:13 -0700663 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400664 }
Florin Coras1502fc32018-10-05 00:50:30 -0700665 if ((conn->cfg.test == VCL_TEST_TYPE_UNI)
666 || (conn->cfg.test == VCL_TEST_TYPE_BI))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400667 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700668 vts_server_rx (conn, rx_bytes);
Florin Coras21795132018-09-09 09:40:51 -0700669 if (vppcom_session_attr (conn->fd, VPPCOM_ATTR_GET_NREAD, 0,
670 0) > 0)
671 goto read_again;
Florin Coras293aa052018-08-30 18:49:13 -0700672 continue;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400673 }
Florin Coras2cba8532018-09-11 16:33:36 -0700674 if (vts_conn_has_ascii (conn))
Florin Coras293aa052018-08-30 18:49:13 -0700675 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700676 vts_server_echo (conn, rx_bytes);
Florin Coras293aa052018-08-30 18:49:13 -0700677 }
678 else
679 {
680 vtwrn ("FIFO not drained! extra bytes %d", rx_bytes);
681 }
682 }
683 else
684 {
685 vtwrn ("Unhandled event");
686 goto fail;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400687 }
688 }
689 }
690
Florin Coras293aa052018-08-30 18:49:13 -0700691fail:
Florin Coras1502fc32018-10-05 00:50:30 -0700692 vsm->worker_fails -= 1;
Florin Coras293aa052018-08-30 18:49:13 -0700693
Dave Wallacee4d5a652018-06-24 21:21:21 -0400694done:
Florin Coras293aa052018-08-30 18:49:13 -0700695 vppcom_session_close (wrk->listen_fd);
696 if (wrk->conn_pool)
697 free (wrk->conn_pool);
Florin Coras1502fc32018-10-05 00:50:30 -0700698 vsm->active_workers -= 1;
Florin Coras293aa052018-08-30 18:49:13 -0700699 return 0;
700}
701
702int
703main (int argc, char **argv)
704{
Florin Coras1502fc32018-10-05 00:50:30 -0700705 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras293aa052018-08-30 18:49:13 -0700706 int rv, i;
707
708 clib_mem_init_thread_safe (0, 64 << 20);
Florin Coras1502fc32018-10-05 00:50:30 -0700709 vsm->cfg.port = VCL_TEST_SERVER_PORT;
Florin Coras6d4bb422018-09-04 22:07:27 -0700710 vsm->cfg.workers = 1;
Florin Coras2cba8532018-09-11 16:33:36 -0700711 vsm->active_workers = 0;
Florin Coras6d4bb422018-09-04 22:07:27 -0700712 vcl_test_server_process_opts (vsm, argc, argv);
Florin Coras293aa052018-08-30 18:49:13 -0700713
714 rv = vppcom_app_create ("vcl_test_server");
715 if (rv)
716 vtfail ("vppcom_app_create()", rv);
717
Florin Coras6d4bb422018-09-04 22:07:27 -0700718 vsm->workers = calloc (vsm->cfg.workers, sizeof (*vsm->workers));
719 vts_worker_init (&vsm->workers[0]);
720 for (i = 1; i < vsm->cfg.workers; i++)
Florin Coras293aa052018-08-30 18:49:13 -0700721 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700722 vsm->workers[i].wrk_index = i;
723 rv = pthread_create (&vsm->workers[i].thread_handle, NULL,
724 vts_worker_loop, (void *) &vsm->workers[i]);
Florin Coras293aa052018-08-30 18:49:13 -0700725 }
Florin Coras6d4bb422018-09-04 22:07:27 -0700726 vts_worker_loop (&vsm->workers[0]);
Florin Coras293aa052018-08-30 18:49:13 -0700727
Florin Coras6d4bb422018-09-04 22:07:27 -0700728 while (vsm->active_workers > 0)
Florin Coras293aa052018-08-30 18:49:13 -0700729 ;
730
Dave Wallacee4d5a652018-06-24 21:21:21 -0400731 vppcom_app_destroy ();
Florin Coras6d4bb422018-09-04 22:07:27 -0700732 free (vsm->workers);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400733
Florin Coras6d4bb422018-09-04 22:07:27 -0700734 return vsm->worker_fails;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400735}
Dave Wallace543852a2017-08-03 02:11:34 -0400736
737/*
738 * fd.io coding-style-patch-verification: ON
739 *
740 * Local Variables:
741 * eval: (c-set-style "gnu")
742 * End:
743 */