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 */
58static int cfg_proto = SOCK_STREAM;
59static int cfg_ipproto = IPPROTO_TCP;
60static int cfg_num_pkts = 4;
61static int do_ipv4 = 1;
62static int do_ipv6 = 1;
63static int cfg_payload_len = 10;
64static int cfg_poll_timeout = 100;
65static int cfg_delay_snd;
66static int cfg_delay_ack;
67static int cfg_delay_tolerance_usec = 500;
68static bool cfg_show_payload;
69static bool cfg_do_pktinfo;
70static bool cfg_busy_poll;
71static int cfg_sleep_usec = 50 * 1000;
72static bool cfg_loop_nodata;
73static bool cfg_use_cmsg;
74static bool cfg_use_pf_packet;
75static bool cfg_use_epoll;
76static bool cfg_epollet;
77static bool cfg_do_listen;
78static uint16_t dest_port = 9000;
79static bool cfg_print_nsec;
80
81static struct sockaddr_in daddr;
82static struct sockaddr_in6 daddr6;
83static struct timespec ts_usr;
84
85static int saved_tskey = -1;
86static int saved_tskey_type = -1;
87
88struct timing_event {
89 int64_t min;
90 int64_t max;
91 int64_t total;
92 int count;
93};
94
95static struct timing_event usr_enq;
96static struct timing_event usr_snd;
97static struct timing_event usr_ack;
98
99static bool test_failed;
100
101static int64_t timespec_to_ns64(struct timespec *ts)
102{
103 return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec;
104}
105
106static 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
111static 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
119static 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(ts: t_end) - timespec_to_ns64(ts: 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
132static 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
154static 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(ts: cur);
160 start64 = timespec_to_us64(ts: &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
171static 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
179static 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(ts: cur) - timespec_to_ns64(ts: &ts_usr);
198 fprintf(stderr, " (USR +");
199 __print_ts_delta_formatted(ts_delta);
200 fprintf(stderr, ")");
201 }
202
203 fprintf(stderr, "\n");
204}
205
206static void print_timestamp_usr(void)
207{
208 if (clock_gettime(CLOCK_REALTIME, &ts_usr))
209 error(1, errno, "clock_gettime");
210
211 __print_timestamp(name: " USR", cur: &ts_usr, key: 0, payload_len: 0);
212}
213
214static 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(cur: &tss->ts[0], min_delay: 0);
225 add_timing_event(te: &usr_enq, t_start: &ts_usr, t_end: &tss->ts[0]);
226 break;
227 case SCM_TSTAMP_SND:
228 tsname = " SND";
229 validate_timestamp(cur: &tss->ts[0], min_delay: cfg_delay_snd);
230 add_timing_event(te: &usr_snd, t_start: &ts_usr, t_end: &tss->ts[0]);
231 break;
232 case SCM_TSTAMP_ACK:
233 tsname = " ACK";
234 validate_timestamp(cur: &tss->ts[0], min_delay: cfg_delay_ack);
235 add_timing_event(te: &usr_ack, t_start: &ts_usr, t_end: &tss->ts[0]);
236 break;
237 default:
238 error(1, 0, "unknown timestamp type: %u",
239 tstype);
240 }
241 __print_timestamp(name: tsname, cur: &tss->ts[0], key: tskey, payload_len);
242}
243
244static 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(ts_delta: (int64_t)(te->total / te->count));
252 fprintf(stderr, ", min=");
253 __print_ts_delta_formatted(ts_delta: te->min);
254 fprintf(stderr, ", max=");
255 __print_ts_delta_formatted(ts_delta: te->max);
256 fprintf(stderr, "\n");
257}
258
259/* TODO: convert to check_and_print payload once API is stable */
260static 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
276static 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
286static 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
297static 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
309static 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, ifindex: info->ipi_ifindex,
340 saddr: &info->ipi_spec_dst, daddr: &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, ifindex: info6->ipi6_ifindex,
345 NULL, daddr: &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, tstype: serr->ee_info, tskey: 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
363static 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: &msg, payload_len: ret);
394 if (cfg_show_payload)
395 print_payload(data, len: cfg_payload_len);
396 }
397
398 free(data);
399 return ret == -1;
400}
401
402static 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
416static 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(start: csum_start, num_words: csum_len >> 1, sum: pseudo_sum);
429}
430
431static 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
449static 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
468static 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, alen: is_ipv4 ? sizeof(struct in_addr) :
478 sizeof(struct in6_addr));
479}
480
481static 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(te: &usr_enq);
493 init_timing_event(te: &usr_snd);
494 init_timing_event(te: &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(p: buf);
588 else
589 off = fill_header_ipv6(p: buf);
590 }
591
592 fill_header_udp(p: buf + off, is_ipv4: 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(name: "USR-ENQ", te: &usr_enq);
656 print_timing_event(name: "USR-SND", te: &usr_snd);
657 print_timing_event(name: "USR-ACK", te: &usr_ack);
658
659 if (close(fd))
660 error(1, errno, "close");
661
662 free(buf);
663 usleep(100 * NSEC_PER_USEC);
664}
665
666static 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
698static 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(filepath: 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
807static 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
813retry:
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
843static 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
864static 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, report_opt: SOF_TIMESTAMPING_TX_SOFTWARE);
872
873 fprintf(stderr, "test ENQ\n");
874 do_test(family, report_opt: SOF_TIMESTAMPING_TX_SCHED);
875
876 fprintf(stderr, "test ENQ + SND\n");
877 do_test(family, report_opt: 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, report_opt: SOF_TIMESTAMPING_TX_ACK);
883
884 fprintf(stderr, "\ntest SND + ACK\n");
885 do_test(family, report_opt: SOF_TIMESTAMPING_TX_SOFTWARE |
886 SOF_TIMESTAMPING_TX_ACK);
887
888 fprintf(stderr, "\ntest ENQ + SND + ACK\n");
889 do_test(family, report_opt: SOF_TIMESTAMPING_TX_SCHED |
890 SOF_TIMESTAMPING_TX_SOFTWARE |
891 SOF_TIMESTAMPING_TX_ACK);
892 }
893}
894
895const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
896
897int main(int argc, char **argv)
898{
899 if (argc == 1)
900 usage(filepath: argv[0]);
901
902 parse_opt(argc, argv);
903 resolve_hostname(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, addr: &daddr, alen: sizeof(daddr));
913 do_main(PF_INET);
914 }
915
916 if (do_ipv6) {
917 if (cfg_do_listen)
918 do_listen(PF_INET6, addr: &daddr6, alen: sizeof(daddr6));
919 do_main(PF_INET6);
920 }
921
922 return test_failed;
923}
924

source code of linux/tools/testing/selftests/net/txtimestamp.c