blob: 54f164e43c1514c94eff5faf8d2b377cd599ffdb [file] [log] [blame]
Dave Wallace543852a2017-08-03 02:11:34 -04001/*
Dave Wallacee4d5a652018-06-24 21:21:21 -04002 * Copyright (c) 2017-2018 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"
Dave Wallacee4d5a652018-06-24 21:21:21 -0400323 " -u Use UDP transport layer\n");
324 exit (1);
325}
326
Florin Coras293aa052018-08-30 18:49:13 -0700327static void
Florin Coras1502fc32018-10-05 00:50:30 -0700328vcl_test_init_endpoint_addr (vcl_test_server_main_t * vsm)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400329{
Florin Coras1502fc32018-10-05 00:50:30 -0700330 struct sockaddr_storage *servaddr = &vsm->servaddr;
Florin Coras293aa052018-08-30 18:49:13 -0700331 memset (servaddr, 0, sizeof (*servaddr));
Dave Wallacee4d5a652018-06-24 21:21:21 -0400332
Florin Coras1502fc32018-10-05 00:50:30 -0700333 if (vsm->cfg.address_ip6)
Florin Coras293aa052018-08-30 18:49:13 -0700334 {
335 struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) servaddr;
336 server_addr->sin6_family = AF_INET6;
337 server_addr->sin6_addr = in6addr_any;
Florin Coras1502fc32018-10-05 00:50:30 -0700338 server_addr->sin6_port = htons (vsm->cfg.port);
Florin Coras293aa052018-08-30 18:49:13 -0700339 }
340 else
341 {
342 struct sockaddr_in *server_addr = (struct sockaddr_in *) servaddr;
343 server_addr->sin_family = AF_INET;
344 server_addr->sin_addr.s_addr = htonl (INADDR_ANY);
Florin Coras1502fc32018-10-05 00:50:30 -0700345 server_addr->sin_port = htons (vsm->cfg.port);
Florin Coras293aa052018-08-30 18:49:13 -0700346 }
347
Florin Coras1502fc32018-10-05 00:50:30 -0700348 if (vsm->cfg.address_ip6)
Florin Coras293aa052018-08-30 18:49:13 -0700349 {
350 struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) servaddr;
Florin Coras1502fc32018-10-05 00:50:30 -0700351 vsm->cfg.endpt.is_ip4 = 0;
352 vsm->cfg.endpt.ip = (uint8_t *) & server_addr->sin6_addr;
353 vsm->cfg.endpt.port = (uint16_t) server_addr->sin6_port;
Florin Coras293aa052018-08-30 18:49:13 -0700354 }
355 else
356 {
357 struct sockaddr_in *server_addr = (struct sockaddr_in *) servaddr;
Florin Coras1502fc32018-10-05 00:50:30 -0700358 vsm->cfg.endpt.is_ip4 = 1;
359 vsm->cfg.endpt.ip = (uint8_t *) & server_addr->sin_addr;
360 vsm->cfg.endpt.port = (uint16_t) server_addr->sin_port;
Florin Coras293aa052018-08-30 18:49:13 -0700361 }
362}
363
Florin Coras6d4bb422018-09-04 22:07:27 -0700364static void
Florin Coras1502fc32018-10-05 00:50:30 -0700365vcl_test_server_process_opts (vcl_test_server_main_t * vsm, int argc,
Florin Coras293aa052018-08-30 18:49:13 -0700366 char **argv)
367{
368 int v, c;
369
Florin Coras1502fc32018-10-05 00:50:30 -0700370 vsm->cfg.proto = VPPCOM_PROTO_TCP;
Dave Barach6a5adc32018-07-04 10:56:23 -0400371
Dave Wallacee4d5a652018-06-24 21:21:21 -0400372 opterr = 0;
Florin Coras2cba8532018-09-11 16:33:36 -0700373 while ((c = getopt (argc, argv, "6Dsw:")) != -1)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400374 switch (c)
375 {
376 case '6':
Florin Coras1502fc32018-10-05 00:50:30 -0700377 vsm->cfg.address_ip6 = 1;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400378 break;
379
380 case 'D':
Florin Coras1502fc32018-10-05 00:50:30 -0700381 vsm->cfg.proto = VPPCOM_PROTO_UDP;
Florin Coras293aa052018-08-30 18:49:13 -0700382 break;
383
384 case 'w':
385 v = atoi (optarg);
386 if (v > 1)
Florin Coras1502fc32018-10-05 00:50:30 -0700387 vsm->cfg.workers = v;
Florin Coras293aa052018-08-30 18:49:13 -0700388 else
389 vtwrn ("Invalid number of workers %d", v);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400390 break;
Florin Coras2cba8532018-09-11 16:33:36 -0700391 case 's':
Florin Coras1502fc32018-10-05 00:50:30 -0700392 vsm->use_ds = 1;
Florin Coras2cba8532018-09-11 16:33:36 -0700393 break;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400394 case '?':
395 switch (optopt)
396 {
397 default:
398 if (isprint (optopt))
Florin Coras6d4bb422018-09-04 22:07:27 -0700399 vtwrn ("Unknown option `-%c'.", optopt);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400400 else
Florin Coras6d4bb422018-09-04 22:07:27 -0700401 vtwrn ("Unknown option character `\\x%x'.", optopt);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400402 }
403 /* fall thru */
404 case 'h':
405 default:
406 print_usage_and_exit ();
407 }
408
409 if (argc < (optind + 1))
410 {
411 fprintf (stderr, "SERVER: ERROR: Insufficient number of arguments!\n");
412 print_usage_and_exit ();
413 }
414
415 if (sscanf (argv[optind], "%d", &v) == 1)
Florin Coras1502fc32018-10-05 00:50:30 -0700416 vsm->cfg.port = (uint16_t) v;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400417 else
418 {
419 fprintf (stderr, "SERVER: ERROR: Invalid port (%s)!\n", argv[optind]);
420 print_usage_and_exit ();
421 }
422
Florin Coras1502fc32018-10-05 00:50:30 -0700423 vcl_test_init_endpoint_addr (vsm);
Florin Coras293aa052018-08-30 18:49:13 -0700424}
Dave Wallacee4d5a652018-06-24 21:21:21 -0400425
Florin Coras293aa052018-08-30 18:49:13 -0700426int
Florin Coras1502fc32018-10-05 00:50:30 -0700427vts_handle_cfg (vcl_test_server_worker_t * wrk, vcl_test_cfg_t * rx_cfg,
Florin Coras6d4bb422018-09-04 22:07:27 -0700428 vcl_test_server_conn_t * conn, int rx_bytes)
Florin Coras293aa052018-08-30 18:49:13 -0700429{
430 if (rx_cfg->verbose)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400431 {
Florin Coras293aa052018-08-30 18:49:13 -0700432 vtinf ("(fd %d): Received a cfg msg!", conn->fd);
Florin Coras1502fc32018-10-05 00:50:30 -0700433 vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
Dave Wallacee4d5a652018-06-24 21:21:21 -0400434 }
435
Florin Coras293aa052018-08-30 18:49:13 -0700436 if (rx_bytes != sizeof (*rx_cfg))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400437 {
Florin Coras293aa052018-08-30 18:49:13 -0700438 vtinf ("(fd %d): Invalid cfg msg size %d expected %lu!", conn->fd,
439 rx_bytes, sizeof (*rx_cfg));
440 conn->cfg.rxbuf_size = 0;
441 conn->cfg.num_writes = 0;
442 if (conn->cfg.verbose)
Florin Coras460dce62018-07-27 05:45:06 -0700443 {
Florin Coras293aa052018-08-30 18:49:13 -0700444 vtinf ("(fd %d): Replying to cfg msg", conn->fd);
Florin Coras1502fc32018-10-05 00:50:30 -0700445 vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
Florin Coras460dce62018-07-27 05:45:06 -0700446 }
Florin Coras293aa052018-08-30 18:49:13 -0700447 vcl_test_write (conn->fd, (uint8_t *) & conn->cfg,
448 sizeof (conn->cfg), NULL, conn->cfg.verbose);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400449 return -1;
450 }
451
Florin Coras293aa052018-08-30 18:49:13 -0700452 switch (rx_cfg->test)
453 {
Florin Coras1502fc32018-10-05 00:50:30 -0700454 case VCL_TEST_TYPE_NONE:
455 case VCL_TEST_TYPE_ECHO:
Florin Coras293aa052018-08-30 18:49:13 -0700456 sync_config_and_reply (conn, rx_cfg);
457 break;
458
Florin Coras1502fc32018-10-05 00:50:30 -0700459 case VCL_TEST_TYPE_BI:
460 case VCL_TEST_TYPE_UNI:
Florin Coras6d4bb422018-09-04 22:07:27 -0700461 vts_server_start_stop (wrk, conn, rx_cfg);
Florin Coras293aa052018-08-30 18:49:13 -0700462 break;
463
Florin Coras1502fc32018-10-05 00:50:30 -0700464 case VCL_TEST_TYPE_EXIT:
465 vtinf ("Session fd %d closing!", conn->fd);
466 clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
Florin Coras293aa052018-08-30 18:49:13 -0700467 vppcom_session_close (conn->fd);
468 conn_pool_free (conn);
Florin Coras293aa052018-08-30 18:49:13 -0700469 wrk->nfds--;
470 break;
471
472 default:
473 vtwrn ("Unknown test type %d", rx_cfg->test);
Florin Coras1502fc32018-10-05 00:50:30 -0700474 vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
Florin Coras293aa052018-08-30 18:49:13 -0700475 break;
476 }
477
478 return 0;
479}
480
481static void
Florin Coras6d4bb422018-09-04 22:07:27 -0700482vts_worker_init (vcl_test_server_worker_t * wrk)
Florin Coras293aa052018-08-30 18:49:13 -0700483{
Florin Coras1502fc32018-10-05 00:50:30 -0700484 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras293aa052018-08-30 18:49:13 -0700485 struct epoll_event listen_ev;
486 int rv;
487
488 __wrk_index = wrk->wrk_index;
489
490 vtinf ("Initializing worker ...");
491
Florin Coras1502fc32018-10-05 00:50:30 -0700492 conn_pool_expand (wrk, VCL_TEST_CFG_MAX_TEST_SESS + 1);
Florin Coras293aa052018-08-30 18:49:13 -0700493 if (wrk->wrk_index)
Florin Corasde9f08b2018-09-07 14:32:58 -0700494 if (vppcom_worker_register ())
495 vtfail ("vppcom_worker_register()", 1);
Florin Coras293aa052018-08-30 18:49:13 -0700496
Florin Coras1502fc32018-10-05 00:50:30 -0700497 wrk->listen_fd = vppcom_session_create (vsm->cfg.proto,
Florin Coras293aa052018-08-30 18:49:13 -0700498 0 /* is_nonblocking */ );
499 if (wrk->listen_fd < 0)
500 vtfail ("vppcom_session_create()", wrk->listen_fd);
501
Florin Coras1502fc32018-10-05 00:50:30 -0700502 rv = vppcom_session_bind (wrk->listen_fd, &vsm->cfg.endpt);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400503 if (rv < 0)
Florin Coras293aa052018-08-30 18:49:13 -0700504 vtfail ("vppcom_session_bind()", rv);
505
Florin Coras1502fc32018-10-05 00:50:30 -0700506 if (!(vsm->cfg.proto == VPPCOM_PROTO_UDP))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400507 {
Florin Coras293aa052018-08-30 18:49:13 -0700508 rv = vppcom_session_listen (wrk->listen_fd, 10);
509 if (rv < 0)
510 vtfail ("vppcom_session_listen()", rv);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400511 }
Florin Coras293aa052018-08-30 18:49:13 -0700512
513 wrk->epfd = vppcom_epoll_create ();
514 if (wrk->epfd < 0)
515 vtfail ("vppcom_epoll_create()", wrk->epfd);
516
517 listen_ev.events = EPOLLIN;
518 listen_ev.data.u32 = ~0;
519 rv = vppcom_epoll_ctl (wrk->epfd, EPOLL_CTL_ADD, wrk->listen_fd,
520 &listen_ev);
521 if (rv < 0)
522 vtfail ("vppcom_epoll_ctl", rv);
523
Florin Coras1502fc32018-10-05 00:50:30 -0700524 vsm->active_workers += 1;
525 vtinf ("Waiting for a client to connect on port %d ...", vsm->cfg.port);
Florin Coras293aa052018-08-30 18:49:13 -0700526}
527
Florin Coras2cba8532018-09-11 16:33:36 -0700528static int
529vts_conn_expect_config (vcl_test_server_conn_t * conn)
530{
Florin Coras1502fc32018-10-05 00:50:30 -0700531 if (conn->cfg.test == VCL_TEST_TYPE_ECHO)
Florin Coras2cba8532018-09-11 16:33:36 -0700532 return 1;
533
534 return (conn->stats.rx_bytes < 128
Florin Coras1502fc32018-10-05 00:50:30 -0700535 || conn->stats.rx_bytes > conn->cfg.total_bytes);
Florin Coras2cba8532018-09-11 16:33:36 -0700536}
537
Florin Coras1502fc32018-10-05 00:50:30 -0700538static vcl_test_cfg_t *
Florin Coras2cba8532018-09-11 16:33:36 -0700539vts_conn_read_config (vcl_test_server_conn_t * conn)
540{
Florin Coras1502fc32018-10-05 00:50:30 -0700541 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras2cba8532018-09-11 16:33:36 -0700542
Florin Coras1502fc32018-10-05 00:50:30 -0700543 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700544 {
545 /* We could avoid the copy if the first segment is big enough but this
546 * just simplifies things */
Florin Coras1502fc32018-10-05 00:50:30 -0700547 vppcom_data_segment_copy (conn->buf, conn->ds, sizeof (vcl_test_cfg_t));
Florin Coras2cba8532018-09-11 16:33:36 -0700548 }
Florin Coras1502fc32018-10-05 00:50:30 -0700549 return (vcl_test_cfg_t *) conn->buf;
Florin Coras2cba8532018-09-11 16:33:36 -0700550}
551
552static inline int
553vts_conn_read (vcl_test_server_conn_t * conn)
554{
Florin Coras1502fc32018-10-05 00:50:30 -0700555 vcl_test_server_main_t *vsm = &vcl_server_main;
556 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700557 return vcl_test_read_ds (conn->fd, conn->ds, &conn->stats);
558 else
559 return vcl_test_read (conn->fd, conn->buf, conn->buf_size, &conn->stats);
560}
561
562static inline int
563vts_conn_has_ascii (vcl_test_server_conn_t * conn)
564{
Florin Coras1502fc32018-10-05 00:50:30 -0700565 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras2cba8532018-09-11 16:33:36 -0700566
Florin Coras1502fc32018-10-05 00:50:30 -0700567 if (vsm->use_ds)
Florin Coras2cba8532018-09-11 16:33:36 -0700568 return isascii (conn->ds[0].data[0]);
569 else
570 return isascii (conn->buf[0]);
571}
572
Florin Coras293aa052018-08-30 18:49:13 -0700573static void *
Florin Coras6d4bb422018-09-04 22:07:27 -0700574vts_worker_loop (void *arg)
Florin Coras293aa052018-08-30 18:49:13 -0700575{
Florin Coras1502fc32018-10-05 00:50:30 -0700576 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras293aa052018-08-30 18:49:13 -0700577 vcl_test_server_worker_t *wrk = arg;
578 vcl_test_server_conn_t *conn;
579 int i, rx_bytes, num_ev;
Florin Coras1502fc32018-10-05 00:50:30 -0700580 vcl_test_cfg_t *rx_cfg;
Florin Coras293aa052018-08-30 18:49:13 -0700581
582 if (wrk->wrk_index)
Florin Coras6d4bb422018-09-04 22:07:27 -0700583 vts_worker_init (wrk);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400584
585 while (1)
586 {
Florin Coras293aa052018-08-30 18:49:13 -0700587 num_ev = vppcom_epoll_wait (wrk->epfd, wrk->wait_events,
Florin Coras1502fc32018-10-05 00:50:30 -0700588 VCL_TEST_CFG_MAX_EPOLL_EVENTS, 60000.0);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400589 if (num_ev < 0)
590 {
Florin Coras293aa052018-08-30 18:49:13 -0700591 vterr ("vppcom_epoll_wait()", num_ev);
592 goto fail;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400593 }
594 else if (num_ev == 0)
595 {
Florin Coras293aa052018-08-30 18:49:13 -0700596 vtinf ("vppcom_epoll_wait() timeout!");
Dave Wallacee4d5a652018-06-24 21:21:21 -0400597 continue;
598 }
599 for (i = 0; i < num_ev; i++)
600 {
Florin Coras293aa052018-08-30 18:49:13 -0700601 conn = &wrk->conn_pool[wrk->wait_events[i].data.u32];
602 if (wrk->wait_events[i].events & (EPOLLHUP | EPOLLRDHUP))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400603 {
604 vppcom_session_close (conn->fd);
Florin Coras21795132018-09-09 09:40:51 -0700605 wrk->nfds -= 1;
606 if (!wrk->nfds)
607 {
608 vtinf ("All client connections closed\n");
609 goto done;
610 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400611 continue;
612 }
Florin Coras293aa052018-08-30 18:49:13 -0700613 if (wrk->wait_events[i].data.u32 == ~0)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400614 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700615 vts_new_client (wrk);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400616 continue;
617 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400618
Florin Coras293aa052018-08-30 18:49:13 -0700619 if (EPOLLIN & wrk->wait_events[i].events)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400620 {
Florin Coras21795132018-09-09 09:40:51 -0700621 read_again:
Florin Coras2cba8532018-09-11 16:33:36 -0700622 rx_bytes = vts_conn_read (conn);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400623
Florin Coras293aa052018-08-30 18:49:13 -0700624 if (rx_bytes <= 0)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400625 {
626 if (errno == ECONNRESET)
627 {
Florin Coras293aa052018-08-30 18:49:13 -0700628 vtinf ("Connection reset by remote peer.\n");
629 goto fail;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400630 }
631 else
632 continue;
633 }
634
Florin Coras2cba8532018-09-11 16:33:36 -0700635 if (vts_conn_expect_config (conn))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400636 {
Florin Coras2cba8532018-09-11 16:33:36 -0700637 rx_cfg = vts_conn_read_config (conn);
Florin Coras1502fc32018-10-05 00:50:30 -0700638 if (rx_cfg->magic == VCL_TEST_CFG_CTRL_MAGIC)
Florin Coras293aa052018-08-30 18:49:13 -0700639 {
Florin Coras1502fc32018-10-05 00:50:30 -0700640 if (vsm->use_ds)
641 vppcom_session_free_segments (conn->fd, conn->ds);
Florin Coras2cba8532018-09-11 16:33:36 -0700642 vts_handle_cfg (wrk, rx_cfg, conn, rx_bytes);
643 if (!wrk->nfds)
644 {
645 vtinf ("All client connections closed\n");
646 goto done;
647 }
648 continue;
Florin Coras293aa052018-08-30 18:49:13 -0700649 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400650 }
Florin Coras1502fc32018-10-05 00:50:30 -0700651 if ((conn->cfg.test == VCL_TEST_TYPE_UNI)
652 || (conn->cfg.test == VCL_TEST_TYPE_BI))
Dave Wallacee4d5a652018-06-24 21:21:21 -0400653 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700654 vts_server_rx (conn, rx_bytes);
Florin Coras21795132018-09-09 09:40:51 -0700655 if (vppcom_session_attr (conn->fd, VPPCOM_ATTR_GET_NREAD, 0,
656 0) > 0)
657 goto read_again;
Florin Coras293aa052018-08-30 18:49:13 -0700658 continue;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400659 }
Florin Coras2cba8532018-09-11 16:33:36 -0700660 if (vts_conn_has_ascii (conn))
Florin Coras293aa052018-08-30 18:49:13 -0700661 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700662 vts_server_echo (conn, rx_bytes);
Florin Coras293aa052018-08-30 18:49:13 -0700663 }
664 else
665 {
666 vtwrn ("FIFO not drained! extra bytes %d", rx_bytes);
667 }
668 }
669 else
670 {
671 vtwrn ("Unhandled event");
672 goto fail;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400673 }
674 }
675 }
676
Florin Coras293aa052018-08-30 18:49:13 -0700677fail:
Florin Coras1502fc32018-10-05 00:50:30 -0700678 vsm->worker_fails -= 1;
Florin Coras293aa052018-08-30 18:49:13 -0700679
Dave Wallacee4d5a652018-06-24 21:21:21 -0400680done:
Florin Coras293aa052018-08-30 18:49:13 -0700681 vppcom_session_close (wrk->listen_fd);
682 if (wrk->conn_pool)
683 free (wrk->conn_pool);
Florin Coras1502fc32018-10-05 00:50:30 -0700684 vsm->active_workers -= 1;
Florin Coras293aa052018-08-30 18:49:13 -0700685 return 0;
686}
687
688int
689main (int argc, char **argv)
690{
Florin Coras1502fc32018-10-05 00:50:30 -0700691 vcl_test_server_main_t *vsm = &vcl_server_main;
Florin Coras293aa052018-08-30 18:49:13 -0700692 int rv, i;
693
694 clib_mem_init_thread_safe (0, 64 << 20);
Florin Coras1502fc32018-10-05 00:50:30 -0700695 vsm->cfg.port = VCL_TEST_SERVER_PORT;
Florin Coras6d4bb422018-09-04 22:07:27 -0700696 vsm->cfg.workers = 1;
Florin Coras2cba8532018-09-11 16:33:36 -0700697 vsm->active_workers = 0;
Florin Coras6d4bb422018-09-04 22:07:27 -0700698 vcl_test_server_process_opts (vsm, argc, argv);
Florin Coras293aa052018-08-30 18:49:13 -0700699
700 rv = vppcom_app_create ("vcl_test_server");
701 if (rv)
702 vtfail ("vppcom_app_create()", rv);
703
Florin Coras6d4bb422018-09-04 22:07:27 -0700704 vsm->workers = calloc (vsm->cfg.workers, sizeof (*vsm->workers));
705 vts_worker_init (&vsm->workers[0]);
706 for (i = 1; i < vsm->cfg.workers; i++)
Florin Coras293aa052018-08-30 18:49:13 -0700707 {
Florin Coras6d4bb422018-09-04 22:07:27 -0700708 vsm->workers[i].wrk_index = i;
709 rv = pthread_create (&vsm->workers[i].thread_handle, NULL,
710 vts_worker_loop, (void *) &vsm->workers[i]);
Florin Coras293aa052018-08-30 18:49:13 -0700711 }
Florin Coras6d4bb422018-09-04 22:07:27 -0700712 vts_worker_loop (&vsm->workers[0]);
Florin Coras293aa052018-08-30 18:49:13 -0700713
Florin Coras6d4bb422018-09-04 22:07:27 -0700714 while (vsm->active_workers > 0)
Florin Coras293aa052018-08-30 18:49:13 -0700715 ;
716
Dave Wallacee4d5a652018-06-24 21:21:21 -0400717 vppcom_app_destroy ();
Florin Coras6d4bb422018-09-04 22:07:27 -0700718 free (vsm->workers);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400719
Florin Coras6d4bb422018-09-04 22:07:27 -0700720 return vsm->worker_fails;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400721}
Dave Wallace543852a2017-08-03 02:11:34 -0400722
723/*
724 * fd.io coding-style-patch-verification: ON
725 *
726 * Local Variables:
727 * eval: (c-set-style "gnu")
728 * End:
729 */