Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

test/vsock: rework message bounds test

This updates message bound test making it more complex. Instead of
sending 1 bytes messages with one MSG_EOR bit, it sends messages of
random length(one half of messages are smaller than page size, second
half are bigger) with random number of MSG_EOR bits set. Receiver
also don't know total number of messages.

Signed-off-by: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Arseniy Krasnov and committed by
Paolo Abeni
5c338112 c43170b7

+157 -15
+28
tools/testing/vsock/control.c
··· 141 141 timeout_end(); 142 142 } 143 143 144 + void control_writeulong(unsigned long value) 145 + { 146 + char str[32]; 147 + 148 + if (snprintf(str, sizeof(str), "%lu", value) >= sizeof(str)) { 149 + perror("snprintf"); 150 + exit(EXIT_FAILURE); 151 + } 152 + 153 + control_writeln(str); 154 + } 155 + 156 + unsigned long control_readulong(void) 157 + { 158 + unsigned long value; 159 + char *str; 160 + 161 + str = control_readln(); 162 + 163 + if (!str) 164 + exit(EXIT_FAILURE); 165 + 166 + value = strtoul(str, NULL, 10); 167 + free(str); 168 + 169 + return value; 170 + } 171 + 144 172 /* Return the next line from the control socket (without the trailing newline). 145 173 * 146 174 * The program terminates if a timeout occurs.
+2
tools/testing/vsock/control.h
··· 9 9 void control_cleanup(void); 10 10 void control_writeln(const char *str); 11 11 char *control_readln(void); 12 + unsigned long control_readulong(void); 12 13 void control_expectln(const char *str); 13 14 bool control_cmpln(char *line, const char *str, bool fail); 15 + void control_writeulong(unsigned long value); 14 16 15 17 #endif /* CONTROL_H */
+13
tools/testing/vsock/util.c
··· 395 395 396 396 test_cases[test_id].skip = true; 397 397 } 398 + 399 + unsigned long hash_djb2(const void *data, size_t len) 400 + { 401 + unsigned long hash = 5381; 402 + int i = 0; 403 + 404 + while (i < len) { 405 + hash = ((hash << 5) + hash) + ((unsigned char *)data)[i]; 406 + i++; 407 + } 408 + 409 + return hash; 410 + }
+1
tools/testing/vsock/util.h
··· 49 49 void list_tests(const struct test_case *test_cases); 50 50 void skip_test(struct test_case *test_cases, size_t test_cases_len, 51 51 const char *test_id_str); 52 + unsigned long hash_djb2(const void *data, size_t len); 52 53 #endif /* UTIL_H */
+113 -15
tools/testing/vsock/vsock_test.c
··· 284 284 close(fd); 285 285 } 286 286 287 - #define MESSAGES_CNT 7 288 - #define MSG_EOR_IDX (MESSAGES_CNT / 2) 287 + #define SOCK_BUF_SIZE (2 * 1024 * 1024) 288 + #define MAX_MSG_SIZE (32 * 1024) 289 + 289 290 static void test_seqpacket_msg_bounds_client(const struct test_opts *opts) 290 291 { 292 + unsigned long curr_hash; 293 + int page_size; 294 + int msg_count; 291 295 int fd; 292 296 293 297 fd = vsock_seqpacket_connect(opts->peer_cid, 1234); ··· 300 296 exit(EXIT_FAILURE); 301 297 } 302 298 303 - /* Send several messages, one with MSG_EOR flag */ 304 - for (int i = 0; i < MESSAGES_CNT; i++) 305 - send_byte(fd, 1, (i == MSG_EOR_IDX) ? MSG_EOR : 0); 299 + /* Wait, until receiver sets buffer size. */ 300 + control_expectln("SRVREADY"); 301 + 302 + curr_hash = 0; 303 + page_size = getpagesize(); 304 + msg_count = SOCK_BUF_SIZE / MAX_MSG_SIZE; 305 + 306 + for (int i = 0; i < msg_count; i++) { 307 + ssize_t send_size; 308 + size_t buf_size; 309 + int flags; 310 + void *buf; 311 + 312 + /* Use "small" buffers and "big" buffers. */ 313 + if (i & 1) 314 + buf_size = page_size + 315 + (rand() % (MAX_MSG_SIZE - page_size)); 316 + else 317 + buf_size = 1 + (rand() % page_size); 318 + 319 + buf = malloc(buf_size); 320 + 321 + if (!buf) { 322 + perror("malloc"); 323 + exit(EXIT_FAILURE); 324 + } 325 + 326 + memset(buf, rand() & 0xff, buf_size); 327 + /* Set at least one MSG_EOR + some random. */ 328 + if (i == (msg_count / 2) || (rand() & 1)) { 329 + flags = MSG_EOR; 330 + curr_hash++; 331 + } else { 332 + flags = 0; 333 + } 334 + 335 + send_size = send(fd, buf, buf_size, flags); 336 + 337 + if (send_size < 0) { 338 + perror("send"); 339 + exit(EXIT_FAILURE); 340 + } 341 + 342 + if (send_size != buf_size) { 343 + fprintf(stderr, "Invalid send size\n"); 344 + exit(EXIT_FAILURE); 345 + } 346 + 347 + /* 348 + * Hash sum is computed at both client and server in 349 + * the same way: 350 + * H += hash('message data') 351 + * Such hash "controls" both data integrity and message 352 + * bounds. After data exchange, both sums are compared 353 + * using control socket, and if message bounds wasn't 354 + * broken - two values must be equal. 355 + */ 356 + curr_hash += hash_djb2(buf, buf_size); 357 + free(buf); 358 + } 306 359 307 360 control_writeln("SENDDONE"); 361 + control_writeulong(curr_hash); 308 362 close(fd); 309 363 } 310 364 311 365 static void test_seqpacket_msg_bounds_server(const struct test_opts *opts) 312 366 { 367 + unsigned long sock_buf_size; 368 + unsigned long remote_hash; 369 + unsigned long curr_hash; 313 370 int fd; 314 - char buf[16]; 371 + char buf[MAX_MSG_SIZE]; 315 372 struct msghdr msg = {0}; 316 373 struct iovec iov = {0}; 317 374 ··· 382 317 exit(EXIT_FAILURE); 383 318 } 384 319 320 + sock_buf_size = SOCK_BUF_SIZE; 321 + 322 + if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE, 323 + &sock_buf_size, sizeof(sock_buf_size))) { 324 + perror("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)"); 325 + exit(EXIT_FAILURE); 326 + } 327 + 328 + if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE, 329 + &sock_buf_size, sizeof(sock_buf_size))) { 330 + perror("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)"); 331 + exit(EXIT_FAILURE); 332 + } 333 + 334 + /* Ready to receive data. */ 335 + control_writeln("SRVREADY"); 336 + /* Wait, until peer sends whole data. */ 385 337 control_expectln("SENDDONE"); 386 338 iov.iov_base = buf; 387 339 iov.iov_len = sizeof(buf); 388 340 msg.msg_iov = &iov; 389 341 msg.msg_iovlen = 1; 390 342 391 - for (int i = 0; i < MESSAGES_CNT; i++) { 392 - if (recvmsg(fd, &msg, 0) != 1) { 393 - perror("message bound violated"); 343 + curr_hash = 0; 344 + 345 + while (1) { 346 + ssize_t recv_size; 347 + 348 + recv_size = recvmsg(fd, &msg, 0); 349 + 350 + if (!recv_size) 351 + break; 352 + 353 + if (recv_size < 0) { 354 + perror("recvmsg"); 394 355 exit(EXIT_FAILURE); 395 356 } 396 357 397 - if ((i == MSG_EOR_IDX) ^ !!(msg.msg_flags & MSG_EOR)) { 398 - perror("MSG_EOR"); 399 - exit(EXIT_FAILURE); 400 - } 358 + if (msg.msg_flags & MSG_EOR) 359 + curr_hash++; 360 + 361 + curr_hash += hash_djb2(msg.msg_iov[0].iov_base, recv_size); 401 362 } 402 363 403 364 close(fd); 365 + remote_hash = control_readulong(); 366 + 367 + if (curr_hash != remote_hash) { 368 + fprintf(stderr, "Message bounds broken\n"); 369 + exit(EXIT_FAILURE); 370 + } 404 371 } 405 372 406 373 #define MESSAGE_TRUNC_SZ 32 ··· 524 427 tv.tv_usec = 0; 525 428 526 429 if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) == -1) { 527 - perror("setsockopt 'SO_RCVTIMEO'"); 430 + perror("setsockopt(SO_RCVTIMEO)"); 528 431 exit(EXIT_FAILURE); 529 432 } 530 433 ··· 741 644 742 645 if (setsockopt(fd, SOL_SOCKET, SO_RCVLOWAT, 743 646 &lowat_val, sizeof(lowat_val))) { 744 - perror("setsockopt"); 647 + perror("setsockopt(SO_RCVLOWAT)"); 745 648 exit(EXIT_FAILURE); 746 649 } 747 650 ··· 934 837 .peer_cid = VMADDR_CID_ANY, 935 838 }; 936 839 840 + srand(time(NULL)); 937 841 init_signals(); 938 842 939 843 for (;;) {