blob: 9d28b262e3abdc8be1692fca7f947edbb2642683 [file] [log] [blame]
Dave Wallacee4d5a652018-06-24 21:21:21 -04001/*
2 * Copyright (c) 2017 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#ifndef __vcl_test_h__
17#define __vcl_test_h__
18
19#include <netdb.h>
20#include <errno.h>
21#include <stdlib.h>
22#include <string.h>
23#include <vcl/vppcom.h>
Dave Wallacee4d5a652018-06-24 21:21:21 -040024
Florin Coras6d4bb422018-09-04 22:07:27 -070025#define vtfail(_fn, _rv) \
26{ \
27 errno = -_rv; \
28 perror ("ERROR when calling " _fn); \
29 fprintf (stderr, "\nERROR: " _fn " failed (errno = %d)!\n", -_rv); \
30 exit (1); \
31}
32
33#define vterr(_fn, _rv) \
34{ \
35 errno = -_rv; \
36 fprintf (stderr, "\nERROR: " _fn " failed (errno = %d)!\n", -_rv); \
37}
38
39#define vtwrn(_fmt, _args...) \
40 fprintf (stderr, "\nERROR: " _fmt "\n", ##_args) \
41
42#define vtinf(_fmt, _args...) \
43 fprintf (stdout, "vt<w%u>: " _fmt "\n", __wrk_index, ##_args)
44
45#define vt_atomic_add(_ptr, _val) \
46 __atomic_fetch_add (_ptr, _val, __ATOMIC_RELEASE)
47
Florin Coras1502fc32018-10-05 00:50:30 -070048#define VCL_TEST_TOKEN_HELP "#H"
49#define VCL_TEST_TOKEN_EXIT "#X"
50#define VCL_TEST_TOKEN_VERBOSE "#V"
51#define VCL_TEST_TOKEN_TXBUF_SIZE "#T:"
52#define VCL_TEST_TOKEN_NUM_TEST_SESS "#I:"
53#define VCL_TEST_TOKEN_NUM_WRITES "#N:"
54#define VCL_TEST_TOKEN_RXBUF_SIZE "#R:"
55#define VCL_TEST_TOKEN_SHOW_CFG "#C"
56#define VCL_TEST_TOKEN_RUN_UNI "#U"
57#define VCL_TEST_TOKEN_RUN_BI "#B"
58
59#define VCL_TEST_SERVER_PORT 22000
60#define VCL_TEST_LOCALHOST_IPADDR "127.0.0.1"
61
62#define VCL_TEST_CFG_CTRL_MAGIC 0xfeedface
63#define VCL_TEST_CFG_NUM_WRITES_DEF 1000000
64#define VCL_TEST_CFG_TXBUF_SIZE_DEF 8192
65#define VCL_TEST_CFG_RXBUF_SIZE_DEF (64*VCL_TEST_CFG_TXBUF_SIZE_DEF)
66#define VCL_TEST_CFG_BUF_SIZE_MIN 128
67#define VCL_TEST_CFG_MAX_TEST_SESS 32
68#define VCL_TEST_CFG_MAX_EPOLL_EVENTS 16
69
70#define VCL_TEST_DELAY_DISCONNECT 1
71#define VCL_TEST_SEPARATOR_STRING \
72 " -----------------------------\n"
73typedef enum
74{
75 VCL_TEST_TYPE_NONE,
76 VCL_TEST_TYPE_ECHO,
77 VCL_TEST_TYPE_UNI,
78 VCL_TEST_TYPE_BI,
79 VCL_TEST_TYPE_EXIT,
80} vcl_test_t;
81
82typedef struct __attribute__ ((packed))
83{
84 uint32_t magic;
85 uint32_t seq_num;
86 uint32_t test;
87 uint32_t ctrl_handle;
88 uint32_t num_test_sessions;
89 uint32_t verbose;
90 uint32_t address_ip6;
91 uint32_t transport_udp;
92 uint64_t rxbuf_size;
93 uint64_t txbuf_size;
94 uint64_t num_writes;
95 uint64_t total_bytes;
96} vcl_test_cfg_t;
97
98typedef struct
99{
100 uint64_t rx_xacts;
101 uint64_t rx_bytes;
102 uint32_t rx_eagain;
103 uint32_t rx_incomp;
104 uint64_t tx_xacts;
105 uint64_t tx_bytes;
106 uint32_t tx_eagain;
107 uint32_t tx_incomp;
108 struct timespec start;
109 struct timespec stop;
110} vcl_test_stats_t;
111
112typedef struct
113{
114 int fd;
115 uint32_t txbuf_size;
116 char *txbuf;
117 uint32_t rxbuf_size;
118 char *rxbuf;
119 vcl_test_cfg_t cfg;
120 vcl_test_stats_t stats;
121} vcl_test_session_t;
122
123static inline void
124vcl_test_stats_accumulate (vcl_test_stats_t * accum, vcl_test_stats_t * incr)
125{
126 accum->rx_xacts += incr->rx_xacts;
127 accum->rx_bytes += incr->rx_bytes;
128 accum->rx_eagain += incr->rx_eagain;
129 accum->rx_incomp += incr->rx_incomp;
130 accum->tx_xacts += incr->tx_xacts;
131 accum->tx_bytes += incr->tx_bytes;
132 accum->tx_eagain += incr->tx_eagain;
133 accum->tx_incomp += incr->tx_incomp;
134}
135
136static inline void
137vcl_test_cfg_init (vcl_test_cfg_t * cfg)
138{
139 cfg->magic = VCL_TEST_CFG_CTRL_MAGIC;
140 cfg->test = VCL_TEST_TYPE_NONE;
141 cfg->ctrl_handle = ~0;
142 cfg->num_test_sessions = 1;
143 cfg->verbose = 0;
144 cfg->rxbuf_size = VCL_TEST_CFG_RXBUF_SIZE_DEF;
145 cfg->num_writes = VCL_TEST_CFG_NUM_WRITES_DEF;
146 cfg->txbuf_size = VCL_TEST_CFG_TXBUF_SIZE_DEF;
147 cfg->total_bytes = cfg->num_writes * cfg->txbuf_size;
148}
149
Dave Wallacee4d5a652018-06-24 21:21:21 -0400150static inline int
Florin Coras1502fc32018-10-05 00:50:30 -0700151vcl_test_cfg_verify (vcl_test_cfg_t * cfg, vcl_test_cfg_t * valid_cfg)
152{
153 /* Note: txbuf & rxbuf on server are the same buffer,
154 * so txbuf_size is not included in this check.
155 */
156 return ((cfg->magic == valid_cfg->magic)
157 && (cfg->test == valid_cfg->test)
158 && (cfg->verbose == valid_cfg->verbose)
159 && (cfg->rxbuf_size == valid_cfg->rxbuf_size)
160 && (cfg->num_writes == valid_cfg->num_writes)
161 && (cfg->total_bytes == valid_cfg->total_bytes));
162}
163
164static inline void
165vcl_test_buf_alloc (vcl_test_cfg_t * cfg, uint8_t is_rxbuf, uint8_t ** buf,
166 uint32_t * bufsize)
167{
168 uint32_t alloc_size = is_rxbuf ? cfg->rxbuf_size : cfg->txbuf_size;
169 uint8_t *lb = realloc (*buf, (size_t) alloc_size);
170
171 if (lb)
172 {
173 if (is_rxbuf)
174 cfg->rxbuf_size = *bufsize = alloc_size;
175 else
176 cfg->txbuf_size = *bufsize = alloc_size;
177
178 *buf = lb;
179 }
180 else
181 {
182 vtwrn ("realloc failed. using buffer size %d instead of %u",
183 *bufsize, alloc_size);
184 }
185}
186
187static inline void
188vcl_test_session_buf_alloc (vcl_test_session_t * socket)
189{
190 socket->rxbuf_size = socket->cfg.rxbuf_size;
191 socket->txbuf_size = socket->cfg.txbuf_size;
192 vcl_test_buf_alloc (&socket->cfg, 0 /* is_rxbuf */ ,
193 (uint8_t **) & socket->txbuf, &socket->txbuf_size);
194 vcl_test_buf_alloc (&socket->cfg, 1 /* is_rxbuf */ ,
195 (uint8_t **) & socket->rxbuf, &socket->rxbuf_size);
196}
197
198static inline char *
199vcl_test_type_str (vcl_test_t t)
200{
201 switch (t)
202 {
203 case VCL_TEST_TYPE_NONE:
204 return "NONE";
205
206 case VCL_TEST_TYPE_ECHO:
207 return "ECHO";
208
209 case VCL_TEST_TYPE_UNI:
210 return "UNI";
211
212 case VCL_TEST_TYPE_BI:
213 return "BI";
214
215 case VCL_TEST_TYPE_EXIT:
216 return "EXIT";
217
218 default:
219 return "Unknown";
220 }
221}
222
223static inline void
224vcl_test_cfg_dump (vcl_test_cfg_t * cfg, uint8_t is_client)
225{
226 char *spc = " ";
227
228 printf (" test config (%p):\n"
229 VCL_TEST_SEPARATOR_STRING
230 " magic: 0x%08x\n"
231 " seq_num: 0x%08x\n"
232 "%-5s test: %s (%d)\n"
233 " ctrl handle: %d (0x%x)\n"
234 "%-5s num test sockets: %u (0x%08x)\n"
235 "%-5s verbose: %s (%d)\n"
236 "%-5s rxbuf size: %lu (0x%08lx)\n"
237 "%-5s txbuf size: %lu (0x%08lx)\n"
238 "%-5s num writes: %lu (0x%08lx)\n"
239 " client tx bytes: %lu (0x%08lx)\n"
240 VCL_TEST_SEPARATOR_STRING,
241 (void *) cfg, cfg->magic, cfg->seq_num,
242 is_client && (cfg->test == VCL_TEST_TYPE_UNI) ?
243 "'" VCL_TEST_TOKEN_RUN_UNI "'" :
244 is_client && (cfg->test == VCL_TEST_TYPE_BI) ?
245 "'" VCL_TEST_TOKEN_RUN_BI "'" : spc,
246 vcl_test_type_str (cfg->test), cfg->test,
247 cfg->ctrl_handle, cfg->ctrl_handle,
248 is_client ? "'" VCL_TEST_TOKEN_NUM_TEST_SESS "'" : spc,
249 cfg->num_test_sessions, cfg->num_test_sessions,
250 is_client ? "'" VCL_TEST_TOKEN_VERBOSE "'" : spc,
251 cfg->verbose ? "on" : "off", cfg->verbose,
252 is_client ? "'" VCL_TEST_TOKEN_RXBUF_SIZE "'" : spc,
253 cfg->rxbuf_size, cfg->rxbuf_size,
254 is_client ? "'" VCL_TEST_TOKEN_TXBUF_SIZE "'" : spc,
255 cfg->txbuf_size, cfg->txbuf_size,
256 is_client ? "'" VCL_TEST_TOKEN_NUM_WRITES "'" : spc,
257 cfg->num_writes, cfg->num_writes,
258 cfg->total_bytes, cfg->total_bytes);
259}
260
261static inline void
262vcl_test_stats_dump (char *header, vcl_test_stats_t * stats,
263 uint8_t show_rx, uint8_t show_tx, uint8_t verbose)
264{
265 struct timespec diff;
266 double duration, rate;
267 uint64_t total_bytes;
268
269 if ((stats->stop.tv_nsec - stats->start.tv_nsec) < 0)
270 {
271 diff.tv_sec = stats->stop.tv_sec - stats->start.tv_sec - 1;
272 diff.tv_nsec = stats->stop.tv_nsec - stats->start.tv_nsec + 1e9;
273 }
274 else
275 {
276 diff.tv_sec = stats->stop.tv_sec - stats->start.tv_sec;
277 diff.tv_nsec = stats->stop.tv_nsec - stats->start.tv_nsec;
278 }
279 duration = (double) diff.tv_sec + (1e-9 * diff.tv_nsec);
280
281 total_bytes = stats->tx_bytes + stats->rx_bytes;
282 rate = (double) total_bytes *8 / duration / 1e9;
283 printf ("\n%s: Streamed %lu bytes\n"
284 " in %lf seconds (%lf Gbps %s-duplex)!\n",
285 header, total_bytes, duration, rate,
286 (show_rx && show_tx) ? "full" : "half");
287
288 if (show_tx)
289 {
290 printf (VCL_TEST_SEPARATOR_STRING
291 " tx stats (0x%p):\n"
292 VCL_TEST_SEPARATOR_STRING
293 " writes: %lu (0x%08lx)\n"
294 " tx bytes: %lu (0x%08lx)\n"
295 " tx eagain: %u (0x%08x)\n"
296 " tx incomplete: %u (0x%08x)\n",
297 (void *) stats, stats->tx_xacts, stats->tx_xacts,
298 stats->tx_bytes, stats->tx_bytes,
299 stats->tx_eagain, stats->tx_eagain,
300 stats->tx_incomp, stats->tx_incomp);
301 }
302 if (show_rx)
303 {
304 printf (VCL_TEST_SEPARATOR_STRING
305 " rx stats (0x%p):\n"
306 VCL_TEST_SEPARATOR_STRING
307 " reads: %lu (0x%08lx)\n"
308 " rx bytes: %lu (0x%08lx)\n"
309 " rx eagain: %u (0x%08x)\n"
310 " rx incomplete: %u (0x%08x)\n",
311 (void *) stats, stats->rx_xacts, stats->rx_xacts,
312 stats->rx_bytes, stats->rx_bytes,
313 stats->rx_eagain, stats->rx_eagain,
314 stats->rx_incomp, stats->rx_incomp);
315 }
316 if (verbose)
317 printf (" start.tv_sec: %ld\n"
318 " start.tv_nsec: %ld\n"
319 " stop.tv_sec: %ld\n"
320 " stop.tv_nsec: %ld\n",
321 stats->start.tv_sec, stats->start.tv_nsec,
322 stats->stop.tv_sec, stats->stop.tv_nsec);
323
324 printf (VCL_TEST_SEPARATOR_STRING);
325}
326
327static inline int
328vcl_comp_tspec (struct timespec *a, struct timespec *b)
329{
330 if (a->tv_sec < b->tv_sec)
331 return -1;
332 else if (a->tv_sec > b->tv_sec)
333 return 1;
334 else if (a->tv_nsec < b->tv_nsec)
335 return -1;
336 else if (a->tv_nsec > b->tv_nsec)
337 return 1;
338 else
339 return 0;
340}
341
342static inline int
343vcl_test_read (int fd, uint8_t * buf, uint32_t nbytes,
344 vcl_test_stats_t * stats)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400345{
346 int rx_bytes, errno_val;
Florin Coras1502fc32018-10-05 00:50:30 -0700347
Dave Wallacee4d5a652018-06-24 21:21:21 -0400348 do
349 {
350 if (stats)
Florin Coras1502fc32018-10-05 00:50:30 -0700351 stats->rx_xacts++;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400352 rx_bytes = vppcom_session_read (fd, buf, nbytes);
353
354 if (rx_bytes < 0)
Florin Coras1502fc32018-10-05 00:50:30 -0700355 {
356 errno = -rx_bytes;
357 rx_bytes = -1;
358 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400359 if (stats)
Florin Coras1502fc32018-10-05 00:50:30 -0700360 {
361 if ((rx_bytes == 0) ||
362 ((rx_bytes < 0)
363 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))))
364 stats->rx_eagain++;
365 else if (rx_bytes < nbytes)
366 stats->rx_incomp++;
367 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400368 }
369 while ((rx_bytes == 0) ||
Florin Coras1502fc32018-10-05 00:50:30 -0700370 ((rx_bytes < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))));
371
Dave Wallacee4d5a652018-06-24 21:21:21 -0400372 if (rx_bytes < 0)
373 {
Florin Coras2cba8532018-09-11 16:33:36 -0700374 vterr ("vppcom_session_read()", -errno);
375 }
376 else if (stats)
377 stats->rx_bytes += rx_bytes;
378
379 return (rx_bytes);
380}
381
382static inline int
Florin Coras1502fc32018-10-05 00:50:30 -0700383vcl_test_read_ds (int fd, vppcom_data_segments_t ds, vcl_test_stats_t * stats)
Florin Coras2cba8532018-09-11 16:33:36 -0700384{
385 int rx_bytes, errno_val;
386
387 do
388 {
389 if (stats)
Florin Coras1502fc32018-10-05 00:50:30 -0700390 stats->rx_xacts++;
Florin Coras2cba8532018-09-11 16:33:36 -0700391 rx_bytes = vppcom_session_read_segments (fd, ds);
392
393 if (rx_bytes < 0)
Florin Coras1502fc32018-10-05 00:50:30 -0700394 {
395 errno = -rx_bytes;
396 rx_bytes = -1;
397 }
Florin Coras2cba8532018-09-11 16:33:36 -0700398 if (stats)
Florin Coras1502fc32018-10-05 00:50:30 -0700399 {
400 if ((rx_bytes == 0) ||
401 ((rx_bytes < 0)
402 && ((errno == EAGAIN) || (errno == EWOULDBLOCK))))
403 stats->rx_eagain++;
404 }
Florin Coras2cba8532018-09-11 16:33:36 -0700405 }
406 while ((rx_bytes == 0) ||
Florin Coras1502fc32018-10-05 00:50:30 -0700407 ((rx_bytes < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))));
Florin Coras2cba8532018-09-11 16:33:36 -0700408
409 if (rx_bytes < 0)
410 {
411 vterr ("vppcom_session_read()", -errno);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400412 }
413 else if (stats)
414 stats->rx_bytes += rx_bytes;
415
416 return (rx_bytes);
417}
418
419static inline int
Florin Coras1502fc32018-10-05 00:50:30 -0700420vcl_test_write (int fd, uint8_t * buf, uint32_t nbytes,
421 vcl_test_stats_t * stats, uint32_t verbose)
Dave Wallacee4d5a652018-06-24 21:21:21 -0400422{
Florin Coras0e88e852018-09-17 22:09:02 -0700423 int tx_bytes = 0, nbytes_left = nbytes, rv;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400424
425 do
426 {
427 if (stats)
Florin Coras1502fc32018-10-05 00:50:30 -0700428 stats->tx_xacts++;
Dave Wallacee4d5a652018-06-24 21:21:21 -0400429 rv = vppcom_session_write (fd, buf, nbytes_left);
430 if (rv < 0)
Florin Coras1502fc32018-10-05 00:50:30 -0700431 {
432 errno = -rv;
433 rv = -1;
434 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400435 if (rv < 0)
Florin Coras1502fc32018-10-05 00:50:30 -0700436 {
437 if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
438 {
439 if (stats)
440 stats->tx_eagain++;
Florin Corasaa27eb92018-10-13 12:20:01 -0700441 break;
Florin Coras1502fc32018-10-05 00:50:30 -0700442 }
443 else
444 break;
445 }
Dave Wallacee4d5a652018-06-24 21:21:21 -0400446 tx_bytes += rv;
Florin Coras1502fc32018-10-05 00:50:30 -0700447
Dave Wallacee4d5a652018-06-24 21:21:21 -0400448 if (tx_bytes != nbytes)
Florin Coras1502fc32018-10-05 00:50:30 -0700449 {
450 nbytes_left = nbytes_left - rv;
451 if (stats)
452 stats->tx_incomp++;
453 }
454
455 }
456 while (tx_bytes != nbytes);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400457
458 if (tx_bytes < 0)
459 {
Florin Coras0e88e852018-09-17 22:09:02 -0700460 vterr ("vpcom_session_write", -errno);
Dave Wallacee4d5a652018-06-24 21:21:21 -0400461 }
462 else if (stats)
463 stats->tx_bytes += tx_bytes;
Florin Coras1502fc32018-10-05 00:50:30 -0700464
Dave Wallacee4d5a652018-06-24 21:21:21 -0400465 return (tx_bytes);
466}
467
468#endif /* __vcl_test_h__ */
Florin Coras1502fc32018-10-05 00:50:30 -0700469
470/*
471 * fd.io coding-style-patch-verification: ON
472 *
473 * Local Variables:
474 * eval: (c-set-style "gnu")
475 * End:
476 */