1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * vsock test utilities 4 * 5 * Copyright (C) 2017 Red Hat, Inc. 6 * 7 * Author: Stefan Hajnoczi <stefanha@redhat.com> 8 */ 9 10 #include <ctype.h> 11 #include <errno.h> 12 #include <stdio.h> 13 #include <stdint.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <signal.h> 17 #include <unistd.h> 18 #include <assert.h> 19 #include <sys/epoll.h> 20 #include <sys/mman.h> 21 #include <linux/sockios.h> 22 23 #include "timeout.h" 24 #include "control.h" 25 #include "util.h" 26 27 #define KALLSYMS_PATH "/proc/kallsyms" 28 #define KALLSYMS_LINE_LEN 512 29 30 /* Install signal handlers */ 31 void init_signals(void) 32 { 33 struct sigaction act = { 34 .sa_handler = sigalrm, 35 }; 36 37 sigaction(SIGALRM, &act, NULL); 38 signal(SIGPIPE, SIG_IGN); 39 } 40 41 static unsigned int parse_uint(const char *str, const char *err_str) 42 { 43 char *endptr = NULL; 44 unsigned long n; 45 46 errno = 0; 47 n = strtoul(str, &endptr, 10); 48 if (errno || *endptr != '\0') { 49 fprintf(stderr, "malformed %s \"%s\"\n", err_str, str); 50 exit(EXIT_FAILURE); 51 } 52 return n; 53 } 54 55 /* Parse a CID in string representation */ 56 unsigned int parse_cid(const char *str) 57 { 58 return parse_uint(str, "CID"); 59 } 60 61 /* Parse a port in string representation */ 62 unsigned int parse_port(const char *str) 63 { 64 return parse_uint(str, "port"); 65 } 66 67 /* Wait for the remote to close the connection */ 68 void vsock_wait_remote_close(int fd) 69 { 70 struct epoll_event ev; 71 int epollfd, nfds; 72 73 epollfd = epoll_create1(0); 74 if (epollfd == -1) { 75 perror("epoll_create1"); 76 exit(EXIT_FAILURE); 77 } 78 79 ev.events = EPOLLRDHUP | EPOLLHUP; 80 ev.data.fd = fd; 81 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { 82 perror("epoll_ctl"); 83 exit(EXIT_FAILURE); 84 } 85 86 nfds = epoll_wait(epollfd, &ev, 1, TIMEOUT * 1000); 87 if (nfds == -1) { 88 perror("epoll_wait"); 89 exit(EXIT_FAILURE); 90 } 91 92 if (nfds == 0) { 93 fprintf(stderr, "epoll_wait timed out\n"); 94 exit(EXIT_FAILURE); 95 } 96 97 assert(nfds == 1); 98 assert(ev.events & (EPOLLRDHUP | EPOLLHUP)); 99 assert(ev.data.fd == fd); 100 101 close(epollfd); 102 } 103 104 /* Wait until transport reports no data left to be sent. 105 * Return false if transport does not implement the unsent_bytes() callback. 106 */ 107 bool vsock_wait_sent(int fd) 108 { 109 int ret, sock_bytes_unsent; 110 111 timeout_begin(TIMEOUT); 112 do { 113 ret = ioctl(fd, SIOCOUTQ, &sock_bytes_unsent); 114 if (ret < 0) { 115 if (errno == EOPNOTSUPP) 116 break; 117 118 perror("ioctl(SIOCOUTQ)"); 119 exit(EXIT_FAILURE); 120 } 121 timeout_check("SIOCOUTQ"); 122 } while (sock_bytes_unsent != 0); 123 timeout_end(); 124 125 return !ret; 126 } 127 128 /* Create socket <type>, bind to <cid, port>. 129 * Return the file descriptor, or -1 on error. 130 */ 131 int vsock_bind_try(unsigned int cid, unsigned int port, int type) 132 { 133 struct sockaddr_vm sa = { 134 .svm_family = AF_VSOCK, 135 .svm_cid = cid, 136 .svm_port = port, 137 }; 138 int fd, saved_errno; 139 140 fd = socket(AF_VSOCK, type, 0); 141 if (fd < 0) { 142 perror("socket"); 143 exit(EXIT_FAILURE); 144 } 145 146 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa))) { 147 saved_errno = errno; 148 close(fd); 149 errno = saved_errno; 150 fd = -1; 151 } 152 153 return fd; 154 } 155 156 /* Create socket <type>, bind to <cid, port> and return the file descriptor. */ 157 int vsock_bind(unsigned int cid, unsigned int port, int type) 158 { 159 int fd; 160 161 fd = vsock_bind_try(cid, port, type); 162 if (fd < 0) { 163 perror("bind"); 164 exit(EXIT_FAILURE); 165 } 166 167 return fd; 168 } 169 170 int vsock_connect_fd(int fd, unsigned int cid, unsigned int port) 171 { 172 struct sockaddr_vm sa = { 173 .svm_family = AF_VSOCK, 174 .svm_cid = cid, 175 .svm_port = port, 176 }; 177 int ret; 178 179 timeout_begin(TIMEOUT); 180 do { 181 ret = connect(fd, (struct sockaddr *)&sa, sizeof(sa)); 182 timeout_check("connect"); 183 } while (ret < 0 && errno == EINTR); 184 timeout_end(); 185 186 return ret; 187 } 188 189 /* Bind to <bind_port>, connect to <cid, port> and return the file descriptor. */ 190 int vsock_bind_connect(unsigned int cid, unsigned int port, unsigned int bind_port, int type) 191 { 192 int client_fd; 193 194 client_fd = vsock_bind(VMADDR_CID_ANY, bind_port, type); 195 196 if (vsock_connect_fd(client_fd, cid, port)) { 197 perror("connect"); 198 exit(EXIT_FAILURE); 199 } 200 201 return client_fd; 202 } 203 204 /* Connect to <cid, port> and return the file descriptor. */ 205 int vsock_connect(unsigned int cid, unsigned int port, int type) 206 { 207 int fd; 208 209 control_expectln("LISTENING"); 210 211 fd = socket(AF_VSOCK, type, 0); 212 if (fd < 0) { 213 perror("socket"); 214 exit(EXIT_FAILURE); 215 } 216 217 if (vsock_connect_fd(fd, cid, port)) { 218 int old_errno = errno; 219 220 close(fd); 221 fd = -1; 222 errno = old_errno; 223 } 224 225 return fd; 226 } 227 228 int vsock_stream_connect(unsigned int cid, unsigned int port) 229 { 230 return vsock_connect(cid, port, SOCK_STREAM); 231 } 232 233 int vsock_seqpacket_connect(unsigned int cid, unsigned int port) 234 { 235 return vsock_connect(cid, port, SOCK_SEQPACKET); 236 } 237 238 /* Listen on <cid, port> and return the file descriptor. */ 239 static int vsock_listen(unsigned int cid, unsigned int port, int type) 240 { 241 int fd; 242 243 fd = vsock_bind(cid, port, type); 244 245 if (listen(fd, 1) < 0) { 246 perror("listen"); 247 exit(EXIT_FAILURE); 248 } 249 250 return fd; 251 } 252 253 /* Listen on <cid, port> and return the first incoming connection. The remote 254 * address is stored to clientaddrp. clientaddrp may be NULL. 255 */ 256 int vsock_accept(unsigned int cid, unsigned int port, 257 struct sockaddr_vm *clientaddrp, int type) 258 { 259 union { 260 struct sockaddr sa; 261 struct sockaddr_vm svm; 262 } clientaddr; 263 socklen_t clientaddr_len = sizeof(clientaddr.svm); 264 int fd, client_fd, old_errno; 265 266 fd = vsock_listen(cid, port, type); 267 268 control_writeln("LISTENING"); 269 270 timeout_begin(TIMEOUT); 271 do { 272 client_fd = accept(fd, &clientaddr.sa, &clientaddr_len); 273 timeout_check("accept"); 274 } while (client_fd < 0 && errno == EINTR); 275 timeout_end(); 276 277 old_errno = errno; 278 close(fd); 279 errno = old_errno; 280 281 if (client_fd < 0) 282 return client_fd; 283 284 if (clientaddr_len != sizeof(clientaddr.svm)) { 285 fprintf(stderr, "unexpected addrlen from accept(2), %zu\n", 286 (size_t)clientaddr_len); 287 exit(EXIT_FAILURE); 288 } 289 if (clientaddr.sa.sa_family != AF_VSOCK) { 290 fprintf(stderr, "expected AF_VSOCK from accept(2), got %d\n", 291 clientaddr.sa.sa_family); 292 exit(EXIT_FAILURE); 293 } 294 295 if (clientaddrp) 296 *clientaddrp = clientaddr.svm; 297 return client_fd; 298 } 299 300 int vsock_stream_accept(unsigned int cid, unsigned int port, 301 struct sockaddr_vm *clientaddrp) 302 { 303 return vsock_accept(cid, port, clientaddrp, SOCK_STREAM); 304 } 305 306 int vsock_stream_listen(unsigned int cid, unsigned int port) 307 { 308 return vsock_listen(cid, port, SOCK_STREAM); 309 } 310 311 int vsock_seqpacket_accept(unsigned int cid, unsigned int port, 312 struct sockaddr_vm *clientaddrp) 313 { 314 return vsock_accept(cid, port, clientaddrp, SOCK_SEQPACKET); 315 } 316 317 /* Transmit bytes from a buffer and check the return value. 318 * 319 * expected_ret: 320 * <0 Negative errno (for testing errors) 321 * 0 End-of-file 322 * >0 Success (bytes successfully written) 323 */ 324 void send_buf(int fd, const void *buf, size_t len, int flags, 325 ssize_t expected_ret) 326 { 327 ssize_t nwritten = 0; 328 ssize_t ret; 329 330 timeout_begin(TIMEOUT); 331 do { 332 ret = send(fd, buf + nwritten, len - nwritten, flags); 333 timeout_check("send"); 334 335 if (ret == 0 || (ret < 0 && errno != EINTR)) 336 break; 337 338 nwritten += ret; 339 } while (nwritten < len); 340 timeout_end(); 341 342 if (expected_ret < 0) { 343 if (ret != -1) { 344 fprintf(stderr, "bogus send(2) return value %zd (expected %zd)\n", 345 ret, expected_ret); 346 exit(EXIT_FAILURE); 347 } 348 if (errno != -expected_ret) { 349 perror("send"); 350 exit(EXIT_FAILURE); 351 } 352 return; 353 } 354 355 if (ret < 0) { 356 perror("send"); 357 exit(EXIT_FAILURE); 358 } 359 360 if (nwritten != expected_ret) { 361 if (ret == 0) 362 fprintf(stderr, "unexpected EOF while sending bytes\n"); 363 364 fprintf(stderr, "bogus send(2) bytes written %zd (expected %zd)\n", 365 nwritten, expected_ret); 366 exit(EXIT_FAILURE); 367 } 368 } 369 370 /* Receive bytes in a buffer and check the return value. 371 * 372 * expected_ret: 373 * <0 Negative errno (for testing errors) 374 * 0 End-of-file 375 * >0 Success (bytes successfully read) 376 */ 377 void recv_buf(int fd, void *buf, size_t len, int flags, ssize_t expected_ret) 378 { 379 ssize_t nread = 0; 380 ssize_t ret; 381 382 timeout_begin(TIMEOUT); 383 do { 384 ret = recv(fd, buf + nread, len - nread, flags); 385 timeout_check("recv"); 386 387 if (ret == 0 || (ret < 0 && errno != EINTR)) 388 break; 389 390 nread += ret; 391 } while (nread < len); 392 timeout_end(); 393 394 if (expected_ret < 0) { 395 if (ret != -1) { 396 fprintf(stderr, "bogus recv(2) return value %zd (expected %zd)\n", 397 ret, expected_ret); 398 exit(EXIT_FAILURE); 399 } 400 if (errno != -expected_ret) { 401 perror("recv"); 402 exit(EXIT_FAILURE); 403 } 404 return; 405 } 406 407 if (ret < 0) { 408 perror("recv"); 409 exit(EXIT_FAILURE); 410 } 411 412 if (nread != expected_ret) { 413 if (ret == 0) 414 fprintf(stderr, "unexpected EOF while receiving bytes\n"); 415 416 fprintf(stderr, "bogus recv(2) bytes read %zd (expected %zd)\n", 417 nread, expected_ret); 418 exit(EXIT_FAILURE); 419 } 420 } 421 422 /* Transmit one byte and check the return value. 423 * 424 * expected_ret: 425 * <0 Negative errno (for testing errors) 426 * 0 End-of-file 427 * 1 Success 428 */ 429 void send_byte(int fd, int expected_ret, int flags) 430 { 431 static const uint8_t byte = 'A'; 432 433 send_buf(fd, &byte, sizeof(byte), flags, expected_ret); 434 } 435 436 /* Receive one byte and check the return value. 437 * 438 * expected_ret: 439 * <0 Negative errno (for testing errors) 440 * 0 End-of-file 441 * 1 Success 442 */ 443 void recv_byte(int fd, int expected_ret, int flags) 444 { 445 uint8_t byte; 446 447 recv_buf(fd, &byte, sizeof(byte), flags, expected_ret); 448 449 if (byte != 'A') { 450 fprintf(stderr, "unexpected byte read 0x%02x\n", byte); 451 exit(EXIT_FAILURE); 452 } 453 } 454 455 /* Run test cases. The program terminates if a failure occurs. */ 456 void run_tests(const struct test_case *test_cases, 457 const struct test_opts *opts) 458 { 459 int i; 460 461 for (i = 0; test_cases[i].name; i++) { 462 void (*run)(const struct test_opts *opts); 463 char *line; 464 465 printf("%d - %s...", i, test_cases[i].name); 466 fflush(stdout); 467 468 /* Full barrier before executing the next test. This 469 * ensures that client and server are executing the 470 * same test case. In particular, it means whoever is 471 * faster will not see the peer still executing the 472 * last test. This is important because port numbers 473 * can be used by multiple test cases. 474 */ 475 if (test_cases[i].skip) 476 control_writeln("SKIP"); 477 else 478 control_writeln("NEXT"); 479 480 line = control_readln(); 481 if (control_cmpln(line, "SKIP", false) || test_cases[i].skip) { 482 483 printf("skipped\n"); 484 485 free(line); 486 continue; 487 } 488 489 control_cmpln(line, "NEXT", true); 490 free(line); 491 492 if (opts->mode == TEST_MODE_CLIENT) 493 run = test_cases[i].run_client; 494 else 495 run = test_cases[i].run_server; 496 497 if (run) 498 run(opts); 499 500 printf("ok\n"); 501 } 502 } 503 504 void list_tests(const struct test_case *test_cases) 505 { 506 int i; 507 508 printf("ID\tTest name\n"); 509 510 for (i = 0; test_cases[i].name; i++) 511 printf("%d\t%s\n", i, test_cases[i].name); 512 513 exit(EXIT_FAILURE); 514 } 515 516 static unsigned long parse_test_id(const char *test_id_str, size_t test_cases_len) 517 { 518 unsigned long test_id; 519 char *endptr = NULL; 520 521 errno = 0; 522 test_id = strtoul(test_id_str, &endptr, 10); 523 if (errno || *endptr != '\0') { 524 fprintf(stderr, "malformed test ID \"%s\"\n", test_id_str); 525 exit(EXIT_FAILURE); 526 } 527 528 if (test_id >= test_cases_len) { 529 fprintf(stderr, "test ID (%lu) larger than the max allowed (%lu)\n", 530 test_id, test_cases_len - 1); 531 exit(EXIT_FAILURE); 532 } 533 534 return test_id; 535 } 536 537 void skip_test(struct test_case *test_cases, size_t test_cases_len, 538 const char *test_id_str) 539 { 540 unsigned long test_id = parse_test_id(test_id_str, test_cases_len); 541 test_cases[test_id].skip = true; 542 } 543 544 void pick_test(struct test_case *test_cases, size_t test_cases_len, 545 const char *test_id_str) 546 { 547 static bool skip_all = true; 548 unsigned long test_id; 549 550 if (skip_all) { 551 unsigned long i; 552 553 for (i = 0; i < test_cases_len; ++i) 554 test_cases[i].skip = true; 555 556 skip_all = false; 557 } 558 559 test_id = parse_test_id(test_id_str, test_cases_len); 560 test_cases[test_id].skip = false; 561 } 562 563 unsigned long hash_djb2(const void *data, size_t len) 564 { 565 unsigned long hash = 5381; 566 int i = 0; 567 568 while (i < len) { 569 hash = ((hash << 5) + hash) + ((unsigned char *)data)[i]; 570 i++; 571 } 572 573 return hash; 574 } 575 576 size_t iovec_bytes(const struct iovec *iov, size_t iovnum) 577 { 578 size_t bytes; 579 int i; 580 581 for (bytes = 0, i = 0; i < iovnum; i++) 582 bytes += iov[i].iov_len; 583 584 return bytes; 585 } 586 587 unsigned long iovec_hash_djb2(const struct iovec *iov, size_t iovnum) 588 { 589 unsigned long hash; 590 size_t iov_bytes; 591 size_t offs; 592 void *tmp; 593 int i; 594 595 iov_bytes = iovec_bytes(iov, iovnum); 596 597 tmp = malloc(iov_bytes); 598 if (!tmp) { 599 perror("malloc"); 600 exit(EXIT_FAILURE); 601 } 602 603 for (offs = 0, i = 0; i < iovnum; i++) { 604 memcpy(tmp + offs, iov[i].iov_base, iov[i].iov_len); 605 offs += iov[i].iov_len; 606 } 607 608 hash = hash_djb2(tmp, iov_bytes); 609 free(tmp); 610 611 return hash; 612 } 613 614 /* Allocates and returns new 'struct iovec *' according pattern 615 * in the 'test_iovec'. For each element in the 'test_iovec' it 616 * allocates new element in the resulting 'iovec'. 'iov_len' 617 * of the new element is copied from 'test_iovec'. 'iov_base' is 618 * allocated depending on the 'iov_base' of 'test_iovec': 619 * 620 * 'iov_base' == NULL -> valid buf: mmap('iov_len'). 621 * 622 * 'iov_base' == MAP_FAILED -> invalid buf: 623 * mmap('iov_len'), then munmap('iov_len'). 624 * 'iov_base' still contains result of 625 * mmap(). 626 * 627 * 'iov_base' == number -> unaligned valid buf: 628 * mmap('iov_len') + number. 629 * 630 * 'iovnum' is number of elements in 'test_iovec'. 631 * 632 * Returns new 'iovec' or calls 'exit()' on error. 633 */ 634 struct iovec *alloc_test_iovec(const struct iovec *test_iovec, int iovnum) 635 { 636 struct iovec *iovec; 637 int i; 638 639 iovec = malloc(sizeof(*iovec) * iovnum); 640 if (!iovec) { 641 perror("malloc"); 642 exit(EXIT_FAILURE); 643 } 644 645 for (i = 0; i < iovnum; i++) { 646 iovec[i].iov_len = test_iovec[i].iov_len; 647 648 iovec[i].iov_base = mmap(NULL, iovec[i].iov_len, 649 PROT_READ | PROT_WRITE, 650 MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, 651 -1, 0); 652 if (iovec[i].iov_base == MAP_FAILED) { 653 perror("mmap"); 654 exit(EXIT_FAILURE); 655 } 656 657 if (test_iovec[i].iov_base != MAP_FAILED) 658 iovec[i].iov_base += (uintptr_t)test_iovec[i].iov_base; 659 } 660 661 /* Unmap "invalid" elements. */ 662 for (i = 0; i < iovnum; i++) { 663 if (test_iovec[i].iov_base == MAP_FAILED) { 664 if (munmap(iovec[i].iov_base, iovec[i].iov_len)) { 665 perror("munmap"); 666 exit(EXIT_FAILURE); 667 } 668 } 669 } 670 671 for (i = 0; i < iovnum; i++) { 672 int j; 673 674 if (test_iovec[i].iov_base == MAP_FAILED) 675 continue; 676 677 for (j = 0; j < iovec[i].iov_len; j++) 678 ((uint8_t *)iovec[i].iov_base)[j] = rand() & 0xff; 679 } 680 681 return iovec; 682 } 683 684 /* Frees 'iovec *', previously allocated by 'alloc_test_iovec()'. 685 * On error calls 'exit()'. 686 */ 687 void free_test_iovec(const struct iovec *test_iovec, 688 struct iovec *iovec, int iovnum) 689 { 690 int i; 691 692 for (i = 0; i < iovnum; i++) { 693 if (test_iovec[i].iov_base != MAP_FAILED) { 694 if (test_iovec[i].iov_base) 695 iovec[i].iov_base -= (uintptr_t)test_iovec[i].iov_base; 696 697 if (munmap(iovec[i].iov_base, iovec[i].iov_len)) { 698 perror("munmap"); 699 exit(EXIT_FAILURE); 700 } 701 } 702 } 703 704 free(iovec); 705 } 706 707 /* Set "unsigned long long" socket option and check that it's indeed set */ 708 void setsockopt_ull_check(int fd, int level, int optname, 709 unsigned long long val, char const *errmsg) 710 { 711 unsigned long long chkval; 712 socklen_t chklen; 713 int err; 714 715 err = setsockopt(fd, level, optname, &val, sizeof(val)); 716 if (err) { 717 fprintf(stderr, "setsockopt err: %s (%d)\n", 718 strerror(errno), errno); 719 goto fail; 720 } 721 722 chkval = ~val; /* just make storage != val */ 723 chklen = sizeof(chkval); 724 725 err = getsockopt(fd, level, optname, &chkval, &chklen); 726 if (err) { 727 fprintf(stderr, "getsockopt err: %s (%d)\n", 728 strerror(errno), errno); 729 goto fail; 730 } 731 732 if (chklen != sizeof(chkval)) { 733 fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val), 734 chklen); 735 goto fail; 736 } 737 738 if (chkval != val) { 739 fprintf(stderr, "value mismatch: set %llu got %llu\n", val, 740 chkval); 741 goto fail; 742 } 743 return; 744 fail: 745 fprintf(stderr, "%s val %llu\n", errmsg, val); 746 exit(EXIT_FAILURE); 747 ; 748 } 749 750 /* Set "int" socket option and check that it's indeed set */ 751 void setsockopt_int_check(int fd, int level, int optname, int val, 752 char const *errmsg) 753 { 754 int chkval; 755 socklen_t chklen; 756 int err; 757 758 err = setsockopt(fd, level, optname, &val, sizeof(val)); 759 if (err) { 760 fprintf(stderr, "setsockopt err: %s (%d)\n", 761 strerror(errno), errno); 762 goto fail; 763 } 764 765 chkval = ~val; /* just make storage != val */ 766 chklen = sizeof(chkval); 767 768 err = getsockopt(fd, level, optname, &chkval, &chklen); 769 if (err) { 770 fprintf(stderr, "getsockopt err: %s (%d)\n", 771 strerror(errno), errno); 772 goto fail; 773 } 774 775 if (chklen != sizeof(chkval)) { 776 fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val), 777 chklen); 778 goto fail; 779 } 780 781 if (chkval != val) { 782 fprintf(stderr, "value mismatch: set %d got %d\n", val, chkval); 783 goto fail; 784 } 785 return; 786 fail: 787 fprintf(stderr, "%s val %d\n", errmsg, val); 788 exit(EXIT_FAILURE); 789 } 790 791 static void mem_invert(unsigned char *mem, size_t size) 792 { 793 size_t i; 794 795 for (i = 0; i < size; i++) 796 mem[i] = ~mem[i]; 797 } 798 799 /* Set "timeval" socket option and check that it's indeed set */ 800 void setsockopt_timeval_check(int fd, int level, int optname, 801 struct timeval val, char const *errmsg) 802 { 803 struct timeval chkval; 804 socklen_t chklen; 805 int err; 806 807 err = setsockopt(fd, level, optname, &val, sizeof(val)); 808 if (err) { 809 fprintf(stderr, "setsockopt err: %s (%d)\n", 810 strerror(errno), errno); 811 goto fail; 812 } 813 814 /* just make storage != val */ 815 chkval = val; 816 mem_invert((unsigned char *)&chkval, sizeof(chkval)); 817 chklen = sizeof(chkval); 818 819 err = getsockopt(fd, level, optname, &chkval, &chklen); 820 if (err) { 821 fprintf(stderr, "getsockopt err: %s (%d)\n", 822 strerror(errno), errno); 823 goto fail; 824 } 825 826 if (chklen != sizeof(chkval)) { 827 fprintf(stderr, "size mismatch: set %zu got %d\n", sizeof(val), 828 chklen); 829 goto fail; 830 } 831 832 if (memcmp(&chkval, &val, sizeof(val)) != 0) { 833 fprintf(stderr, "value mismatch: set %ld:%ld got %ld:%ld\n", 834 val.tv_sec, val.tv_usec, chkval.tv_sec, chkval.tv_usec); 835 goto fail; 836 } 837 return; 838 fail: 839 fprintf(stderr, "%s val %ld:%ld\n", errmsg, val.tv_sec, val.tv_usec); 840 exit(EXIT_FAILURE); 841 } 842 843 void enable_so_zerocopy_check(int fd) 844 { 845 setsockopt_int_check(fd, SOL_SOCKET, SO_ZEROCOPY, 1, 846 "setsockopt SO_ZEROCOPY"); 847 } 848 849 void enable_so_linger(int fd, int timeout) 850 { 851 struct linger optval = { 852 .l_onoff = 1, 853 .l_linger = timeout 854 }; 855 856 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &optval, sizeof(optval))) { 857 perror("setsockopt(SO_LINGER)"); 858 exit(EXIT_FAILURE); 859 } 860 } 861 862 static int __get_transports(void) 863 { 864 char buf[KALLSYMS_LINE_LEN]; 865 const char *ksym; 866 int ret = 0; 867 FILE *f; 868 869 f = fopen(KALLSYMS_PATH, "r"); 870 if (!f) { 871 perror("Can't open " KALLSYMS_PATH); 872 exit(EXIT_FAILURE); 873 } 874 875 while (fgets(buf, sizeof(buf), f)) { 876 char *match; 877 int i; 878 879 assert(buf[strlen(buf) - 1] == '\n'); 880 881 for (i = 0; i < TRANSPORT_NUM; ++i) { 882 if (ret & BIT(i)) 883 continue; 884 885 /* Match should be followed by '\t' or '\n'. 886 * See kallsyms.c:s_show(). 887 */ 888 ksym = transport_ksyms[i]; 889 match = strstr(buf, ksym); 890 if (match && isspace(match[strlen(ksym)])) { 891 ret |= BIT(i); 892 break; 893 } 894 } 895 } 896 897 fclose(f); 898 return ret; 899 } 900 901 /* Return integer with TRANSPORT_* bit set for every (known) registered vsock 902 * transport. 903 */ 904 int get_transports(void) 905 { 906 static int tr = -1; 907 908 if (tr == -1) 909 tr = __get_transports(); 910 911 return tr; 912 } 913