0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #define _GNU_SOURCE
0021
0022 #include <arpa/inet.h>
0023 #include <asm/types.h>
0024 #include <error.h>
0025 #include <errno.h>
0026 #include <inttypes.h>
0027 #include <linux/errqueue.h>
0028 #include <linux/if_ether.h>
0029 #include <linux/if_packet.h>
0030 #include <linux/ipv6.h>
0031 #include <linux/net_tstamp.h>
0032 #include <netdb.h>
0033 #include <net/if.h>
0034 #include <netinet/in.h>
0035 #include <netinet/ip.h>
0036 #include <netinet/udp.h>
0037 #include <netinet/tcp.h>
0038 #include <poll.h>
0039 #include <stdarg.h>
0040 #include <stdbool.h>
0041 #include <stdio.h>
0042 #include <stdlib.h>
0043 #include <string.h>
0044 #include <sys/epoll.h>
0045 #include <sys/ioctl.h>
0046 #include <sys/select.h>
0047 #include <sys/socket.h>
0048 #include <sys/time.h>
0049 #include <sys/types.h>
0050 #include <time.h>
0051 #include <unistd.h>
0052
0053 #define NSEC_PER_USEC 1000L
0054 #define USEC_PER_SEC 1000000L
0055 #define NSEC_PER_SEC 1000000000LL
0056
0057
0058 static int cfg_proto = SOCK_STREAM;
0059 static int cfg_ipproto = IPPROTO_TCP;
0060 static int cfg_num_pkts = 4;
0061 static int do_ipv4 = 1;
0062 static int do_ipv6 = 1;
0063 static int cfg_payload_len = 10;
0064 static int cfg_poll_timeout = 100;
0065 static int cfg_delay_snd;
0066 static int cfg_delay_ack;
0067 static int cfg_delay_tolerance_usec = 500;
0068 static bool cfg_show_payload;
0069 static bool cfg_do_pktinfo;
0070 static bool cfg_busy_poll;
0071 static int cfg_sleep_usec = 50 * 1000;
0072 static bool cfg_loop_nodata;
0073 static bool cfg_use_cmsg;
0074 static bool cfg_use_pf_packet;
0075 static bool cfg_use_epoll;
0076 static bool cfg_epollet;
0077 static bool cfg_do_listen;
0078 static uint16_t dest_port = 9000;
0079 static bool cfg_print_nsec;
0080
0081 static struct sockaddr_in daddr;
0082 static struct sockaddr_in6 daddr6;
0083 static struct timespec ts_usr;
0084
0085 static int saved_tskey = -1;
0086 static int saved_tskey_type = -1;
0087
0088 struct timing_event {
0089 int64_t min;
0090 int64_t max;
0091 int64_t total;
0092 int count;
0093 };
0094
0095 static struct timing_event usr_enq;
0096 static struct timing_event usr_snd;
0097 static struct timing_event usr_ack;
0098
0099 static bool test_failed;
0100
0101 static int64_t timespec_to_ns64(struct timespec *ts)
0102 {
0103 return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec;
0104 }
0105
0106 static int64_t timespec_to_us64(struct timespec *ts)
0107 {
0108 return ts->tv_sec * USEC_PER_SEC + ts->tv_nsec / NSEC_PER_USEC;
0109 }
0110
0111 static void init_timing_event(struct timing_event *te)
0112 {
0113 te->min = INT64_MAX;
0114 te->max = 0;
0115 te->total = 0;
0116 te->count = 0;
0117 }
0118
0119 static void add_timing_event(struct timing_event *te,
0120 struct timespec *t_start, struct timespec *t_end)
0121 {
0122 int64_t ts_delta = timespec_to_ns64(t_end) - timespec_to_ns64(t_start);
0123
0124 te->count++;
0125 if (ts_delta < te->min)
0126 te->min = ts_delta;
0127 if (ts_delta > te->max)
0128 te->max = ts_delta;
0129 te->total += ts_delta;
0130 }
0131
0132 static void validate_key(int tskey, int tstype)
0133 {
0134 int stepsize;
0135
0136
0137
0138
0139 if (saved_tskey == -1)
0140 saved_tskey_type = tstype;
0141 else if (saved_tskey_type != tstype)
0142 return;
0143
0144 stepsize = cfg_proto == SOCK_STREAM ? cfg_payload_len : 1;
0145 if (tskey != saved_tskey + stepsize) {
0146 fprintf(stderr, "ERROR: key %d, expected %d\n",
0147 tskey, saved_tskey + stepsize);
0148 test_failed = true;
0149 }
0150
0151 saved_tskey = tskey;
0152 }
0153
0154 static void validate_timestamp(struct timespec *cur, int min_delay)
0155 {
0156 int64_t cur64, start64;
0157 int max_delay;
0158
0159 cur64 = timespec_to_us64(cur);
0160 start64 = timespec_to_us64(&ts_usr);
0161 max_delay = min_delay + cfg_delay_tolerance_usec;
0162
0163 if (cur64 < start64 + min_delay || cur64 > start64 + max_delay) {
0164 fprintf(stderr, "ERROR: %" PRId64 " us expected between %d and %d\n",
0165 cur64 - start64, min_delay, max_delay);
0166 test_failed = true;
0167 }
0168 }
0169
0170 static void __print_ts_delta_formatted(int64_t ts_delta)
0171 {
0172 if (cfg_print_nsec)
0173 fprintf(stderr, "%" PRId64 " ns", ts_delta);
0174 else
0175 fprintf(stderr, "%" PRId64 " us", ts_delta / NSEC_PER_USEC);
0176 }
0177
0178 static void __print_timestamp(const char *name, struct timespec *cur,
0179 uint32_t key, int payload_len)
0180 {
0181 int64_t ts_delta;
0182
0183 if (!(cur->tv_sec | cur->tv_nsec))
0184 return;
0185
0186 if (cfg_print_nsec)
0187 fprintf(stderr, " %s: %lu s %lu ns (seq=%u, len=%u)",
0188 name, cur->tv_sec, cur->tv_nsec,
0189 key, payload_len);
0190 else
0191 fprintf(stderr, " %s: %lu s %lu us (seq=%u, len=%u)",
0192 name, cur->tv_sec, cur->tv_nsec / NSEC_PER_USEC,
0193 key, payload_len);
0194
0195 if (cur != &ts_usr) {
0196 ts_delta = timespec_to_ns64(cur) - timespec_to_ns64(&ts_usr);
0197 fprintf(stderr, " (USR +");
0198 __print_ts_delta_formatted(ts_delta);
0199 fprintf(stderr, ")");
0200 }
0201
0202 fprintf(stderr, "\n");
0203 }
0204
0205 static void print_timestamp_usr(void)
0206 {
0207 if (clock_gettime(CLOCK_REALTIME, &ts_usr))
0208 error(1, errno, "clock_gettime");
0209
0210 __print_timestamp(" USR", &ts_usr, 0, 0);
0211 }
0212
0213 static void print_timestamp(struct scm_timestamping *tss, int tstype,
0214 int tskey, int payload_len)
0215 {
0216 const char *tsname;
0217
0218 validate_key(tskey, tstype);
0219
0220 switch (tstype) {
0221 case SCM_TSTAMP_SCHED:
0222 tsname = " ENQ";
0223 validate_timestamp(&tss->ts[0], 0);
0224 add_timing_event(&usr_enq, &ts_usr, &tss->ts[0]);
0225 break;
0226 case SCM_TSTAMP_SND:
0227 tsname = " SND";
0228 validate_timestamp(&tss->ts[0], cfg_delay_snd);
0229 add_timing_event(&usr_snd, &ts_usr, &tss->ts[0]);
0230 break;
0231 case SCM_TSTAMP_ACK:
0232 tsname = " ACK";
0233 validate_timestamp(&tss->ts[0], cfg_delay_ack);
0234 add_timing_event(&usr_ack, &ts_usr, &tss->ts[0]);
0235 break;
0236 default:
0237 error(1, 0, "unknown timestamp type: %u",
0238 tstype);
0239 }
0240 __print_timestamp(tsname, &tss->ts[0], tskey, payload_len);
0241 }
0242
0243 static void print_timing_event(char *name, struct timing_event *te)
0244 {
0245 if (!te->count)
0246 return;
0247
0248 fprintf(stderr, " %s: count=%d", name, te->count);
0249 fprintf(stderr, ", avg=");
0250 __print_ts_delta_formatted((int64_t)(te->total / te->count));
0251 fprintf(stderr, ", min=");
0252 __print_ts_delta_formatted(te->min);
0253 fprintf(stderr, ", max=");
0254 __print_ts_delta_formatted(te->max);
0255 fprintf(stderr, "\n");
0256 }
0257
0258
0259 static void print_payload(char *data, int len)
0260 {
0261 int i;
0262
0263 if (!len)
0264 return;
0265
0266 if (len > 70)
0267 len = 70;
0268
0269 fprintf(stderr, "payload: ");
0270 for (i = 0; i < len; i++)
0271 fprintf(stderr, "%02hhx ", data[i]);
0272 fprintf(stderr, "\n");
0273 }
0274
0275 static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr)
0276 {
0277 char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN];
0278
0279 fprintf(stderr, " pktinfo: ifindex=%u src=%s dst=%s\n",
0280 ifindex,
0281 saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown",
0282 daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown");
0283 }
0284
0285 static void __epoll(int epfd)
0286 {
0287 struct epoll_event events;
0288 int ret;
0289
0290 memset(&events, 0, sizeof(events));
0291 ret = epoll_wait(epfd, &events, 1, cfg_poll_timeout);
0292 if (ret != 1)
0293 error(1, errno, "epoll_wait");
0294 }
0295
0296 static void __poll(int fd)
0297 {
0298 struct pollfd pollfd;
0299 int ret;
0300
0301 memset(&pollfd, 0, sizeof(pollfd));
0302 pollfd.fd = fd;
0303 ret = poll(&pollfd, 1, cfg_poll_timeout);
0304 if (ret != 1)
0305 error(1, errno, "poll");
0306 }
0307
0308 static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len)
0309 {
0310 struct sock_extended_err *serr = NULL;
0311 struct scm_timestamping *tss = NULL;
0312 struct cmsghdr *cm;
0313 int batch = 0;
0314
0315 for (cm = CMSG_FIRSTHDR(msg);
0316 cm && cm->cmsg_len;
0317 cm = CMSG_NXTHDR(msg, cm)) {
0318 if (cm->cmsg_level == SOL_SOCKET &&
0319 cm->cmsg_type == SCM_TIMESTAMPING) {
0320 tss = (void *) CMSG_DATA(cm);
0321 } else if ((cm->cmsg_level == SOL_IP &&
0322 cm->cmsg_type == IP_RECVERR) ||
0323 (cm->cmsg_level == SOL_IPV6 &&
0324 cm->cmsg_type == IPV6_RECVERR) ||
0325 (cm->cmsg_level == SOL_PACKET &&
0326 cm->cmsg_type == PACKET_TX_TIMESTAMP)) {
0327 serr = (void *) CMSG_DATA(cm);
0328 if (serr->ee_errno != ENOMSG ||
0329 serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
0330 fprintf(stderr, "unknown ip error %d %d\n",
0331 serr->ee_errno,
0332 serr->ee_origin);
0333 serr = NULL;
0334 }
0335 } else if (cm->cmsg_level == SOL_IP &&
0336 cm->cmsg_type == IP_PKTINFO) {
0337 struct in_pktinfo *info = (void *) CMSG_DATA(cm);
0338 print_pktinfo(AF_INET, info->ipi_ifindex,
0339 &info->ipi_spec_dst, &info->ipi_addr);
0340 } else if (cm->cmsg_level == SOL_IPV6 &&
0341 cm->cmsg_type == IPV6_PKTINFO) {
0342 struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm);
0343 print_pktinfo(AF_INET6, info6->ipi6_ifindex,
0344 NULL, &info6->ipi6_addr);
0345 } else
0346 fprintf(stderr, "unknown cmsg %d,%d\n",
0347 cm->cmsg_level, cm->cmsg_type);
0348
0349 if (serr && tss) {
0350 print_timestamp(tss, serr->ee_info, serr->ee_data,
0351 payload_len);
0352 serr = NULL;
0353 tss = NULL;
0354 batch++;
0355 }
0356 }
0357
0358 if (batch > 1)
0359 fprintf(stderr, "batched %d timestamps\n", batch);
0360 }
0361
0362 static int recv_errmsg(int fd)
0363 {
0364 static char ctrl[1024 ];
0365 static struct msghdr msg;
0366 struct iovec entry;
0367 static char *data;
0368 int ret = 0;
0369
0370 data = malloc(cfg_payload_len);
0371 if (!data)
0372 error(1, 0, "malloc");
0373
0374 memset(&msg, 0, sizeof(msg));
0375 memset(&entry, 0, sizeof(entry));
0376 memset(ctrl, 0, sizeof(ctrl));
0377
0378 entry.iov_base = data;
0379 entry.iov_len = cfg_payload_len;
0380 msg.msg_iov = &entry;
0381 msg.msg_iovlen = 1;
0382 msg.msg_name = NULL;
0383 msg.msg_namelen = 0;
0384 msg.msg_control = ctrl;
0385 msg.msg_controllen = sizeof(ctrl);
0386
0387 ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
0388 if (ret == -1 && errno != EAGAIN)
0389 error(1, errno, "recvmsg");
0390
0391 if (ret >= 0) {
0392 __recv_errmsg_cmsg(&msg, ret);
0393 if (cfg_show_payload)
0394 print_payload(data, cfg_payload_len);
0395 }
0396
0397 free(data);
0398 return ret == -1;
0399 }
0400
0401 static uint16_t get_ip_csum(const uint16_t *start, int num_words,
0402 unsigned long sum)
0403 {
0404 int i;
0405
0406 for (i = 0; i < num_words; i++)
0407 sum += start[i];
0408
0409 while (sum >> 16)
0410 sum = (sum & 0xFFFF) + (sum >> 16);
0411
0412 return ~sum;
0413 }
0414
0415 static uint16_t get_udp_csum(const struct udphdr *udph, int alen)
0416 {
0417 unsigned long pseudo_sum, csum_len;
0418 const void *csum_start = udph;
0419
0420 pseudo_sum = htons(IPPROTO_UDP);
0421 pseudo_sum += udph->len;
0422
0423
0424 csum_start -= alen * 2;
0425 csum_len = ntohs(udph->len) + alen * 2;
0426
0427 return get_ip_csum(csum_start, csum_len >> 1, pseudo_sum);
0428 }
0429
0430 static int fill_header_ipv4(void *p)
0431 {
0432 struct iphdr *iph = p;
0433
0434 memset(iph, 0, sizeof(*iph));
0435
0436 iph->ihl = 5;
0437 iph->version = 4;
0438 iph->ttl = 2;
0439 iph->saddr = daddr.sin_addr.s_addr;
0440 iph->daddr = daddr.sin_addr.s_addr;
0441 iph->protocol = IPPROTO_UDP;
0442
0443
0444
0445 return sizeof(*iph);
0446 }
0447
0448 static int fill_header_ipv6(void *p)
0449 {
0450 struct ipv6hdr *ip6h = p;
0451
0452 memset(ip6h, 0, sizeof(*ip6h));
0453
0454 ip6h->version = 6;
0455 ip6h->payload_len = htons(sizeof(struct udphdr) + cfg_payload_len);
0456 ip6h->nexthdr = IPPROTO_UDP;
0457 ip6h->hop_limit = 64;
0458
0459 ip6h->saddr = daddr6.sin6_addr;
0460 ip6h->daddr = daddr6.sin6_addr;
0461
0462
0463
0464 return sizeof(*ip6h);
0465 }
0466
0467 static void fill_header_udp(void *p, bool is_ipv4)
0468 {
0469 struct udphdr *udph = p;
0470
0471 udph->source = ntohs(dest_port + 1);
0472 udph->dest = ntohs(dest_port);
0473 udph->len = ntohs(sizeof(*udph) + cfg_payload_len);
0474 udph->check = 0;
0475
0476 udph->check = get_udp_csum(udph, is_ipv4 ? sizeof(struct in_addr) :
0477 sizeof(struct in6_addr));
0478 }
0479
0480 static void do_test(int family, unsigned int report_opt)
0481 {
0482 char control[CMSG_SPACE(sizeof(uint32_t))];
0483 struct sockaddr_ll laddr;
0484 unsigned int sock_opt;
0485 struct cmsghdr *cmsg;
0486 struct msghdr msg;
0487 struct iovec iov;
0488 char *buf;
0489 int fd, i, val = 1, total_len, epfd = 0;
0490
0491 init_timing_event(&usr_enq);
0492 init_timing_event(&usr_snd);
0493 init_timing_event(&usr_ack);
0494
0495 total_len = cfg_payload_len;
0496 if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) {
0497 total_len += sizeof(struct udphdr);
0498 if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) {
0499 if (family == PF_INET)
0500 total_len += sizeof(struct iphdr);
0501 else
0502 total_len += sizeof(struct ipv6hdr);
0503 }
0504
0505
0506
0507
0508 daddr6.sin6_port = htons(cfg_ipproto);
0509 }
0510
0511 buf = malloc(total_len);
0512 if (!buf)
0513 error(1, 0, "malloc");
0514
0515 fd = socket(cfg_use_pf_packet ? PF_PACKET : family,
0516 cfg_proto, cfg_ipproto);
0517 if (fd < 0)
0518 error(1, errno, "socket");
0519
0520 if (cfg_use_epoll) {
0521 struct epoll_event ev;
0522
0523 memset(&ev, 0, sizeof(ev));
0524 ev.data.fd = fd;
0525 if (cfg_epollet)
0526 ev.events |= EPOLLET;
0527 epfd = epoll_create(1);
0528 if (epfd <= 0)
0529 error(1, errno, "epoll_create");
0530 if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev))
0531 error(1, errno, "epoll_ctl");
0532 }
0533
0534
0535 saved_tskey = -1;
0536
0537 if (cfg_proto == SOCK_STREAM) {
0538 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
0539 (char*) &val, sizeof(val)))
0540 error(1, 0, "setsockopt no nagle");
0541
0542 if (family == PF_INET) {
0543 if (connect(fd, (void *) &daddr, sizeof(daddr)))
0544 error(1, errno, "connect ipv4");
0545 } else {
0546 if (connect(fd, (void *) &daddr6, sizeof(daddr6)))
0547 error(1, errno, "connect ipv6");
0548 }
0549 }
0550
0551 if (cfg_do_pktinfo) {
0552 if (family == AF_INET6) {
0553 if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO,
0554 &val, sizeof(val)))
0555 error(1, errno, "setsockopt pktinfo ipv6");
0556 } else {
0557 if (setsockopt(fd, SOL_IP, IP_PKTINFO,
0558 &val, sizeof(val)))
0559 error(1, errno, "setsockopt pktinfo ipv4");
0560 }
0561 }
0562
0563 sock_opt = SOF_TIMESTAMPING_SOFTWARE |
0564 SOF_TIMESTAMPING_OPT_CMSG |
0565 SOF_TIMESTAMPING_OPT_ID;
0566
0567 if (!cfg_use_cmsg)
0568 sock_opt |= report_opt;
0569
0570 if (cfg_loop_nodata)
0571 sock_opt |= SOF_TIMESTAMPING_OPT_TSONLY;
0572
0573 if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
0574 (char *) &sock_opt, sizeof(sock_opt)))
0575 error(1, 0, "setsockopt timestamping");
0576
0577 for (i = 0; i < cfg_num_pkts; i++) {
0578 memset(&msg, 0, sizeof(msg));
0579 memset(buf, 'a' + i, total_len);
0580
0581 if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) {
0582 int off = 0;
0583
0584 if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) {
0585 if (family == PF_INET)
0586 off = fill_header_ipv4(buf);
0587 else
0588 off = fill_header_ipv6(buf);
0589 }
0590
0591 fill_header_udp(buf + off, family == PF_INET);
0592 }
0593
0594 print_timestamp_usr();
0595
0596 iov.iov_base = buf;
0597 iov.iov_len = total_len;
0598
0599 if (cfg_proto != SOCK_STREAM) {
0600 if (cfg_use_pf_packet) {
0601 memset(&laddr, 0, sizeof(laddr));
0602
0603 laddr.sll_family = AF_PACKET;
0604 laddr.sll_ifindex = 1;
0605 laddr.sll_protocol = htons(family == AF_INET ? ETH_P_IP : ETH_P_IPV6);
0606 laddr.sll_halen = ETH_ALEN;
0607
0608 msg.msg_name = (void *)&laddr;
0609 msg.msg_namelen = sizeof(laddr);
0610 } else if (family == PF_INET) {
0611 msg.msg_name = (void *)&daddr;
0612 msg.msg_namelen = sizeof(daddr);
0613 } else {
0614 msg.msg_name = (void *)&daddr6;
0615 msg.msg_namelen = sizeof(daddr6);
0616 }
0617 }
0618
0619 msg.msg_iov = &iov;
0620 msg.msg_iovlen = 1;
0621
0622 if (cfg_use_cmsg) {
0623 memset(control, 0, sizeof(control));
0624
0625 msg.msg_control = control;
0626 msg.msg_controllen = sizeof(control);
0627
0628 cmsg = CMSG_FIRSTHDR(&msg);
0629 cmsg->cmsg_level = SOL_SOCKET;
0630 cmsg->cmsg_type = SO_TIMESTAMPING;
0631 cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t));
0632
0633 *((uint32_t *) CMSG_DATA(cmsg)) = report_opt;
0634 }
0635
0636 val = sendmsg(fd, &msg, 0);
0637 if (val != total_len)
0638 error(1, errno, "send");
0639
0640
0641 if (cfg_sleep_usec)
0642 usleep(cfg_sleep_usec);
0643
0644 if (!cfg_busy_poll) {
0645 if (cfg_use_epoll)
0646 __epoll(epfd);
0647 else
0648 __poll(fd);
0649 }
0650
0651 while (!recv_errmsg(fd)) {}
0652 }
0653
0654 print_timing_event("USR-ENQ", &usr_enq);
0655 print_timing_event("USR-SND", &usr_snd);
0656 print_timing_event("USR-ACK", &usr_ack);
0657
0658 if (close(fd))
0659 error(1, errno, "close");
0660
0661 free(buf);
0662 usleep(100 * NSEC_PER_USEC);
0663 }
0664
0665 static void __attribute__((noreturn)) usage(const char *filepath)
0666 {
0667 fprintf(stderr, "\nUsage: %s [options] hostname\n"
0668 "\nwhere options are:\n"
0669 " -4: only IPv4\n"
0670 " -6: only IPv6\n"
0671 " -h: show this message\n"
0672 " -b: busy poll to read from error queue\n"
0673 " -c N: number of packets for each test\n"
0674 " -C: use cmsg to set tstamp recording options\n"
0675 " -e: use level-triggered epoll() instead of poll()\n"
0676 " -E: use event-triggered epoll() instead of poll()\n"
0677 " -F: poll()/epoll() waits forever for an event\n"
0678 " -I: request PKTINFO\n"
0679 " -l N: send N bytes at a time\n"
0680 " -L listen on hostname and port\n"
0681 " -n: set no-payload option\n"
0682 " -N: print timestamps and durations in nsec (instead of usec)\n"
0683 " -p N: connect to port N\n"
0684 " -P: use PF_PACKET\n"
0685 " -r: use raw\n"
0686 " -R: use raw (IP_HDRINCL)\n"
0687 " -S N: usec to sleep before reading error queue\n"
0688 " -t N: tolerance (usec) for timestamp validation\n"
0689 " -u: use udp\n"
0690 " -v: validate SND delay (usec)\n"
0691 " -V: validate ACK delay (usec)\n"
0692 " -x: show payload (up to 70 bytes)\n",
0693 filepath);
0694 exit(1);
0695 }
0696
0697 static void parse_opt(int argc, char **argv)
0698 {
0699 int proto_count = 0;
0700 int c;
0701
0702 while ((c = getopt(argc, argv,
0703 "46bc:CeEFhIl:LnNp:PrRS:t:uv:V:x")) != -1) {
0704 switch (c) {
0705 case '4':
0706 do_ipv6 = 0;
0707 break;
0708 case '6':
0709 do_ipv4 = 0;
0710 break;
0711 case 'b':
0712 cfg_busy_poll = true;
0713 break;
0714 case 'c':
0715 cfg_num_pkts = strtoul(optarg, NULL, 10);
0716 break;
0717 case 'C':
0718 cfg_use_cmsg = true;
0719 break;
0720 case 'e':
0721 cfg_use_epoll = true;
0722 break;
0723 case 'E':
0724 cfg_use_epoll = true;
0725 cfg_epollet = true;
0726 case 'F':
0727 cfg_poll_timeout = -1;
0728 break;
0729 case 'I':
0730 cfg_do_pktinfo = true;
0731 break;
0732 case 'l':
0733 cfg_payload_len = strtoul(optarg, NULL, 10);
0734 break;
0735 case 'L':
0736 cfg_do_listen = true;
0737 break;
0738 case 'n':
0739 cfg_loop_nodata = true;
0740 break;
0741 case 'N':
0742 cfg_print_nsec = true;
0743 break;
0744 case 'p':
0745 dest_port = strtoul(optarg, NULL, 10);
0746 break;
0747 case 'P':
0748 proto_count++;
0749 cfg_use_pf_packet = true;
0750 cfg_proto = SOCK_DGRAM;
0751 cfg_ipproto = 0;
0752 break;
0753 case 'r':
0754 proto_count++;
0755 cfg_proto = SOCK_RAW;
0756 cfg_ipproto = IPPROTO_UDP;
0757 break;
0758 case 'R':
0759 proto_count++;
0760 cfg_proto = SOCK_RAW;
0761 cfg_ipproto = IPPROTO_RAW;
0762 break;
0763 case 'S':
0764 cfg_sleep_usec = strtoul(optarg, NULL, 10);
0765 break;
0766 case 't':
0767 cfg_delay_tolerance_usec = strtoul(optarg, NULL, 10);
0768 break;
0769 case 'u':
0770 proto_count++;
0771 cfg_proto = SOCK_DGRAM;
0772 cfg_ipproto = IPPROTO_UDP;
0773 break;
0774 case 'v':
0775 cfg_delay_snd = strtoul(optarg, NULL, 10);
0776 break;
0777 case 'V':
0778 cfg_delay_ack = strtoul(optarg, NULL, 10);
0779 break;
0780 case 'x':
0781 cfg_show_payload = true;
0782 break;
0783 case 'h':
0784 default:
0785 usage(argv[0]);
0786 }
0787 }
0788
0789 if (!cfg_payload_len)
0790 error(1, 0, "payload may not be nonzero");
0791 if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472)
0792 error(1, 0, "udp packet might exceed expected MTU");
0793 if (!do_ipv4 && !do_ipv6)
0794 error(1, 0, "pass -4 or -6, not both");
0795 if (proto_count > 1)
0796 error(1, 0, "pass -P, -r, -R or -u, not multiple");
0797 if (cfg_do_pktinfo && cfg_use_pf_packet)
0798 error(1, 0, "cannot ask for pktinfo over pf_packet");
0799 if (cfg_busy_poll && cfg_use_epoll)
0800 error(1, 0, "pass epoll or busy_poll, not both");
0801
0802 if (optind != argc - 1)
0803 error(1, 0, "missing required hostname argument");
0804 }
0805
0806 static void resolve_hostname(const char *hostname)
0807 {
0808 struct addrinfo hints = { .ai_family = do_ipv4 ? AF_INET : AF_INET6 };
0809 struct addrinfo *addrs, *cur;
0810 int have_ipv4 = 0, have_ipv6 = 0;
0811
0812 retry:
0813 if (getaddrinfo(hostname, NULL, &hints, &addrs))
0814 error(1, errno, "getaddrinfo");
0815
0816 cur = addrs;
0817 while (cur && !have_ipv4 && !have_ipv6) {
0818 if (!have_ipv4 && cur->ai_family == AF_INET) {
0819 memcpy(&daddr, cur->ai_addr, sizeof(daddr));
0820 daddr.sin_port = htons(dest_port);
0821 have_ipv4 = 1;
0822 }
0823 else if (!have_ipv6 && cur->ai_family == AF_INET6) {
0824 memcpy(&daddr6, cur->ai_addr, sizeof(daddr6));
0825 daddr6.sin6_port = htons(dest_port);
0826 have_ipv6 = 1;
0827 }
0828 cur = cur->ai_next;
0829 }
0830 if (addrs)
0831 freeaddrinfo(addrs);
0832
0833 if (do_ipv6 && hints.ai_family != AF_INET6) {
0834 hints.ai_family = AF_INET6;
0835 goto retry;
0836 }
0837
0838 do_ipv4 &= have_ipv4;
0839 do_ipv6 &= have_ipv6;
0840 }
0841
0842 static void do_listen(int family, void *addr, int alen)
0843 {
0844 int fd, type;
0845
0846 type = cfg_proto == SOCK_RAW ? SOCK_DGRAM : cfg_proto;
0847
0848 fd = socket(family, type, 0);
0849 if (fd == -1)
0850 error(1, errno, "socket rx");
0851
0852 if (bind(fd, addr, alen))
0853 error(1, errno, "bind rx");
0854
0855 if (type == SOCK_STREAM && listen(fd, 10))
0856 error(1, errno, "listen rx");
0857
0858
0859
0860
0861 }
0862
0863 static void do_main(int family)
0864 {
0865 fprintf(stderr, "family: %s %s\n",
0866 family == PF_INET ? "INET" : "INET6",
0867 cfg_use_pf_packet ? "(PF_PACKET)" : "");
0868
0869 fprintf(stderr, "test SND\n");
0870 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE);
0871
0872 fprintf(stderr, "test ENQ\n");
0873 do_test(family, SOF_TIMESTAMPING_TX_SCHED);
0874
0875 fprintf(stderr, "test ENQ + SND\n");
0876 do_test(family, SOF_TIMESTAMPING_TX_SCHED |
0877 SOF_TIMESTAMPING_TX_SOFTWARE);
0878
0879 if (cfg_proto == SOCK_STREAM) {
0880 fprintf(stderr, "\ntest ACK\n");
0881 do_test(family, SOF_TIMESTAMPING_TX_ACK);
0882
0883 fprintf(stderr, "\ntest SND + ACK\n");
0884 do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE |
0885 SOF_TIMESTAMPING_TX_ACK);
0886
0887 fprintf(stderr, "\ntest ENQ + SND + ACK\n");
0888 do_test(family, SOF_TIMESTAMPING_TX_SCHED |
0889 SOF_TIMESTAMPING_TX_SOFTWARE |
0890 SOF_TIMESTAMPING_TX_ACK);
0891 }
0892 }
0893
0894 const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
0895
0896 int main(int argc, char **argv)
0897 {
0898 if (argc == 1)
0899 usage(argv[0]);
0900
0901 parse_opt(argc, argv);
0902 resolve_hostname(argv[argc - 1]);
0903
0904 fprintf(stderr, "protocol: %s\n", sock_names[cfg_proto]);
0905 fprintf(stderr, "payload: %u\n", cfg_payload_len);
0906 fprintf(stderr, "server port: %u\n", dest_port);
0907 fprintf(stderr, "\n");
0908
0909 if (do_ipv4) {
0910 if (cfg_do_listen)
0911 do_listen(PF_INET, &daddr, sizeof(daddr));
0912 do_main(PF_INET);
0913 }
0914
0915 if (do_ipv6) {
0916 if (cfg_do_listen)
0917 do_listen(PF_INET6, &daddr6, sizeof(daddr6));
0918 do_main(PF_INET6);
0919 }
0920
0921 return test_failed;
0922 }