]> rtime.felk.cvut.cz Git - can-eth-gw.git/blob - utils/cegwbench/cegwbench.c
improved rtnl processing, some error checks added
[can-eth-gw.git] / utils / cegwbench / cegwbench.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <getopt.h>
6 #include <time.h>
7 #include <math.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <net/if.h>
11 #include <arpa/inet.h>
12 #include <linux/can.h>
13 #include <pthread.h>
14 #include "cegwerr.h"
15 #include "readif.h"
16
17 /**
18  * ToDo:
19  * [ ] consider can timestamp
20  */
21
22 //#define BENCH_DEBUG
23 #ifdef BENCH_DEBUG
24 #define printdbg(...) printf( __VA_ARGS__ )
25 #else
26 #define printdbg(...)
27 #endif
28
29 #define BENCH_FLAG_N 1
30 #define BENCH_FLAG_SRC 2
31 #define BENCH_FLAG_DST 4
32
33 enum {
34         BENCH_MODE_UNDEF,
35         BENCH_MODE_ASAP,
36         BENCH_MODE_ONEATTIME,
37         BENCH_MODE_PERIOD
38 };
39
40 int can_sock_create( int ifindex );
41 int udp_sock_create( struct in_addr ip, unsigned int port );
42
43 struct optdata
44 {
45         int optflag;
46         int mode;
47         int n;
48         struct cegw_if ceif[2]; /* 0 -> src, 1 -> dst */
49 };
50
51 struct optdata d;
52 pthread_barrier_t barrier;
53 struct timespec* tx_time, * rx_time;
54
55 void* thr_recv( void* arg )
56 {
57         int sock;
58         struct can_frame cf;
59         int i;
60         int seq;
61
62         if( d.ceif[1].type == IF_CAN )
63                 sock = can_sock_create( d.ceif[1].can.ifindex );
64         else
65                 sock = udp_sock_create( d.ceif[1].eth.ip, d.ceif[1].eth.port );
66         if( sock == -1 )
67         {
68         /* ToDo: handle */
69                 return NULL;
70         }
71
72         pthread_barrier_wait( &barrier );
73
74         /* recv */
75         for( i=0; i<d.n; i++ )
76         {
77                 recvfrom( sock, &cf, sizeof(cf), 0, NULL, 0 );
78                 seq = *((int*)cf.data);
79                 clock_gettime( CLOCK_REALTIME, &rx_time[ seq ] );
80                 printdbg( "recv: (id=%d)%d\n", cf.can_id, seq );
81                 if( d.mode == BENCH_MODE_ONEATTIME )
82                 {
83                         pthread_barrier_wait( &barrier );
84                 }
85         }
86
87         close( sock );
88         return NULL;
89 }
90
91 int timespec_subtract( struct timespec *result, struct timespec *x, struct timespec *yy )
92 {
93         struct timespec ylocal = *yy, *y = &ylocal;
94 /* Perform the carry for the later subtraction by updating Y. */
95         if( x->tv_nsec < y->tv_nsec )
96         {
97                 int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
98                 y->tv_nsec -= 1000000000 * nsec;
99                 y->tv_sec += nsec;
100         }
101         if (x->tv_nsec - y->tv_nsec > 1000000000)
102         {
103                 int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
104                 y->tv_nsec += 1000000000 * nsec;
105                 y->tv_sec -= nsec;
106         }
107
108         /* Compute the time remaining to wait.
109          *         `tv_nsec' is certainly positive. */
110         result->tv_sec = x->tv_sec - y->tv_sec;
111         result->tv_nsec = x->tv_nsec - y->tv_nsec;
112         /* Return 1 if result is negative. */
113         return x->tv_sec < y->tv_sec;
114 }
115
116 int udp_sock_create( struct in_addr ip, unsigned int port  )
117 {
118         struct sockaddr_in addr_udp;
119         int udp_sock;
120
121         addr_udp.sin_family = AF_INET;
122         addr_udp.sin_port = htons( port );
123         addr_udp.sin_addr.s_addr = INADDR_ANY;
124
125         udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
126         if( udp_sock < 0 )
127         {
128                 fprintf( stderr, "error: udp socket creation failed\n" );
129                 return -1;
130         }
131
132         if( bind(udp_sock, (struct sockaddr*)&addr_udp, sizeof(addr_udp)) != 0 )
133         {
134                 fprintf( stderr, "error: udp socket binding failed\n" );
135                 return -1;
136         }
137
138         return udp_sock;
139 }
140
141 /**
142  * can_sock_create()
143  * @return can socket fd, or -1 on failure
144  */
145 int can_sock_create( int ifindex )
146 {
147         int can_sock;
148         struct sockaddr_can addr_can;
149
150         addr_can.can_family = AF_CAN;
151         addr_can.can_ifindex = ifindex;
152         
153         can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
154         if( can_sock < 0 )
155         {
156                 fprintf( stderr, "error: can socket creation failed\n" );
157                 return -1;
158         }
159
160         if( bind(can_sock, (struct sockaddr*)&addr_can, sizeof(addr_can)) != 0 )
161         {
162                 fprintf( stderr, "error: can socket binding failed\n" );
163                 return -1;
164         }
165
166         return can_sock;
167 }
168
169 void dump_arg( int argc, char* argv[] )
170 {
171         int i;
172
173         putchar( '#' );
174         for( i=0; i<argc; i++ )
175         {
176                 printf( "%s ", argv[i] );
177         }
178         putchar( '\n' );        
179 }
180
181 int read_mode( char* in )
182 {
183         if( strcmp( in, "asap" ) == 0 )
184                 return BENCH_MODE_ASAP;
185         if( strcmp( in, "oneattime") == 0 )
186                 return BENCH_MODE_ONEATTIME;
187         if( strcmp( in, "period" ) == 0 )
188                 return BENCH_MODE_PERIOD;
189
190         return BENCH_MODE_UNDEF;
191 }
192
193 int main( int argc, char* argv[] )
194 {
195         char opt;
196         struct can_frame cf;
197         int sock;
198         pthread_t thr;
199         float time;
200         int ret;
201         struct timespec res;
202         int i, tmp;
203
204         d.optflag = 0;
205         d.mode = BENCH_MODE_ASAP;
206
207         struct option longopt[] =
208         {
209                 { "mode", 0, NULL, 'm' },
210                 { 0, 0, 0, 0 }
211         };
212
213         while( 1 )
214         {
215                 opt = getopt( argc, argv, "s:d:m:n:" );
216                 if( opt == -1 )
217                         break;
218                 switch( opt )
219                 {
220                         case 's':
221                                 d.optflag |= BENCH_FLAG_SRC;
222                                 if( read_if( optarg, &d.ceif[0] ) != 0 )
223                                 {
224                                         perr( "'-s'" );
225                                         return -1;
226                                 }
227                                 break;
228                         case 'd':
229                                 d.optflag |= BENCH_FLAG_DST;
230                                 if( read_if( optarg, &d.ceif[1] ) )
231                                 {
232                                         perr( "-d" );
233                                         return -1;
234                                 }
235                                 break;
236                         case 'm':
237                                 tmp = read_mode( optarg );
238                                 if( tmp == BENCH_MODE_UNDEF )
239                                 {
240                                         perr( "benchmarking mode unknown" );
241                                         return -1;
242                                 }
243                                 d.mode = tmp;
244                                 break;
245                         case 'n':
246                                 d.optflag |= BENCH_FLAG_N;
247                                 d.n = atoi( optarg );
248                                 break;
249                         case '?':
250                                 return -1;
251                                 break;
252                 }
253         }
254
255         /* check opt */
256         /* '-n' option is mandatory and its value is >0 */
257         if( d.optflag & BENCH_FLAG_N )
258         {
259                 if( d.n < 1 )
260                 {
261                         perr( "'-n' should be at least 1." );
262                 }
263         } else 
264         {
265                 perr( "'-n' is mandatory." );
266                 return -1;
267         }
268
269         /* '-s' and '-d' should be defined and different iftype */
270         if( (d.optflag & BENCH_FLAG_SRC) && (d.optflag & BENCH_FLAG_DST) )
271         {
272                 if( !(d.ceif[0].type == IF_CAN     && d.ceif[1].type == IF_ETH_UDP) &&
273                     !(d.ceif[0].type == IF_ETH_UDP && d.ceif[1].type == IF_CAN    )    )
274                 {
275                         perr( "'-s' and '-d' should be different interface type." );
276                         return -1;
277                 }
278         } else
279         {
280                 perr( "'-s' and '-d' should be defined." );
281                 return -1;
282         }
283
284         tx_time = malloc( d.n*sizeof(struct timespec) );
285         rx_time = malloc( d.n*sizeof(struct timespec) );
286
287         pthread_barrier_init( &barrier, NULL, 2 );
288         pthread_create( &thr, NULL, thr_recv, NULL  );
289
290         /**/
291         struct sockaddr* addr;
292         struct sockaddr_can addr_can;
293         struct sockaddr_in addr_udp;
294         int addr_size;
295
296         if( d.ceif[0].type == IF_CAN )
297         {
298                 sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
299                 addr_can.can_family = AF_CAN;
300                 addr_can.can_ifindex = d.ceif[0].can.ifindex;
301                 addr = (struct sockaddr*)&addr_can;
302                 addr_size = sizeof( addr_can );
303         }
304         else
305         {
306                 sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
307                 addr_udp.sin_family = AF_INET;
308                 addr_udp.sin_addr = d.ceif[0].eth.ip;
309                 addr_udp.sin_port = htons( d.ceif[0].eth.port );
310                 addr = (struct sockaddr*)&addr_udp;
311                 addr_size = sizeof( addr_udp );
312         }
313         if( sock < 0 ) /* ToDo: ? */
314                 return -1;
315
316         pthread_barrier_wait( &barrier );
317
318         /* send  */
319         for( i=0; i<d.n; i++ )
320         {
321                 cf.can_id = i;
322                 cf.can_dlc = 8;
323                 memcpy( cf.data, &i, sizeof(i) );
324
325                 clock_gettime( CLOCK_REALTIME, &tx_time[cf.data[0]] );
326                 ret = sendto( sock, &cf, sizeof(cf), 0, addr, addr_size ); /* ToDo: check ret */
327                 printdbg( "sending(%d)\n", ret );
328                 if( d.mode == BENCH_MODE_ONEATTIME )
329                 {
330                         pthread_barrier_wait( &barrier );
331                 }
332         }
333
334         close( sock ); /* ToDo: shutdown? */
335         pthread_join( thr, NULL );
336
337         /* results */
338         dump_arg( argc, argv );
339         for( i=0; i<d.n; i++ )
340         {
341                 timespec_subtract( &res, &rx_time[i], &tx_time[i] );
342
343                 time = res.tv_sec*1000000000.0f + (float)res.tv_nsec;
344                 printf( "%f\t", time );
345         }
346         putchar( '\n' );
347
348         pthread_barrier_destroy( &barrier );
349         free( tx_time );
350         free( rx_time );
351
352         return 0;
353 }
354