Skip to content

Commit 75e4ea8

Browse files
committed
test(vsock): latency performance test
Create simple ping latency test in vsock_helper host tools Signed-off-by: Aaron Ang <[email protected]>
1 parent 4993d4d commit 75e4ea8

File tree

2 files changed

+385
-7
lines changed

2 files changed

+385
-7
lines changed

tests/host_tools/vsock_helper.c

Lines changed: 235 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,39 @@
1010
#include <sys/types.h>
1111
#include <sys/select.h>
1212
#include <sys/wait.h>
13+
#include <sys/un.h>
1314
#include <linux/vm_sockets.h>
1415
#include <stdio.h>
1516
#include <stdlib.h>
1617
#include <stdint.h>
1718
#include <string.h>
1819
#include <unistd.h>
1920
#include <stdio.h>
20-
#include <errno.h>
21+
#include <time.h>
2122

2223

2324
#define BUF_SIZE (16 * 1024)
2425
#define SERVER_ACCEPT_BACKLOG 128
2526

2627

2728
int print_usage() {
28-
fprintf(stderr, "Usage: ./vsock-helper echo <cid> <port>\n");
29+
fprintf(stderr, "Usage: ./vsock-helper <command> <args>\n");
2930
fprintf(stderr, "\n");
30-
fprintf(stderr, " echo connect to an echo server, listening on CID:port.\n");
31-
fprintf(stderr, " STDIN will be piped through to the echo server, and\n");
32-
fprintf(stderr, " data coming from the server will pe sent to STDOUT.\n");
31+
fprintf(stderr, "Commands:\n");
32+
fprintf(stderr, " echo <cid> <port>\n");
33+
fprintf(stderr, " Connect to echo server at CID:port. Pipe STDIN to server,\n");
34+
fprintf(stderr, " server response to STDOUT.\n");
35+
fprintf(stderr, "\n");
36+
fprintf(stderr, " ping <cid> <port> <count> <delay>\n");
37+
fprintf(stderr, " Send <count> ping messages to echo server at CID:port.\n");
38+
fprintf(stderr, " <delay> is the delay in seconds between pings (float).\n");
39+
fprintf(stderr, " Prints RTT for each ping in microseconds.\n");
40+
fprintf(stderr, "\n");
41+
fprintf(stderr, " ping-uds <uds_path> <port> <count> <delay>\n");
42+
fprintf(stderr, " Send <count> ping messages to echo server at <uds_path>:port.\n");
43+
fprintf(stderr, " Uses Unix Domain Socket with Firecracker CONNECT protocol.\n");
44+
fprintf(stderr, " <delay> is the delay in seconds between pings (float).\n");
45+
fprintf(stderr, " Prints RTT for each ping in microseconds.\n");
3346
fprintf(stderr, "\n");
3447
return -1;
3548
}
@@ -88,9 +101,195 @@ int run_echo(uint32_t cid, uint32_t port) {
88101
}
89102

90103

