vsock/test: two tests to check credit update logic
Both tests are almost same, only differs in two 'if' conditions, so implemented in a single function. Tests check, that credit update message is sent: 1) During setting SO_RCVLOWAT value of the socket. 2) When number of 'rx_bytes' become smaller than SO_RCVLOWAT value. Signed-off-by: Arseniy Krasnov <avkrasnov@salutedevices.com> Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0fe1798968
commit
542e893fba
1 changed files with 175 additions and 0 deletions
|
@ -1232,6 +1232,171 @@ static void test_double_bind_connect_client(const struct test_opts *opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define RCVLOWAT_CREDIT_UPD_BUF_SIZE (1024 * 128)
|
||||||
|
/* This define is the same as in 'include/linux/virtio_vsock.h':
|
||||||
|
* it is used to decide when to send credit update message during
|
||||||
|
* reading from rx queue of a socket. Value and its usage in
|
||||||
|
* kernel is important for this test.
|
||||||
|
*/
|
||||||
|
#define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64)
|
||||||
|
|
||||||
|
static void test_stream_rcvlowat_def_cred_upd_client(const struct test_opts *opts)
|
||||||
|
{
|
||||||
|
size_t buf_size;
|
||||||
|
void *buf;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = vsock_stream_connect(opts->peer_cid, 1234);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("connect");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send 1 byte more than peer's buffer size. */
|
||||||
|
buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE + 1;
|
||||||
|
|
||||||
|
buf = malloc(buf_size);
|
||||||
|
if (!buf) {
|
||||||
|
perror("malloc");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until peer sets needed buffer size. */
|
||||||
|
recv_byte(fd, 1, 0);
|
||||||
|
|
||||||
|
if (send(fd, buf, buf_size, 0) != buf_size) {
|
||||||
|
perror("send failed");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stream_credit_update_test(const struct test_opts *opts,
|
||||||
|
bool low_rx_bytes_test)
|
||||||
|
{
|
||||||
|
size_t recv_buf_size;
|
||||||
|
struct pollfd fds;
|
||||||
|
size_t buf_size;
|
||||||
|
void *buf;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = vsock_stream_accept(VMADDR_CID_ANY, 1234, NULL);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("accept");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_size = RCVLOWAT_CREDIT_UPD_BUF_SIZE;
|
||||||
|
|
||||||
|
if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
|
||||||
|
&buf_size, sizeof(buf_size))) {
|
||||||
|
perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (low_rx_bytes_test) {
|
||||||
|
/* Set new SO_RCVLOWAT here. This enables sending credit
|
||||||
|
* update when number of bytes if our rx queue become <
|
||||||
|
* SO_RCVLOWAT value.
|
||||||
|
*/
|
||||||
|
recv_buf_size = 1 + VIRTIO_VSOCK_MAX_PKT_BUF_SIZE;
|
||||||
|
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
|
||||||
|
&recv_buf_size, sizeof(recv_buf_size))) {
|
||||||
|
perror("setsockopt(SO_RCVLOWAT)");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send one dummy byte here, because 'setsockopt()' above also
|
||||||
|
* sends special packet which tells sender to update our buffer
|
||||||
|
* size. This 'send_byte()' will serialize such packet with data
|
||||||
|
* reads in a loop below. Sender starts transmission only when
|
||||||
|
* it receives this single byte.
|
||||||
|
*/
|
||||||
|
send_byte(fd, 1, 0);
|
||||||
|
|
||||||
|
buf = malloc(buf_size);
|
||||||
|
if (!buf) {
|
||||||
|
perror("malloc");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait until there will be 128KB of data in rx queue. */
|
||||||
|
while (1) {
|
||||||
|
ssize_t res;
|
||||||
|
|
||||||
|
res = recv(fd, buf, buf_size, MSG_PEEK);
|
||||||
|
if (res == buf_size)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (res <= 0) {
|
||||||
|
fprintf(stderr, "unexpected 'recv()' return: %zi\n", res);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is 128KB of data in the socket's rx queue, dequeue first
|
||||||
|
* 64KB, credit update is sent if 'low_rx_bytes_test' == true.
|
||||||
|
* Otherwise, credit update is sent in 'if (!low_rx_bytes_test)'.
|
||||||
|
*/
|
||||||
|
recv_buf_size = VIRTIO_VSOCK_MAX_PKT_BUF_SIZE;
|
||||||
|
recv_buf(fd, buf, recv_buf_size, 0, recv_buf_size);
|
||||||
|
|
||||||
|
if (!low_rx_bytes_test) {
|
||||||
|
recv_buf_size++;
|
||||||
|
|
||||||
|
/* Updating SO_RCVLOWAT will send credit update. */
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT,
|
||||||
|
&recv_buf_size, sizeof(recv_buf_size))) {
|
||||||
|
perror("setsockopt(SO_RCVLOWAT)");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fds.fd = fd;
|
||||||
|
fds.events = POLLIN | POLLRDNORM | POLLERR |
|
||||||
|
POLLRDHUP | POLLHUP;
|
||||||
|
|
||||||
|
/* This 'poll()' will return once we receive last byte
|
||||||
|
* sent by client.
|
||||||
|
*/
|
||||||
|
if (poll(&fds, 1, -1) < 0) {
|
||||||
|
perror("poll");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds.revents & POLLERR) {
|
||||||
|
fprintf(stderr, "'poll()' error\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds.revents & (POLLIN | POLLRDNORM)) {
|
||||||
|
recv_buf(fd, buf, recv_buf_size, MSG_DONTWAIT, recv_buf_size);
|
||||||
|
} else {
|
||||||
|
/* These flags must be set, as there is at
|
||||||
|
* least 64KB of data ready to read.
|
||||||
|
*/
|
||||||
|
fprintf(stderr, "POLLIN | POLLRDNORM expected\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stream_cred_upd_on_low_rx_bytes(const struct test_opts *opts)
|
||||||
|
{
|
||||||
|
test_stream_credit_update_test(opts, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_stream_cred_upd_on_set_rcvlowat(const struct test_opts *opts)
|
||||||
|
{
|
||||||
|
test_stream_credit_update_test(opts, false);
|
||||||
|
}
|
||||||
|
|
||||||
static struct test_case test_cases[] = {
|
static struct test_case test_cases[] = {
|
||||||
{
|
{
|
||||||
.name = "SOCK_STREAM connection reset",
|
.name = "SOCK_STREAM connection reset",
|
||||||
|
@ -1342,6 +1507,16 @@ static struct test_case test_cases[] = {
|
||||||
.run_client = test_double_bind_connect_client,
|
.run_client = test_double_bind_connect_client,
|
||||||
.run_server = test_double_bind_connect_server,
|
.run_server = test_double_bind_connect_server,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "SOCK_STREAM virtio credit update + SO_RCVLOWAT",
|
||||||
|
.run_client = test_stream_rcvlowat_def_cred_upd_client,
|
||||||
|
.run_server = test_stream_cred_upd_on_set_rcvlowat,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "SOCK_STREAM virtio credit update + low rx_bytes",
|
||||||
|
.run_client = test_stream_rcvlowat_def_cred_upd_client,
|
||||||
|
.run_server = test_stream_cred_upd_on_low_rx_bytes,
|
||||||
|
},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue