Skip to content

Commit

Permalink
devices/vsock: integration test
Browse files Browse the repository at this point in the history
Added a vsock integration test, along with a new testing tool
(tests/host_tools/vsock_helper.c).

Signed-off-by: Dan Horobeanu <[email protected]>
  • Loading branch information
dhrgit committed Sep 2, 2019
1 parent bb63011 commit 7486f35
Show file tree
Hide file tree
Showing 3 changed files with 524 additions and 0 deletions.
10 changes: 10 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,15 @@ def aux_bin_paths(test_session_root_path):
cloner_bin_path
)

vsock_helper_bin_path = os.path.join(
test_session_root_path,
'vsock_helper'
)
_gcc_compile(
'host_tools/vsock_helper.c',
vsock_helper_bin_path
)

seccomp_build_path = os.path.join(
test_session_root_path,
build_tools.CARGO_RELEASE_REL_PATH
Expand Down Expand Up @@ -274,6 +283,7 @@ def aux_bin_paths(test_session_root_path):

yield {
'cloner': cloner_bin_path,
'vsock_helper': vsock_helper_bin_path,
'demo_basic_jailer': demo_basic_jailer,
'demo_advanced_jailer': demo_advanced_jailer,
'demo_harmless': demo_harmless,
Expand Down
206 changes: 206 additions & 0 deletions tests/host_tools/vsock_helper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

// This is a vsock helper tool, used by the Firecracker integration tests,
// to - well - test the virtio vsock device. It can be used to:
// 1. Run a forking echo server, that echoes back any data received from
// a client; and
// 2. Run a vsock echo client, that reads data from STDIN, sends it to an
// echo server, then forwards the server's reply to STDOUT.

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <linux/vm_sockets.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>


#define BUF_SIZE (16 * 1024)
#define SERVER_ACCEPT_BACKLOG 128


int print_usage() {
fprintf(stderr, "Usage: ./vsock-helper {echosrv [-d] <port> | echo <cid> <port>}\n");
fprintf(stderr, "\n");
fprintf(stderr, " echosrv start a vsock echo server. The server will accept\n");
fprintf(stderr, " any incoming connection, and echo back any data\n");
fprintf(stderr, " received on it.\n");
fprintf(stderr, " -d can be used to daemonize the server.\n");
fprintf(stderr, "\n");
fprintf(stderr, " echo connect to an echo server, listening on CID:port.\n");
fprintf(stderr, " STDIN will be piped through to the echo server, and\n");
fprintf(stderr, " data coming from the server will pe sent to STDOUT.\n");
fprintf(stderr, "\n");
return -1;
}

int xfer(int src_fd, int dst_fd) {
char buf[BUF_SIZE];
int count = read(src_fd, buf, sizeof(buf));

if (!count) return 0;
if (count < 0) return -1;

int offset = 0;
do {
int written;
written = write(dst_fd, &buf[offset], count - offset);
if (written <= 0) return -1;
offset += written;
} while (offset < count);

return offset;
}


int run_echosrv(uint32_t port) {

struct sockaddr_vm vsock_addr = {
.svm_family = AF_VSOCK,
.svm_port = port,
.svm_cid = VMADDR_CID_ANY
};

int srv_sock = socket(AF_VSOCK, SOCK_STREAM, 0);
if (srv_sock < 0) {
perror("socket()");
return -1;
}

int res = bind(srv_sock, (struct sockaddr*)&vsock_addr, sizeof(struct sockaddr_vm));
if (res) {
perror("bind()");
return -1;
}

res = listen(srv_sock, SERVER_ACCEPT_BACKLOG);
if (res) {
perror("listen()");
return -1;
}

for (;;) {
struct sockaddr cl_addr;
socklen_t sockaddr_len = sizeof(cl_addr);
int cl_sock = accept(srv_sock, &cl_addr, &sockaddr_len);
if (cl_sock < 0) {
perror("accept()");
continue;
}

int pid = fork();
if (pid < 0) {
perror("fork()");
close(cl_sock);
continue;
}

if (!pid) {
int res;
do {
res = xfer(cl_sock, cl_sock);
} while (res > 0);
return res >= 0 ? 0 : -1;
}

close(cl_sock);
int cstatus;
waitpid(-1, &cstatus, WNOHANG);
printf("New client forked...\n");
}

return 0;
}


int run_echo(uint32_t cid, uint32_t port) {

int sock = socket(AF_VSOCK, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket()");
return -1;
}

struct sockaddr_vm vsock_addr = {
.svm_family = AF_VSOCK,
.svm_port = port,
.svm_cid = cid
};
if (connect(sock, (struct sockaddr*)&vsock_addr, sizeof(vsock_addr)) < 0) {
perror("connect()");
return -1;
}

for (;;) {
int ping_cnt = xfer(STDIN_FILENO, sock);
if (!ping_cnt) break;
if (ping_cnt < 0) return -1;

int pong_cnt = 0;
while (pong_cnt < ping_cnt) {
int res = xfer(sock, STDOUT_FILENO);
if (res <= 0) return -1;
pong_cnt += res;
}
}

return 0;
}


int main(int argc, char **argv) {

if (argc < 3) {
return print_usage();
}

if (strcmp(argv[1], "echosrv") == 0) {
uint32_t port;
if (strcmp(argv[2], "-d") == 0) {
if (argc < 4) {
return print_usage();
}
port = atoi(argv[3]);
if (!port) {
return print_usage();
}
int pid = fork();
if (pid < 0) return -1;
if (pid) {
printf("Forked vsock echo daemon listening on port %d\n", port);
return 0;
}
setsid();
close(STDIN_FILENO);
close(STDOUT_FILENO);
}
else {
port = atoi(argv[2]);
if (!port) {
return print_usage();
}
}
return run_echosrv(port);
}

if (strcmp(argv[1], "echo") == 0) {
if (argc != 4) {
return print_usage();
}
uint32_t cid = atoi(argv[2]);
uint32_t port = atoi(argv[3]);
if (!cid || !port) {
return print_usage();
}
return run_echo(cid, port);
}

return print_usage();
}
Loading

0 comments on commit 7486f35

Please sign in to comment.