]> rtime.felk.cvut.cz Git - can-eth-gw.git/blobdiff - utils/cegwbench/cegwbench.c
improved rtnl processing, some error checks added
[can-eth-gw.git] / utils / cegwbench / cegwbench.c
index dba10dda015b5dc206a27959dd5a8b1b34a4cb9a..00663d0db7bed9796dd499bde0bea95c6452cdf2 100644 (file)
@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <getopt.h>
 #include <time.h>
 #include <math.h>
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <linux/can.h>
 #include <pthread.h>
+#include "cegwerr.h"
+#include "readif.h"
 
 /**
  * ToDo:
  * [ ] consider can timestamp
  */
 
+//#define BENCH_DEBUG
+#ifdef BENCH_DEBUG
+#define printdbg(...) printf( __VA_ARGS__ )
+#else
+#define printdbg(...)
+#endif
+
+#define BENCH_FLAG_N 1
+#define BENCH_FLAG_SRC 2
+#define BENCH_FLAG_DST 4
+
+enum {
+       BENCH_MODE_UNDEF,
+       BENCH_MODE_ASAP,
+       BENCH_MODE_ONEATTIME,
+       BENCH_MODE_PERIOD
+};
+
+int can_sock_create( int ifindex );
+int udp_sock_create( struct in_addr ip, unsigned int port );
+
 struct optdata
 {
+       int optflag;
+       int mode;
        int n;
+       struct cegw_if ceif[2]; /* 0 -> src, 1 -> dst */
 };
 
 struct optdata d;
 pthread_barrier_t barrier;
 struct timespec* tx_time, * rx_time;
 
