From: Radek Matejka Date: Wed, 15 Aug 2012 14:58:24 +0000 (+0200) Subject: netdevice_notifier implemented; test script; cegwbench rxtimeo X-Git-Url: http://rtime.felk.cvut.cz/gitweb/can-eth-gw.git/commitdiff_plain/ff3d57b5a70914d5728e49fd96d65e6e0fc1cad3 netdevice_notifier implemented; test script; cegwbench rxtimeo netdevice_notifier was implemented to avoid sending can frames to detached devices or device index mismatch. The test script was written to test basic functionality of canethgw. cegwbench has now ability to set timeout for receiving function with its '-t' option. --- diff --git a/kernel/canethgw.c b/kernel/canethgw.c index 7686039..1b4bb43 100644 --- a/kernel/canethgw.c +++ b/kernel/canethgw.c @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -51,6 +53,7 @@ struct cegw_setting static int cegw_state = CEGW_STOP; static struct socket* can_sock = NULL, * udp_sock = NULL; static struct task_struct* eth_to_can = NULL, * can_to_eth = NULL; +static struct notifier_block notifier; HLIST_HEAD( cegw_rule_can_eth ); HLIST_HEAD( cegw_rule_eth_can ); @@ -96,7 +99,7 @@ inline static void cegw_can_send( struct socket* can_sock, struct can_frame* cf, vec.iov_base = cf; vec.iov_len = sizeof( *cf ); - kernel_sendmsg( can_sock, &mh, &vec, 1, sizeof( *cf ) ); /* ToDo: handle error */ + kernel_sendmsg( can_sock, &mh, &vec, 1, sizeof( *cf ) ); } /** @@ -108,7 +111,7 @@ static int cegw_udp_can( void* data ) struct can_frame cf; struct kvec vec; struct msghdr mh; - struct cegw_rule* job; + struct cegw_rule* rule; struct hlist_node* pos; int can_ifidx; int recv_size; @@ -127,15 +130,20 @@ static int cegw_udp_can( void* data ) break; vec.iov_base = &cf; vec.iov_len = sizeof(cf); - recv_size = kernel_recvmsg( udp_sock, &mh, &vec, 1, sizeof(cf), 0 ); /* ToDo: handle error, size check */ - if( recv_size == 0 ) + recv_size = kernel_recvmsg( udp_sock, &mh, &vec, 1, sizeof(cf), 0 ); + /* recv_size == 0 when shutting down */ + if( recv_size != sizeof(cf) || recv_size == 0 ) { continue; + } else if( recv_size < 0 ) + { + return -1; } - hlist_for_each_entry_rcu( job, pos, &cegw_rule_eth_can, list ) + + hlist_for_each_entry_rcu( rule, pos, &cegw_rule_eth_can, list ) { - rcu_read_lock(); /**/ - can_ifidx = job->can_ifindex; + rcu_read_lock(); + can_ifidx = rule->can_ifindex; rcu_read_unlock(); /* ToDo: from filter */ cegw_can_send( can_sock, &cf, can_ifidx ); @@ -168,16 +176,20 @@ static int cegw_can_udp( void* data ) while( 1 ) { - if( cegw_state == CEGW_STOP ) /**/ + if( cegw_state == CEGW_STOP ) break; vec.iov_base = &cf; vec.iov_len = sizeof( cf ); recv_size = kernel_recvmsg( can_sock, &mh, &vec, 1, sizeof( cf ), 0 ); - if( recv_size == 0 ) + if( recv_size != sizeof(cf) || recv_size == 0 ) { continue; + } else if( recv_size < 0 ) + { + return -1; } + hlist_for_each_entry_rcu( rule, pos, &cegw_rule_can_eth, list ) { rcu_read_lock(); @@ -192,9 +204,7 @@ static int cegw_can_udp( void* data ) return 0; } -/* NetLink */ - -static int cegw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg ) +static int cegw_newroute( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg ) { struct nlattr* tb[ CEGW_MAX+1 ]; struct cegw_rule* rule = NULL; @@ -299,8 +309,8 @@ static int cegw_create_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg static void cegw_flush( void ) { - struct hlist_node* pos,* n; struct cegw_rule* rule; + struct hlist_node* pos,* n; hlist_for_each_entry_safe( rule, pos, n, &cegw_rule_can_eth, list ) { @@ -314,7 +324,7 @@ static void cegw_flush( void ) } } -static int cegw_remove_job( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg ) +static int cegw_delroute( struct sk_buff* skb, struct nlmsghdr* nlh, void* arg ) { struct rtmsg* r; struct nlattr* tb[ CEGW_MAX+1 ]; @@ -394,7 +404,7 @@ cancel: return -EMSGSIZE; } -static int cegw_dump_job( struct sk_buff* skb, struct netlink_callback* cb ) +static int cegw_getroute( struct sk_buff* skb, struct netlink_callback* cb ) { struct cegw_rule* rule; struct hlist_node* pos; @@ -436,6 +446,41 @@ brk: return skb->len; } +static int cegw_notifier( struct notifier_block* nb, unsigned long msg, void* data ) +{ + struct net_device* dev = (struct net_device*)data; + struct cegw_rule* rule; + struct hlist_node* pos,* n; + + if( !net_eq(dev_net(dev), &init_net) ) + return NOTIFY_DONE; + if( dev->type != ARPHRD_CAN ) + return NOTIFY_DONE; + + if( msg == NETDEV_UNREGISTER ) + { + hlist_for_each_entry_safe( rule, pos, n, &cegw_rule_eth_can, list ) + { + if( rule->can_ifindex == dev->ifindex ) + { + hlist_del( &rule->list ); + kfree( rule ); + } + } + + hlist_for_each_entry_safe( rule, pos, n, &cegw_rule_can_eth, list ) + { + if( rule->can_ifindex == dev->ifindex ) + { + hlist_del( &rule->list ); + kfree( rule ); + } + } + } + + return NOTIFY_DONE; +} + /** * cegw_thread_start - start working threads * Two threads are started. One is serving udp->can routing and the other @@ -566,10 +611,13 @@ static int cegw_thread_stop( void ) static int __init cegw_init( void ) { + notifier.notifier_call = cegw_notifier; + register_netdevice_notifier( ¬ifier ); + /* subscribe to netlink */ - rtnl_register( PF_CAN, RTM_GETROUTE, NULL, cegw_dump_job, NULL ); - rtnl_register( PF_CAN, RTM_NEWROUTE, cegw_create_job, NULL, NULL ); - rtnl_register( PF_CAN, RTM_DELROUTE, cegw_remove_job, NULL, NULL ); + rtnl_register( PF_CAN, RTM_GETROUTE, NULL, cegw_getroute, NULL ); + rtnl_register( PF_CAN, RTM_NEWROUTE, cegw_newroute, NULL, NULL ); + rtnl_register( PF_CAN, RTM_DELROUTE, cegw_delroute, NULL, NULL ); return 0; } @@ -588,6 +636,7 @@ static void __exit cegw_exit( void ) cegw_state = CEGW_EXIT; mutex_unlock( &cegw_mutex ); + unregister_netdevice_notifier( ¬ifier ); cegw_flush(); } diff --git a/test/boot b/test/boot index 29a273b..cf19abc 100755 --- a/test/boot +++ b/test/boot @@ -1,4 +1,4 @@ #!/usr/bin/env novaboot -KERNEL=qemuKernel console=ttyS0,115200 +KERNEL=kernel/arch/x86/boot/bzImage console=ttyS0,115200 ramdisk < ( ( cd ~/workdir/busybox/_install; find . | cpio -o -H newc ); ( cd $SRCDIR/myroot; find . | cpio -o --dereference -H newc ) ) | gzip diff --git a/test/test b/test/test new file mode 100755 index 0000000..44b0ecd --- /dev/null +++ b/test/test @@ -0,0 +1,19 @@ +#!/bin/sh +evalmsg() +{ + if test $1 -eq 0; then + echo -e "\033[32mOK" + else + echo -e "\033[31mFAIL" + fi; + echo -ne "\033[0m" +} + +echo -n "Testing eth->can: " +cegwbench -s udp@127.0.0.1:10501 -d can@vcan0 -n 10 -t 1 &> /dev/zero +evalmsg $? + +echo -n "Testing can->eth: " +cegwbench -s can@vcan0 -d udp@127.0.0.1:10502 -n 10 -t 1 &> /dev/zero +evalmsg $? + diff --git a/utils/cegw/cegw.c b/utils/cegw/cegw.c index dcaecc3..c5c27b8 100644 --- a/utils/cegw/cegw.c +++ b/utils/cegw/cegw.c @@ -258,7 +258,6 @@ inline static int cegw_listen( struct cegw_nlmsg* req, struct cegw_data* d ) addattr32( &req->nh, sizeof(*req), CEGW_CMD_INFO, CEGW_LISTEN ); addattr_l( &req->nh, sizeof(*req), CEGW_ETH_IP, &d->eth_listen_addr, sizeof(d->eth_listen_addr) ); addattr_l( &req->nh, sizeof(*req), CEGW_ETH_PORT, &d->eth_listen_port, sizeof(d->eth_listen_port) ); - printf( "listen at: %x, %hu\n", d->eth_listen_addr.s_addr, d->eth_listen_port ); return 0; } @@ -446,12 +445,11 @@ int main( int argc, char* argv[] ) if( err < 0 ) { perror( "netlink sendto" ); - return err; + return -1; } /* recv */ rsize = recv( s, &rxbuf, sizeof(rxbuf), 0 ); - printf( "recv size=%d\n", rsize ); if( rsize < 0 ) { perr( "recv" ); @@ -459,33 +457,38 @@ int main( int argc, char* argv[] ) } nlh = (struct nlmsghdr*)rxbuf; - if( cmd & CEGW_CMD_LIST ) + if( nlh->nlmsg_type == NLMSG_ERROR ) { - printf( "recv nlmsg_type=%d\n", nlh->nlmsg_type ); - if( nlh->nlmsg_type == NLMSG_ERROR ) + rte = (struct nlmsgerr*)NLMSG_DATA( nlh ); + err = rte->error; + + if( err == 0 ) { - struct nlmsgerr* nlerr = NLMSG_DATA( nlh ); - int err = nlerr->error; - printf( "nlerror: %d,%s\n", err, strerror(abs(err)) ); + printf( "%s\n", strerror(abs(err)) ); + return 0; + } else + { + printf( "netlink error: %s\n", strerror(abs(err)) ); + return -1; } + } + + if( cmd & CEGW_CMD_LIST ) + { /* ToDo recv while */ printf( "%10ssource%20sdestination\n", "", "" ); while( 1 ) { if( !NLMSG_OK( nlh, rsize ) ) { - puts( "NLMSG_OK\n" ); break; } if( nlh->nlmsg_type == NLMSG_DONE ) { - puts( "NLMSG_DONE" ); break; } /* ToDo: NLMSG_ERR */ - rta = NLMSG_DATA( nlh ); - //rta = (struct rtattr*)( ((char *)rtm) + NLMSG_ALIGN(sizeof(struct rtmsg)) ); len = NLMSG_PAYLOAD( nlh, 0 ); for( ;RTA_OK(rta, len); rta = RTA_NEXT(rta,len) ) { @@ -511,19 +514,8 @@ int main( int argc, char* argv[] ) nlh = NLMSG_NEXT( nlh, rsize ); } - } else - { - if( nlh->nlmsg_type != NLMSG_ERROR ) - { - fprintf( stderr, "error: unexpected netlink answer=%d\n", nlh->nlmsg_type ); - return -1; - } - rte = (struct nlmsgerr*)NLMSG_DATA( nlh ); - err = rte->error; - if( err < 0 ) - fprintf( stderr, "error: netlink(%d); %s\n", err, strerror(abs(err)) ); } - + return 0; } diff --git a/utils/cegwbench/cegwbench.c b/utils/cegwbench/cegwbench.c index 00663d0..c1438c4 100644 --- a/utils/cegwbench/cegwbench.c +++ b/utils/cegwbench/cegwbench.c @@ -14,11 +14,6 @@ #include "cegwerr.h" #include "readif.h" -/** - * ToDo: - * [ ] consider can timestamp - */ - //#define BENCH_DEBUG #ifdef BENCH_DEBUG #define printdbg(...) printf( __VA_ARGS__ ) @@ -29,6 +24,7 @@ #define BENCH_FLAG_N 1 #define BENCH_FLAG_SRC 2 #define BENCH_FLAG_DST 4 +#define BENCH_FLAG_TIMEO 8 enum { BENCH_MODE_UNDEF, @@ -45,6 +41,7 @@ struct optdata int optflag; int mode; int n; + struct timeval timeo; struct cegw_if ceif[2]; /* 0 -> src, 1 -> dst */ }; @@ -58,6 +55,7 @@ void* thr_recv( void* arg ) struct can_frame cf; int i; int seq; + int ret; if( d.ceif[1].type == IF_CAN ) sock = can_sock_create( d.ceif[1].can.ifindex ); @@ -65,16 +63,26 @@ void* thr_recv( void* arg ) sock = udp_sock_create( d.ceif[1].eth.ip, d.ceif[1].eth.port ); if( sock == -1 ) { - /* ToDo: handle */ - return NULL; + /* ToDo: handle */ + return (void*)1; } + ret = setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, &d.timeo, sizeof(d.timeo) ); + if( ret != 0 ) + return (void*)1; + pthread_barrier_wait( &barrier ); /* recv */ for( i=0; i