1*8abbffd2SArseniy Krasnov // SPDX-License-Identifier: GPL-2.0-only
2*8abbffd2SArseniy Krasnov /*
3*8abbffd2SArseniy Krasnov * vsock_perf - benchmark utility for vsock.
4*8abbffd2SArseniy Krasnov *
5*8abbffd2SArseniy Krasnov * Copyright (C) 2022 SberDevices.
6*8abbffd2SArseniy Krasnov *
7*8abbffd2SArseniy Krasnov * Author: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
8*8abbffd2SArseniy Krasnov */
9*8abbffd2SArseniy Krasnov #include <getopt.h>
10*8abbffd2SArseniy Krasnov #include <stdio.h>
11*8abbffd2SArseniy Krasnov #include <stdlib.h>
12*8abbffd2SArseniy Krasnov #include <stdbool.h>
13*8abbffd2SArseniy Krasnov #include <string.h>
14*8abbffd2SArseniy Krasnov #include <errno.h>
15*8abbffd2SArseniy Krasnov #include <unistd.h>
16*8abbffd2SArseniy Krasnov #include <time.h>
17*8abbffd2SArseniy Krasnov #include <stdint.h>
18*8abbffd2SArseniy Krasnov #include <poll.h>
19*8abbffd2SArseniy Krasnov #include <sys/socket.h>
20*8abbffd2SArseniy Krasnov #include <linux/vm_sockets.h>
21*8abbffd2SArseniy Krasnov
22*8abbffd2SArseniy Krasnov #define DEFAULT_BUF_SIZE_BYTES (128 * 1024)
23*8abbffd2SArseniy Krasnov #define DEFAULT_TO_SEND_BYTES (64 * 1024)
24*8abbffd2SArseniy Krasnov #define DEFAULT_VSOCK_BUF_BYTES (256 * 1024)
25*8abbffd2SArseniy Krasnov #define DEFAULT_RCVLOWAT_BYTES 1
26*8abbffd2SArseniy Krasnov #define DEFAULT_PORT 1234
27*8abbffd2SArseniy Krasnov
28*8abbffd2SArseniy Krasnov #define BYTES_PER_GB (1024 * 1024 * 1024ULL)
29*8abbffd2SArseniy Krasnov #define NSEC_PER_SEC (1000000000ULL)
30*8abbffd2SArseniy Krasnov
31*8abbffd2SArseniy Krasnov static unsigned int port = DEFAULT_PORT;
32*8abbffd2SArseniy Krasnov static unsigned long buf_size_bytes = DEFAULT_BUF_SIZE_BYTES;
33*8abbffd2SArseniy Krasnov static unsigned long vsock_buf_bytes = DEFAULT_VSOCK_BUF_BYTES;
34*8abbffd2SArseniy Krasnov
error(const char * s)35*8abbffd2SArseniy Krasnov static void error(const char *s)
36*8abbffd2SArseniy Krasnov {
37*8abbffd2SArseniy Krasnov perror(s);
38*8abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
39*8abbffd2SArseniy Krasnov }
40*8abbffd2SArseniy Krasnov
current_nsec(void)41*8abbffd2SArseniy Krasnov static time_t current_nsec(void)
42*8abbffd2SArseniy Krasnov {
43*8abbffd2SArseniy Krasnov struct timespec ts;
44*8abbffd2SArseniy Krasnov
45*8abbffd2SArseniy Krasnov if (clock_gettime(CLOCK_REALTIME, &ts))
46*8abbffd2SArseniy Krasnov error("clock_gettime");
47*8abbffd2SArseniy Krasnov
48*8abbffd2SArseniy Krasnov return (ts.tv_sec * NSEC_PER_SEC) + ts.tv_nsec;
49*8abbffd2SArseniy Krasnov }
50*8abbffd2SArseniy Krasnov
51*8abbffd2SArseniy Krasnov /* From lib/cmdline.c. */
memparse(const char * ptr)52*8abbffd2SArseniy Krasnov static unsigned long memparse(const char *ptr)
53*8abbffd2SArseniy Krasnov {
54*8abbffd2SArseniy Krasnov char *endptr;
55*8abbffd2SArseniy Krasnov
56*8abbffd2SArseniy Krasnov unsigned long long ret = strtoull(ptr, &endptr, 0);
57*8abbffd2SArseniy Krasnov
58*8abbffd2SArseniy Krasnov switch (*endptr) {
59*8abbffd2SArseniy Krasnov case 'E':
60*8abbffd2SArseniy Krasnov case 'e':
61*8abbffd2SArseniy Krasnov ret <<= 10;
62*8abbffd2SArseniy Krasnov case 'P':
63*8abbffd2SArseniy Krasnov case 'p':
64*8abbffd2SArseniy Krasnov ret <<= 10;
65*8abbffd2SArseniy Krasnov case 'T':
66*8abbffd2SArseniy Krasnov case 't':
67*8abbffd2SArseniy Krasnov ret <<= 10;
68*8abbffd2SArseniy Krasnov case 'G':
69*8abbffd2SArseniy Krasnov case 'g':
70*8abbffd2SArseniy Krasnov ret <<= 10;
71*8abbffd2SArseniy Krasnov case 'M':
72*8abbffd2SArseniy Krasnov case 'm':
73*8abbffd2SArseniy Krasnov ret <<= 10;
74*8abbffd2SArseniy Krasnov case 'K':
75*8abbffd2SArseniy Krasnov case 'k':
76*8abbffd2SArseniy Krasnov ret <<= 10;
77*8abbffd2SArseniy Krasnov endptr++;
78*8abbffd2SArseniy Krasnov default:
79*8abbffd2SArseniy Krasnov break;
80*8abbffd2SArseniy Krasnov }
81*8abbffd2SArseniy Krasnov
82*8abbffd2SArseniy Krasnov return ret;
83*8abbffd2SArseniy Krasnov }
84*8abbffd2SArseniy Krasnov
vsock_increase_buf_size(int fd)85*8abbffd2SArseniy Krasnov static void vsock_increase_buf_size(int fd)
86*8abbffd2SArseniy Krasnov {
87*8abbffd2SArseniy Krasnov if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
88*8abbffd2SArseniy Krasnov &vsock_buf_bytes, sizeof(vsock_buf_bytes)))
89*8abbffd2SArseniy Krasnov error("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
90*8abbffd2SArseniy Krasnov
91*8abbffd2SArseniy Krasnov if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
92*8abbffd2SArseniy Krasnov &vsock_buf_bytes, sizeof(vsock_buf_bytes)))
93*8abbffd2SArseniy Krasnov error("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
94*8abbffd2SArseniy Krasnov }
95*8abbffd2SArseniy Krasnov
vsock_connect(unsigned int cid,unsigned int port)96*8abbffd2SArseniy Krasnov static int vsock_connect(unsigned int cid, unsigned int port)
97*8abbffd2SArseniy Krasnov {
98*8abbffd2SArseniy Krasnov union {
99*8abbffd2SArseniy Krasnov struct sockaddr sa;
100*8abbffd2SArseniy Krasnov struct sockaddr_vm svm;
101*8abbffd2SArseniy Krasnov } addr = {
102*8abbffd2SArseniy Krasnov .svm = {
103*8abbffd2SArseniy Krasnov .svm_family = AF_VSOCK,
104*8abbffd2SArseniy Krasnov .svm_port = port,
105*8abbffd2SArseniy Krasnov .svm_cid = cid,
106*8abbffd2SArseniy Krasnov },
107*8abbffd2SArseniy Krasnov };
108*8abbffd2SArseniy Krasnov int fd;
109*8abbffd2SArseniy Krasnov
110*8abbffd2SArseniy Krasnov fd = socket(AF_VSOCK, SOCK_STREAM, 0);
111*8abbffd2SArseniy Krasnov
112*8abbffd2SArseniy Krasnov if (fd < 0) {
113*8abbffd2SArseniy Krasnov perror("socket");
114*8abbffd2SArseniy Krasnov return -1;
115*8abbffd2SArseniy Krasnov }
116*8abbffd2SArseniy Krasnov
117*8abbffd2SArseniy Krasnov if (connect(fd, &addr.sa, sizeof(addr.svm)) < 0) {
118*8abbffd2SArseniy Krasnov perror("connect");
119*8abbffd2SArseniy Krasnov close(fd);
120*8abbffd2SArseniy Krasnov return -1;
121*8abbffd2SArseniy Krasnov }
122*8abbffd2SArseniy Krasnov
123*8abbffd2SArseniy Krasnov return fd;
124*8abbffd2SArseniy Krasnov }
125*8abbffd2SArseniy Krasnov
get_gbps(unsigned long bits,time_t ns_delta)126*8abbffd2SArseniy Krasnov static float get_gbps(unsigned long bits, time_t ns_delta)
127*8abbffd2SArseniy Krasnov {
128*8abbffd2SArseniy Krasnov return ((float)bits / 1000000000ULL) /
129*8abbffd2SArseniy Krasnov ((float)ns_delta / NSEC_PER_SEC);
130*8abbffd2SArseniy Krasnov }
131*8abbffd2SArseniy Krasnov
run_receiver(unsigned long rcvlowat_bytes)132*8abbffd2SArseniy Krasnov static void run_receiver(unsigned long rcvlowat_bytes)
133*8abbffd2SArseniy Krasnov {
134*8abbffd2SArseniy Krasnov unsigned int read_cnt;
135*8abbffd2SArseniy Krasnov time_t rx_begin_ns;
136*8abbffd2SArseniy Krasnov time_t in_read_ns;
137*8abbffd2SArseniy Krasnov size_t total_recv;
138*8abbffd2SArseniy Krasnov int client_fd;
139*8abbffd2SArseniy Krasnov char *data;
140*8abbffd2SArseniy Krasnov int fd;
141*8abbffd2SArseniy Krasnov union {
142*8abbffd2SArseniy Krasnov struct sockaddr sa;
143*8abbffd2SArseniy Krasnov struct sockaddr_vm svm;
144*8abbffd2SArseniy Krasnov } addr = {
145*8abbffd2SArseniy Krasnov .svm = {
146*8abbffd2SArseniy Krasnov .svm_family = AF_VSOCK,
147*8abbffd2SArseniy Krasnov .svm_port = port,
148*8abbffd2SArseniy Krasnov .svm_cid = VMADDR_CID_ANY,
149*8abbffd2SArseniy Krasnov },
150*8abbffd2SArseniy Krasnov };
151*8abbffd2SArseniy Krasnov union {
152*8abbffd2SArseniy Krasnov struct sockaddr sa;
153*8abbffd2SArseniy Krasnov struct sockaddr_vm svm;
154*8abbffd2SArseniy Krasnov } clientaddr;
155*8abbffd2SArseniy Krasnov
156*8abbffd2SArseniy Krasnov socklen_t clientaddr_len = sizeof(clientaddr.svm);
157*8abbffd2SArseniy Krasnov
158*8abbffd2SArseniy Krasnov printf("Run as receiver\n");
159*8abbffd2SArseniy Krasnov printf("Listen port %u\n", port);
160*8abbffd2SArseniy Krasnov printf("RX buffer %lu bytes\n", buf_size_bytes);
161*8abbffd2SArseniy Krasnov printf("vsock buffer %lu bytes\n", vsock_buf_bytes);
162*8abbffd2SArseniy Krasnov printf("SO_RCVLOWAT %lu bytes\n", rcvlowat_bytes);
163*8abbffd2SArseniy Krasnov
164*8abbffd2SArseniy Krasnov fd = socket(AF_VSOCK, SOCK_STREAM, 0);
165*8abbffd2SArseniy Krasnov
166*8abbffd2SArseniy Krasnov if (fd < 0)
167*8abbffd2SArseniy Krasnov error("socket");
168*8abbffd2SArseniy Krasnov
169*8abbffd2SArseniy Krasnov if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0)
170*8abbffd2SArseniy Krasnov error("bind");
171*8abbffd2SArseniy Krasnov
172*8abbffd2SArseniy Krasnov if (listen(fd, 1) < 0)
173*8abbffd2SArseniy Krasnov error("listen");
174*8abbffd2SArseniy Krasnov
175*8abbffd2SArseniy Krasnov client_fd = accept(fd, &clientaddr.sa, &clientaddr_len);
176*8abbffd2SArseniy Krasnov
177*8abbffd2SArseniy Krasnov if (client_fd < 0)
178*8abbffd2SArseniy Krasnov error("accept");
179*8abbffd2SArseniy Krasnov
180*8abbffd2SArseniy Krasnov vsock_increase_buf_size(client_fd);
181*8abbffd2SArseniy Krasnov
182*8abbffd2SArseniy Krasnov if (setsockopt(client_fd, SOL_SOCKET, SO_RCVLOWAT,
183*8abbffd2SArseniy Krasnov &rcvlowat_bytes,
184*8abbffd2SArseniy Krasnov sizeof(rcvlowat_bytes)))
185*8abbffd2SArseniy Krasnov error("setsockopt(SO_RCVLOWAT)");
186*8abbffd2SArseniy Krasnov
187*8abbffd2SArseniy Krasnov data = malloc(buf_size_bytes);
188*8abbffd2SArseniy Krasnov
189*8abbffd2SArseniy Krasnov if (!data) {
190*8abbffd2SArseniy Krasnov fprintf(stderr, "'malloc()' failed\n");
191*8abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
192*8abbffd2SArseniy Krasnov }
193*8abbffd2SArseniy Krasnov
194*8abbffd2SArseniy Krasnov read_cnt = 0;
195*8abbffd2SArseniy Krasnov in_read_ns = 0;
196*8abbffd2SArseniy Krasnov total_recv = 0;
197*8abbffd2SArseniy Krasnov rx_begin_ns = current_nsec();
198*8abbffd2SArseniy Krasnov
199*8abbffd2SArseniy Krasnov while (1) {
200*8abbffd2SArseniy Krasnov struct pollfd fds = { 0 };
201*8abbffd2SArseniy Krasnov
202*8abbffd2SArseniy Krasnov fds.fd = client_fd;
203*8abbffd2SArseniy Krasnov fds.events = POLLIN | POLLERR |
204*8abbffd2SArseniy Krasnov POLLHUP | POLLRDHUP;
205*8abbffd2SArseniy Krasnov
206*8abbffd2SArseniy Krasnov if (poll(&fds, 1, -1) < 0)
207*8abbffd2SArseniy Krasnov error("poll");
208*8abbffd2SArseniy Krasnov
209*8abbffd2SArseniy Krasnov if (fds.revents & POLLERR) {
210*8abbffd2SArseniy Krasnov fprintf(stderr, "'poll()' error\n");
211*8abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
212*8abbffd2SArseniy Krasnov }
213*8abbffd2SArseniy Krasnov
214*8abbffd2SArseniy Krasnov if (fds.revents & POLLIN) {
215*8abbffd2SArseniy Krasnov ssize_t bytes_read;
216*8abbffd2SArseniy Krasnov time_t t;
217*8abbffd2SArseniy Krasnov
218*8abbffd2SArseniy Krasnov t = current_nsec();
219*8abbffd2SArseniy Krasnov bytes_read = read(fds.fd, data, buf_size_bytes);
220*8abbffd2SArseniy Krasnov in_read_ns += (current_nsec() - t);
221*8abbffd2SArseniy Krasnov read_cnt++;
222*8abbffd2SArseniy Krasnov
223*8abbffd2SArseniy Krasnov if (!bytes_read)
224*8abbffd2SArseniy Krasnov break;
225*8abbffd2SArseniy Krasnov
226*8abbffd2SArseniy Krasnov if (bytes_read < 0) {
227*8abbffd2SArseniy Krasnov perror("read");
228*8abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
229*8abbffd2SArseniy Krasnov }
230*8abbffd2SArseniy Krasnov
231*8abbffd2SArseniy Krasnov total_recv += bytes_read;
232*8abbffd2SArseniy Krasnov }
233*8abbffd2SArseniy Krasnov
234*8abbffd2SArseniy Krasnov if (fds.revents & (POLLHUP | POLLRDHUP))
235*8abbffd2SArseniy Krasnov break;
236*8abbffd2SArseniy Krasnov }
237*8abbffd2SArseniy Krasnov
238*8abbffd2SArseniy Krasnov printf("total bytes received: %zu\n", total_recv);
239*8abbffd2SArseniy Krasnov printf("rx performance: %f Gbits/s\n",
240*8abbffd2SArseniy Krasnov get_gbps(total_recv * 8, current_nsec() - rx_begin_ns));
241*8abbffd2SArseniy Krasnov printf("total time in 'read()': %f sec\n", (float)in_read_ns / NSEC_PER_SEC);
242*8abbffd2SArseniy Krasnov printf("average time in 'read()': %f ns\n", (float)in_read_ns / read_cnt);
243*8abbffd2SArseniy Krasnov printf("POLLIN wakeups: %i\n", read_cnt);
244*8abbffd2SArseniy Krasnov
245*8abbffd2SArseniy Krasnov free(data);
246*8abbffd2SArseniy Krasnov close(client_fd);
247*8abbffd2SArseniy Krasnov close(fd);
248*8abbffd2SArseniy Krasnov }
249*8abbffd2SArseniy Krasnov
run_sender(int peer_cid,unsigned long to_send_bytes)250*8abbffd2SArseniy Krasnov static void run_sender(int peer_cid, unsigned long to_send_bytes)
251*8abbffd2SArseniy Krasnov {
252*8abbffd2SArseniy Krasnov time_t tx_begin_ns;
253*8abbffd2SArseniy Krasnov time_t tx_total_ns;
254*8abbffd2SArseniy Krasnov size_t total_send;
255*8abbffd2SArseniy Krasnov void *data;
256*8abbffd2SArseniy Krasnov int fd;
257*8abbffd2SArseniy Krasnov
258*8abbffd2SArseniy Krasnov printf("Run as sender\n");
259*8abbffd2SArseniy Krasnov printf("Connect to %i:%u\n", peer_cid, port);
260*8abbffd2SArseniy Krasnov printf("Send %lu bytes\n", to_send_bytes);
261*8abbffd2SArseniy Krasnov printf("TX buffer %lu bytes\n", buf_size_bytes);
262*8abbffd2SArseniy Krasnov
263*8abbffd2SArseniy Krasnov fd = vsock_connect(peer_cid, port);
264*8abbffd2SArseniy Krasnov
265*8abbffd2SArseniy Krasnov if (fd < 0)
266*8abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
267*8abbffd2SArseniy Krasnov
268*8abbffd2SArseniy Krasnov data = malloc(buf_size_bytes);
269*8abbffd2SArseniy Krasnov
270*8abbffd2SArseniy Krasnov if (!data) {
271*8abbffd2SArseniy Krasnov fprintf(stderr, "'malloc()' failed\n");
272*8abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
273*8abbffd2SArseniy Krasnov }
274*8abbffd2SArseniy Krasnov
275*8abbffd2SArseniy Krasnov memset(data, 0, buf_size_bytes);
276*8abbffd2SArseniy Krasnov total_send = 0;
277*8abbffd2SArseniy Krasnov tx_begin_ns = current_nsec();
278*8abbffd2SArseniy Krasnov
279*8abbffd2SArseniy Krasnov while (total_send < to_send_bytes) {
280*8abbffd2SArseniy Krasnov ssize_t sent;
281*8abbffd2SArseniy Krasnov
282*8abbffd2SArseniy Krasnov sent = write(fd, data, buf_size_bytes);
283*8abbffd2SArseniy Krasnov
284*8abbffd2SArseniy Krasnov if (sent <= 0)
285*8abbffd2SArseniy Krasnov error("write");
286*8abbffd2SArseniy Krasnov
287*8abbffd2SArseniy Krasnov total_send += sent;
288*8abbffd2SArseniy Krasnov }
289*8abbffd2SArseniy Krasnov
290*8abbffd2SArseniy Krasnov tx_total_ns = current_nsec() - tx_begin_ns;
291*8abbffd2SArseniy Krasnov
292*8abbffd2SArseniy Krasnov printf("total bytes sent: %zu\n", total_send);
293*8abbffd2SArseniy Krasnov printf("tx performance: %f Gbits/s\n",
294*8abbffd2SArseniy Krasnov get_gbps(total_send * 8, tx_total_ns));
295*8abbffd2SArseniy Krasnov printf("total time in 'write()': %f sec\n",
296*8abbffd2SArseniy Krasnov (float)tx_total_ns / NSEC_PER_SEC);
297*8abbffd2SArseniy Krasnov
298*8abbffd2SArseniy Krasnov close(fd);
299*8abbffd2SArseniy Krasnov free(data);
300*8abbffd2SArseniy Krasnov }
301*8abbffd2SArseniy Krasnov
302*8abbffd2SArseniy Krasnov static const char optstring[] = "";
303*8abbffd2SArseniy Krasnov static const struct option longopts[] = {
304*8abbffd2SArseniy Krasnov {
305*8abbffd2SArseniy Krasnov .name = "help",
306*8abbffd2SArseniy Krasnov .has_arg = no_argument,
307*8abbffd2SArseniy Krasnov .val = 'H',
308*8abbffd2SArseniy Krasnov },
309*8abbffd2SArseniy Krasnov {
310*8abbffd2SArseniy Krasnov .name = "sender",
311*8abbffd2SArseniy Krasnov .has_arg = required_argument,
312*8abbffd2SArseniy Krasnov .val = 'S',
313*8abbffd2SArseniy Krasnov },
314*8abbffd2SArseniy Krasnov {
315*8abbffd2SArseniy Krasnov .name = "port",
316*8abbffd2SArseniy Krasnov .has_arg = required_argument,
317*8abbffd2SArseniy Krasnov .val = 'P',
318*8abbffd2SArseniy Krasnov },
319*8abbffd2SArseniy Krasnov {
320*8abbffd2SArseniy Krasnov .name = "bytes",
321*8abbffd2SArseniy Krasnov .has_arg = required_argument,
322*8abbffd2SArseniy Krasnov .val = 'M',
323*8abbffd2SArseniy Krasnov },
324*8abbffd2SArseniy Krasnov {
325*8abbffd2SArseniy Krasnov .name = "buf-size",
326*8abbffd2SArseniy Krasnov .has_arg = required_argument,
327*8abbffd2SArseniy Krasnov .val = 'B',
328*8abbffd2SArseniy Krasnov },
329*8abbffd2SArseniy Krasnov {
330*8abbffd2SArseniy Krasnov .name = "vsk-size",
331*8abbffd2SArseniy Krasnov .has_arg = required_argument,
332*8abbffd2SArseniy Krasnov .val = 'V',
333*8abbffd2SArseniy Krasnov },
334*8abbffd2SArseniy Krasnov {
335*8abbffd2SArseniy Krasnov .name = "rcvlowat",
336*8abbffd2SArseniy Krasnov .has_arg = required_argument,
337*8abbffd2SArseniy Krasnov .val = 'R',
338*8abbffd2SArseniy Krasnov },
339*8abbffd2SArseniy Krasnov {},
340*8abbffd2SArseniy Krasnov };
341*8abbffd2SArseniy Krasnov
usage(void)342*8abbffd2SArseniy Krasnov static void usage(void)
343*8abbffd2SArseniy Krasnov {
344*8abbffd2SArseniy Krasnov printf("Usage: ./vsock_perf [--help] [options]\n"
345*8abbffd2SArseniy Krasnov "\n"
346*8abbffd2SArseniy Krasnov "This is benchmarking utility, to test vsock performance.\n"
347*8abbffd2SArseniy Krasnov "It runs in two modes: sender or receiver. In sender mode, it\n"
348*8abbffd2SArseniy Krasnov "connects to the specified CID and starts data transmission.\n"
349*8abbffd2SArseniy Krasnov "\n"
350*8abbffd2SArseniy Krasnov "Options:\n"
351*8abbffd2SArseniy Krasnov " --help This message\n"
352*8abbffd2SArseniy Krasnov " --sender <cid> Sender mode (receiver default)\n"
353*8abbffd2SArseniy Krasnov " <cid> of the receiver to connect to\n"
354*8abbffd2SArseniy Krasnov " --port <port> Port (default %d)\n"
355*8abbffd2SArseniy Krasnov " --bytes <bytes>KMG Bytes to send (default %d)\n"
356*8abbffd2SArseniy Krasnov " --buf-size <bytes>KMG Data buffer size (default %d). In sender mode\n"
357*8abbffd2SArseniy Krasnov " it is the buffer size, passed to 'write()'. In\n"
358*8abbffd2SArseniy Krasnov " receiver mode it is the buffer size passed to 'read()'.\n"
359*8abbffd2SArseniy Krasnov " --vsk-size <bytes>KMG Socket buffer size (default %d)\n"
360*8abbffd2SArseniy Krasnov " --rcvlowat <bytes>KMG SO_RCVLOWAT value (default %d)\n"
361*8abbffd2SArseniy Krasnov "\n", DEFAULT_PORT, DEFAULT_TO_SEND_BYTES,
362*8abbffd2SArseniy Krasnov DEFAULT_BUF_SIZE_BYTES, DEFAULT_VSOCK_BUF_BYTES,
363*8abbffd2SArseniy Krasnov DEFAULT_RCVLOWAT_BYTES);
364*8abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
365*8abbffd2SArseniy Krasnov }
366*8abbffd2SArseniy Krasnov
strtolx(const char * arg)367*8abbffd2SArseniy Krasnov static long strtolx(const char *arg)
368*8abbffd2SArseniy Krasnov {
369*8abbffd2SArseniy Krasnov long value;
370*8abbffd2SArseniy Krasnov char *end;
371*8abbffd2SArseniy Krasnov
372*8abbffd2SArseniy Krasnov value = strtol(arg, &end, 10);
373*8abbffd2SArseniy Krasnov
374*8abbffd2SArseniy Krasnov if (end != arg + strlen(arg))
375*8abbffd2SArseniy Krasnov usage();
376*8abbffd2SArseniy Krasnov
377*8abbffd2SArseniy Krasnov return value;
378*8abbffd2SArseniy Krasnov }
379*8abbffd2SArseniy Krasnov
main(int argc,char ** argv)380*8abbffd2SArseniy Krasnov int main(int argc, char **argv)
381*8abbffd2SArseniy Krasnov {
382*8abbffd2SArseniy Krasnov unsigned long to_send_bytes = DEFAULT_TO_SEND_BYTES;
383*8abbffd2SArseniy Krasnov unsigned long rcvlowat_bytes = DEFAULT_RCVLOWAT_BYTES;
384*8abbffd2SArseniy Krasnov int peer_cid = -1;
385*8abbffd2SArseniy Krasnov bool sender = false;
386*8abbffd2SArseniy Krasnov
387*8abbffd2SArseniy Krasnov while (1) {
388*8abbffd2SArseniy Krasnov int opt = getopt_long(argc, argv, optstring, longopts, NULL);
389*8abbffd2SArseniy Krasnov
390*8abbffd2SArseniy Krasnov if (opt == -1)
391*8abbffd2SArseniy Krasnov break;
392*8abbffd2SArseniy Krasnov
393*8abbffd2SArseniy Krasnov switch (opt) {
394*8abbffd2SArseniy Krasnov case 'V': /* Peer buffer size. */
395*8abbffd2SArseniy Krasnov vsock_buf_bytes = memparse(optarg);
396*8abbffd2SArseniy Krasnov break;
397*8abbffd2SArseniy Krasnov case 'R': /* SO_RCVLOWAT value. */
398*8abbffd2SArseniy Krasnov rcvlowat_bytes = memparse(optarg);
399*8abbffd2SArseniy Krasnov break;
400*8abbffd2SArseniy Krasnov case 'P': /* Port to connect to. */
401*8abbffd2SArseniy Krasnov port = strtolx(optarg);
402*8abbffd2SArseniy Krasnov break;
403*8abbffd2SArseniy Krasnov case 'M': /* Bytes to send. */
404*8abbffd2SArseniy Krasnov to_send_bytes = memparse(optarg);
405*8abbffd2SArseniy Krasnov break;
406*8abbffd2SArseniy Krasnov case 'B': /* Size of rx/tx buffer. */
407*8abbffd2SArseniy Krasnov buf_size_bytes = memparse(optarg);
408*8abbffd2SArseniy Krasnov break;
409*8abbffd2SArseniy Krasnov case 'S': /* Sender mode. CID to connect to. */
410*8abbffd2SArseniy Krasnov peer_cid = strtolx(optarg);
411*8abbffd2SArseniy Krasnov sender = true;
412*8abbffd2SArseniy Krasnov break;
413*8abbffd2SArseniy Krasnov case 'H': /* Help. */
414*8abbffd2SArseniy Krasnov usage();
415*8abbffd2SArseniy Krasnov break;
416*8abbffd2SArseniy Krasnov default:
417*8abbffd2SArseniy Krasnov usage();
418*8abbffd2SArseniy Krasnov }
419*8abbffd2SArseniy Krasnov }
420*8abbffd2SArseniy Krasnov
421*8abbffd2SArseniy Krasnov if (!sender)
422*8abbffd2SArseniy Krasnov run_receiver(rcvlowat_bytes);
423*8abbffd2SArseniy Krasnov else
424*8abbffd2SArseniy Krasnov run_sender(peer_cid, to_send_bytes);
425*8abbffd2SArseniy Krasnov
426*8abbffd2SArseniy Krasnov return 0;
427*8abbffd2SArseniy Krasnov }
428