-void* udp_recv( void* arg )
+void* thr_recv( void* arg )
 {
-       struct sockaddr_in sa_udp;
-       int udp_sock;
+       int sock;
        struct can_frame cf;
        int i;
+       int seq;
 
-       sa_udp.sin_family = AF_INET;
-       sa_udp.sin_port = htons( 10502 );
-       inet_aton( "127.0.0.1", &sa_udp.sin_addr );
-
-       udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       if( udp_sock < 0 )
+       if( d.ceif[1].type == IF_CAN )
+               sock = can_sock_create( d.ceif[1].can.ifindex );
+       else
+               sock = udp_sock_create( d.ceif[1].eth.ip, d.ceif[1].eth.port );
+       if( sock == -1 )
        {
-               fprintf( stderr, "error: udp socket creation failed\n" );
-               return NULL;
-       }
-
-       if( bind(udp_sock, (struct sockaddr*)&sa_udp, sizeof(sa_udp)) != 0 )
-       {
-               fprintf( stderr, "error: udp socket binding failed\n" );
+       /* ToDo: handle */
                return NULL;
        }
 
@@ -54,26 +74,32 @@ void* udp_recv( void* arg )
        /* recv */
        for( i=0; i<d.n; i++ )
        {
-               recvfrom( udp_sock, &cf, sizeof(cf), 0, NULL, 0 );
-               clock_gettime( CLOCK_REALTIME, &rx_time[cf.data[0]] );
-               printf( "recv: (id=%d)%u\n", cf.can_id, cf.data[0] );
+               recvfrom( sock, &cf, sizeof(cf), 0, NULL, 0 );
+               seq = *((int*)cf.data);
+               clock_gettime( CLOCK_REALTIME, &rx_time[ seq ] );
+               printdbg( "recv: (id=%d)%d\n", cf.can_id, seq );
+               if( d.mode == BENCH_MODE_ONEATTIME )
+               {
+                       pthread_barrier_wait( &barrier );
+               }
        }
 
-       close( udp_sock );
+       close( sock );
        return NULL;
 }
 
 int timespec_subtract( struct timespec *result, struct timespec *x, struct timespec *yy )
 {
        struct timespec ylocal = *yy, *y = &ylocal;
-       /* Perform the carry for the later subtraction by updating Y. */
+/* Perform the carry for the later subtraction by updating Y. */
        if( x->tv_nsec < y->tv_nsec )
        {
                int nsec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
                y->tv_nsec -= 1000000000 * nsec;
                y->tv_sec += nsec;
-               }
-       if (x->tv_nsec - y->tv_nsec > 1000000000) {
+       }
+       if (x->tv_nsec - y->tv_nsec > 1000000000)
+       {
                int nsec = (x->tv_nsec - y->tv_nsec) / 1000000000;
                y->tv_nsec += 1000000000 * nsec;
                y->tv_sec -= nsec;
@@ -87,26 +113,137 @@ int timespec_subtract( struct timespec *result, struct timespec *x, struct times
        return x->tv_sec < y->tv_sec;
 }
 
+int udp_sock_create( struct in_addr ip, unsigned int port  )
+{
+       struct sockaddr_in addr_udp;
+       int udp_sock;
+
+       addr_udp.sin_family = AF_INET;
+       addr_udp.sin_port = htons( port );
+       addr_udp.sin_addr.s_addr = INADDR_ANY;
+
+       udp_sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+       if( udp_sock < 0 )
+       {
+               fprintf( stderr, "error: udp socket creation failed\n" );
+               return -1;
+       }
+
+       if( bind(udp_sock, (struct sockaddr*)&addr_udp, sizeof(addr_udp)) != 0 )
+       {
+               fprintf( stderr, "error: udp socket binding failed\n" );
+               return -1;
+       }
+
+       return udp_sock;
+}
+
+/**
+ * can_sock_create()
+ * @return can socket fd, or -1 on failure
+ */
+int can_sock_create( int ifindex )
+{
+       int can_sock;
+       struct sockaddr_can addr_can;
+
+       addr_can.can_family = AF_CAN;
+       addr_can.can_ifindex = ifindex;
+       
+       can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+       if( can_sock < 0 )
+       {
+               fprintf( stderr, "error: can socket creation failed\n" );
+               return -1;
+       }
+
+       if( bind(can_sock, (struct sockaddr*)&addr_can, sizeof(addr_can)) != 0 )
+       {
+               fprintf( stderr, "error: can socket binding failed\n" );
+               return -1;
+       }
+
+       return can_sock;
+}
+
+void dump_arg( int argc, char* argv[] )
+{
+       int i;
+
+       putchar( '#' );
+       for( i=0; i<argc; i++ )
+       {
+               printf( "%s ", argv[i] );
+       }
+       putchar( '\n' );        
+}
+
+int read_mode( char* in )
+{
+       if( strcmp( in, "asap" ) == 0 )
+               return BENCH_MODE_ASAP;
+       if( strcmp( in, "oneattime") == 0 )
+               return BENCH_MODE_ONEATTIME;
+       if( strcmp( in, "period" ) == 0 )
+               return BENCH_MODE_PERIOD;
+
+       return BENCH_MODE_UNDEF;
+}
+
 int main( int argc, char* argv[] )
 {
        char opt;
-       struct sockaddr_can sa_can;
        struct can_frame cf;
-       int can_sock;
+       int sock;
        pthread_t thr;
-       float mean = 0;
        float time;
+       int ret;
        struct timespec res;
-       int i;
+       int i, tmp;
+
+       d.optflag = 0;
+       d.mode = BENCH_MODE_ASAP;
+
+       struct option longopt[] =
+       {
+               { "mode", 0, NULL, 'm' },
+               { 0, 0, 0, 0 }
+       };
 
        while( 1 )
        {
-               opt = getopt( argc, argv, "n:" );
+               opt = getopt( argc, argv, "s:d:m:n:" );
                if( opt == -1 )
                        break;
                switch( opt )
                {
+                       case 's':
+                               d.optflag |= BENCH_FLAG_SRC;
+                               if( read_if( optarg, &d.ceif[0] ) != 0 )
+                               {
+                                       perr( "'-s'" );
+                                       return -1;
+                               }
+                               break;
+                       case 'd':
+                               d.optflag |= BENCH_FLAG_DST;
+                               if( read_if( optarg, &d.ceif[1] ) )
+                               {
+                                       perr( "-d" );
+                                       return -1;
+                               }
+                               break;
+                       case 'm':
+                               tmp = read_mode( optarg );
+                               if( tmp == BENCH_MODE_UNDEF )
+                               {
+                                       perr( "benchmarking mode unknown" );
+                                       return -1;
+                               }
+                               d.mode = tmp;
+                               break;
                        case 'n':
+                               d.optflag |= BENCH_FLAG_N;
                                d.n = atoi( optarg );
                                break;
                        case '?':
@@ -115,64 +252,102 @@ int main( int argc, char* argv[] )
                }
        }
 
+       /* check opt */
+       /* '-n' option is mandatory and its value is >0 */
+       if( d.optflag & BENCH_FLAG_N )
+       {
+               if( d.n < 1 )
+               {
+                       perr( "'-n' should be at least 1." );
+               }
+       } else 
+       {
+               perr( "'-n' is mandatory." );
+               return -1;
+       }
+
+       /* '-s' and '-d' should be defined and different iftype */
+       if( (d.optflag & BENCH_FLAG_SRC) && (d.optflag & BENCH_FLAG_DST) )
+       {
+               if( !(d.ceif[0].type == IF_CAN     && d.ceif[1].type == IF_ETH_UDP) &&
+                   !(d.ceif[0].type == IF_ETH_UDP && d.ceif[1].type == IF_CAN    )    )
+               {
+                       perr( "'-s' and '-d' should be different interface type." );
+                       return -1;
+               }
+       } else
+       {
+               perr( "'-s' and '-d' should be defined." );
+               return -1;
+       }
+
        tx_time = malloc( d.n*sizeof(struct timespec) );
        rx_time = malloc( d.n*sizeof(struct timespec) );
 
        pthread_barrier_init( &barrier, NULL, 2 );
-       pthread_create( &thr, NULL, udp_recv, NULL  );
+       pthread_create( &thr, NULL, thr_recv, NULL  );
 
-       sa_can.can_family = AF_CAN;
-       sa_can.can_ifindex = if_nametoindex( "vcan0" );
-       
-       can_sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
-       if( can_sock < 0 )
+       /**/
+       struct sockaddr* addr;
+       struct sockaddr_can addr_can;
+       struct sockaddr_in addr_udp;
+       int addr_size;
+
+       if( d.ceif[0].type == IF_CAN )
        {
-               fprintf( stderr, "error: can socket creation failed\n" );
-               return -1;
+               sock = socket( PF_CAN, SOCK_RAW, CAN_RAW );
+               addr_can.can_family = AF_CAN;
+               addr_can.can_ifindex = d.ceif[0].can.ifindex;
+               addr = (struct sockaddr*)&addr_can;
+               addr_size = sizeof( addr_can );
        }
-
-       if( bind(can_sock, (struct sockaddr*)&sa_can, sizeof(sa_can)) != 0 )
+       else
        {
-               fprintf( stderr, "error: can socket binding failed\n" );
-               return -1;
+               sock = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
+               addr_udp.sin_family = AF_INET;
+               addr_udp.sin_addr = d.ceif[0].eth.ip;
+               addr_udp.sin_port = htons( d.ceif[0].eth.port );
+               addr = (struct sockaddr*)&addr_udp;
+               addr_size = sizeof( addr_udp );
        }
+       if( sock < 0 ) /* ToDo: ? */
+               return -1;
 
        pthread_barrier_wait( &barrier );
 
        /* send  */
        for( i=0; i<d.n; i++ )
        {
-               //memset( &cf, 0, sizeof(cf) );
                cf.can_id = i;
                cf.can_dlc = 8;
-               cf.data[0] = i;
-               int ret = sendto( can_sock, &cf, sizeof(cf), 0, (struct sockaddr*)&sa_can, sizeof(sa_can) );
+               memcpy( cf.data, &i, sizeof(i) );
+
                clock_gettime( CLOCK_REALTIME, &tx_time[cf.data[0]] );
-               printf( "sending(%d)\n", ret );
+               ret = sendto( sock, &cf, sizeof(cf), 0, addr, addr_size ); /* ToDo: check ret */
+               printdbg( "sending(%d)\n", ret );
+               if( d.mode == BENCH_MODE_ONEATTIME )
+               {
+                       pthread_barrier_wait( &barrier );
+               }
        }
 
-       close( can_sock ); /* shutdown? */
+       close( sock ); /* ToDo: shutdown? */
        pthread_join( thr, NULL );
 
        /* results */
+       dump_arg( argc, argv );
        for( i=0; i<d.n; i++ )
        {
-               if( timespec_subtract( &res, &rx_time[i], &tx_time[i] ) == 0 )
-               {
-                       time = res.tv_sec*1000000000.0f + (float)res.tv_nsec;
-                       mean += time;
-                       printf( "transfer time:%fns\n", time );
-               } else
-               {
-                       printf( "transfer time: irrelevant\n" );
-               }
+               timespec_subtract( &res, &rx_time[i], &tx_time[i] );
+
+               time = res.tv_sec*1000000000.0f + (float)res.tv_nsec;
+               printf( "%f\t", time );
        }
-       mean /= ++i;
-       printf( "average: %fns\n", mean );
+       putchar( '\n' );
 
+       pthread_barrier_destroy( &barrier );
        free( tx_time );
        free( rx_time );
-//     clock_gettime( CLOCK_REALTIME, &tx_time );
 
        return 0;
 }