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

Configure Feed

Select the types of activity you want to include in your feed.

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