1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2014 Google Inc.
4 * Author: willemb@google.com (Willem de Bruijn)
6 * Test software tx timestamping, including
8 * - SCHED, SND and ACK timestamps
11 * - various packet sizes (to test GSO and TSO)
13 * Consult the command line arguments for help on running
14 * the various testcases.
16 * This test requires a dummy TCP server.
17 * A simple `nc6 [-u] -l -p $DESTPORT` will do
22 #include <arpa/inet.h>
23 #include <asm/types.h>
27 #include <linux/errqueue.h>
28 #include <linux/if_ether.h>
29 #include <linux/ipv6.h>
30 #include <linux/net_tstamp.h>
33 #include <netinet/in.h>
34 #include <netinet/ip.h>
35 #include <netinet/udp.h>
36 #include <netinet/tcp.h>
37 #include <netpacket/packet.h>
44 #include <sys/epoll.h>
45 #include <sys/ioctl.h>
46 #include <sys/select.h>
47 #include <sys/socket.h>
49 #include <sys/types.h>
53 #define NSEC_PER_USEC 1000L
54 #define USEC_PER_SEC 1000000L
55 #define NSEC_PER_SEC 1000000000LL
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
;
81 static struct sockaddr_in daddr
;
82 static struct sockaddr_in6 daddr6
;
83 static struct timespec ts_usr
;
85 static int saved_tskey
= -1;
86 static int saved_tskey_type
= -1;
95 static struct timing_event usr_enq
;
96 static struct timing_event usr_snd
;
97 static struct timing_event usr_ack
;
99 static bool test_failed
;
101 static int64_t timespec_to_ns64(struct timespec
*ts
)
103 return ts
->tv_sec
* NSEC_PER_SEC
+ ts
->tv_nsec
;
106 static int64_t timespec_to_us64(struct timespec
*ts
)
108 return ts
->tv_sec
* USEC_PER_SEC
+ ts
->tv_nsec
/ NSEC_PER_USEC
;
111 static void init_timing_event(struct timing_event
*te
)
119 static void add_timing_event(struct timing_event
*te
,
120 struct timespec
*t_start
, struct timespec
*t_end
)
122 int64_t ts_delta
= timespec_to_ns64(t_end
) - timespec_to_ns64(t_start
);
125 if (ts_delta
< te
->min
)
127 if (ts_delta
> te
->max
)
129 te
->total
+= ts_delta
;
132 static void validate_key(int tskey
, int tstype
)
136 /* compare key for each subsequent request
137 * must only test for one type, the first one requested
139 if (saved_tskey
== -1)
140 saved_tskey_type
= tstype
;
141 else if (saved_tskey_type
!= tstype
)
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
);
154 static void validate_timestamp(struct timespec
*cur
, int min_delay
)
156 int64_t cur64
, start64
;
159 cur64
= timespec_to_us64(cur
);
160 start64
= timespec_to_us64(&ts_usr
);
161 max_delay
= min_delay
+ cfg_delay_tolerance_usec
;
163 if (cur64
< start64
+ min_delay
|| cur64
> start64
+ max_delay
) {
164 fprintf(stderr
, "ERROR: %lu us expected between %d and %d\n",
165 cur64
- start64
, min_delay
, max_delay
);
170 static void __print_ts_delta_formatted(int64_t ts_delta
)
173 fprintf(stderr
, "%lu ns", ts_delta
);
175 fprintf(stderr
, "%lu us", ts_delta
/ NSEC_PER_USEC
);
178 static void __print_timestamp(const char *name
, struct timespec
*cur
,
179 uint32_t key
, int payload_len
)
183 if (!(cur
->tv_sec
| cur
->tv_nsec
))
187 fprintf(stderr
, " %s: %lu s %lu ns (seq=%u, len=%u)",
188 name
, cur
->tv_sec
, cur
->tv_nsec
,
191 fprintf(stderr
, " %s: %lu s %lu us (seq=%u, len=%u)",
192 name
, cur
->tv_sec
, cur
->tv_nsec
/ NSEC_PER_USEC
,
195 if (cur
!= &ts_usr
) {
196 ts_delta
= timespec_to_ns64(cur
) - timespec_to_ns64(&ts_usr
);
197 fprintf(stderr
, " (USR +");
198 __print_ts_delta_formatted(ts_delta
);
199 fprintf(stderr
, ")");
202 fprintf(stderr
, "\n");
205 static void print_timestamp_usr(void)
207 if (clock_gettime(CLOCK_REALTIME
, &ts_usr
))
208 error(1, errno
, "clock_gettime");
210 __print_timestamp(" USR", &ts_usr
, 0, 0);
213 static void print_timestamp(struct scm_timestamping
*tss
, int tstype
,
214 int tskey
, int payload_len
)
218 validate_key(tskey
, tstype
);
221 case SCM_TSTAMP_SCHED
:
223 validate_timestamp(&tss
->ts
[0], 0);
224 add_timing_event(&usr_enq
, &ts_usr
, &tss
->ts
[0]);
228 validate_timestamp(&tss
->ts
[0], cfg_delay_snd
);
229 add_timing_event(&usr_snd
, &ts_usr
, &tss
->ts
[0]);
233 validate_timestamp(&tss
->ts
[0], cfg_delay_ack
);
234 add_timing_event(&usr_ack
, &ts_usr
, &tss
->ts
[0]);
237 error(1, 0, "unknown timestamp type: %u",
240 __print_timestamp(tsname
, &tss
->ts
[0], tskey
, payload_len
);
243 static void print_timing_event(char *name
, struct timing_event
*te
)
248 fprintf(stderr
, " %s: count=%d", name
, te
->count
);
249 fprintf(stderr
, ", avg=");
250 __print_ts_delta_formatted((int64_t)(te
->total
/ te
->count
));
251 fprintf(stderr
, ", min=");
252 __print_ts_delta_formatted(te
->min
);
253 fprintf(stderr
, ", max=");
254 __print_ts_delta_formatted(te
->max
);
255 fprintf(stderr
, "\n");
258 /* TODO: convert to check_and_print payload once API is stable */
259 static void print_payload(char *data
, int len
)
269 fprintf(stderr
, "payload: ");
270 for (i
= 0; i
< len
; i
++)
271 fprintf(stderr
, "%02hhx ", data
[i
]);
272 fprintf(stderr
, "\n");
275 static void print_pktinfo(int family
, int ifindex
, void *saddr
, void *daddr
)
277 char sa
[INET6_ADDRSTRLEN
], da
[INET6_ADDRSTRLEN
];
279 fprintf(stderr
, " pktinfo: ifindex=%u src=%s dst=%s\n",
281 saddr
? inet_ntop(family
, saddr
, sa
, sizeof(sa
)) : "unknown",
282 daddr
? inet_ntop(family
, daddr
, da
, sizeof(da
)) : "unknown");
285 static void __epoll(int epfd
)
287 struct epoll_event events
;
290 memset(&events
, 0, sizeof(events
));
291 ret
= epoll_wait(epfd
, &events
, 1, cfg_poll_timeout
);
293 error(1, errno
, "epoll_wait");
296 static void __poll(int fd
)
298 struct pollfd pollfd
;
301 memset(&pollfd
, 0, sizeof(pollfd
));
303 ret
= poll(&pollfd
, 1, cfg_poll_timeout
);
305 error(1, errno
, "poll");
308 static void __recv_errmsg_cmsg(struct msghdr
*msg
, int payload_len
)
310 struct sock_extended_err
*serr
= NULL
;
311 struct scm_timestamping
*tss
= NULL
;
315 for (cm
= CMSG_FIRSTHDR(msg
);
317 cm
= CMSG_NXTHDR(msg
, cm
)) {
318 if (cm
->cmsg_level
== SOL_SOCKET
&&
319 cm
->cmsg_type
== SCM_TIMESTAMPING
) {
320 tss
= (void *) CMSG_DATA(cm
);
321 } else if ((cm
->cmsg_level
== SOL_IP
&&
322 cm
->cmsg_type
== IP_RECVERR
) ||
323 (cm
->cmsg_level
== SOL_IPV6
&&
324 cm
->cmsg_type
== IPV6_RECVERR
) ||
325 (cm
->cmsg_level
== SOL_PACKET
&&
326 cm
->cmsg_type
== PACKET_TX_TIMESTAMP
)) {
327 serr
= (void *) CMSG_DATA(cm
);
328 if (serr
->ee_errno
!= ENOMSG
||
329 serr
->ee_origin
!= SO_EE_ORIGIN_TIMESTAMPING
) {
330 fprintf(stderr
, "unknown ip error %d %d\n",
335 } else if (cm
->cmsg_level
== SOL_IP
&&
336 cm
->cmsg_type
== IP_PKTINFO
) {
337 struct in_pktinfo
*info
= (void *) CMSG_DATA(cm
);
338 print_pktinfo(AF_INET
, info
->ipi_ifindex
,
339 &info
->ipi_spec_dst
, &info
->ipi_addr
);
340 } else if (cm
->cmsg_level
== SOL_IPV6
&&
341 cm
->cmsg_type
== IPV6_PKTINFO
) {
342 struct in6_pktinfo
*info6
= (void *) CMSG_DATA(cm
);
343 print_pktinfo(AF_INET6
, info6
->ipi6_ifindex
,
344 NULL
, &info6
->ipi6_addr
);
346 fprintf(stderr
, "unknown cmsg %d,%d\n",
347 cm
->cmsg_level
, cm
->cmsg_type
);
350 print_timestamp(tss
, serr
->ee_info
, serr
->ee_data
,
359 fprintf(stderr
, "batched %d timestamps\n", batch
);
362 static int recv_errmsg(int fd
)
364 static char ctrl
[1024 /* overprovision*/];
365 static struct msghdr msg
;
370 data
= malloc(cfg_payload_len
);
372 error(1, 0, "malloc");
374 memset(&msg
, 0, sizeof(msg
));
375 memset(&entry
, 0, sizeof(entry
));
376 memset(ctrl
, 0, sizeof(ctrl
));
378 entry
.iov_base
= data
;
379 entry
.iov_len
= cfg_payload_len
;
380 msg
.msg_iov
= &entry
;
384 msg
.msg_control
= ctrl
;
385 msg
.msg_controllen
= sizeof(ctrl
);
387 ret
= recvmsg(fd
, &msg
, MSG_ERRQUEUE
);
388 if (ret
== -1 && errno
!= EAGAIN
)
389 error(1, errno
, "recvmsg");
392 __recv_errmsg_cmsg(&msg
, ret
);
393 if (cfg_show_payload
)
394 print_payload(data
, cfg_payload_len
);
401 static uint16_t get_ip_csum(const uint16_t *start
, int num_words
,
406 for (i
= 0; i
< num_words
; i
++)
410 sum
= (sum
& 0xFFFF) + (sum
>> 16);
415 static uint16_t get_udp_csum(const struct udphdr
*udph
, int alen
)
417 unsigned long pseudo_sum
, csum_len
;
418 const void *csum_start
= udph
;
420 pseudo_sum
= htons(IPPROTO_UDP
);
421 pseudo_sum
+= udph
->len
;
423 /* checksum ip(v6) addresses + udp header + payload */
424 csum_start
-= alen
* 2;
425 csum_len
= ntohs(udph
->len
) + alen
* 2;
427 return get_ip_csum(csum_start
, csum_len
>> 1, pseudo_sum
);
430 static int fill_header_ipv4(void *p
)
432 struct iphdr
*iph
= p
;
434 memset(iph
, 0, sizeof(*iph
));
439 iph
->saddr
= daddr
.sin_addr
.s_addr
; /* set for udp csum calc */
440 iph
->daddr
= daddr
.sin_addr
.s_addr
;
441 iph
->protocol
= IPPROTO_UDP
;
443 /* kernel writes saddr, csum, len */
448 static int fill_header_ipv6(void *p
)
450 struct ipv6hdr
*ip6h
= p
;
452 memset(ip6h
, 0, sizeof(*ip6h
));
455 ip6h
->payload_len
= htons(sizeof(struct udphdr
) + cfg_payload_len
);
456 ip6h
->nexthdr
= IPPROTO_UDP
;
457 ip6h
->hop_limit
= 64;
459 ip6h
->saddr
= daddr6
.sin6_addr
;
460 ip6h
->daddr
= daddr6
.sin6_addr
;
462 /* kernel does not write saddr in case of ipv6 */
464 return sizeof(*ip6h
);
467 static void fill_header_udp(void *p
, bool is_ipv4
)
469 struct udphdr
*udph
= p
;
471 udph
->source
= ntohs(dest_port
+ 1); /* spoof */
472 udph
->dest
= ntohs(dest_port
);
473 udph
->len
= ntohs(sizeof(*udph
) + cfg_payload_len
);
476 udph
->check
= get_udp_csum(udph
, is_ipv4
? sizeof(struct in_addr
) :
477 sizeof(struct in6_addr
));
480 static void do_test(int family
, unsigned int report_opt
)
482 char control
[CMSG_SPACE(sizeof(uint32_t))];
483 struct sockaddr_ll laddr
;
484 unsigned int sock_opt
;
485 struct cmsghdr
*cmsg
;
489 int fd
, i
, val
= 1, total_len
, epfd
= 0;
491 init_timing_event(&usr_enq
);
492 init_timing_event(&usr_snd
);
493 init_timing_event(&usr_ack
);
495 total_len
= cfg_payload_len
;
496 if (cfg_use_pf_packet
|| cfg_proto
== SOCK_RAW
) {
497 total_len
+= sizeof(struct udphdr
);
498 if (cfg_use_pf_packet
|| cfg_ipproto
== IPPROTO_RAW
)
499 if (family
== PF_INET
)
500 total_len
+= sizeof(struct iphdr
);
502 total_len
+= sizeof(struct ipv6hdr
);
504 /* special case, only rawv6_sendmsg:
505 * pass proto in sin6_port if not connected
506 * also see ANK comment in net/ipv4/raw.c
508 daddr6
.sin6_port
= htons(cfg_ipproto
);
511 buf
= malloc(total_len
);
513 error(1, 0, "malloc");
515 fd
= socket(cfg_use_pf_packet
? PF_PACKET
: family
,
516 cfg_proto
, cfg_ipproto
);
518 error(1, errno
, "socket");
521 struct epoll_event ev
;
523 memset(&ev
, 0, sizeof(ev
));
526 ev
.events
|= EPOLLET
;
527 epfd
= epoll_create(1);
529 error(1, errno
, "epoll_create");
530 if (epoll_ctl(epfd
, EPOLL_CTL_ADD
, fd
, &ev
))
531 error(1, errno
, "epoll_ctl");
534 /* reset expected key on each new socket */
537 if (cfg_proto
== SOCK_STREAM
) {
538 if (setsockopt(fd
, IPPROTO_TCP
, TCP_NODELAY
,
539 (char*) &val
, sizeof(val
)))
540 error(1, 0, "setsockopt no nagle");
542 if (family
== PF_INET
) {
543 if (connect(fd
, (void *) &daddr
, sizeof(daddr
)))
544 error(1, errno
, "connect ipv4");
546 if (connect(fd
, (void *) &daddr6
, sizeof(daddr6
)))
547 error(1, errno
, "connect ipv6");
551 if (cfg_do_pktinfo
) {
552 if (family
== AF_INET6
) {
553 if (setsockopt(fd
, SOL_IPV6
, IPV6_RECVPKTINFO
,
555 error(1, errno
, "setsockopt pktinfo ipv6");
557 if (setsockopt(fd
, SOL_IP
, IP_PKTINFO
,
559 error(1, errno
, "setsockopt pktinfo ipv4");
563 sock_opt
= SOF_TIMESTAMPING_SOFTWARE
|
564 SOF_TIMESTAMPING_OPT_CMSG
|
565 SOF_TIMESTAMPING_OPT_ID
;
568 sock_opt
|= report_opt
;
571 sock_opt
|= SOF_TIMESTAMPING_OPT_TSONLY
;
573 if (setsockopt(fd
, SOL_SOCKET
, SO_TIMESTAMPING
,
574 (char *) &sock_opt
, sizeof(sock_opt
)))
575 error(1, 0, "setsockopt timestamping");
577 for (i
= 0; i
< cfg_num_pkts
; i
++) {
578 memset(&msg
, 0, sizeof(msg
));
579 memset(buf
, 'a' + i
, total_len
);
581 if (cfg_use_pf_packet
|| cfg_proto
== SOCK_RAW
) {
584 if (cfg_use_pf_packet
|| cfg_ipproto
== IPPROTO_RAW
) {
585 if (family
== PF_INET
)
586 off
= fill_header_ipv4(buf
);
588 off
= fill_header_ipv6(buf
);
591 fill_header_udp(buf
+ off
, family
== PF_INET
);
594 print_timestamp_usr();
597 iov
.iov_len
= total_len
;
599 if (cfg_proto
!= SOCK_STREAM
) {
600 if (cfg_use_pf_packet
) {
601 memset(&laddr
, 0, sizeof(laddr
));
603 laddr
.sll_family
= AF_PACKET
;
604 laddr
.sll_ifindex
= 1;
605 laddr
.sll_protocol
= htons(family
== AF_INET
? ETH_P_IP
: ETH_P_IPV6
);
606 laddr
.sll_halen
= ETH_ALEN
;
608 msg
.msg_name
= (void *)&laddr
;
609 msg
.msg_namelen
= sizeof(laddr
);
610 } else if (family
== PF_INET
) {
611 msg
.msg_name
= (void *)&daddr
;
612 msg
.msg_namelen
= sizeof(daddr
);
614 msg
.msg_name
= (void *)&daddr6
;
615 msg
.msg_namelen
= sizeof(daddr6
);
623 memset(control
, 0, sizeof(control
));
625 msg
.msg_control
= control
;
626 msg
.msg_controllen
= sizeof(control
);
628 cmsg
= CMSG_FIRSTHDR(&msg
);
629 cmsg
->cmsg_level
= SOL_SOCKET
;
630 cmsg
->cmsg_type
= SO_TIMESTAMPING
;
631 cmsg
->cmsg_len
= CMSG_LEN(sizeof(uint32_t));
633 *((uint32_t *) CMSG_DATA(cmsg
)) = report_opt
;
636 val
= sendmsg(fd
, &msg
, 0);
637 if (val
!= total_len
)
638 error(1, errno
, "send");
640 /* wait for all errors to be queued, else ACKs arrive OOO */
642 usleep(cfg_sleep_usec
);
644 if (!cfg_busy_poll
) {
651 while (!recv_errmsg(fd
)) {}
654 print_timing_event("USR-ENQ", &usr_enq
);
655 print_timing_event("USR-SND", &usr_snd
);
656 print_timing_event("USR-ACK", &usr_ack
);
659 error(1, errno
, "close");
662 usleep(100 * NSEC_PER_USEC
);
665 static void __attribute__((noreturn
)) usage(const char *filepath
)
667 fprintf(stderr
, "\nUsage: %s [options] hostname\n"
668 "\nwhere options are:\n"
671 " -h: show this message\n"
672 " -b: busy poll to read from error queue\n"
673 " -c N: number of packets for each test\n"
674 " -C: use cmsg to set tstamp recording options\n"
675 " -e: use level-triggered epoll() instead of poll()\n"
676 " -E: use event-triggered epoll() instead of poll()\n"
677 " -F: poll()/epoll() waits forever for an event\n"
678 " -I: request PKTINFO\n"
679 " -l N: send N bytes at a time\n"
680 " -L listen on hostname and port\n"
681 " -n: set no-payload option\n"
682 " -N: print timestamps and durations in nsec (instead of usec)\n"
683 " -p N: connect to port N\n"
684 " -P: use PF_PACKET\n"
686 " -R: use raw (IP_HDRINCL)\n"
687 " -S N: usec to sleep before reading error queue\n"
688 " -t N: tolerance (usec) for timestamp validation\n"
690 " -v: validate SND delay (usec)\n"
691 " -V: validate ACK delay (usec)\n"
692 " -x: show payload (up to 70 bytes)\n",
697 static void parse_opt(int argc
, char **argv
)
702 while ((c
= getopt(argc
, argv
,
703 "46bc:CeEFhIl:LnNp:PrRS:t:uv:V:x")) != -1) {
712 cfg_busy_poll
= true;
715 cfg_num_pkts
= strtoul(optarg
, NULL
, 10);
721 cfg_use_epoll
= true;
724 cfg_use_epoll
= true;
727 cfg_poll_timeout
= -1;
730 cfg_do_pktinfo
= true;
733 cfg_payload_len
= strtoul(optarg
, NULL
, 10);
736 cfg_do_listen
= true;
739 cfg_loop_nodata
= true;
742 cfg_print_nsec
= true;
745 dest_port
= strtoul(optarg
, NULL
, 10);
749 cfg_use_pf_packet
= true;
750 cfg_proto
= SOCK_DGRAM
;
755 cfg_proto
= SOCK_RAW
;
756 cfg_ipproto
= IPPROTO_UDP
;
760 cfg_proto
= SOCK_RAW
;
761 cfg_ipproto
= IPPROTO_RAW
;
764 cfg_sleep_usec
= strtoul(optarg
, NULL
, 10);
767 cfg_delay_tolerance_usec
= strtoul(optarg
, NULL
, 10);
771 cfg_proto
= SOCK_DGRAM
;
772 cfg_ipproto
= IPPROTO_UDP
;
775 cfg_delay_snd
= strtoul(optarg
, NULL
, 10);
778 cfg_delay_ack
= strtoul(optarg
, NULL
, 10);
781 cfg_show_payload
= true;
789 if (!cfg_payload_len
)
790 error(1, 0, "payload may not be nonzero");
791 if (cfg_proto
!= SOCK_STREAM
&& cfg_payload_len
> 1472)
792 error(1, 0, "udp packet might exceed expected MTU");
793 if (!do_ipv4
&& !do_ipv6
)
794 error(1, 0, "pass -4 or -6, not both");
796 error(1, 0, "pass -P, -r, -R or -u, not multiple");
797 if (cfg_do_pktinfo
&& cfg_use_pf_packet
)
798 error(1, 0, "cannot ask for pktinfo over pf_packet");
799 if (cfg_busy_poll
&& cfg_use_epoll
)
800 error(1, 0, "pass epoll or busy_poll, not both");
802 if (optind
!= argc
- 1)
803 error(1, 0, "missing required hostname argument");
806 static void resolve_hostname(const char *hostname
)
808 struct addrinfo hints
= { .ai_family
= do_ipv4
? AF_INET
: AF_INET6
};
809 struct addrinfo
*addrs
, *cur
;
810 int have_ipv4
= 0, have_ipv6
= 0;
813 if (getaddrinfo(hostname
, NULL
, &hints
, &addrs
))
814 error(1, errno
, "getaddrinfo");
817 while (cur
&& !have_ipv4
&& !have_ipv6
) {
818 if (!have_ipv4
&& cur
->ai_family
== AF_INET
) {
819 memcpy(&daddr
, cur
->ai_addr
, sizeof(daddr
));
820 daddr
.sin_port
= htons(dest_port
);
823 else if (!have_ipv6
&& cur
->ai_family
== AF_INET6
) {
824 memcpy(&daddr6
, cur
->ai_addr
, sizeof(daddr6
));
825 daddr6
.sin6_port
= htons(dest_port
);
833 if (do_ipv6
&& hints
.ai_family
!= AF_INET6
) {
834 hints
.ai_family
= AF_INET6
;
838 do_ipv4
&= have_ipv4
;
839 do_ipv6
&= have_ipv6
;
842 static void do_listen(int family
, void *addr
, int alen
)
846 type
= cfg_proto
== SOCK_RAW
? SOCK_DGRAM
: cfg_proto
;
848 fd
= socket(family
, type
, 0);
850 error(1, errno
, "socket rx");
852 if (bind(fd
, addr
, alen
))
853 error(1, errno
, "bind rx");
855 if (type
== SOCK_STREAM
&& listen(fd
, 10))
856 error(1, errno
, "listen rx");
858 /* leave fd open, will be closed on process exit.
859 * this enables connect() to succeed and avoids icmp replies
863 static void do_main(int family
)
865 fprintf(stderr
, "family: %s %s\n",
866 family
== PF_INET
? "INET" : "INET6",
867 cfg_use_pf_packet
? "(PF_PACKET)" : "");
869 fprintf(stderr
, "test SND\n");
870 do_test(family
, SOF_TIMESTAMPING_TX_SOFTWARE
);
872 fprintf(stderr
, "test ENQ\n");
873 do_test(family
, SOF_TIMESTAMPING_TX_SCHED
);
875 fprintf(stderr
, "test ENQ + SND\n");
876 do_test(family
, SOF_TIMESTAMPING_TX_SCHED
|
877 SOF_TIMESTAMPING_TX_SOFTWARE
);
879 if (cfg_proto
== SOCK_STREAM
) {
880 fprintf(stderr
, "\ntest ACK\n");
881 do_test(family
, SOF_TIMESTAMPING_TX_ACK
);
883 fprintf(stderr
, "\ntest SND + ACK\n");
884 do_test(family
, SOF_TIMESTAMPING_TX_SOFTWARE
|
885 SOF_TIMESTAMPING_TX_ACK
);
887 fprintf(stderr
, "\ntest ENQ + SND + ACK\n");
888 do_test(family
, SOF_TIMESTAMPING_TX_SCHED
|
889 SOF_TIMESTAMPING_TX_SOFTWARE
|
890 SOF_TIMESTAMPING_TX_ACK
);
894 const char *sock_names
[] = { NULL
, "TCP", "UDP", "RAW" };
896 int main(int argc
, char **argv
)
901 parse_opt(argc
, argv
);
902 resolve_hostname(argv
[argc
- 1]);
904 fprintf(stderr
, "protocol: %s\n", sock_names
[cfg_proto
]);
905 fprintf(stderr
, "payload: %u\n", cfg_payload_len
);
906 fprintf(stderr
, "server port: %u\n", dest_port
);
907 fprintf(stderr
, "\n");
911 do_listen(PF_INET
, &daddr
, sizeof(daddr
));
917 do_listen(PF_INET6
, &daddr6
, sizeof(daddr6
));