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