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 } 362 363 static int recv_errmsg(int fd) 364 { 365 static char ctrl[1024 /* overprovision*/]; 366 static struct msghdr msg; 367 struct iovec entry; 368 static char *data; 369 int ret = 0; 370 371 data = malloc(cfg_payload_len); 372 if (!data) 373 error(1, 0, "malloc"); 374 375 memset(&msg, 0, sizeof(msg)); 376 memset(&entry, 0, sizeof(entry)); 377 memset(ctrl, 0, sizeof(ctrl)); 378 379 entry.iov_base = data; 380 entry.iov_len = cfg_payload_len; 381 msg.msg_iov = &entry; 382 msg.msg_iovlen = 1; 383 msg.msg_name = NULL; 384 msg.msg_namelen = 0; 385 msg.msg_control = ctrl; 386 msg.msg_controllen = sizeof(ctrl); 387 388 ret = recvmsg(fd, &msg, MSG_ERRQUEUE); 389 if (ret == -1 && errno != EAGAIN) 390 error(1, errno, "recvmsg"); 391 392 if (ret >= 0) { 393 __recv_errmsg_cmsg(&msg, ret); 394 if (cfg_show_payload) 395 print_payload(data, cfg_payload_len); 396 } 397 398 free(data); 399 return ret == -1; 400 } 401 402 static uint16_t get_ip_csum(const uint16_t *start, int num_words, 403 unsigned long sum) 404 { 405 int i; 406 407 for (i = 0; i < num_words; i++) 408 sum += start[i]; 409 410 while (sum >> 16) 411 sum = (sum & 0xFFFF) + (sum >> 16); 412 413 return ~sum; 414 } 415 416 static uint16_t get_udp_csum(const struct udphdr *udph, int alen) 417 { 418 unsigned long pseudo_sum, csum_len; 419 const void *csum_start = udph; 420 421 pseudo_sum = htons(IPPROTO_UDP); 422 pseudo_sum += udph->len; 423 424 /* checksum ip(v6) addresses + udp header + payload */ 425 csum_start -= alen * 2; 426 csum_len = ntohs(udph->len) + alen * 2; 427 428 return get_ip_csum(csum_start, csum_len >> 1, pseudo_sum); 429 } 430 431 static int fill_header_ipv4(void *p) 432 { 433 struct iphdr *iph = p; 434 435 memset(iph, 0, sizeof(*iph)); 436 437 iph->ihl = 5; 438 iph->version = 4; 439 iph->ttl = 2; 440 iph->saddr = daddr.sin_addr.s_addr; /* set for udp csum calc */ 441 iph->daddr = daddr.sin_addr.s_addr; 442 iph->protocol = IPPROTO_UDP; 443 444 /* kernel writes saddr, csum, len */ 445 446 return sizeof(*iph); 447 } 448 449 static int fill_header_ipv6(void *p) 450 { 451 struct ipv6hdr *ip6h = p; 452 453 memset(ip6h, 0, sizeof(*ip6h)); 454 455 ip6h->version = 6; 456 ip6h->payload_len = htons(sizeof(struct udphdr) + cfg_payload_len); 457 ip6h->nexthdr = IPPROTO_UDP; 458 ip6h->hop_limit = 64; 459 460 ip6h->saddr = daddr6.sin6_addr; 461 ip6h->daddr = daddr6.sin6_addr; 462 463 /* kernel does not write saddr in case of ipv6 */ 464 465 return sizeof(*ip6h); 466 } 467 468 static void fill_header_udp(void *p, bool is_ipv4) 469 { 470 struct udphdr *udph = p; 471 472 udph->source = ntohs(dest_port + 1); /* spoof */ 473 udph->dest = ntohs(dest_port); 474 udph->len = ntohs(sizeof(*udph) + cfg_payload_len); 475 udph->check = 0; 476 477 udph->check = get_udp_csum(udph, is_ipv4 ? sizeof(struct in_addr) : 478 sizeof(struct in6_addr)); 479 } 480 481 static void do_test(int family, unsigned int report_opt) 482 { 483 char control[CMSG_SPACE(sizeof(uint32_t))]; 484 struct sockaddr_ll laddr; 485 unsigned int sock_opt; 486 struct cmsghdr *cmsg; 487 struct msghdr msg; 488 struct iovec iov; 489 char *buf; 490 int fd, i, val = 1, total_len, epfd = 0; 491 492 init_timing_event(&usr_enq); 493 init_timing_event(&usr_snd); 494 init_timing_event(&usr_ack); 495 496 total_len = cfg_payload_len; 497 if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) { 498 total_len += sizeof(struct udphdr); 499 if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) { 500 if (family == PF_INET) 501 total_len += sizeof(struct iphdr); 502 else 503 total_len += sizeof(struct ipv6hdr); 504 } 505 /* special case, only rawv6_sendmsg: 506 * pass proto in sin6_port if not connected 507 * also see ANK comment in net/ipv4/raw.c 508 */ 509 daddr6.sin6_port = htons(cfg_ipproto); 510 } 511 512 buf = malloc(total_len); 513 if (!buf) 514 error(1, 0, "malloc"); 515 516 fd = socket(cfg_use_pf_packet ? PF_PACKET : family, 517 cfg_proto, cfg_ipproto); 518 if (fd < 0) 519 error(1, errno, "socket"); 520 521 if (cfg_use_epoll) { 522 struct epoll_event ev; 523 524 memset(&ev, 0, sizeof(ev)); 525 ev.data.fd = fd; 526 if (cfg_epollet) 527 ev.events |= EPOLLET; 528 epfd = epoll_create(1); 529 if (epfd <= 0) 530 error(1, errno, "epoll_create"); 531 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev)) 532 error(1, errno, "epoll_ctl"); 533 } 534 535 /* reset expected key on each new socket */ 536 saved_tskey = -1; 537 538 if (cfg_proto == SOCK_STREAM) { 539 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, 540 (char*) &val, sizeof(val))) 541 error(1, 0, "setsockopt no nagle"); 542 543 if (family == PF_INET) { 544 if (connect(fd, (void *) &daddr, sizeof(daddr))) 545 error(1, errno, "connect ipv4"); 546 } else { 547 if (connect(fd, (void *) &daddr6, sizeof(daddr6))) 548 error(1, errno, "connect ipv6"); 549 } 550 } 551 552 if (cfg_do_pktinfo) { 553 if (family == AF_INET6) { 554 if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO, 555 &val, sizeof(val))) 556 error(1, errno, "setsockopt pktinfo ipv6"); 557 } else { 558 if (setsockopt(fd, SOL_IP, IP_PKTINFO, 559 &val, sizeof(val))) 560 error(1, errno, "setsockopt pktinfo ipv4"); 561 } 562 } 563 564 sock_opt = SOF_TIMESTAMPING_SOFTWARE | 565 SOF_TIMESTAMPING_OPT_CMSG | 566 SOF_TIMESTAMPING_OPT_ID; 567 568 if (!cfg_use_cmsg) 569 sock_opt |= report_opt; 570 571 if (cfg_loop_nodata) 572 sock_opt |= SOF_TIMESTAMPING_OPT_TSONLY; 573 574 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, 575 (char *) &sock_opt, sizeof(sock_opt))) 576 error(1, 0, "setsockopt timestamping"); 577 578 for (i = 0; i < cfg_num_pkts; i++) { 579 memset(&msg, 0, sizeof(msg)); 580 memset(buf, 'a' + i, total_len); 581 582 if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) { 583 int off = 0; 584 585 if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) { 586 if (family == PF_INET) 587 off = fill_header_ipv4(buf); 588 else 589 off = fill_header_ipv6(buf); 590 } 591 592 fill_header_udp(buf + off, family == PF_INET); 593 } 594 595 print_timestamp_usr(); 596 597 iov.iov_base = buf; 598 iov.iov_len = total_len; 599 600 if (cfg_proto != SOCK_STREAM) { 601 if (cfg_use_pf_packet) { 602 memset(&laddr, 0, sizeof(laddr)); 603 604 laddr.sll_family = AF_PACKET; 605 laddr.sll_ifindex = 1; 606 laddr.sll_protocol = htons(family == AF_INET ? ETH_P_IP : ETH_P_IPV6); 607 laddr.sll_halen = ETH_ALEN; 608 609 msg.msg_name = (void *)&laddr; 610 msg.msg_namelen = sizeof(laddr); 611 } else if (family == PF_INET) { 612 msg.msg_name = (void *)&daddr; 613 msg.msg_namelen = sizeof(daddr); 614 } else { 615 msg.msg_name = (void *)&daddr6; 616 msg.msg_namelen = sizeof(daddr6); 617 } 618 } 619 620 msg.msg_iov = &iov; 621 msg.msg_iovlen = 1; 622 623 if (cfg_use_cmsg) { 624 memset(control, 0, sizeof(control)); 625 626 msg.msg_control = control; 627 msg.msg_controllen = sizeof(control); 628 629 cmsg = CMSG_FIRSTHDR(&msg); 630 cmsg->cmsg_level = SOL_SOCKET; 631 cmsg->cmsg_type = SO_TIMESTAMPING; 632 cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t)); 633 634 *((uint32_t *) CMSG_DATA(cmsg)) = report_opt; 635 } 636 637 val = sendmsg(fd, &msg, 0); 638 if (val != total_len) 639 error(1, errno, "send"); 640 641 /* wait for all errors to be queued, else ACKs arrive OOO */ 642 if (cfg_sleep_usec) 643 usleep(cfg_sleep_usec); 644 645 if (!cfg_busy_poll) { 646 if (cfg_use_epoll) 647 __epoll(epfd); 648 else 649 __poll(fd); 650 } 651 652 while (!recv_errmsg(fd)) {} 653 } 654 655 print_timing_event("USR-ENQ", &usr_enq); 656 print_timing_event("USR-SND", &usr_snd); 657 print_timing_event("USR-ACK", &usr_ack); 658 659 if (close(fd)) 660 error(1, errno, "close"); 661 662 free(buf); 663 usleep(100 * NSEC_PER_USEC); 664 } 665 666 static void __attribute__((noreturn)) usage(const char *filepath) 667 { 668 fprintf(stderr, "\nUsage: %s [options] hostname\n" 669 "\nwhere options are:\n" 670 " -4: only IPv4\n" 671 " -6: only IPv6\n" 672 " -h: show this message\n" 673 " -b: busy poll to read from error queue\n" 674 " -c N: number of packets for each test\n" 675 " -C: use cmsg to set tstamp recording options\n" 676 " -e: use level-triggered epoll() instead of poll()\n" 677 " -E: use event-triggered epoll() instead of poll()\n" 678 " -F: poll()/epoll() waits forever for an event\n" 679 " -I: request PKTINFO\n" 680 " -l N: send N bytes at a time\n" 681 " -L listen on hostname and port\n" 682 " -n: set no-payload option\n" 683 " -N: print timestamps and durations in nsec (instead of usec)\n" 684 " -p N: connect to port N\n" 685 " -P: use PF_PACKET\n" 686 " -r: use raw\n" 687 " -R: use raw (IP_HDRINCL)\n" 688 " -S N: usec to sleep before reading error queue\n" 689 " -t N: tolerance (usec) for timestamp validation\n" 690 " -u: use udp\n" 691 " -v: validate SND delay (usec)\n" 692 " -V: validate ACK delay (usec)\n" 693 " -x: show payload (up to 70 bytes)\n", 694 filepath); 695 exit(1); 696 } 697 698 static void parse_opt(int argc, char **argv) 699 { 700 int proto_count = 0; 701 int c; 702 703 while ((c = getopt(argc, argv, 704 "46bc:CeEFhIl:LnNp:PrRS:t:uv:V:x")) != -1) { 705 switch (c) { 706 case '4': 707 do_ipv6 = 0; 708 break; 709 case '6': 710 do_ipv4 = 0; 711 break; 712 case 'b': 713 cfg_busy_poll = true; 714 break; 715 case 'c': 716 cfg_num_pkts = strtoul(optarg, NULL, 10); 717 break; 718 case 'C': 719 cfg_use_cmsg = true; 720 break; 721 case 'e': 722 cfg_use_epoll = true; 723 break; 724 case 'E': 725 cfg_use_epoll = true; 726 cfg_epollet = true; 727 case 'F': 728 cfg_poll_timeout = -1; 729 break; 730 case 'I': 731 cfg_do_pktinfo = true; 732 break; 733 case 'l': 734 cfg_payload_len = strtoul(optarg, NULL, 10); 735 break; 736 case 'L': 737 cfg_do_listen = true; 738 break; 739 case 'n': 740 cfg_loop_nodata = true; 741 break; 742 case 'N': 743 cfg_print_nsec = true; 744 break; 745 case 'p': 746 dest_port = strtoul(optarg, NULL, 10); 747 break; 748 case 'P': 749 proto_count++; 750 cfg_use_pf_packet = true; 751 cfg_proto = SOCK_DGRAM; 752 cfg_ipproto = 0; 753 break; 754 case 'r': 755 proto_count++; 756 cfg_proto = SOCK_RAW; 757 cfg_ipproto = IPPROTO_UDP; 758 break; 759 case 'R': 760 proto_count++; 761 cfg_proto = SOCK_RAW; 762 cfg_ipproto = IPPROTO_RAW; 763 break; 764 case 'S': 765 cfg_sleep_usec = strtoul(optarg, NULL, 10); 766 break; 767 case 't': 768 cfg_delay_tolerance_usec = strtoul(optarg, NULL, 10); 769 break; 770 case 'u': 771 proto_count++; 772 cfg_proto = SOCK_DGRAM; 773 cfg_ipproto = IPPROTO_UDP; 774 break; 775 case 'v': 776 cfg_delay_snd = strtoul(optarg, NULL, 10); 777 break; 778 case 'V': 779 cfg_delay_ack = strtoul(optarg, NULL, 10); 780 break; 781 case 'x': 782 cfg_show_payload = true; 783 break; 784 case 'h': 785 default: 786 usage(argv[0]); 787 } 788 } 789 790 if (!cfg_payload_len) 791 error(1, 0, "payload may not be nonzero"); 792 if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472) 793 error(1, 0, "udp packet might exceed expected MTU"); 794 if (!do_ipv4 && !do_ipv6) 795 error(1, 0, "pass -4 or -6, not both"); 796 if (proto_count > 1) 797 error(1, 0, "pass -P, -r, -R or -u, not multiple"); 798 if (cfg_do_pktinfo && cfg_use_pf_packet) 799 error(1, 0, "cannot ask for pktinfo over pf_packet"); 800 if (cfg_busy_poll && cfg_use_epoll) 801 error(1, 0, "pass epoll or busy_poll, not both"); 802 803 if (optind != argc - 1) 804 error(1, 0, "missing required hostname argument"); 805 } 806 807 static void resolve_hostname(const char *hostname) 808 { 809 struct addrinfo hints = { .ai_family = do_ipv4 ? AF_INET : AF_INET6 }; 810 struct addrinfo *addrs, *cur; 811 int have_ipv4 = 0, have_ipv6 = 0; 812 813 retry: 814 if (getaddrinfo(hostname, NULL, &hints, &addrs)) 815 error(1, errno, "getaddrinfo"); 816 817 cur = addrs; 818 while (cur && !have_ipv4 && !have_ipv6) { 819 if (!have_ipv4 && cur->ai_family == AF_INET) { 820 memcpy(&daddr, cur->ai_addr, sizeof(daddr)); 821 daddr.sin_port = htons(dest_port); 822 have_ipv4 = 1; 823 } 824 else if (!have_ipv6 && cur->ai_family == AF_INET6) { 825 memcpy(&daddr6, cur->ai_addr, sizeof(daddr6)); 826 daddr6.sin6_port = htons(dest_port); 827 have_ipv6 = 1; 828 } 829 cur = cur->ai_next; 830 } 831 if (addrs) 832 freeaddrinfo(addrs); 833 834 if (do_ipv6 && hints.ai_family != AF_INET6) { 835 hints.ai_family = AF_INET6; 836 goto retry; 837 } 838 839 do_ipv4 &= have_ipv4; 840 do_ipv6 &= have_ipv6; 841 } 842 843 static void do_listen(int family, void *addr, int alen) 844 { 845 int fd, type; 846 847 type = cfg_proto == SOCK_RAW ? SOCK_DGRAM : cfg_proto; 848 849 fd = socket(family, type, 0); 850 if (fd == -1) 851 error(1, errno, "socket rx"); 852 853 if (bind(fd, addr, alen)) 854 error(1, errno, "bind rx"); 855 856 if (type == SOCK_STREAM && listen(fd, 10)) 857 error(1, errno, "listen rx"); 858 859 /* leave fd open, will be closed on process exit. 860 * this enables connect() to succeed and avoids icmp replies 861 */ 862 } 863 864 static void do_main(int family) 865 { 866 fprintf(stderr, "family: %s %s\n", 867 family == PF_INET ? "INET" : "INET6", 868 cfg_use_pf_packet ? "(PF_PACKET)" : ""); 869 870 fprintf(stderr, "test SND\n"); 871 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE); 872 873 fprintf(stderr, "test ENQ\n"); 874 do_test(family, SOF_TIMESTAMPING_TX_SCHED); 875 876 fprintf(stderr, "test ENQ + SND\n"); 877 do_test(family, SOF_TIMESTAMPING_TX_SCHED | 878 SOF_TIMESTAMPING_TX_SOFTWARE); 879 880 if (cfg_proto == SOCK_STREAM) { 881 fprintf(stderr, "\ntest ACK\n"); 882 do_test(family, SOF_TIMESTAMPING_TX_ACK); 883 884 fprintf(stderr, "\ntest SND + ACK\n"); 885 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE | 886 SOF_TIMESTAMPING_TX_ACK); 887 888 fprintf(stderr, "\ntest ENQ + SND + ACK\n"); 889 do_test(family, SOF_TIMESTAMPING_TX_SCHED | 890 SOF_TIMESTAMPING_TX_SOFTWARE | 891 SOF_TIMESTAMPING_TX_ACK); 892 } 893 } 894 895 const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" }; 896 897 int main(int argc, char **argv) 898 { 899 if (argc == 1) 900 usage(argv[0]); 901 902 parse_opt(argc, argv); 903 resolve_hostname(argv[argc - 1]); 904 905 fprintf(stderr, "protocol: %s\n", sock_names[cfg_proto]); 906 fprintf(stderr, "payload: %u\n", cfg_payload_len); 907 fprintf(stderr, "server port: %u\n", dest_port); 908 fprintf(stderr, "\n"); 909 910 if (do_ipv4) { 911 if (cfg_do_listen) 912 do_listen(PF_INET, &daddr, sizeof(daddr)); 913 do_main(PF_INET); 914 } 915 916 if (do_ipv6) { 917 if (cfg_do_listen) 918 do_listen(PF_INET6, &daddr6, sizeof(daddr6)); 919 do_main(PF_INET6); 920 } 921 922 return test_failed; 923 } 924
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.