8 #include <sys/socket.h>
9 #include <netinet/in.h>
11 #include <arpa/inet.h>
12 #include <linux/can.h>
19 #define printdbg(...) printf( __VA_ARGS__ )
24 #define BENCH_FLAG_N 1
25 #define BENCH_FLAG_SRC 2
26 #define BENCH_FLAG_DST 4
27 #define BENCH_FLAG_TIMEO 8
36 int can_sock_create( int ifindex );
37 int udp_sock_create( struct in_addr ip, unsigned int port );
45 struct cegw_if ceif[2]; /* 0 -> src, 1 -> dst */
49 pthread_barrier_t barrier;
50 struct timespec* tx_time, * rx_time;
52 void* thr_recv( void* arg )
60 if( d.ceif[1].type == IF_CAN )
61 sock = can_sock_create( d.ceif[1].can.ifindex );
63 sock = udp_sock_create( d.ceif[1].eth.ip, d.ceif[1].eth.port );
70 ret = setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, &d.timeo, sizeof(d.timeo) );
74 pthread_barrier_wait( &barrier );
77 for( i=0; i<d.n; i++ )
79 ret = recvfrom( sock, &cf, sizeof(cf), 0, NULL, 0 );
80 printdbg( "ret=%d\n", ret );
84 puts( "cegwbench: recv timed out\n" );
87 seq = *((int*)cf.data);
88 clock_gettime( CLOCK_REALTIME, &rx_time[ seq ] );
89 printdbg( "recv: cf.data=%d\n", seq );
90 if( d.mode == BENCH_MODE_ONEATTIME )
92 pthread_barrier_wait( &barrier );
100 int timespec_subtract( struct timespec *result, struct timespec *x, struct timespec *yy )
102 struct timespec ylocal = *yy, *y = &ylocal;
103 /* Perform the carry for the later subtraction by updating Y. */
104 if( x->tv_nsec < y->tv_nsec )
106 int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
107 y->tv_nsec -= 1000000000 * nsec;
110 if (x->tv_nsec - y->tv_nsec > 1000000000)
112 int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
113 y->tv_nsec += 1000000000 * nsec;
117 /* Compute the time remaining to wait.
118 * `tv_nsec' is certainly positive. */
119 result->tv_sec = x->tv_sec - y->tv_sec;
120 result->tv_nsec = x->tv_nsec - y->tv_nsec;
121 /* Return 1 if result is negative. */
122 return x->tv_sec < y->tv_sec;
125 int udp_sock_create( struct in_addr ip, unsigned int port )
127 struct sockaddr_in addr_udp;
130 addr_udp.sin_family = AF_INET;
131 addr_udp.sin_port = htons( port );
132 addr_udp.sin_addr.s_addr = INADDR_ANY;
134 udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
137 fprintf( stderr, "error: udp socket creation failed\n" );
141 if( bind(udp_sock, (struct sockaddr*)&addr_udp, sizeof(addr_udp)) != 0 )
143 fprintf( stderr, "error: udp socket binding failed\n" );
152 * @return can socket fd, or -1 on failure
154 int can_sock_create( int ifindex )
157 struct sockaddr_can addr_can;
159 addr_can.can_family = AF_CAN;
160 addr_can.can_ifindex = ifindex;
162 can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
165 fprintf( stderr, "error: can socket creation failed\n" );
169 if( bind(can_sock, (struct sockaddr*)&addr_can, sizeof(addr_can)) != 0 )
171 fprintf( stderr, "error: can socket binding failed\n" );
178 void dump_arg( int argc, char* argv[] )
183 for( i=0; i<argc; i++ )
185 printf( "%s ", argv[i] );
190 int read_mode( char* in )
192 if( strcmp( in, "asap" ) == 0 )
193 return BENCH_MODE_ASAP;
194 if( strcmp( in, "oneattime") == 0 )
195 return BENCH_MODE_ONEATTIME;
196 if( strcmp( in, "period" ) == 0 )
197 return BENCH_MODE_PERIOD;
199 return BENCH_MODE_UNDEF;
202 int main( int argc, char* argv[] )
215 d.mode = BENCH_MODE_ASAP;
219 struct option longopt[] =
221 { "mode", 0, NULL, 'm' },
227 opt = getopt( argc, argv, "s:d:m:n:t:" );
233 d.optflag |= BENCH_FLAG_SRC;
234 if( read_if( optarg, &d.ceif[0] ) != 0 )
241 d.optflag |= BENCH_FLAG_DST;
242 if( read_if( optarg, &d.ceif[1] ) )
249 tmp = read_mode( optarg );
250 if( tmp == BENCH_MODE_UNDEF )
252 perr( "benchmarking mode unknown" );
258 d.optflag |= BENCH_FLAG_N;
259 d.n = atoi( optarg );
262 d.optflag |= BENCH_FLAG_TIMEO;
263 if( sscanf( optarg, "%ld", &d.timeo.tv_sec ) != 1 )
265 perr( "timeout mismatch" );
277 /* '-n' option is mandatory and its value is >0 */
278 if( d.optflag & BENCH_FLAG_N )
282 perr( "'-n' should be at least 1." );
286 perr( "'-n' is mandatory." );
290 /* '-s' and '-d' should be defined and different iftype */
291 if( (d.optflag & BENCH_FLAG_SRC) && (d.optflag & BENCH_FLAG_DST) )
293 if( !(d.ceif[0].type == IF_CAN && d.ceif[1].type == IF_ETH_UDP) &&
294 !(d.ceif[0].type == IF_ETH_UDP && d.ceif[1].type == IF_CAN ) )
296 perr( "'-s' and '-d' should be different interface type." );
301 perr( "'-s' and '-d' should be defined." );
305 tx_time = malloc( d.n*sizeof(struct timespec) );
306 rx_time = malloc( d.n*sizeof(struct timespec) );
308 pthread_barrier_init( &barrier, NULL, 2 );
309 pthread_create( &thr, NULL, thr_recv, &d );
312 struct sockaddr* addr;
313 struct sockaddr_can addr_can;
314 struct sockaddr_in addr_udp;
317 if( d.ceif[0].type == IF_CAN )
319 sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
320 addr_can.can_family = AF_CAN;
321 addr_can.can_ifindex = d.ceif[0].can.ifindex;
322 addr = (struct sockaddr*)&addr_can;
323 addr_size = sizeof( addr_can );
327 sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
328 addr_udp.sin_family = AF_INET;
329 addr_udp.sin_addr = d.ceif[0].eth.ip;
330 addr_udp.sin_port = htons( d.ceif[0].eth.port );
331 addr = (struct sockaddr*)&addr_udp;
332 addr_size = sizeof( addr_udp );
334 if( sock < 0 ) /* ToDo: ? */
337 pthread_barrier_wait( &barrier );
340 for( i=0; i<d.n; i++ )
344 memcpy( cf.data, &i, sizeof(i) );
346 clock_gettime( CLOCK_REALTIME, &tx_time[i] );
347 ret = sendto( sock, &cf, sizeof(cf), 0, addr, addr_size ); /* ToDo: check ret */
348 printdbg( "sending(%d)\n", ret );
349 if( d.mode == BENCH_MODE_ONEATTIME )
351 pthread_barrier_wait( &barrier );
355 close( sock ); /* ToDo: shutdown? */
356 pthread_join( thr, &thr_ret );
358 if( thr_ret != NULL )
364 dump_arg( argc, argv );
365 for( i=0; i<d.n; i++ )
367 timespec_subtract( &res, &rx_time[i], &tx_time[i] );
369 time = res.tv_sec*1000000000.0f + (float)res.tv_nsec;
370 printf( "%f\t", time );
374 pthread_barrier_destroy( &barrier );