@@ -70,17 +70,67 @@ static int do_ipv4 = 1;
70
70
static int do_ipv6 = 1 ;
71
71
static int cfg_payload_len = 10 ;
72
72
static int cfg_poll_timeout = 100 ;
73
+ static int cfg_delay_snd ;
74
+ static int cfg_delay_ack ;
73
75
static bool cfg_show_payload ;
74
76
static bool cfg_do_pktinfo ;
75
77
static bool cfg_loop_nodata ;
76
78
static bool cfg_no_delay ;
77
79
static bool cfg_use_cmsg ;
78
80
static bool cfg_use_pf_packet ;
81
+ static bool cfg_do_listen ;
79
82
static uint16_t dest_port = 9000 ;
80
83
81
84
static struct sockaddr_in daddr ;
82
85
static struct sockaddr_in6 daddr6 ;
83
- static struct timespec ts_prev ;
86
+ static struct timespec ts_usr ;
87
+
88
+ static int saved_tskey = -1 ;
89
+ static int saved_tskey_type = -1 ;
90
+
91
+ static bool test_failed ;
92
+
93
+ static int64_t timespec_to_us64 (struct timespec * ts )
94
+ {
95
+ return ts -> tv_sec * 1000 * 1000 + ts -> tv_nsec / 1000 ;
96
+ }
97
+
98
+ static 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
+
120
+ static 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
+ }
84
134
85
135
static void __print_timestamp (const char * name , struct timespec * cur ,
86
136
uint32_t key , int payload_len )
@@ -92,48 +142,40 @@ static void __print_timestamp(const char *name, struct timespec *cur,
92
142
name , cur -> tv_sec , cur -> tv_nsec / 1000 ,
93
143
key , payload_len );
94
144
95
- if ((ts_prev .tv_sec | ts_prev .tv_nsec )) {
96
- int64_t cur_ms , prev_ms ;
97
-
98
- cur_ms = (long ) cur -> tv_sec * 1000 * 1000 ;
99
- cur_ms += cur -> tv_nsec / 1000 ;
100
-
101
- prev_ms = (long ) ts_prev .tv_sec * 1000 * 1000 ;
102
- prev_ms += ts_prev .tv_nsec / 1000 ;
145
+ if (cur != & ts_usr )
146
+ fprintf (stderr , " (USR %+" PRId64 " us)" ,
147
+ timespec_to_us64 (cur ) - timespec_to_us64 (& ts_usr ));
103
148
104
- fprintf (stderr , " (%+" PRId64 " us)" , cur_ms - prev_ms );
105
- }
106
-
107
- ts_prev = * cur ;
108
149
fprintf (stderr , "\n" );
109
150
}
110
151
111
152
static void print_timestamp_usr (void )
112
153
{
113
- struct timespec ts ;
114
- struct timeval tv ; /* avoid dependency on -lrt */
115
-
116
- gettimeofday (& tv , NULL );
117
- ts .tv_sec = tv .tv_sec ;
118
- ts .tv_nsec = tv .tv_usec * 1000 ;
154
+ if (clock_gettime (CLOCK_REALTIME , & ts_usr ))
155
+ error (1 , errno , "clock_gettime" );
119
156
120
- __print_timestamp (" USR" , & ts , 0 , 0 );
157
+ __print_timestamp (" USR" , & ts_usr , 0 , 0 );
121
158
}
122
159
123
160
static void print_timestamp (struct scm_timestamping * tss , int tstype ,
124
161
int tskey , int payload_len )
125
162
{
126
163
const char * tsname ;
127
164
165
+ validate_key (tskey , tstype );
166
+
128
167
switch (tstype ) {
129
168
case SCM_TSTAMP_SCHED :
130
169
tsname = " ENQ" ;
170
+ validate_timestamp (& tss -> ts [0 ], 0 );
131
171
break ;
132
172
case SCM_TSTAMP_SND :
133
173
tsname = " SND" ;
174
+ validate_timestamp (& tss -> ts [0 ], cfg_delay_snd );
134
175
break ;
135
176
case SCM_TSTAMP_ACK :
136
177
tsname = " ACK" ;
178
+ validate_timestamp (& tss -> ts [0 ], cfg_delay_ack );
137
179
break ;
138
180
default :
139
181
error (1 , 0 , "unknown timestamp type: %u" ,
@@ -389,6 +431,9 @@ static void do_test(int family, unsigned int report_opt)
389
431
if (fd < 0 )
390
432
error (1 , errno , "socket" );
391
433
434
+ /* reset expected key on each new socket */
435
+ saved_tskey = -1 ;
436
+
392
437
if (cfg_proto == SOCK_STREAM ) {
393
438
if (setsockopt (fd , IPPROTO_TCP , TCP_NODELAY ,
394
439
(char * ) & val , sizeof (val )))
@@ -431,7 +476,6 @@ static void do_test(int family, unsigned int report_opt)
431
476
432
477
for (i = 0 ; i < cfg_num_pkts ; i ++ ) {
433
478
memset (& msg , 0 , sizeof (msg ));
434
- memset (& ts_prev , 0 , sizeof (ts_prev ));
435
479
memset (buf , 'a' + i , total_len );
436
480
437
481
if (cfg_use_pf_packet || cfg_proto == SOCK_RAW ) {
@@ -506,7 +550,7 @@ static void do_test(int family, unsigned int report_opt)
506
550
error (1 , errno , "close" );
507
551
508
552
free (buf );
509
- usleep (400 * 1000 );
553
+ usleep (100 * 1000 );
510
554
}
511
555
512
556
static void __attribute__((noreturn )) usage (const char * filepath )
@@ -522,12 +566,15 @@ static void __attribute__((noreturn)) usage(const char *filepath)
522
566
" -F: poll() waits forever for an event\n"
523
567
" -I: request PKTINFO\n"
524
568
" -l N: send N bytes at a time\n"
569
+ " -L listen on hostname and port\n"
525
570
" -n: set no-payload option\n"
526
571
" -p N: connect to port N\n"
527
572
" -P: use PF_PACKET\n"
528
573
" -r: use raw\n"
529
574
" -R: use raw (IP_HDRINCL)\n"
530
575
" -u: use udp\n"
576
+ " -v: validate SND delay (usec)\n"
577
+ " -V: validate ACK delay (usec)\n"
531
578
" -x: show payload (up to 70 bytes)\n" ,
532
579
filepath );
533
580
exit (1 );
@@ -538,7 +585,7 @@ static void parse_opt(int argc, char **argv)
538
585
int proto_count = 0 ;
539
586
int c ;
540
587
541
- while ((c = getopt (argc , argv , "46c:CDFhIl:np:PrRux " )) != -1 ) {
588
+ while ((c = getopt (argc , argv , "46c:CDFhIl:Lnp:PrRuv:V:x " )) != -1 ) {
542
589
switch (c ) {
543
590
case '4' :
544
591
do_ipv6 = 0 ;
@@ -564,6 +611,9 @@ static void parse_opt(int argc, char **argv)
564
611
case 'l' :
565
612
cfg_payload_len = strtoul (optarg , NULL , 10 );
566
613
break ;
614
+ case 'L' :
615
+ cfg_do_listen = true;
616
+ break ;
567
617
case 'n' :
568
618
cfg_loop_nodata = true;
569
619
break ;
@@ -591,6 +641,12 @@ static void parse_opt(int argc, char **argv)
591
641
cfg_proto = SOCK_DGRAM ;
592
642
cfg_ipproto = IPPROTO_UDP ;
593
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 ;
594
650
case 'x' :
595
651
cfg_show_payload = true;
596
652
break ;
@@ -651,6 +707,27 @@ static void resolve_hostname(const char *hostname)
651
707
do_ipv6 &= have_ipv6 ;
652
708
}
653
709
710
+ static 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
+
654
731
static void do_main (int family )
655
732
{
656
733
fprintf (stderr , "family: %s %s\n" ,
@@ -697,10 +774,17 @@ int main(int argc, char **argv)
697
774
fprintf (stderr , "server port: %u\n" , dest_port );
698
775
fprintf (stderr , "\n" );
699
776
700
- if (do_ipv4 )
777
+ if (do_ipv4 ) {
778
+ if (cfg_do_listen )
779
+ do_listen (PF_INET , & daddr , sizeof (daddr ));
701
780
do_main (PF_INET );
702
- if (do_ipv6 )
781
+ }
782
+
783
+ if (do_ipv6 ) {
784
+ if (cfg_do_listen )
785
+ do_listen (PF_INET6 , & daddr6 , sizeof (daddr6 ));
703
786
do_main (PF_INET6 );
787
+ }
704
788
705
- return 0 ;
789
+ return test_failed ;
706
790
}
0 commit comments