1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2014 Google Inc. 4 * Author: willemb@google.com (Willem de Bruijn) 5 * 6 * Test software tx timestamping, including 7 * 8 * - SCHED, SND and ACK timestamps 9 * - RAW, UDP and TCP 10 * - IPv4 and IPv6 11 * - various packet sizes (to test GSO and TSO) 12 * 13 * Consult the command line arguments for help on running 14 * the various testcases. 15 * 16 * This test requires a dummy TCP server. 17 * A simple `nc6 [-u] -l -p $DESTPORT` will do 18 */ 19 20 #define _GNU_SOURCE 21 22 #include <arpa/inet.h> 23 #include <asm/types.h> 24 #include <error.h> 25 #include <errno.h> 26 #include <inttypes.h> 27 #include <linux/errqueue.h> 28 #include <linux/if_ether.h> 29 #include <linux/if_packet.h> 30 #include <linux/ipv6.h> 31 #include <linux/net_tstamp.h> 32 #include <netdb.h> 33 #include <net/if.h> 34 #include <netinet/in.h> 35 #include <netinet/ip.h> 36 #include <netinet/udp.h> 37 #include <netinet/tcp.h> 38 #include <poll.h> 39 #include <stdarg.h> 40 #include <stdbool.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <sys/epoll.h> 45 #include <sys/ioctl.h> 46 #include <sys/select.h> 47 #include <sys/socket.h> 48 #include <sys/time.h> 49 #include <sys/types.h> 50 #include <time.h> 51 #include <unistd.h> 52 53 #define NSEC_PER_USEC 1000L 54 #define USEC_PER_SEC 1000000L 55 #define NSEC_PER_SEC 1000000000LL 56 57 /* command line parameters */ 58 static int cfg_proto = SOCK_STREAM; 59 static int cfg_ipproto = IPPROTO_TCP; 60 static int cfg_num_pkts = 4; 61 static int do_ipv4 = 1; 62 static int do_ipv6 = 1; 63 static int cfg_payload_len = 10; 64 static int cfg_poll_timeout = 100; 65 static int cfg_delay_snd; 66 static int cfg_delay_ack; 67 static int cfg_delay_tolerance_usec = 500; 68 static bool cfg_show_payload; 69 static bool cfg_do_pktinfo; 70 static bool cfg_busy_poll; 71 static int cfg_sleep_usec = 50 * 1000; 72 static bool cfg_loop_nodata; 73 static bool cfg_use_cmsg; 74 static bool cfg_use_pf_packet; 75 static bool cfg_use_epoll; 76 static bool cfg_epollet; 77 static bool cfg_do_listen; 78 static uint16_t dest_port = 9000; 79 static bool cfg_print_nsec; 80 81 static struct sockaddr_in daddr; 82 static struct sockaddr_in6 daddr6; 83 static struct timespec ts_usr; 84 85 static int saved_tskey = -1; 86 static int saved_tskey_type = -1; 87 88 struct timing_event { 89 int64_t min; 90 int64_t max; 91 int64_t total; 92 int count; 93 }; 94 95 static struct timing_event usr_enq; 96 static struct timing_event usr_snd; 97 static struct timing_event usr_ack; 98 99 static bool test_failed; 100 101 static int64_t timespec_to_ns64(struct timespec *ts) 102 { 103 return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec; 104 } 105 106 static int64_t timespec_to_us64(struct timespec *ts) 107 { 108 return ts->tv_sec * USEC_PER_SEC + ts->tv_nsec / NSEC_PER_USEC; 109 } 110 111 static void init_timing_event(struct timing_event *te) 112 { 113 te->min = INT64_MAX; 114 te->max = 0; 115 te->total = 0; 116 te->count = 0; 117 } 118 119 static void add_timing_event(struct timing_event *te, 120 struct timespec *t_start, struct timespec *t_end) 121 { 122 int64_t ts_delta = timespec_to_ns64(t_end) - timespec_to_ns64(t_start); 123 124 te->count++; 125 if (ts_delta < te->min) 126 te->min = ts_delta; 127 if (ts_delta > te->max) 128 te->max = ts_delta; 129 te->total += ts_delta; 130 } 131 132 static void validate_key(int tskey, int tstype) 133 { 134 int stepsize; 135 136 /* compare key for each subsequent request 137 * must only test for one type, the first one requested 138 */ 139 if (saved_tskey == -1) 140 saved_tskey_type = tstype; 141 else if (saved_tskey_type != tstype) 142 return; 143 144 stepsize = cfg_proto == SOCK_STREAM ? cfg_payload_len : 1; 145 if (tskey != saved_tskey + stepsize) { 146 fprintf(stderr, "ERROR: key %d, expected %d\n", 147 tskey, saved_tskey + stepsize); 148 test_failed = true; 149 } 150 151 saved_tskey = tskey; 152 } 153 154 static void validate_timestamp(struct timespec *cur, int min_delay) 155 { 156 int64_t cur64, start64; 157 int max_delay; 158 159 cur64 = timespec_to_us64(cur); 160 start64 = timespec_to_us64(&ts_usr); 161 max_delay = min_delay + cfg_delay_tolerance_usec; 162 163 if (cur64 < start64 + min_delay || cur64 > start64 + max_delay) { 164 fprintf(stderr, "ERROR: %" PRId64 " us expected between %d and %d\n", 165 cur64 - start64, min_delay, max_delay); 166 if (!getenv("KSFT_MACHINE_SLOW")) 167 test_failed = true; 168 } 169 } 170 171 static void __print_ts_delta_formatted(int64_t ts_delta) 172 { 173 if (cfg_print_nsec) 174 fprintf(stderr, "%" PRId64 " ns", ts_delta); 175 else 176 fprintf(stderr, "%" PRId64 " us", ts_delta / NSEC_PER_USEC); 177 } 178 179 static void __print_timestamp(const char *name, struct timespec *cur, 180 uint32_t key, int payload_len) 181 { 182 int64_t ts_delta; 183 184 if (!(cur->tv_sec | cur->tv_nsec)) 185 return; 186 187 if (cfg_print_nsec) 188 fprintf(stderr, " %s: %lu s %lu ns (seq=%u, len=%u)", 189 name, cur->tv_sec, cur->tv_nsec, 190 key, payload_len); 191 else 192 fprintf(stderr, " %s: %lu s %lu us (seq=%u, len=%u)", 193 name, cur->tv_sec, cur->tv_nsec / NSEC_PER_USEC, 194 key, payload_len); 195 196 if (cur != &ts_usr) { 197 ts_delta = timespec_to_ns64(cur) - timespec_to_ns64(&ts_usr); 198 fprintf(stderr, " (USR +"); 199 __print_ts_delta_formatted(ts_delta); 200 fprintf(stderr, ")"); 201 } 202 203 fprintf(stderr, "\n"); 204 } 205 206 static void print_timestamp_usr(void) 207 { 208 if (clock_gettime(CLOCK_REALTIME, &ts_usr)) 209 error(1, errno, "clock_gettime"); 210 211 __print_timestamp(" USR", &ts_usr, 0, 0); 212 } 213 214 static void print_timestamp(struct scm_timestamping *tss, int tstype, 215 int tskey, int payload_len) 216 { 217 const char *tsname; 218 219 validate_key(tskey, tstype); 220 221 switch (tstype) { 222 case SCM_TSTAMP_SCHED: 223 tsname = " ENQ"; 224 validate_timestamp(&tss->ts[0], 0); 225 add_timing_event(&usr_enq, &ts_usr, &tss->ts[0]); 226 break; 227 case SCM_TSTAMP_SND: 228 tsname = " SND"; 229 validate_timestamp(&tss->ts[0], cfg_delay_snd); 230 add_timing_event(&usr_snd, &ts_usr, &tss->ts[0]); 231 break; 232 case SCM_TSTAMP_ACK: 233 tsname = " ACK"; 234 validate_timestamp(&tss->ts[0], cfg_delay_ack); 235 add_timing_event(&usr_ack, &ts_usr, &tss->ts[0]); 236 break; 237 default: 238 error(1, 0, "unknown timestamp type: %u", 239 tstype); 240 } 241 __print_timestamp(tsname, &tss->ts[0], tskey, payload_len); 242 } 243 244 static void print_timing_event(char *name, struct timing_event *te) 245 { 246 if (!te->count) 247 return; 248 249 fprintf(stderr, " %s: count=%d", name, te->count); 250 fprintf(stderr, ", avg="); 251 __print_ts_delta_formatted((int64_t)(te->total / te->count)); 252 fprintf(stderr, ", min="); 253 __print_ts_delta_formatted(te->min); 254 fprintf(stderr, ", max="); 255 __print_ts_delta_formatted(te->max); 256 fprintf(stderr, "\n"); 257 } 258 259 /* TODO: convert to check_and_print payload once API is stable */ 260 static void print_payload(char *data, int len) 261 { 262 int i; 263 264 if (!len) 265 return; 266 267 if (len > 70) 268 len = 70; 269 270 fprintf(stderr, "payload: "); 271 for (i = 0; i < len; i++) 272 fprintf(stderr, "%02hhx ", data[i]); 273 fprintf(stderr, "\n"); 274 } 275 276 static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr) 277 { 278 char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN]; 279 280 fprintf(stderr, " pktinfo: ifindex=%u src=%s dst=%s\n", 281 ifindex, 282 saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown", 283 daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown"); 284 } 285 286 static void __epoll(int epfd) 287 { 288 struct epoll_event events; 289 int ret; 290 291 memset(&events, 0, sizeof(events)); 292 ret = epoll_wait(epfd, &events, 1, cfg_poll_timeout); 293 if (ret != 1) 294 error(1, errno, "epoll_wait"); 295 } 296 297 static void __poll(int fd) 298 { 299 struct pollfd pollfd; 300 int ret; 301 302 memset(&pollfd, 0, sizeof(pollfd)); 303 pollfd.fd = fd; 304 ret = poll(&pollfd, 1, cfg_poll_timeout); 305 if (ret != 1) 306 error(1, errno, "poll"); 307 } 308 309 static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len) 310 { 311 struct sock_extended_err *serr = NULL; 312 struct scm_timestamping *tss = NULL; 313 struct cmsghdr *cm; 314 int batch = 0; 315 316 for (cm = CMSG_FIRSTHDR(msg); 317 cm && cm->cmsg_len; 318 cm = CMSG_NXTHDR(msg, cm)) { 319 if (cm->cmsg_level == SOL_SOCKET && 320 cm->cmsg_type == SCM_TIMESTAMPING) { 321 tss = (void *) CMSG_DATA(cm); 322 } else if ((cm->cmsg_level == SOL_IP && 323 cm->cmsg_type == IP_RECVERR) || 324 (cm->cmsg_level == SOL_IPV6 && 325 cm->cmsg_type == IPV6_RECVERR) || 326 (cm->cmsg_level == SOL_PACKET && 327 cm->cmsg_type == PACKET_TX_TIMESTAMP)) { 328 serr = (void *) CMSG_DATA(cm); 329 if (serr->ee_errno != ENOMSG || 330 serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) { 331 fprintf(stderr, "unknown ip error %d %d\n", 332 serr->ee_errno, 333 serr->ee_origin); 334 serr = NULL; 335 } 336 } else if (cm->cmsg_level == SOL_IP && 337 cm->cmsg_type == IP_PKTINFO) { 338 struct in_pktinfo *info = (void *) CMSG_DATA(cm); 339 print_pktinfo(AF_INET, info->ipi_ifindex, 340 &info->ipi_spec_dst, &info->ipi_addr); 341 } else if (cm->cmsg_level == SOL_IPV6 && 342 cm->cmsg_type == IPV6_PKTINFO) { 343 struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm); 344 print_pktinfo(AF_INET6, info6->ipi6_ifindex, 345 NULL, &info6->ipi6_addr); 346 } else 347 fprintf(stderr, "unknown cmsg %d,%d\n", 348 cm->cmsg_level, cm->cmsg_type); 349 350 if (serr && tss) { 351 print_timestamp(tss, serr->ee_info, serr->ee_data, 352 payload_len); 353 serr = NULL; 354 tss = NULL; 355 batch++; 356 } 357 } 358 359 if (batch > 1) { 360 fprintf(stderr, "batched %d timestamps\n", batch); 361 } else if (!batch) { 362 fprintf(stderr, "Failed to report timestamps\n"); 363 test_failed = true; 364 } 365 } 366 367 static int recv_errmsg(int fd) 368 { 369 static char ctrl[1024 /* overprovision*/]; 370 static struct msghdr msg; 371 struct iovec entry; 372 static char *data; 373 int ret = 0; 374 375 data = malloc(cfg_payload_len); 376 if (!data) 377 error(1, 0, "malloc"); 378 379 memset(&msg, 0, sizeof(msg)); 380 memset(&entry, 0, sizeof(entry)); 381 memset(ctrl, 0, sizeof(ctrl)); 382 383 entry.iov_base = data; 384 entry.iov_len = cfg_payload_len; 385 msg.msg_iov = &entry; 386 msg.msg_iovlen = 1; 387 msg.msg_name = NULL; 388 msg.msg_namelen = 0; 389 msg.msg_control = ctrl; 390 msg.msg_controllen = sizeof(ctrl); 391 392 ret = recvmsg(fd, &msg, MSG_ERRQUEUE); 393 if (ret == -1 && errno != EAGAIN) 394 error(1, errno, "recvmsg"); 395 396 if (ret >= 0) { 397 __recv_errmsg_cmsg(&msg, ret); 398 if (cfg_show_payload) 399 print_payload(data, cfg_payload_len); 400 } 401 402 free(data); 403 return ret == -1; 404 } 405 406 static uint16_t get_ip_csum(const uint16_t *start, int num_words, 407 unsigned long sum) 408 { 409 int i; 410 411 for (i = 0; i < num_words; i++) 412 sum += start[i]; 413 414 while (sum >> 16) 415 sum = (sum & 0xFFFF) + (sum >> 16); 416 417 return ~sum; 418 } 419 420 static uint16_t get_udp_csum(const struct udphdr *udph, int alen) 421 { 422 unsigned long pseudo_sum, csum_len; 423 const void *csum_start = udph; 424 425 pseudo_sum = htons(IPPROTO_UDP); 426 pseudo_sum += udph->len; 427 428 /* checksum ip(v6) addresses + udp header + payload */ 429 csum_start -= alen * 2; 430 csum_len = ntohs(udph->len) + alen * 2; 431 432 return get_ip_csum(csum_start, csum_len >> 1, pseudo_sum); 433 } 434 435 static int fill_header_ipv4(void *p) 436 { 437 struct iphdr *iph = p; 438 439 memset(iph, 0, sizeof(*iph)); 440 441 iph->ihl = 5; 442 iph->version = 4; 443 iph->ttl = 2; 444 iph->saddr = daddr.sin_addr.s_addr; /* set for udp csum calc */ 445 iph->daddr = daddr.sin_addr.s_addr; 446 iph->protocol = IPPROTO_UDP; 447 448 /* kernel writes saddr, csum, len */ 449 450 return sizeof(*iph); 451 } 452 453 static int fill_header_ipv6(void *p) 454 { 455 struct ipv6hdr *ip6h = p; 456 457 memset(ip6h, 0, sizeof(*ip6h)); 458 459 ip6h->version = 6; 460 ip6h->payload_len = htons(sizeof(struct udphdr) + cfg_payload_len); 461 ip6h->nexthdr = IPPROTO_UDP; 462 ip6h->hop_limit = 64; 463 464 ip6h->saddr = daddr6.sin6_addr; 465 ip6h->daddr = daddr6.sin6_addr; 466 467 /* kernel does not write saddr in case of ipv6 */ 468 469 return sizeof(*ip6h); 470 } 471 472 static void fill_header_udp(void *p, bool is_ipv4) 473 { 474 struct udphdr *udph = p; 475 476 udph->source = ntohs(dest_port + 1); /* spoof */ 477 udph->dest = ntohs(dest_port); 478 udph->len = ntohs(sizeof(*udph) + cfg_payload_len); 479 udph->check = 0; 480 481 udph->check = get_udp_csum(udph, is_ipv4 ? sizeof(struct in_addr) : 482 sizeof(struct in6_addr)); 483 } 484 485 static void do_test(int family, unsigned int report_opt) 486 { 487 char control[CMSG_SPACE(sizeof(uint32_t))]; 488 struct sockaddr_ll laddr; 489 unsigned int sock_opt; 490 struct cmsghdr *cmsg; 491 struct msghdr msg; 492 struct iovec iov; 493 char *buf; 494 int fd, i, val = 1, total_len, epfd = 0; 495 496 init_timing_event(&usr_enq); 497 init_timing_event(&usr_snd); 498 init_timing_event(&usr_ack); 499 500 total_len = cfg_payload_len; 501 if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) { 502 total_len += sizeof(struct udphdr); 503 if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) { 504 if (family == PF_INET) 505 total_len += sizeof(struct iphdr); 506 else 507 total_len += sizeof(struct ipv6hdr); 508 } 509 /* special case, only rawv6_sendmsg: 510 * pass proto in sin6_port if not connected 511 * also see ANK comment in net/ipv4/raw.c 512 */ 513 daddr6.sin6_port = htons(cfg_ipproto); 514 } 515 516 buf = malloc(total_len); 517 if (!buf) 518 error(1, 0, "malloc"); 519 520 fd = socket(cfg_use_pf_packet ? PF_PACKET : family, 521 cfg_proto, cfg_ipproto); 522 if (fd < 0) 523 error(1, errno, "socket"); 524 525 if (cfg_use_epoll) { 526 struct epoll_event ev; 527 528 memset(&ev, 0, sizeof(ev)); 529 ev.data.fd = fd; 530 if (cfg_epollet) 531 ev.events |= EPOLLET; 532 epfd = epoll_create(1); 533 if (epfd <= 0) 534 error(1, errno, "epoll_create"); 535 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev)) 536 error(1, errno, "epoll_ctl"); 537 } 538 539 /* reset expected key on each new socket */ 540 saved_tskey = -1; 541 542 if (cfg_proto == SOCK_STREAM) { 543 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, 544 (char*) &val, sizeof(val))) 545 error(1, 0, "setsockopt no nagle"); 546 547 if (family == PF_INET) { 548 if (connect(fd, (void *) &daddr, sizeof(daddr))) 549 error(1, errno, "connect ipv4"); 550 } else { 551 if (connect(fd, (void *) &daddr6, sizeof(daddr6))) 552 error(1, errno, "connect ipv6"); 553 } 554 } 555 556 if (cfg_do_pktinfo) { 557 if (family == AF_INET6) { 558 if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO, 559 &val, sizeof(val))) 560 error(1, errno, "setsockopt pktinfo ipv6"); 561 } else { 562 if (setsockopt(fd, SOL_IP, IP_PKTINFO, 563 &val, sizeof(val))) 564 error(1, errno, "setsockopt pktinfo ipv4"); 565 } 566 } 567 568 sock_opt = SOF_TIMESTAMPING_SOFTWARE | 569 SOF_TIMESTAMPING_OPT_CMSG | 570 SOF_TIMESTAMPING_OPT_ID; 571 572 if (!cfg_use_cmsg) 573 sock_opt |= report_opt; 574 575 if (cfg_loop_nodata) 576 sock_opt |= SOF_TIMESTAMPING_OPT_TSONLY; 577 578 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, 579 (char *) &sock_opt, sizeof(sock_opt))) 580 error(1, 0, "setsockopt timestamping"); 581 582 for (i = 0; i < cfg_num_pkts; i++) { 583 memset(&msg, 0, sizeof(msg)); 584 memset(buf, 'a' + i, total_len); 585 586 if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) { 587 int off = 0; 588 589 if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) { 590 if (family == PF_INET) 591 off = fill_header_ipv4(buf); 592 else 593 off = fill_header_ipv6(buf); 594 } 595 596 fill_header_udp(buf + off, family == PF_INET); 597 } 598 599 print_timestamp_usr(); 600 601 iov.iov_base = buf; 602 iov.iov_len = total_len; 603 604 if (cfg_proto != SOCK_STREAM) { 605 if (cfg_use_pf_packet) { 606 memset(&laddr, 0, sizeof(laddr)); 607 608 laddr.sll_family = AF_PACKET; 609 laddr.sll_ifindex = 1; 610 laddr.sll_protocol = htons(family == AF_INET ? ETH_P_IP : ETH_P_IPV6); 611 laddr.sll_halen = ETH_ALEN; 612 613 msg.msg_name = (void *)&laddr; 614 msg.msg_namelen = sizeof(laddr); 615 } else if (family == PF_INET) { 616 msg.msg_name = (void *)&daddr; 617 msg.msg_namelen = sizeof(daddr); 618 } else { 619 msg.msg_name = (void *)&daddr6; 620 msg.msg_namelen = sizeof(daddr6); 621 } 622 } 623 624 msg.msg_iov = &iov; 625 msg.msg_iovlen = 1; 626 627 if (cfg_use_cmsg) { 628 memset(control, 0, sizeof(control)); 629 630 msg.msg_control = control; 631 msg.msg_controllen = sizeof(control); 632 633 cmsg = CMSG_FIRSTHDR(&msg); 634 cmsg->cmsg_level = SOL_SOCKET; 635 cmsg->cmsg_type = SO_TIMESTAMPING; 636 cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t)); 637 638 *((uint32_t *) CMSG_DATA(cmsg)) = report_opt; 639 } 640 641 val = sendmsg(fd, &msg, 0); 642 if (val != total_len) 643 error(1, errno, "send"); 644 645 /* wait for all errors to be queued, else ACKs arrive OOO */ 646 if (cfg_sleep_usec) 647 usleep(cfg_sleep_usec); 648 649 if (!cfg_busy_poll) { 650 if (cfg_use_epoll) 651 __epoll(epfd); 652 else 653 __poll(fd); 654 } 655 656 while (!recv_errmsg(fd)) {} 657 } 658 659 print_timing_event("USR-ENQ", &usr_enq); 660 print_timing_event("USR-SND", &usr_snd); 661 print_timing_event("USR-ACK", &usr_ack); 662 663 if (close(fd)) 664 error(1, errno, "close"); 665 666 free(buf); 667 usleep(100 * NSEC_PER_USEC); 668 } 669 670 static void __attribute__((noreturn)) usage(const char *filepath) 671 { 672 fprintf(stderr, "\nUsage: %s [options] hostname\n" 673 "\nwhere options are:\n" 674 " -4: only IPv4\n" 675 " -6: only IPv6\n" 676 " -h: show this message\n" 677 " -b: busy poll to read from error queue\n" 678 " -c N: number of packets for each test\n" 679 " -C: use cmsg to set tstamp recording options\n" 680 " -e: use level-triggered epoll() instead of poll()\n" 681 " -E: use event-triggered epoll() instead of poll()\n" 682 " -F: poll()/epoll() waits forever for an event\n" 683 " -I: request PKTINFO\n" 684 " -l N: send N bytes at a time\n" 685 " -L listen on hostname and port\n" 686 " -n: set no-payload option\n" 687 " -N: print timestamps and durations in nsec (instead of usec)\n" 688 " -p N: connect to port N\n" 689 " -P: use PF_PACKET\n" 690 " -r: use raw\n" 691 " -R: use raw (IP_HDRINCL)\n" 692 " -S N: usec to sleep before reading error queue\n" 693 " -t N: tolerance (usec) for timestamp validation\n" 694 " -u: use udp\n" 695 " -v: validate SND delay (usec)\n" 696 " -V: validate ACK delay (usec)\n" 697 " -x: show payload (up to 70 bytes)\n", 698 filepath); 699 exit(1); 700 } 701 702 static void parse_opt(int argc, char **argv) 703 { 704 int proto_count = 0; 705 int c; 706 707 while ((c = getopt(argc, argv, 708 "46bc:CeEFhIl:LnNp:PrRS:t:uv:V:x")) != -1) { 709 switch (c) { 710 case '4': 711 do_ipv6 = 0; 712 break; 713 case '6': 714 do_ipv4 = 0; 715 break; 716 case 'b': 717 cfg_busy_poll = true; 718 break; 719 case 'c': 720 cfg_num_pkts = strtoul(optarg, NULL, 10); 721 break; 722 case 'C': 723 cfg_use_cmsg = true; 724 break; 725 case 'e': 726 cfg_use_epoll = true; 727 break; 728 case 'E': 729 cfg_use_epoll = true; 730 cfg_epollet = true; 731 case 'F': 732 cfg_poll_timeout = -1; 733 break; 734 case 'I': 735 cfg_do_pktinfo = true; 736 break; 737 case 'l': 738 cfg_payload_len = strtoul(optarg, NULL, 10); 739 break; 740 case 'L': 741 cfg_do_listen = true; 742 break; 743 case 'n': 744 cfg_loop_nodata = true; 745 break; 746 case 'N': 747 cfg_print_nsec = true; 748 break; 749 case 'p': 750 dest_port = strtoul(optarg, NULL, 10); 751 break; 752 case 'P': 753 proto_count++; 754 cfg_use_pf_packet = true; 755 cfg_proto = SOCK_DGRAM; 756 cfg_ipproto = 0; 757 break; 758 case 'r': 759 proto_count++; 760 cfg_proto = SOCK_RAW; 761 cfg_ipproto = IPPROTO_UDP; 762 break; 763 case 'R': 764 proto_count++; 765 cfg_proto = SOCK_RAW; 766 cfg_ipproto = IPPROTO_RAW; 767 break; 768 case 'S': 769 cfg_sleep_usec = strtoul(optarg, NULL, 10); 770 break; 771 case 't': 772 cfg_delay_tolerance_usec = strtoul(optarg, NULL, 10); 773 break; 774 case 'u': 775 proto_count++; 776 cfg_proto = SOCK_DGRAM; 777 cfg_ipproto = IPPROTO_UDP; 778 break; 779 case 'v': 780 cfg_delay_snd = strtoul(optarg, NULL, 10); 781 break; 782 case 'V': 783 cfg_delay_ack = strtoul(optarg, NULL, 10); 784 break; 785 case 'x': 786 cfg_show_payload = true; 787 break; 788 case 'h': 789 default: 790 usage(argv[0]); 791 } 792 } 793 794 if (!cfg_payload_len) 795 error(1, 0, "payload may not be nonzero"); 796 if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472) 797 error(1, 0, "udp packet might exceed expected MTU"); 798 if (!do_ipv4 && !do_ipv6) 799 error(1, 0, "pass -4 or -6, not both"); 800 if (proto_count > 1) 801 error(1, 0, "pass -P, -r, -R or -u, not multiple"); 802 if (cfg_do_pktinfo && cfg_use_pf_packet) 803 error(1, 0, "cannot ask for pktinfo over pf_packet"); 804 if (cfg_busy_poll && cfg_use_epoll) 805 error(1, 0, "pass epoll or busy_poll, not both"); 806 807 if (optind != argc - 1) 808 error(1, 0, "missing required hostname argument"); 809 } 810 811 static void resolve_hostname(const char *hostname) 812 { 813 struct addrinfo hints = { .ai_family = do_ipv4 ? AF_INET : AF_INET6 }; 814 struct addrinfo *addrs, *cur; 815 int have_ipv4 = 0, have_ipv6 = 0; 816 817 retry: 818 if (getaddrinfo(hostname, NULL, &hints, &addrs)) 819 error(1, errno, "getaddrinfo"); 820 821 cur = addrs; 822 while (cur && !have_ipv4 && !have_ipv6) { 823 if (!have_ipv4 && cur->ai_family == AF_INET) { 824 memcpy(&daddr, cur->ai_addr, sizeof(daddr)); 825 daddr.sin_port = htons(dest_port); 826 have_ipv4 = 1; 827 } 828 else if (!have_ipv6 && cur->ai_family == AF_INET6) { 829 memcpy(&daddr6, cur->ai_addr, sizeof(daddr6)); 830 daddr6.sin6_port = htons(dest_port); 831 have_ipv6 = 1; 832 } 833 cur = cur->ai_next; 834 } 835 if (addrs) 836 freeaddrinfo(addrs); 837 838 if (do_ipv6 && hints.ai_family != AF_INET6) { 839 hints.ai_family = AF_INET6; 840 goto retry; 841 } 842 843 do_ipv4 &= have_ipv4; 844 do_ipv6 &= have_ipv6; 845 } 846 847 static void do_listen(int family, void *addr, int alen) 848 { 849 int fd, type; 850 851 type = cfg_proto == SOCK_RAW ? SOCK_DGRAM : cfg_proto; 852 853 fd = socket(family, type, 0); 854 if (fd == -1) 855 error(1, errno, "socket rx"); 856 857 if (bind(fd, addr, alen)) 858 error(1, errno, "bind rx"); 859 860 if (type == SOCK_STREAM && listen(fd, 10)) 861 error(1, errno, "listen rx"); 862 863 /* leave fd open, will be closed on process exit. 864 * this enables connect() to succeed and avoids icmp replies 865 */ 866 } 867 868 static void do_main(int family) 869 { 870 fprintf(stderr, "family: %s %s\n", 871 family == PF_INET ? "INET" : "INET6", 872 cfg_use_pf_packet ? "(PF_PACKET)" : ""); 873 874 fprintf(stderr, "test SND\n"); 875 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE); 876 877 fprintf(stderr, "test ENQ\n"); 878 do_test(family, SOF_TIMESTAMPING_TX_SCHED); 879 880 fprintf(stderr, "test ENQ + SND\n"); 881 do_test(family, SOF_TIMESTAMPING_TX_SCHED | 882 SOF_TIMESTAMPING_TX_SOFTWARE); 883 884 if (cfg_proto == SOCK_STREAM) { 885 fprintf(stderr, "\ntest ACK\n"); 886 do_test(family, SOF_TIMESTAMPING_TX_ACK); 887 888 fprintf(stderr, "\ntest SND + ACK\n"); 889 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE | 890 SOF_TIMESTAMPING_TX_ACK); 891 892 fprintf(stderr, "\ntest ENQ + SND + ACK\n"); 893 do_test(family, SOF_TIMESTAMPING_TX_SCHED | 894 SOF_TIMESTAMPING_TX_SOFTWARE | 895 SOF_TIMESTAMPING_TX_ACK); 896 } 897 } 898 899 const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" }; 900 901 int main(int argc, char **argv) 902 { 903 if (argc == 1) 904 usage(argv[0]); 905 906 parse_opt(argc, argv); 907 resolve_hostname(argv[argc - 1]); 908 909 fprintf(stderr, "protocol: %s\n", sock_names[cfg_proto]); 910 fprintf(stderr, "payload: %u\n", cfg_payload_len); 911 fprintf(stderr, "server port: %u\n", dest_port); 912 fprintf(stderr, "\n"); 913 914 if (do_ipv4) { 915 if (cfg_do_listen) 916 do_listen(PF_INET, &daddr, sizeof(daddr)); 917 do_main(PF_INET); 918 } 919 920 if (do_ipv6) { 921 if (cfg_do_listen) 922 do_listen(PF_INET6, &daddr6, sizeof(daddr6)); 923 do_main(PF_INET6); 924 } 925 926 return test_failed; 927 } 928