104+
int run_ping(uint32_t cid, uint32_t port, int count, double delay_sec) {
105+
106+
int sock = socket(AF_VSOCK, SOCK_STREAM, 0);
107+
if (sock < 0) {
108+
perror("socket()");
109+
return -1;
110+
}
111+
112+
struct sockaddr_vm vsock_addr = {
113+
.svm_family = AF_VSOCK,
114+
.svm_port = port,
115+
.svm_cid = cid
116+
};
117+
if (connect(sock, (struct sockaddr*)&vsock_addr, sizeof(vsock_addr)) < 0) {
118+
perror("connect()");
119+
close(sock);
120+
return -1;
121+
}
122+
123+
char ping_msg[64];
124+
memset(ping_msg, 'A', sizeof(ping_msg));
125+
126+
struct timespec delay_ts;
127+
delay_ts.tv_sec = (time_t)delay_sec;
128+
delay_ts.tv_nsec = (long)((delay_sec - (time_t)delay_sec) * 1000000000);
129+
130+
for (int seq = 1; seq <= count; seq++) {
131+
struct timespec start, end;
132+
133+
if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) {
134+
perror("clock_gettime(start)");
135+
close(sock);
136+
return -1;
137+
}
138+
139+
ssize_t sent = write(sock, ping_msg, sizeof(ping_msg));
140+
if (sent != sizeof(ping_msg)) {
141+
perror("write()");
142+
close(sock);
143+
return -1;
144+
}
145+
146+
char pong_buf[64];
147+
size_t total_received = 0;
148+
while (total_received < sizeof(ping_msg)) {
149+
ssize_t received = read(sock, pong_buf + total_received,
150+
sizeof(ping_msg) - total_received);
151+
if (received <= 0) {
152+
perror("read()");
153+
close(sock);
154+
return -1;
155+
}
156+
total_received += received;
157+
}
158+
159+
if (clock_gettime(CLOCK_MONOTONIC, &end) < 0) {
160+
perror("clock_gettime(end)");
161+
close(sock);
162+
return -1;
163+
}
164+
165+
long long start_us = start.tv_sec * 1000000LL + start.tv_nsec / 1000;
166+
long long end_us = end.tv_sec * 1000000LL + end.tv_nsec / 1000;
167+
long long rtt_us = end_us - start_us;
168+
169+
printf("rtt=%.3f us seq=%d\n", (double)rtt_us, seq);
170+
fflush(stdout);
171+
172+
if (seq < count && delay_sec > 0) {
173+
nanosleep(&delay_ts, NULL);
174+
}
175+
}
176+
177+
close(sock);
178+
return 0;
179+
}
180+
181+
182+
int run_ping_uds(const char *uds_path, uint32_t port, int count, double delay_sec) {
183+
184+
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
185+
if (sock < 0) {
186+
perror("socket()");
187+
return -1;
188+
}
189+
190+
struct sockaddr_un unix_addr;
191+
memset(&unix_addr, 0, sizeof(unix_addr));
192+
unix_addr.sun_family = AF_UNIX;
193+
strncpy(unix_addr.sun_path, uds_path, sizeof(unix_addr.sun_path) - 1);
194+
195+
if (connect(sock, (struct sockaddr*)&unix_addr, sizeof(unix_addr)) < 0) {
196+
perror("connect()");
197+
close(sock);
198+
return -1;
199+
}
200+
201+
char connect_msg[64];
202+
int connect_len = snprintf(connect_msg, sizeof(connect_msg), "CONNECT %u\n", port);
203+
if (connect_len < 0 || connect_len >= sizeof(connect_msg)) {
204+
fprintf(stderr, "Error formatting CONNECT message\n");
205+
close(sock);
206+
return -1;
207+
}
208+
209+
ssize_t sent = write(sock, connect_msg, connect_len);
210+
if (sent != connect_len) {
211+
perror("write(CONNECT)");
212+
close(sock);
213+
return -1;
214+
}
215+
216+
char ack_buf[32];
217+
ssize_t ack_received = read(sock, ack_buf, sizeof(ack_buf) - 1);
218+
if (ack_received <= 0) {
219+
perror("read(ack)");
220+
close(sock);
221+
return -1;
222+
}
223+
ack_buf[ack_received] = '\0';
224+
225+
if (strncmp(ack_buf, "OK ", 3) != 0) {
226+
fprintf(stderr, "Invalid acknowledgment: %s\n", ack_buf);
227+
close(sock);
228+
return -1;
229+
}
230+
231+
char ping_msg[64];
232+
memset(ping_msg, 'A', sizeof(ping_msg));
233+
234+
struct timespec delay_ts;
235+
delay_ts.tv_sec = (time_t)delay_sec;
236+
delay_ts.tv_nsec = (long)((delay_sec - (time_t)delay_sec) * 1000000000);
237+
238+
for (int seq = 1; seq <= count; seq++) {
239+
struct timespec start, end;
240+
241+
if (clock_gettime(CLOCK_MONOTONIC, &start) < 0) {
242+
perror("clock_gettime(start)");
243+
close(sock);
244+
return -1;
245+
}
246+
247+
sent = write(sock, ping_msg, sizeof(ping_msg));
248+
if (sent != sizeof(ping_msg)) {
249+
perror("write()");
250+
close(sock);
251+
return -1;
252+
}
253+
254+
char pong_buf[64];
255+
size_t total_received = 0;
256+
while (total_received < sizeof(ping_msg)) {
257+
ssize_t received = read(sock, pong_buf + total_received,
258+
sizeof(ping_msg) - total_received);
259+
if (received <= 0) {
260+
perror("read()");
261+
close(sock);
262+
return -1;
263+
}
264+
total_received += received;
265+
}
266+
267+
if (clock_gettime(CLOCK_MONOTONIC, &end) < 0) {
268+
perror("clock_gettime(end)");
269+
close(sock);
270+
return -1;
271+
}
272+
273+
long long start_us = start.tv_sec * 1000000LL + start.tv_nsec / 1000;
274+
long long end_us = end.tv_sec * 1000000LL + end.tv_nsec / 1000;
275+
long long rtt_us = end_us - start_us;
276+
277+
printf("rtt=%.3f us seq=%d\n", (double)rtt_us, seq);
278+
fflush(stdout);
279+
280+
if (seq < count && delay_sec > 0) {
281+
nanosleep(&delay_ts, NULL);
282+
}
283+
}
284+
285+
close(sock);
286+
return 0;
287+
}
288+
289+
91290
int main(int argc, char **argv) {
92291

93-
if (argc < 3) {
292+
if (argc < 2) {
94293
return print_usage();
95294
}
96295

@@ -106,5 +305,35 @@ int main(int argc, char **argv) {
106305
return run_echo(cid, port);
107306
}
108307

308+
if (strcmp(argv[1], "ping") == 0) {
309+
if (argc != 6) {
310+
return print_usage();
311+
}
312+
uint32_t cid = atoi(argv[2]);
313+
uint32_t port = atoi(argv[3]);
314+
int count = atoi(argv[4]);
315+
double delay = atof(argv[5]);
316+
317+
if (!cid || !port || count <= 0 || delay < 0) {
318+
return print_usage();
319+
}
320+
return run_ping(cid, port, count, delay);
321+
}
322+
323+
if (strcmp(argv[1], "ping-uds") == 0) {
324+
if (argc != 6) {
325+
return print_usage();
326+
}
327+
const char *uds_path = argv[2];
328+
uint32_t port = atoi(argv[3]);
329+
int count = atoi(argv[4]);
330+
double delay = atof(argv[5]);
331+
332+
if (!port || count <= 0 || delay < 0) {
333+
return print_usage();
334+
}
335+
return run_ping_uds(uds_path, port, count, delay);
336+
}
337+
109338
return print_usage();
110339
}

0 commit comments

Comments
 (0)